feat: 添加最近安装和应用分类model

This commit is contained in:
hewenfei 2024-01-09 09:56:50 +08:00
parent ade3df6014
commit f3e9858b88
13 changed files with 801 additions and 20 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -32,6 +32,7 @@ class ContextMenuExtension;
class Q_DECL_EXPORT MenuExtensionPlugin : public QObject
{
Q_OBJECT
public:
explicit MenuExtensionPlugin(QObject *parent = nullptr);
~MenuExtensionPlugin() override;

View File

@ -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

View File

@ -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

View File

@ -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;
}
return false;
// TODO: 根据数据的类型进行比较
// bool equals = false;
// QVariant value = appInfo.value(iterator.key());
// value.userType();
}
return true;
}
DataEntityVector AppDatabaseWorkerPrivate::getAllApps()

View File

@ -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

View File

@ -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;
}

View File

@ -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};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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