Merge branch 'ukss-dev0510' into 'ukss-dev'

新增搜索服务应用数据库接口;新增搜索应用插件功能;搜索服务接口新增设置返回数据结构(应用搜索插件);目录结构优化等;

See merge request kylin-desktop/ukui-search!329
This commit is contained in:
PengfeiZhang 2022-06-14 01:19:34 +00:00
commit 1939d5b865
43 changed files with 2638 additions and 343 deletions

View File

@ -0,0 +1,16 @@
[Desktop Entry]
Name=ukui-search-app-data-service
Name[zh_CN]=应用数据搜索服务
GenericName=ukui-search-app-data-service
GenericName[zh_CN]=应用数据搜索服务
Comment=ukui-search-app-data-service
Comment[zh_CN]=应用数据搜索服务
Exec=/usr/bin/ukui-search-app-data-service %U
Type=Application
Icon=kylin-search
X-UKUI-AutoRestart=true
OnlyShowIn=UKUI
NoDisplay=true
X-UKUI-Autostart-Phase=Application
Terminal=false

View File

@ -32,7 +32,7 @@
#include <QPushButton>
#include <QScrollArea>
#include <QTimer>
#include <libsearch.h>
#include "libsearch.h"
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
#include "xatom-helper.h"
#endif

View File

@ -1,4 +1,4 @@
QT += core gui dbus KWindowSystem xml x11extras
QT += core gui dbus KWindowSystem xml x11extras sql
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

View File

@ -1,40 +0,0 @@
#include "app-db-manager.h"
#include <QDir>
#include <QSqlError>
#include <QSqlQuery>
#include <QDebug>
#include <QApplication>
using namespace UkuiSearch;
#define APP_DATABASE_PATH QDir::homePath()+"/.config/org.ukui/ukui-search/appdata/"+"app-info.db"
#define CONNECTION_NAME QLatin1String("ukss-appdb-connection")
static AppDBManager *global_instance = nullptr;
AppDBManager *AppDBManager::getInstance()
{
if (!global_instance) {
global_instance = new AppDBManager();
}
return global_instance;
}
AppDBManager::AppDBManager(QObject *parent) : QObject(parent), m_database(QSqlDatabase::addDatabase("QSQLITE",CONNECTION_NAME))
{
}
AppDBManager::~AppDBManager()
{
}
void AppDBManager::initDateBaseConnection()
{
if(!m_database.isValid()) {
qWarning() << m_database.lastError();
QApplication::quit();
}
m_database.setDatabaseName(APP_DATABASE_PATH);
if(!m_database.open()) {
qWarning() << m_database.lastError();
QApplication::quit();
}
//todo: 建表
}

View File

@ -1,27 +0,0 @@
#ifndef APPDBMANAGER_H
#define APPDBMANAGER_H
#include <QObject>
#include <QSqlDatabase>
namespace UkuiSearch {
/**
* @brief The AppDBManager class
* 1.desktop文件目录
* 2.
*/
class AppDBManager : public QObject
{
Q_OBJECT
public:
static AppDBManager *getInstance();
void initDateBaseConnection();
private:
explicit AppDBManager(QObject *parent = nullptr);
~AppDBManager();
QSqlDatabase m_database;
};
}
#endif // APPDBMANAGER_H

View File

