feat: 修改插件接口,增加Factory整合widget和菜单插件接口
This commit is contained in:
parent
3cfba996d4
commit
3fc780d666
|
@ -121,7 +121,13 @@ set(SOURCE_FILES
|
|||
src/menu/menu-manager.cpp src/menu/menu-manager.h
|
||||
src/items/theme-icon.h src/items/theme-icon.cpp
|
||||
src/settings/user-config.cpp src/settings/user-config.h
|
||||
)
|
||||
src/extension/widget-extension.cpp src/extension/widget-extension.h
|
||||
src/extension/context-menu-extension.cpp src/extension/context-menu-extension.h
|
||||
src/extension/menu-extension-loader.cpp src/extension/menu-extension-loader.h
|
||||
src/extension/menu-extension-plugin.cpp src/extension/menu-extension-plugin.h
|
||||
src/extension/widget-extension-model.cpp src/extension/widget-extension-model.h
|
||||
src/extension/widget-model.cpp src/extension/widget-model.h
|
||||
)
|
||||
|
||||
|
||||
if(COMMAND qt_add_dbus_adaptor)
|
||||
|
@ -141,6 +147,9 @@ set(LIBRARY_HEADERS
|
|||
src/data-entity.h
|
||||
src/menu/menu-provider.h
|
||||
src/extension/menu-extension-iface.h
|
||||
src/extension/menu-extension-plugin.h
|
||||
src/extension/widget-extension.h
|
||||
src/extension/context-menu-extension.h
|
||||
)
|
||||
|
||||
# qrc文件
|
||||
|
|
|
@ -29,54 +29,103 @@ import org.ukui.menu.extension 1.0
|
|||
|
||||
Item {
|
||||
ColumnLayout {
|
||||
id: sidebarLayout
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 12
|
||||
spacing: 0
|
||||
spacing: 5
|
||||
|
||||
Item {
|
||||
id: sidebarTopBar
|
||||
// header
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 40
|
||||
Layout.rightMargin: 12
|
||||
Layout.leftMargin: 12
|
||||
height: 40
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 4
|
||||
anchors.leftMargin: 12
|
||||
anchors.rightMargin:12
|
||||
spacing: 0
|
||||
|
||||
ListView {
|
||||
id: extensionInfoList
|
||||
|
||||
id: widgetList
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.leftMargin: 4
|
||||
Layout.rightMargin: 4
|
||||
|
||||
clip: true
|
||||
spacing: 24
|
||||
interactive: false
|
||||
orientation: ListView.Horizontal
|
||||
model: extensionManager.extensionModel()
|
||||
delegate: extensionInfoDelegate
|
||||
|
||||
function send(data) {
|
||||
if (currentItem !== null) {
|
||||
model.send(currentIndex, data);
|
||||
}
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
if (currentItem !== null) {
|
||||
currentItem.select();
|
||||
}
|
||||
}
|
||||
model: WidgetModel {}
|
||||
delegate: Component {
|
||||
// 插件信息
|
||||
UkuiItems.StyleBackground {
|
||||
useStyleTransparency: false
|
||||
paletteRole: Palette.Highlight
|
||||
alpha: 0
|
||||
radius: UkuiItems.Theme.minRadius
|
||||
borderColor: Palette.Highlight
|
||||
border.width: activeFocus ? 2 : 0
|
||||
|
||||
property var extensionData: model.data
|
||||
property var extensionOptions: model.options
|
||||
width: styleText.width
|
||||
height: ListView.view ? ListView.view.height : 0
|
||||
|
||||
activeFocusOnTab: true
|
||||
KeyNavigation.down: widgetLoader
|
||||
Keys.onPressed: {
|
||||
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
|
||||
widgetList.currentIndex = model.index;
|
||||
EventTrack.sendClickEvent("switch_plugin", "Sidebar", {"plugin": model.name});
|
||||
}
|
||||
}
|
||||
|
||||
onExtensionDataChanged: {
|
||||
if (widgetLoader.source === model.main) {
|
||||
widgetLoader.item.extensionData = extensionData;
|
||||
}
|
||||
}
|
||||
|
||||
function select() {
|
||||
if (widgetLoader.source !== model.main) {
|
||||
widgetLoader.setSource(model.main, {extensionData: extensionData});
|
||||
}
|
||||
}
|
||||
|
||||
UkuiItems.StyleText {
|
||||
height: parent.height
|
||||
id: styleText
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.bold: parent.ListView.isCurrentItem
|
||||
|
||||
paletteRole: parent.ListView.isCurrentItem ? UkuiItems.Theme.Highlight: UkuiItems.Theme.Text
|
||||
text: model.name
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
normalUI.focusToFalse();
|
||||
widgetList.currentIndex = model.index;
|
||||
EventTrack.sendClickEvent("switch_plugin", "Sidebar", {"plugin": model.name});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: extensionMenuLoader
|
||||
visible: sourceComponent !== undefined
|
||||
id: widgetMenuLoader
|
||||
Layout.preferredWidth: 34
|
||||
Layout.preferredHeight: 34
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
@ -84,100 +133,39 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Loader {
|
||||
id: widgetLoader
|
||||
// 加载插件区域
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
clip: true
|
||||
|
||||
Loader {
|
||||
id: extensionLoader
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
onLoaded: {
|
||||
item.send.connect(extensionInfoList.send);
|
||||
// sidebarLayout.updateSidebarLayout(extensionInfoList.currentItem.extensionOptions);
|
||||
updateMenu();
|
||||
item.extensionMenuChanged.connect(updateMenu);
|
||||
}
|
||||
Keys.onTabPressed: {
|
||||
extensionInfoList.focus = true
|
||||
}
|
||||
|
||||
function updateMenu() {
|
||||
if (item === null) {
|
||||
return;
|
||||
}
|
||||
if (item.extensionMenu !== null) {
|
||||
extensionMenuLoader.sourceComponent = item.extensionMenu;
|
||||
} else {
|
||||
extensionMenuLoader.sourceComponent = undefined;
|
||||
}
|
||||
}
|
||||
onLoaded: {
|
||||
item.send.connect(widgetList.send);
|
||||
// sidebarLayout.updateSidebarLayout(widgetList.currentItem.extensionOptions);
|
||||
updateMenu();
|
||||
item.extensionMenuChanged.connect(updateMenu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: extensionInfoDelegate
|
||||
|
||||
AppControls2.StyleBackground {
|
||||
useStyleTransparent: false
|
||||
paletteRole: Palette.Highlight
|
||||
alpha: 0
|
||||
radius: UkuiItems.Theme.minRadius
|
||||
borderColor: Palette.Highlight
|
||||
border.width: activeFocus ? 2 : 0
|
||||
|
||||
property var extensionData: model.data
|
||||
property var extensionOptions: model.options
|
||||
width: styleText.width
|
||||
height: ListView.view ? ListView.view.height : 0
|
||||
|
||||
activeFocusOnTab: true
|
||||
KeyNavigation.down: extensionLoader
|
||||
Keys.onPressed: {
|
||||
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
|
||||
ListView.view.currentIndex = model.index;
|
||||
EventTrack.sendClickEvent("switch_plugin", "Sidebar", {"plugin": model.name});
|
||||
}
|
||||
Keys.onTabPressed: {
|
||||
widgetList.focus = true
|
||||
}
|
||||
|
||||
onExtensionDataChanged: {
|
||||
if (extensionLoader.source === model.url) {
|
||||
extensionLoader.item.extensionData = extensionData;
|
||||
function updateMenu() {
|
||||
if (item === null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function select() {
|
||||
if (extensionLoader.source !== model.url) {
|
||||
extensionLoader.setSource(model.url, {extensionData: extensionData});
|
||||
}
|
||||
}
|
||||
|
||||
UkuiItems.StyleText {
|
||||
height: parent.height
|
||||
id: styleText
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.bold: parent.ListView.isCurrentItem
|
||||
|
||||
paletteRole: parent.ListView.isCurrentItem ? UkuiItems.Theme.Highlight: UkuiItems.Theme.Text
|
||||
text: model.name
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
normalUI.focusToFalse();
|
||||
parent.ListView.view.currentIndex = model.index;
|
||||
EventTrack.sendClickEvent("switch_plugin", "Sidebar", {"plugin": model.name});
|
||||
if (item.extensionMenu !== null) {
|
||||
widgetMenuLoader.sourceComponent = item.extensionMenu;
|
||||
} else {
|
||||
widgetMenuLoader.sourceComponent = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (extensionInfoList.count > 0) {
|
||||
extensionInfoList.currentIndex = 0;
|
||||
if (widgetList.count > 0) {
|
||||
widgetList.currentIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (C) 2023, 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "context-menu-extension.h"
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
int ContextMenuExtension::index() const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // UkuiMenu
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (C) 2023, 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UKUI_MENU_CONTEXT_MENU_EXTENSION_H
|
||||
#define UKUI_MENU_CONTEXT_MENU_EXTENSION_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QMenu>
|
||||
#include "data-entity.h"
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
class MenuInfo
|
||||
{
|
||||
Q_GADGET
|
||||
public:
|
||||
enum Location {
|
||||
AppList = 0, /**< 小屏幕的应用列表 */
|
||||
Extension, /**< 扩展页 */
|
||||
FolderPage, /**< 文件夹页面 */
|
||||
FullScreen, /**< 全屏应用列表 */
|
||||
FullScreenFolder, /**< 全屏文件夹页面 */
|
||||
};
|
||||
Q_ENUM(Location)
|
||||
};
|
||||
|
||||
/**
|
||||
* @class ContextMenuExtension
|
||||
*
|
||||
* 开始菜单应用列表的上下文菜单扩展插件
|
||||
*/
|
||||
class ContextMenuExtension
|
||||
{
|
||||
public:
|
||||
virtual ~ContextMenuExtension() = default;
|
||||
/**
|
||||
* 控制菜单项显示在哪个位置
|
||||
* 对于第三方项目们应该选择-1,或者大于1000的值
|
||||
* @return -1:表示随机放在最后
|
||||
*/
|
||||
virtual int index() const;
|
||||
|
||||
/**
|
||||
* 根据data生成action,或者子菜单
|
||||
*
|
||||
* @param data app信息
|
||||
* @param parent action最终显示的QMenu
|
||||
* @param location 请求菜单的位置
|
||||
* @param locationId 位置的描述信息,可选的值有:all,category,letterSort和favorite等插件的id
|
||||
* @return
|
||||
*/
|
||||
virtual QList<QAction*> actions(const DataEntity &data, QMenu *parent, const MenuInfo::Location &location, const QString &locationId) = 0;
|
||||
};
|
||||
|
||||
} // UkuiMenu
|
||||
|
||||
#endif //UKUI_MENU_CONTEXT_MENU_EXTENSION_H
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (C) 2023, 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "menu-extension-loader.h"
|
||||
#include "menu-extension-plugin.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QPluginLoader>
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
QHash<QString, MenuExtensionPlugin*> MenuExtensionLoader::plugins = QHash<QString, MenuExtensionPlugin*>();
|
||||
|
||||
MenuExtensionLoader *MenuExtensionLoader::instance()
|
||||
{
|
||||
static MenuExtensionLoader loader;
|
||||
return &loader;
|
||||
}
|
||||
|
||||
MenuExtensionLoader::MenuExtensionLoader()
|
||||
{
|
||||
// setBlackList({});
|
||||
load();
|
||||
}
|
||||
|
||||
void MenuExtensionLoader::load()
|
||||
{
|
||||
loadInternalExtension();
|
||||
loadExtensionFromDisk();
|
||||
|
||||
expand();
|
||||
}
|
||||
|
||||
void MenuExtensionLoader::loadInternalExtension()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MenuExtensionLoader::loadExtensionFromDisk()
|
||||
{
|
||||
QDir pluginsDir(UKUI_MENU_EXTENSION_DIR);
|
||||
for(const QString& fileName : pluginsDir.entryList({"*.so"},QDir::Files)) {
|
||||
QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
|
||||
QJsonObject metaData = pluginLoader.metaData().value("MetaData").toObject();
|
||||
QString type = metaData.value("Type").toString();
|
||||
QString version = metaData.value("Version").toString();
|
||||
if(type != UKUI_MENU_EXTENSION_I_FACE_TYPE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(version != UKUI_MENU_EXTENSION_I_FACE_VERSION) {
|
||||
qWarning() << "UKUI_MENU_EXTENSION version check failed:" << fileName << "version:" << version << "iface version : " << UKUI_MENU_EXTENSION_I_FACE_VERSION;
|
||||
continue;
|
||||
}
|
||||
|
||||
QObject *obj = pluginLoader.instance();
|
||||
if (!obj) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MenuExtensionPlugin *plugin = qobject_cast<MenuExtensionPlugin*>(obj);
|
||||
if (!plugin) {
|
||||
continue;
|
||||
}
|
||||
|
||||
registerExtension(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuExtensionLoader::expand()
|
||||
{
|
||||
for (const auto &plugin : MenuExtensionLoader::plugins) {
|
||||
// qDebug() << "Expand Extension:" << plugin->id();
|
||||
WidgetExtension *widget = plugin->createWidgetExtension();
|
||||
if (widget) {
|
||||
// register widget.
|
||||
m_widgets.append(widget);
|
||||
}
|
||||
|
||||
ContextMenuExtension *contextMenu = plugin->createContextMenuExtension();
|
||||
if (contextMenu) {
|
||||
// 注册菜单
|
||||
m_menus.append(contextMenu);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(m_widgets.begin(), m_widgets.end(), [] (const WidgetExtension *a, const WidgetExtension *b) {
|
||||
return a->index() <= b->index();
|
||||
});
|
||||
|
||||
std::sort(m_menus.begin(), m_menus.end(), [] (const ContextMenuExtension *a, const ContextMenuExtension *b) {
|
||||
return a->index() <= b->index();
|
||||
});
|
||||
}
|
||||
|
||||
void MenuExtensionLoader::setBlackList(const QStringList &blackList)
|
||||
{
|
||||
m_blackList = blackList;
|
||||
}
|
||||
|
||||
QList<WidgetExtension *> MenuExtensionLoader::widgets() const
|
||||
{
|
||||
return m_widgets;
|
||||
}
|
||||
|
||||
QList<ContextMenuExtension *> MenuExtensionLoader::menus() const
|
||||
{
|
||||
return m_menus;
|
||||
}
|
||||
|
||||
void MenuExtensionLoader::registerExtension(MenuExtensionPlugin *plugin)
|
||||
{
|
||||
QString id = plugin->id();
|
||||
if (m_blackList.contains(id) || MenuExtensionLoader::plugins.contains(id)) {
|
||||
delete plugin;
|
||||
return;
|
||||
}
|
||||
|
||||
MenuExtensionLoader::plugins.insert(id, plugin);
|
||||
}
|
||||
|
||||
} // UkuiMenu
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (C) 2023, 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UKUI_MENU_MENU_EXTENSION_LOADER_H
|
||||
#define UKUI_MENU_MENU_EXTENSION_LOADER_H
|
||||
|
||||
#include <QHash>
|
||||
#include <QString>
|
||||
|
||||
#include "widget-extension.h"
|
||||
#include "context-menu-extension.h"
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
class MenuExtensionPlugin;
|
||||
|
||||
class MenuExtensionLoader
|
||||
{
|
||||
public:
|
||||
static MenuExtensionLoader *instance();
|
||||
|
||||
QList<WidgetExtension*> widgets() const;
|
||||
QList<ContextMenuExtension*> menus() const;
|
||||
|
||||
private:
|
||||
MenuExtensionLoader();
|
||||
void loadInternalExtension();
|
||||
void loadExtensionFromDisk();
|
||||
|
||||
void setBlackList(const QStringList &blackList);
|
||||
void load();
|
||||
void expand();
|
||||
|
||||
void registerExtension(MenuExtensionPlugin *plugin);
|
||||
|
||||
private:
|
||||
QStringList m_blackList;
|
||||
QList<WidgetExtension*> m_widgets;
|
||||
QList<ContextMenuExtension*> m_menus;
|
||||
static QHash<QString, MenuExtensionPlugin*> plugins;
|
||||
};
|
||||
|
||||
} // UkuiMenu
|
||||
|
||||
#endif //UKUI_MENU_MENU_EXTENSION_LOADER_H
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (C) 2023, 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "menu-extension-plugin.h"
|
||||
|
||||
UkuiMenu::MenuExtensionPlugin::MenuExtensionPlugin(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
UkuiMenu::MenuExtensionPlugin::~MenuExtensionPlugin() = default;
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2023, 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UKUI_MENU_MENU_EXTENSION_PLUGIN_H
|
||||
#define UKUI_MENU_MENU_EXTENSION_PLUGIN_H
|
||||
|
||||
#define UKUI_MENU_EXTENSION_I_FACE_TYPE "UKUI_MENU_EXTENSION"
|
||||
#define UKUI_MENU_EXTENSION_I_FACE_IID "org.ukui.menu.extension"
|
||||
#define UKUI_MENU_EXTENSION_I_FACE_VERSION "1.0.2"
|
||||
|
||||
#include <QtPlugin>
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
class WidgetExtension;
|
||||
class ContextMenuExtension;
|
||||
|
||||
class Q_DECL_EXPORT MenuExtensionPlugin : public QObject
|
||||
{
|
||||
public:
|
||||
explicit MenuExtensionPlugin(QObject *parent = nullptr);
|
||||
~MenuExtensionPlugin() override;
|
||||
|
||||
/**
|
||||
* 插件的唯一id,会被用于区分插件
|
||||
* @return 唯一id
|
||||
*/
|
||||
virtual QString id() = 0;
|
||||
|
||||
/**
|
||||
* 创建一个Widget扩展
|
||||
* @return 返回nullptr代表不生产此插件
|
||||
*/
|
||||
virtual WidgetExtension *createWidgetExtension() = 0;
|
||||
|
||||
/**
|
||||
* 创建上下文菜单扩展
|
||||
* @return 返回nullptr代表不生产此插件
|
||||
*/
|
||||
virtual ContextMenuExtension *createContextMenuExtension() = 0;
|
||||
};
|
||||
|
||||
} // UkuiMenu
|
||||
|
||||
Q_DECLARE_INTERFACE(UkuiMenu::MenuExtensionPlugin, UKUI_MENU_EXTENSION_I_FACE_IID)
|
||||
|
||||
#endif //UKUI_MENU_MENU_EXTENSION_PLUGIN_H
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (C) 2023, 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "widget-extension-model.h"
|
||||
#include "menu-extension-loader.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
WidgetExtensionModel::WidgetExtensionModel(QObject *parent) : QAbstractListModel(parent)
|
||||
{
|
||||
m_widgets = MenuExtensionLoader::instance()->widgets();
|
||||
|
||||
for (int i = 0; i < m_widgets.size(); ++i) {
|
||||
connect(m_widgets.at(i), &WidgetExtension::dataUpdated, this, [i, this] {
|
||||
Q_EMIT dataChanged(QAbstractListModel::index(i), QAbstractListModel::index(i), {WidgetMetadata::Data});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex WidgetExtensionModel::parent(const QModelIndex &child) const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
int WidgetExtensionModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return m_widgets.count();
|
||||
}
|
||||
|
||||
int WidgetExtensionModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
QVariant WidgetExtensionModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
int row = index.row();
|
||||
WidgetExtension *widget = m_widgets.at(row);
|
||||
|
||||
auto key = WidgetMetadata::Key(role);
|
||||
switch (key) {
|
||||
case WidgetMetadata::Id:
|
||||
case WidgetMetadata::Icon:
|
||||
case WidgetMetadata::Name:
|
||||
case WidgetMetadata::Tooltip:
|
||||
case WidgetMetadata::Version:
|
||||
case WidgetMetadata::Description:
|
||||
case WidgetMetadata::Main:
|
||||
case WidgetMetadata::Type:
|
||||
case WidgetMetadata::Flag:
|
||||
return widget->metadata().value(key, {});
|
||||
case WidgetMetadata::Data:
|
||||
return widget->data();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> WidgetExtensionModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> hash;
|
||||
|
||||
hash.insert(WidgetMetadata::Id, "id");
|
||||
hash.insert(WidgetMetadata::Icon, "icon");
|
||||
hash.insert(WidgetMetadata::Name, "name");
|
||||
hash.insert(WidgetMetadata::Tooltip, "tooltip");
|
||||
hash.insert(WidgetMetadata::Version, "version");
|
||||
hash.insert(WidgetMetadata::Description, "description");
|
||||
hash.insert(WidgetMetadata::Main, "main");
|
||||
hash.insert(WidgetMetadata::Type, "type");
|
||||
hash.insert(WidgetMetadata::Flag, "flag");
|
||||
hash.insert(WidgetMetadata::Data, "data");
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
WidgetExtension *WidgetExtensionModel::widgetAt(int index) const
|
||||
{
|
||||
if (index < 0 || index >= m_widgets.count()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_widgets.at(index);
|
||||
}
|
||||
|
||||
void WidgetExtensionModel::notify(int index, const QVariantMap &data) const
|
||||
{
|
||||
WidgetExtension *widget = widgetAt(index);
|
||||
if (widget) {
|
||||
widget->receive(data);
|
||||
}
|
||||
}
|
||||
|
||||
WidgetExtensionModel *WidgetExtensionModel::instance()
|
||||
{
|
||||
static WidgetExtensionModel model;
|
||||
return &model;
|
||||
}
|
||||
|
||||
} // UkuiMenu
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (C) 2023, 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UKUI_MENU_WIDGET_EXTENSION_MODEL_H
|
||||
#define UKUI_MENU_WIDGET_EXTENSION_MODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
class WidgetExtension;
|
||||
|
||||
class WidgetExtensionModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static WidgetExtensionModel *instance();
|
||||
explicit WidgetExtensionModel(QObject *parent = nullptr);
|
||||
|
||||
QModelIndex parent(const QModelIndex &child) const override;
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
int columnCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
Q_INVOKABLE UkuiMenu::WidgetExtension *widgetAt(int index) const;
|
||||
Q_INVOKABLE void notify(int index, const QVariantMap &data) const;
|
||||
|
||||
private:
|
||||
QList<WidgetExtension*> m_widgets;
|
||||
};
|
||||
|
||||
} // UkuiMenu
|
||||
|
||||
#endif //UKUI_MENU_WIDGET_EXTENSION_MODEL_H
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (C) 2023, 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "widget-extension.h"
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
WidgetExtension::WidgetExtension(QObject *parent) : QObject(parent)
|
||||
{
|
||||
qRegisterMetaType<UkuiMenu::MetadataMap>();
|
||||
}
|
||||
|
||||
int WidgetExtension::index() const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
QVariantMap WidgetExtension::data()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void WidgetExtension::receive(const QVariantMap &data)
|
||||
{
|
||||
Q_UNUSED(data)
|
||||
}
|
||||
|
||||
} // UkuiMenu
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (C) 2023, 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UKUI_MENU_WIDGET_EXTENSION_H
|
||||
#define UKUI_MENU_WIDGET_EXTENSION_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVariant>
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
class WidgetMetadata
|
||||
{
|
||||
Q_GADGET
|
||||
public:
|
||||
enum Key {
|
||||
Id = 0,
|
||||
Icon,
|
||||
Name,
|
||||
Tooltip,
|
||||
Version,
|
||||
Description,
|
||||
Main,
|
||||
Type,
|
||||
Flag,
|
||||
Data
|
||||
};
|
||||
Q_ENUM(Key)
|
||||
|
||||
enum TypeValue {
|
||||
Widget = 0x01, /**> 显示在插件区域 */
|
||||
Button = 0x02, /**> 显示在侧边栏 */
|
||||
AppList = 0x04 /**> 显示在应用列表,默认会显示在全屏界面 */
|
||||
};
|
||||
Q_ENUM(TypeValue)
|
||||
Q_DECLARE_FLAGS(Types, TypeValue)
|
||||
Q_FLAGS(Types)
|
||||
|
||||
enum FlagValue {
|
||||
OnlySmallScreen = 0x01,
|
||||
OnlyFullScreen = 0x02,
|
||||
Normal = OnlySmallScreen | OnlyFullScreen
|
||||
};
|
||||
Q_ENUM(FlagValue)
|
||||
Q_DECLARE_FLAGS(Flags, FlagValue)
|
||||
Q_FLAGS(Flags)
|
||||
};
|
||||
|
||||
typedef QMap<UkuiMenu::WidgetMetadata::Key, QVariant> MetadataMap;
|
||||
|
||||
class WidgetExtension : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit WidgetExtension(QObject *parent = nullptr);
|
||||
virtual int index() const;
|
||||
virtual MetadataMap metadata() const = 0;
|
||||
|
||||
// 兼容老版本
|
||||
virtual QVariantMap data();
|
||||
virtual void receive(const QVariantMap &data);
|
||||
|
||||
Q_SIGNALS:
|
||||
void dataUpdated();
|
||||
};
|
||||
|
||||
} // UkuiMenu
|
||||
|
||||
Q_DECLARE_METATYPE(UkuiMenu::MetadataMap)
|
||||
Q_DECLARE_METATYPE(UkuiMenu::WidgetMetadata::TypeValue)
|
||||
Q_DECLARE_METATYPE(UkuiMenu::WidgetMetadata::FlagValue)
|
||||
|
||||
#endif //UKUI_MENU_WIDGET_EXTENSION_H
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (C) 2023, 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "widget-model.h"
|
||||
#include "widget-extension-model.h"
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QDebug>
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
// ====== WidgetModel ====== //
|
||||
WidgetModel::WidgetModel(QObject *parent) : QSortFilterProxyModel(parent)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
WidgetMetadata::Types WidgetModel::types() const
|
||||
{
|
||||
return m_types;
|
||||
}
|
||||
|
||||
void WidgetModel::setTypes(WidgetMetadata::Types types)
|
||||
{
|
||||
if (m_types == types) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_types = types;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
WidgetMetadata::Flags WidgetModel::flags() const
|
||||
{
|
||||
return m_flags;
|
||||
}
|
||||
|
||||
void WidgetModel::setFlags(WidgetMetadata::Flags flags)
|
||||
{
|
||||
if (m_flags == flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_flags = flags;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
bool WidgetModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
|
||||
{
|
||||
QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
|
||||
|
||||
bool acceptFlag = m_types.testFlag(index.data(WidgetMetadata::Type).value<WidgetMetadata::TypeValue>());
|
||||
if (acceptFlag) {
|
||||
return m_flags.testFlag(index.data(WidgetMetadata::Flag).value<WidgetMetadata::FlagValue>());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WidgetModel::init()
|
||||
{
|
||||
QSortFilterProxyModel::setSourceModel(WidgetExtensionModel::instance());
|
||||
// invalidateFilter();
|
||||
}
|
||||
|
||||
void WidgetModel::send(int index, const QVariantMap &data)
|
||||
{
|
||||
auto sourceModel = qobject_cast<WidgetExtensionModel*>(QSortFilterProxyModel::sourceModel());
|
||||
if (sourceModel) {
|
||||
sourceModel->notify(index, data);
|
||||
}
|
||||
}
|
||||
|
||||
} // UkuiMenu
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (C) 2023, 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UKUI_MENU_WIDGET_MODEL_H
|
||||
#define UKUI_MENU_WIDGET_MODEL_H
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QVariant>
|
||||
#include "widget-extension.h"
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
class WidgetModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(UkuiMenu::WidgetMetadata::Types types READ types WRITE setTypes)
|
||||
Q_PROPERTY(UkuiMenu::WidgetMetadata::Flags flags READ flags WRITE setFlags)
|
||||
public:
|
||||
explicit WidgetModel(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void init();
|
||||
Q_INVOKABLE void send(int index, const QVariantMap &data);
|
||||
|
||||
WidgetMetadata::Types types() const;
|
||||
void setTypes(WidgetMetadata::Types types);
|
||||
WidgetMetadata::Flags flags() const;
|
||||
void setFlags(WidgetMetadata::Flags flags);
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||
|
||||
private:
|
||||
WidgetMetadata::Types m_types = WidgetMetadata::Widget;
|
||||
WidgetMetadata::Flags m_flags = WidgetMetadata::Normal;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //UKUI_MENU_WIDGET_MODEL_H
|
|
@ -33,6 +33,7 @@
|
|||
#include "data-provider-manager.h"
|
||||
#include "event-track.h"
|
||||
#include "sidebar-button-utils.h"
|
||||
#include "extension/widget-model.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QCommandLineParser>
|
||||
|
@ -67,6 +68,8 @@ void UkuiMenuApplication::registerQmlTypes()
|
|||
|
||||
ModelManager::registerMetaTypes();
|
||||
|
||||
qmlRegisterType<WidgetModel>(uri, versionMajor, versionMinor, "WidgetModel");
|
||||
|
||||
// commons
|
||||
qRegisterMetaType<UkuiMenu::DataType::Type>("DataType::Type");
|
||||
qRegisterMetaType<UkuiMenu::DataEntity>("DataEntity");
|
||||
|
|
Loading…
Reference in New Issue