实现开始菜单扩展加载和管理功能

This commit is contained in:
hewenfei 2023-01-03 11:00:52 +08:00
parent e4899b0f49
commit 29a0046b44
8 changed files with 284 additions and 33 deletions

View File

@ -1,6 +1,5 @@
import QtQuick 2.12 import QtQuick 2.12
import QtQuick.Controls 2.0 as QQC2 import QtQuick.Controls 2.0 as QQC2
import org.ukui.menu.extension 1.0
Item { Item {
Row { Row {
@ -12,19 +11,7 @@ Item {
} }
Sidebar { Sidebar {
width: parent.width - 400; width: parent.width - 300;
height: parent.height;
MouseArea {
anchors.fill: parent;
onClicked: {
mainWindow.isFullScreen = !mainWindow.isFullScreen;
}
}
}
UkuiMenuExtension {
width: 100;
height: parent.height; height: parent.height;
} }
} }

View File

@ -1,8 +1,93 @@
import QtQuick 2.0 import QtQuick 2.0
import AppControls2 1.0 as AppControls2 import QtQuick.Layouts 1.12
Item { Item {
AppControls2.AppTest { ColumnLayout {
anchors.fill: parent; anchors.fill: parent
Item {
Layout.fillWidth: true
Layout.preferredHeight: 30
ListView {
id: extensionListView
anchors.fill: parent
orientation: ListView.Horizontal
model: extensionManager.extensionModel()
delegate: headerDelegate
function send(data) {
if (currentItem !== null) {
model.send(currentIndex, data);
}
}
onCurrentIndexChanged: {
if (currentItem !== null) {
currentItem.select();
}
}
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Loader {
id: extensionLoader
anchors.fill: parent
clip: true
focus: true
onLoaded: {
item.send.connect(extensionListView.send);
}
}
}
}
Component {
id: headerDelegate
Item {
property var extensionData: model.data
width: 100
height: ListView.view ? ListView.view.height : 0
onExtensionDataChanged: {
if (extensionLoader.source === model.url) {
extensionLoader.item.extensionData = extensionData;
}
}
function select() {
if (extensionLoader.source !== model.url) {
extensionLoader.setSource(model.url, {extensionData: extensionData});
}
}
Text {
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.bold: true
wrapMode: Text.ElideRight
color: parent.ListView.isCurrentItem ? "blue" : "black"
text: model.name
}
MouseArea {
anchors.fill: parent
onClicked: {
parent.ListView.view.currentIndex = model.index;
}
}
}
}
Component.onCompleted: {
if (extensionListView.count > 0) {
extensionListView.currentIndex = 0;
}
} }
} }

View File

@ -1,3 +1,21 @@
/*
* Copyright (C) 2022, 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/>.
*
*/
import QtQuick 2.12 import QtQuick 2.12
import org.ukui.menu.core 1.0 import org.ukui.menu.core 1.0
@ -17,18 +35,7 @@ MenuMainWindow {
} }
AppUI.NormalUI { AppUI.NormalUI {
anchors.fill: mainWindow.contentItem; parent: mainWindow.contentItem
transitions: Transition { anchors.fill: parent
NumberAnimation {
easing.type: Easing.OutBounce;
properties: "width,height";
duration: 4000;
}
}
Behavior on width {
PropertyAnimation {
}
}
} }
} }

View File

@ -1,7 +1,6 @@
import QtQuick 2.0 import QtQuick 2.0
Item { Item {
id: extensionView; property var extensionData;
property var data;
signal send(var data); signal send(var data);
} }

View File

@ -21,6 +21,7 @@
#include <QObject> #include <QObject>
#include <QUrl>
#include <QString> #include <QString>
#include <QVariant> #include <QVariant>
@ -30,9 +31,10 @@ class MenuExtensionIFace : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit MenuExtensionIFace(QObject *parent = nullptr) : QObject(parent) {};
virtual int index() = 0; virtual int index() = 0;
virtual QString name() = 0; virtual QString name() = 0;
virtual QString url() = 0; virtual QUrl url() = 0;
virtual QVariantMap data() = 0; virtual QVariantMap data() = 0;
virtual void receive(QVariantMap data) = 0; virtual void receive(QVariantMap data) = 0;

View File