@ -1,7 +1,9 @@
#ifndef APPINFOTABLEPRIVATE_H
#define APPINFOTABLEPRIVATE_H
#include <QObject>
#include <QSqlDatabase>
#include <app-info-table.h>
namespace UkuiSearch {
class AppInfoTablePrivate : public QObject
{
@ -11,8 +13,45 @@ public:
AppInfoTablePrivate(AppInfoTablePrivate &) = delete;
AppInfoTablePrivate &operator =(const AppInfoTablePrivate &) = delete;
bool setAppFavoritesState(QString &desktopfp, size_t num);
bool setAppTopState(QString &desktopfp, size_t num);
bool setAppLaunchTimes(QString &desktopfp, size_t num);
bool updateAppLaunchTimes(QString &desktopfp);
bool setAppLockState(QString &desktopfp, size_t num);
bool getAllAppDesktopList(QStringList &list);
bool getFavoritesAppList(QStringList &list);
bool getTopAppList(QStringList &list);
bool getLaunchTimesAppList(QStringList &list);
bool getAppCategory(QString &desktopfp, QString &category);
bool getAppInfoResults(QVector<AppInfoTable::AppInfoResult> &appInfoResults);
bool getAppLockState(QString &desktopfp, size_t &num);
bool getAppTopState(QString &desktopfp, size_t &num);
bool getAppLaunchedState(QString &desktopfp, size_t &num);
bool getAppFavoriteState(QString &desktopfp, size_t &num);
bool addAppShortcut2Desktop(QString &desktopfp);
bool addAppShortcut2Panel(QString &desktopfp);
bool getInstallAppMap(QMultiMap<QString, QStringList> &installAppMap);
bool searchInstallApp(QString &keyWord, QStringList &installAppInfoRes);
bool searchInstallApp(QStringList &keyWord, QStringList &installAppInfoRes);
bool uninstallApp(QString &desktopfp);
QString lastError(void) const;
private:
AppInfoTable *q;
~AppInfoTablePrivate();
void initDateBaseConnection();
void openDataBase();
void closeDataBase();
AppInfoTable *q = nullptr;
QSqlDatabase *m_database = nullptr;
QString m_ConnectionName;
};

View File

@ -1,10 +1,790 @@
#include <QDebug>
#include <QtGlobal>
#include <string>
#include <QStandardPaths>
#include <QProcess>
#include <QDBusInterface>
#include <QDBusReply>
#include <QFileInfo>
#include <QTime>
#include <QSqlQuery>
#include <QSqlError>
#include <QApplication>
#include <qt5xdg/XdgDesktopFile>
#include "app-info-table.h"
#include "app-info-table-private.h"
#include "../ukui-search-app-data-service/app-db-common-defines.h"
using namespace UkuiSearch;
AppInfoTablePrivate::AppInfoTablePrivate(AppInfoTable *parent) : QObject(parent), q(parent)
AppInfoTablePrivate::AppInfoTablePrivate(AppInfoTable *parent) : QObject(parent), q(parent), m_database(new QSqlDatabase)
{
while(1) {
srand(QTime(0,0,0).secsTo(QTime::currentTime()));
m_ConnectionName = QString::fromStdString(std::to_string(rand()));//随机生产链接
if (!QSqlDatabase::contains(m_ConnectionName))
break;
}
qDebug() << "App info database currunt connection name:" << m_ConnectionName;
this->openDataBase();
}
bool AppInfoTablePrivate::setAppFavoritesState(QString &desktopfp, size_t num)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QString cmd = QString("UPDATE appInfo SET MODIFYED_TIME='%0', FAVORITES=%1 WHERE DESKTOP_FILE_PATH='%2'")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
.arg(num)
.arg(desktopfp);
if (!sql.exec(cmd)) {
qWarning() << "Set app favorites state failed!" << m_database->lastError();
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}
bool AppInfoTablePrivate::setAppTopState(QString &desktopfp, size_t num)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QString cmd = QString("UPDATE appInfo SET MODIFYED_TIME='%0', TOP=%1 WHERE DESKTOP_FILE_PATH='%2'")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
.arg(num)
.arg(desktopfp);
if (!sql.exec(cmd)) {
qWarning() << "Set app favorites state failed!" << m_database->lastError();
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}
bool AppInfoTablePrivate::setAppLaunchTimes(QString &desktopfp, size_t num)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QString cmd = QString("UPDATE appInfo SET MODIFYED_TIME='%0', LAUNCH_TIMES=%1, LAUNCHED=%2 WHERE DESKTOP_FILE_PATH='%3'")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
.arg(num)
.arg(1)
.arg(desktopfp);
if (!sql.exec(cmd)) {
qWarning() << "Set app favorites state failed!" << m_database->lastError();
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}
bool AppInfoTablePrivate::updateAppLaunchTimes(QString &desktopfp)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QString cmd = QString("SELECT LAUNCH_TIMES FROM appInfo WHERE DESKTOP_FILE_PATH='%1'").arg(desktopfp);
if (sql.exec(cmd)) {
if (sql.next()) {
cmd = QString("UPDATE appInfo SET MODIFYED_TIME='%0', LAUNCH_TIMES=%1, LAUNCHED=%2 WHERE DESKTOP_FILE_PATH='%3'")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
.arg(sql.value(0).toInt() + 1)
.arg(1)
.arg(desktopfp);
if (!sql.exec(cmd)) {
qWarning() << "Set app favorites state failed!" << m_database->lastError();
res = false;
}
} else {
qWarning() << "Failed to exec next!" << cmd;
res = false;
}
} else {
qWarning() << "Failed to exec:" << cmd;
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}
bool AppInfoTablePrivate::setAppLockState(QString &desktopfp, size_t num)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QString cmd = QString("UPDATE appInfo SET MODIFYED_TIME='%0', LOCK=%1 WHERE DESKTOP_FILE_PATH='%2'")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
.arg(num)
.arg(desktopfp);
if (!sql.exec(cmd)) {
qWarning() << "Set app favorites state failed!" << m_database->lastError();
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}
bool AppInfoTablePrivate::getAllAppDesktopList(QStringList &list)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QString cmd = QString("SELECT DESKTOP_FILE_PATH FROM appInfo");
if (sql.exec(cmd)) {
while (sql.next()) {
list.append(sql.value(0).toString());
}
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}
bool AppInfoTablePrivate::getFavoritesAppList(QStringList &list)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QSqlQuery sqlque(*m_database);
QString cmd = QString("SELECT DESKTOP_FILE_PATH FROM appInfo WHERE FAVORITES!=0 ORDER BY FAVORITES");
int count = 0;
if (sql.exec(cmd)) {
while (sql.next()) {
list.append(sql.value(0).toString());
cmd = QString("UPDATE appInfo SET FAVORITES=%1 WHERE DESKTOP_FILE_PATH='%2'")
.arg(++count)
.arg(sql.value(0).toString());
if (!sqlque.exec(cmd)) {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
break;
}
}
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}
bool AppInfoTablePrivate::getTopAppList(QStringList &list)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QSqlQuery sqlque(*m_database);
QString cmd = QString("SELECT DESKTOP_FILE_PATH FROM appInfo WHERE TOP!=0 ORDER BY TOP");
int count = 0;
if (sql.exec(cmd)) {
while (sql.next()) {
list.append(sql.value(0).toString());
cmd = QString("UPDATE appInfo SET TOP=%1 WHERE DESKTOP_FILE_PATH='%2'")
.arg(++count)
.arg(sql.value(0).toString());
if (!sqlque.exec(cmd)) {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
break;
}
}
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}
bool AppInfoTablePrivate::getLaunchTimesAppList(QStringList &list)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QSqlQuery sqlque(*m_database);
QString cmd = QString("SELECT DESKTOP_FILE_PATH FROM appInfo ORDER BY LAUNCH_TIMES");
int count = 0;
if (sql.exec(cmd)) {
while (sql.next()) {
list.append(sql.value(0).toString());
cmd = QString("UPDATE appInfo SET TOP=%1 WHERE DESKTOP_FILE_PATH='%2'")
.arg(++count)
.arg(sql.value(0).toString());
if (!sqlque.exec(cmd)) {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
break;
}
}
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}
bool AppInfoTablePrivate::getAppCategory(QString &desktopfp, QString &category)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QString cmd = QString("SELECT CATEGORY FROM appInfo WHERE DESKTOP_FILE_PATH='%0'")
.arg(desktopfp);
if (sql.exec(cmd)) {
if (sql.next()) {
category = sql.value(0).toString();
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}
bool AppInfoTablePrivate::getAppInfoResults(QVector<AppInfoTable::AppInfoResult> &appInfoResults)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QString cmd = QString("SELECT DESKTOP_FILE_PATH,LOCAL_NAME,ICON,CATEGORY,TOP,FAVORITES,LAUNCH_TIMES,LOCK FROM appInfo");
if (sql.exec(cmd)) {
while (sql.next()) {
AppInfoTable::AppInfoResult result;
result.desktopPath = sql.value(0).toString();
result.appLocalName = sql.value(1).toString();
result.iconName = sql.value(2).toString();
result.category = sql.value(3).toString();
result.top = sql.value(4).toInt();
result.favorate = sql.value(5).toInt();
result.launchTimes = sql.value(6).toInt();
result.lock = sql.value(7).toInt();
appInfoResults.append(std::move(result));
}
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}
bool AppInfoTablePrivate::getAppLockState(QString &desktopfp, size_t &num)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QString cmd = QString("SELECT LOCK FROM appInfo WHERE DESKTOP_FILE_PATH='%0'")
.arg(desktopfp);
if (sql.exec(cmd)) {
if (sql.next()) {
num = sql.value(0).toInt();
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}
bool AppInfoTablePrivate::getAppTopState(QString &desktopfp, size_t &num)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QString cmd = QString("SELECT TOP FROM appInfo WHERE DESKTOP_FILE_PATH='%0'")
.arg(desktopfp);
if (sql.exec(cmd)) {
if (sql.next()) {
num = sql.value(0).toInt();
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}
bool AppInfoTablePrivate::getAppLaunchedState(QString &desktopfp, size_t &num)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QString cmd = QString("SELECT LAUNCHED FROM appInfo WHERE DESKTOP_FILE_PATH='%0'")
.arg(desktopfp);
if (sql.exec(cmd)) {
if (sql.next()) {
num = sql.value(0).toInt();
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}
bool AppInfoTablePrivate::getAppFavoriteState(QString &desktopfp, size_t &num)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QString cmd = QString("SELECT FAVORITES FROM appInfo WHERE DESKTOP_FILE_PATH='%0'")
.arg(desktopfp);
if (sql.exec(cmd)) {
if (sql.next()) {
num = sql.value(0).toInt();
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}
bool AppInfoTablePrivate::addAppShortcut2Desktop(QString &desktopfp)
{
bool res(true);
QString dirpath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
QFileInfo fileInfo(desktopfp);
QString desktopfn = fileInfo.fileName();
QFile file(desktopfp);
QString newName = QString(dirpath + "/" + desktopfn);
if(file.copy(QString(dirpath + "/" + desktopfn))) {
QProcess process;
process.startDetached(QString("chmod a+x %1").arg(newName));
} else {
res = false;
}
return res;
}
bool AppInfoTablePrivate::addAppShortcut2Panel(QString &desktopfp)
{
bool res(true);
QDBusInterface iface("com.ukui.panel.desktop",
"/",
"com.ukui.panel.desktop",
QDBusConnection::sessionBus());
if(iface.isValid()) {
QDBusReply<bool> isExist = iface.call("CheckIfExist", desktopfp);
if(isExist) {
qWarning() << "Add shortcut to panel failed, because it is already existed!";
} else {
QDBusReply<bool> ret = iface.call("AddToTaskbar", desktopfp);
if (ret.value()) {
qDebug() << "Add shortcut to panel success.";
} else {
qWarning() << "Add shortcut to panel failed, reply:" << ret.error();
res = false;
}
}
} else {
res = false;
}
return res;
}
bool AppInfoTablePrivate::searchInstallApp(QString &keyWord, QStringList &installAppInfoRes)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QString cmd;
if (keyWord.size() < 2) {
cmd = QString("SELECT DESKTOP_FILE_PATH,LOCAL_NAME,ICON FROM appInfo WHERE LOCAL_NAME OR NAME_EN OR NAME_ZH OR FIRST_LETTER_OF_PINYIN LIKE '%%0%' ORDER BY FAVORITES DESC")
.arg(keyWord);
} else {
cmd = QString("SELECT DESKTOP_FILE_PATH,LOCAL_NAME,ICON FROM appInfo WHERE LOCAL_NAME OR NAME_EN OR NAME_ZH OR PINYIN_NAME OR FIRST_LETTER_OF_PINYIN LIKE '%%0%' ORDER BY FAVORITES DESC")
.arg(keyWord);
}
if (sql.exec(cmd)) {
while (sql.next()) {
installAppInfoRes << sql.value(0).toString() << sql.value(1).toString() << sql.value(2).toString();
}
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}
bool AppInfoTablePrivate::searchInstallApp(QStringList &keyWord, QStringList &installAppInfoRes)
{
bool res(true);
if (m_database->transaction() or keyWord.size() != 0) {
QSqlQuery sql(*m_database);
QString cmd;
if (keyWord.at(0).size() < 2) {
cmd = QString("SELECT DESKTOP_FILE_PATH,LOCAL_NAME,ICON,NAME_EN,NAME_ZH,FIRST_LETTER_OF_PINYIN FROM appInfo"
" WHERE LOCAL_NAME LIKE '%%0%' OR NAME_EN LIKE '%%0%' OR NAME_ZH LIKE '%%0%' OR FIRST_LETTER_OF_PINYIN LIKE '%%0%'")
.arg(keyWord.at(0));
} else {
cmd = QString("SELECT DESKTOP_FILE_PATH,LOCAL_NAME,ICON,NAME_EN,NAME_ZH,FIRST_LETTER_OF_PINYIN FROM appInfo"
" WHERE LOCAL_NAME LIKE '%%0%' OR NAME_EN LIKE '%%0%' OR NAME_ZH LIKE '%%0%' OR PINYIN_NAME LIKE '%%0%' OR FIRST_LETTER_OF_PINYIN LIKE '%%0%'")
.arg(keyWord.at(0));
}
for (int i = 0; ++i<keyWord.size();) {
if (keyWord.at(i).size() < 2) {
cmd += QString(" AND (LOCAL_NAME LIKE '%%1%' OR NAME_EN LIKE '%%1%' OR NAME_ZH LIKE '%%1%' OR FIRST_LETTER_OF_PINYIN LIKE '%%1%')")
.arg(keyWord.at(i));
} else {
cmd += QString(" AND (LOCAL_NAME LIKE '%%1%' OR NAME_EN LIKE '%%1%' OR NAME_ZH LIKE '%%1%' OR PINYIN_NAME LIKE '%%1%' OR FIRST_LETTER_OF_PINYIN LIKE '%%1%')")
.arg(keyWord.at(i));
}
}
cmd += QString(" ORDER BY LENGTH(LOCAL_NAME)");
if (sql.exec(cmd)) {
while (sql.next()) {
installAppInfoRes << sql.value(0).toString() << sql.value(1).toString() << sql.value(2).toString();
}
} else {
qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database->lastError();
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!! keyword size:" << keyWord.size();
res = false;
}
return res;
}
bool AppInfoTablePrivate::uninstallApp(QString &desktopfp)
{
bool res(false);
bool isOsReleaseUbuntu(false);
QFile file("/etc/os-release");
if (file.open(QFile::ReadOnly)) {
QByteArray line = file.readLine();
file.close();
if (QString(line).contains("Ubuntu")) { //目前已无效
isOsReleaseUbuntu = true;
}
}
QString cmd;
QProcess process;
if (!isOsReleaseUbuntu) {
cmd = QString("kylin-uninstaller %1")
.arg(desktopfp.toLocal8Bit().data());
res = QProcess::startDetached(cmd);
qDebug() << "kylin-uninstaller uninstall" << cmd << res;
} else {
cmd = QString("dpkg -S " + desktopfp);
process.start("sh", QStringList() << "-c" << cmd);
process.waitForFinished();
QString output = process.readAllStandardOutput().trimmed();
QString packageName = output.split(":").at(0);
cmd = QString("kylin-installer -remove %0")
.arg(packageName.toLocal8Bit().data());
res = QProcess::startDetached(cmd);
qDebug() << "dpkg -S uninstall" << cmd << res;
}
return res;
}
QString AppInfoTablePrivate::lastError() const
{
return m_database->lastError().text();
}
AppInfoTablePrivate::~AppInfoTablePrivate()
{
this->closeDataBase();
}
void AppInfoTablePrivate::initDateBaseConnection()
{
m_database->setDatabaseName(APP_DATABASE_PATH + APP_DATABASE_NAME);
if(!m_database->open()) {
qWarning() << m_database->lastError();
QApplication::quit();
}
}
void AppInfoTablePrivate::openDataBase()
{
*m_database = QSqlDatabase::addDatabase("QSQLITE", m_ConnectionName);
m_database->setDatabaseName(APP_DATABASE_PATH + APP_DATABASE_NAME);
if(!m_database->open()) {
qWarning() << m_database->lastError();
QApplication::quit();
}
}
void AppInfoTablePrivate::closeDataBase()
{
m_database->close();
delete m_database;
QSqlDatabase::removeDatabase(m_ConnectionName);
}
AppInfoTable::AppInfoTable(QObject *parent) : QObject(parent), d(new AppInfoTablePrivate(this))
{
}
bool AppInfoTable::setAppFavoritesState(QString &desktopfp, size_t num)
{
return d->setAppFavoritesState(desktopfp, num);
}
bool AppInfoTable::setAppTopState(QString &desktopfp, size_t num)
{
return d->setAppTopState(desktopfp, num);
}
bool AppInfoTable::setAppLaunchTimes(QString &desktopfp, size_t num)
{
return d->setAppLaunchTimes(desktopfp, num);
}
bool AppInfoTable::updateAppLaunchTimes(QString &desktopfp)
{
return d->updateAppLaunchTimes(desktopfp);
}
bool AppInfoTable::setAppLockState(QString &desktopfp, size_t num)
{
return d->setAppLockState(desktopfp, num);
}
bool AppInfoTable::getAllAppDesktopList(QStringList &list)
{
return d->getAllAppDesktopList(list);
}
bool AppInfoTable::getFavoritesAppList(QStringList &list)
{
return d->getFavoritesAppList(list);
}
bool AppInfoTable::getTopAppList(QStringList &list)
{
return d->getTopAppList(list);
}
bool AppInfoTable::getLaunchTimesAppList(QStringList &list)
{
return d->getLaunchTimesAppList(list);
}
bool AppInfoTable::getAppCategory(QString &desktopfp, QString &category)
{
return d->getAppCategory(desktopfp, category);
}
bool AppInfoTable::getAppInfoResults(QVector<AppInfoTable::AppInfoResult> &appInfoResults)
{
return d->getAppInfoResults(appInfoResults);
}
bool AppInfoTable::getAppLockState(QString &desktopfp, size_t &num)
{
return d->getAppLockState(desktopfp, num);
}
bool AppInfoTable::getAppTopState(QString &desktopfp, size_t &num)
{
return d->getAppTopState(desktopfp, num);
}
bool AppInfoTable::getAppLaunchedState(QString &desktopfp, size_t &num)
{
return d->getAppLaunchedState(desktopfp, num);
}
bool AppInfoTable::getAppFavoriteState(QString &desktopfp, size_t &num)
{
return d->getAppFavoriteState(desktopfp, num);
}
bool AppInfoTable::addAppShortcut2Desktop(QString &desktopfp)
{
return d->addAppShortcut2Desktop(desktopfp);
}
bool AppInfoTable::addAppShortcut2Panel(QString &desktopfp)
{
return d->addAppShortcut2Panel(desktopfp);
}
bool AppInfoTable::searchInstallApp(QString &keyWord, QStringList &installAppInfoRes)
{
return d->searchInstallApp(keyWord, installAppInfoRes);
}
bool AppInfoTable::searchInstallApp(QStringList &keyWord, QStringList &installAppInfoRes)
{
return d->searchInstallApp(keyWord, installAppInfoRes);
}
bool AppInfoTable::uninstallApp(QString &desktopfp)
{
return d->uninstallApp(desktopfp);
}
QString AppInfoTable::lastError() const
{
return d->lastError();
}

View File

@ -4,29 +4,77 @@
#include <QObject>
namespace UkuiSearch {
class AppInfoTablePrivate;
/**
* @brief The AppInfoTable class
* TODO:
* 1.
* 2.
* 3.
* 4.
* 5.
* 6.
* 7.
* 8.
* 9.
*
*/
class AppInfoTable : public QObject
{
Q_OBJECT
public:
typedef struct appInfoResult
{
appInfoResult() {
top = 0;
favorate = 0;
launchTimes = 0;
lock = 0;
}
QString desktopPath;
QString iconName;
QString appLocalName;
QString firstLetter;
QString category;
size_t top;
size_t favorate;
size_t launchTimes;
size_t lock;
} AppInfoResult;
public:
explicit AppInfoTable(QObject *parent = nullptr);
AppInfoTable(AppInfoTable &) = delete;
AppInfoTable &operator =(const AppInfoTable &) = delete;
bool setAppFavoritesState(QString &desktopfp, size_t num);
bool setAppTopState(QString &desktopfp, size_t num);
bool getAllAppDesktopList(QStringList &list);
bool getFavoritesAppList(QStringList &list);
bool getTopAppList(QStringList &list);
bool getLaunchTimesAppList(QStringList &list);
bool getAppCategory(QString &desktopfp, QString &category);
/**
* @brief getAppInfoResults
* @param appInfoResults
* @return
*/
bool getAppInfoResults(QVector<AppInfoTable::AppInfoResult> &appInfoResults);
bool getAppLockState(QString &desktopfp, size_t &num);
bool getAppTopState(QString &desktopfp, size_t &num);
bool getAppLaunchedState(QString &desktopfp, size_t &num);
bool getAppFavoriteState(QString &desktopfp, size_t &num);
bool addAppShortcut2Desktop(QString &desktopfp);
bool addAppShortcut2Panel(QString &desktopfp);
bool searchInstallApp(QString &keyWord, QStringList &installAppInfoRes);
bool searchInstallApp(QStringList &keyWord, QStringList &installAppInfoRes);
bool uninstallApp(QString &desktopfp);
/**
* @brief lastError
* @return
*/
QString lastError(void) const;
private:
bool setAppLaunchTimes(QString &desktopfp, size_t num);
bool setAppLockState(QString &desktopfp, size_t num);
bool updateAppLaunchTimes(QString &desktopfp);
AppInfoTablePrivate *d;
};

View File

@ -1,11 +1,9 @@
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/app-db-manager.h \
$$PWD/app-info-table-private.h \
$$PWD/app-info-table.h
SOURCES += \
$$PWD/app-db-manager.cpp \
$$PWD/app-info-table.cpp

View File

@ -21,9 +21,10 @@
#include <glib.h>
#include <qt5xdg/XdgIcon>
#include <qt5xdg/XdgDesktopFile>
#include <QMap>
#include "file-utils.h"
#include "app-search-plugin.h"
#define ANDROID_APP_DESKTOP_PATH QDir::homePath() + "/.local/share/applications/"
using namespace UkuiSearch;
static AppMatch *app_match_Class = nullptr;
@ -36,13 +37,6 @@ AppMatch *AppMatch::getAppMatch() {
AppMatch::AppMatch(QObject *parent) : QThread(parent)
// m_versionCommand(new QProcess(this))
{
m_watchAppDir = new QFileSystemWatcher(this);
m_watchAppDir->addPath("/usr/share/applications/");
QDir androidPath(ANDROID_APP_DESKTOP_PATH);
if(!androidPath.exists()) {
androidPath.mkpath(ANDROID_APP_DESKTOP_PATH);
}
m_watchAppDir->addPath(ANDROID_APP_DESKTOP_PATH);
qDBusRegisterMetaType<QMap<QString, QString>>();
qDBusRegisterMetaType<QList<QMap<QString, QString>>>();
m_interFace = new QDBusInterface("com.kylin.softwarecenter.getsearchresults", "/com/kylin/softwarecenter/getsearchresults",
@ -52,6 +46,7 @@ AppMatch::AppMatch(QObject *parent) : QThread(parent)
qWarning() << qPrintable(QDBusConnection::sessionBus().lastError().message());
}
m_interFace->setTimeout(1500);
m_appInfoTable = new AppInfoTable;
qDebug() << "AppMatch init finished.";
}
@ -60,10 +55,10 @@ AppMatch::~AppMatch() {
delete m_interFace;
}
m_interFace = NULL;
if(m_watchAppDir) {
delete m_watchAppDir;
if(m_appInfoTable) {
delete m_appInfoTable;
}
m_watchAppDir = NULL;
m_appInfoTable = NULL;
}
void AppMatch::startMatchApp(QString input, size_t uniqueSymbol, DataQueue<SearchPluginIface::ResultInfo> *searchResult) {
@ -72,73 +67,6 @@ void AppMatch::startMatchApp(QString input, size_t uniqueSymbol, DataQueue<Searc
qDebug() << "App match finished!";
}
/**
* @brief AppMatch::getAllDesktopFilePath desktop文件
* @param path desktop文件夹
*/
void AppMatch::getAllDesktopFilePath(QString path) {
QDir dir(path);
if(!dir.exists()) {
return;
}
dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
dir.setSorting(QDir::DirsFirst);
QFileInfoList list = dir.entryInfoList();
list.removeAll(QFileInfo("/usr/share/applications/screensavers"));
if(list.size() < 1) {
return;
}
XdgDesktopFile desktopfile;
int i = 0;
while(i < list.size()) {
QFileInfo fileInfo = list.at(i);
//如果是文件夹,递归
bool isDir = fileInfo.isDir();
if(isDir) {
getAllDesktopFilePath(fileInfo.filePath());
qDebug() << fileInfo.filePath();
++i;
} else {
QString filePathStr = fileInfo.filePath();
if(m_ExcludedDesktopfiles.contains(filePathStr)) {
++i;
continue;
}
//过滤后缀不是.desktop的文件
if(!filePathStr.endsWith(".desktop")) {
++i;
continue;
}
desktopfile.load(filePathStr);
if(desktopfile.value("NoDisplay").toString().contains("true") || desktopfile.value("NotShowIn").toString().contains("UKUI")) {
++i;
continue;
}
QString name = desktopfile.localizedValue("Name").toString();
if(name.isEmpty()) {
++i;
qDebug() << filePathStr << "name!!";
continue;
}
QString icon = desktopfile.iconName();
NameString appname;
QStringList appInfolist;
appname.app_name = name;
appInfolist << filePathStr << icon;
appInfolist.append(desktopfile.value("Name").toString());
appInfolist.append(desktopfile.value("Name[zh_CN]").toString());
m_installAppMap.insert(appname, appInfolist);
++i;
}
}
}
/**
* @brief AppMatch::appNameMatch
*
@ -146,7 +74,36 @@ void AppMatch::getAllDesktopFilePath(QString path) {
*
*/
void AppMatch::appNameMatch(QString keyWord, size_t uniqueSymbol, DataQueue<SearchPluginIface::ResultInfo> *searchResult) {
QMapIterator<NameString, QStringList> iter(m_installAppMap);
QStringList results;
//m_appInfoTable->searchInstallAppOrderByFavoritesDesc(keyWord, results);
for (int i = 0; i < results.size() / 3; i++) {
{
QMutexLocker locker(&AppSearchPlugin::m_mutex);
if (uniqueSymbol != AppSearchPlugin::uniqueSymbol) {
return;
}
}
SearchPluginIface::ResultInfo ri;
ri.actionKey = results.at(i*3);
ri.name = results.at(i*3 + 1);
ri.icon = XdgIcon::fromTheme(results.at(i*3 + 2), QIcon(":/res/icons/desktop.png"));
ri.type = 0;
searchResult->enqueue(ri);
}
/* QMultiMap<QString, QStringList> installAppMap;
m_appInfoTable->getInstallAppMap(installAppMap);
QMap<NameString, QStringList> resultAppMap;
for (auto i = installAppMap.begin(); i != installAppMap.end(); ++i) {
NameString name;
name.app_name = i.key();
QStringList infoList;
infoList = i.value();
resultAppMap.insert(name, infoList);
}
QMapIterator<NameString, QStringList> iter(resultAppMap);
while(iter.hasNext()) {
iter.next();
if(iter.key().app_name.contains(keyWord, Qt::CaseInsensitive)) {
@ -224,27 +181,16 @@ void AppMatch::appNameMatch(QString keyWord, size_t uniqueSymbol, DataQueue<Sear
}
}
}
}
}
void AppMatch::softWareCenterSearch(QMap<NameString, QStringList> &softwarereturn) {
// if(m_interFace->timeout() != -1) {
// qWarning() << "softWareCente Dbus is timeout !";
// return;
// }
// slotDBusCallFinished(softwarereturn);
qDebug() << "softWareCenter match app is successful!";
}*/
}
void AppMatch::slotDBusCallFinished(QString keyWord, size_t uniqueSymbol, DataQueue<SearchPluginIface::ResultInfo> *searchResult) {
QDBusReply<QList<QMap<QString, QString>>> reply = m_interFace->call("get_search_result", keyWord); //阻塞,直到远程方法调用完成。
// QDBusPendingReply<QList<QMap<QString,QString>>> reply = *call;
if(reply.isValid()) {
parseSoftWareCenterReturn(reply.value(), uniqueSymbol, searchResult);
} else {
qWarning() << "SoftWareCenter dbus called failed!";
}
// call->deleteLater();
}
void AppMatch::parseSoftWareCenterReturn(QList<QMap<QString, QString>> list, size_t uniqueSymbol, DataQueue<SearchPluginIface::ResultInfo> *searchResult) {
@ -275,24 +221,17 @@ void AppMatch::parseSoftWareCenterReturn(QList<QMap<QString, QString>> list, siz
}
}
void AppMatch::creatResultInfo(SearchPluginIface::ResultInfo &ri, QMapIterator<NameString, QStringList> &iter, bool isInstalled)
{
// ri.icon = QIcon::fromTheme(iter.value().at(1), QIcon(":/res/icons/desktop.png"));
ri.icon = XdgIcon::fromTheme(iter.value().at(1), QIcon(":/res/icons/desktop.png"));
ri.name = iter.key().app_name;
ri.actionKey = iter.value().at(0);
ri.type = 0; //0 means installed apps.
}
//void AppMatch::creatResultInfo(SearchPluginIface::ResultInfo &ri, QMapIterator<NameString, QStringList> &iter, bool isInstalled)
//{
//// ri.icon = QIcon::fromTheme(iter.value().at(1), QIcon(":/res/icons/desktop.png"));
// ri.icon = XdgIcon::fromTheme(iter.value().at(1), QIcon(":/res/icons/desktop.png"));
// ri.name = iter.key().app_name;
// ri.actionKey = iter.value().at(0);
// ri.type = 0; //0 means installed apps.
//}
void AppMatch::run() {
qDebug() << "App map init..";
this->getAllDesktopFilePath("/usr/share/applications/");
this->getAllDesktopFilePath(ANDROID_APP_DESKTOP_PATH);
connect(m_watchAppDir, &QFileSystemWatcher::directoryChanged, this, [ = ](const QString & path) {
m_installAppMap.clear();
this->getAllDesktopFilePath("/usr/share/applications/");
this->getAllDesktopFilePath(ANDROID_APP_DESKTOP_PATH);
qDebug() << "App map update " << m_installAppMap.size();
});
qDebug() << "App map init finished.." << m_installAppMap.size();
qDebug() << "App map init finished..";
}

View File

@ -29,31 +29,9 @@
#include <QtDBus>
#include <QThread>
#include "search-plugin-iface.h"
#include "../appdata/app-info-table.h"
namespace UkuiSearch {
class NameString {
public:
explicit NameString(const QString &str_) : app_name(str_) {}
NameString() = default;
QString app_name;
bool operator<(const NameString& name) const {
return this->app_name.length() <= name.app_name.length();
}
bool operator==(const NameString& name) const {
return this->app_name == name.app_name;
}
};
//struct NameString
//{
// QString app_name;
// //重载操作符
// inline bool operator < (const NameString& name) const
// {
//// return name.app_name.length() >= app_name.length();
// return true;
// }
//};
class AppMatch : public QThread {
Q_OBJECT
public:
@ -68,61 +46,14 @@ private:
~AppMatch();
void getAllDesktopFilePath(QString path);
void appNameMatch(QString keyWord, size_t uniqueSymbol, DataQueue<SearchPluginIface::ResultInfo> *searchResult);
void softWareCenterSearch(QMap<NameString, QStringList> &softwarereturn);
void parseSoftWareCenterReturn(QList<QMap<QString, QString>> list, size_t uniqueSymbol, DataQueue<SearchPluginIface::ResultInfo> *searchResult);
void creatResultInfo(SearchPluginIface::ResultInfo &ri, QMapIterator<NameString, QStringList> &iter, bool isInstalled = true);
//void creatResultInfo(SearchPluginIface::ResultInfo &ri, QMapIterator<UkuiSearch::NameString, QStringList> &iter, bool isInstalled = true);
AppInfoTable *m_appInfoTable = nullptr;
QString m_sourceText;
size_t m_uniqueSymbol;
DataQueue<SearchPluginIface::ResultInfo> *m_search_result = nullptr;
QDBusInterface *m_interFace = nullptr;
QFileSystemWatcher *m_watchAppDir = nullptr;
QMap<NameString, QStringList> m_installAppMap;
QStringList m_ExcludedDesktopfiles = {
"/usr/share/applications/software-properties-livepatch.desktop",
"/usr/share/applications/mate-color-select.desktop",
"/usr/share/applications/blueman-adapters.desktop",
"/usr/share/applications/blueman-manager.desktop",
"/usr/share/applications/mate-user-guide.desktop",
"/usr/share/applications/nm-connection-editor.desktop",
"/usr/share/applications/debian-uxterm.desktop",
"/usr/share/applications/debian-xterm.desktop",
"/usr/share/applications/im-config.desktop",
"/usr/share/applications/fcitx.desktop",
"/usr/share/applications/fcitx-configtool.desktop",
"/usr/share/applications/onboard-settings.desktop",
"/usr/share/applications/info.desktop",
"/usr/share/applications/ukui-power-preferences.desktop",
"/usr/share/applications/ukui-power-statistics.desktop",
"/usr/share/applications/software-properties-drivers.desktop",
"/usr/share/applications/software-properties-gtk.desktop",
"/usr/share/applications/gnome-session-properties.desktop",
"/usr/share/applications/org.gnome.font-viewer.desktop",
"/usr/share/applications/xdiagnose.desktop",
"/usr/share/applications/gnome-language-selector.desktop",
"/usr/share/applications/mate-notification-properties.desktop",
"/usr/share/applications/transmission-gtk.desktop",
"/usr/share/applications/mpv.desktop",
"/usr/share/applications/system-config-printer.desktop",
"/usr/share/applications/org.gnome.DejaDup.desktop",
"/usr/share/applications/yelp.desktop",
"/usr/share/applications/peony-computer.desktop",
"/usr/share/applications/peony-home.desktop",
"/usr/share/applications/peony-trash.desktop",
//v10
"/usr/share/applications/mate-about.desktop",
"/usr/share/applications/time.desktop",
"/usr/share/applications/network.desktop",
"/usr/share/applications/shares.desktop",
"/usr/share/applications/mate-power-statistics.desktop",
"/usr/share/applications/display-im6.desktop",
"/usr/share/applications/display-im6.q16.desktop",
"/usr/share/applications/openjdk-8-policytool.desktop",
"/usr/share/applications/kylin-io-monitor.desktop",
"/usr/share/applications/wps-office-uninstall.desktop",
};
private Q_SLOTS:
void slotDBusCallFinished(QString keyWord, size_t uniqueSymbol, DataQueue<SearchPluginIface::ResultInfo> *searchResult);

View File

@ -6,7 +6,7 @@
using namespace UkuiSearch;
size_t AppSearchPlugin::uniqueSymbol = 0;
QMutex AppSearchPlugin::m_mutex;
AppSearchPlugin::AppSearchPlugin(QObject *parent) : QObject(parent)
AppSearchPlugin::AppSearchPlugin(QObject *parent) : QObject(parent), m_appSearchTask(new UkuiSearchTask(this))
{
SearchPluginIface::Actioninfo open { 0, tr("Open")};
SearchPluginIface::Actioninfo addtoDesktop { 1, tr("Add Shortcut to Desktop")};
@ -14,10 +14,18 @@ AppSearchPlugin::AppSearchPlugin(QObject *parent) : QObject(parent)
SearchPluginIface::Actioninfo install { 0, tr("Install")};
m_actionInfo_installed << open << addtoDesktop << addtoPanel;
m_actionInfo_not_installed << install;
AppMatch::getAppMatch()->start();
m_pool.setMaxThreadCount(1);
m_pool.setExpiryTimeout(1000);
initDetailPage();
m_appSearchResults = m_appSearchTask->init();
m_appSearchTask->initSearchPlugin(SearchType::Application);
m_appSearchTask->setSearchOnlineApps(true);
m_appSearchTask->setResultDataType(SearchType::Application, UkuiSearch::ApplicationDesktopPath |
UkuiSearch::ApplicationLocalName |
UkuiSearch::ApplicationIconName |
UkuiSearch::ApplicationDescription |
UkuiSearch::IsOnlineApplication);
}
const QString AppSearchPlugin::name()
@ -40,7 +48,7 @@ void AppSearchPlugin::KeywordSearch(QString keyword, DataQueue<SearchPluginIface
m_mutex.lock();
++uniqueSymbol;
m_mutex.unlock();
AppSearch *appsearch = new AppSearch(searchResult, keyword, uniqueSymbol);
AppSearch *appsearch = new AppSearch(searchResult, m_appSearchResults, m_appSearchTask, keyword, uniqueSymbol);
m_pool.start(appsearch);
}
@ -103,7 +111,7 @@ void AppSearchPlugin::openAction(int actionkey, QString key, int type)
QWidget *AppSearchPlugin::detailPage(const ResultInfo &ri)
{
m_currentActionKey = ri.actionKey;
m_iconLabel->setPixmap(ri.icon.pixmap(120, 120));
m_iconLabel->setPixmap(ri.icon.isNull() ? QIcon(":/res/icons/desktop.png").pixmap(120, 120) : ri.icon.pixmap(120, 120));
QFontMetrics fontMetrics = m_nameLabel->fontMetrics();
QString showname = fontMetrics.elidedText(ri.name, Qt::ElideRight, 215); //当字体长度超过215时显示为省略号
m_nameLabel->setText(FileUtils::setAllTextBold(showname));
@ -206,16 +214,6 @@ void AppSearchPlugin::initDetailPage()
});
}
//bool AppSearchPlugin::isPreviewEnable(QString key, int type)
//{
// return false;
//}
//QWidget *AppSearchPlugin::previewPage(QString key, int type, QWidget *parent = nullptr)
//{
// return nullptr;
//}
bool AppSearchPlugin::launch(const QString &path)
{
GDesktopAppInfo * desktopAppInfo = g_desktop_app_info_new_from_filename(path.toLocal8Bit().data());
@ -275,11 +273,14 @@ bool AppSearchPlugin::installAppAction(const QString & name) {
}
}
AppSearch::AppSearch(DataQueue<SearchPluginIface::ResultInfo> *searchResult, const QString &keyword, size_t uniqueSymbol)
AppSearch::AppSearch(DataQueue<SearchPluginIface::ResultInfo> *searchResult, DataQueue<ResultItem>* appSearchResults, UkuiSearchTask *appSearchTask, QString keyword, size_t uniqueSymbol)
{
this->setAutoDelete(true);
m_search_result = searchResult;
m_keyword = keyword;
m_appSearchResults = appSearchResults;
m_appSearchTask = appSearchTask;
m_appSearchTask->clearKeyWords();
m_appSearchTask->addKeyword(keyword);
m_uniqueSymbol = uniqueSymbol;
}
@ -289,5 +290,55 @@ AppSearch::~AppSearch()
void AppSearch::run()
{
AppMatch::getAppMatch()->startMatchApp(m_keyword, m_uniqueSymbol, m_search_result);
m_appSearchTask->startSearch(SearchType::Application);
QTimer timer;
timer.setInterval(3000);
bool is_empty;
while(1) {
is_empty = false;
if(!m_appSearchResults->isEmpty()) {
ResultItem oneResult = m_appSearchResults->dequeue();
SearchPluginIface::ResultInfo ri;
ri.actionKey = oneResult.getExtral().at(0).toString();
ri.name = oneResult.getExtral().at(1).toString();
ri.icon = oneResult.getExtral().at(2).value<QIcon>();
SearchPluginIface::DescriptionInfo description;
description.key = QString(tr("Application Description:"));
description.value = oneResult.getExtral().at(3).toString();
ri.description.append(description);
ri.type = oneResult.getExtral().at(4).toInt();
if (isUniqueSymbolChanged()) {
m_appSearchResults->clear();
break;
}
m_search_result->enqueue(ri);
} else {
is_empty = true;
}
if (isUniqueSymbolChanged()) {
break;
}
if(timer.isActive() && timer.remainingTime() < 0.01) {
qWarning()<<"-------------->stopped by itself";
break;
}
if(is_empty && !timer.isActive()) {
timer.start();
} else if(!is_empty) {
timer.stop();
} else {
QThread::msleep(100);
}
}
}
bool AppSearch::isUniqueSymbolChanged()
{
QMutexLocker locker(&AppSearchPlugin::m_mutex);
if (m_uniqueSymbol != AppSearchPlugin::uniqueSymbol) {
qDebug() << "uniqueSymbol changged, app search finished!";
return true;
} else {
return false;
}
}

View File

@ -8,11 +8,14 @@
#include <QFrame>
#include <QLabel>
#include <QAction>
#include <QDBusInterface>
#include <QDBusReply>
#include <QtDBus>
#include "search-plugin-iface.h"
#include "app-match.h"
#include "action-label.h"
#include "separation-line.h"
#include "libsearch_global.h"
#include "ukui-search-task.h"
namespace UkuiSearch {
class LIBSEARCH_EXPORT AppSearchPlugin : public QObject, public SearchPluginIface
{
@ -49,6 +52,9 @@ private:
static size_t uniqueSymbol;
static QMutex m_mutex;
UkuiSearchTask *m_appSearchTask = nullptr;
DataQueue<ResultItem>* m_appSearchResults = nullptr;
QString m_currentActionKey;
QWidget *m_detailPage;
QVBoxLayout *m_detailLyt = nullptr;
@ -75,16 +81,19 @@ private:
class AppSearch : public QObject, public QRunnable {
Q_OBJECT
public:
AppSearch(DataQueue<SearchPluginIface::ResultInfo> *searchResult, const QString& keyword, size_t uniqueSymbol);
AppSearch(DataQueue<SearchPluginIface::ResultInfo> *searchResult, DataQueue<ResultItem>* appSearchResults, UkuiSearchTask *appSearchTask, QString keyword, size_t uniqueSymbol);
~AppSearch();
protected:
void run() override;
private:
DataQueue<SearchPluginIface::ResultInfo> *m_search_result = nullptr;
bool isUniqueSymbolChanged();
size_t m_uniqueSymbol;
QString m_keyword;
QMap<NameString, QStringList> m_installed_apps;
QMap<NameString, QStringList> m_not_installed_apps;
UkuiSearchTask *m_appSearchTask = nullptr;
DataQueue<ResultItem>* m_appSearchResults = nullptr;
DataQueue<SearchPluginIface::ResultInfo> *m_search_result = nullptr;
};
}

View File

@ -1,9 +1,7 @@
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/app-match.h \
$$PWD/app-search-plugin.h
SOURCES += \
$$PWD/app-match.cpp \
$$PWD/app-search-plugin.cpp

View File

@ -0,0 +1 @@
#include "app-info-table.h"

View File

@ -1,5 +1,5 @@
QT += core xml widgets dbus concurrent sql
VERSION = 2.2.3
QT += core xml widgets dbus concurrent sql KWindowSystem
VERSION = 2.3.0
DEFINES += VERSION='\\"$${VERSION}\\"'
TARGET = ukui-search
@ -55,7 +55,8 @@ HEADERS += \
global-settings.h \
gobject-template.h \
libsearch_global.h \
libsearch.h
libsearch.h \
../ukui-search-app-data-service/app-db-common-defines.h
RESOURCES += \
resource1.qrc \
@ -86,6 +87,7 @@ unix {
header.path = /usr/include/ukui-search
header.files += *.h index/*.h appsearch/*.h settingsearch/*.h plugininterface/*.h websearch/*.h \
searchinterface/ukui-search-task.h \
appdata/app-info-table.h \
searchinterface/search-controller.h \
searchinterface/result-item.h
header.files += development-files/header-files/*

View File

@ -1,15 +1,44 @@
#ifndef COMMONDEFINES_H
#define COMMONDEFINES_H
#include <QFlags>
namespace UkuiSearch {
/**
* @brief The SearchType enum
*
*/
enum class SearchType
{
File = 0x1 << 0,
FileContent = 0x1 << 1,
Application = 0x1 << 2,
Setting = 0x1 << 3,
Note = 0x1 << 4,
Mail = 0x1 << 5,
Custom = 0x1 << 6
File = 1u << 0,
FileContent = 1u << 1,
Application = 1u << 2,
Setting = 1u << 3,
Note = 1u << 4,
Mail = 1u << 5,
Custom = 1u << 6
};
/**
* @brief The ResultDataType enum
*
*/
enum ResultDataType
{
FilePath = 1u << 0,
FileIconName = 1u << 1,
FileName = 1u << 2,
ModifiedTime = 1u << 3,
ApplicationDesktopPath = 1u << 4,
ApplicationLocalName = 1u << 5,
ApplicationIconName = 1u << 6,
ApplicationDescription = 1u << 7,
IsOnlineApplication = 1u << 8
//add more...
};
Q_DECLARE_FLAGS(ResultDataTypes, ResultDataType)
}
Q_DECLARE_OPERATORS_FOR_FLAGS(UkuiSearch::ResultDataTypes)
#endif // COMMONDEFINES_H

View File

@ -4,6 +4,7 @@
#include "file-search-task.h"
#include "file-content-search-task.h"
#include "app-search-task.h"
using namespace UkuiSearch;
static SearchTaskPluginManager *global_instance = nullptr;
@ -24,6 +25,8 @@ void SearchTaskPluginManager::initPlugins(SearchType searchType)
case SearchType::FileContent:
registerBuildinPlugin(new FileContentSearchTask(this));
break;
case SearchType::Application:
registerBuildinPlugin(new AppSearchTask(this));
default:
break;
}
@ -127,6 +130,9 @@ SearchTaskPluginIface *SearchTaskPluginManager::getPlugin(SearchType searchType,
case SearchType::FileContent:
searchPlugin = new FileContentSearchTask(this);
break;
case SearchType::Application:
searchPlugin = new AppSearchTask(this);
break;
default:
break;
}

View File

@ -10,13 +10,15 @@ public:
~ResultItemPrivate();
void setSearchId(size_t searchId);
void setItemKey(QString itemKey);
void setExtral(QVariantList extral);
size_t getSearchId();
QString getItemKey();
QVariantList getExtral();
private:
size_t m_searchId;
QString m_itemKey;
QString m_label;
QVariant m_extral;
QVariantList m_extral;
//and something else...
ResultItem *q;

View File

@ -7,7 +7,6 @@ ResultItemPrivate::ResultItemPrivate::ResultItemPrivate(ResultItem *parent) : q(
ResultItemPrivate::~ResultItemPrivate()
{
}
void ResultItemPrivate::setSearchId(size_t searchId)
@ -20,6 +19,13 @@ void ResultItemPrivate::setItemKey(QString itemKey)
m_itemKey = itemKey;
}
void ResultItemPrivate::setExtral(QVariantList extral)
{
for (auto &info : extral) {
m_extral.append(info);
}
}
size_t ResultItemPrivate::getSearchId()
{
return m_searchId;
@ -29,6 +35,12 @@ QString ResultItemPrivate::getItemKey()
{
return m_itemKey;
}
QVariantList ResultItemPrivate::getExtral()
{
return m_extral;
}
ResultItem::ResultItem() : d(new ResultItemPrivate(this))
{
}
@ -43,22 +55,39 @@ ResultItem::ResultItem(const QString itemKey) : d(new ResultItemPrivate(this))
d->setItemKey(itemKey);
}
ResultItem::ResultItem(const size_t searchId, const QString itemKey) : d(new ResultItemPrivate(this))
ResultItem::ResultItem(const size_t searchId, const QString itemKey, QVariantList extral) : d(new ResultItemPrivate(this))
{
d->setSearchId(searchId);
d->setItemKey(itemKey);
d->setExtral(extral);
}
size_t ResultItem::getSearchId()
size_t ResultItem::getSearchId() const
{
return d->getSearchId();
}
QString ResultItem::getItemKey()
QString ResultItem::getItemKey() const
{
return d->getItemKey();
}
QVariantList ResultItem::getExtral() const
{
return d->getExtral();
}
ResultItem::~ResultItem()
{
if (d)
delete d;
d = nullptr;
}
ResultItem::ResultItem(const ResultItem &item): d(new ResultItemPrivate(this))
{
d->setSearchId(item.getSearchId());
d->setItemKey(item.getItemKey());
d->setExtral(item.getExtral());
}

View File

@ -9,12 +9,16 @@ class ResultItem
{
public:
explicit ResultItem();
virtual ~ResultItem();
ResultItem(const ResultItem &item);
explicit ResultItem(const size_t searchId);
explicit ResultItem(const QString itemKey);
explicit ResultItem(const size_t searchId, const QString itemKey);
size_t getSearchId();
QString getItemKey();
~ResultItem();
explicit ResultItem(const size_t searchId, const QString itemKey, QVariantList extral = QVariantList());
size_t getSearchId() const;
QString getItemKey() const;
QVariantList getExtral() const;
private:
ResultItemPrivate *d;
};

View File

@ -21,9 +21,12 @@ public:
void addFileLabel(QString &label);
void setOnlySearchFile(bool onlySearchFile);
void setOnlySearchDir(bool onlySearchDir);
void setSearchOnlineApps(bool searchOnlineApps);
size_t getCurrentSearchId();
DataQueue<ResultItem>* getDataQueue();
ResultDataTypes getResultDataType(SearchType searchType);
QStringList getCustomResultDataType(QString customSearchType);
bool beginSearchIdCheck(size_t searchId);
void finishSearchIdCheck();
void stop();
@ -34,11 +37,15 @@ public:
QStringList getFileLabel();
bool isSearchFileOnly();
bool isSearchDirOnly();
bool isSearchOnlineApps();
void clearAllConditions();
void clearKeyWords();
void clearSearchDir();
void clearFileLabel();
bool setResultDataType(SearchType searchType, ResultDataTypes dataType);
bool setCustomResultDataType(QString customSearchType, QStringList dataType);
/**
* @brief
* @param first
@ -52,7 +59,7 @@ private:
void copyData();
//TODO: 这里是否可以改为字节对齐的写法?
// DataQueue<ResultItem>* m_dataQueue = nullptr ;
std::shared_ptr<DataQueue<ResultItem>> m_sharedDataueue = nullptr;
std::shared_ptr<DataQueue<ResultItem>> m_sharedDataQueue = nullptr;
size_t m_searchId = 0;
QMutex m_searchIdMutex;
SearchController *q = nullptr;
@ -65,9 +72,13 @@ private:
bool m_activeKeywordSegmentation = false;
bool m_onlySearchFile = false;
bool m_onlySearchDir = false;
bool m_searchOnlineApps = false;
unsigned int m_first = 0;
unsigned int m_maxResults = 100; //默认取100条结果
QMap<SearchType, ResultDataTypes> m_searchType2ResultDataType;
QMap<QString, QStringList> m_customSearchType2ResultDataType;
};
}

View File

@ -24,22 +24,22 @@ size_t SearchControllerPrivate::refreshSearchId()
DataQueue<ResultItem> *SearchControllerPrivate::refreshDataqueue()
{
if(!m_sharedDataueue.get()) {
if(!m_sharedDataQueue.get()) {
// m_dataQueue = new DataQueue<ResultItem>;
m_sharedDataueue = std::make_shared<DataQueue<ResultItem>>();
return m_sharedDataueue.get();
m_sharedDataQueue = std::make_shared<DataQueue<ResultItem>>();
return m_sharedDataQueue.get();
}
m_sharedDataueue.get()->clear();
return m_sharedDataueue.get();
m_sharedDataQueue.get()->clear();
return m_sharedDataQueue.get();
}
DataQueue<ResultItem> *SearchControllerPrivate::initDataQueue()
{
if(!m_sharedDataueue.get()) {
m_sharedDataueue = std::make_shared<DataQueue<ResultItem>>();
return m_sharedDataueue.get();
if(!m_sharedDataQueue.get()) {
m_sharedDataQueue = std::make_shared<DataQueue<ResultItem>>();
return m_sharedDataQueue.get();
}
return m_sharedDataueue.get();
return m_sharedDataQueue.get();
}
void SearchControllerPrivate::addSearchDir(QString &path)
@ -77,6 +77,11 @@ void SearchControllerPrivate::setOnlySearchDir(bool onlySearchDir)
m_onlySearchDir = onlySearchDir;
}
void SearchControllerPrivate::setSearchOnlineApps(bool searchOnlineApps)
{
m_searchOnlineApps = searchOnlineApps;
}
size_t SearchControllerPrivate::getCurrentSearchId()
{
m_searchIdMutex.lock();
@ -88,7 +93,17 @@ size_t SearchControllerPrivate::getCurrentSearchId()
DataQueue<ResultItem> *SearchControllerPrivate::getDataQueue()
{
return m_sharedDataueue.get();
return m_sharedDataQueue.get();
}
ResultDataTypes SearchControllerPrivate::getResultDataType(SearchType searchType)
{
return m_searchType2ResultDataType[searchType];
}
QStringList SearchControllerPrivate::getCustomResultDataType(QString customSearchType)
{
return m_customSearchType2ResultDataType[customSearchType];
}
bool SearchControllerPrivate::beginSearchIdCheck(size_t searchId)
@ -151,13 +166,17 @@ bool SearchControllerPrivate::isSearchDirOnly()
return m_onlySearchDir;
}
bool SearchControllerPrivate::isSearchOnlineApps()
{
return m_searchOnlineApps;
}
void SearchControllerPrivate::copyData()
{
if(m_formerController.get()) {
m_searchId = m_formerController.get()->getCurrentSearchId();
//所有子节点都有一个指向根节点的队列的智能指针
m_sharedDataueue = m_formerController.get()->d->m_sharedDataueue;
m_sharedDataQueue = m_formerController.get()->d->m_sharedDataQueue;
m_keywords = m_formerController.get()->getKeyword();
m_searchDirs = m_formerController.get()->getSearchDir();
m_FileLabels = m_formerController.get()->getFileLabel();
@ -190,6 +209,20 @@ void SearchControllerPrivate::clearFileLabel()
m_FileLabels.clear();
}
bool SearchControllerPrivate::setResultDataType(SearchType searchType, ResultDataTypes dataType)
{
bool res(true);
m_searchType2ResultDataType[searchType] = dataType;
return res;
}
bool SearchControllerPrivate::setCustomResultDataType(QString customSearchType, QStringList dataType)
{
bool res(true);
m_customSearchType2ResultDataType[customSearchType] = dataType;
return res;
}
void SearchControllerPrivate::setPagination(unsigned int first, unsigned int maxResults)
{
m_first = first;
@ -258,6 +291,16 @@ DataQueue<ResultItem> *SearchController::getDataQueue()
return d->getDataQueue();
}
ResultDataTypes SearchController::getResultDataType(SearchType searchType)
{
return d->getResultDataType(searchType);
}
QStringList SearchController::getCustomResultDataType(QString customSearchType)
{
return d->getCustomResultDataType(customSearchType);
}
void SearchController::setActiveKeywordSegmentation(bool active)
{
d->setActiveKeywordSegmentation(active);
@ -278,6 +321,11 @@ void SearchController::setOnlySearchDir(bool onlySearchDir)
d->setOnlySearchDir(onlySearchDir);
}
void SearchController::setSearchOnlineApps(bool searchOnlineApps)
{
d->setSearchOnlineApps(searchOnlineApps);
}
bool SearchController::beginSearchIdCheck(size_t searchId)
{
return d->beginSearchIdCheck(searchId);
@ -323,6 +371,11 @@ bool SearchController::isSearchDirOnly()
return d->isSearchDirOnly();
}
bool SearchController::isSearchOnlineApps()
{
return d->isSearchOnlineApps();
}
void SearchController::stop()
{
d->stop();
@ -362,3 +415,13 @@ unsigned int SearchController::maxResults() const
{
return d->maxResults();
}
bool SearchController::setResultDataType(SearchType searchType, ResultDataTypes dataType)
{
return d->setResultDataType(searchType, dataType);
}
bool SearchController::setCustomResultDataType(QString customSearchType, QStringList dataType)
{
return d->setCustomResultDataType(customSearchType, dataType);
}

View File

@ -4,6 +4,7 @@
#include <QStringList>
#include <memory>
#include "data-queue.h"
#include "common-defines.h"
//todo: url parser?
namespace UkuiSearch {
class UkuiSearchTask;
@ -34,11 +35,14 @@ public:
void addFileLabel(QString &label);
void setOnlySearchFile(bool onlySearchFile);
void setOnlySearchDir(bool onlySearchDir);
void setSearchOnlineApps(bool searchOnlineApps);
//以上方法插件请不要调用
//以下方法插件可以调用
size_t getCurrentSearchId();
DataQueue<ResultItem>* getDataQueue();
ResultDataTypes getResultDataType(SearchType searchType);
QStringList getCustomResultDataType(QString customSearchType);
bool beginSearchIdCheck(size_t searchId);
void finishSearchIdCheck();
@ -49,6 +53,7 @@ public:
QStringList getFileLabel();
bool isSearchFileOnly();
bool isSearchDirOnly();
bool isSearchOnlineApps();
void clearAllConditions();
void clearKeyWords();
void clearSearchDir();
@ -58,6 +63,8 @@ public:
unsigned int first() const;
unsigned int maxResults() const;
bool setResultDataType(SearchType searchType, ResultDataTypes dataType);
bool setCustomResultDataType(QString customSearchType, QStringList dataType);
private:
std::shared_ptr<SearchController> m_parent = nullptr;
SearchControllerPrivate *d = nullptr;

View File

@ -0,0 +1,154 @@
#include "app-search-task.h"
#include "index-status-recorder.h"
#include "common.h"
#include <qt5xdg/XdgIcon>
#include <QDir>
#include <QFile>
#include <QQueue>
#include <QDebug>
using namespace UkuiSearch;
AppSearchTask::AppSearchTask(QObject *parent)
{
this->setParent(parent);
qRegisterMetaType<size_t>("size_t");
m_pool = new QThreadPool(this);
m_pool->setMaxThreadCount(1);
}
const QString AppSearchTask::name()
{
return tr("Application");
}
const QString AppSearchTask::description()
{
return tr("Application search.");
}
QString AppSearchTask::getCustomSearchType()
{
return "Application";
}
void AppSearchTask::startSearch(std::shared_ptr<SearchController> searchController)
{
AppSearchWorker *appSearchWorker;
appSearchWorker = new AppSearchWorker(this, searchController);
m_pool->start(appSearchWorker);
}
void AppSearchTask::stop()
{
}
void AppSearchTask::sendFinishSignal(size_t searchId)
{
Q_EMIT searchFinished(searchId);
}
AppSearchWorker::AppSearchWorker(AppSearchTask *AppSarchTask, std::shared_ptr<SearchController> searchController) : m_AppSearchTask(AppSarchTask), m_searchController(searchController)
{
qDBusRegisterMetaType<QMap<QString, QString>>();
qDBusRegisterMetaType<QList<QMap<QString, QString>>>();
m_interFace = new QDBusInterface("com.kylin.softwarecenter.getsearchresults", "/com/kylin/softwarecenter/getsearchresults",
"com.kylin.getsearchresults",
QDBusConnection::sessionBus());
if(!m_interFace->isValid()) {
qWarning() << qPrintable(QDBusConnection::sessionBus().lastError().message());
}
m_interFace->setTimeout(1500);
}
void AppSearchWorker::run()
{
m_currentSearchId = m_searchController->getCurrentSearchId();
bool finished = true;
QStringList results;
QStringList keyWords = m_searchController->getKeyword();
ResultDataTypes dataType = m_searchController->getResultDataType(SearchType::Application);
m_appInfoTable.searchInstallApp(keyWords, results);
for (int i = 0; i < results.size() / 3; i++) {
if (m_searchController->beginSearchIdCheck(m_currentSearchId)) {
QVariantList info;
if (dataType & UkuiSearch::ApplicationDesktopPath) {
info << QVariant(results.at(i*3));
}
if (dataType & UkuiSearch::ApplicationLocalName) {
info << QVariant(results.at(i*3 + 1));
}
if (dataType & UkuiSearch::ApplicationIconName) {
info << QVariant(XdgIcon::fromTheme(results.at(i*3 + 2)));
}
if (dataType & UkuiSearch::ApplicationDescription) {//本地应用暂无简介
info << QVariant(QString());
}
if (dataType & UkuiSearch::IsOnlineApplication) {
info << QVariant(0);
}
ResultItem ri(m_currentSearchId, results.at(i*3), info);
m_searchController->getDataQueue()->enqueue(ri);
m_searchController->finishSearchIdCheck();
} else {
qDebug() << "Search id changed!";
m_searchController->finishSearchIdCheck();
}
}
if (m_searchController->isSearchOnlineApps()) {
//online app search
for (auto keyword : keyWords) {
QDBusReply<QList<QMap<QString, QString>>> reply = m_interFace->call("get_search_result", keyword); //阻塞,直到远程方法调用完成。
if(reply.isValid()) {
for(int i = 0; i < reply.value().size(); i++) {
if (m_searchController->beginSearchIdCheck(m_currentSearchId)) {
QVariantList info;
if (dataType & UkuiSearch::ApplicationDesktopPath) {
info << QVariant(reply.value().at(i).value("appname"));
}
if (dataType & UkuiSearch::ApplicationLocalName) {
QLocale locale;
if(locale.language() == QLocale::Chinese) {
info << QVariant(reply.value().at(i).value("displayname_cn"));
} else {
info << QVariant(reply.value().at(i).value("appname"));
}
}
if (dataType & UkuiSearch::ApplicationIconName) {
info << QVariant(QIcon(reply.value().at(i).value("icon")));
}
if (dataType & UkuiSearch::ApplicationDescription) {//在线应用有效
info << QVariant(reply.value().at(i).value("discription"));
}
if (dataType & UkuiSearch::IsOnlineApplication) {
info << QVariant(1);
}
ResultItem ri(m_currentSearchId, reply.value().at(i).value("appname"), info);
m_searchController->getDataQueue()->enqueue(ri);
m_searchController->finishSearchIdCheck();
} else {
qDebug() << "Search id changed!";
m_searchController->finishSearchIdCheck();
}
}
} else {
qWarning() << "SoftWareCenter dbus called failed!";
}
}
}
if (finished) QMetaObject::invokeMethod(m_AppSearchTask, "searchFinished", Q_ARG(size_t, m_currentSearchId));
}
AppSearchWorker::~AppSearchWorker()
{
}
void AppSearchWorker::sendErrorMsg(const QString &msg)
{
QMetaObject::invokeMethod(m_AppSearchTask, "searchError",
Q_ARG(size_t, m_currentSearchId),
Q_ARG(QString, msg));
}

View File

@ -0,0 +1,57 @@
#ifndef APPSEARCHTASK_H
#define APPSEARCHTASK_H
#include <QIcon>
#include <QThreadPool>
#include <QRunnable>
#include <QDBusInterface>
#include <QtDBus>
#include "search-task-plugin-iface.h"
#include "search-controller.h"
#include "result-item.h"
#include "app-info-table.h"
namespace UkuiSearch {
class AppSearchTask : public SearchTaskPluginIface
{
Q_OBJECT
public:
explicit AppSearchTask(QObject *parent);
PluginType pluginType() {return PluginType::SearchTaskPlugin;}
const QString name();
const QString description();
const QIcon icon() {return QIcon::fromTheme("appsearch");}
void setEnable(bool enable) {}
bool isEnable() { return true;}
SearchType getSearchType() {return SearchType::Application;}
QString getCustomSearchType();
void startSearch(std::shared_ptr<SearchController> searchController);
void stop();
Q_INVOKABLE void sendFinishSignal(size_t searchId);
private:
QThreadPool *m_pool = nullptr;
};
class AppSearchWorker : public QRunnable
{
public:
explicit AppSearchWorker(AppSearchTask *AppSarchTask, std::shared_ptr<SearchController> searchController);
protected:
void run();
private:
~AppSearchWorker();
void sendErrorMsg(const QString &msg);
private:
AppInfoTable m_appInfoTable;
AppSearchTask *m_AppSearchTask = nullptr;
std::shared_ptr<SearchController> m_searchController;
QDBusInterface *m_interFace = nullptr;
size_t m_currentSearchId = 0;
};
}
#endif // APPSEARCHTASK_H

View File

@ -52,12 +52,12 @@ const QIcon FileContentSearchTask::icon()
void FileContentSearchTask::setEnable(bool enable)
{
e_enable = enable;
m_enable = enable;
}
bool FileContentSearchTask::isEnable()
{
return e_enable && IndexStatusRecorder::getInstance()->contentIndexDatabaseEnable();
return m_enable && IndexStatusRecorder::getInstance()->contentIndexDatabaseEnable();
}
QString FileContentSearchTask::getCustomSearchType()

View File

@ -38,7 +38,7 @@ public:
private:
QThreadPool *m_pool = nullptr;
bool e_enable = true;
bool m_enable = true;
};
class FileContentSearchWorker : public QRunnable

View File

@ -11,9 +11,6 @@
#include "result-item.h"
namespace UkuiSearch {
/*
*
*/
class FileSearchTask : public SearchTaskPluginIface
{
Q_OBJECT

View File

@ -2,10 +2,12 @@ INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/file-search-task.h \
$$PWD/file-content-search-task.h
$$PWD/file-content-search-task.h \
$$PWD/app-search-task.h
SOURCES += \
$$PWD/file-search-task.cpp \
$$PWD/file-content-search-task.cpp
$$PWD/file-content-search-task.cpp \
$$PWD/app-search-task.cpp

View File

@ -27,6 +27,8 @@ public:
void setOnlySearchDir(bool onlySearchDir);
void setSearchOnlineApps(bool searchOnlineApps);
void initSearchPlugin(SearchType searchType, const QString& customSearchType = QString());
bool setResultDataType(SearchType searchType, ResultDataTypes dataType);
bool setCustomResultDataType(QString customSearchType, QStringList dataType);
void clearAllConditions();
void clearKeyWords();
void clearSearchDir();

View File

@ -54,6 +54,7 @@ void UkuiSearchTaskPrivate::setOnlySearchDir(bool onlySearchDir)
void UkuiSearchTaskPrivate::setSearchOnlineApps(bool searchOnlineApps)
{
m_searchCotroller->setSearchOnlineApps(searchOnlineApps);
}
void UkuiSearchTaskPrivate::initSearchPlugin(SearchType searchType, const QString& customSearchType)
@ -67,6 +68,17 @@ void UkuiSearchTaskPrivate::initSearchPlugin(SearchType searchType, const QStrin
}
}
bool UkuiSearchTaskPrivate::setCustomResultDataType(QString customSearchType, QStringList dataType)
{
return m_searchCotroller->setCustomResultDataType(customSearchType, dataType);
}
bool UkuiSearchTaskPrivate::setResultDataType(SearchType searchType, ResultDataTypes dataType)
{
return m_searchCotroller->setResultDataType(searchType, dataType);
}
size_t UkuiSearchTaskPrivate::startSearch(SearchType searchtype, const QString& customSearchType)
{
m_searchId = m_searchCotroller->refreshSearchId();
@ -167,6 +179,16 @@ void UkuiSearchTask::initSearchPlugin(SearchType searchType)
d->initSearchPlugin(searchType);
}
bool UkuiSearchTask::setResultDataType(SearchType searchType, ResultDataTypes dataType)
{
return d->setResultDataType(searchType, dataType);
}
bool UkuiSearchTask::setCustomResultDataType(QString customSearchType, QStringList dataType)
{
return d->setCustomResultDataType(customSearchType, dataType);
}
size_t UkuiSearchTask::startSearch(SearchType searchtype, QString customSearchType)
{
return d->startSearch(searchtype, customSearchType);

View File

@ -21,6 +21,15 @@ public:
void setOnlySearchDir(bool onlySearchDir);
void setSearchOnlineApps(bool searchOnlineApps);
void initSearchPlugin(SearchType searchType);
/**
* @brief setResultDataType
* @param searchType
* @param dataType
* @return
*/
bool setResultDataType(SearchType searchType, UkuiSearch::ResultDataTypes dataType);
bool setCustomResultDataType(QString customSearchType, QStringList dataType);
void clearAllConditions();
void clearKeyWords();
void clearSearchDir();

View File

@ -0,0 +1,11 @@
#ifndef APPDBCOMMONDEFINES_H
#define APPDBCOMMONDEFINES_H
#include <QDir>
namespace UkuiSearch {
#define APP_DATABASE_PATH QDir::homePath()+"/.config/org.ukui/ukui-search/appdata/"
#define APP_DATABASE_NAME "app-info.db"
}
#endif // APPDBCOMMONDEFINES_H

View File

@ -0,0 +1,490 @@
#include <qt5xdg/XdgDesktopFile>
#include <QMutexLocker>
#include <QCryptographicHash>
#include <QFile>
#include "app-db-manager.h"
#include "../libsearch/file-utils.h"
using namespace UkuiSearch;
#define GENERAL_APP_DESKTOP_PATH "/usr/share/applications/"
#define ANDROID_APP_DESKTOP_PATH QDir::homePath() + "/.local/share/applications/"
#define SNAPD_APP_DESKTOP_PATH "/var/lib/snapd/desktop/applications/"
static AppDBManager *global_instance = AppDBManager::getInstance();
QMutex AppDBManager::s_installAppMapMutex;
AppDBManager *AppDBManager::getInstance()
{
if (!global_instance) {
global_instance = new AppDBManager();
}
return global_instance;
}
AppDBManager::AppDBManager(QObject *parent) : QObject(parent), m_database(new QSqlDatabase)
{
openDataBase();
m_watchAppDir = new QFileSystemWatcher(this);
m_watchAppDir->addPath(GENERAL_APP_DESKTOP_PATH);
QDir androidPath(ANDROID_APP_DESKTOP_PATH);
if(!androidPath.exists()) {
androidPath.mkpath(ANDROID_APP_DESKTOP_PATH);
}
m_watchAppDir->addPath(ANDROID_APP_DESKTOP_PATH);
QDir snapdPath(SNAPD_APP_DESKTOP_PATH);
if(!snapdPath.exists()) {
snapdPath.mkpath(SNAPD_APP_DESKTOP_PATH);
}
m_watchAppDir->addPath(SNAPD_APP_DESKTOP_PATH);
initDateBaseConnection();
connect(m_watchAppDir, &QFileSystemWatcher::directoryChanged, this, [ = ](const QString & path) {
qDebug() << "m_watchAppDir directoryChanged:" << path;
if (m_database->transaction()) {
this->updateAppInfoDB();
if (!m_database->commit()) {
qWarning() << "Failed to commit !";
m_database->rollback();
}
} else {
qWarning() << "Failed to start transaction mode!!!";
}
});
}
AppDBManager::~AppDBManager()
{
if(m_watchAppDir) {
delete m_watchAppDir;
}
m_watchAppDir = NULL;
closeDataBase();
}
void AppDBManager::buildAppInfoDB()
{
QSqlQuery sql(*m_database);
QString cmd = QString("CREATE TABLE IF NOT EXISTS appInfo(%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15,%16,%17,%18,%19,%20)")
// .arg("ID INT")//自增id
.arg("DESKTOP_FILE_PATH TEXT")//desktop文件路径
.arg("MODIFYED_TIME TEXT")//YYYYMMDDHHmmSS 修改日期
.arg("INSERT_TIME TEXT")//YYYYMMDDHHmmSS 插入日期
.arg("LOCAL_NAME TEXT")//本地名称,跟随系统语言
.arg("NAME_EN TEXT")//应用英文名称
.arg("NAME_ZH TEXT")//应用中文名称
.arg("PINYIN_NAME TEXT")//中文拼音
.arg("FIRST_LETTER_OF_PINYIN TEXT")//中文拼音首字母
.arg("ICON TEXT")//图标名称(或路径)
.arg("TYPE TEXT")//应用类型
.arg("CATEGORY TEXT")//应用分类
.arg("EXEC TEXT")//应用命令
.arg("COMMENT TEXT")//应用注释
.arg("MD5 TEXT")//desktop文件内容md5值
.arg("LAUNCH_TIMES INT")//应用打开次数, 等比例缩减
.arg("FAVORITES INT")//收藏顺序0:为收藏,>0的数字表示收藏顺序
.arg("LAUNCHED INT")//应用安装后是否打开过0:未打开过;1:打开过
.arg("TOP INT")//置顶顺序 0:未置顶;>0的数字表示置顶顺序
.arg("LOCK INT")//应用是否锁定管控0未锁定1锁定
.arg("PRIMARY KEY (DESKTOP_FILE_PATH)");
if (!sql.exec(cmd)) {
qWarning() << m_database->lastError() << cmd;
return;
}
}
void AppDBManager::updateAppInfoDB()
{
QMutexLocker locker(&s_installAppMapMutex);
m_installAppMap.clear();
this->getAllDesktopFilePath(GENERAL_APP_DESKTOP_PATH);
this->getAllDesktopFilePath(ANDROID_APP_DESKTOP_PATH);
this->getAllDesktopFilePath(SNAPD_APP_DESKTOP_PATH);
QStringList filePathList;
this->getFilePathList(filePathList);
QSqlQuery sql(*m_database);
QString cmd;
if (!sql.exec("SELECT COUNT(*) FROM appInfo")) {
this->buildAppInfoDB();
for (auto &filePath : filePathList) {
this->addAppDesktopFile2DB(filePath);
}
} else {
cmd = QString("SELECT COUNT(*) FROM appInfo");
if (sql.exec(cmd)) {
if (sql.next()) {
if (sql.value(0).toInt() > filePathList.size()) {
int size = sql.value(0).toInt();
cmd = QString("SELECT DESKTOP_FILE_PATH FROM appInfo");
if (!sql.exec(cmd)) {
qWarning() << m_database->lastError() << cmd;
return;
}
QString path;
for (int i = 0; i<size; ++i) {
if (!sql.next()) {
qWarning() << m_database->lastError() << cmd;
return;
}
path = sql.value(0).toString();
if (!filePathList.contains(path)) {
this->deleteAppDesktopFile2DB(path);
break;
}
}
}
for (QString &filePath:filePathList) {
cmd = QString("SELECT COUNT(*) FROM appInfo WHERE DESKTOP_FILE_PATH = '%0'").arg(filePath);
if (sql.exec(cmd)) {
if (sql.next()) {
if (sql.value(0).toInt() == 0) {
this->addAppDesktopFile2DB(filePath);
} else {
cmd = QString("SELECT MD5 FROM appInfo WHERE DESKTOP_FILE_PATH = '%0'").arg(filePath);
if (!sql.exec(cmd)) {
qWarning() << m_database->lastError() << cmd;
return;
}
if (!sql.next()) {
qWarning() << m_database->lastError() << cmd;
return;
}
if (sql.value(0).toString() != getAppDesktopMd5(filePath)) {
this->updateAppDesktopFile2DB(filePath);
}
}
} else {
qWarning() << m_database->lastError() << cmd;
return;
}
} else {
qWarning() << m_database->lastError() << cmd;
return;
}
}
} else {
qWarning() << m_database->lastError() << cmd;
return;
}
} else {
qWarning() << m_database->lastError() << cmd;
return;
}
}
}
void AppDBManager::getFilePathList(QStringList &pathList)
{
for (auto i=m_installAppMap.begin(); i!=m_installAppMap.end(); ++i) {
pathList.append(i.value().at(0));
}
}
/**
* @brief AppMatch::getAllDesktopFilePath desktop文件
* @param path desktop文件夹
*/
void AppDBManager::getAllDesktopFilePath(QString path) {
QDir dir(path);
if(!dir.exists()) {
return;
}
dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
dir.setSorting(QDir::DirsFirst);
QFileInfoList list = dir.entryInfoList();
list.removeAll(QFileInfo("/usr/share/applications/screensavers"));
if(list.size() < 1) {
return;
}
XdgDesktopFile desktopfile;
int i = 0;
while(i < list.size()) {
QFileInfo fileInfo = list.at(i);
//如果是文件夹,递归
bool isDir = fileInfo.isDir();
if(isDir) {
getAllDesktopFilePath(fileInfo.filePath());
qDebug() << fileInfo.filePath();
++i;
} else {
QString filePathStr = fileInfo.filePath();
if(m_excludedDesktopfiles.contains(filePathStr)) {
++i;
continue;
}
//过滤后缀不是.desktop的文件
if(!filePathStr.endsWith(".desktop")) {
++i;
continue;
}
desktopfile.load(filePathStr);
if(desktopfile.value("NoDisplay").toString().contains("true") || desktopfile.value("NotShowIn").toString().contains("UKUI")) {
++i;
continue;
}
QString name = desktopfile.localizedValue("Name").toString();
if(name.isEmpty()) {
++i;
qDebug() << filePathStr << "name!!";
continue;
}
QString icon = desktopfile.iconName();
NameString appname;
QStringList appInfolist;
appname.app_name = name;
appInfolist << filePathStr << icon;
appInfolist.append(desktopfile.value("Name").toString());
appInfolist.append(desktopfile.value("Name[zh_CN]").toString());
m_installAppMap.insert(appname, appInfolist);
++i;
}
}
}
void AppDBManager::initDateBaseConnection()
{
if (m_database->transaction()) {
this->updateAppInfoDB();
if (!m_database->commit()) {
qWarning() << "Failed to commit !";
m_database->rollback();
}
} else {
qWarning() << "Failed to start transaction mode!!!";
}
}
void AppDBManager::openDataBase()
{
QDir dir;
if (!dir.exists(APP_DATABASE_PATH)) {
dir.mkpath(APP_DATABASE_PATH);
}
if (QSqlDatabase::contains(CONNECTION_NAME)) {
*m_database = QSqlDatabase::database(CONNECTION_NAME);
} else {
*m_database = QSqlDatabase::addDatabase("QSQLITE", CONNECTION_NAME);
m_database->setDatabaseName(APP_DATABASE_PATH + APP_DATABASE_NAME);
}
if(!m_database->open()) {
qWarning() << m_database->lastError();
QApplication::quit();
}
}
void AppDBManager::closeDataBase()
{
m_database->close();
delete m_database;
QSqlDatabase::removeDatabase(CONNECTION_NAME);
}
QString AppDBManager::getAppDesktopMd5(QString &desktopfd)
{
QString res;
QFile file(desktopfd);
file.open(QIODevice::ReadOnly);
res = QString::fromStdString(QCryptographicHash::hash(file.readAll(), QCryptographicHash::Md5).toHex().toStdString());
file.close();
return res;
}
void AppDBManager::getInstallAppMap(QMap<QString, QStringList> &installAppMap)
{
QMutexLocker locker(&s_installAppMapMutex);
for (auto i=m_installAppMap.begin(); i!=m_installAppMap.end(); ++i) {
installAppMap[i.key().app_name] = i.value();
}
installAppMap.detach();
}
bool AppDBManager::addAppDesktopFile2DB(QString &desktopfd)
{
bool res(true);
QSqlQuery sql(*m_database);
XdgDesktopFile desktopfile;
desktopfile.load(desktopfd);
QString hanzi, pinyin, firstLetterOfPinyin;
bool isHanzi = true;
if (desktopfile.contains("Name[zh_CN]")) {
hanzi = desktopfile.value("Name[zh_CN]").toString();
} else {
hanzi = desktopfile.value("Name").toString();
if (!hanzi.contains(QRegExp("[\\x4e00-\\x9fa5]+"))) {
isHanzi = false;
}
}
if (isHanzi) {
QStringList pinyinList = FileUtils::findMultiToneWords(hanzi);
for (int i = 0; i<pinyinList.size(); ++i) {
if (i%2) {
firstLetterOfPinyin += pinyinList.at(i);
} else {
pinyin += pinyinList.at(i);
}
}
}
QString cmd = QString("INSERT INTO appInfo "
"(DESKTOP_FILE_PATH,MODIFYED_TIME,INSERT_TIME,LOCAL_NAME,NAME_EN,NAME_ZH,PINYIN_NAME,FIRST_LETTER_OF_PINYIN,ICON,TYPE,CATEGORY,EXEC,COMMENT,MD5,LAUNCH_TIMES,FAVORITES,LAUNCHED,TOP,LOCK) "
"VALUES('%1','%2','%3','%4','%5','%6','%7','%8','%9','%10','%11','%12','%13','%14',%15,%16,%17,%18,%19)")
.arg(desktopfd)
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
.arg(desktopfile.localizedValue("Name").toString())
.arg(desktopfile.value("Name").toString())
.arg(hanzi)
.arg(pinyin)
.arg(firstLetterOfPinyin)
.arg(desktopfile.value("Icon").toString())
.arg(desktopfile.value("Type").toString())
.arg(desktopfile.value("Categories").toString())
.arg(desktopfile.value("Exec").toString())
.arg(desktopfile.value("Comment").toString())
.arg(getAppDesktopMd5(desktopfd))
.arg(0)
.arg(0)
.arg(0)
.arg(0)
.arg(0);
if (!sql.exec(cmd)) {
qWarning() << m_database->lastError() << cmd;
res = false;
}
if (res) {
qDebug() << "app database add " << desktopfd << "success!";
} else {
qDebug() << "app database add " << desktopfd << "failed!";
}
return res;
}
bool AppDBManager::deleteAppDesktopFile2DB(QString &desktopfd)
{
bool res(true);
QSqlQuery sql(*m_database);
QString cmd = QString("DELETE FROM appInfo WHERE DESKTOP_FILE_PATH = '%0'").arg(desktopfd);
if (!sql.exec(cmd)) {
qWarning() << m_database->lastError() << cmd;
res = false;
}
if (res) {
qDebug() << "app database delete " << desktopfd << "success!";
} else {
qDebug() << "app database delete " << desktopfd << "failed!";
}
return res;
}
bool AppDBManager::updateAppDesktopFile2DB(QString &desktopfd)
{
bool res(true);
XdgDesktopFile desktopfile;
desktopfile.load(desktopfd);
if(desktopfile.value("NoDisplay").toString().contains("true") || desktopfile.value("NotShowIn").toString().contains("UKUI")) {
qDebug() << "app" << desktopfd << "is changed, NoDisplay or NotShowIn is working!";
return this->deleteAppDesktopFile2DB(desktopfd);
}
QString hanzi, pinyin, firstLetterOfPinyin;
bool isHanzi = true;
if (desktopfile.contains("Name[zh_CN]")) {
hanzi = desktopfile.value("Name[zh_CN]").toString();
} else {
hanzi = desktopfile.value("Name").toString();
if (!hanzi.contains(QRegExp("[\\x4e00-\\x9fa5]+"))) {
isHanzi = false;
}
}
if (isHanzi) {
QStringList pinyinList = FileUtils::findMultiToneWords(hanzi);
for (int i = 0; i<pinyinList.size(); ++i) {
if (i%2) {
firstLetterOfPinyin += pinyinList.at(i);
} else {
pinyin += pinyinList.at(i);
}
}
}
QSqlQuery sql(*m_database);
QString cmd = QString("UPDATE appInfo SET "
"MODIFYED_TIME='%0',"
"LOCAL_NAME='%1',"
"NAME_EN='%2',"
"NAME_ZH='%3'"
",PINYIN_NAME='%4',"
"FIRST_LETTER_OF_PINYIN='%5',"
"ICON='%6',"
"TYPE='%7',"
"CATEGORY='%8',"
"EXEC='%9',"
"COMMENT='%10',"
"MD5='%11' "
"WHERE DESKTOP_FILE_PATH='%12'")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
.arg(desktopfile.localizedValue("Name").toString())
.arg(desktopfile.value("Name").toString())
.arg(hanzi)
.arg(pinyin)
.arg(firstLetterOfPinyin)
.arg(desktopfile.value("Icon").toString())
.arg(desktopfile.value("Type").toString())
.arg(desktopfile.value("Categories").toString())
.arg(desktopfile.value("Exec").toString())
.arg(desktopfile.value("Comment").toString())
.arg(getAppDesktopMd5(desktopfd))
.arg(desktopfd);
if (!sql.exec(cmd)) {
qWarning() << m_database->lastError() << cmd;
res = false;
}
if (res) {
qDebug() << "app database update " << desktopfd << "success!";
} else {
qDebug() << "app database update " << desktopfd << "failed!";
}
return res;
}
bool AppDBManager::updateAppLaunchTimes(QString &desktopfp)
{
bool res(true);
if (m_database->transaction()) {
QSqlQuery sql(*m_database);
QString cmd = QString("SELECT LAUNCH_TIMES FROM appInfo WHERE DESKTOP_FILE_PATH='%1'").arg(desktopfp);
if (sql.exec(cmd)) {
if (sql.next()) {
cmd = QString("UPDATE appInfo SET MODIFYED_TIME='%0', LAUNCH_TIMES=%1, LAUNCHED=%2 WHERE DESKTOP_FILE_PATH='%3'")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
.arg(sql.value(0).toInt() + 1)
.arg(1)
.arg(desktopfp);
if (!sql.exec(cmd)) {
qWarning() << "Set app favorites state failed!" << m_database->lastError();
res = false;
}
} else {
qWarning() << "Failed to exec next!" << cmd;
res = false;
}
} else {
qWarning() << "Failed to exec:" << cmd;
res = false;
}
if (!m_database->commit()) {
qWarning() << "Failed to commit !" << cmd;
m_database->rollback();
res = false;
}
} else {
qWarning() << "Failed to start transaction mode!!!";
res = false;
}
return res;
}

View File

@ -0,0 +1,127 @@
#ifndef APPDBMANAGER_H
#define APPDBMANAGER_H
#include <QDir>
#include <QObject>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>
#include <QApplication>
#include <QDateTime>
#include <QFileSystemWatcher>
#include <QMutex>
#include "app-db-common-defines.h"
#define CONNECTION_NAME QLatin1String("ukss-appdb-connection")
namespace UkuiSearch {
/**
* @brief The AppDBManager class
* 1.desktop文件目录
* 2.
*/
class NameString {
public:
explicit NameString(const QString &str_) : app_name(str_) {}
NameString() = default;
QString app_name;
bool operator<(const NameString& name) const {
return this->app_name.length() <= name.app_name.length();
}
bool operator==(const NameString& name) const {
return this->app_name == name.app_name;
}
};
class AppDBManager : public QObject
{
Q_OBJECT
enum APP_LOCK_STATE{
APP_UNLOCK = 0,
APP_LOCK
};
public:
static AppDBManager *getInstance();
QString getAppDesktopMd5(QString &desktopfd);
void getInstallAppMap(QMap<QString, QStringList> &installAppMap);
bool addAppDesktopFile2DB(QString &desktopfd);
bool deleteAppDesktopFile2DB(QString &desktopfd);
bool updateAppDesktopFile2DB(QString &desktopfd);
bool updateAppLaunchTimes(QString &desktopfp);
private:
explicit AppDBManager(QObject *parent = nullptr);
~AppDBManager();
void getAllDesktopFilePath(QString path);
void initDateBaseConnection();
void openDataBase();
void closeDataBase();
void buildAppInfoDB();
void updateAppInfoDB();
void getFilePathList(QStringList &pathList);
QSqlDatabase *m_database = nullptr;
QFileSystemWatcher *m_watchAppDir = nullptr;
static QMutex s_installAppMapMutex;
QMap<NameString, QStringList> m_installAppMap;
QStringList m_excludedDesktopfiles = {
"/usr/share/applications/software-properties-livepatch.desktop",
"/usr/share/applications/mate-color-select.desktop",
"/usr/share/applications/blueman-adapters.desktop",
"/usr/share/applications/blueman-manager.desktop",
"/usr/share/applications/mate-user-guide.desktop",
"/usr/share/applications/nm-connection-editor.desktop",
"/usr/share/applications/debian-uxterm.desktop",
"/usr/share/applications/debian-xterm.desktop",
"/usr/share/applications/im-config.desktop",
"/usr/share/applications/fcitx.desktop",
"/usr/share/applications/fcitx-configtool.desktop",
"/usr/share/applications/onboard-settings.desktop",
"/usr/share/applications/info.desktop",
"/usr/share/applications/ukui-power-preferences.desktop",
"/usr/share/applications/ukui-power-statistics.desktop",
"/usr/share/applications/software-properties-drivers.desktop",
"/usr/share/applications/software-properties-gtk.desktop",
"/usr/share/applications/gnome-session-properties.desktop",
"/usr/share/applications/org.gnome.font-viewer.desktop",
"/usr/share/applications/xdiagnose.desktop",
"/usr/share/applications/gnome-language-selector.desktop",
"/usr/share/applications/mate-notification-properties.desktop",
"/usr/share/applications/transmission-gtk.desktop",
"/usr/share/applications/mpv.desktop",
"/usr/share/applications/system-config-printer.desktop",
"/usr/share/applications/org.gnome.DejaDup.desktop",
"/usr/share/applications/yelp.desktop",
"/usr/share/applications/peony-computer.desktop",
"/usr/share/applications/peony-home.desktop",
"/usr/share/applications/peony-trash.desktop",
//v10
"/usr/share/applications/mate-about.desktop",
"/usr/share/applications/time.desktop",
"/usr/share/applications/network.desktop",
"/usr/share/applications/shares.desktop",
"/usr/share/applications/mate-power-statistics.desktop",
"/usr/share/applications/display-im6.desktop",
"/usr/share/applications/display-im6.q16.desktop",
"/usr/share/applications/openjdk-8-policytool.desktop",
"/usr/share/applications/kylin-io-monitor.desktop",
"/usr/share/applications/wps-office-uninstall.desktop",
};
};
}
#endif // APPDBMANAGER_H

View File

@ -0,0 +1,291 @@
/*
* Copyright (C) 2019 Tianjin KYLIN Information Technology 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, 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 <http://www.gnu.org/licenses/&gt;.
*
*/
#include <KWindowSystem>
#include <QFile>
#include <QDebug>
#include <QDir>
#include "convert-winid-to-desktop.h"
ConvertWinidToDesktop::ConvertWinidToDesktop(QObject *parent) : QObject(parent)
{
}
QString ConvertWinidToDesktop::tranIdToDesktop(WId id)
{
KWindowInfo info(id, 0, NET::WM2AllProperties);
QString desktopName = confirmDesktopFile(info);
qDebug() << "PID:" << info.pid() << "open desktopName:" << desktopName;
return desktopName;
}
QString ConvertWinidToDesktop::confirmDesktopFile(KWindowInfo info)
{
QString desktopFilePath = nullptr;
QDir dir = QDir(DESKTOP_FILE_PATH);
QFileInfoList list = dir.entryInfoList();
//跳过 ./ 和 ../ 目录
list.removeAll(QFile(USR_SHARE_APP_CURRENT));
list.removeAll(QFile(USR_SHARE_APP_UPER));
//第一种方法获取点击应用时大部分desktop文件名
desktopFilePath = searchFromEnviron(info, list);
//第二种方法:比较名字一致性
if (desktopFilePath.isEmpty()) {
m_classClass = info.windowClassClass().toLower();
m_className = info.windowClassName();
//匹配安卓兼容
if (m_className == "kylin-kmre-window") {
return searchAndroidApp(info);
}
QFile file(QString("/proc/%1/status").arg(info.pid()));
if (file.open(QIODevice::ReadOnly)) {
char buf[1024];
qint64 len=file.readLine(buf,sizeof(buf));
if (len!=-1) {
m_statusName = QString::fromLocal8Bit(buf).remove("Name:").remove("\t").remove("\n");
}
}
desktopFilePath = compareClassName(list);
}
//第三种方法比较cmd命令行操作一致性
if (desktopFilePath.isEmpty()) {
QFile file(QString("/proc/%1/cmdline").arg(info.pid()));
if (file.open(QIODevice::ReadOnly)) {
char buf[1024];
qint64 len=file.readLine(buf,sizeof(buf));
if (len!=-1) {
m_cmdLine = QString::fromLocal8Bit(buf).remove("\n");
}
}
desktopFilePath = compareCmdExec(list);
}
//第四种方法:匹配部分字段
if (desktopFilePath.isEmpty()) {
desktopFilePath = compareLastStrategy(list);
}
return desktopFilePath;
}
QString ConvertWinidToDesktop::searchAndroidApp(KWindowInfo info)
{
QDir androidDir = QString(QDir::homePath() + ANDROID_FILE_PATH);
QFileInfoList androidList = androidDir.entryInfoList();
androidList.removeAll(QDir::homePath() + ANDROID_APP_CURRENT);
androidList.removeAll(QDir::homePath() + ANDROID_APP_UPER);
QFile file(QString("/proc/%1/cmdline").arg(info.pid()));
file.open(QIODevice::ReadOnly);
QByteArray cmd = file.readAll();
file.close();
QList<QByteArray> cmdList = cmd.split('\0');
for (int i = 0; i < androidList.size(); i++) {
QFileInfo fileInfo = androidList.at(i);
QString desktopName = fileInfo.filePath();
if (!fileInfo.filePath().endsWith(".desktop")) {
continue;
}
desktopName = desktopName.mid(desktopName.lastIndexOf("/") + 1);
desktopName = desktopName.left(desktopName.lastIndexOf("."));
if(desktopName == cmdList.at(10)){
return fileInfo.filePath();
}
}
return nullptr;
}
QString ConvertWinidToDesktop::searchFromEnviron(KWindowInfo info, QFileInfoList list)
{
QFile file("/proc/" + QString::number(info.pid()) + "/environ");
file.open(QIODevice::ReadOnly);
QByteArray BA = file.readAll();
file.close();
QList<QByteArray> list_BA = BA.split('\0');
QString desktopFilePath = nullptr;
for (int i = 0; i < list_BA.length(); i++) {
if (list_BA.at(i).startsWith("GIO_LAUNCHED_DESKTOP_FILE=")) {
desktopFilePath = list_BA.at(i);
desktopFilePath = desktopFilePath.mid(desktopFilePath.indexOf("=") + 1);
//desktop文件地址需要重写
desktopFilePath = desktopFilePath.mid(desktopFilePath.lastIndexOf("/") + 1);
break;
}
}
//desktop文件地址重写
if (!desktopFilePath.isEmpty()) {
for (int i = 0; i < list.size(); i++) {
QFileInfo fileInfo = list.at(i);
if (fileInfo.filePath() == DESKTOP_FILE_PATH + desktopFilePath) {
desktopFilePath = fileInfo.filePath();
return desktopFilePath;
}
}
}
return desktopFilePath;
}
QString ConvertWinidToDesktop::compareClassName(QFileInfoList list)
{
for (int i = 0; i < list.size(); i++) {
QFileInfo fileInfo = list.at(i);;
QString pathDesktopName = fileInfo.filePath();
if (!fileInfo.filePath().endsWith(".desktop")) {
continue;
}
pathDesktopName = pathDesktopName.mid(pathDesktopName.lastIndexOf("/") + 1);
pathDesktopName = pathDesktopName.left(pathDesktopName.lastIndexOf("."));
if (pathDesktopName == m_classClass || pathDesktopName == m_className || pathDesktopName == m_statusName) {
return fileInfo.filePath();
}
}
return nullptr;
}
QString ConvertWinidToDesktop::compareCmdExec(QFileInfoList list)
{
for (int i = 0; i < list.size(); i++) {
QString cmd;
QFileInfo fileInfo = list.at(i);
if (!fileInfo.filePath().endsWith(".desktop")) {
continue;
}
cmd.sprintf(GET_DESKTOP_EXEC_NAME_MAIN, fileInfo.filePath().toStdString().data());
QString desktopFileExeName = getDesktopFileName(cmd).remove("\n");
if (desktopFileExeName.isEmpty()) {
continue;
}
if (desktopFileExeName == m_cmdLine || desktopFileExeName.startsWith(m_cmdLine) || m_cmdLine.startsWith(desktopFileExeName)) {
return fileInfo.filePath();
}
//仅仅是为了适配微信
desktopFileExeName = "/usr/lib/" + desktopFileExeName;
if (desktopFileExeName == m_cmdLine || desktopFileExeName.startsWith(m_cmdLine) || m_cmdLine.startsWith(desktopFileExeName)) {
return fileInfo.filePath();
}
}
return nullptr;
}
//最后的匹配策略汇总
QString ConvertWinidToDesktop::compareLastStrategy(QFileInfoList list)
{
QString desktopFilePath = compareCmdName(list);
if (desktopFilePath.isEmpty()) {
desktopFilePath = compareDesktopClass(list);
}
if (desktopFilePath.isEmpty()) {
desktopFilePath = containsName(list);
}
return desktopFilePath;
}
QString ConvertWinidToDesktop::compareCmdName(QFileInfoList list)
{
for (int i = 0; i < list.size(); i++) {
QString cmd;
QFileInfo fileInfo = list.at(i);
if (!fileInfo.filePath().endsWith(".desktop")) {
continue;
}
cmd.sprintf(GET_DESKTOP_EXEC_NAME_MAIN, fileInfo.filePath().toStdString().data());
QString desktopFileExeName = getDesktopFileName(cmd).remove("\n");
if (desktopFileExeName.isEmpty()) {
continue;
}
if (desktopFileExeName.startsWith(m_className) || desktopFileExeName.endsWith(m_className)) {
return fileInfo.filePath();
}
}
return nullptr;
}
QString ConvertWinidToDesktop::compareDesktopClass(QFileInfoList list)
{
for (int i = 0; i < list.size(); i++) {
QFileInfo fileInfo = list.at(i);
QString pathDesktopName = fileInfo.filePath();
if (!fileInfo.filePath().endsWith(".desktop")) {
continue;
}
pathDesktopName = pathDesktopName.mid(pathDesktopName.lastIndexOf("/") + 1);
pathDesktopName = pathDesktopName.left(pathDesktopName.lastIndexOf("."));
if (pathDesktopName.startsWith(m_className) || pathDesktopName.endsWith(m_className)) {
return fileInfo.filePath();
}
else if (m_className.startsWith(pathDesktopName) || m_className.endsWith(pathDesktopName)) {
return fileInfo.filePath();
}
}
return nullptr;
}
QString ConvertWinidToDesktop::containsName(QFileInfoList list)
{
for (int i = 0; i < list.size(); i++) {
QString cmd;
QFileInfo fileInfo = list.at(i);
QString pathDesktopName = fileInfo.filePath();
if (!fileInfo.filePath().endsWith(".desktop")) {
continue;
}
cmd.sprintf(GET_DESKTOP_EXEC_NAME_MAIN, fileInfo.filePath().toStdString().data());
QString desktopFileExeName = getDesktopFileName(cmd).remove("\n");
pathDesktopName = pathDesktopName.mid(pathDesktopName.lastIndexOf("/") + 1);
pathDesktopName = pathDesktopName.left(pathDesktopName.lastIndexOf("."));
if (pathDesktopName.contains(m_className) || desktopFileExeName.contains(m_className)) {
return fileInfo.filePath();
}
}
return nullptr;
}
//执行头文件中宏定义写好的终端指令获取对应的Exec字段
QString ConvertWinidToDesktop::getDesktopFileName(QString cmd)
{
char name[200];
FILE *fp1 = NULL;
if ((fp1 = popen(cmd.toStdString().data(), "r")) == NULL) {
return QString();
}
memset(name, 0, sizeof(name));
fgets(name, sizeof(name), fp1);
pclose(fp1);
return QString(name);
}
ConvertWinidToDesktop::~ConvertWinidToDesktop()
{
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2019 Tianjin KYLIN Information Technology 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, 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 <http://www.gnu.org/licenses/&gt;.
*
*/
#ifndef CONVERTDESKTOPTOWINID_H
#define CONVERTDESKTOPTOWINID_H
#include <QObject>
#include <KWindowSystem>
#include <QDir>
#define DESKTOP_FILE_PATH "/usr/share/applications/"
#define USR_SHARE_APP_CURRENT "/usr/share/applications/."
#define USR_SHARE_APP_UPER "/usr/share/applications/.."
#define PEONY_TRASH "/usr/share/applications/peony-trash.desktop"
#define PEONY_COMUTER "/usr/share/applications/peony-computer.desktop"
#define PEONY_HOME "/usr/share/applications/peony-home.desktop"
#define PEONY_MAIN "/usr/share/applications/peony.desktop"
#define GET_DESKTOP_EXEC_NAME_MAIN "cat %s | awk '{if($1~\"Exec=\")if($2~\"\%\"){print $1} else print}' | cut -d '=' -f 2"
#define ANDROID_FILE_PATH "/.local/share/applications/"
#define ANDROID_APP_CURRENT "/.local/share/applications/."
#define ANDROID_APP_UPER "/.local/share/applications/.."
/**
* @brief The ConvertWinidToDesktop class
* desktop文件与windowId的转换
* (int)WindowIddesktop文件的路径
*/
class ConvertWinidToDesktop : public QObject
{
Q_OBJECT
public:
explicit ConvertWinidToDesktop(QObject *parent = nullptr);
~ConvertWinidToDesktop();
QString tranIdToDesktop(WId id);
private:
QString m_classClass = nullptr;
QString m_className = nullptr;
QString m_statusName = nullptr;
QString m_cmdLine = nullptr;
QString confirmDesktopFile(KWindowInfo info);
QString searchFromEnviron(KWindowInfo info, QFileInfoList list);
QString searchAndroidApp(KWindowInfo info);
QString compareClassName(QFileInfoList list);
QString compareCmdExec(QFileInfoList list);
QString compareLastStrategy(QFileInfoList list);
QString compareCmdName(QFileInfoList list);
QString compareDesktopClass(QFileInfoList list);
QString containsName(QFileInfoList list);
QString getDesktopFileName(QString cmd);
};
#endif // CONVERTDESKTOPTOWINID_H

View File

@ -1,8 +1,67 @@
#include <QCoreApplication>
#include <QTime>
#include <QStandardPaths>
#include <QFile>
#include "ukui-search-app-data-service.h"
using namespace UkuiSearch;
void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
QByteArray localMsg = msg.toLocal8Bit();
QByteArray currentTime = QTime::currentTime().toString().toLocal8Bit();
bool showDebug = true;
QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.config/org.ukui/ukui-search-app-data-service.log";
if (!QFile::exists(logFilePath)) {
showDebug = false;
}
FILE *log_file = nullptr;
if (showDebug) {
log_file = fopen(logFilePath.toLocal8Bit().constData(), "a+");
}
const char *file = context.file ? context.file : "";
const char *function = context.function ? context.function : "";
switch (type) {
case QtDebugMsg:
if (!log_file) {
break;
}
fprintf(log_file, "Debug: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function);
break;
case QtInfoMsg:
fprintf(log_file? log_file: stdout, "Info: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function);
break;
case QtWarningMsg:
fprintf(log_file? log_file: stderr, "Warning: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function);
break;
case QtCriticalMsg:
fprintf(log_file? log_file: stderr, "Critical: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function);
break;
case QtFatalMsg:
fprintf(log_file? log_file: stderr, "Fatal: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function);
break;
}
if (log_file)
fclose(log_file);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// Output log to file
qInstallMessageHandler(messageOutput);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif
UkuiSearchAppDataService ukss(argc, argv, "ukui-search-app-data-service");
if (ukss.isRunning())
return 0;
return a.exec();
return ukss.exec();
}

View File

@ -0,0 +1,61 @@
#include <QDebug>
#include "ukui-search-app-data-service.h"
#include "app-db-manager.h"
#include "convert-winid-to-desktop.h"
using namespace UkuiSearch;
UkuiSearchAppDataService::UkuiSearchAppDataService(int &argc, char *argv[], const QString &applicationName):
QtSingleApplication (applicationName, argc, argv)
{
qDebug()<<"ukui search app data service constructor start";
setApplicationVersion(QString("v%1").arg(VERSION));
setQuitOnLastWindowClosed(false);
if (!this->isRunning()) {
connect(this, &QtSingleApplication::messageReceived, [=](QString msg) {
this->parseCmd(msg, true);
});
//监控应用进程开启
connect(KWindowSystem::self(), &KWindowSystem::windowAdded, [ = ](WId id) {
ConvertWinidToDesktop reply;
QString desktopfp = reply.tranIdToDesktop(id);
if (!desktopfp.isEmpty()) {
AppDBManager::getInstance()->updateAppLaunchTimes(desktopfp);
}
});
}
//parse cmd
qDebug()<<"parse cmd";
auto message = this->arguments().join(' ').toUtf8();
parseCmd(message, !isRunning());
qDebug()<<"ukui search app data service constructor end";
}
void UkuiSearchAppDataService::parseCmd(QString msg, bool isPrimary)
{
QCommandLineParser parser;
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption quitOption(QStringList()<<"q"<<"quit", tr("Stop service"));
parser.addOption(quitOption);
if (isPrimary) {
const QStringList args = QString(msg).split(' ');
parser.process(args);
if (parser.isSet(quitOption)) {
qApp->quit();
return;
}
}
else {
if (arguments().count() < 2) {
parser.showHelp();
}
parser.process(arguments());
sendMessage(msg);
}
}

View File

@ -0,0 +1,19 @@
#ifndef UkuiSearchAppDataService_H
#define UkuiSearchAppDataService_H
#include <QObject>
#include <QCommandLineParser>
#include "qtsingleapplication.h"
namespace UkuiSearch {
class UkuiSearchAppDataService : public QtSingleApplication
{
Q_OBJECT
public:
UkuiSearchAppDataService(int &argc, char *argv[], const QString &applicationName = "ukui-search-app-data-service");
protected Q_SLOTS:
void parseCmd(QString msg, bool isPrimary);
};
}
#endif // UkuiSearchAppDataService_H

View File

@ -1,4 +1,4 @@
QT += core gui dbus
QT += core gui dbus sql xml KWindowSystem
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
@ -7,8 +7,7 @@ TARGET = ukui-search-app-data-service
VERSION = 1.0.0
DEFINES += VERSION='\\"$${VERSION}\\"'
CONFIG += c++11 link_pkgconfig no_keywords lrelease
PKGCONFIG += gsettings-qt
PKGCONFIG += glib-2.0 gio-unix-2.0 gio-2.0 poppler-qt5
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
@ -22,9 +21,34 @@ QMAKE_CXXFLAGS += -Werror=return-type -Werror=return-local-addr -Werror=uninitia
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp
#include(../libsearch/appdata/appdata.pri)
include(../3rd-parties/qtsingleapplication/qtsingleapplication.pri)
LIBS += -lQt5Xdg -lquazip5 -luchardet -ltesseract
SOURCES += \
main.cpp \
convert-winid-to-desktop.cpp \
app-db-manager.cpp \
ukui-search-app-data-service.cpp \
../libsearch/file-utils.cpp \
../libsearch/gobject-template.cpp
HEADERS += \
convert-winid-to-desktop.h \
app-db-manager.h \
ukui-search-app-data-service.h \
app-db-common-defines.h \
../libsearch/file-utils.h \
../libsearch/gobject-template.h
# Default rules for deployment.
target.path = /usr/bin
INSTALLS += target
desktop.path = /etc/xdg/autostart
desktop.files += ../data/ukui-search-app-data-service.desktop
INSTALLS += desktop
LIBS += -L$$OUT_PWD/../libchinese-segmentation/ -lchinese-segmentation
INCLUDEPATH += $$PWD/../libchinese-segmentation
DEPENDPATH += $$PWD/../libchinese-segmentation

View File

@ -7,6 +7,7 @@ SUBDIRS += $$PWD/libchinese-segmentation \
$$PWD/ukui-search-service \
$$PWD/ukui-search-app-data-service \
$$PWD/ukui-search-service-dir-manager
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
@ -23,7 +24,7 @@ ukui-search-service.depends += libsearch
#src.depends = libsearch
frontend.depends = libsearch
CONFIG += ordered \
CONFIG += ordered
QT += widgets