From 57df9970392e62c599a71b10a4a9260b7b832ca3 Mon Sep 17 00:00:00 2001 From: JunjieBai Date: Thu, 23 Jun 2022 10:12:02 +0800 Subject: [PATCH 1/3] Fix: The AppDatabase exception will cause the program that calls it to exit. --- libsearch/appdata/app-info-table-private.h | 4 ++-- libsearch/appdata/app-info-table.cpp | 17 +++++++++++------ libsearch/appdata/app-info-table.h | 2 ++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/libsearch/appdata/app-info-table-private.h b/libsearch/appdata/app-info-table-private.h index 358ba60..7cbe75d 100644 --- a/libsearch/appdata/app-info-table-private.h +++ b/libsearch/appdata/app-info-table-private.h @@ -45,8 +45,8 @@ public: private: ~AppInfoTablePrivate(); - void initDateBaseConnection(); - void openDataBase(); + bool initDateBaseConnection(); + bool openDataBase(); void closeDataBase(); AppInfoTable *q = nullptr; diff --git a/libsearch/appdata/app-info-table.cpp b/libsearch/appdata/app-info-table.cpp index 2f28351..8201547 100644 --- a/libsearch/appdata/app-info-table.cpp +++ b/libsearch/appdata/app-info-table.cpp @@ -25,7 +25,10 @@ AppInfoTablePrivate::AppInfoTablePrivate(AppInfoTable *parent) : QObject(parent) break; } qDebug() << "App info database currunt connection name:" << m_ConnectionName; - this->openDataBase(); + if (!this->openDataBase()) { + Q_EMIT q->DBOpenFailed(); + qWarning() << "Fail to open App DataBase, because:" << m_database->lastError(); + } } bool AppInfoTablePrivate::setAppFavoritesState(QString &desktopfp, size_t num) @@ -653,24 +656,26 @@ AppInfoTablePrivate::~AppInfoTablePrivate() this->closeDataBase(); } -void AppInfoTablePrivate::initDateBaseConnection() +bool AppInfoTablePrivate::initDateBaseConnection() { m_database->setDatabaseName(APP_DATABASE_PATH + APP_DATABASE_NAME); if(!m_database->open()) { qWarning() << m_database->lastError(); - QApplication::quit(); + return false; +// QApplication::quit(); } + return true; } -void AppInfoTablePrivate::openDataBase() +bool 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(); + return false; } + return true; } void AppInfoTablePrivate::closeDataBase() diff --git a/libsearch/appdata/app-info-table.h b/libsearch/appdata/app-info-table.h index ef50ac2..04cf34e 100644 --- a/libsearch/appdata/app-info-table.h +++ b/libsearch/appdata/app-info-table.h @@ -76,6 +76,8 @@ private: bool updateAppLaunchTimes(QString &desktopfp); AppInfoTablePrivate *d; +Q_SIGNALS: + void DBOpenFailed(); }; } From e7cfd7bd831aac8e12ee002e1b100df6c71d698a Mon Sep 17 00:00:00 2001 From: JunjieBai Date: Thu, 23 Jun 2022 10:13:58 +0800 Subject: [PATCH 2/3] Optimize the structure of app-search plugin. --- libsearch/appsearch/app-search-plugin.cpp | 194 +++++++++++------- libsearch/appsearch/app-search-plugin.h | 38 ++-- .../searchinterface/ukui-search-task.cpp | 1 + 3 files changed, 146 insertions(+), 87 deletions(-) diff --git a/libsearch/appsearch/app-search-plugin.cpp b/libsearch/appsearch/app-search-plugin.cpp index 2f96345..d03bdd9 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), m_appSearchTask(new UkuiSearchTask(this)) +AppSearchPlugin::AppSearchPlugin(QObject *parent) : QThread(parent), m_appSearchTask(new UkuiSearchTask(this)) { SearchPluginIface::Actioninfo open { 0, tr("Open")}; SearchPluginIface::Actioninfo addtoDesktop { 1, tr("Add Shortcut to Desktop")}; @@ -14,10 +14,20 @@ AppSearchPlugin::AppSearchPlugin(QObject *parent) : QObject(parent), m_appSearch SearchPluginIface::Actioninfo install { 0, tr("Install")}; m_actionInfo_installed << open << addtoDesktop << addtoPanel; m_actionInfo_not_installed << install; - m_pool.setMaxThreadCount(1); - m_pool.setExpiryTimeout(1000); +// m_pool.setMaxThreadCount(1); +// m_pool.setExpiryTimeout(1000); initDetailPage(); + m_timer = new QTimer(this); + m_timer->setInterval(3000); + m_timer->moveToThread(this); + connect(this, SIGNAL(startTimer), m_timer, SLOT(start())); + connect(this, &AppSearchPlugin::stopTimer, m_timer, &QTimer::stop); + connect(m_timer, &QTimer::timeout, this, [ & ]{ + qWarning()<<"-------------->stopped by itself"; + this->quit(); + }); + m_appSearchResults = m_appSearchTask->init(); m_appSearchTask->initSearchPlugin(SearchType::Application); m_appSearchTask->setSearchOnlineApps(true); @@ -26,6 +36,31 @@ AppSearchPlugin::AppSearchPlugin(QObject *parent) : QObject(parent), m_appSearch UkuiSearch::ApplicationIconName | UkuiSearch::ApplicationDescription | UkuiSearch::IsOnlineApplication); + + connect(m_appSearchTask, &UkuiSearchTask::searchFinished, this, [ & ] { + if (m_timer->isActive()) { + Q_EMIT this->stopTimer(); + m_timer->setInterval(3000); + } + + while(!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(); + m_searchResult->enqueue(ri); + } + + if(!m_timer->isActive()) { + Q_EMIT this->startTimer(); + } + }); } const QString AppSearchPlugin::name() @@ -48,8 +83,17 @@ void AppSearchPlugin::KeywordSearch(QString keyword, DataQueueisRunning()) { + this->start(); + } + m_searchResult = searchResult; + m_appSearchTask->clearKeyWords(); + m_appSearchTask->addKeyword(keyword); + m_appSearchTask->startSearch(SearchType::Application); + +// AppSearch *appsearch = new AppSearch(searchResult, m_appSearchResults, m_appSearchTask, keyword, uniqueSymbol); +// m_pool.start(appsearch); } void AppSearchPlugin::stopSearch() @@ -142,6 +186,11 @@ QWidget *AppSearchPlugin::detailPage(const ResultInfo &ri) return m_detailPage; } +void AppSearchPlugin::run() +{ + exec(); +} + void AppSearchPlugin::initDetailPage() { m_detailPage = new QWidget(); @@ -273,72 +322,75 @@ bool AppSearchPlugin::installAppAction(const QString & name) { } } -AppSearch::AppSearch(DataQueue *searchResult, DataQueue* appSearchResults, UkuiSearchTask *appSearchTask, QString keyword, size_t uniqueSymbol) -{ - this->setAutoDelete(true); - m_search_result = searchResult; - m_appSearchResults = appSearchResults; - m_appSearchTask = appSearchTask; - m_appSearchTask->clearKeyWords(); - m_appSearchTask->addKeyword(keyword); - m_uniqueSymbol = uniqueSymbol; -} +//AppSearch::AppSearch(DataQueue *searchResult, DataQueue* appSearchResults, UkuiSearchTask *appSearchTask, QString keyword, size_t uniqueSymbol) +//{ +// this->setAutoDelete(true); +// m_search_result = searchResult; +// m_appSearchResults = appSearchResults; +// m_appSearchTask = appSearchTask; +// m_appSearchTask->clearKeyWords(); +// m_appSearchTask->addKeyword(keyword); +// m_uniqueSymbol = uniqueSymbol; +//} -AppSearch::~AppSearch() -{ -} +//AppSearch::~AppSearch() +//{ +//} -void AppSearch::run() -{ - 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); - } - } -} +//void AppSearch::run() +//{ +//// m_appSearchTask->startSearch(SearchType::Application); +// QTimer timer; +// timer.setInterval(3000); +// bool is_empty; +// while(1) { +// is_empty = false; +// if(!m_appSearchResults->isEmpty()) { -bool AppSearch::isUniqueSymbolChanged() -{ - QMutexLocker locker(&AppSearchPlugin::m_mutex); - if (m_uniqueSymbol != AppSearchPlugin::uniqueSymbol) { - qDebug() << "uniqueSymbol changged, app search finished!"; - return true; - } else { - return false; - } -} +// 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 ece119f..13eb7b5 100644 --- a/libsearch/appsearch/app-search-plugin.h +++ b/libsearch/appsearch/app-search-plugin.h @@ -17,7 +17,7 @@ #include "libsearch_global.h" #include "ukui-search-task.h" namespace UkuiSearch { -class LIBSEARCH_EXPORT AppSearchPlugin : public QObject, public SearchPluginIface +class LIBSEARCH_EXPORT AppSearchPlugin : public QThread, public SearchPluginIface { friend class AppSearch; friend class AppMatch; @@ -39,6 +39,7 @@ public: // bool isPreviewEnable(QString key, int type); // QWidget *previewPage(QString key, int type, QWidget *parent); QWidget *detailPage(const ResultInfo &ri); + void run() override; private: void initDetailPage(); bool launch(const QString &path); @@ -48,12 +49,14 @@ private: bool m_enable = true; QList m_actionInfo_installed; QList m_actionInfo_not_installed; - QThreadPool m_pool; +// QThreadPool m_pool; + QTimer *m_timer; static size_t uniqueSymbol; static QMutex m_mutex; UkuiSearchTask *m_appSearchTask = nullptr; DataQueue* m_appSearchResults = nullptr; + DataQueue *m_searchResult = nullptr; QString m_currentActionKey; QWidget *m_detailPage; @@ -76,25 +79,28 @@ private: ActionLabel *m_actionLabel4 = nullptr; QVBoxLayout * m_actionLyt = nullptr; +Q_SIGNALS: + void startTimer(); + void stopTimer(); }; -class AppSearch : public QObject, public QRunnable { - Q_OBJECT -public: - AppSearch(DataQueue *searchResult, DataQueue* appSearchResults, UkuiSearchTask *appSearchTask, QString keyword, size_t uniqueSymbol); - ~AppSearch(); -protected: - void run() override; -private: +//class AppSearch : public QObject, public QRunnable { +// Q_OBJECT +//public: +// AppSearch(DataQueue *searchResult, DataQueue* appSearchResults, UkuiSearchTask *appSearchTask, QString keyword, size_t uniqueSymbol); +// ~AppSearch(); +//protected: +// void run() override; +//private: - bool isUniqueSymbolChanged(); +// bool isUniqueSymbolChanged(); - size_t m_uniqueSymbol; - UkuiSearchTask *m_appSearchTask = nullptr; - DataQueue* m_appSearchResults = nullptr; - DataQueue *m_search_result = nullptr; +// size_t m_uniqueSymbol; +// UkuiSearchTask *m_appSearchTask = nullptr; +// DataQueue* m_appSearchResults = nullptr; +// DataQueue *m_search_result = nullptr; -}; +//}; } #endif // APPSEARCHPLUGIN_H diff --git a/libsearch/searchinterface/ukui-search-task.cpp b/libsearch/searchinterface/ukui-search-task.cpp index e1dd994..396d311 100644 --- a/libsearch/searchinterface/ukui-search-task.cpp +++ b/libsearch/searchinterface/ukui-search-task.cpp @@ -86,6 +86,7 @@ size_t UkuiSearchTaskPrivate::startSearch(SearchType searchtype, const QString& qWarning() << "the date queue has not been initialized, you need run init first!"; } + m_searchCotroller->refreshDataqueue(); //plugin manager do async search here if (!SearchTaskPluginManager::getInstance()->startSearch(m_uuid, m_searchCotroller, searchtype, customSearchType)) { Q_EMIT searchError(m_searchCotroller->getCurrentSearchId(), tr("Current task uuid error or an unregistered plugin is used!")); From 5b90706ca8574d53ee8222f4e9ff40db50051c71 Mon Sep 17 00:00:00 2001 From: JunjieBai Date: Thu, 23 Jun 2022 10:21:22 +0800 Subject: [PATCH 3/3] Add a new function to traverse the desktop files and to handle the data in AppDataBase. Adjust the code structure. --- libsearch/appsearch/app-search-plugin.cpp | 2 +- .../app-db-manager.cpp | 372 +++++++++++++----- ukui-search-app-data-service/app-db-manager.h | 20 +- .../convert-winid-to-desktop.cpp | 6 + .../convert-winid-to-desktop.h | 8 +- ukui-search-app-data-service/main.cpp | 8 +- .../ukui-search-app-data-service.cpp | 21 +- .../ukui-search-app-data-service.pro | 15 +- .../dirwatcher/dir-watcher.h | 7 +- 9 files changed, 336 insertions(+), 123 deletions(-) diff --git a/libsearch/appsearch/app-search-plugin.cpp b/libsearch/appsearch/app-search-plugin.cpp index d03bdd9..11958ff 100644 --- a/libsearch/appsearch/app-search-plugin.cpp +++ b/libsearch/appsearch/app-search-plugin.cpp @@ -24,7 +24,7 @@ AppSearchPlugin::AppSearchPlugin(QObject *parent) : QThread(parent), m_appSearch connect(this, SIGNAL(startTimer), m_timer, SLOT(start())); connect(this, &AppSearchPlugin::stopTimer, m_timer, &QTimer::stop); connect(m_timer, &QTimer::timeout, this, [ & ]{ - qWarning()<<"-------------->stopped by itself"; + qWarning() << "The app-search thread stopped because of timeout."; this->quit(); }); diff --git a/ukui-search-app-data-service/app-db-manager.cpp b/ukui-search-app-data-service/app-db-manager.cpp index 8435d4d..a4b95db 100644 --- a/ukui-search-app-data-service/app-db-manager.cpp +++ b/ukui-search-app-data-service/app-db-manager.cpp @@ -3,14 +3,21 @@ #include #include #include "app-db-manager.h" -#include "../libsearch/file-utils.h" -using namespace UkuiSearch; +#include "file-utils.h" +#include "convert-winid-to-desktop.h" + #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(); +#define LAST_LOCALE_NAME QDir::homePath() + "/.config/org.ukui/ukui-search/appdata/last-locale-name.conf" +#define LOCALE_NAME_VALUE "CurrentLocaleName" + +using namespace UkuiSearch; + +static AppDBManager *global_instance; QMutex AppDBManager::s_installAppMapMutex; + AppDBManager *AppDBManager::getInstance() { if (!global_instance) { @@ -18,37 +25,68 @@ AppDBManager *AppDBManager::getInstance() } return global_instance; } -AppDBManager::AppDBManager(QObject *parent) : QObject(parent), m_database(new QSqlDatabase) + +AppDBManager::AppDBManager(QObject *parent) : QObject(parent), m_database(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(); + //链接数据库 + if (openDataBase()) { + //监听系统语言变化 + m_qSettings = new QSettings(LAST_LOCALE_NAME, QSettings::IniFormat); + m_localeChanged = false; + m_qSettings->beginGroup(LOCALE_NAME_VALUE); + QString lastLocale = m_qSettings->value(LOCALE_NAME_VALUE).toString(); + if (QLocale::system().name().compare(lastLocale)) { + qDebug() << "I'm going to update the locale name in conf file."; + if (!lastLocale.isEmpty()) { + m_localeChanged = true; } - } else { - qWarning() << "Failed to start transaction mode!!!"; + m_qSettings->setValue(LOCALE_NAME_VALUE, QLocale::system().name()); } - }); + m_qSettings->endGroup(); + + //初始化数据库 + initDataBase(); + + //初始化FileSystemWatcher + 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); + + //监听desktop文件所在目录,TODO:directoryChange会发多次信号,需要计时器阻塞 + connect(m_watchAppDir, &QFileSystemWatcher::directoryChanged, this, [ = ](const QString & path) { + qDebug() << "m_watchAppDir directoryChanged:" << path; + if (m_database.transaction()) { +// this->updateAppInfoDB(); + this->updateAllData2DB(); + if (!m_database.commit()) { + qWarning() << "Failed to commit !"; + m_database.rollback(); + } + } else { + qWarning() << "Failed to start transaction mode!!!"; + } + }); + + //监控应用进程开启 + connect(KWindowSystem::self(), &KWindowSystem::windowAdded, [ = ](WId id) { + QString desktopfp = ConvertWinidToDesktop::getConverter().tranIdToDesktop(id); + if (!desktopfp.isEmpty()) { + AppDBManager::getInstance()->updateAppLaunchTimes(desktopfp); + } + }); + } else { + qDebug() << "App-db-manager does nothing."; + } } AppDBManager::~AppDBManager() @@ -62,8 +100,8 @@ AppDBManager::~AppDBManager() 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)") + 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, %21)") // .arg("ID INT")//自增id .arg("DESKTOP_FILE_PATH TEXT")//desktop文件路径 .arg("MODIFYED_TIME TEXT")//YYYYMMDDHHmmSS 修改日期 @@ -73,6 +111,7 @@ void AppDBManager::buildAppInfoDB() .arg("NAME_ZH TEXT")//应用中文名称 .arg("PINYIN_NAME TEXT")//中文拼音 .arg("FIRST_LETTER_OF_PINYIN TEXT")//中文拼音首字母 + .arg("FIRST_LETTER_ALL")//中英文首字母(只包含一个,目前方案取拼音首字母的第一项,由于模糊拼音算法可能出问题) .arg("ICON TEXT")//图标名称(或路径) .arg("TYPE TEXT")//应用类型 .arg("CATEGORY TEXT")//应用分类 @@ -87,7 +126,7 @@ void AppDBManager::buildAppInfoDB() .arg("PRIMARY KEY (DESKTOP_FILE_PATH)"); if (!sql.exec(cmd)) { - qWarning() << m_database->lastError() << cmd; + qWarning() << m_database.lastError() << cmd; return; } } @@ -101,28 +140,28 @@ void AppDBManager::updateAppInfoDB() this->getAllDesktopFilePath(SNAPD_APP_DESKTOP_PATH); QStringList filePathList; this->getFilePathList(filePathList); - QSqlQuery sql(*m_database); - QString cmd; - if (!sql.exec("SELECT COUNT(*) FROM appInfo")) { + QSqlQuery sql(m_database); + QString cmd = "SELECT COUNT(*) FROM appInfo"; + if (!sql.exec(cmd)) { 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; + qWarning() << m_database.lastError() << cmd; return; } QString path; for (int i = 0; ilastError() << cmd; + qWarning() << m_database.lastError() << cmd; return; } path = sql.value(0).toString(); @@ -132,7 +171,8 @@ void AppDBManager::updateAppInfoDB() } } } - for (QString &filePath:filePathList) { + //添加新增项,根据md5判断desktop文件是否改变以更新对应项 + for (QString &filePath : filePathList) { cmd = QString("SELECT COUNT(*) FROM appInfo WHERE DESKTOP_FILE_PATH = '%0'").arg(filePath); if (sql.exec(cmd)) { if (sql.next()) { @@ -141,11 +181,11 @@ void AppDBManager::updateAppInfoDB() } else { cmd = QString("SELECT MD5 FROM appInfo WHERE DESKTOP_FILE_PATH = '%0'").arg(filePath); if (!sql.exec(cmd)) { - qWarning() << m_database->lastError() << cmd; + qWarning() << m_database.lastError() << cmd; return; } if (!sql.next()) { - qWarning() << m_database->lastError() << cmd; + qWarning() << m_database.lastError() << cmd; return; } if (sql.value(0).toString() != getAppDesktopMd5(filePath)) { @@ -153,20 +193,20 @@ void AppDBManager::updateAppInfoDB() } } } else { - qWarning() << m_database->lastError() << cmd; + qWarning() << m_database.lastError() << cmd; return; } } else { - qWarning() << m_database->lastError() << cmd; + qWarning() << m_database.lastError() << cmd; return; } } } else { - qWarning() << m_database->lastError() << cmd; + qWarning() << m_database.lastError() << cmd; return; } } else { - qWarning() << m_database->lastError() << cmd; + qWarning() << m_database.lastError() << cmd; return; } } @@ -246,41 +286,172 @@ void AppDBManager::getAllDesktopFilePath(QString path) { } } -void AppDBManager::initDateBaseConnection() +void AppDBManager::loadDesktopFilePaths(QString path, QFileInfoList &infolist) { - if (m_database->transaction()) { - this->updateAppInfoDB(); - if (!m_database->commit()) { + QDir dir(path); + dir.setSorting(QDir::DirsFirst); + dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); + infolist.append(dir.entryInfoList()); +} + +void AppDBManager::updateAllData2DB() +{ + bool firstExec = false; + QSqlQuery sql(m_database); + QString cmd = "SELECT DESKTOP_FILE_PATH,MD5 FROM appInfo"; + QMap dataMap; + if (!sql.exec(cmd)) { + qDebug() << "Fail to read database, because: " << m_database.lastError(); + this->buildAppInfoDB(); + firstExec = true; + } else { + sql.exec(cmd); + while (sql.next()) { + dataMap.insert(sql.value("DESKTOP_FILE_PATH").toString(), sql.value("MD5").toString()); + } + } + + //遍历desktop文件 + QFileInfoList infos; + this->loadDesktopFilePaths(GENERAL_APP_DESKTOP_PATH, infos); + this->loadDesktopFilePaths(ANDROID_APP_DESKTOP_PATH, infos); + this->loadDesktopFilePaths(SNAPD_APP_DESKTOP_PATH, infos); + if(infos.size() < 1) { + return; + } + XdgDesktopFile desktopfile; + for (int i = 0; i < infos.length(); i++) { + QFileInfo fileInfo = infos.at(i); + QString path = fileInfo.filePath(); + //对目录递归 + if (fileInfo.isDir()) { + loadDesktopFilePaths(path, infos); + continue; + } + //排除非法路径(黑名单 + 非desktop文件) + if (m_excludedDesktopfiles.contains(path) or !path.endsWith(".desktop")) { + continue; + } + + desktopfile.load(path); + //排除NoDisplay和NotShowIn字段,排除loaclized名字为空 + if (desktopfile.value("NoDisplay").toString().contains("true") or + desktopfile.value("NotShowIn").toString().contains("UKUI") or + desktopfile.localizedValue("Name").toString().isEmpty()) { + continue; + } + + if (!firstExec) { + //数据库有记录 + if (dataMap.contains(path)) { + if (!QString::compare(dataMap.value(path), getAppDesktopMd5(path))) { + //判断系统语言是否改变 + if (m_localeChanged) { + this->updateLocaleData2DB(path); + } + dataMap.remove(path); + continue; + } else { + //数据库有记录但md5值改变则update + this->updateAppDesktopFile2DB(path); + dataMap.remove(path); + continue; + } + } else { + //数据库中没有记录则insert + this->addAppDesktopFile2DB(path); + dataMap.remove(path); + continue; + } + } + //数据库为空则全部insert + this->addAppDesktopFile2DB(path); + dataMap.remove(path); + } + + //遍历完成后重置标志位 + m_localeChanged = false; + + //数据库冗余项直接delete + if (!dataMap.isEmpty()) { + for (auto i = dataMap.constBegin(); i != dataMap.constEnd(); i++) { + this->deleteAppDesktopFile2DB(i.key()); + } + } +} + +bool AppDBManager::updateLocaleData2DB(QString desktopPath) +{ + bool res(true); + XdgDesktopFile desktopFile; + desktopFile.load(desktopPath); + QString localName = desktopFile.localizedValue("Name", "NULL").toString(); + QString firstLetter2All = localName; + + if (localName.contains(QRegExp("[\\x4e00-\\x9fa5]+"))) { + firstLetter2All = FileUtils::findMultiToneWords(localName).at(0); + } + + + QSqlQuery sql(m_database); + QString cmd = QString("UPDATE appInfo SET " + "LOCAL_NAME = '%0', FIRST_LETTER_ALL = '%1'" + "WHERE DESKTOP_FILE_PATH='%2'") + .arg(localName) + .arg(firstLetter2All) + .arg(desktopPath); + + if (!sql.exec(cmd)) { + qWarning() << m_database.lastError() << cmd; + res = false; + } + if (res) { + qDebug() << "Already to update the locale app-data of " << desktopPath; + } else { + qDebug() << "Fail to update the locale app-data of " << desktopPath; + } + return res; +} + +void AppDBManager::initDataBase() +{ + if (m_database.transaction()) { +// this->updateAppInfoDB(); + this->updateAllData2DB(); + if (!m_database.commit()) { qWarning() << "Failed to commit !"; - m_database->rollback(); + m_database.rollback(); } } else { qWarning() << "Failed to start transaction mode!!!"; } } -void AppDBManager::openDataBase() +bool AppDBManager::openDataBase() { + bool res(true); + QDir dir; if (!dir.exists(APP_DATABASE_PATH)) { dir.mkpath(APP_DATABASE_PATH); } if (QSqlDatabase::contains(CONNECTION_NAME)) { - *m_database = QSqlDatabase::database(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); + 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(); + if(!m_database.open()) { + qWarning() << "Fail to open AppDataBase, because" << m_database.lastError(); + res = false; } + return res; } void AppDBManager::closeDataBase() { - m_database->close(); - delete m_database; + m_database.close(); +// delete m_database; QSqlDatabase::removeDatabase(CONNECTION_NAME); } @@ -306,11 +477,18 @@ void AppDBManager::getInstallAppMap(QMap &installAppMap) bool AppDBManager::addAppDesktopFile2DB(QString &desktopfd) { bool res(true); - QSqlQuery sql(*m_database); + QSqlQuery sql(m_database); XdgDesktopFile desktopfile; desktopfile.load(desktopfd); QString hanzi, pinyin, firstLetterOfPinyin; + QString localName = desktopfile.localizedValue("Name", "NULL").toString(); + QString firstLtter2All = localName; bool isHanzi = true; + + if (localName.contains(QRegExp("[\\x4e00-\\x9fa5]+"))) { + firstLtter2All = FileUtils::findMultiToneWords(localName).at(0); + } + if (desktopfile.contains("Name[zh_CN]")) { hanzi = desktopfile.value("Name[zh_CN]").toString(); } else { @@ -319,10 +497,11 @@ bool AppDBManager::addAppDesktopFile2DB(QString &desktopfd) isHanzi = false; } } + if (isHanzi) { QStringList pinyinList = FileUtils::findMultiToneWords(hanzi); for (int i = 0; ilastError() << cmd; + qWarning() << m_database.lastError() << cmd; res = false; } if (res) { @@ -364,13 +548,13 @@ bool AppDBManager::addAppDesktopFile2DB(QString &desktopfd) return res; } -bool AppDBManager::deleteAppDesktopFile2DB(QString &desktopfd) +bool AppDBManager::deleteAppDesktopFile2DB(const QString &desktopfd) { bool res(true); - QSqlQuery sql(*m_database); + 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; + qWarning() << m_database.lastError() << cmd; res = false; } if (res) { @@ -391,7 +575,14 @@ bool AppDBManager::updateAppDesktopFile2DB(QString &desktopfd) return this->deleteAppDesktopFile2DB(desktopfd); } QString hanzi, pinyin, firstLetterOfPinyin; + QString localName = desktopfile.localizedValue("Name", "NULL").toString(); + QString firstLetter2All = localName; bool isHanzi = true; + + if (localName.contains(QRegExp("[\\x4e00-\\x9fa5]+"))) { + firstLetter2All = FileUtils::findMultiToneWords(localName).at(0); + } + if (desktopfile.contains("Name[zh_CN]")) { hanzi = desktopfile.value("Name[zh_CN]").toString(); } else { @@ -400,17 +591,20 @@ bool AppDBManager::updateAppDesktopFile2DB(QString &desktopfd) isHanzi = false; } } + if (isHanzi) { QStringList pinyinList = FileUtils::findMultiToneWords(hanzi); + firstLetter2All = pinyinList.at(0); for (int i = 0; ilastError() << cmd; + qWarning() << m_database.lastError() << cmd; res = false; } if (res) { @@ -453,8 +649,8 @@ bool AppDBManager::updateAppDesktopFile2DB(QString &desktopfd) bool AppDBManager::updateAppLaunchTimes(QString &desktopfp) { bool res(true); - if (m_database->transaction()) { - QSqlQuery sql(*m_database); + 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()) { @@ -464,7 +660,7 @@ bool AppDBManager::updateAppLaunchTimes(QString &desktopfp) .arg(1) .arg(desktopfp); if (!sql.exec(cmd)) { - qWarning() << "Set app favorites state failed!" << m_database->lastError(); + qWarning() << "Set app favorites state failed!" << m_database.lastError(); res = false; } } else { @@ -475,9 +671,9 @@ bool AppDBManager::updateAppLaunchTimes(QString &desktopfp) qWarning() << "Failed to exec:" << cmd; res = false; } - if (!m_database->commit()) { + if (!m_database.commit()) { qWarning() << "Failed to commit !" << cmd; - m_database->rollback(); + m_database.rollback(); res = false; } } else { diff --git a/ukui-search-app-data-service/app-db-manager.h b/ukui-search-app-data-service/app-db-manager.h index 9b7be42..604c81c 100644 --- a/ukui-search-app-data-service/app-db-manager.h +++ b/ukui-search-app-data-service/app-db-manager.h @@ -11,6 +11,7 @@ #include #include #include +#include #include "app-db-common-defines.h" #define CONNECTION_NAME QLatin1String("ukss-appdb-connection") @@ -51,25 +52,31 @@ public: void getInstallAppMap(QMap &installAppMap); bool addAppDesktopFile2DB(QString &desktopfd); - bool deleteAppDesktopFile2DB(QString &desktopfd); + bool deleteAppDesktopFile2DB(const QString &desktopfd); bool updateAppDesktopFile2DB(QString &desktopfd); bool updateAppLaunchTimes(QString &desktopfp); + void updateAllData2DB(); + bool updateLocaleData2DB(QString desktopPath); private: explicit AppDBManager(QObject *parent = nullptr); ~AppDBManager(); - void getAllDesktopFilePath(QString path); + void loadDesktopFilePaths(QString path, QFileInfoList &infolist); - void initDateBaseConnection(); - void openDataBase(); + void initDataBase(); + bool openDataBase(); void closeDataBase(); void buildAppInfoDB(); void updateAppInfoDB(); + void getAllDesktopFilePath(QString path); void getFilePathList(QStringList &pathList); - QSqlDatabase *m_database = nullptr; + QSettings *m_qSettings = nullptr; + bool m_localeChanged; + + QSqlDatabase m_database; QFileSystemWatcher *m_watchAppDir = nullptr; @@ -119,6 +126,9 @@ private: "/usr/share/applications/openjdk-8-policytool.desktop", "/usr/share/applications/kylin-io-monitor.desktop", "/usr/share/applications/wps-office-uninstall.desktop", + + //原本额外排除的目录,不知道额外的原因,有可能之后有问题--bjj20220621 + "/usr/share/applications/screensavers" }; }; diff --git a/ukui-search-app-data-service/convert-winid-to-desktop.cpp b/ukui-search-app-data-service/convert-winid-to-desktop.cpp index 6914844..6bf8b10 100755 --- a/ukui-search-app-data-service/convert-winid-to-desktop.cpp +++ b/ukui-search-app-data-service/convert-winid-to-desktop.cpp @@ -26,6 +26,12 @@ ConvertWinidToDesktop::ConvertWinidToDesktop(QObject *parent) : QObject(parent) { } +ConvertWinidToDesktop &ConvertWinidToDesktop::getConverter() +{ + static ConvertWinidToDesktop instance; + return instance; +} + QString ConvertWinidToDesktop::tranIdToDesktop(WId id) { KWindowInfo info(id, 0, NET::WM2AllProperties); diff --git a/ukui-search-app-data-service/convert-winid-to-desktop.h b/ukui-search-app-data-service/convert-winid-to-desktop.h index ba6a77f..5cb964c 100755 --- a/ukui-search-app-data-service/convert-winid-to-desktop.h +++ b/ukui-search-app-data-service/convert-winid-to-desktop.h @@ -47,12 +47,16 @@ class ConvertWinidToDesktop : public QObject { Q_OBJECT public: - explicit ConvertWinidToDesktop(QObject *parent = nullptr); - ~ConvertWinidToDesktop(); + static ConvertWinidToDesktop &getConverter(); QString tranIdToDesktop(WId id); private: + explicit ConvertWinidToDesktop(QObject *parent = nullptr); + ConvertWinidToDesktop(const ConvertWinidToDesktop&) = delete; + ConvertWinidToDesktop& operator =(const ConvertWinidToDesktop&) = delete; + ~ConvertWinidToDesktop(); + QString m_classClass = nullptr; QString m_className = nullptr; QString m_statusName = nullptr; diff --git a/ukui-search-app-data-service/main.cpp b/ukui-search-app-data-service/main.cpp index 5bed375..ca8eff3 100644 --- a/ukui-search-app-data-service/main.cpp +++ b/ukui-search-app-data-service/main.cpp @@ -59,9 +59,9 @@ int main(int argc, char *argv[]) #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()) + UkuiSearchAppDataService appDB(argc, argv, "ukui-search-app-data-service"); + if (appDB.isRunning()) { return 0; - - return ukss.exec(); + } + return appDB.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 index f483fe4..176d061 100644 --- a/ukui-search-app-data-service/ukui-search-app-data-service.cpp +++ b/ukui-search-app-data-service/ukui-search-app-data-service.cpp @@ -1,35 +1,30 @@ #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"; + 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) { + qDebug() << "First running"; + AppDBManager::getInstance(); + + 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"; + qDebug() << "parse cmd"; auto message = this->arguments().join(' ').toUtf8(); parseCmd(message, !isRunning()); - qDebug()<<"ukui search app data service constructor end"; + qDebug() << "ukui search app data service constructor end"; } void UkuiSearchAppDataService::parseCmd(QString msg, bool isPrimary) 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 bc4ff76..3a51d34 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 sql xml KWindowSystem +QT += core gui dbus sql KWindowSystem greaterThan(QT_MAJOR_VERSION, 4): QT += widgets @@ -6,8 +6,7 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = ukui-search-app-data-service VERSION = 1.0.0 DEFINES += VERSION='\\"$${VERSION}\\"' -CONFIG += c++11 link_pkgconfig no_keywords lrelease -PKGCONFIG += glib-2.0 gio-unix-2.0 gio-2.0 poppler-qt5 +CONFIG += c++11 no_keywords # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings @@ -24,23 +23,19 @@ QMAKE_CXXFLAGS += -Werror=return-type -Werror=return-local-addr -Werror=uninitia #include(../libsearch/appdata/appdata.pri) include(../3rd-parties/qtsingleapplication/qtsingleapplication.pri) -LIBS += -lQt5Xdg -lquazip5 -luchardet -ltesseract +LIBS += -lQt5Xdg 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 target.path = /usr/bin INSTALLS += target @@ -52,3 +47,7 @@ INSTALLS += desktop LIBS += -L$$OUT_PWD/../libchinese-segmentation/ -lchinese-segmentation INCLUDEPATH += $$PWD/../libchinese-segmentation DEPENDPATH += $$PWD/../libchinese-segmentation + +LIBS += -L$$OUT_PWD/../libsearch/ -lukui-search +INCLUDEPATH += $$PWD/../libsearch +DEPENDPATH += $$PWD/../libsearch diff --git a/ukui-search-service-dir-manager/dirwatcher/dir-watcher.h b/ukui-search-service-dir-manager/dirwatcher/dir-watcher.h index f06b050..ffe6016 100644 --- a/ukui-search-service-dir-manager/dirwatcher/dir-watcher.h +++ b/ukui-search-service-dir-manager/dirwatcher/dir-watcher.h @@ -58,8 +58,6 @@ private: void initDiskWatcher(); void handleDisk(); - void handleAddedUDiskDevice(QDBusMessage msg); - void handleRemovedUDiskDevice(QDBusMessage msg); void handleIndexItemAppend(const QString &path, QStringList &blackList); void handleIndexItemRemove(const QString &path); @@ -86,6 +84,11 @@ private: QStringList m_currentUDiskDeviceList; QString m_removedUDiskDevice; QMap m_currentUDiskDeviceInfo; + +private Q_SLOTS: + void handleAddedUDiskDevice(QDBusMessage msg); + void handleRemovedUDiskDevice(QDBusMessage msg); + Q_SIGNALS: void udiskRemoved(); void appendIndexItem(const QString&, const QStringList&);