feat: 添加最近安装和应用分类model
This commit is contained in:
parent
ade3df6014
commit
f3e9858b88
|
@ -233,6 +233,7 @@ QHash<int, QByteArray> DataEntity::AppRoleNames()
|
|||
names.insert(DataEntity::Favorite, "favorite");
|
||||
names.insert(DataEntity::Top, "top");
|
||||
names.insert(DataEntity::RecentInstall, "recentInstall");
|
||||
names.insert(DataEntity::Entity, "entity");
|
||||
return names;
|
||||
}
|
||||
|
||||
|
@ -303,6 +304,8 @@ QVariant DataEntity::getValue(DataEntity::PropertyName property) const
|
|||
return d->top;
|
||||
case RecentInstall:
|
||||
return d->recentInstall;
|
||||
case Entity:
|
||||
return QVariant::fromValue(*this);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -61,13 +61,14 @@ public:
|
|||
Category, /**> 应用类别 */
|
||||
Group, /**> 应用分组 */
|
||||
FirstLetter, /**> 应用名称首字母 */
|
||||
InstallationTime, /**> 安装时间 */
|
||||
InstallationTime, /**> 安装时间 format: yyyy-MM-dd hh:mm:ss */
|
||||
IsLaunched, /**> 是否启动过该程序 */
|
||||
LaunchTimes, /**> 应用被启动的次数 */
|
||||
IsLocked, /**> 应用是否锁定 */
|
||||
Favorite, /**> 是否被收藏及序号, 小于或等于0表示未被收藏 */
|
||||
Top, /**> 是否被置顶及序号, 小于或等于0表示未被置顶 */
|
||||
RecentInstall
|
||||
RecentInstall,
|
||||
Entity /**> 返回自己的拷贝 */
|
||||
};
|
||||
DataEntity();
|
||||
DataEntity(DataType::Type type, const QString& name, const QString& icon, const QString& comment, const QString& extraData);
|
||||
|
@ -140,5 +141,6 @@ private:
|
|||
} // UkuiMenu
|
||||
|
||||
Q_DECLARE_METATYPE(UkuiMenu::DataType)
|
||||
Q_DECLARE_METATYPE(UkuiMenu::DataEntity)
|
||||
|
||||
#endif //UKUI_MENU_DATA_ENTITY_H
|
||||
|
|
|
@ -32,6 +32,7 @@ class ContextMenuExtension;
|
|||
|
||||
class Q_DECL_EXPORT MenuExtensionPlugin : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MenuExtensionPlugin(QObject *parent = nullptr);
|
||||
~MenuExtensionPlugin() override;
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* 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-category-model.h"
|
||||
#include "basic-app-model.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
AppCategoryModel::AppCategoryModel(QObject *parent) : QSortFilterProxyModel(parent)
|
||||
{
|
||||
m_mainCategories.insert(QStringLiteral("Audio"), {tr("Audio"), 0});
|
||||
m_mainCategories.insert(QStringLiteral("AudioVideo"), {tr("AudioVideo"), 1});
|
||||
m_mainCategories.insert(QStringLiteral("Development"), {tr("Development"), 2});
|
||||
m_mainCategories.insert(QStringLiteral("Education"), {tr("Education"), 3});
|
||||
m_mainCategories.insert(QStringLiteral("Game"), {tr("Game"), 4});
|
||||
m_mainCategories.insert(QStringLiteral("Graphics"), {tr("Graphics"), 5});
|
||||
m_mainCategories.insert(QStringLiteral("Network"), {tr("Network"), 6});
|
||||
m_mainCategories.insert(QStringLiteral("Office"), {tr("Office"), 7});
|
||||
m_mainCategories.insert(QStringLiteral("Science"), {tr("Science"), 8});
|
||||
m_mainCategories.insert(QStringLiteral("Settings"), {tr("Settings"), 9});
|
||||
m_mainCategories.insert(QStringLiteral("System"), {tr("System"), 10});
|
||||
m_mainCategories.insert(QStringLiteral("Utility"), {tr("Utility"), 11});
|
||||
m_mainCategories.insert(QStringLiteral("Video"), {tr("Video"), 12});
|
||||
m_mainCategories.insert(QStringLiteral("Other"), {tr("Other"), 13});
|
||||
|
||||
QSortFilterProxyModel::setSourceModel(BasicAppModel::instance());
|
||||
QSortFilterProxyModel::sort(0);
|
||||
}
|
||||
|
||||
AppCategoryModel::Mode AppCategoryModel::mode() const
|
||||
{
|
||||
return m_mode;
|
||||
}
|
||||
|
||||
void AppCategoryModel::setMode(AppCategoryModel::Mode mode)
|
||||
{
|
||||
if (m_mode == mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_mode = mode;
|
||||
// TODO: 刷新
|
||||
invalidate();
|
||||
}
|
||||
|
||||
QVariant AppCategoryModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!checkIndex(index, CheckIndexOption::IndexIsValid)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (role == DataEntity::Group) {
|
||||
if (m_mode == FirstLatter) {
|
||||
return AppCategoryModel::getFirstLatterUpper(QSortFilterProxyModel::data(index, DataEntity::FirstLetter).toString());
|
||||
} else {
|
||||
return getCategoryName(QSortFilterProxyModel::data(index, DataEntity::Category).toString());
|
||||
}
|
||||
}
|
||||
|
||||
return QSortFilterProxyModel::data(index, role);
|
||||
}
|
||||
|
||||
bool AppCategoryModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
|
||||
{
|
||||
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
|
||||
}
|
||||
|
||||
bool AppCategoryModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
|
||||
{
|
||||
int result = 0;
|
||||
if (m_mode == FirstLatter) {
|
||||
QString leftKey = AppCategoryModel::getFirstLatterUpper(source_left.data(DataEntity::FirstLetter).toString());
|
||||
QString rightKey = AppCategoryModel::getFirstLatterUpper(source_right.data(DataEntity::FirstLetter).toString());
|
||||
|
||||
result = leftKey.compare(rightKey);
|
||||
|
||||
} else {
|
||||
// 按分类进行排序
|
||||
int leftIndex = getCategoryIndex(source_left.data(DataEntity::Category).toString());
|
||||
int rightIndex = getCategoryIndex(source_right.data(DataEntity::Category).toString());
|
||||
|
||||
result = (leftIndex < rightIndex) ? -1 : (leftIndex > rightIndex) ? 1 : 0;
|
||||
}
|
||||
|
||||
if (result == 0) {
|
||||
// 分类相同时,按打开次数排序; model使用的升序排序,为了保持使用次数多的在前,所以此处使用 > 比较符,
|
||||
return source_left.data(DataEntity::LaunchTimes).toInt() > source_right.data(DataEntity::LaunchTimes).toInt();
|
||||
}
|
||||
|
||||
return result < 0;
|
||||
}
|
||||
|
||||
inline QString AppCategoryModel::getCategoryName(const QString &categories) const
|
||||
{
|
||||
return m_mainCategories[getCategoryKey(categories)].first;
|
||||
}
|
||||
|
||||
inline int AppCategoryModel::getCategoryIndex(const QString &categories) const
|
||||
{
|
||||
return m_mainCategories[getCategoryKey(categories)].second;
|
||||
}
|
||||
|
||||
QString AppCategoryModel::getCategoryKey(const QString &categories) const
|
||||
{
|
||||
QStringList list;
|
||||
// 某些应用使用空格(" ")进行分隔,此处做一下处理
|
||||
if (categories.contains( QStringLiteral(";"))) {
|
||||
list = categories.split(QStringLiteral(";"));
|
||||
} else {
|
||||
list = categories.split(QStringLiteral(" "));
|
||||
}
|
||||
|
||||
for (const auto &key : list) {
|
||||
if (m_mainCategories.contains(key)) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
return QStringLiteral("Other");
|
||||
}
|
||||
|
||||
QString AppCategoryModel::getFirstLatterUpper(const QString &pinyinName)
|
||||
{
|
||||
if (!pinyinName.isEmpty()) {
|
||||
QChar first = pinyinName.at(0).toUpper();
|
||||
if (first >= 'A' && first <= 'Z') {
|
||||
return first;
|
||||
} else if (first >= '0' && first <= '9') {
|
||||
return QStringLiteral("#");
|
||||
}
|
||||
}
|
||||
|
||||
return QStringLiteral("&");
|
||||
}
|
||||
|
||||
} // UkuiMenu
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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_CATEGORY_MODEL_H
|
||||
#define UKUI_MENU_APP_CATEGORY_MODEL_H
|
||||
|
||||
#include "app-list-plugin.h"
|
||||
#include <QAction>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
class AppCategoryModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Mode {
|
||||
FirstLatter, /**> 按首字母排序 */
|
||||
Category /**> 按类型排序 */
|
||||
};
|
||||
Q_ENUM(Mode)
|
||||
|
||||
explicit AppCategoryModel(QObject *parent = nullptr);
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
Mode mode() const;
|
||||
void setMode(Mode mode);
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
|
||||
|
||||
private:
|
||||
static QString getFirstLatterUpper(const QString &pinyinName) ;
|
||||
inline QString getCategoryName(const QString &categories) const;
|
||||
inline int getCategoryIndex(const QString &categories) const;
|
||||
QString getCategoryKey(const QString &categories) const;
|
||||
|
||||
private:
|
||||
Mode m_mode { Category };
|
||||
QMap<QString, QPair<QString, int> > m_mainCategories;
|
||||
};
|
||||
|
||||
} // UkuiMenu
|
||||
|
||||
#endif //UKUI_MENU_APP_CATEGORY_MODEL_H
|
|
@ -1,6 +1,22 @@
|
|||
//
|
||||
// Created by hxf on 23-12-11.
|
||||
//
|
||||
/*
|
||||
* 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-database-interface.h"
|
||||
|
@ -46,6 +62,7 @@ private:
|
|||
|
||||
UkuiSearch::ApplicationInfo *appDatabase {nullptr};
|
||||
UkuiSearch::ApplicationProperties properties;
|
||||
// 设置我们需要的属性和值
|
||||
UkuiSearch::ApplicationPropertyMap filter;
|
||||
};
|
||||
|
||||
|
@ -80,7 +97,7 @@ AppDatabaseWorkerPrivate::AppDatabaseWorkerPrivate(AppDatabaseInterface *parent)
|
|||
<< UkuiSearch::ApplicationProperty::Property::InsertTime
|
||||
<< UkuiSearch::ApplicationProperty::Property::Launched;
|
||||
|
||||
// 需要从数据库过滤的属性
|
||||
// 需要从数据库过滤的属性,满足该条件的数据才会被查询出来
|
||||
filter.insert(UkuiSearch::ApplicationProperty::Property::DontDisplay, 0);
|
||||
filter.insert(UkuiSearch::ApplicationProperty::Property::AutoStart, 0);
|
||||
|
||||
|
@ -113,11 +130,16 @@ bool AppDatabaseWorkerPrivate::isFiltered(const UkuiSearch::ApplicationPropertyM
|
|||
while (iterator.hasNext()) {
|
||||
iterator.next();
|
||||
if (appInfo.value(iterator.key()) == iterator.value()) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: 根据数据的类型进行比较
|
||||
// bool equals = false;
|
||||
// QVariant value = appInfo.value(iterator.key());
|
||||
// value.userType();
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
DataEntityVector AppDatabaseWorkerPrivate::getAllApps()
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
//
|
||||
// Created by hxf on 23-12-11.
|
||||
//
|
||||
/*
|
||||
* 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_DATABASE_INTERFACE_H
|
||||
#define UKUI_MENU_APP_DATABASE_INTERFACE_H
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
//
|
||||
// Created by hxf on 23-12-11.
|
||||
//
|
||||
/*
|
||||
* 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 "basic-app-model.h"
|
||||
|
||||
|
@ -8,6 +24,12 @@
|
|||
|
||||
namespace UkuiMenu {
|
||||
|
||||
BasicAppModel *BasicAppModel::instance()
|
||||
{
|
||||
static BasicAppModel model;
|
||||
return &model;
|
||||
}
|
||||
|
||||
BasicAppModel::BasicAppModel(QObject *parent) : QAbstractListModel(parent)
|
||||
, m_databaseInterface(new AppDatabaseInterface(this))
|
||||
{
|
||||
|
@ -90,7 +112,7 @@ QHash<int, QByteArray> BasicAppModel::roleNames() const
|
|||
return DataEntity::AppRoleNames();
|
||||
}
|
||||
|
||||
AppDatabaseInterface *BasicAppModel::databaseInterface() const
|
||||
const AppDatabaseInterface *BasicAppModel::databaseInterface() const
|
||||
{
|
||||
return m_databaseInterface;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
//
|
||||
// Created by hxf on 23-12-11.
|
||||
//
|
||||
/*
|
||||
* 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_BASIC_APP_MODEL_H
|
||||
#define UKUI_MENU_BASIC_APP_MODEL_H
|
||||
|
@ -17,13 +33,13 @@ class BasicAppModel : public QAbstractListModel
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit BasicAppModel(QObject *parent = nullptr);
|
||||
static BasicAppModel *instance();
|
||||
|
||||
/**
|
||||
* 数据库访问接口
|
||||
* @return @AppDatabaseInterface *
|
||||
*/
|
||||
AppDatabaseInterface *databaseInterface() const;
|
||||
const AppDatabaseInterface *databaseInterface() const;
|
||||
DataEntity appOfIndex(int row) const;
|
||||
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
|
@ -38,6 +54,7 @@ private Q_SLOTS:
|
|||
void onAppDeleted(const QStringList &apps);
|
||||
|
||||
private:
|
||||
explicit BasicAppModel(QObject *parent = nullptr);
|
||||
int indexOfApp(const QString &appid) const;
|
||||
AppDatabaseInterface *m_databaseInterface {nullptr};
|
||||
|
||||
|
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* 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 "combined-list-model.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
// CombinedListModel
|
||||
CombinedListModel::CombinedListModel(QObject *parent) : QAbstractItemModel(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QModelIndex CombinedListModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (column != 0 || row < 0 || row >= rowCount(QModelIndex())) {
|
||||
return {};
|
||||
}
|
||||
|
||||
int start = 0;
|
||||
for (const auto &pair : m_subModels) {
|
||||
int rc = pair.second;
|
||||
if (row < (start + rc)) {
|
||||
return createIndex(row, 0, pair.first);
|
||||
} else {
|
||||
start += rc;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QModelIndex CombinedListModel::parent(const QModelIndex &child) const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
int CombinedListModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
int count = 0;
|
||||
for (const auto &pair : m_subModels) {
|
||||
count += pair.second;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int CombinedListModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> CombinedListModel::roleNames() const
|
||||
{
|
||||
return QAbstractItemModel::roleNames();
|
||||
}
|
||||
|
||||
QModelIndex CombinedListModel::mapToSource(const QModelIndex &proxyIndex) const
|
||||
{
|
||||
if (!proxyIndex.isValid()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto sourceModel = static_cast<QAbstractItemModel*>(proxyIndex.internalPointer());
|
||||
if (!sourceModel) {
|
||||
return {};
|
||||
}
|
||||
|
||||
int offset = offsetOfSubModel(sourceModel);
|
||||
if (offset < 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return sourceModel->index(proxyIndex.row() - offset, 0);
|
||||
}
|
||||
|
||||
QModelIndex CombinedListModel::mapFromSource(const QModelIndex &sourceIndex) const
|
||||
{
|
||||
if (!sourceIndex.isValid()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
int offset = offsetOfSubModel(sourceIndex.model());
|
||||
if (offset < 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return createIndex(offset + sourceIndex.row(), 0);
|
||||
}
|
||||
|
||||
int CombinedListModel::offsetOfSubModel(const QAbstractItemModel *subModel) const
|
||||
{
|
||||
int offset = 0;
|
||||
for (const auto &pair : m_subModels) {
|
||||
if (pair.first == subModel) {
|
||||
return offset;
|
||||
} else {
|
||||
offset += pair.second;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
QVariant CombinedListModel::data(const QModelIndex &proxyIndex, int role) const
|
||||
{
|
||||
if (!checkIndex(proxyIndex, CheckIndexOption::IndexIsValid)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
QModelIndex sourceIndex = mapToSource(proxyIndex);
|
||||
if (!sourceIndex.isValid()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return sourceIndex.data(role);
|
||||
}
|
||||
|
||||
int CombinedListModel::subModelCount() const
|
||||
{
|
||||
return m_subModels.size();
|
||||
}
|
||||
|
||||
const QAbstractItemModel *CombinedListModel::subModelAt(int index) const
|
||||
{
|
||||
if (index < 0 || index >= m_subModels.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_subModels.at(index).first;
|
||||
}
|
||||
|
||||
void CombinedListModel::insertSubModel(QAbstractItemModel *subModel, int index)
|
||||
{
|
||||
if (!subModel || offsetOfSubModel(subModel) >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
beginResetModel();
|
||||
|
||||
if (index < 0 || index > m_subModels.size()) {
|
||||
m_subModels.append({subModel, subModel->rowCount()});
|
||||
} else {
|
||||
m_subModels.insert(index, {subModel, subModel->rowCount()});
|
||||
}
|
||||
|
||||
connect(subModel, &QAbstractItemModel::rowsRemoved,
|
||||
this, [subModel, this] (const QModelIndex &parent, int first, int last) {
|
||||
int offset = offsetOfSubModel(subModel);
|
||||
if (offset >= 0) {
|
||||
beginRemoveRows(mapFromSource(parent), offset + first, offset + last);
|
||||
for (auto &pair : m_subModels) {
|
||||
if (pair.first == subModel) {
|
||||
// pair.second = subModel->rowCount();
|
||||
pair.second = pair.second - (last - first + 1);
|
||||
}
|
||||
}
|
||||
endRemoveRows();
|
||||
}
|
||||
});
|
||||
|
||||
connect(subModel, &QAbstractItemModel::rowsInserted,
|
||||
this, [subModel, this] (const QModelIndex &parent, int first, int last) {
|
||||
int offset = offsetOfSubModel(subModel);
|
||||
if (offset >= 0) {
|
||||
beginInsertRows(mapFromSource(parent), offset + first, offset + last);
|
||||
for (auto &pair : m_subModels) {
|
||||
if (pair.first == subModel) {
|
||||
// pair.second = subModel->rowCount();
|
||||
pair.second = pair.second + (last - first + 1);
|
||||
}
|
||||
}
|
||||
endInsertRows();
|
||||
}
|
||||
});
|
||||
|
||||
connect(subModel, &QAbstractItemModel::dataChanged,
|
||||
this, [subModel, this] (const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) {
|
||||
Q_EMIT dataChanged( mapFromSource(topLeft), mapFromSource(bottomRight), roles);
|
||||
});
|
||||
|
||||
connect(subModel, &QAbstractItemModel::modelReset, this, [subModel, this] {
|
||||
beginResetModel();
|
||||
for (auto &pair : m_subModels) {
|
||||
if (pair.first == subModel) {
|
||||
pair.second = pair.second;
|
||||
}
|
||||
}
|
||||
endResetModel();
|
||||
});
|
||||
|
||||
connect(subModel, &QAbstractItemModel::layoutAboutToBeChanged, this, [this] {
|
||||
emit layoutAboutToBeChanged();
|
||||
});
|
||||
|
||||
connect(subModel, &QAbstractItemModel::layoutChanged, this, [this] {
|
||||
emit layoutChanged();
|
||||
});
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void CombinedListModel::removeSubModel(int index)
|
||||
{
|
||||
if (index < 0 || index >= m_subModels.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QPair<QAbstractItemModel*, int> pair = m_subModels[index];
|
||||
int offset = offsetOfSubModel(pair.first);
|
||||
|
||||
beginRemoveRows(QModelIndex(), offset, offset + pair.second);
|
||||
pair = m_subModels.takeAt(index);
|
||||
disconnect(pair.first, nullptr, this, nullptr);
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
void CombinedListModel::removeSubModel(QAbstractItemModel *subModel)
|
||||
{
|
||||
removeSubModel(indexOfSubModel(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 index;
|
||||
}
|
||||
|
||||
} // UkuiMenu
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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_COMBINED_LIST_MODEL_H
|
||||
#define UKUI_MENU_COMBINED_LIST_MODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QVector>
|
||||
#include <QPair>
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
/**
|
||||
* 由多个子model组合成的model
|
||||
*
|
||||
* 通过index设置或获取子model
|
||||
* CombinedListModel
|
||||
*/
|
||||
class CombinedListModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CombinedListModel(QObject *parent = nullptr);
|
||||
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
|
||||
QModelIndex parent(const QModelIndex &child) const override;
|
||||
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
int columnCount(const QModelIndex &parent) const override;
|
||||
|
||||
QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
|
||||
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
QVariant data(const QModelIndex &proxyIndex, int role) const override;
|
||||
|
||||
// 获取subModel的数量
|
||||
int subModelCount() const;
|
||||
|
||||
// 获取index位置和对应的subModel
|
||||
const QAbstractItemModel *subModelAt(int index) const;
|
||||
int indexOfSubModel(QAbstractItemModel *subModel);
|
||||
|
||||
/**
|
||||
* 插入一个subModel
|
||||
* @param subModel
|
||||
* @param index 插入的位置,默认放到最后
|
||||
*/
|
||||
void insertSubModel(QAbstractItemModel *subModel, int index = -1);
|
||||
void removeSubModel(int index);
|
||||
void removeSubModel(QAbstractItemModel *subModel);
|
||||
|
||||
private:
|
||||
int offsetOfSubModel(const QAbstractItemModel *subModel) const;
|
||||
|
||||
private:
|
||||
QVector<QPair<QAbstractItemModel*, int> > m_subModels;
|
||||
};
|
||||
|
||||
} // UkuiMenu
|
||||
|
||||
#endif //UKUI_MENU_COMBINED_LIST_MODEL_H
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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 "recently-installed-model.h"
|
||||
#include "basic-app-model.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
#include <QTimerEvent>
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
// ====== RecentlyInstalledModel ====== //
|
||||
RecentlyInstalledModel::RecentlyInstalledModel(QObject *parent) : QSortFilterProxyModel(parent), m_timer(new QTimer(this))
|
||||
{
|
||||
QSortFilterProxyModel::setSourceModel(BasicAppModel::instance());
|
||||
// 触发排序动作
|
||||
// QSortFilterProxyModel::sort(0, Qt::DescendingOrder);
|
||||
QSortFilterProxyModel::sort(0);
|
||||
|
||||
// 每48小时主动刷新
|
||||
m_timer->setInterval(48 * 3600000);
|
||||
m_timer->start();
|
||||
}
|
||||
|
||||
bool RecentlyInstalledModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
|
||||
{
|
||||
QModelIndex sourceIndex = sourceModel()->index(source_row, 0, source_parent);
|
||||
QDateTime installDate = QDateTime::fromString(sourceIndex.data(DataEntity::InstallationTime).value<QString>(), "yyyy-MM-dd hh:mm:ss");
|
||||
if (!installDate.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QDateTime currentDateTime = QDateTime::currentDateTime();
|
||||
// 安装时间小于当前时间,差距超过48小时
|
||||
// 安装时间小于当前时间,差距在[48-0]小时内
|
||||
// 安装时间大于当前时间
|
||||
qint64 xt = currentDateTime.toSecsSinceEpoch() - installDate.toSecsSinceEpoch();
|
||||
return (xt >= 0) && (xt <= 48 * 3600);
|
||||
}
|
||||
|
||||
bool RecentlyInstalledModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
|
||||
{
|
||||
QDateTime leftInstallDate = QDateTime::fromString(source_left.data(DataEntity::InstallationTime).value<QString>(), "yyyy-MM-dd hh:mm:ss");
|
||||
QDateTime rightInstallDate = QDateTime::fromString(source_right.data(DataEntity::InstallationTime).value<QString>(), "yyyy-MM-dd hh:mm:ss");
|
||||
|
||||
qint64 xt = leftInstallDate.toSecsSinceEpoch() - rightInstallDate.toSecsSinceEpoch();
|
||||
// if (xt == 0) {
|
||||
// return source_left.data(DataEntity::FirstLetter).value<QString>() < source_right.data(DataEntity::FirstLetter).value<QString>();
|
||||
// }
|
||||
|
||||
return xt <= 0;
|
||||
}
|
||||
|
||||
bool RecentlyInstalledModel::event(QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::Timer) {
|
||||
auto timerEvent = static_cast<QTimerEvent*>(event);
|
||||
if (timerEvent->timerId() == m_timer->timerId()) {
|
||||
invalidate();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return QObject::event(event);
|
||||
}
|
||||
|
||||
QVariant RecentlyInstalledModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role == DataEntity::Group) {
|
||||
return QStringLiteral("RecentlyInstalled");
|
||||
}
|
||||
|
||||
return QSortFilterProxyModel::data(index, role);
|
||||
}
|
||||
|
||||
} // UkuiMenu
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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_RECENTLY_INSTALLED_MODEL_H
|
||||
#define UKUI_MENU_RECENTLY_INSTALLED_MODEL_H
|
||||
|
||||
#include "app-list-plugin.h"
|
||||
#include <QSortFilterProxyModel>
|
||||
class QTimer;
|
||||
|
||||
namespace UkuiMenu {
|
||||
|
||||
class RecentlyInstalledModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RecentlyInstalledModel(QObject *parent = nullptr);
|
||||
bool event(QEvent *event) override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
|
||||
|
||||
private:
|
||||
QTimer *m_timer {nullptr};
|
||||
};
|
||||
|
||||
} // UkuiMenu
|
||||
|
||||
//Q_DECLARE_METATYPE(UkuiMenu::RecentlyInstalledModel*)
|
||||
|
||||
#endif //UKUI_MENU_RECENTLY_INSTALLED_MODEL_H
|
Loading…
Reference in New Issue