diff --git a/qml/AppUI/NormalUI.qml b/qml/AppUI/NormalUI.qml
index 5db239f..85b58ae 100644
--- a/qml/AppUI/NormalUI.qml
+++ b/qml/AppUI/NormalUI.qml
@@ -1,6 +1,5 @@
import QtQuick 2.12
import QtQuick.Controls 2.0 as QQC2
-import org.ukui.menu.extension 1.0
Item {
Row {
@@ -12,19 +11,7 @@ Item {
}
Sidebar {
- width: parent.width - 400;
- height: parent.height;
-
- MouseArea {
- anchors.fill: parent;
- onClicked: {
- mainWindow.isFullScreen = !mainWindow.isFullScreen;
- }
- }
- }
-
- UkuiMenuExtension {
- width: 100;
+ width: parent.width - 300;
height: parent.height;
}
}
diff --git a/qml/AppUI/Sidebar.qml b/qml/AppUI/Sidebar.qml
index e668f72..7443747 100644
--- a/qml/AppUI/Sidebar.qml
+++ b/qml/AppUI/Sidebar.qml
@@ -1,8 +1,93 @@
import QtQuick 2.0
-import AppControls2 1.0 as AppControls2
+import QtQuick.Layouts 1.12
Item {
- AppControls2.AppTest {
- anchors.fill: parent;
+ ColumnLayout {
+ 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;
+ }
}
}
diff --git a/qml/main.qml b/qml/main.qml
index 204e2e5..d383f54 100644
--- a/qml/main.qml
+++ b/qml/main.qml
@@ -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 .
+ *
+ */
+
import QtQuick 2.12
import org.ukui.menu.core 1.0
@@ -17,18 +35,7 @@ MenuMainWindow {
}
AppUI.NormalUI {
- anchors.fill: mainWindow.contentItem;
- transitions: Transition {
- NumberAnimation {
- easing.type: Easing.OutBounce;
- properties: "width,height";
- duration: 4000;
- }
- }
- Behavior on width {
- PropertyAnimation {
-
- }
- }
+ parent: mainWindow.contentItem
+ anchors.fill: parent
}
}
diff --git a/qml/org/ukui/menu/extension/UkuiMenuExtension.qml b/qml/org/ukui/menu/extension/UkuiMenuExtension.qml
index 4c59cc3..ef817fe 100644
--- a/qml/org/ukui/menu/extension/UkuiMenuExtension.qml
+++ b/qml/org/ukui/menu/extension/UkuiMenuExtension.qml
@@ -1,7 +1,6 @@
import QtQuick 2.0
Item {
- id: extensionView;
- property var data;
+ property var extensionData;
signal send(var data);
}
diff --git a/src/extension/menu-extension-iface.h b/src/extension/menu-extension-iface.h
index ff854cc..3df7903 100644
--- a/src/extension/menu-extension-iface.h
+++ b/src/extension/menu-extension-iface.h
@@ -21,6 +21,7 @@
#include
+#include
#include
#include
@@ -30,9 +31,10 @@ class MenuExtensionIFace : public QObject
{
Q_OBJECT
public:
+ explicit MenuExtensionIFace(QObject *parent = nullptr) : QObject(parent) {};
virtual int index() = 0;
virtual QString name() = 0;
- virtual QString url() = 0;
+ virtual QUrl url() = 0;
virtual QVariantMap data() = 0;
virtual void receive(QVariantMap data) = 0;
diff --git a/src/extension/menu-extension.cpp b/src/extension/menu-extension.cpp
index bd80a56..a0cc168 100644
--- a/src/extension/menu-extension.cpp
+++ b/src/extension/menu-extension.cpp
@@ -18,7 +18,132 @@
#include "menu-extension.h"
+#include
+#include
+
namespace UkuiMenu {
+MenuExtension *MenuExtension::instance()
+{
+ static MenuExtension menuExtension;
+ return &menuExtension;
+}
+
+MenuExtension::MenuExtension()
+{
+ qRegisterMetaType("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 data;
+
+ QMap::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 &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 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 roles(1, Data);
+ QModelIndex modelIndex = createIndex(index, 0);
+ Q_EMIT dataChanged(modelIndex, modelIndex, roles);
+}
} // UkuiMenu
diff --git a/src/extension/menu-extension.h b/src/extension/menu-extension.h
index 5918a4c..4e2c779 100644
--- a/src/extension/menu-extension.h
+++ b/src/extension/menu-extension.h
@@ -20,15 +20,59 @@
#define UKUI_MENU_MENU_EXTENSION_H
#include
+#include
+#include
+#include
+#include
+#include
+
+#include "menu-extension-iface.h"
namespace UkuiMenu {
+class ExtensionModel;
+
class MenuExtension : public QObject
{
Q_OBJECT
public:
+ static MenuExtension *instance();
+ void registerExtension(MenuExtensionIFace *extension);
+ Q_INVOKABLE ExtensionModel *extensionModel();
+private:
+ MenuExtension();
+ void initModel();
+private:
+ ExtensionModel *m_model{nullptr};
+ QMap m_extensions;
+};
+
+class ExtensionModel : public QAbstractListModel
+{
+ Q_OBJECT
+public:
+ enum Name {
+ Name,
+ Url,
+ Data
+ };
+
+ explicit ExtensionModel(const QVector &extensions, QObject *parent = nullptr);
+
+ int rowCount(const QModelIndex &parent) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+ QHash roleNames() const override;
+
+ Q_INVOKABLE void send(int index, QVariantMap data);
+
+private:
+ void extensionDataChanged(int index);
+
+private:
+ QHash m_roleNames;
+ QVector m_extensions;
};
} // UkuiMenu
diff --git a/src/ukui-menu-application.cpp b/src/ukui-menu-application.cpp
index 4ff7669..fdcd789 100644
--- a/src/ukui-menu-application.cpp
+++ b/src/ukui-menu-application.cpp
@@ -24,6 +24,7 @@
#include "theme-palette.h"
#include "app-icon-provider.h"
#include "menu-main-window.h"
+#include "extension/menu-extension.h"
#include
#include
@@ -77,6 +78,7 @@ void UkuiMenuApplication::initQmlEngine()
m_applicationEngine->rootContext()->setContextProperty("themePalette", ThemePalette::getInstance());
m_applicationEngine->rootContext()->setContextProperty("menuSetting", MenuSetting::instance());
m_applicationEngine->rootContext()->setContextProperty("modelManager", new ModelManager(this));
+ m_applicationEngine->rootContext()->setContextProperty("extensionManager", MenuExtension::instance());
QObject::connect(m_applicationEngine, &QQmlApplicationEngine::objectCreated,
this, [url](QObject *obj, const QUrl &objUrl) {