From 0004538ee35664b321b8203785818590f8c05f7f Mon Sep 17 00:00:00 2001 From: jixiaoxu Date: Mon, 13 Jun 2022 13:38:47 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=90=9C=E7=B4=A2=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=BA=94=E7=94=A8=E6=95=B0=E6=8D=AE=E5=BA=93=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=EF=BC=9B=E6=96=B0=E5=A2=9E=E6=90=9C=E7=B4=A2=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E6=8F=92=E4=BB=B6=E5=8A=9F=E8=83=BD=EF=BC=9B=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E6=9C=8D=E5=8A=A1=E6=8E=A5=E5=8F=A3=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E8=BF=94=E5=9B=9E=E6=95=B0=E6=8D=AE=E7=BB=93?= =?UTF-8?q?=E6=9E=84=EF=BC=88=E5=BA=94=E7=94=A8=E6=90=9C=E7=B4=A2=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=EF=BC=89=EF=BC=9B=E7=9B=AE=E5=BD=95=E7=BB=93=E6=9E=84?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=AD=89=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/ukui-search-app-data-service.desktop | 16 + frontend/control/settings-widget.h | 2 +- frontend/frontend.pro | 2 +- libsearch/appdata/app-db-manager.cpp | 40 - libsearch/appdata/app-db-manager.h | 27 - libsearch/appdata/app-info-table-private.h | 41 +- libsearch/appdata/app-info-table.cpp | 782 +++++++++++++++++- libsearch/appdata/app-info-table.h | 76 +- libsearch/appdata/appdata.pri | 2 - libsearch/appsearch/app-match.cpp | 155 ++-- libsearch/appsearch/app-match.h | 77 +- libsearch/appsearch/app-search-plugin.cpp | 85 +- libsearch/appsearch/app-search-plugin.h | 21 +- libsearch/appsearch/appsearch.pri | 2 - .../header-files/UkuiSearchAppInfoTable | 1 + libsearch/libsearch.pro | 8 +- libsearch/plugininterface/common-defines.h | 43 +- .../search-task-plugin-manager.cpp | 6 + .../searchinterface/result-item-private.h | 6 +- libsearch/searchinterface/result-item.cpp | 37 +- libsearch/searchinterface/result-item.h | 12 +- .../search-controller-private.h | 13 +- .../searchinterface/search-controller.cpp | 87 +- libsearch/searchinterface/search-controller.h | 7 + .../searchtasks/app-search-task.cpp | 154 ++++ .../searchtasks/app-search-task.h | 57 ++ .../searchtasks/file-content-search-task.cpp | 4 +- .../searchtasks/file-content-search-task.h | 2 +- .../searchtasks/file-search-task.h | 3 - .../searchtasks/search-tasks.pri | 6 +- .../ukui-search-task-private.h | 2 + .../searchinterface/ukui-search-task.cpp | 22 + libsearch/searchinterface/ukui-search-task.h | 9 + .../app-db-common-defines.h | 11 + .../app-db-manager.cpp | 490 +++++++++++ ukui-search-app-data-service/app-db-manager.h | 127 +++ .../convert-winid-to-desktop.cpp | 291 +++++++ .../convert-winid-to-desktop.h | 73 ++ ukui-search-app-data-service/main.cpp | 63 +- .../ukui-search-app-data-service.cpp | 61 ++ .../ukui-search-app-data-service.h | 19 + .../ukui-search-app-data-service.pro | 36 +- ukui-search.pro | 3 +- 43 files changed, 2638 insertions(+), 343 deletions(-) create mode 100644 data/ukui-search-app-data-service.desktop delete mode 100644 libsearch/appdata/app-db-manager.cpp delete mode 100644 libsearch/appdata/app-db-manager.h create mode 100644 libsearch/development-files/header-files/UkuiSearchAppInfoTable create mode 100644 libsearch/searchinterface/searchtasks/app-search-task.cpp create mode 100644 libsearch/searchinterface/searchtasks/app-search-task.h create mode 100644 ukui-search-app-data-service/app-db-common-defines.h create mode 100644 ukui-search-app-data-service/app-db-manager.cpp create mode 100644 ukui-search-app-data-service/app-db-manager.h create mode 100755 ukui-search-app-data-service/convert-winid-to-desktop.cpp create mode 100755 ukui-search-app-data-service/convert-winid-to-desktop.h create mode 100644 ukui-search-app-data-service/ukui-search-app-data-service.cpp create mode 100644 ukui-search-app-data-service/ukui-search-app-data-service.h diff --git a/data/ukui-search-app-data-service.desktop b/data/ukui-search-app-data-service.desktop new file mode 100644 index 0000000..27343a5 --- /dev/null +++ b/data/ukui-search-app-data-service.desktop @@ -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 + diff --git a/frontend/control/settings-widget.h b/frontend/control/settings-widget.h index 984d352..185a8c1 100644 --- a/frontend/control/settings-widget.h +++ b/frontend/control/settings-widget.h @@ -32,7 +32,7 @@ #include #include #include -#include +#include "libsearch.h" #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) #include "xatom-helper.h" #endif diff --git a/frontend/frontend.pro b/frontend/frontend.pro index b4fd28a..a76c77f 100644 --- a/frontend/frontend.pro +++ b/frontend/frontend.pro @@ -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 diff --git a/libsearch/appdata/app-db-manager.cpp b/libsearch/appdata/app-db-manager.cpp deleted file mode 100644 index cd61e09..0000000 --- a/libsearch/appdata/app-db-manager.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "app-db-manager.h" -#include -#include -#include -#include -#include -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: 建表 -} - - diff --git a/libsearch/appdata/app-db-manager.h b/libsearch/appdata/app-db-manager.h deleted file mode 100644 index 79affad..0000000 --- a/libsearch/appdata/app-db-manager.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef APPDBMANAGER_H -#define APPDBMANAGER_H - -#include -#include -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 diff --git a/libsearch/appdata/app-info-table-private.h b/libsearch/appdata/app-info-table-private.h index e4b7ba8..358ba60 100644 --- a/libsearch/appdata/app-info-table-private.h +++ b/libsearch/appdata/app-info-table-private.h @@ -1,7 +1,9 @@ #ifndef APPINFOTABLEPRIVATE_H #define APPINFOTABLEPRIVATE_H #include +#include #include + 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 &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 &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; }; diff --git a/libsearch/appdata/app-info-table.cpp b/libsearch/appdata/app-info-table.cpp index dfe2356..2f28351 100644 --- a/libsearch/appdata/app-info-table.cpp +++ b/libsearch/appdata/app-info-table.cpp @@ -1,10 +1,790 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #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 &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 isExist = iface.call("CheckIfExist", desktopfp); + if(isExist) { + qWarning() << "Add shortcut to panel failed, because it is already existed!"; + } else { + QDBusReply 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; ++ilastError(); + 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 &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(); +} diff --git a/libsearch/appdata/app-info-table.h b/libsearch/appdata/app-info-table.h index c177700..ef50ac2 100644 --- a/libsearch/appdata/app-info-table.h +++ b/libsearch/appdata/app-info-table.h @@ -4,29 +4,77 @@ #include 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 &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; }; diff --git a/libsearch/appdata/appdata.pri b/libsearch/appdata/appdata.pri index 875aabf..c265c1e 100644 --- a/libsearch/appdata/appdata.pri +++ b/libsearch/appdata/appdata.pri @@ -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 diff --git a/libsearch/appsearch/app-match.cpp b/libsearch/appsearch/app-match.cpp index 176ce37..859bde2 100644 --- a/libsearch/appsearch/app-match.cpp +++ b/libsearch/appsearch/app-match.cpp @@ -21,9 +21,10 @@ #include #include #include +#include #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>(); qDBusRegisterMetaType>>(); 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 *searchResult) { @@ -72,73 +67,6 @@ void AppMatch::startMatchApp(QString input, size_t uniqueSymbol, DataQueue *searchResult) { - QMapIterator 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 installAppMap; + m_appInfoTable->getInstallAppMap(installAppMap); + QMap 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 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 &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 *searchResult) { QDBusReply>> reply = m_interFace->call("get_search_result", keyWord); //阻塞,直到远程方法调用完成。 -// QDBusPendingReply>> reply = *call; if(reply.isValid()) { parseSoftWareCenterReturn(reply.value(), uniqueSymbol, searchResult); } else { qWarning() << "SoftWareCenter dbus called failed!"; } -// call->deleteLater(); } void AppMatch::parseSoftWareCenterReturn(QList> list, size_t uniqueSymbol, DataQueue *searchResult) { @@ -275,24 +221,17 @@ void AppMatch::parseSoftWareCenterReturn(QList> list, siz } } -void AppMatch::creatResultInfo(SearchPluginIface::ResultInfo &ri, QMapIterator &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 &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.."; } diff --git a/libsearch/appsearch/app-match.h b/libsearch/appsearch/app-match.h index f4a95e8..08cfbf7 100644 --- a/libsearch/appsearch/app-match.h +++ b/libsearch/appsearch/app-match.h @@ -29,31 +29,9 @@ #include #include #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 *searchResult); - void softWareCenterSearch(QMap &softwarereturn); void parseSoftWareCenterReturn(QList> list, size_t uniqueSymbol, DataQueue *searchResult); - void creatResultInfo(SearchPluginIface::ResultInfo &ri, QMapIterator &iter, bool isInstalled = true); + //void creatResultInfo(SearchPluginIface::ResultInfo &ri, QMapIterator &iter, bool isInstalled = true); + AppInfoTable *m_appInfoTable = nullptr; QString m_sourceText; size_t m_uniqueSymbol; DataQueue *m_search_result = nullptr; QDBusInterface *m_interFace = nullptr; - QFileSystemWatcher *m_watchAppDir = nullptr; - QMap 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 *searchResult); diff --git a/libsearch/appsearch/app-search-plugin.cpp b/libsearch/appsearch/app-search-plugin.cpp index a52ebf0..2f96345 100644 --- a/libsearch/appsearch/app-search-plugin.cpp +++ b/libsearch/appsearch/app-search-plugin.cpp @@ -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, DataQueuesetPixmap(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 *searchResult, const QString &keyword, size_t uniqueSymbol) +AppSearch::AppSearch(DataQueue *searchResult, DataQueue* 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(); + 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; + } } diff --git a/libsearch/appsearch/app-search-plugin.h b/libsearch/appsearch/app-search-plugin.h index 2b34c2e..ece119f 100644 --- a/libsearch/appsearch/app-search-plugin.h +++ b/libsearch/appsearch/app-search-plugin.h @@ -8,11 +8,14 @@ #include #include #include +#include +#include +#include #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* 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 *searchResult, const QString& keyword, size_t uniqueSymbol); + AppSearch(DataQueue *searchResult, DataQueue* appSearchResults, UkuiSearchTask *appSearchTask, QString keyword, size_t uniqueSymbol); ~AppSearch(); protected: void run() override; private: - DataQueue *m_search_result = nullptr; + + bool isUniqueSymbolChanged(); + size_t m_uniqueSymbol; - QString m_keyword; - QMap m_installed_apps; - QMap m_not_installed_apps; + UkuiSearchTask *m_appSearchTask = nullptr; + DataQueue* m_appSearchResults = nullptr; + DataQueue *m_search_result = nullptr; + }; } diff --git a/libsearch/appsearch/appsearch.pri b/libsearch/appsearch/appsearch.pri index c222506..9f39bab 100644 --- a/libsearch/appsearch/appsearch.pri +++ b/libsearch/appsearch/appsearch.pri @@ -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 diff --git a/libsearch/development-files/header-files/UkuiSearchAppInfoTable b/libsearch/development-files/header-files/UkuiSearchAppInfoTable new file mode 100644 index 0000000..046c057 --- /dev/null +++ b/libsearch/development-files/header-files/UkuiSearchAppInfoTable @@ -0,0 +1 @@ +#include "app-info-table.h" diff --git a/libsearch/libsearch.pro b/libsearch/libsearch.pro index fd86553..79da936 100644 --- a/libsearch/libsearch.pro +++ b/libsearch/libsearch.pro @@ -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/* diff --git a/libsearch/plugininterface/common-defines.h b/libsearch/plugininterface/common-defines.h index 0107a89..422fc77 100644 --- a/libsearch/plugininterface/common-defines.h +++ b/libsearch/plugininterface/common-defines.h @@ -1,15 +1,44 @@ #ifndef COMMONDEFINES_H #define COMMONDEFINES_H +#include 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 diff --git a/libsearch/pluginmanage/search-task-plugin-manager.cpp b/libsearch/pluginmanage/search-task-plugin-manager.cpp index 1dbd963..195dcda 100644 --- a/libsearch/pluginmanage/search-task-plugin-manager.cpp +++ b/libsearch/pluginmanage/search-task-plugin-manager.cpp @@ -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; } diff --git a/libsearch/searchinterface/result-item-private.h b/libsearch/searchinterface/result-item-private.h index 3c3a5d7..7c4b00f 100644 --- a/libsearch/searchinterface/result-item-private.h +++ b/libsearch/searchinterface/result-item-private.h @@ -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; diff --git a/libsearch/searchinterface/result-item.cpp b/libsearch/searchinterface/result-item.cpp index 8b6d0e5..6fc0542 100644 --- a/libsearch/searchinterface/result-item.cpp +++ b/libsearch/searchinterface/result-item.cpp @@ -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()); } diff --git a/libsearch/searchinterface/result-item.h b/libsearch/searchinterface/result-item.h index 5e159bc..14e402b 100644 --- a/libsearch/searchinterface/result-item.h +++ b/libsearch/searchinterface/result-item.h @@ -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; }; diff --git a/libsearch/searchinterface/search-controller-private.h b/libsearch/searchinterface/search-controller-private.h index 40d82e7..49ad0ba 100644 --- a/libsearch/searchinterface/search-controller-private.h +++ b/libsearch/searchinterface/search-controller-private.h @@ -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* 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* m_dataQueue = nullptr ; - std::shared_ptr> m_sharedDataueue = nullptr; + std::shared_ptr> 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 m_searchType2ResultDataType; + QMap m_customSearchType2ResultDataType; }; } diff --git a/libsearch/searchinterface/search-controller.cpp b/libsearch/searchinterface/search-controller.cpp index 2af8f95..d91bedd 100644 --- a/libsearch/searchinterface/search-controller.cpp +++ b/libsearch/searchinterface/search-controller.cpp @@ -24,22 +24,22 @@ size_t SearchControllerPrivate::refreshSearchId() DataQueue *SearchControllerPrivate::refreshDataqueue() { - if(!m_sharedDataueue.get()) { + if(!m_sharedDataQueue.get()) { // m_dataQueue = new DataQueue; - m_sharedDataueue = std::make_shared>(); - return m_sharedDataueue.get(); + m_sharedDataQueue = std::make_shared>(); + return m_sharedDataQueue.get(); } - m_sharedDataueue.get()->clear(); - return m_sharedDataueue.get(); + m_sharedDataQueue.get()->clear(); + return m_sharedDataQueue.get(); } DataQueue *SearchControllerPrivate::initDataQueue() { - if(!m_sharedDataueue.get()) { - m_sharedDataueue = std::make_shared>(); - return m_sharedDataueue.get(); + if(!m_sharedDataQueue.get()) { + m_sharedDataQueue = std::make_shared>(); + 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 *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 *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); +} diff --git a/libsearch/searchinterface/search-controller.h b/libsearch/searchinterface/search-controller.h index 4a9a992..51918ef 100644 --- a/libsearch/searchinterface/search-controller.h +++ b/libsearch/searchinterface/search-controller.h @@ -4,6 +4,7 @@ #include #include #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* 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 m_parent = nullptr; SearchControllerPrivate *d = nullptr; diff --git a/libsearch/searchinterface/searchtasks/app-search-task.cpp b/libsearch/searchinterface/searchtasks/app-search-task.cpp new file mode 100644 index 0000000..13e6dd0 --- /dev/null +++ b/libsearch/searchinterface/searchtasks/app-search-task.cpp @@ -0,0 +1,154 @@ +#include "app-search-task.h" +#include "index-status-recorder.h" +#include "common.h" +#include +#include +#include +#include +#include + +using namespace UkuiSearch; +AppSearchTask::AppSearchTask(QObject *parent) +{ + this->setParent(parent); + qRegisterMetaType("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) +{ + 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) : m_AppSearchTask(AppSarchTask), m_searchController(searchController) +{ + qDBusRegisterMetaType>(); + qDBusRegisterMetaType>>(); + 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>> 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)); +} diff --git a/libsearch/searchinterface/searchtasks/app-search-task.h b/libsearch/searchinterface/searchtasks/app-search-task.h new file mode 100644 index 0000000..3c16ea7 --- /dev/null +++ b/libsearch/searchinterface/searchtasks/app-search-task.h @@ -0,0 +1,57 @@ +#ifndef APPSEARCHTASK_H +#define APPSEARCHTASK_H + +#include +#include +#include +#include +#include +#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); + 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); + +protected: + void run(); + +private: + ~AppSearchWorker(); + void sendErrorMsg(const QString &msg); + +private: + AppInfoTable m_appInfoTable; + AppSearchTask *m_AppSearchTask = nullptr; + std::shared_ptr m_searchController; + QDBusInterface *m_interFace = nullptr; + size_t m_currentSearchId = 0; +}; +} +#endif // APPSEARCHTASK_H diff --git a/libsearch/searchinterface/searchtasks/file-content-search-task.cpp b/libsearch/searchinterface/searchtasks/file-content-search-task.cpp index 221a4da..ddaaf4a 100644 --- a/libsearch/searchinterface/searchtasks/file-content-search-task.cpp +++ b/libsearch/searchinterface/searchtasks/file-content-search-task.cpp @@ -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() diff --git a/libsearch/searchinterface/searchtasks/file-content-search-task.h b/libsearch/searchinterface/searchtasks/file-content-search-task.h index 82ff757..48d441f 100644 --- a/libsearch/searchinterface/searchtasks/file-content-search-task.h +++ b/libsearch/searchinterface/searchtasks/file-content-search-task.h @@ -38,7 +38,7 @@ public: private: QThreadPool *m_pool = nullptr; - bool e_enable = true; + bool m_enable = true; }; class FileContentSearchWorker : public QRunnable diff --git a/libsearch/searchinterface/searchtasks/file-search-task.h b/libsearch/searchinterface/searchtasks/file-search-task.h index 216d250..1acacaf 100644 --- a/libsearch/searchinterface/searchtasks/file-search-task.h +++ b/libsearch/searchinterface/searchtasks/file-search-task.h @@ -11,9 +11,6 @@ #include "result-item.h" namespace UkuiSearch { -/* - * 这里只写了大概框架,具体逻辑未实现,可以当成伪代码参考。 -*/ class FileSearchTask : public SearchTaskPluginIface { Q_OBJECT diff --git a/libsearch/searchinterface/searchtasks/search-tasks.pri b/libsearch/searchinterface/searchtasks/search-tasks.pri index 7bf36a7..0751fb3 100644 --- a/libsearch/searchinterface/searchtasks/search-tasks.pri +++ b/libsearch/searchinterface/searchtasks/search-tasks.pri @@ -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 diff --git a/libsearch/searchinterface/ukui-search-task-private.h b/libsearch/searchinterface/ukui-search-task-private.h index 3a00832..e7d6fa7 100644 --- a/libsearch/searchinterface/ukui-search-task-private.h +++ b/libsearch/searchinterface/ukui-search-task-private.h @@ -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(); diff --git a/libsearch/searchinterface/ukui-search-task.cpp b/libsearch/searchinterface/ukui-search-task.cpp index fb42c91..e1dd994 100644 --- a/libsearch/searchinterface/ukui-search-task.cpp +++ b/libsearch/searchinterface/ukui-search-task.cpp @@ -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); diff --git a/libsearch/searchinterface/ukui-search-task.h b/libsearch/searchinterface/ukui-search-task.h index 3b29ebd..b2d71e8 100644 --- a/libsearch/searchinterface/ukui-search-task.h +++ b/libsearch/searchinterface/ukui-search-task.h @@ -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(); diff --git a/ukui-search-app-data-service/app-db-common-defines.h b/ukui-search-app-data-service/app-db-common-defines.h new file mode 100644 index 0000000..e3c1225 --- /dev/null +++ b/ukui-search-app-data-service/app-db-common-defines.h @@ -0,0 +1,11 @@ +#ifndef APPDBCOMMONDEFINES_H +#define APPDBCOMMONDEFINES_H +#include + +namespace UkuiSearch { + +#define APP_DATABASE_PATH QDir::homePath()+"/.config/org.ukui/ukui-search/appdata/" +#define APP_DATABASE_NAME "app-info.db" + +} +#endif // APPDBCOMMONDEFINES_H diff --git a/ukui-search-app-data-service/app-db-manager.cpp b/ukui-search-app-data-service/app-db-manager.cpp new file mode 100644 index 0000000..8435d4d --- /dev/null +++ b/ukui-search-app-data-service/app-db-manager.cpp @@ -0,0 +1,490 @@ +#include +#include +#include +#include +#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; ilastError() << 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 &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; ilastError() << 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; ilastError() << 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; +} + + diff --git a/ukui-search-app-data-service/app-db-manager.h b/ukui-search-app-data-service/app-db-manager.h new file mode 100644 index 0000000..9b7be42 --- /dev/null +++ b/ukui-search-app-data-service/app-db-manager.h @@ -0,0 +1,127 @@ +#ifndef APPDBMANAGER_H +#define APPDBMANAGER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 &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 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 diff --git a/ukui-search-app-data-service/convert-winid-to-desktop.cpp b/ukui-search-app-data-service/convert-winid-to-desktop.cpp new file mode 100755 index 0000000..6914844 --- /dev/null +++ b/ukui-search-app-data-service/convert-winid-to-desktop.cpp @@ -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 +#include +#include +#include +#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 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 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() +{ +} diff --git a/ukui-search-app-data-service/convert-winid-to-desktop.h b/ukui-search-app-data-service/convert-winid-to-desktop.h new file mode 100755 index 0000000..ba6a77f --- /dev/null +++ b/ukui-search-app-data-service/convert-winid-to-desktop.h @@ -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 +#include +#include + +#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)WindowId,转化为desktop文件的路径 + */ + +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 diff --git a/ukui-search-app-data-service/main.cpp b/ukui-search-app-data-service/main.cpp index 470a030..5bed375 100644 --- a/ukui-search-app-data-service/main.cpp +++ b/ukui-search-app-data-service/main.cpp @@ -1,8 +1,67 @@ #include +#include +#include +#include +#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(); } diff --git a/ukui-search-app-data-service/ukui-search-app-data-service.cpp b/ukui-search-app-data-service/ukui-search-app-data-service.cpp new file mode 100644 index 0000000..f483fe4 --- /dev/null +++ b/ukui-search-app-data-service/ukui-search-app-data-service.cpp @@ -0,0 +1,61 @@ +#include +#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); + } +} diff --git a/ukui-search-app-data-service/ukui-search-app-data-service.h b/ukui-search-app-data-service/ukui-search-app-data-service.h new file mode 100644 index 0000000..e50fe71 --- /dev/null +++ b/ukui-search-app-data-service/ukui-search-app-data-service.h @@ -0,0 +1,19 @@ +#ifndef UkuiSearchAppDataService_H +#define UkuiSearchAppDataService_H + +#include +#include +#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 diff --git a/ukui-search-app-data-service/ukui-search-app-data-service.pro b/ukui-search-app-data-service/ukui-search-app-data-service.pro index df00b1f..bc4ff76 100644 --- a/ukui-search-app-data-service/ukui-search-app-data-service.pro +++ b/ukui-search-app-data-service/ukui-search-app-data-service.pro @@ -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 diff --git a/ukui-search.pro b/ukui-search.pro index 31b885b..1bbc3f4 100644 --- a/ukui-search.pro +++ b/ukui-search.pro @@ -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