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::Favorite, "favorite");
|
||||||
names.insert(DataEntity::Top, "top");
|
names.insert(DataEntity::Top, "top");
|
||||||
names.insert(DataEntity::RecentInstall, "recentInstall");
|
names.insert(DataEntity::RecentInstall, "recentInstall");
|
||||||
|
names.insert(DataEntity::Entity, "entity");
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,6 +304,8 @@ QVariant DataEntity::getValue(DataEntity::PropertyName property) const
|
||||||
return d->top;
|
return d->top;
|
||||||
case RecentInstall:
|
case RecentInstall:
|
||||||
return d->recentInstall;
|
return d->recentInstall;
|
||||||
|
case Entity:
|
||||||
|
return QVariant::fromValue(*this);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,13 +61,14 @@ public:
|
||||||
Category, /**> 应用类别 */
|
Category, /**> 应用类别 */
|
||||||
Group, /**> 应用分组 */
|
Group, /**> 应用分组 */
|
||||||
FirstLetter, /**> 应用名称首字母 */
|
FirstLetter, /**> 应用名称首字母 */
|
||||||
InstallationTime, /**> 安装时间 */
|
InstallationTime, /**> 安装时间 format: yyyy-MM-dd hh:mm:ss */
|
||||||
IsLaunched, /**> 是否启动过该程序 */
|
IsLaunched, /**> 是否启动过该程序 */
|
||||||
LaunchTimes, /**> 应用被启动的次数 */
|
LaunchTimes, /**> 应用被启动的次数 */
|
||||||
IsLocked, /**> 应用是否锁定 */
|
IsLocked, /**> 应用是否锁定 */
|
||||||
Favorite, /**> 是否被收藏及序号, 小于或等于0表示未被收藏 */
|
Favorite, /**> 是否被收藏及序号, 小于或等于0表示未被收藏 */
|
||||||
Top, /**> 是否被置顶及序号, 小于或等于0表示未被置顶 */
|
Top, /**> 是否被置顶及序号, 小于或等于0表示未被置顶 */
|
||||||
RecentInstall
|
RecentInstall,
|
||||||
|
Entity /**> 返回自己的拷贝 */
|
||||||
};
|
};
|
||||||
DataEntity();
|
DataEntity();
|
||||||
DataEntity(DataType::Type type, const QString& name, const QString& icon, const QString& comment, const QString& extraData);
|
DataEntity(DataType::Type type, const QString& name, const QString& icon, const QString& comment, const QString& extraData);
|
||||||
|
@ -140,5 +141,6 @@ private:
|
||||||
} // UkuiMenu
|
} // UkuiMenu
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(UkuiMenu::DataType)
|
Q_DECLARE_METATYPE(UkuiMenu::DataType)
|
||||||
|
Q_DECLARE_METATYPE(UkuiMenu::DataEntity)
|
||||||
|
|
||||||
#endif //UKUI_MENU_DATA_ENTITY_H
|
#endif //UKUI_MENU_DATA_ENTITY_H
|
||||||
|
|
|
@ -32,6 +32,7 @@ class ContextMenuExtension;
|
||||||
|
|
||||||
class Q_DECL_EXPORT MenuExtensionPlugin : public QObject
|
class Q_DECL_EXPORT MenuExtensionPlugin : public QObject
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit MenuExtensionPlugin(QObject *parent = nullptr);
|
explicit MenuExtensionPlugin(QObject *parent = nullptr);
|
||||||
~MenuExtensionPlugin() override;
|
~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"
|
#include "app-database-interface.h"
|
||||||
|
@ -46,6 +62,7 @@ private:
|
||||||
|
|
||||||
UkuiSearch::ApplicationInfo *appDatabase {nullptr};
|
UkuiSearch::ApplicationInfo *appDatabase {nullptr};
|
||||||
UkuiSearch::ApplicationProperties properties;
|
UkuiSearch::ApplicationProperties properties;
|
||||||
|
// 设置我们需要的属性和值
|
||||||
UkuiSearch::ApplicationPropertyMap filter;
|
UkuiSearch::ApplicationPropertyMap filter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -80,7 +97,7 @@ AppDatabaseWorkerPrivate::AppDatabaseWorkerPrivate(AppDatabaseInterface *parent)
|
||||||
<< UkuiSearch::ApplicationProperty::Property::InsertTime
|
<< UkuiSearch::ApplicationProperty::Property::InsertTime
|
||||||
<< UkuiSearch::ApplicationProperty::Property::Launched;
|
<< UkuiSearch::ApplicationProperty::Property::Launched;
|
||||||
|
|
||||||
// 需要从数据库过滤的属性
|
// 需要从数据库过滤的属性,满足该条件的数据才会被查询出来
|
||||||
filter.insert(UkuiSearch::ApplicationProperty::Property::DontDisplay, 0);
|
filter.insert(UkuiSearch::ApplicationProperty::Property::DontDisplay, 0);
|
||||||
filter.insert(UkuiSearch::ApplicationProperty::Property::AutoStart, 0);
|
filter.insert(UkuiSearch::ApplicationProperty::Property::AutoStart, 0);
|
||||||
|
|
||||||
|
@ -113,11 +130,16 @@ bool AppDatabaseWorkerPrivate::isFiltered(const UkuiSearch::ApplicationPropertyM
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
iterator.next();
|
iterator.next();
|
||||||
if (appInfo.value(iterator.key()) == iterator.value()) {
|
if (appInfo.value(iterator.key()) == iterator.value()) {
|
||||||
return true;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
// TODO: 根据数据的类型进行比较
|
||||||
|
// bool equals = false;
|
||||||
|
// QVariant value = appInfo.value(iterator.key());
|
||||||
|
// value.userType();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataEntityVector AppDatabaseWorkerPrivate::getAllApps()
|
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
|
#ifndef UKUI_MENU_APP_DATABASE_INTERFACE_H
|
||||||
#define 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"
|
#include "basic-app-model.h"
|
||||||
|
|
||||||
|
@ -8,6 +24,12 @@
|
||||||
|
|
||||||
namespace UkuiMenu {
|
namespace UkuiMenu {
|
||||||
|
|
||||||
|
BasicAppModel *BasicAppModel::instance()
|
||||||
|
{
|
||||||
|
static BasicAppModel model;
|
||||||
|
return &model;
|
||||||
|
}
|
||||||
|
|
||||||
BasicAppModel::BasicAppModel(QObject *parent) : QAbstractListModel(parent)
|
BasicAppModel::BasicAppModel(QObject *parent) : QAbstractListModel(parent)
|
||||||
, m_databaseInterface(new AppDatabaseInterface(this))
|
, m_databaseInterface(new AppDatabaseInterface(this))
|
||||||
{
|
{
|
||||||
|
@ -90,7 +112,7 @@ QHash<int, QByteArray> BasicAppModel::roleNames() const
|
||||||
return DataEntity::AppRoleNames();
|
return DataEntity::AppRoleNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
AppDatabaseInterface *BasicAppModel::databaseInterface() const
|
const AppDatabaseInterface *BasicAppModel::databaseInterface() const
|
||||||
{
|
{
|
||||||
return m_databaseInterface;
|
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
|
#ifndef UKUI_MENU_BASIC_APP_MODEL_H
|
||||||
#define UKUI_MENU_BASIC_APP_MODEL_H
|
#define UKUI_MENU_BASIC_APP_MODEL_H
|
||||||
|
@ -17,13 +33,13 @@ class BasicAppModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit BasicAppModel(QObject *parent = nullptr);
|
static BasicAppModel *instance();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据库访问接口
|
* 数据库访问接口
|
||||||
* @return @AppDatabaseInterface *
|
* @return @AppDatabaseInterface *
|
||||||
*/
|
*/
|
||||||
AppDatabaseInterface *databaseInterface() const;
|
const AppDatabaseInterface *databaseInterface() const;
|
||||||
DataEntity appOfIndex(int row) const;
|
DataEntity appOfIndex(int row) const;
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent) const override;
|
int rowCount(const QModelIndex &parent) const override;
|
||||||
|
@ -38,6 +54,7 @@ private Q_SLOTS:
|
||||||
void onAppDeleted(const QStringList &apps);
|
void onAppDeleted(const QStringList &apps);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
explicit BasicAppModel(QObject *parent = nullptr);
|
||||||
int indexOfApp(const QString &appid) const;
|
int indexOfApp(const QString &appid) const;
|
||||||
AppDatabaseInterface *m_databaseInterface {nullptr};
|
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