Commit c79483c3 authored by Marco Martin's avatar Marco Martin
Browse files

Add a landing page KCM

A new KCM that will replace the Systemsettings initial page. It won't be shown in the sidebar, but can be reloaded clicking on the home button. It shows some of the very common used options such as light/dark theme, mouse single/double click, file indexing enabled/disabled
parent a33f2678
......@@ -14,6 +14,7 @@ add_subdirectory( autostart )
add_subdirectory( ksplash )
add_subdirectory( launch )
add_subdirectory( landingpage )
add_subdirectory( keys )
add_subdirectory( ksmserver )
add_subdirectory( nightcolor )
......
# KI18N Translation Domain for this library
add_definitions(-DTRANSLATION_DOMAIN=\"kcm_landingpage\")
########### next target ###############
set(kcm_landingpage_SRCS
landingpage.cpp
landingpagedata.cpp
)
kcmutils_generate_module_data(
kcm_landingpage_SRCS
MODULE_DATA_HEADER landingpagedata.h
MODULE_DATA_CLASS_NAME LandingPageData
SETTINGS_HEADERS landingpage_kdeglobalssettings.h landingpage_baloosettings.h
SETTINGS_CLASSES LandingPageGlobalsSettings BalooSettings
)
kconfig_add_kcfg_files(kcm_landingpage_SRCS landingpage_kdeglobalssettings.kcfgc GENERATE_MOC)
kconfig_add_kcfg_files(kcm_landingpage_SRCS landingpage_baloosettings.kcfgc GENERATE_MOC)
add_library(kcm_landingpage MODULE ${kcm_landingpage_SRCS})
target_link_libraries(kcm_landingpage
KF5::QuickAddons
KF5::I18n
KF5::KCMUtils
KF5::ConfigWidgets
KF5::Declarative
KF5::KDELibs4Support # kglobalsettings
PW::KWorkspace
KF5::ActivitiesStats
Qt5::DBus
)
if(X11_FOUND)
target_link_libraries(kcm_landingpage ${X11_LIBRARIES} Qt5::X11Extras)
endif()
kcoreaddons_desktop_to_json(kcm_landingpage "kcm_landingpage.desktop" SERVICE_TYPES kcmodule.desktop)
########### install files ###############
install(FILES landingpage_kdeglobalssettings.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR})
install(FILES landingpage_baloosettings.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR})
install(FILES kcm_landingpage.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR})
install(TARGETS kcm_landingpage DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms)
kpackage_install_package(package kcm_landingpage kcms)
#! /usr/bin/env bash
$EXTRACTRC `find . -name \*.kcfg` >> rc.cpp
$XGETTEXT `find . -name "*.cpp" -o -name "*.qml"` -o $podir/kcm_landingpage.pot
[Desktop Entry]
Icon=preferences-desktop
Type=Service
X-KDE-ServiceTypes=KCModule
X-KDE-Library=kcm_landingpage
X-KDE-PluginKeyword=kcm_landingpage
X-KDE-ParentApp=kcontrol
X-KDE-System-Settings-Parent-Category=rootcategory
X-KDE-Weight=40
X-DocPath=kcontrol/landingpage/index.html
Name=Quick Settings
Comment=Landing page with some basic settings
Categories=Qt;KDE;X-KDE-settings-system;
/*
* Copyright (C) 2021 Marco Martin <mart@kde.org>
* Copyright (C) 2018 <furkantokac34@gmail.com>
* Copyright (c) 2019 Cyril Rossi <cyril.rossi@enioka.com>
*
* 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 "landingpage.h"
#include <KPluginFactory>
#include <KAboutData>
#include <KColorScheme>
#include <KLocalizedString>
#include <KGlobalSettings>
#include <KPackage/PackageLoader>
#include <KService>
#include <KCModuleInfo>
#include <QDBusMessage>
#include <QDBusConnection>
#include <QDBusPendingCall>
#include <QQuickItem>
#include <QQuickWindow>
#include <QQuickRenderControl>
#include <QScreen>
#include <QStandardItemModel>
#include <QGuiApplication>
#include "landingpagedata.h"
#include "landingpage_kdeglobalssettings.h"
#include "landingpage_baloosettings.h"
#include <KActivities/Stats/ResultModel>
#include <KActivities/Stats/ResultSet>
#include <KActivities/Stats/Terms>
namespace KAStats = KActivities::Stats;
using namespace KAStats;
using namespace KAStats::Terms;
K_PLUGIN_FACTORY_WITH_JSON(KCMLandingPageFactory, "kcm_landingpage.json", registerPlugin<KCMLandingPage>(); registerPlugin<LandingPageData>();)
MostUsedModel::MostUsedModel(QObject *parent)
: QSortFilterProxyModel (parent)
{
sort(0, Qt::DescendingOrder);
setSortRole(ResultModel::ScoreRole);
setDynamicSortFilter(true);
//prepare default items
m_defaultModel = new QStandardItemModel(this);
KService::Ptr service = KService::serviceByDesktopName(qGuiApp->desktopFileName());
if (service) {
const auto actions = service->actions();
for (const KServiceAction &action : actions) {
QStandardItem *item = new QStandardItem();
item->setData(QUrl(QStringLiteral("kcm:%1.desktop").arg(action.name())), ResultModel::ResourceRole);
m_defaultModel->appendRow(item);
}
} else {
qCritical() << "Failed to find desktop file for" << qGuiApp->desktopFileName();
}
}
void MostUsedModel::setResultModel(ResultModel *model)
{
if (m_resultModel == model) {
return;
}
auto updateModel = [this]() {
if (m_resultModel->rowCount() >= 5) {
setSourceModel(m_resultModel);
} else {
setSourceModel(m_defaultModel);
}
};
m_resultModel = model;
connect(m_resultModel, &QAbstractItemModel::rowsInserted, this, updateModel);
connect(m_resultModel, &QAbstractItemModel::rowsRemoved, this, updateModel);
updateModel();
}
QHash<int, QByteArray> MostUsedModel::roleNames() const
{
QHash<int, QByteArray> roleNames;
roleNames.insert(Qt::DisplayRole, "display");
roleNames.insert(Qt::DecorationRole, "decoration");
roleNames.insert(ResultModel::ScoreRole, "score");
roleNames.insert(KcmPluginRole, "kcmPlugin");
return roleNames;
}
bool MostUsedModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
const QString desktopName = sourceModel()->index(source_row, 0, source_parent).data(ResultModel::ResourceRole).toUrl().path();
KService::Ptr service = KService::serviceByStorageId(desktopName);
return service;
}
QVariant MostUsedModel::data(const QModelIndex &index, int role) const
{
//MenuItem *mi;
const QString desktopName = QSortFilterProxyModel::data(index, ResultModel::ResourceRole).toUrl().path();
KService::Ptr service = KService::serviceByStorageId(desktopName);
if (!service) {
return QVariant();
}
switch (role) {
case Qt::DisplayRole:
return service->name();
case Qt::DecorationRole:
return service->icon();
case KcmPluginRole: {
return service->desktopEntryName();
KCModuleInfo info(service);
return info.handle();
}
case ResultModel::ScoreRole:
return QSortFilterProxyModel::data(index, ResultModel::ScoreRole);
default:
return QVariant();
}
}
LookAndFeelGroup::LookAndFeelGroup(QObject *parent)
: QObject(parent)
{
m_package = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/LookAndFeel"));
}
QString LookAndFeelGroup::id() const
{
return m_package.metadata().pluginId();
}
QString LookAndFeelGroup::name() const
{
return m_package.metadata().name();
}
QString LookAndFeelGroup::thumbnail() const
{
return m_package.filePath("preview");;
}
KCMLandingPage::KCMLandingPage(QObject *parent, const QVariantList &args)
: KQuickAddons::ManagedConfigModule(parent, args)
, m_data(new LandingPageData(this))
{
qmlRegisterType<LandingPageGlobalsSettings>();
qmlRegisterType<BalooSettings>();
qmlRegisterType<MostUsedModel>();
qmlRegisterType<LookAndFeelGroup>();
KAboutData *about = new KAboutData(QStringLiteral("kcm_landingpage"),
i18n("Quick Settings"),
QStringLiteral("1.1"),
i18n("Landing page with some basic settings."),
KAboutLicense::GPL);
about->addAuthor(i18n("Marco Martin"), QString(), QStringLiteral("mart@kde.org"));
setAboutData(about);
setButtons(Apply | Help);
m_mostUsedModel = new MostUsedModel(this);
m_mostUsedModel->setResultModel(new ResultModel( AllResources | Agent(QStringLiteral("org.kde.systemsettings")) | HighScoredFirst | Limit(5), this));
m_defaultLightLookAndFeel = new LookAndFeelGroup(this);
m_defaultDarkLookAndFeel = new LookAndFeelGroup(this);
m_defaultLightLookAndFeel->m_package.setPath(m_data->landingPageGlobalsSettings()->defaultLightLookAndFeel());
m_defaultDarkLookAndFeel->m_package.setPath(m_data->landingPageGlobalsSettings()->defaultDarkLookAndFeel());
connect(globalsSettings(), &LandingPageGlobalsSettings::lookAndFeelPackageChanged,
this, [this]() {m_lnfDirty = true;});
}
MostUsedModel *KCMLandingPage::mostUsedModel() const
{
return m_mostUsedModel;
}
LandingPageGlobalsSettings *KCMLandingPage::globalsSettings() const
{
return m_data->landingPageGlobalsSettings();
}
BalooSettings *KCMLandingPage::balooSettings() const
{
return m_data->balooSettings();
}
void KCMLandingPage::save()
{
ManagedConfigModule::save();
QDBusMessage message = QDBusMessage::createSignal("/KGlobalSettings", "org.kde.KGlobalSettings", "notifyChange");
QList<QVariant> args;
args.append(KGlobalSettings::SettingsChanged);
args.append(KGlobalSettings::SETTINGS_MOUSE);
message.setArguments(args);
QDBusConnection::sessionBus().send(message);
// Update Baloo config or start/stop Baloo
if (balooSettings()->indexingEnabled()) {
// Trying to start baloo when it is already running is fine
const QString exe = QStandardPaths::findExecutable(QStringLiteral("baloo_file"));
QProcess::startDetached(exe, QStringList());
} else {
QDBusMessage message =
QDBusMessage::createMethodCall(QStringLiteral("org.kde.baloo"), QStringLiteral("/"), QStringLiteral("org.kde.baloo.main"), QStringLiteral("quit"));
QDBusConnection::sessionBus().asyncCall(message);
}
if (m_lnfDirty) {
QProcess::startDetached(QStringLiteral("lookandfeeltool"), QStringList({QStringLiteral("-a"), m_data->landingPageGlobalsSettings()->lookAndFeelPackage()}));
}
}
static void copyEntry(KConfigGroup &from, KConfigGroup &to, const QString &entry)
{
if (from.hasKey(entry)) {
to.writeEntry(entry, from.readEntry(entry));
}
}
LookAndFeelGroup *KCMLandingPage::defaultLightLookAndFeel() const
{
return m_defaultLightLookAndFeel;
}
LookAndFeelGroup *KCMLandingPage::defaultDarkLookAndFeel() const
{
return m_defaultDarkLookAndFeel;
}
void KCMLandingPage::openWallpaperDialog()
{
QString connector;
QQuickItem *item = mainUi();
if (!item) {
return;
}
QQuickWindow *quickWindow = item->window();
if (!quickWindow) {
return;
}
QWindow *window = QQuickRenderControl::renderWindowFor(quickWindow);
if (!window) {
return;
}
QScreen *screen = window->screen();
if (screen) {
connector = screen->name();
}
QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.plasmashell"), QStringLiteral("/PlasmaShell"),
QStringLiteral("org.kde.PlasmaShell"), QStringLiteral("evaluateScript"));
QList<QVariant> args;
args << QStringLiteral(R"(
let id = screenForConnector("%1");
if (id >= 0) {
let desktop = desktopForScreen(id);
desktop.showConfigurationInterface();
})").arg(connector);
message.setArguments(args);
QDBusConnection::sessionBus().call(message, QDBus::NoBlock);
}
Q_INVOKABLE void KCMLandingPage::openKCM(const QString &kcm)
{
QProcess::startDetached(QStringLiteral("systemsettings5"), QStringList({kcm}));
}
#include "landingpage.moc"
/*
* Copyright (C) 2018 <furkantokac34@gmail.com>
* Copyright (c) 2019 Cyril Rossi <cyril.rossi@enioka.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _KCM_LANDINGPAGE_H
#define _KCM_LANDINGPAGE_H
#include <KQuickAddons/ManagedConfigModule>
#include <KPackage/Package>
class QStandardItemModel;
class LandingPageData;
class LandingPageGlobalsSettings;
class BalooSettings;
class BalooData;
namespace KActivities {
namespace Stats {
class ResultModel;
}
}
class MostUsedModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
enum Roles {
KcmPluginRole = Qt::UserRole + 1000
};
explicit MostUsedModel(QObject *parent = nullptr);
void setResultModel(KActivities::Stats::ResultModel *model);
QHash<int, QByteArray> roleNames() const override;
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
private:
// Model when there is nothing from kactivities-stat
QStandardItemModel *m_defaultModel;
// Model fed by kactivities-stats
KActivities::Stats::ResultModel *m_resultModel;
};
class LookAndFeelGroup : public QObject {
Q_OBJECT
Q_PROPERTY(QString id READ id CONSTANT)
Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(QString thumbnail READ thumbnail CONSTANT)
public:
LookAndFeelGroup(QObject *parent = nullptr);
QString id() const;
QString name() const;
QString thumbnail() const;
KPackage::Package m_package;
};
class KCMLandingPage : public KQuickAddons::ManagedConfigModule
{
Q_OBJECT
Q_PROPERTY(MostUsedModel *mostUsedModel READ mostUsedModel CONSTANT)
Q_PROPERTY(LandingPageGlobalsSettings *globalsSettings READ globalsSettings CONSTANT)
Q_PROPERTY(BalooSettings *balooSettings READ balooSettings CONSTANT)
Q_PROPERTY(LookAndFeelGroup *defaultLightLookAndFeel READ defaultLightLookAndFeel CONSTANT)
Q_PROPERTY(LookAndFeelGroup *defaultDarkLookAndFeel READ defaultDarkLookAndFeel CONSTANT)
public:
KCMLandingPage(QObject *parent, const QVariantList &args);
~KCMLandingPage() override {}
MostUsedModel *mostUsedModel() const;
LandingPageGlobalsSettings *globalsSettings() const;
BalooSettings *balooSettings() const;
LookAndFeelGroup *defaultLightLookAndFeel() const;
LookAndFeelGroup *defaultDarkLookAndFeel() const;
Q_INVOKABLE void openWallpaperDialog();
Q_INVOKABLE void openKCM(const QString &kcm);
public Q_SLOTS:
void save() override;
private:
LandingPageData *m_data;
LookAndFeelGroup *m_defaultLightLookAndFeel = nullptr;
LookAndFeelGroup *m_defaultDarkLookAndFeel = nullptr;
MostUsedModel *m_mostUsedModel = nullptr;
bool m_lnfDirty = false;
};
#endif // _KCM_LANDINGPAGE_H
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name="baloofilerc" />
<group name="Basic Settings">
<entry name="IndexingEnabled" key="Indexing-Enabled" type="Bool">
<label>Enable file indexer</label>
<default>true</default>
</entry>
</group>
</kcfg>
File=landingpage_baloosettings.kcfg
ClassName=BalooSettings
Mutators=true
DefaultValueGetters=true
GenerateProperties=true
ParentInConstructor=true
Notifiers=Indexing-Enabled
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name="kdeglobals" />
<group name="General">
<entry name="colorScheme" key="ColorScheme" type="String">
<label>Color scheme name</label>
<default>BreezeLight</default>
</entry>
</group>
<group name="KDE">
<entry name="singleClick" key="SingleClick" type="Bool">
<label>Single click to open files</label>
<default>true</default>
</entry>
<entry name="lookAndFeelPackage" key="LookAndFeelPackage" type="String">
<label>Global Look and Feel package</label>
<default>org.kde.breeze.desktop</default>
</entry>
<entry name="defaultLightLookAndFeel" key="DefaultLightLookAndFeel" type="String">
<label>Global Look and Feel package, alternate</label>
<default>org.kde.breeze.desktop</default>
</entry>
<entry name="defaultDarkLookAndFeel" key="DefaultDarkLookAndFeel" type="String">
<label>Global Look and Feel package, alternate</label>
<default>org.kde.breezedark.desktop</default>
</entry>
<entry name="animationDurationFactor" key="AnimationDurationFactor" type="Double">
<label>Animation speed</label>
<default>1.0</default>
</entry>
</group>
</kcfg>
File=landingpage_kdeglobalssettings.kcfg
ClassName=LandingPageGlobalsSettings
Mutators=true
DefaultValueGetters=true
GenerateProperties=true
ParentInConstructor=true
Notifiers=animationDurationFactor
/*
Copyright (c) 2017 Marco Martin <mart@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
import QtQuick 2.5
import QtQuick.Controls 2.5 as QQC2
import QtQuick.Layouts 1.1
import org.kde.kirigami 2.5 as Kirigami
MouseArea {
id: item
property alias icon: iconItem.source
property alias text: label.text
property string module
property int iconSize: Kirigami.Units.iconSizes.medium
Layout.minimumWidth: Kirigami.Units.iconSizes.medium
Layout.minimumHeight: column.implicitHeight