diff --git a/kirigami.pri b/kirigami.pri
index 70ff4145..922ca53a 100644
--- a/kirigami.pri
+++ b/kirigami.pri
@@ -1,70 +1,72 @@
QT += core qml quick gui svg network quickcontrols2
HEADERS += $$PWD/src/kirigamiplugin.h \
$$PWD/src/enums.h \
$$PWD/src/settings.h \
$$PWD/src/colorutils.h \
$$PWD/src/columnview_p.h \
$$PWD/src/columnview.h \
$$PWD/src/formlayoutattached.h \
$$PWD/src/mnemonicattached.h \
$$PWD/src/scenepositionattached.h \
$$PWD/src/libkirigami/basictheme_p.h \
$$PWD/src/libkirigami/platformtheme.h \
$$PWD/src/libkirigami/kirigamipluginfactory.h \
$$PWD/src/libkirigami/tabletmodewatcher.h \
$$PWD/src/scenegraph/paintedrectangleitem.h \
$$PWD/src/scenegraph/shadowedrectanglenode.h \
$$PWD/src/scenegraph/shadowedborderrectanglematerial.h \
$$PWD/src/scenegraph/shadowedbordertexturematerial.h \
$$PWD/src/scenegraph/shadowedrectanglematerial.h \
$$PWD/src/scenegraph/shadowedtexturematerial.h \
$$PWD/src/scenegraph/shadowedtexturenode.h \
$$PWD/src/icon.h \
$$PWD/src/delegaterecycler.h \
$$PWD/src/wheelhandler.h \
$$PWD/src/shadowedrectangle.h \
$$PWD/src/shadowedtexture.h \
$$PWD/src/pagerouter.h \
- $$PWD/src/pagepool.h
+ $$PWD/src/pagepool.h \
+ $$PWD/src/avatar.h
SOURCES += $$PWD/src/kirigamiplugin.cpp \
$$PWD/src/enums.cpp \
$$PWD/src/settings.cpp \
$$PWD/src/colorutils.cpp \
$$PWD/src/columnview.cpp \
$$PWD/src/formlayoutattached.cpp \
$$PWD/src/mnemonicattached.cpp \
$$PWD/src/scenepositionattached.cpp \
$$PWD/src/libkirigami/basictheme.cpp \
$$PWD/src/libkirigami/platformtheme.cpp \
$$PWD/src/libkirigami/kirigamipluginfactory.cpp \
$$PWD/src/libkirigami/tabletmodewatcher.cpp \
$$PWD/src/scenegraph/paintedrectangleitem.cpp \
$$PWD/src/scenegraph/shadowedrectanglenode.cpp \
$$PWD/src/scenegraph/shadowedborderrectanglematerial.cpp \
$$PWD/src/scenegraph/shadowedbordertexturematerial.cpp \
$$PWD/src/scenegraph/shadowedrectanglematerial.cpp \
$$PWD/src/scenegraph/shadowedtexturematerial.cpp \
$$PWD/src/scenegraph/shadowedtexturenode.cpp \
$$PWD/src/icon.cpp \
$$PWD/src/delegaterecycler.cpp \
$$PWD/src/wheelhandler.cpp \
$$PWD/src/shadowedrectangle.cpp \
$$PWD/src/shadowedtexture.cpp \
$$PWD/src/pagerouter.cpp \
- $$PWD/src/pagepool.cpp
+ $$PWD/src/pagepool.cpp \
+ $$PWD/src/avatar.cpp
INCLUDEPATH += $$PWD/src $$PWD/src/libkirigami
DEFINES += KIRIGAMI_BUILD_TYPE_STATIC
API_VER=1.0
RESOURCES += $$PWD/kirigami.qrc
exists($$_PRO_FILE_PWD_/kirigami-icons.qrc) {
message("Using icons QRC file shipped by the project")
RESOURCES += $$_PRO_FILE_PWD_/kirigami-icons.qrc
} else {
message("Using icons QRCfile shipped in kirigami")
RESOURCES += $$PWD/kirigami-icons.qrc
}
diff --git a/kirigami.qrc b/kirigami.qrc
index 5fcf4f80..d208b57b 100644
--- a/kirigami.qrc
+++ b/kirigami.qrc
@@ -1,95 +1,97 @@
src/controls/AbstractApplicationWindow.qml
src/controls/ContextDrawer.qml
src/controls/Action.qml
src/controls/Page.qml
src/controls/PageRow.qml
src/controls/AbstractListItem.qml
src/controls/Theme.qml
src/controls/AbstractCard.qml
src/controls/templates/AbstractCard.qml
src/controls/Card.qml
src/controls/CardsLayout.qml
src/controls/CardsListView.qml
src/controls/CardsGridView.qml
src/controls/ActionToolBar.qml
src/controls/templates/InlineMessage.qml
src/controls/InlineMessage.qml
src/controls/ToolBarApplicationHeader.qml
src/controls/ActionTextField.qml
src/controls/SearchField.qml
src/controls/PasswordField.qml
src/controls/private/GlobalDrawerActionItem.qml
src/controls/private/ContextDrawerActionItem.qml
src/controls/private/RefreshableScrollView.qml
src/controls/private/SwipeItemEventFilter.qml
src/controls/private/PageActionPropertyGroup.qml
src/controls/private/ActionIconGroup.qml
src/controls/private/CornerShadow.qml
src/controls/private/ActionButton.qml
src/controls/private/DefaultListItemBackground.qml
src/controls/private/DefaultCardBackground.qml
src/controls/private/BannerImage.qml
src/controls/private/EdgeShadow.qml
src/controls/private/ActionToolBarLayoutDetails.qml
src/controls/private/globaltoolbar/AbstractPageHeader.qml
src/controls/private/globaltoolbar/PageRowGlobalToolBarStyleGroup.qml
src/controls/private/globaltoolbar/PageRowGlobalToolBarUI.qml
src/controls/private/PrivateActionToolButton.qml
src/controls/private/globaltoolbar/TitlesPageHeader.qml
src/controls/private/globaltoolbar/ToolBarPageHeader.qml
src/controls/private/globaltoolbar/BreadcrumbControl.qml
src/controls/private/globaltoolbar/TabBarControl.qml
src/controls/private/ActionsMenu.qml
src/controls/private/ActionMenuItem.qml
src/controls/private/CardsGridViewPrivate.qml
src/controls/private/CardsListViewPrivate.qml
src/controls/Separator.qml
src/controls/OverlayDrawer.qml
src/controls/OverlaySheet.qml
src/controls/GlobalDrawer.qml
src/controls/templates/AbstractListItem.qml
src/controls/templates/private/MenuIcon.qml
src/controls/templates/private/GenericDrawerIcon.qml
src/controls/templates/private/PassiveNotification.qml
src/controls/templates/private/ContextIcon.qml
src/controls/templates/private/ScrollView.qml
src/controls/templates/private/BackButton.qml
src/controls/templates/private/IconPropertiesGroup.qml
src/controls/templates/private/ForwardButton.qml
+ src/controls/templates/private/BorderPropertiesGroup.qml
src/controls/templates/OverlayDrawer.qml
src/controls/templates/OverlaySheet.qml
src/controls/templates/SwipeListItem.qml
src/controls/templates/ApplicationHeader.qml
src/controls/templates/AbstractApplicationHeader.qml
src/controls/Units.qml
src/controls/SwipeListItem.qml
src/controls/ApplicationWindow.qml
src/controls/AbstractApplicationItem.qml
src/controls/ApplicationItem.qml
src/controls/ApplicationHeader.qml
src/controls/Heading.qml
src/controls/ScrollablePage.qml
src/controls/AboutPage.qml
src/controls/UrlButton.qml
src/controls/LinkButton.qml
src/controls/Label.qml
src/controls/BasicListItem.qml
src/controls/AbstractApplicationHeader.qml
src/controls/FormLayout.qml
src/controls/ListItemDragHandle.qml
src/controls/ShadowedImage.qml
+ src/controls/ShadowedImage.qml
src/styles/Material/AbstractListItem.qml
src/styles/Material/Theme.qml
src/styles/Material/SwipeListItem.qml
src/styles/Material/Label.qml
src/styles/org.kde.desktop/AbstractListItem.qml
src/styles/org.kde.desktop/Theme.qml
src/styles/org.kde.desktop/Units.qml
src/styles/org.kde.desktop/SwipeListItem.qml
src/styles/org.kde.desktop/ApplicationWindow.qml
src/styles/org.kde.desktop/AbstractApplicationHeader.qml
src/controls/PlaceholderMessage.qml
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c11deb97..9c153607 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,122 +1,123 @@
project(kirigami)
if (BUILD_SHARED_LIBS)
ecm_create_qm_loader(kirigami_QM_LOADER libkirigami2plugin_qt)
else()
set(KIRIGAMI_STATIC_FILES
libkirigami/basictheme.cpp
libkirigami/platformtheme.cpp
libkirigami/tabletmodewatcher.cpp
libkirigami/kirigamipluginfactory.cpp)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libkirigami ${CMAKE_CURRENT_BINARY_DIR}/libkirigami)
set(kirigami_SRCS
kirigamiplugin.cpp
columnview.cpp
enums.cpp
delegaterecycler.cpp
icon.cpp
settings.cpp
formlayoutattached.cpp
pagepool.cpp
imagecolors.cpp
scenepositionattached.cpp
mnemonicattached.cpp
wheelhandler.cpp
shadowedrectangle.cpp
shadowedtexture.cpp
colorutils.cpp
pagerouter.cpp
+ avatar.cpp
scenegraph/shadowedrectanglenode.cpp
scenegraph/shadowedrectanglematerial.cpp
scenegraph/shadowedborderrectanglematerial.cpp
scenegraph/paintedrectangleitem.cpp
scenegraph/shadowedtexturenode.cpp
scenegraph/shadowedtexturematerial.cpp
scenegraph/shadowedbordertexturematerial.cpp
${kirigami_QM_LOADER}
${KIRIGAMI_STATIC_FILES}
)
qt5_add_resources(SHADERS scenegraph/shaders/shaders.qrc)
add_subdirectory(libkirigami)
if(NOT BUILD_SHARED_LIBS)
# `rcc` is a bit dumb and isn't designed to use auto generated files, to
# avoid poluting the source directory, use absolute paths
set(kirigami_QML_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../)
# First, pre-process the QRC to add the files associated with the right Qt
# version.
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/../kirigami.qrc.in
${CMAKE_CURRENT_BINARY_DIR}/../kirigami.qrc
@ONLY
)
# When using the static library, all QML files need to be shipped within the
# .a file.
qt5_add_resources(
RESOURCES ${CMAKE_CURRENT_BINARY_DIR}/../kirigami.qrc
)
if (UNIX AND NOT ANDROID AND NOT(APPLE) AND NOT(DISABLE_DBUS))
qt5_add_dbus_interface(kirigami_SRCS libkirigami/org.kde.KWin.TabletModeManager.xml tabletmodemanager_interface)
endif()
endif()
add_library(kirigamiplugin ${kirigami_SRCS} ${RESOURCES} ${SHADERS})
if(NOT BUILD_SHARED_LIBS)
SET_TARGET_PROPERTIES(kirigamiplugin PROPERTIES
AUTOMOC_MOC_OPTIONS -Muri=org.kde.kirigami)
if (UNIX AND NOT ANDROID AND NOT(APPLE) AND NOT(DISABLE_DBUS))
set(Kirigami_EXTRA_LIBS Qt5::DBus)
else()
set(Kirigami_EXTRA_LIBS "")
endif()
else()
set(Kirigami_EXTRA_LIBS KF5::Kirigami2)
endif()
target_link_libraries(kirigamiplugin
PUBLIC
Qt5::Core
PRIVATE
${Kirigami_EXTRA_LIBS} Qt5::Qml Qt5::Quick Qt5::QuickControls2 Qt5::Concurrent
)
if (BUILD_SHARED_LIBS)
add_custom_target(copy_to_bin ALL
COMMAND ${CMAKE_COMMAND} -E
make_directory ${CMAKE_BINARY_DIR}/bin/org/kde/kirigami.2/
COMMAND ${CMAKE_COMMAND} -E
copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/controls ${CMAKE_BINARY_DIR}/bin/org/kde/kirigami.2/
COMMAND ${CMAKE_COMMAND} -E
copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/styles ${CMAKE_BINARY_DIR}/bin/org/kde/kirigami.2/styles
COMMAND ${CMAKE_COMMAND} -E
copy $ ${CMAKE_BINARY_DIR}/bin/org/kde/kirigami.2/
)
install(DIRECTORY controls/ DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2)
if (DESKTOP_ENABLED)
install(DIRECTORY styles/org.kde.desktop DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2/styles)
endif()
install(DIRECTORY styles/Material DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2/styles)
install(FILES ${platformspecific} DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2)
include(ECMGeneratePriFile)
ecm_generate_pri_file(BASE_NAME Kirigami2 LIB_NAME KF5Kirigami2 DEPS "core qml quick svg" FILENAME_VAR PRI_FILENAME )
install(FILES ${PRI_FILENAME}
DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
endif()
install(TARGETS kirigamiplugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2)
diff --git a/src/avatar.cpp b/src/avatar.cpp
new file mode 100644
index 00000000..1bedb2b7
--- /dev/null
+++ b/src/avatar.cpp
@@ -0,0 +1,107 @@
+#include "avatar.h"
+#include
+#include
+
+auto AvatarPrivate::initialsFromString(const QString& string) -> QString
+{
+ // "" -> ""
+ if (string.isEmpty()) return QStringLiteral("");
+
+ auto normalized = string.normalized(QString::NormalizationForm_D);
+ // "FirstName Name Name LastName"
+ if (normalized.contains(QStringLiteral(" "))) {
+ // "FirstName Name Name LastName" -> "FirstName" "Name" "Name" "LastName"
+ QStringList split = normalized.split(QStringLiteral(" "));
+ // "FirstName"
+ auto first = split.first();
+ // "LastName"
+ auto last = split.last();
+ if (first.isEmpty()) {
+ // "" "LastName" -> "L"
+ return QString(last.front());
+ }
+ if (last.isEmpty()) {
+ // "FirstName" "" -> "F"
+ return QString(first.front());
+ }
+ // "FirstName" "LastName" -> "FL"
+ return QString(first.front())+QString(last.front());
+ // "OneName"
+ } else {
+ // "OneName" -> "O"
+ return QString(normalized.front());
+ }
+}
+
+const QMap> c_colors = {
+ {
+ QStringLiteral("default"),
+ {
+ QColor("#e93a9a"),
+ QColor("#e93d58"),
+ QColor("#e9643a"),
+ QColor("#ef973c"),
+ QColor("#e8cb2d"),
+ QColor("#b6e521"),
+ QColor("#3dd425"),
+ QColor("#00d485"),
+ QColor("#00d3b8"),
+ QColor("#3daee9"),
+ QColor("#b875dc"),
+ QColor("#926ee4"),
+ }
+ },
+ {
+ QStringLiteral("Material"),
+ {
+ QColor("#f44336"),
+ QColor("#e91e63"),
+ QColor("#9c27b0"),
+ QColor("#673ab7"),
+ QColor("#3f51b5"),
+ QColor("#2196f3"),
+ QColor("#03a9f4"),
+ QColor("#00bcd4"),
+ QColor("#009688"),
+ QColor("#4caf50"),
+ QColor("#8bc34a"),
+ QColor("#cddc39"),
+ QColor("#ffeb3b"),
+ QColor("#ffc107"),
+ QColor("#ff9800"),
+ QColor("#ff5722"),
+ }
+ }
+};
+
+QList grabColors()
+{
+ if (c_colors.contains(QQuickStyle::name())) {
+ return c_colors[QQuickStyle::name()];
+ }
+ return c_colors[QStringLiteral("default")];
+}
+
+auto AvatarPrivate::colorsFromString(const QString& string) -> QColor
+{
+ // We use a hash to get a "random" number that's always the same for
+ // a given string.
+ auto hash = qHash(string);
+ // hash modulo the length of the colors list minus one will always get us a valid
+ // index
+ auto index = hash % (grabColors().length()-1);
+ // return a colour
+ return grabColors()[index];
+}
+
+auto AvatarPrivate::stringHasNonLatinCharacters(const QString& string) -> bool
+{
+ for (auto character : string) {
+ if (character.script() != QChar::Script_Common &&
+ character.script() != QChar::Script_Inherited &&
+ character.script() != QChar::Script_Latin) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/avatar.h b/src/avatar.h
new file mode 100644
index 00000000..b8ee1117
--- /dev/null
+++ b/src/avatar.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include
+#include
+
+class AvatarPrivate : public QObject {
+ Q_OBJECT
+
+public:
+ Q_INVOKABLE QString initialsFromString(const QString& name);
+ Q_INVOKABLE QColor colorsFromString(const QString& name);
+ Q_INVOKABLE bool stringHasNonLatinCharacters(const QString& name);
+};
diff --git a/src/controls/Avatar.qml b/src/controls/Avatar.qml
new file mode 100644
index 00000000..775e5987
--- /dev/null
+++ b/src/controls/Avatar.qml
@@ -0,0 +1,160 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Carson Black
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+import QtQuick 2.5
+import org.kde.kirigami 2.13 as Kirigami
+import QtQuick.Controls 2.13 as QQC2
+import org.kde.kirigami.private 2.13
+
+import "templates/private" as P
+
+/**
+ * An element that represents a user, either with initials, an icon, or a profile image.
+ */
+QQC2.Control {
+ id: avatarRoot
+
+ enum ImageMode {
+ AlwaysShowImage,
+ AdaptiveImageOrInitals,
+ AlwaysShowInitials
+ }
+ enum InitialsMode {
+ UseInitials,
+ UseIcon
+ }
+
+ /**
+ * The given name of a user.
+ *
+ * The user's name will be used for generating initials.
+ */
+ property string name
+
+ /**
+ * The source of the user's profile picture; an image.
+ */
+ property alias source: avatarImage.source
+
+ /**
+ * How the button should represent the user when there is no image available.
+ * * `UseInitials` - Use initials when the image is not available
+ * * `UseIcon` - Use an icon of a user when the image is not available
+ */
+ property int initialsMode: Kirigami.Avatar.InitialsMode.UseInitials
+
+ /**
+ * Whether the button should always show the image; show the image if one is
+ * available and show initials when it is not; or always show initials.
+ * * `AlwaysShowImage` - Always show the image; even if is not value
+ * * `AdaptiveImageOrInitals` - Show the image if it is valid; or show initials if it is not
+ * * `AlwaysShowInitials` - Always show initials
+ */
+ property int imageMode: Kirigami.Avatar.ImageMode.AdaptiveImageOrInitals
+
+ /**
+ * color: color
+ *
+ * The color to use for this avatar.
+ */
+ property var color: undefined
+ // We use a var instead of a color here to allow setting the colour
+ // as undefined, which will result in a generated colour being used.
+
+ property P.BorderPropertiesGroup border: P.BorderPropertiesGroup {
+ width: 2
+ color: Qt.rgba(0,0,0,0.2)
+ }
+
+ padding: 0
+ topPadding: 0
+ leftPadding: 0
+ rightPadding: 0
+ bottomPadding: 0
+
+ implicitWidth: Kirigami.Units.iconSizes.large
+ implicitHeight: Kirigami.Units.iconSizes.large
+
+ background: Rectangle {
+ radius: parent.width / 2
+
+ color: __private.color
+ }
+
+ QtObject {
+ id: __private
+ // This property allows us to fall back to colour generation if
+ // the root colour property is undefined.
+ property color color: {
+ if (!!avatarRoot.color) {
+ return avatarRoot.color
+ }
+ return AvatarPrivate.colorsFromString(name)
+ }
+ property bool showImage: {
+ return (avatarRoot.imageMode == Kirigami.Avatar.ImageMode.AlwaysShowImage) ||
+ (avatarImage.status == Image.Ready && avatarRoot.imageMode == Kirigami.Avatar.ImageMode.AdaptiveImageOrInitals)
+ }
+ }
+
+ contentItem: Item {
+ Kirigami.Heading {
+ visible: avatarRoot.initialsMode == Kirigami.Avatar.InitialsMode.UseInitials &&
+ !__private.showImage &&
+ !AvatarPrivate.stringHasNonLatinCharacters(avatarRoot.name)
+
+ text: AvatarPrivate.initialsFromString(name)
+ color: Kirigami.ColorUtils.brightnessForColor(__private.color) == Kirigami.ColorUtils.Light
+ ? "black"
+ : "white"
+
+ anchors.centerIn: parent
+ }
+ Kirigami.Icon {
+ visible: (avatarRoot.initialsMode == Kirigami.Avatar.InitialsMode.UseIcon && !__private.showImage) ||
+ (AvatarPrivate.stringHasNonLatinCharacters(avatarRoot.name) && !__private.showImage)
+
+ source: "user"
+
+ anchors.fill: parent
+ anchors.margins: Kirigami.Units.smallSpacing
+
+ Kirigami.Theme.textColor: Kirigami.ColorUtils.brightnessForColor(__private.color) == Kirigami.ColorUtils.Light
+ ? "black"
+ : "white"
+ }
+ Image {
+ id: avatarImage
+ visible: false
+
+ mipmap: true
+ smooth: true
+
+ fillMode: Image.PreserveAspectFit
+ anchors.fill: parent
+ }
+ Kirigami.ShadowedTexture {
+ visible: __private.showImage
+
+ radius: width / 2
+ anchors.fill: parent
+
+ source: avatarImage
+ }
+
+ Rectangle {
+ color: "transparent"
+
+ radius: width / 2
+ anchors.fill: parent
+
+ border {
+ width: avatarRoot.border.width
+ color: avatarRoot.border.color
+ }
+ }
+ }
+}
diff --git a/src/controls/templates/private/BorderPropertiesGroup.qml b/src/controls/templates/private/BorderPropertiesGroup.qml
new file mode 100644
index 00000000..89132259
--- /dev/null
+++ b/src/controls/templates/private/BorderPropertiesGroup.qml
@@ -0,0 +1,19 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Carson Black
+ *
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+import QtQuick 2.5
+
+QtObject {
+ /**
+ * The color of this border.
+ */
+ property color color
+
+ /**
+ * The width of this border.
+ */
+ property real width
+}
diff --git a/src/kirigamiplugin.cpp b/src/kirigamiplugin.cpp
index 8b120d25..5753ef5d 100644
--- a/src/kirigamiplugin.cpp
+++ b/src/kirigamiplugin.cpp
@@ -1,271 +1,274 @@
/*
* SPDX-FileCopyrightText: 2009 Alan Alpert
* SPDX-FileCopyrightText: 2010 Ménard Alexis
* SPDX-FileCopyrightText: 2010 Marco Martin
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "kirigamiplugin.h"
#include "columnview.h"
#include "enums.h"
#include "icon.h"
#include "settings.h"
#include "formlayoutattached.h"
#include "mnemonicattached.h"
#include "delegaterecycler.h"
#include "pagepool.h"
#include "scenepositionattached.h"
#include "wheelhandler.h"
#include "shadowedrectangle.h"
#include "shadowedtexture.h"
#include "colorutils.h"
#include "pagerouter.h"
#include "imagecolors.h"
+#include "avatar.h"
#include
#include
#include
#include
#include
#include
#include "libkirigami/platformtheme.h"
static QString s_selectedStyle;
//Q_INIT_RESOURCE(kirigami);
#ifdef KIRIGAMI_BUILD_TYPE_STATIC
#include
#endif
class CopyHelperPrivate : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE static void copyTextToClipboard(const QString& text)
{
qGuiApp->clipboard()->setText(text);
}
};
// we can't do this in the plugin object directly, as that can live in a different thread
// and event filters are only allowed in the same thread as the filtered object
class LanguageChangeEventFilter : public QObject
{
Q_OBJECT
public:
bool eventFilter(QObject *receiver, QEvent *event) override
{
if (event->type() == QEvent::LanguageChange && receiver == QCoreApplication::instance()) {
emit languageChangeEvent();
}
return QObject::eventFilter(receiver, event);
}
Q_SIGNALS:
void languageChangeEvent();
};
KirigamiPlugin::KirigamiPlugin(QObject *parent)
: QQmlExtensionPlugin(parent)
{
auto filter = new LanguageChangeEventFilter;
filter->moveToThread(QCoreApplication::instance()->thread());
QCoreApplication::instance()->installEventFilter(filter);
connect(filter, &LanguageChangeEventFilter::languageChangeEvent, this, &KirigamiPlugin::languageChangeEvent);
}
QUrl KirigamiPlugin::componentUrl(const QString &fileName) const
{
for (const QString &style : qAsConst(m_stylesFallbackChain)) {
const QString candidate = QStringLiteral("styles/") + style + QLatin1Char('/') + fileName;
if (QFile::exists(resolveFilePath(candidate))) {
#ifdef KIRIGAMI_BUILD_TYPE_STATIC
return QUrl(QStringLiteral("qrc:/org/kde/kirigami/styles/") + style + QLatin1Char('/') + fileName);
#else
return QUrl(resolveFileUrl(candidate));
#endif
}
}
#ifdef KIRIGAMI_BUILD_TYPE_STATIC
return QUrl(QStringLiteral("qrc:/org/kde/kirigami/") + fileName);
#else
return QUrl(resolveFileUrl(fileName));
#endif
}
void KirigamiPlugin::registerTypes(const char *uri)
{
#if defined(Q_OS_ANDROID) && QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QResource::registerResource(QStringLiteral("assets:/android_rcc_bundle.rcc"));
#endif
Q_ASSERT(QLatin1String(uri) == QLatin1String("org.kde.kirigami"));
const QString style = QQuickStyle::name();
if (QIcon::themeName().isEmpty() && !qEnvironmentVariableIsSet("XDG_CURRENT_DESKTOP")) {
QIcon::setThemeSearchPaths({resolveFilePath(QStringLiteral(".")), QStringLiteral(":/icons")});
QIcon::setThemeName(QStringLiteral("breeze-internal"));
}
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
//org.kde.desktop.plasma is a couple of files that fall back to desktop by purpose
if ((style.isEmpty() || style == QStringLiteral("org.kde.desktop.plasma")) && QFile::exists(resolveFilePath(QStringLiteral("/styles/org.kde.desktop")))) {
m_stylesFallbackChain.prepend(QStringLiteral("org.kde.desktop"));
}
#elif defined(Q_OS_ANDROID)
if (!m_stylesFallbackChain.contains(QLatin1String("Material"))) {
m_stylesFallbackChain.prepend(QStringLiteral("Material"));
}
#else // do we have an iOS specific style?
if (!m_stylesFallbackChain.contains(QLatin1String("Material"))) {
m_stylesFallbackChain.prepend(QStringLiteral("Material"));
}
#endif
if (!style.isEmpty() && QFile::exists(resolveFilePath(QStringLiteral("/styles/") + style)) && !m_stylesFallbackChain.contains(style)) {
m_stylesFallbackChain.prepend(style);
//if we have plasma deps installed, use them for extra integration
if (style == QStringLiteral("org.kde.desktop") && QFile::exists(resolveFilePath(QStringLiteral("/styles/org.kde.desktop.plasma")))) {
m_stylesFallbackChain.prepend(QStringLiteral("org.kde.desktop.plasma"));
}
} else {
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
m_stylesFallbackChain.prepend(QStringLiteral("org.kde.desktop"));
#endif
}
//At this point the fallback chain will be selected->org.kde.desktop->Fallback
s_selectedStyle = m_stylesFallbackChain.first();
qmlRegisterSingletonType(uri, 2, 0, "Settings",
[](QQmlEngine *e, QJSEngine*) -> QObject* {
Settings *settings = Settings::self();
//singleton managed internally, qml should never delete it
e->setObjectOwnership(settings, QQmlEngine::CppOwnership);
settings->setStyle(s_selectedStyle);
return settings;
}
);
qmlRegisterUncreatableType(uri, 2, 0, "ApplicationHeaderStyle", QStringLiteral("Cannot create objects of type ApplicationHeaderStyle"));
//old legacy retrocompatible Theme
qmlRegisterSingletonType(componentUrl(QStringLiteral("Theme.qml")), uri, 2, 0, "Theme");
qmlRegisterSingletonType(componentUrl(QStringLiteral("Units.qml")), uri, 2, 0, "Units");
qmlRegisterType(componentUrl(QStringLiteral("Action.qml")), uri, 2, 0, "Action");
qmlRegisterType(componentUrl(QStringLiteral("AbstractApplicationHeader.qml")), uri, 2, 0, "AbstractApplicationHeader");
qmlRegisterType(componentUrl(QStringLiteral("AbstractApplicationWindow.qml")), uri, 2, 0, "AbstractApplicationWindow");
qmlRegisterType(componentUrl(QStringLiteral("AbstractListItem.qml")), uri, 2, 0, "AbstractListItem");
qmlRegisterType(componentUrl(QStringLiteral("ApplicationHeader.qml")), uri, 2, 0, "ApplicationHeader");
qmlRegisterType(componentUrl(QStringLiteral("ToolBarApplicationHeader.qml")), uri, 2, 0, "ToolBarApplicationHeader");
qmlRegisterType(componentUrl(QStringLiteral("ApplicationWindow.qml")), uri, 2, 0, "ApplicationWindow");
qmlRegisterType(componentUrl(QStringLiteral("BasicListItem.qml")), uri, 2, 0, "BasicListItem");
qmlRegisterType(componentUrl(QStringLiteral("OverlayDrawer.qml")), uri, 2, 0, "OverlayDrawer");
qmlRegisterType(componentUrl(QStringLiteral("ContextDrawer.qml")), uri, 2, 0, "ContextDrawer");
qmlRegisterType(componentUrl(QStringLiteral("GlobalDrawer.qml")), uri, 2, 0, "GlobalDrawer");
qmlRegisterType(componentUrl(QStringLiteral("Heading.qml")), uri, 2, 0, "Heading");
qmlRegisterType(componentUrl(QStringLiteral("Separator.qml")), uri, 2, 0, "Separator");
qmlRegisterType(componentUrl(QStringLiteral("PageRow.qml")), uri, 2, 0, "PageRow");
qmlRegisterType(uri, 2, 0, "Icon");
qmlRegisterType(componentUrl(QStringLiteral("Label.qml")), uri, 2, 0, "Label");
//TODO: uncomment for 2.3 release
//qmlRegisterTypeNotAvailable(uri, 2, 3, "Label", "Label type not supported anymore, use QtQuick.Controls.Label 2.0 instead");
qmlRegisterType(componentUrl(QStringLiteral("OverlaySheet.qml")), uri, 2, 0, "OverlaySheet");
qmlRegisterType(componentUrl(QStringLiteral("Page.qml")), uri, 2, 0, "Page");
qmlRegisterType(componentUrl(QStringLiteral("ScrollablePage.qml")), uri, 2, 0, "ScrollablePage");
qmlRegisterType(componentUrl(QStringLiteral("SplitDrawer.qml")), uri, 2, 0, "SplitDrawer");
qmlRegisterType(componentUrl(QStringLiteral("SwipeListItem.qml")), uri, 2, 0, "SwipeListItem");
//2.1
qmlRegisterType(componentUrl(QStringLiteral("AbstractItemViewHeader.qml")), uri, 2, 1, "AbstractItemViewHeader");
qmlRegisterType(componentUrl(QStringLiteral("ItemViewHeader.qml")), uri, 2, 1, "ItemViewHeader");
qmlRegisterType(componentUrl(QStringLiteral("AbstractApplicationItem.qml")), uri, 2, 1, "AbstractApplicationItem");
qmlRegisterType(componentUrl(QStringLiteral("ApplicationItem.qml")), uri, 2, 1, "ApplicationItem");
//2.2
//Theme changed from a singleton to an attached property
qmlRegisterUncreatableType(uri, 2, 2, "Theme", QStringLiteral("Cannot create objects of type Theme, use it as an attached property"));
//2.3
qmlRegisterType(componentUrl(QStringLiteral("FormLayout.qml")), uri, 2, 3, "FormLayout");
qmlRegisterUncreatableType(uri, 2, 3, "FormData", QStringLiteral("Cannot create objects of type FormData, use it as an attached property"));
qmlRegisterUncreatableType(uri, 2, 3, "MnemonicData", QStringLiteral("Cannot create objects of type MnemonicData, use it as an attached property"));
//2.4
qmlRegisterType(componentUrl(QStringLiteral("AbstractCard.qml")), uri, 2, 4, "AbstractCard");
qmlRegisterType(componentUrl(QStringLiteral("Card.qml")), uri, 2, 4, "Card");
qmlRegisterType(componentUrl(QStringLiteral("CardsListView.qml")), uri, 2, 4, "CardsListView");
qmlRegisterType(componentUrl(QStringLiteral("CardsGridView.qml")), uri, 2, 4, "CardsGridView");
qmlRegisterType(componentUrl(QStringLiteral("CardsLayout.qml")), uri, 2, 4, "CardsLayout");
qmlRegisterType(componentUrl(QStringLiteral("InlineMessage.qml")), uri, 2, 4, "InlineMessage");
qmlRegisterUncreatableType(uri, 2, 4, "MessageType", QStringLiteral("Cannot create objects of type MessageType"));
qmlRegisterType(uri, 2, 4, "DelegateRecycler");
//2.5
qmlRegisterType(componentUrl(QStringLiteral("ListItemDragHandle.qml")), uri, 2, 5, "ListItemDragHandle");
qmlRegisterType(componentUrl(QStringLiteral("ActionToolBar.qml")), uri, 2, 5, "ActionToolBar");
qmlRegisterUncreatableType(uri, 2, 5, "ScenePosition", QStringLiteral("Cannot create objects of type ScenePosition, use it as an attached property"));
//2.6
qmlRegisterType(componentUrl(QStringLiteral("AboutPage.qml")), uri, 2, 6, "AboutPage");
qmlRegisterType(componentUrl(QStringLiteral("LinkButton.qml")), uri, 2, 6, "LinkButton");
qmlRegisterType(componentUrl(QStringLiteral("UrlButton.qml")), uri, 2, 6, "UrlButton");
qmlRegisterSingletonType("org.kde.kirigami.private", 2, 6, "CopyHelperPrivate", [] (QQmlEngine*, QJSEngine*) -> QObject* { return new CopyHelperPrivate; });
//2.7
qmlRegisterType(uri, 2, 7, "ColumnView");
qmlRegisterType(componentUrl(QStringLiteral("ActionTextField.qml")), uri, 2, 7, "ActionTextField");
//2.8
qmlRegisterType(componentUrl(QStringLiteral("SearchField.qml")), uri, 2, 8, "SearchField");
qmlRegisterType(componentUrl(QStringLiteral("PasswordField.qml")), uri, 2, 8, "PasswordField");
//2.9
qmlRegisterType(uri, 2, 9, "WheelHandler");
qmlRegisterUncreatableType(uri, 2, 9, "WheelEvent", QStringLiteral("Cannot create objects of type WheelEvent."));
//2.10
qmlRegisterType(componentUrl(QStringLiteral("ListSectionHeader.qml")), uri, 2, 10, "ListSectionHeader");
// 2.11
qmlRegisterType(uri, 2, 11, "PagePool");
qmlRegisterType(componentUrl(QStringLiteral("PagePoolAction.qml")), uri, 2, 11, "PagePoolAction");
//TODO: remove
qmlRegisterType(componentUrl(QStringLiteral("SwipeListItem2.qml")), uri, 2, 11, "SwipeListItem2");
// 2.12
qmlRegisterType(uri, 2, 12, "ShadowedRectangle");
qmlRegisterType(uri, 2, 12, "ShadowedTexture");
qmlRegisterType(componentUrl(QStringLiteral("ShadowedImage.qml")), uri, 2, 12, "ShadowedImage");
qmlRegisterType(componentUrl(QStringLiteral("PlaceholderMessage.qml")), uri, 2, 12, "PlaceholderMessage");
qmlRegisterUncreatableType(uri, 2, 12, "BorderGroup", QStringLiteral("Used as grouped property"));
qmlRegisterUncreatableType(uri, 2, 12, "ShadowGroup", QStringLiteral("Used as grouped property"));
qmlRegisterSingletonType(uri, 2, 12, "ColorUtils", [] (QQmlEngine*, QJSEngine*) -> QObject* { return new ColorUtils; });
qmlRegisterUncreatableType(uri, 2, 12, "CornersGroup", QStringLiteral("Used as grouped property"));
qmlRegisterType(uri, 2, 12, "PageRouter");
qmlRegisterType(uri, 2, 12, "PageRoute");
qmlRegisterUncreatableType(uri, 2, 12, "PageRouterAttached", QStringLiteral("PageRouterAttached cannot be created"));
qmlRegisterType(componentUrl(QStringLiteral("RouterWindow.qml")), uri, 2, 12, "RouterWindow");
// 2.13
qmlRegisterType(uri, 2, 13, "ImageColors");
+ qmlRegisterSingletonType("org.kde.kirigami.private", 2, 13, "AvatarPrivate", [] (QQmlEngine*, QJSEngine*) -> QObject* { return new AvatarPrivate; });
+ qmlRegisterType(componentUrl(QStringLiteral("Avatar.qml")), uri, 2, 13, "Avatar");
qmlProtectModule(uri, 2);
}
void KirigamiPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
{
Q_UNUSED(uri);
connect(this, &KirigamiPlugin::languageChangeEvent, engine, &QQmlEngine::retranslate);
}
#include "kirigamiplugin.moc"