1
0
mirror of https://github.com/KDE/latte-dock.git synced 2024-12-23 13:33:50 +03:00

editdock:support indicatorsuimanager

--the new approach is much more memory efficient
as the same indicator config ui is used for ALL
views and anything related to config uis is now
handled by the manager instead of each diffent
view on its own
This commit is contained in:
Michail Vourlakos 2020-07-31 20:16:14 +03:00
parent 5d1edfe68d
commit 45d09b2cd4
11 changed files with 313 additions and 168 deletions

View File

@ -78,7 +78,6 @@ Indicator::Indicator(Latte::View *parent)
Indicator::~Indicator()
{
unloadIndicators();
releaseConfigUi();
if (m_component) {
m_component->deleteLater();
@ -137,21 +136,6 @@ bool Indicator::latteTasksArePresent()
return m_view->extendedInterface()->hasLatteTasks();
}
bool Indicator::providesConfigUi() const
{
return m_providesConfigUi;
}
void Indicator::setProvidesConfigUi(bool provides)
{
if (m_providesConfigUi == provides) {
return;
}
m_providesConfigUi = provides;
emit providesConfigUiChanged();
}
bool Indicator::pluginIsReady()
{
return m_pluginIsReady;
@ -316,81 +300,6 @@ void Indicator::loadPlasmaComponent()
emit plasmaComponentChanged();
}
void Indicator::configUiFor(QString type, QQuickItem *parent)
{
if (!parent) {
return;
}
if (m_lastCreatedConfigUi && m_lastCreatedConfigUiType == type && !type.isEmpty()) {
//! config ui has already been created and can be provided again
QQuickItem *qmlItem = qobject_cast<QQuickItem*>(m_lastCreatedConfigUi->rootObject());
if (qmlItem) {
qmlItem->setParentItem(parent);
qmlItem->setVisible(true);
}
return;
}
if (m_lastCreatedConfigUi) {
delete m_lastCreatedConfigUi;
m_lastCreatedConfigUi = nullptr;
}
auto prevConfigUi = m_lastCreatedConfigUi;
KPluginMetaData metadata;
if (m_metadata.pluginId() == type) {
metadata = m_metadata;
} else {
metadata = m_corona->indicatorFactory()->metadata(type);
}
if (metadata.isValid()) {
QString uiPath = metadata.value("X-Latte-ConfigUi");
if (!uiPath.isEmpty()) {
m_lastCreatedConfigUi = new KDeclarative::QmlObjectSharedEngine(this);
m_lastCreatedConfigUi->setTranslationDomain(QLatin1String("latte_indicator_") + m_metadata.pluginId());
m_lastCreatedConfigUi->setInitializationDelayed(true);
uiPath = m_pluginPath + "package/" + uiPath;
m_lastCreatedConfigUi->setSource(QUrl::fromLocalFile(uiPath));
m_lastCreatedConfigUi->rootContext()->setContextProperty(QStringLiteral("dialog"), parent);
m_lastCreatedConfigUi->rootContext()->setContextProperty(QStringLiteral("indicator"), this);
m_lastCreatedConfigUi->completeInitialization();
QQuickItem *qmlItem = qobject_cast<QQuickItem*>(m_lastCreatedConfigUi->rootObject());
if (qmlItem) {
qmlItem->setParentItem(parent);
m_lastCreatedConfigUiType = type;
setProvidesConfigUi(true);
}
} else {
m_lastCreatedConfigUiType = "";
setProvidesConfigUi(false);
}
}
}
void Indicator::hideConfigUi()
{
if (m_lastCreatedConfigUi) {
QQuickItem *qmlItem = qobject_cast<QQuickItem*>(m_lastCreatedConfigUi->rootObject());
if (qmlItem) {
qmlItem->setVisible(false);
}
}
}
void Indicator::releaseConfigUi()
{
if (m_lastCreatedConfigUi) {
m_lastCreatedConfigUi->deleteLater();
m_lastCreatedConfigUi = nullptr;
}
}
void Indicator::unloadIndicators()
{
setPluginIsReady(false);
@ -421,48 +330,6 @@ void Indicator::updateScheme()
}
}
void Indicator::addIndicator()
{
QFileDialog *fileDialog = new QFileDialog(nullptr
, i18nc("add indicator", "Add Indicator")
, QDir::homePath()
, QStringLiteral("indicator.latte"));
fileDialog->setFileMode(QFileDialog::AnyFile);
fileDialog->setAcceptMode(QFileDialog::AcceptOpen);
fileDialog->setDefaultSuffix("indicator.latte");
QStringList filters;
filters << QString(i18nc("add indicator file", "Latte Indicator") + "(*.indicator.latte)");
fileDialog->setNameFilters(filters);
connect(fileDialog, &QFileDialog::finished, fileDialog, &QFileDialog::deleteLater);
connect(fileDialog, &QFileDialog::fileSelected, this, [&](const QString & file) {
qDebug() << "Trying to import indicator file ::: " << file;
m_corona->indicatorFactory()->importIndicatorFile(file);
});
fileDialog->open();
}
void Indicator::downloadIndicator()
{
//! call asynchronously in order to not crash when view settings window
//! loses focus and it closes
QTimer::singleShot(0, [this]() {
m_corona->indicatorFactory()->downloadIndicator();
});
}
void Indicator::removeIndicator(QString pluginId)
{ //! call asynchronously in order to not crash when view settings window
//! loses focus and it closes
QTimer::singleShot(0, [this, pluginId]() {
m_corona->indicatorFactory()->removeIndicator(pluginId);
});
}
void Indicator::loadConfig()
{
auto config = m_view->containment()->config().group("Indicator");

View File

@ -56,7 +56,6 @@ class Indicator: public QObject
Q_PROPERTY(bool enabledForApplets READ enabledForApplets WRITE setEnabledForApplets NOTIFY enabledForAppletsChanged)
Q_PROPERTY(bool latteTasksArePresent READ latteTasksArePresent NOTIFY latteTasksArePresentChanged)
Q_PROPERTY(bool pluginIsReady READ pluginIsReady NOTIFY pluginIsReadyChanged)
Q_PROPERTY(bool providesConfigUi READ providesConfigUi NOTIFY providesConfigUiChanged)
Q_PROPERTY(QString type READ type WRITE setType NOTIFY pluginChanged)
Q_PROPERTY(QString customType READ customType NOTIFY customPluginChanged)
@ -99,7 +98,6 @@ public:
bool isCustomIndicator() const;
bool latteTasksArePresent();
bool providesConfigUi() const;
bool pluginIsReady();
@ -125,14 +123,6 @@ public:
void load(QString type);
void unloadIndicators();
public slots:
Q_INVOKABLE void configUiFor(QString type, QQuickItem *parent);
Q_INVOKABLE void addIndicator();
Q_INVOKABLE void downloadIndicator();
Q_INVOKABLE void removeIndicator(QString pluginId);
void hideConfigUi();
void releaseConfigUi();
signals:
void customPluginsChanged();
void enabledChanged();
@ -143,7 +133,6 @@ signals:
void plasmaComponentChanged();
void pluginChanged();
void pluginIsReadyChanged();
void providesConfigUiChanged();
void resourcesChanged();
private:
@ -151,7 +140,6 @@ private:
void saveConfig();
void setPluginIsReady(bool ready);
void setProvidesConfigUi(bool provides);
void setCustomType(QString type);
@ -163,7 +151,6 @@ private:
bool m_enabled{true};
bool m_enabledForApplets{true};
bool m_pluginIsReady{false};
bool m_providesConfigUi{true};
QString m_pluginPath;
QString m_type{"org.kde.latte.default"};
@ -182,9 +169,6 @@ private:
QPointer<IndicatorPart::Resources> m_resources;
QPointer<KDeclarative::ConfigPropertyMap> m_configuration;
QString m_lastCreatedConfigUiType;
QPointer<KDeclarative::QmlObjectSharedEngine> m_lastCreatedConfigUi;
};
}

