feat(fullscreen): 全屏模式添加应用分组model,前端适配分组model
This commit is contained in:
parent
dacc9d4608
commit
07767c2a5b
|
@ -49,7 +49,7 @@ set(SingleApplication "qtsingleapplication")
|
|||
|
||||
# include文件夹
|
||||
include_directories(src)
|
||||
include_directories(src/model)
|
||||
#include_directories(src/model)
|
||||
include_directories(src/appdata)
|
||||
include_directories(src/libappdata)
|
||||
include_directories(src/settings)
|
||||
|
@ -131,6 +131,7 @@ set(SOURCE_FILES
|
|||
src/libappdata/app-list-plugin.cpp src/libappdata/app-list-plugin.h
|
||||
src/libappdata/app-search-plugin.cpp src/libappdata/app-search-plugin.h
|
||||
src/libappdata/app-category-plugin.cpp src/libappdata/app-category-plugin.h
|
||||
src/libappdata/app-group-model.cpp src/libappdata/app-group-model.h
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ MouseArea {
|
|||
id: control
|
||||
hoverEnabled: true
|
||||
|
||||
property alias displayName: labelText.text
|
||||
|
||||
// ToolTip.text: comment
|
||||
// ToolTip.visible: control.containsMouse
|
||||
// ToolTip.delay: 500
|
||||
|
@ -18,11 +20,12 @@ MouseArea {
|
|||
radius: Platform.Theme.minRadius
|
||||
useStyleTransparency: false
|
||||
paletteRole: Platform.Theme.Text
|
||||
alpha: control.containsPress ? 0.16 : control.containsMouse ? 0.08 : 0.00
|
||||
alpha: control.containsPress ? 0.15 : control.containsMouse ? 0.08 : 0.00
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
UkuiItems.StyleText {
|
||||
id: labelText
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.leftMargin: 12
|
||||
|
@ -30,7 +33,6 @@ MouseArea {
|
|||
horizontalAlignment: Qt.AlignLeft
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
font.bold: true
|
||||
text: section
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
|
|
|
@ -105,7 +105,8 @@ AppListView {
|
|||
AppControls2.LabelItem {
|
||||
width: ListView.view.width
|
||||
height: appListView.itemHeight
|
||||
focus: true;
|
||||
focus: true
|
||||
displayName: section
|
||||
onClicked: labelItemClicked();
|
||||
Keys.onPressed: {
|
||||
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
|
||||
|
|
|
@ -30,10 +30,14 @@ UkuiItems.StyleBackground {
|
|||
|
||||
width: count > 0 ? (childrenRect.width + maring*2) : 0
|
||||
|
||||
useStyleTransparency: false
|
||||
paletteRole: Platform.Theme.Text
|
||||
radius: height/2
|
||||
alpha: 0.06
|
||||
alpha: 0.03
|
||||
useStyleTransparency: false
|
||||
paletteRole: Platform.Theme.WindowText
|
||||
|
||||
border.width: 1
|
||||
borderAlpha: 0.06
|
||||
borderColor: Platform.Theme.WindowText
|
||||
|
||||
Row {
|
||||
id: mainLayout
|
||||
|
@ -54,9 +58,11 @@ UkuiItems.StyleBackground {
|
|||
ToolTip.visible: modelData.toolTip !== "" && containsMouse
|
||||
|
||||
background.radius: width / 2
|
||||
background.alpha: modelData.checked ? 0.75 : containsMouse ? 0.4 : 0
|
||||
background.paletteRole: Platform.Theme.Highlight
|
||||
background.alpha: modelData.checked ? 1 : containsMouse ? 0.3 : 0
|
||||
|
||||
icon.source: modelData.icon
|
||||
icon.mode: UkuiItems.Icon.AutoHighlight
|
||||
icon.mode: modelData.checked ? UkuiItems.Icon.Highlight : UkuiItems.Icon.AutoHighlight
|
||||
|
||||
onClicked: {
|
||||
// 执行action
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import org.ukui.quick.items 1.0 as UkuiItems
|
||||
import org.ukui.quick.platform 1.0 as Platform
|
||||
|
||||
MouseArea {
|
||||
id: root
|
||||
property alias icon: appIcon
|
||||
property alias text: appName
|
||||
property alias background: styleBackground
|
||||
|
||||
hoverEnabled: true
|
||||
|
||||
UkuiItems.StyleBackground {
|
||||
id: styleBackground
|
||||
anchors.fill: parent
|
||||
radius: Platform.Theme.normalRadius
|
||||
useStyleTransparency: false
|
||||
paletteRole: Platform.Theme.WindowText
|
||||
alpha: root.containsPress ? 0.15 : root.containsMouse ? 0.08 : 0
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 16
|
||||
spacing: 0
|
||||
|
||||
UkuiItems.Icon {
|
||||
id: appIcon
|
||||
Layout.minimumWidth: 32
|
||||
Layout.minimumHeight: 32
|
||||
Layout.maximumWidth: 96
|
||||
Layout.maximumHeight: 96
|
||||
|
||||
Layout.preferredWidth: 96
|
||||
Layout.preferredHeight: 96
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
}
|
||||
|
||||
UkuiItems.StyleText {
|
||||
id: appName
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
paletteRole: Platform.Theme.Text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQml.Models 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import org.ukui.menu.core 1.0
|
||||
import AppControls2 1.0 as AppControls2
|
||||
|
||||
import org.ukui.quick.items 1.0 as UkuiItems
|
||||
import org.ukui.quick.platform 1.0 as Platform
|
||||
|
||||
ListView {
|
||||
id: root
|
||||
property int itemHeight: 40
|
||||
property alias sourceModel: appGroupModel.sourceModel
|
||||
|
||||
spacing: 5
|
||||
clip: true
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
model: AppGroupModel {
|
||||
id: appGroupModel
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
width: ListView.view.width
|
||||
height: childrenRect.height
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
height: childrenRect.height
|
||||
spacing: 0
|
||||
|
||||
AppControls2.LabelItem {
|
||||
width: parent.width
|
||||
height: root.itemHeight
|
||||
displayName: model.name
|
||||
}
|
||||
|
||||
GridView {
|
||||
width: parent.width
|
||||
height: childrenRect.height
|
||||
// TODO: 动态计算尺寸
|
||||
cellWidth: width / 8
|
||||
cellHeight: cellWidth
|
||||
interactive: false
|
||||
|
||||
model: DelegateModel {
|
||||
model: appGroupModel
|
||||
rootIndex: modelIndex(index)
|
||||
delegate: Item {
|
||||
width: GridView.view.cellWidth
|
||||
height: GridView.view.cellHeight
|
||||
|
||||
FullScreenAppItem {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
|
||||
text.text: model.name
|
||||
icon.source: model.icon
|
||||
|
||||
onClicked: (event) => {
|
||||
if (event.button === Qt.LeftButton) {
|
||||
// openApplication
|
||||
appManager.launchApp(id);
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
// appListView.model.openMenu(index, MenuInfo.FullScreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,12 @@
|
|||
import QtQuick 2.0
|
||||
import QtQuick.Layouts 1.12
|
||||
import org.ukui.quick.platform 1.0 as Platform
|
||||
import org.ukui.quick.items 1.0 as UkuiItems
|
||||
import QtQml.Models 2.12
|
||||
|
||||
import org.ukui.menu.core 1.0
|
||||
import AppControls2 1.0 as AppControls2
|
||||
|
||||
import org.ukui.quick.items 1.0 as UkuiItems
|
||||
import org.ukui.quick.platform 1.0 as Platform
|
||||
|
||||
UkuiItems.StyleBackground {
|
||||
paletteRole: Platform.Theme.Dark
|
||||
|
@ -23,6 +27,7 @@ UkuiItems.StyleBackground {
|
|||
Item {
|
||||
id: mainContainer
|
||||
anchors.fill: parent
|
||||
z: 10
|
||||
|
||||
AppPageBackend {
|
||||
id: appPageBackend
|
||||
|
@ -81,10 +86,6 @@ UkuiItems.StyleBackground {
|
|||
appPageBackend.startSearch(text);
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: 300; easing.type: Easing.InOutCubic }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,21 +115,13 @@ UkuiItems.StyleBackground {
|
|||
}
|
||||
|
||||
// 应用列表: [row: 1, column: 1]
|
||||
Item {
|
||||
FullScreenAppList {
|
||||
Layout.row: 1
|
||||
Layout.column: 1
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
AppList {
|
||||
anchors.fill: parent
|
||||
visible: true
|
||||
model: appPageBackend.appModel
|
||||
|
||||
view.onContentYChanged: {
|
||||
//
|
||||
}
|
||||
}
|
||||
sourceModel: appPageBackend.appModel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,4 +13,6 @@ PluginSelectButton 1.0 PluginSelectButton.qml
|
|||
FullScreenHeader 1.0 FullScreenHeader.qml
|
||||
FullScreenContent 1.0 FullScreenContent.qml
|
||||
FullScreenFooter 1.0 FullScreenFooter.qml
|
||||
FullScreenAppList 1.0 FullScreenAppList.qml
|
||||
FullScreenAppItem 1.0 FullScreenAppItem.qml
|
||||
Folder 1.0 Folder.qml
|
||||
|
|
|
@ -36,5 +36,7 @@
|
|||
<file>AppUI/EditText.qml</file>
|
||||
<file>AppUI/Folder.qml</file>
|
||||
<file>AppUI/AppPageSearch.qml</file>
|
||||
<file>AppUI/FullScreenAppList.qml</file>
|
||||
<file>AppUI/FullScreenAppItem.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* 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 "app-group-model.h"
|
||||
#include <QDebug>
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
AppGroupModel::AppGroupModel(QObject *parent) : QAbstractProxyModel(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QModelIndex AppGroupModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (column != 0 || row < 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// 通过parent找到所属的组,将组的信息放入index附带数据中,作为判断依据
|
||||
if (parent.isValid()) {
|
||||
const auto subItems = m_groups.at(parent.row());
|
||||
if (row >= subItems->size()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return createIndex(row, column, subItems);
|
||||
}
|
||||
|
||||
return createIndex(row, column, nullptr);
|
||||
}
|
||||
|
||||
QModelIndex AppGroupModel::parent(const QModelIndex &child) const
|
||||
{
|
||||
if (!child.isValid()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto subItems = static_cast<QVector<int>*>(child.internalPointer());
|
||||
if (subItems) {
|
||||
return createIndex(m_groups.indexOf(subItems), 0);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool AppGroupModel::hasChildren(const QModelIndex &parent) const
|
||||
{
|
||||
if (!sourceModel()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// root
|
||||
if (!parent.isValid()) {
|
||||
return !m_groups.isEmpty();
|
||||
}
|
||||
|
||||
// child, 两层
|
||||
if (parent.parent().isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int AppGroupModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (!sourceModel()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// root
|
||||
if (!parent.isValid()) {
|
||||
return m_groups.size();
|
||||
}
|
||||
|
||||
if (parent.parent().isValid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i = parent.row();
|
||||
if (i < 0 || i >= m_groups.size()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_groups.at(i)->size();
|
||||
}
|
||||
|
||||
int AppGroupModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> AppGroupModel::roleNames() const
|
||||
{
|
||||
return QAbstractItemModel::roleNames();
|
||||
}
|
||||
|
||||
void AppGroupModel::setSourceModel(QAbstractItemModel *sourceModel)
|
||||
{
|
||||
if (AppGroupModel::sourceModel() == sourceModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
beginResetModel();
|
||||
if (AppGroupModel::sourceModel()) {
|
||||
AppGroupModel::sourceModel()->disconnect(this);
|
||||
}
|
||||
|
||||
QAbstractProxyModel::setSourceModel(sourceModel);
|
||||
|
||||
if (sourceModel) {
|
||||
rebuildAppGroups();
|
||||
|
||||
connect(sourceModel, &QAbstractItemModel::dataChanged, this, &AppGroupModel::onDataChanged);
|
||||
connect(sourceModel, &QAbstractItemModel::layoutChanged, this, &AppGroupModel::onLayoutChanged);
|
||||
connect(sourceModel, &QAbstractItemModel::rowsInserted, this, &AppGroupModel::onRowsInserted);
|
||||
connect(sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &AppGroupModel::onRowsAboutToBeRemoved);
|
||||
connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, [=] (const QModelIndex &parent, int first, int last) {
|
||||
if (m_needRebuild) {
|
||||
beginResetModel();
|
||||
rebuildAppGroups();
|
||||
endResetModel();
|
||||
m_needRebuild = false;
|
||||
|
||||
} else if (!parent.isValid()) {
|
||||
reLocationIndex(first, -(last - first + 1));
|
||||
}
|
||||
});
|
||||
connect(sourceModel, &QAbstractItemModel::modelReset, this, [=] {
|
||||
beginResetModel();
|
||||
rebuildAppGroups();
|
||||
endResetModel();
|
||||
});
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QModelIndex AppGroupModel::mapToSource(const QModelIndex &proxyIndex) const
|
||||
{
|
||||
if (!sourceModel() || !proxyIndex.isValid()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto subItems = static_cast<QVector<int>*>(proxyIndex.internalPointer());
|
||||
if (subItems) {
|
||||
int idx = subItems->at(proxyIndex.row());
|
||||
return sourceModel()->index(idx, 0);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QModelIndex AppGroupModel::mapFromSource(const QModelIndex &sourceIndex) const
|
||||
{
|
||||
if (!sourceModel() || !sourceIndex.isValid()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
int groupIndex = findGroupIndex(sourceIndex);
|
||||
if (groupIndex < 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
int tempIndex = m_groups.at(groupIndex)->indexOf(sourceIndex.row());
|
||||
return index(tempIndex, 0, index(groupIndex, 0, QModelIndex()));
|
||||
}
|
||||
|
||||
QVariant AppGroupModel::data(const QModelIndex &proxyIndex, int role) const
|
||||
{
|
||||
if (!checkIndex(proxyIndex, CheckIndexOption::IndexIsValid)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (proxyIndex.parent().isValid()) {
|
||||
return QAbstractProxyModel::data(proxyIndex, role);
|
||||
}
|
||||
|
||||
if (role == DataEntity::Name) {
|
||||
return sourceModel()->index(m_groups.at(proxyIndex.row())->first(), 0).data(DataEntity::Group);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void AppGroupModel::rebuildAppGroups()
|
||||
{
|
||||
qDeleteAll(m_groups);
|
||||
m_groups.clear();
|
||||
|
||||
for (int i = 0; i < sourceModel()->rowCount(); ++i) {
|
||||
int groupIndex = findGroupIndex(sourceModel()->index(i, 0));
|
||||
QVector<int> *subItems {nullptr};
|
||||
if (groupIndex < 0) {
|
||||
subItems = new QVector<int>();
|
||||
m_groups.append(subItems);
|
||||
} else {
|
||||
subItems = m_groups[groupIndex];
|
||||
}
|
||||
|
||||
subItems->append(i);
|
||||
}
|
||||
}
|
||||
|
||||
int AppGroupModel::findGroupIndex(const QModelIndex &sourceIndex) const
|
||||
{
|
||||
for (int i = 0; i < m_groups.size(); ++i) {
|
||||
const QVector<int> *subItems = m_groups.at(i);
|
||||
if (subItems->isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 使用group属性进行分组
|
||||
QString groupA = sourceIndex.data(DataEntity::Group).toString();
|
||||
QString groupB = sourceModel()->index(subItems->at(0), 0).data(DataEntity::Group).toString();
|
||||
if (groupA == groupB) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void AppGroupModel::insertApp(int groupIndex, const QModelIndex &sourceIndex)
|
||||
{
|
||||
if (groupIndex < 0 || groupIndex >= m_groups.size()) {
|
||||
beginInsertRows(QModelIndex(), m_groups.size(), m_groups.size());
|
||||
m_groups.append(new QVector<int>(1, sourceIndex.row()));
|
||||
endInsertRows();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int index = 0;
|
||||
int newItem = sourceIndex.row();
|
||||
QVector<int> *subItems = m_groups[groupIndex];
|
||||
for (; index < subItems->size(); ++index) {
|
||||
if (newItem < subItems->at(index)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
beginInsertRows(AppGroupModel::index(groupIndex, 0, QModelIndex()), index, index);
|
||||
subItems->insert(index, newItem);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
// slots
|
||||
void AppGroupModel::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
|
||||
{
|
||||
for (int i = topLeft.row(); i <= bottomRight.row(); ++i) {
|
||||
QModelIndex proxyIndex = mapFromSource(sourceModel()->index(i, 0));
|
||||
Q_EMIT dataChanged(proxyIndex, proxyIndex, roles);
|
||||
}
|
||||
}
|
||||
|
||||
void AppGroupModel::onLayoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
|
||||
{
|
||||
Q_UNUSED(parents)
|
||||
Q_UNUSED(hint)
|
||||
beginResetModel();
|
||||
rebuildAppGroups();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void AppGroupModel::onRowsInserted(const QModelIndex &parent, int first, int last)
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (first < (sourceModel()->rowCount() - 1)) {
|
||||
reLocationIndex(first, (last - first + 1));
|
||||
}
|
||||
|
||||
for (int i = first; i <= last; ++i) {
|
||||
QModelIndex sourceIndex = sourceModel()->index(i, 0, parent);
|
||||
insertApp(findGroupIndex(sourceIndex), sourceIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void AppGroupModel::reLocationIndex(int base, int offset)
|
||||
{
|
||||
for (QVector<int> *group : m_groups) {
|
||||
QMutableVectorIterator<int> it(*group);
|
||||
while (it.hasNext()) {
|
||||
const int &value = it.next();
|
||||
if (value >= base) {
|
||||
it.setValue(value + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppGroupModel::onRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int groupIndex = 0, itemIndex = 0;
|
||||
for (int i = first; i <= last; ++i) {
|
||||
groupIndex = findGroupIndex(sourceModel()->index(i, 0));
|
||||
if (groupIndex < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto subItems = m_groups[groupIndex];
|
||||
itemIndex = subItems->indexOf(i);
|
||||
if (itemIndex < 0) {
|
||||
// 如果出现错误,那么重新构建映射关系
|
||||
m_needRebuild = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// 删除组里的元素
|
||||
beginRemoveRows(index(groupIndex, 0, QModelIndex()), itemIndex, itemIndex);
|
||||
subItems->removeAt(itemIndex);
|
||||
endRemoveRows();
|
||||
|
||||
// 删除组
|
||||
if (subItems->isEmpty()) {
|
||||
beginRemoveRows(QModelIndex(), groupIndex, groupIndex);
|
||||
delete m_groups.takeAt(groupIndex);
|
||||
endRemoveRows();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // UkuiMenu
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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_MENU_APP_GROUP_MODEL_H
|
||||
#define UKUI_MENU_APP_GROUP_MODEL_H
|
||||
|
||||
#include <QAbstractProxyModel>
|
||||
#include "data-entity.h"
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
/**
|
||||
* @class AppGroupModel
|
||||
*
|
||||
* 根据app的group属性进行分组,将同一组的应用挂在到某一个索引下
|
||||
*/
|
||||
class AppGroupModel : public QAbstractProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
// Q_PROPERTY(UkuiMenu::DataEntity::PropertyName sourceModel READ sourceModel WRITE setSourceModel NOTIFY sourceModelChanged)
|
||||
public:
|
||||
explicit AppGroupModel(QObject *parent = nullptr);
|
||||
|
||||
void setSourceModel(QAbstractItemModel *sourceModel) override;
|
||||
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
|
||||
QModelIndex parent(const QModelIndex &child) const override;
|
||||
|
||||
bool hasChildren(const QModelIndex &parent) const override;
|
||||
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
int columnCount(const QModelIndex &parent) const override;
|
||||
|
||||
QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
|
||||
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override;
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
QVariant data(const QModelIndex &proxyIndex, int role) const override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
|
||||
void onLayoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
|
||||
void onRowsInserted(const QModelIndex &parent, int first, int last);
|
||||
void onRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
|
||||
|
||||
private:
|
||||
void rebuildAppGroups();
|
||||
void reLocationIndex(int base, int offset);
|
||||
int findGroupIndex(const QModelIndex &sourceIndex) const;
|
||||
void insertApp(int groupIndex, const QModelIndex &sourceIndex);
|
||||
|
||||
private:
|
||||
// 存储分组信息
|
||||
QVector<QVector<int>*> m_groups;
|
||||
bool m_needRebuild {false};
|
||||
};
|
||||
|
||||
} // UkuiMenu
|
||||
|
||||
#endif //UKUI_MENU_APP_GROUP_MODEL_H
|
|
@ -163,7 +163,8 @@ void CombinedListModel::insertSubModel(QAbstractItemModel *subModel, int index)
|
|||
m_subModels.insert(index, {subModel, subModel->rowCount()});
|
||||
}
|
||||
|
||||
connect(subModel, &QAbstractItemModel::rowsRemoved,
|
||||
// 在删除前通知上层model进行处理
|
||||
connect(subModel, &QAbstractItemModel::rowsAboutToBeRemoved,
|
||||
this, [subModel, this] (const QModelIndex &parent, int first, int last) {
|
||||
int offset = offsetOfSubModel(subModel);
|
||||
if (offset >= 0) {
|
||||
|
@ -241,15 +242,13 @@ void CombinedListModel::removeSubModel(QAbstractItemModel *subModel)
|
|||
|
||||
int CombinedListModel::indexOfSubModel(QAbstractItemModel *subModel)
|
||||
{
|
||||
int index = -1;
|
||||
for (int i = 0; i < m_subModels.size(); ++i) {
|
||||
if (m_subModels.at(i).first == subModel) {
|
||||
index = i;
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // UkuiMenu
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "sidebar-button-utils.h"
|
||||
#include "extension/widget-model.h"
|
||||
#include "app-page-backend.h"
|
||||
#include "app-group-model.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QCommandLineParser>
|
||||
|
@ -64,6 +65,7 @@ void UkuiMenuApplication::registerQmlTypes()
|
|||
SidebarButtonUtils::defineModule(uri, versionMajor, versionMinor);
|
||||
|
||||
qmlRegisterType<WidgetModel>(uri, versionMajor, versionMinor, "WidgetModel");
|
||||
qmlRegisterType<AppGroupModel>(uri, versionMajor, versionMinor, "AppGroupModel");
|
||||
qmlRegisterType<AppPageBackend>(uri, versionMajor, versionMinor, "AppPageBackend");
|
||||
qmlRegisterUncreatableType<AppListPluginGroup>(uri, versionMajor, versionMinor, "PluginGroup", "Use enums only.");
|
||||
|
||||
|
|
Loading…
Reference in New Issue