plasma-framework/src/plasma/private/containment_p.cpp

247 lines
7.8 KiB
C++

/*
SPDX-FileCopyrightText: 2007 Aaron Seigo <aseigo@kde.org>
SPDX-FileCopyrightText: 2008 Ménard Alexis <darktears31@gmail.com>
SPDX-FileCopyrightText: 2009 Chani Armitage <chani@kde.org>
SPDX-FileCopyrightText: 2012 Marco Martin <notmart@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "private/containment_p.h"
#include <KLocalizedString>
#include <KWindowSystem>
#include <QDebug>
#include "config-plasma.h"
#include "pluginloader.h"
#include "debug_p.h"
#include "private/applet_p.h"
#include "timetracker.h"
namespace Plasma
{
const char ContainmentPrivate::defaultWallpaper[] = "org.kde.image";
ContainmentPrivate::ContainmentPrivate(Containment *c)
: q(c)
, formFactor(Types::Planar)
, location(Types::Floating)
, lastScreen(-1)
, type(Plasma::Types::NoContainmentType) // never had a screen
, uiReady(false)
, appletsUiReady(false)
{
// if the parent is an applet (i.e we are the systray)
// we want to follow screen changed signals from the parent's containment
auto appletParent = qobject_cast<Plasma::Applet *>(c->parent());
if (appletParent) {
QObject::connect(appletParent->containment(), &Containment::screenChanged, c, &Containment::screenChanged);
}
}
Plasma::ContainmentPrivate::~ContainmentPrivate()
{
applets.clear();
}
void ContainmentPrivate::addDefaultActions(KActionCollection *actions, Containment *c)
{
actions->setConfigGroup(QStringLiteral("Shortcuts-Containment"));
// adjust applet actions
QAction *appAction = qobject_cast<QAction *>(actions->action(QStringLiteral("remove")));
appAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_D, Qt::ALT + Qt::Key_R));
if (c && c->d->isPanelContainment()) {
appAction->setText(i18n("Remove this Panel"));
} else {
appAction->setText(i18n("Remove this Activity"));
}
appAction = qobject_cast<QAction *>(actions->action(QStringLiteral("configure")));
if (appAction) {
appAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_D, Qt::ALT + Qt::Key_S));
appAction->setText(i18n("Activity Settings"));
}
// add our own actions
QAction *appletBrowserAction = actions->add<QAction>(QStringLiteral("add widgets"));
appletBrowserAction->setAutoRepeat(false);
appletBrowserAction->setText(i18n("Add Widgets..."));
appletBrowserAction->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
appletBrowserAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_D, Qt::Key_A));
appletBrowserAction->setData(Plasma::Types::AddAction);
}
KConfigGroup ContainmentPrivate::containmentActionsConfig() const
{
KConfigGroup cfg = KConfigGroup(q->corona()->config(), "ActionPlugins");
return KConfigGroup(&cfg, QString::number(type));
}
void ContainmentPrivate::configChanged()
{
KConfigGroup group = q->config();
q->setWallpaper(group.readEntry("wallpaperplugin", defaultWallpaper));
}
void ContainmentPrivate::checkStatus(Plasma::Types::ItemStatus appletStatus)
{
// qCDebug(LOG_PLASMA) << "================== "<< appletStatus << q->status();
if (appletStatus == q->status()) {
return;
}
if (appletStatus < q->status() || appletStatus == Plasma::Types::HiddenStatus) {
// check to see if any other applet has a higher status, and stick with that if we do
// we'll treat HiddenStatus as lowest as we cannot change the enum value which is highest anymore
for (Applet *applet : qAsConst(applets)) {
if (applet->status() > appletStatus && applet->status() != Plasma::Types::HiddenStatus) {
appletStatus = applet->status();
}
}
}
if (appletStatus != Plasma::Types::HiddenStatus) {
q->setStatus(appletStatus);
}
}
void ContainmentPrivate::triggerShowAddWidgets()
{
Q_EMIT q->showAddWidgetsInterface(QPointF());
}
void ContainmentPrivate::containmentConstraintsEvent(Plasma::Types::Constraints constraints)
{
if (!q->isContainment()) {
return;
}
// qCDebug(LOG_PLASMA) << "got containmentConstraintsEvent" << constraints;
if (constraints & Plasma::Types::ImmutableConstraint) {
// update actions
const bool unlocked = q->immutability() == Types::Mutable;
QAction *action = q->actions()->action(QStringLiteral("remove"));
if (action) {
action->setEnabled(unlocked);
action->setVisible(unlocked);
}
action = q->actions()->action(QStringLiteral("add widgets"));
if (action) {
action->setEnabled(unlocked);
action->setVisible(unlocked);
}
// tell the applets too
for (Applet *a : qAsConst(applets)) {
/*Why qMin?
* the applets immutability() is the maximum between internal applet immutability
* and the immutability of its containment.
* so not set higher immutability in the internal member of Applet
* or the applet will not be able to be unlocked properly
*/
a->setImmutability(qMin(q->immutability(), a->d->immutability));
a->updateConstraints(Types::ImmutableConstraint);
}
}
// pass on the constraints that are relevant here
Types::Constraints appletConstraints = Types::NoConstraint;
if (constraints & Types::FormFactorConstraint) {
appletConstraints |= Types::FormFactorConstraint;
}
if (constraints & Types::ScreenConstraint) {
appletConstraints |= Types::ScreenConstraint;
}
if (appletConstraints != Types::NoConstraint) {
for (Applet *applet : qAsConst(applets)) {
applet->updateConstraints(appletConstraints);
}
}
}
Applet *ContainmentPrivate::createApplet(const QString &name, const QVariantList &args, uint id)
{
if (!q->isContainment()) {
return nullptr;
}
if (q->immutability() != Types::Mutable && !args.contains(QVariant::fromValue(QStringLiteral("org.kde.plasma:force-create")))) {
#ifndef NDEBUG
// qCDebug(LOG_PLASMA) << "addApplet for" << name << "requested, but we're currently immutable!";
#endif
return nullptr;
}
Applet *applet = PluginLoader::self()->loadApplet(name, id, args);
if (!applet) {
qCWarning(LOG_PLASMA) << "Applet" << name << "could not be loaded.";
applet = new Applet(nullptr, QString(), id);
applet->setLaunchErrorMessage(i18n("Could not find requested component: %1", name));
}
q->addApplet(applet);
// mirror behavior of resorecontents: if an applet is not valid, set it immediately to uiReady
if (!applet->pluginMetaData().isValid()) {
applet->updateConstraints(Plasma::Types::UiReadyConstraint);
}
return applet;
}
void ContainmentPrivate::appletDeleted(Plasma::Applet *applet)
{
applets.removeAll(applet);
Q_EMIT q->appletRemoved(applet);
Q_EMIT q->configNeedsSaving();
}
bool ContainmentPrivate::isPanelContainment() const
{
return type == Plasma::Types::PanelContainment || type == Plasma::Types::CustomPanelContainment;
}
void ContainmentPrivate::setStarted()
{
if (!q->Applet::d->started) {
q->Applet::d->started = true;
if (uiReady) {
Q_EMIT q->uiReadyChanged(true);
}
}
}
void ContainmentPrivate::setUiReady()
{
// if we are the containment and there is still some incomplete applet, we're still incomplete
if (!uiReady) {
uiReady = true;
if (q->Applet::d->started && (appletsUiReady || applets.isEmpty()) && loadingApplets.isEmpty()) {
Q_EMIT q->uiReadyChanged(true);
}
}
}
void ContainmentPrivate::appletLoaded(Applet *applet)
{
loadingApplets.remove(applet);
if (loadingApplets.isEmpty() && !appletsUiReady) {
appletsUiReady = true;
if (q->Applet::d->started && uiReady) {
Q_EMIT q->uiReadyChanged(true);
}
}
}
}