View File

@ -1,6 +1,7 @@
set(lattedock-app_SRCS
${lattedock-app_SRCS}
${CMAKE_CURRENT_SOURCE_DIR}/canvasconfigview.cpp
${CMAKE_CURRENT_SOURCE_DIR}/indicatoruimanager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/primaryconfigview.cpp
${CMAKE_CURRENT_SOURCE_DIR}/secondaryconfigview.cpp
${CMAKE_CURRENT_SOURCE_DIR}/subconfigview.cpp

View File

@ -0,0 +1,190 @@
/*
* Copyright 2020 Michail Vourlakos <mvourlakos@gmail.com>
*
* This file is part of Latte-Dock
*
* Latte-Dock 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.
*
* Latte-Dock 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, see <http://www.gnu.org/licenses/>.
*/
#include "indicatoruimanager.h"
// local
#include "primaryconfigview.h"
#include "../view.h"
#include "../../lattecorona.h"
#include "../../indicator/factory.h"
// Qt
#include <QFileDialog>
#include <QTimer>
// KDE
#include <KLocalizedString>
#include <KPluginMetaData>
#include <KDeclarative/QmlObjectSharedEngine>
namespace Latte {
namespace ViewPart {
namespace Config {
IndicatorUiManager::IndicatorUiManager(ViewPart::PrimaryConfigView *parent)
: QObject(parent),
m_primary(parent)
{
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
qmlRegisterType<Latte::ViewPart::Config::IndicatorUiManager>();
#else
qmlRegisterAnonymousType<Latte::ViewPart::Config::IndicatorUiManager>("latte-dock", 1);
#endif
}
IndicatorUiManager::~IndicatorUiManager()
{
}
bool IndicatorUiManager::contains(const QString &type)
{
return (index(type) >= 0);
}
int IndicatorUiManager::index(const QString &type)
{
for (int i=0; i<m_uidata.count(); ++i) {
if (m_uidata[i].type == type) {
return i;
}
}
return -1;
}
void IndicatorUiManager::setParentItem(QQuickItem *parentItem)
{
m_parentItem = parentItem;
}
void IndicatorUiManager::hideAllUi()
{
for (int i=0; i<m_uidata.count(); ++i) {
if (m_uidata[i].ui) {
//! config ui has already been created and can be provided again
QQuickItem *qmlItem = qobject_cast<QQuickItem*>(m_uidata[i].ui->rootObject());
if (qmlItem) {
qmlItem->setVisible(false);
}
}
}
}
void IndicatorUiManager::ui(const QString &type, Latte::View *view)
{
if (!m_parentItem) {
return;
}
hideAllUi();
int typeIndex = index(type);
if (typeIndex > -1 && m_uidata[typeIndex].ui) {
m_uidata[typeIndex].ui->rootContext()->setContextProperty(QStringLiteral("indicator"), view->indicator());
m_uidata[typeIndex].view = view;
//! config ui has already been created and can be provided again
QQuickItem *qmlItem = qobject_cast<QQuickItem*>(m_uidata[typeIndex].ui->rootObject());
if (qmlItem) {
qmlItem->setVisible(true);
}
return;
}
//! type needs to be created again
KPluginMetaData metadata = m_primary->corona()->indicatorFactory()->metadata(type);;
if (metadata.isValid()) {
QString uiPath = metadata.value("X-Latte-ConfigUi");
if (!uiPath.isEmpty()) {
IndicatorUiData uidata;
uidata.ui = new KDeclarative::QmlObjectSharedEngine(this);
uidata.pluginPath = metadata.fileName().remove("metadata.desktop");
uidata.type = type;
uidata.view = view;
uidata.ui->setTranslationDomain(QLatin1String("latte_indicator_") + metadata.pluginId());
uidata.ui->setInitializationDelayed(true);
uiPath = uidata.pluginPath + "package/" + uiPath;
uidata.ui->setSource(QUrl::fromLocalFile(uiPath));
uidata.ui->rootContext()->setContextProperty(QStringLiteral("dialog"), m_parentItem);
uidata.ui->rootContext()->setContextProperty(QStringLiteral("indicator"), view->indicator());
uidata.ui->completeInitialization();
QQuickItem *qmlItem = qobject_cast<QQuickItem*>(uidata.ui->rootObject());
if (qmlItem) {
qmlItem->setParentItem(m_parentItem);
}
m_uidata << uidata;
}
}
}
void IndicatorUiManager::addIndicator()
{
QFileDialog *fileDialog = new QFileDialog(nullptr
, i18nc("add indicator", "Add Indicator")
, QDir::homePath()
, QStringLiteral("indicator.latte"));
fileDialog->setFileMode(QFileDialog::AnyFile);
fileDialog->setAcceptMode(QFileDialog::AcceptOpen);
fileDialog->setDefaultSuffix("indicator.latte");
QStringList filters;
filters << QString(i18nc("add indicator file", "Latte Indicator") + "(*.indicator.latte)");
fileDialog->setNameFilters(filters);
connect(fileDialog, &QFileDialog::finished, fileDialog, &QFileDialog::deleteLater);
connect(fileDialog, &QFileDialog::fileSelected, this, [&](const QString & file) {
qDebug() << "Trying to import indicator file ::: " << file;
m_primary->corona()->indicatorFactory()->importIndicatorFile(file);
});
fileDialog->open();
}
void IndicatorUiManager::downloadIndicator()
{
//! call asynchronously in order to not crash when view settings window
//! loses focus and it closes
QTimer::singleShot(0, [this]() {
m_primary->corona()->indicatorFactory()->downloadIndicator();
});
}
void IndicatorUiManager::removeIndicator(QString pluginId)
{ //! call asynchronously in order to not crash when view settings window
//! loses focus and it closes
QTimer::singleShot(0, [this, pluginId]() {
m_primary->corona()->indicatorFactory()->removeIndicator(pluginId);
});
}
}
}
}

View File

@ -0,0 +1,90 @@
/*
* Copyright 2020 Michail Vourlakos <mvourlakos@gmail.com>
*
* This file is part of Latte-Dock
*
* Latte-Dock 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.
*
* Latte-Dock 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef INDICATORUIMANAGER_H
#define INDICATORUIMANAGER_H
//Qt
#include <QList>
#include <QObject>
#include <QQuickItem>
#include <QPointer>
namespace KDeclarative
{
class QmlObjectSharedEngine;
}
namespace Latte {
class View;
}
namespace Latte {
namespace ViewPart {
class PrimaryConfigView;
}
}
namespace Latte {
namespace ViewPart {
namespace Config {
struct IndicatorUiData
{
QString type;
QString pluginPath;
QPointer<Latte::View> view;
QPointer<KDeclarative::QmlObjectSharedEngine> ui;
};
class IndicatorUiManager : public QObject
{
Q_OBJECT
public:
IndicatorUiManager(ViewPart::PrimaryConfigView *parent);
~IndicatorUiManager() override;
public slots:
Q_INVOKABLE void addIndicator();
Q_INVOKABLE void downloadIndicator();
Q_INVOKABLE void removeIndicator(QString pluginId);
Q_INVOKABLE void setParentItem(QQuickItem *parentItem);
Q_INVOKABLE void ui(const QString &type, Latte::View *view);
private:
bool contains(const QString &type);
int index(const QString &type);
void hideAllUi();
private:
QQuickItem *m_parentItem{nullptr};
PrimaryConfigView *m_primary{nullptr};
QList<IndicatorUiData> m_uidata;
};
}
}
}
#endif

View File

@ -23,6 +23,7 @@
// local
#include <config-latte.h>
#include "canvasconfigview.h"
#include "indicatoruimanager.h"
#include "secondaryconfigview.h"
#include "../effects.h"
#include "../panelshadows_p.h"
@ -59,7 +60,8 @@ namespace Latte {
namespace ViewPart {
PrimaryConfigView::PrimaryConfigView(Latte::View *view)
: SubConfigView(view, QString("#primaryconfigview#"))
: SubConfigView(view, QString("#primaryconfigview#")),
m_indicatorUiManager(new Config::IndicatorUiManager(this))
{
connect(this, &QQuickView::widthChanged, this, &PrimaryConfigView::updateEffects);
connect(this, &QQuickView::heightChanged, this, &PrimaryConfigView::updateEffects);
@ -106,11 +108,6 @@ PrimaryConfigView::~PrimaryConfigView()
if (m_secConfigView) {
delete m_secConfigView;
}
if (m_latteView && m_latteView->indicator()) {
//! destroy indicator config ui when the configuration window is closed
m_latteView->indicator()->releaseConfigUi();
}
}
void PrimaryConfigView::init()
@ -124,6 +121,11 @@ void PrimaryConfigView::init()
syncGeometry();
}
Config::IndicatorUiManager *PrimaryConfigView::indicatorUiManager()
{
return m_indicatorUiManager;
}
void PrimaryConfigView::setOnActivities(QStringList activities)
{
m_corona->wm()->setWindowOnActivities(*this, activities);
@ -244,11 +246,6 @@ void PrimaryConfigView::initParentView(Latte::View *view)
{
setIsReady(false);
if (m_latteView && m_latteView->indicator()) {
//! hide indicator config ui when parent view is changing
m_latteView->indicator()->hideConfigUi();
}
SubConfigView::initParentView(view);
viewconnections << connect(m_latteView, &Latte::View::layoutChanged, this, [this]() {

View File

@ -59,6 +59,10 @@ namespace Latte {
namespace ViewPart {
class CanvasConfigView;
class SecondaryConfigView;
namespace Config{
class IndicatorUiManager;
}
}
}
@ -75,6 +79,8 @@ class PrimaryConfigView : public SubConfigView
Q_PROPERTY(QRect availableScreenGeometry READ availableScreenGeometry NOTIFY availableScreenGeometryChanged)
Q_PROPERTY(Latte::ViewPart::Config::IndicatorUiManager *indicatorUiManager READ indicatorUiManager NOTIFY indicatorUiManagerChanged)
public:
enum ConfigViewType
{
@ -98,6 +104,8 @@ public:
QRect availableScreenGeometry() const;
QRect geometryWhenVisible() const;
Config::IndicatorUiManager *indicatorUiManager();
void setParentView(Latte::View *view, const bool &immediate = false) override;
void setOnActivities(QStringList activities);
@ -114,6 +122,7 @@ public slots:
signals:
void availableScreenGeometryChanged();
void inAdvancedModeChanged();
void indicatorUiManagerChanged();
void isReadyChanged();
void raiseDocksTemporaryChanged();
void showInlinePropertiesChanged();
@ -167,6 +176,8 @@ private:
QPointer<SecondaryConfigView> m_secConfigView;
QPointer<CanvasConfigView> m_canvasConfigView;
Config::IndicatorUiManager *m_indicatorUiManager{nullptr};
//only for the mask on disabled compositing, not to actually paint
Plasma::FrameSvg *m_background{nullptr};
};

View File

@ -158,6 +158,11 @@ Latte::WindowSystem::WindowId SubConfigView::trackedWindowId()
return !KWindowSystem::isPlatformWayland() ? winId() : m_waylandWindowId;
}
Latte::Corona *SubConfigView::corona() const
{
return m_corona;
}
Latte::View *SubConfigView::parentView() const
{
return m_latteView;

View File

@ -63,7 +63,7 @@ public:
Plasma::FrameSvg::EnabledBorders enabledBorders() const;
Latte::Corona *corona() const;
Latte::View *parentView() const;
virtual void setParentView(Latte::View *view, const bool &immediate = false);
virtual void showAfter(int msecs = 0);

View File

@ -470,7 +470,6 @@ PlasmaComponents.Page {
Layout.fillWidth: true
Layout.topMargin: units.smallSpacing * 2
spacing: 0
visible: latteView.indicator.providesConfigUi
enabled: latteView.indicator.enabled
// @since 0.10.0
@ -479,19 +478,20 @@ PlasmaComponents.Page {
readonly property int optionsWidth: dialog.optionsWidth
Component.onCompleted: {
latteView.indicator.configUiFor(latteView.indicator.type, indicatorSpecificOptions);
viewConfig.indicatorUiManager.setParentItem(indicatorSpecificOptions);
viewConfig.indicatorUiManager.ui(latteView.indicator.type, latteView);
}
Connections {
target: latteView.indicator
onPluginChanged: latteView.indicator.configUiFor(latteView.indicator.type, indicatorSpecificOptions);
onPluginChanged: viewConfig.indicatorUiManager.ui(latteView.indicator.type, latteView);
}
Connections {
target: viewConfig
onIsReadyChanged: {
if (viewConfig.isReady) {
latteView.indicator.configUiFor(latteView.indicator.type, indicatorSpecificOptions);
viewConfig.indicatorUiManager.ui(latteView.indicator.type, latteView);
}
}
}

View File

@ -78,9 +78,9 @@ LatteComponents.ComboBoxButton{
if (index>=0) {
var item = actionsModel.get(index);
if (item.pluginId === "add:") {
latteView.indicator.addIndicator();
viewConfig.indicatorUiManager.addIndicator();
} else if (item.pluginId === "download:") {
latteView.indicator.downloadIndicator();
viewConfig.indicatorUiManager.downloadIndicator();
} else {
latteView.indicator.type = item.pluginId;
}
@ -94,7 +94,7 @@ LatteComponents.ComboBoxButton{
var item = actionsModel.get(index);
var pluginId = item.pluginId;
if (latteView.indicator.customLocalPluginIds.indexOf(pluginId)>=0) {
latteView.indicator.removeIndicator(pluginId);
viewConfig.indicatorUiManager.removeIndicator(pluginId);
custom.comboBox.popup.close();
}
}