feat(panel): 增加插件排序和动态卸载功能

This commit is contained in:
hewenfei 2024-04-07 16:29:16 +08:00
parent 58b9baeaef
commit 08d3d9429f
6 changed files with 289 additions and 15 deletions

View File

@ -48,6 +48,8 @@ set(PROJECT_SOURCES
src/general-config-define.h
src/screens-manager.cpp
src/screens-manager.h
src/view/widget-model.cpp
src/view/widget-model.h
)
qt5_generate_repc(PROJECT_SOURCES src/remote-config.rep SOURCE)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)

View File

@ -5,6 +5,7 @@ import org.ukui.quick.widgets 1.0
import org.ukui.quick.container 1.0
import org.ukui.quick.items 1.0
import org.ukui.quick.platform 1.0
import org.ukui.panel.impl 1.0 as Panel
WidgetContainerItem {
id: containerItem
@ -40,7 +41,11 @@ WidgetContainerItem {
Repeater {
id: repeater
model: containerItem.widgetItemModel
model: Panel.WidgetSortModel {
// TODO: use config
widgetOrder: widgetsOrder
sourceModel: containerItem.widgetItemModel
}
delegate: widgetLoaderComponent
}
}

View File

@ -15,6 +15,7 @@
#include <config-loader.h>
#include <widget-container-item.h>
#include "general-config-define.h"
#include "widget-model.h"
#define DEFAULT_PANEL_SIZE 48
static const QString WIDGETS_KEY = QStringLiteral("widgets");
@ -46,6 +47,9 @@ Panel::Panel(Screen *screen, const QString &id, QWindow *parent)
m_id(id),
m_container(new UkuiQuick::WidgetContainer(QStringLiteral("ukui-panel"), id, this))
{
qRegisterMetaType<QList<int>>();
qmlRegisterType<UkuiPanel::WidgetSortModel>("org.ukui.panel.impl", 1, 0, "WidgetSortModel");
setColor(Qt::transparent);
setFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
@ -61,6 +65,7 @@ Panel::Panel(Screen *screen, const QString &id, QWindow *parent)
// items
loadContainerItem();
initWidgets();
loadActions();
KWindowEffects::enableBlurBehind(this);
kdk::WindowManager::setSkipSwitcher(this, true);
@ -147,8 +152,6 @@ void Panel::initContainer()
// position
setPosition(UkuiQuick::Types::Pos(map.value(QStringLiteral("position"))));
loadActions();
}
void Panel::setPosition(UkuiQuick::Types::Pos position)
@ -199,18 +202,101 @@ void Panel::loadContainerItem()
setSource(QUrl("qrc:///Container.qml"));
}
void Panel::initWidgets()
void Panel::loadWidgetsConfig()
{
QStringList loadingWidgets = DEFAULT_LOADING_WIDGETS;
QVariant widgets = m_config->getValue(WIDGETS_KEY);
if(widgets.isNull()) {
m_config->setValue(WIDGETS_KEY, DEFAULT_LOADING_WIDGETS);
QVariant widgets = m_config->getValue(QStringLiteral("widgets"));
QStringList widgetList, widgetsOrder;
if (widgets.isNull()) {
for (const auto &widget : DEFAULT_LOADING_WIDGETS) {
int instanceId = widgetList.size();
widgetsOrder.append(QString::number(instanceId));
widgetList.append(widget + QStringLiteral(":") + widgetsOrder.last());
m_widgetMap.insert(instanceId, widget);
m_widgetsOrder.append(instanceId);
}
m_config->setValue(QStringLiteral("widgets"), widgetList);
m_config->setValue(QStringLiteral("widgetsOrder"), widgetsOrder);
} else {
loadingWidgets = widgets.toStringList();
widgetList = widgets.toStringList();
widgetsOrder = m_config->getValue(QStringLiteral("widgetsOrder")).toStringList();
bool ok = false;
for (const auto &item : widgetList) {
QStringList tmp = item.split(QStringLiteral(":"));
if (tmp.size() != 2) {
continue;
}
int instanceId = tmp.last().toInt(&ok);
if (ok) {
m_widgetMap.insert(instanceId, tmp.first());
if (!widgetsOrder.contains(tmp.last())) {
widgetsOrder << tmp.last();
}
}
}
for (const auto &item : widgetsOrder) {
int instanceId = item.toInt(&ok);
if (ok) {
m_widgetsOrder << instanceId;
}
}
m_config->setValue(QStringLiteral("widgetsOrder"), widgetsOrder);
}
for (const auto &id : loadingWidgets) {
m_container->addWidget(id);
// 禁用列表
m_disabledWidgets = m_config->getValue(QStringLiteral("disabledWidgets")).toStringList();
// widgetsOrder
rootContext()->setContextProperty("widgetsOrder", QVariant::fromValue(m_widgetsOrder));
}
void Panel::initWidgets()
{
loadWidgetsConfig();
// 加载Widget
QMapIterator<int, QString> iterator(m_widgetMap);
while (iterator.hasNext()) {
iterator.next();
if (m_disabledWidgets.contains(iterator.value())) {
continue;
}
m_container->addWidget(iterator.value(), iterator.key());
}
// 卸载插件选项
QStringList canRemove;
canRemove << QStringLiteral("org.ukui.panel.search");
canRemove << QStringLiteral("org.ukui.panel.taskView");
QStringList widgets = m_widgetMap.values();
widgets.removeDuplicates();
for (const auto &wid : widgets) {
if (canRemove.contains(wid)) {
UkuiQuick::WidgetMetadata metadata = UkuiQuick::WidgetContainer::widgetLoader().loadMetadata(wid);
if (!metadata.isValid()) {
continue;
}
auto action = new QAction(metadata.name());
action->setProperty("widget", wid);
action->setCheckable(true);
action->setChecked(!m_disabledWidgets.contains(wid));
m_widgetActions << action;
connect(action, &QAction::triggered, this, [this, action] {
widgetActionTriggered(action);
});
}
}
}
@ -330,18 +416,56 @@ void Panel::setPanelPolicy(GeneralConfigDefine::PanelSizePolicy sizePolicy)
}
}
void Panel::widgetActionTriggered(const QAction *action)
{
QString id = action->property("widget").toString();
if (id.isEmpty()) {
return;
}
if (action->isChecked()) {
// 启用
m_disabledWidgets.removeAll(id);
// 重新激活全部widget
QMapIterator<int, QString> iterator(m_widgetMap);
while (iterator.hasNext()) {
iterator.next();
if (iterator.value() == id) {
container()->addWidget(iterator.value(), iterator.key());
}
}
} else {
// 禁用
m_disabledWidgets.append(id);
// 卸载全部widget
QVector<UkuiQuick::Widget *> widgets = m_container->widgets();
for (const auto &item : widgets) {
if (item->id() == id) {
m_container->removeWidget(item);
}
}
}
m_config->setValue(QStringLiteral("disabledWidgets"), m_disabledWidgets);
}
void Panel::loadActions()
{
QList<QAction *> actions;
// widget操作
actions << m_widgetActions;
// 分割线
auto *separator = new QAction(this);
separator->setSeparator(true);
actions << separator;
// actions
initSizeAction();
initPositionAction();
// auto *separator = new QAction(this);
// separator->setSeparator(true);
// actions << separator;
// 调整大小
actions << m_sizeAction;
// 调整位置

View File

@ -30,9 +30,13 @@ private Q_SLOTS:
void setPanelSize(int size);
void setPanelPolicy(GeneralConfigDefine::PanelSizePolicy sizePolicy);
// widget opt
void widgetActionTriggered(const QAction *);
private:
void initContainer();
void loadContainerItem();
void loadWidgetsConfig();
void initWidgets();
void updateGeometry();
void refreshRect();
@ -52,8 +56,14 @@ private:
QAction *m_sizeAction {nullptr};
QAction *m_positionAction {nullptr};
QList<QAction*> m_widgetActions;
QMap<int, QString> m_widgetMap;
QStringList m_disabledWidgets;
QList<int> m_widgetsOrder;
};
} // UkuiPanel
Q_DECLARE_METATYPE(QList<int>)
#endif //UKUI_PANEL_PANEL_H

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*
* Authors: hxf <hewenfei@kylinos.cn>
*
*/
#include "widget-model.h"
#include <widget.h>
#include <widget-item.h>
#include <widget-container-item.h>
namespace UkuiPanel {
WidgetSortModel::WidgetSortModel(QObject *parent) : QSortFilterProxyModel(parent)
{
}
bool WidgetSortModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
auto leftItem = source_left.data(UkuiQuick::WidgetItemModel::WidgetItemRole).value<UkuiQuick::WidgetItem *>();
auto rightItem = source_right.data(UkuiQuick::WidgetItemModel::WidgetItemRole).value<UkuiQuick::WidgetItem *>();
int lIdx = m_widgetOrder.indexOf(leftItem->widget()->instanceId());
int rIdx = m_widgetOrder.indexOf(rightItem->widget()->instanceId());
if (lIdx < 0) {
return false;
}
return lIdx < rIdx;
}
bool WidgetSortModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
}
void WidgetSortModel::setSourceModel(QAbstractItemModel *sourceModel)
{
QSortFilterProxyModel::setSourceModel(sourceModel);
QSortFilterProxyModel::sort(0);
}
QList<int> WidgetSortModel::widgetOrder() const
{
return m_widgetOrder;
}
void WidgetSortModel::setWidgetOrder(const QList<int> &order)
{
m_widgetOrder = order;
invalidate();
Q_EMIT widgetOrderChanged();
}
} // UkuiPanel

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2024, KylinSoft Co., Ltd.
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*
* Authors: hxf <hewenfei@kylinos.cn>
*
*/
#ifndef UKUI_PANEL_WIDGET_MODEL_H
#define UKUI_PANEL_WIDGET_MODEL_H
#include <QSortFilterProxyModel>
#include <QStringList>
#include <QPair>
#include <QPersistentModelIndex>
namespace UkuiQuick{
class WidgetItem;
}
namespace UkuiPanel {
class WidgetSortModel : public QSortFilterProxyModel
{
Q_OBJECT
Q_PROPERTY(QList<int> widgetOrder READ widgetOrder WRITE setWidgetOrder NOTIFY widgetOrderChanged)
public:
explicit WidgetSortModel(QObject *parent = nullptr);
QList<int> widgetOrder() const;
void setWidgetOrder(const QList<int> &order);
void setSourceModel(QAbstractItemModel *sourceModel) override;
protected:
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
Q_SIGNALS:
void widgetOrderChanged();
private:
QList<int> m_widgetOrder;
};
} // UkuiPanel
#endif //UKUI_PANEL_WIDGET_MODEL_H