diff --git a/ukui-search-app-data-service/app-db-manager.cpp b/ukui-search-app-data-service/app-db-manager.cpp index 09be3bb..adb62c8 100644 --- a/ukui-search-app-data-service/app-db-manager.cpp +++ b/ukui-search-app-data-service/app-db-manager.cpp @@ -33,6 +33,9 @@ AppDBManager::AppDBManager(QObject *parent) : QThread(parent), m_database(QSqlDa { //链接数据库 if (openDataBase()) { + //建数据库 + buildAppInfoDB(); + //监听系统语言变化 m_lastLocaleNameQsettings = new QSettings(LAST_LOCALE_NAME, QSettings::IniFormat); m_localeChanged = false; @@ -66,7 +69,14 @@ AppDBManager::AppDBManager(QObject *parent) : QThread(parent), m_database(QSqlDa qDebug() << "app db version need update! old version:" << dbVersion.toDouble() << "new version:" << APP_DATABASE_VERSION.toDouble(); } - //初始化数据库 + //版本号改变更新数据库字段 + if (m_dbVersionNeedUpdate) { + for (auto iter = m_namesOfAppinfoTable.constBegin(); iter!= m_namesOfAppinfoTable.constEnd(); iter++) { + this->addItem2BackIfNotExist(iter.key(), iter.value()); + } + } + + //刷新应用数据 QStringList appPaths; appPaths << GENERAL_APP_DESKTOP_PATH << ANDROID_APP_DESKTOP_PATH << SNAPD_APP_DESKTOP_PATH << AUTOSTART_APP_DESKTOP_PATH; @@ -80,107 +90,7 @@ AppDBManager::AppDBManager(QObject *parent) : QThread(parent), m_database(QSqlDa } //初始化FileSystemWatcher - m_watcher = new FileSystemWatcher; - m_watcher->addWatch(GENERAL_APP_DESKTOP_PATH); - QDir androidDir(ANDROID_APP_DESKTOP_PATH); - if(!androidDir.exists()) { - androidDir.mkpath(ANDROID_APP_DESKTOP_PATH); - } - m_watcher->addWatch(ANDROID_APP_DESKTOP_PATH); - - m_snapdDir = new QDir(SNAPD_APP_DESKTOP_PATH); - if(!m_snapdDir->exists()) { - m_snapdWatcher = new FileSystemWatcher(false); - QDir dir("/var/lib/snapd"); - if (!dir.exists()) { - dir.setPath("/var/lib"); - } - m_snapdPath = dir.absolutePath(); - m_snapdWatcher->addWatch(m_snapdPath); - } else { - m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH); - } - - m_watcher->addWatch(AUTOSTART_APP_DESKTOP_PATH); - - connect(m_snapdWatcher, &FileSystemWatcher::created, this, [ = ] (const QString &path, bool isDir) { - if (isDir) { - //监测新增目录为/var/lib/snapd时,将其替换为snapdWatcher的watchpath - if (path == "/var/lib/snapd") { - m_snapdWatcher->removeWatch(m_snapdPath); - m_snapdWatcher->addWatch(path); - qDebug() << "~~~~~~~add watch" << path << "~~~~~remove watch" << m_snapdPath; - m_snapdPath = path; - //snapd下的desktop目录可能在还没替换监听目录为/var/lib/snapd时就已经被创建,因此需要特别判断 - QDir dir("/var/lib/snapd/desktop"); - if (dir.exists()) { - if (m_snapdDir->exists()) { - m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH); - m_snapdWatcher->removeWatch(m_snapdPath); - qDebug() << "======add watch" << SNAPD_APP_DESKTOP_PATH << "======remove watch" << m_snapdPath; - } - } - } - //检测到/var/lib/snapd/desktop被创建,则将监听目录替换为/var/lib/snapd/desktop/applications - if (path == "/var/lib/snapd/desktop" and m_snapdDir->exists()) { - m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH); - m_snapdWatcher->removeWatch(m_snapdPath); - qDebug() << "======add watch" << SNAPD_APP_DESKTOP_PATH << "======remove watch" << m_snapdPath; - } - - } - }); - - connect(m_watcher, &FileSystemWatcher::created, this, [ = ] (const QString &desktopfp, bool isDir) { - //event is IN_CREATE - if (!isDir and desktopfp.endsWith(".desktop")) { - QStringList appPaths(desktopfp.left(desktopfp.lastIndexOf("/"))); - this->refreshAllData2DB(appPaths); - } - }); - - connect(m_watcher, &FileSystemWatcher::moveTo, this, [ = ] (const QString &desktopfp, bool isDir) { - //event is IN_MOVED_TO - if (!isDir and desktopfp.endsWith(".desktop")) { - this->insertDBItem(desktopfp); - } - }); - - connect(m_watcher, &FileSystemWatcher::modified, this, [ = ] (const QString &desktopfp) { - //event is IN_MODIFY - if (desktopfp.endsWith(".desktop")) { - this->updateDBItem(desktopfp); - } - }); - - connect(m_watcher, &FileSystemWatcher::moved, this, [ = ] (const QString &desktopfp, bool isDir) { - //event is IN_MOVED_FROM - if (!isDir) { - if (desktopfp.endsWith(".desktop")) { - this->deleteDBItem(desktopfp); - } - } else { - //event is IN_MOVE_SELF - qWarning() << "Dir:" << desktopfp << "has been moved to other place! Stop the watching of the desktop files in it!"; - } - }); - - connect(m_watcher, &FileSystemWatcher::deleted, this, [ = ] (const QString &desktopfp, bool isDir) { - //event is IN_DELETE - if (!isDir) { - if (desktopfp.endsWith(".desktop")) { - this->deleteDBItem(desktopfp); - } - } else { - //event is IN_DELETE_SELF - qWarning() << "Dir:" << desktopfp << "has been deleted! Stop the watching of the desktop files in it!"; - } - }); - - connect(m_watcher, &FileSystemWatcher::unmounted, this, [ = ] (const QString &desktopfp) { - //event is IN_UNMOUNT - qWarning() << "Dir:" << desktopfp << "has been unmounted! Stop the watching of the desktop files in it!"; - }); + initFileSystemWatcher(); /* //初始化FileSystemWatcher @@ -307,6 +217,106 @@ void AppDBManager::buildAppInfoDB() } } +void AppDBManager::initFileSystemWatcher() +{ + m_watcher = new FileSystemWatcher; + m_watcher->addWatch(GENERAL_APP_DESKTOP_PATH); + QDir androidDir(ANDROID_APP_DESKTOP_PATH); + if(!androidDir.exists()) { + androidDir.mkpath(ANDROID_APP_DESKTOP_PATH); + } + m_watcher->addWatch(ANDROID_APP_DESKTOP_PATH); + + m_snapdDir = new QDir(SNAPD_APP_DESKTOP_PATH); + if(!m_snapdDir->exists()) { + m_snapdWatcher = new FileSystemWatcher(false); + QDir dir("/var/lib/snapd"); + if (!dir.exists()) { + dir.setPath("/var/lib"); + } + m_snapdPath = dir.absolutePath(); + m_snapdWatcher->addWatch(m_snapdPath); + } else { + m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH); + } + + m_watcher->addWatch(AUTOSTART_APP_DESKTOP_PATH); + + connect(m_snapdWatcher, &FileSystemWatcher::created, this, [ = ] (const QString &path, bool isDir) { + if (isDir) { + //监测新增目录为/var/lib/snapd时,将其替换为snapdWatcher的watchpath + if (path == "/var/lib/snapd") { + m_snapdWatcher->removeWatch(m_snapdPath); + m_snapdWatcher->addWatch(path); + qDebug() << "~~~~~~~add watch" << path << "~~~~~remove watch" << m_snapdPath; + m_snapdPath = path; + //snapd下的desktop目录可能在还没替换监听目录为/var/lib/snapd时就已经被创建,因此需要特别判断 + QDir dir("/var/lib/snapd/desktop"); + if (dir.exists()) { + if (m_snapdDir->exists()) { + m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH); + m_snapdWatcher->removeWatch(m_snapdPath); + qDebug() << "======add watch" << SNAPD_APP_DESKTOP_PATH << "======remove watch" << m_snapdPath; + } + } + } + //检测到/var/lib/snapd/desktop被创建,则将监听目录替换为/var/lib/snapd/desktop/applications + if (path == "/var/lib/snapd/desktop" and m_snapdDir->exists()) { + m_watcher->addWatch(SNAPD_APP_DESKTOP_PATH); + m_snapdWatcher->removeWatch(m_snapdPath); + qDebug() << "======add watch" << SNAPD_APP_DESKTOP_PATH << "======remove watch" << m_snapdPath; + } + + } + }); + + connect(m_watcher, &FileSystemWatcher::created, this, [ = ] (const QString &desktopfp, bool isDir) { + //event is IN_CREATE + if (!isDir and desktopfp.endsWith(".desktop")) { + this->insertDBItem(desktopfp); + } + }); + + connect(m_watcher, &FileSystemWatcher::moveTo, this, [ = ] (const QString &desktopfp, bool isDir) { + //event is IN_MOVED_TO + if (!isDir and desktopfp.endsWith(".desktop")) { + QStringList appPaths(desktopfp.left(desktopfp.lastIndexOf("/"))); + this->refreshAllData2DB(appPaths); + } + }); + + connect(m_watcher, &FileSystemWatcher::modified, this, [ = ] (const QString &desktopfp) { + //event is IN_MODIFY + if (desktopfp.endsWith(".desktop")) { + this->updateDBItem(desktopfp); + } + }); + + connect(m_watcher, &FileSystemWatcher::moved, this, [ = ] (const QString &desktopfp, bool isDir) { + //event is IN_MOVED_FROM + if (!isDir) { + if (desktopfp.endsWith(".desktop")) { + this->deleteDBItem(desktopfp); + } + } else { + //event is IN_MOVE_SELF + qWarning() << "Dir:" << desktopfp << "has been moved to other place! Stop the watching of the desktop files in it!"; + } + }); + + connect(m_watcher, &FileSystemWatcher::deleted, this, [ = ] (const QString &desktopfp, bool isDir) { + //event is IN_DELETE + if (!isDir) { + if (desktopfp.endsWith(".desktop")) { + this->deleteDBItem(desktopfp); + } + } else { + //event is IN_DELETE_SELF + qWarning() << "Dir:" << desktopfp << "has been deleted! Stop the watching of the desktop files in it!"; + } + }); +} + void AppDBManager::loadDesktopFilePaths(QString path, QFileInfoList &infolist) { QDir dir(path); @@ -331,8 +341,8 @@ bool AppDBManager::addItem2BackIfNotExist(QString itemName, QString itemDataType return res; } - cmd = QString("ALTER TABLE appInfo ADD '%0' '%1' ").arg(itemName) - .arg(itemDataType); + cmd = QString("ALTER TABLE appInfo ADD '%0' %1 ").arg(itemName) + .arg(itemDataType); if (defult != QVariant()) { //TODO 根据数据类型将初始值转化为对应格式数据 if (itemDataType == "INT(4)") { @@ -355,98 +365,10 @@ bool AppDBManager::addItem2BackIfNotExist(QString itemName, QString itemDataType void AppDBManager::refreshAllData2DB(const QStringList &appPaths) { - //版本号改变更新数据库字段 - if (m_dbVersionNeedUpdate) { - for (auto iter = m_namesOfAppinfoTable.constBegin(); iter!= m_namesOfAppinfoTable.constEnd(); iter++) { - this->addItem2BackIfNotExist(iter.key(), iter.value()); - } - } - - bool firstExec = false; - QSqlQuery sql(m_database); - sql.setForwardOnly(true); - 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; - for (const QString &path : appPaths) { - this->loadDesktopFilePaths(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)) - and !m_dbVersionNeedUpdate) { - //判断系统语言是否改变 - if (m_localeChanged) { - this->updateLocaleData(path); - } - dataMap.remove(path); - continue; - } else { - //数据库有记录但md5值改变或数据库版本需要更新则update - this->updateDBItem(path); - dataMap.remove(path); - continue; - } - } else { - //数据库中没有记录则insert - this->insertDBItem(path); - dataMap.remove(path); - continue; - } - } - //数据库为空则全部insert - this->insertDBItem(path); - dataMap.remove(path); - } - - //遍历完成后重置标志位 - m_localeChanged = false; - - //数据库冗余项直接delete - if (!dataMap.isEmpty()) { - for (auto i = dataMap.constBegin(); i != dataMap.constEnd(); i++) { - this->deleteDBItem(i.key()); - } - } + PendingAppInfo items; + items.setHandleType(PendingAppInfo::RefreshDataBase); + items.setPathsNeedRefreshData(appPaths); + PendingAppInfoQueue::getAppInfoQueue().enqueue(items); } bool AppDBManager::handleLocaleDataUpdate(const QString &desktopFilePath) @@ -947,6 +869,98 @@ bool AppDBManager::handleLockStateUpdate(const QString &desktopFilePath, int num return res; } +void AppDBManager::handleDataBaseRefresh(const QStringList &appPaths) +{ + QMap dataMap; + QSqlQuery query(m_database); + query.setForwardOnly(true); + QString condition; + for (int i = 0; i < appPaths.size(); i++) { + condition.append("DESKTOP_FILE_PATH LIKE ? OR "); + } + condition = condition.left(condition.lastIndexOf(" OR ")); + query.prepare(QString("SELECT DESKTOP_FILE_PATH,MD5 FROM APPINFO WHERE %0").arg(condition)); + for (int t = 0; t < appPaths.size(); t++) { + query.bindValue(t, appPaths.at(t) + "/%"); + } + + if (!query.exec()) { + qWarning() << m_database.lastError() << query.lastError(); + } else { + query.exec(); + while (query.next()) { + dataMap.insert(query.value("DESKTOP_FILE_PATH").toString(), query.value("MD5").toString()); + } + } + + //遍历desktop文件 + QFileInfoList infos; + for (const QString &path : appPaths) { + this->loadDesktopFilePaths(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 (!path.endsWith(".desktop")) { + continue; + } + + desktopfile.load(path); + //排除loaclized名字为空 + if (desktopfile.localizedValue("Name").toString().isEmpty()) { + continue; + } + + if (!dataMap.isEmpty()) { + //数据库有记录 + if (dataMap.contains(path)) { + if (!QString::compare(dataMap.value(path), getAppDesktopMd5(path)) && !m_dbVersionNeedUpdate) { + //判断系统语言是否改变 + if (m_localeChanged) { + this->handleLocaleDataUpdate(path); + } + dataMap.remove(path); + continue; + } else { + //数据库有记录但md5值改变或数据库版本需要更新则update + this->handleDBItemUpdate(path); + dataMap.remove(path); + continue; + } + } else { + //数据库中没有记录则insert + this->handleDBItemInsert(path); + dataMap.remove(path); + continue; + } + } + //数据库为空则全部insert + this->handleDBItemInsert(path); + dataMap.remove(path); + } + + //遍历完成后重置标志位 + m_localeChanged = false; + + //数据库冗余项直接delete + if (!dataMap.isEmpty()) { + for (auto i = dataMap.constBegin(); i != dataMap.constEnd(); i++) { + this->handleDBItemDelete(i.key()); + } + } +} + QString AppDBManager::tranPidToDesktopFp(int pid) { QString exePath = QFile::symLinkTarget("/proc/" + QString::number(pid) + "/exe"); diff --git a/ukui-search-app-data-service/app-db-manager.h b/ukui-search-app-data-service/app-db-manager.h index 68e314b..751616f 100644 --- a/ukui-search-app-data-service/app-db-manager.h +++ b/ukui-search-app-data-service/app-db-manager.h @@ -59,6 +59,7 @@ public: bool handleFavoritesStateUpdate(const QString &desktopFilePath, int num, bool isOrderChanged = false); bool handleTopStateUpdate(const QString &desktopFilePath, int num, bool isOrderChanged = false); bool handleLockStateUpdate(const QString &desktopFilePath, int num); + void handleDataBaseRefresh(const QStringList &appPaths); public Q_SLOTS: //通过pid查找对应的desktop文件 @@ -103,6 +104,9 @@ private: //创建数据库字段 void buildAppInfoDB(); + //初始化fileSystemWatcher + void initFileSystemWatcher(); + private: static QMutex s_mutex; bool m_localeChanged; diff --git a/ukui-search-app-data-service/pending-app-info-queue.cpp b/ukui-search-app-data-service/pending-app-info-queue.cpp index 5b5d63c..d3b2110 100644 --- a/ukui-search-app-data-service/pending-app-info-queue.cpp +++ b/ukui-search-app-data-service/pending-app-info-queue.cpp @@ -19,6 +19,10 @@ void PendingAppInfoQueue::enqueue(const PendingAppInfo &appInfo) if (index == -1) { m_cache << appInfo; } else { + //刷新数据库操作直接插入 + if (appInfo.handleType() == PendingAppInfo::RefreshDataBase) { + m_cache << appInfo; + } //要插入项操作类型为删除,清除之前所有操作,替换为删除 if (appInfo.handleType() == PendingAppInfo::Delete) { m_cache.removeAll(appInfo); @@ -127,7 +131,7 @@ void PendingAppInfoQueue::processCache() if (AppDBManager::getInstance()->startTransaction()) { for (const PendingAppInfo &info : m_pendingAppInfos) { PendingAppInfo::HandleTypes handleTypes = info.handleType(); - if (handleTypes <= PendingAppInfo::UpdateLocaleData) { + if (handleTypes <= PendingAppInfo::UpdateLocaleData || handleTypes == PendingAppInfo::RefreshDataBase) { switch (handleTypes) { case PendingAppInfo::Delete: AppDBManager::getInstance()->handleDBItemDelete(info.path()); @@ -141,6 +145,9 @@ void PendingAppInfoQueue::processCache() case PendingAppInfo::UpdateLocaleData: AppDBManager::getInstance()->handleLocaleDataUpdate(info.path()); break; + case PendingAppInfo::RefreshDataBase: + AppDBManager::getInstance()->handleDataBaseRefresh(info.pathsNeedRefreshData()); + break; default: break; } diff --git a/ukui-search-app-data-service/pending-app-info.h b/ukui-search-app-data-service/pending-app-info.h index 653580f..4dc7100 100644 --- a/ukui-search-app-data-service/pending-app-info.h +++ b/ukui-search-app-data-service/pending-app-info.h @@ -2,6 +2,7 @@ #define PENDINGAPPINFO_H #include +#include #include namespace UkuiSearch { @@ -17,7 +18,8 @@ public: UpdateLaunchTimes = 1u << 3, UpdateFavorites = 1u << 4, UpdateTop = 1u << 5, - UpdateLock = 1u << 6 + UpdateLock = 1u << 6, + RefreshDataBase = 1u << 7 }; Q_DECLARE_FLAGS(HandleTypes, HandleType) @@ -37,6 +39,7 @@ public: m_isTopPosChanged(isChangeTopPos) {} QString path() const {return m_desktopfp;} + QStringList pathsNeedRefreshData() const {return m_pathsNeedRefreshData;} HandleTypes handleType() const {return m_handleType;} int favoritesState() const {return m_favoritesState;} int topState() const {return m_topState;} @@ -56,6 +59,7 @@ public: void setLaunchTimes(int times) {m_launchTimes = times;} void setChangeFavoritePos(bool isOrderChanged) {m_isFavoritePosChanged = isOrderChanged;} void setChangeTopPos(bool isOrderChanged) {m_isTopPosChanged = isOrderChanged;} + void setPathsNeedRefreshData (const QStringList& paths) {m_pathsNeedRefreshData = paths;} void merge(const PendingAppInfo& info) { m_handleType |= info.handleType(); @@ -89,6 +93,7 @@ private: int m_launchTimes = 0; bool m_isFavoritePosChanged = false; bool m_isTopPosChanged = false; + QStringList m_pathsNeedRefreshData; }; }