@ -18,7 +18,132 @@
#include "menu-extension.h" #include "menu-extension.h"
#include <utility>
#include <QDebug>
namespace UkuiMenu { namespace UkuiMenu {
MenuExtension *MenuExtension::instance()
{
static MenuExtension menuExtension;
return &menuExtension;
}
MenuExtension::MenuExtension()
{
qRegisterMetaType<ExtensionModel*>("ExtensionModel*");
// TODO load extension from filesystem.
// register extension.
initModel();
}
void MenuExtension::registerExtension(MenuExtensionIFace *extension)
{
if (!extension) {
return;
}
extension->setParent(this);
if (m_extensions.contains(extension->name())) {
return;
}
m_extensions.insert(extension->name(), extension);
}
ExtensionModel *MenuExtension::extensionModel()
{
return m_model;
}
void MenuExtension::initModel()
{
QVector<MenuExtensionIFace*> data;
QMap<QString, MenuExtensionIFace*>::const_iterator iterator = m_extensions.constBegin();
for (; iterator != m_extensions.constEnd(); ++iterator) {
MenuExtensionIFace* extension = iterator.value();
data.append(extension);
}
std::sort(data.begin(), data.end(), [](MenuExtensionIFace* a, MenuExtensionIFace* b) {
return a->index() <= b->index();
});
m_model = new ExtensionModel(data, this);
if (!m_model) {
qWarning() << "MenuExtension: unable to init the model of menu-extension.";
}
}
ExtensionModel::ExtensionModel(const QVector<MenuExtensionIFace*> &extensions, QObject *parent)
: QAbstractListModel(parent), m_extensions(extensions)
{
m_roleNames.insert(Name, "name");
m_roleNames.insert(Url, "url");
m_roleNames.insert(Data, "data");
for (int i = 0; i < m_extensions.size(); ++i) {
connect(m_extensions.at(i), &MenuExtensionIFace::dataUpdated, this, [this, i] {
extensionDataChanged(i);
});
}
}
int ExtensionModel::rowCount(const QModelIndex &parent) const
{
return m_extensions.size();
}
QVariant ExtensionModel::data(const QModelIndex &index, int role) const
{
int row = index.row();
if (row < 0 || row >= m_extensions.size()) {
return {};
}
switch (role) {
case Name:
return m_extensions.at(row)->name();
case Url:
return m_extensions.at(row)->url();
case Data: {
return m_extensions.at(row)->data();
}
default:
break;
}
return {};
}
QHash<int, QByteArray> ExtensionModel::roleNames() const
{
return m_roleNames;
}
void ExtensionModel::send(int index, QVariantMap data)
{
if (index < 0 || index >= m_extensions.size()) {
return;
}
m_extensions.at(index)->receive(std::move(data));
}
void ExtensionModel::extensionDataChanged(int index)
{
if (index < 0 || index >= m_extensions.size()) {
return;
}
QVector<int> roles(1, Data);
QModelIndex modelIndex = createIndex(index, 0);
Q_EMIT dataChanged(modelIndex, modelIndex, roles);
}
} // UkuiMenu } // UkuiMenu

View File

@ -20,15 +20,59 @@
#define UKUI_MENU_MENU_EXTENSION_H #define UKUI_MENU_MENU_EXTENSION_H
#include <QObject> #include <QObject>
#include <QHash>
#include <QString>
#include <QVector>
#include <QVariant>
#include <QAbstractListModel>
#include "menu-extension-iface.h"
namespace UkuiMenu { namespace UkuiMenu {
class ExtensionModel;
class MenuExtension : public QObject class MenuExtension : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
static MenuExtension *instance();
void registerExtension(MenuExtensionIFace *extension);
Q_INVOKABLE ExtensionModel *extensionModel();
private:
MenuExtension();
void initModel();
private:
ExtensionModel *m_model{nullptr};
QMap<QString, MenuExtensionIFace*> m_extensions;
};
class ExtensionModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Name {
Name,
Url,
Data
};
explicit ExtensionModel(const QVector<MenuExtensionIFace*> &extensions, QObject *parent = nullptr);
int rowCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
QHash<int, QByteArray> roleNames() const override;
Q_INVOKABLE void send(int index, QVariantMap data);
private:
void extensionDataChanged(int index);
private:
QHash<int, QByteArray> m_roleNames;
QVector<MenuExtensionIFace*> m_extensions;
}; };
} // UkuiMenu } // UkuiMenu

View File

@ -24,6 +24,7 @@
#include "theme-palette.h" #include "theme-palette.h"
#include "app-icon-provider.h" #include "app-icon-provider.h"
#include "menu-main-window.h" #include "menu-main-window.h"
#include "extension/menu-extension.h"
#include <QCoreApplication> #include <QCoreApplication>
#include <QCommandLineParser> #include <QCommandLineParser>
@ -77,6 +78,7 @@ void UkuiMenuApplication::initQmlEngine()
m_applicationEngine->rootContext()->setContextProperty("themePalette", ThemePalette::getInstance()); m_applicationEngine->rootContext()->setContextProperty("themePalette", ThemePalette::getInstance());
m_applicationEngine->rootContext()->setContextProperty("menuSetting", MenuSetting::instance()); m_applicationEngine->rootContext()->setContextProperty("menuSetting", MenuSetting::instance());
m_applicationEngine->rootContext()->setContextProperty("modelManager", new ModelManager(this)); m_applicationEngine->rootContext()->setContextProperty("modelManager", new ModelManager(this));
m_applicationEngine->rootContext()->setContextProperty("extensionManager", MenuExtension::instance());
QObject::connect(m_applicationEngine, &QQmlApplicationEngine::objectCreated, QObject::connect(m_applicationEngine, &QQmlApplicationEngine::objectCreated,
this, [url](QObject *obj, const QUrl &objUrl) { this, [url](QObject *obj, const QUrl &objUrl) {