#include "app-db-manager.h" #include "file-utils.h" #include "convert-winid-to-desktop.h" #include #include #include #include #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" #define LAST_LOCALE_NAME QDir::homePath() + "/.config/org.ukui/ukui-search/appdata/last-locale-name.conf" #define LOCALE_NAME_VALUE "CurrentLocaleName" #define APP_DATABASE_VERSION_CONFIG QDir::homePath() + "/.config/org.ukui/ukui-search/appdata/app-database-version.conf" #define APP_DATABASE_VERSION_VALUE "AppDatabaseVersion" using namespace UkuiSearch; static AppDBManager *global_instance; QMutex AppDBManager::s_mutex; AppDBManager *AppDBManager::getInstance() { if (!global_instance) { global_instance = new AppDBManager(); } return global_instance; } AppDBManager::AppDBManager(QObject *parent) : QThread(parent), m_database(QSqlDatabase()) { //链接数据库 if (openDataBase()) { //监听系统语言变化 m_lastLocaleNameQsettings = new QSettings(LAST_LOCALE_NAME, QSettings::IniFormat); m_localeChanged = false; m_lastLocaleNameQsettings->beginGroup(LOCALE_NAME_VALUE); QString lastLocale = m_lastLocaleNameQsettings->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; } m_lastLocaleNameQsettings->setValue(LOCALE_NAME_VALUE, QLocale::system().name()); } m_lastLocaleNameQsettings->endGroup(); //检查数据库版本 m_dbVersionQsettings = new QSettings(APP_DATABASE_VERSION_CONFIG, QSettings::IniFormat); m_dbVersionQsettings->beginGroup(APP_DATABASE_VERSION_VALUE); QString dbVersion = m_dbVersionQsettings->value(APP_DATABASE_VERSION_VALUE).toString(); if (dbVersion.isEmpty()) { m_dbVersionNeedUpdate = true; }else if (dbVersion != APP_DATABASE_VERSION) { if (dbVersion.toDouble() < APP_DATABASE_VERSION.toDouble()) { m_dbVersionNeedUpdate = true; } else { qDebug() << "app db version old version:" << dbVersion.toDouble() << "new version:" << APP_DATABASE_VERSION.toDouble(); } } m_dbVersionQsettings->endGroup(); if (m_dbVersionNeedUpdate) { qDebug() << "app db version need update! old version:" << dbVersion.toDouble() << "new version:" << APP_DATABASE_VERSION.toDouble(); } //初始化数据库 refreshAllData2DB(); if (m_dbVersionNeedUpdate) { m_dbVersionQsettings->beginGroup(APP_DATABASE_VERSION_VALUE); m_dbVersionQsettings->setValue(APP_DATABASE_VERSION_VALUE, APP_DATABASE_VERSION); m_dbVersionQsettings->endGroup(); m_dbVersionNeedUpdate = false; } //初始化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); } 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 or 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!"; }); /* //初始化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); //初始化timer this->start(); m_timer = new QTimer(); m_maxProcessTimer = new QTimer(); m_timer->setInterval(2*1000); m_maxProcessTimer->setInterval(5*1000); m_timer->setSingleShot(true); m_maxProcessTimer->setSingleShot(true); m_timer->moveToThread(this); m_maxProcessTimer->moveToThread(this); connect(this, SIGNAL(startTimer()), m_timer, SLOT(start())); connect(this, SIGNAL(maxProcessTimerStart()), m_maxProcessTimer, SLOT(start())); connect(this, &AppDBManager::stopTimer, m_timer, &QTimer::stop); connect(this, &AppDBManager::stopTimer, m_maxProcessTimer, &QTimer::stop); //监听desktop文件所在目录,由于directoryChange会发多次信号,使用计时器阻塞 connect(m_watchAppDir, &QFileSystemWatcher::directoryChanged, this, [ = ](const QString & path) { qDebug() << "m_watchAppDir directoryChanged:" << path; Q_EMIT this->startTimer(); if (!m_maxProcessTimer->isActive()) { Q_EMIT this->maxProcessTimerStart(); } }); //计时器超时统一进行更新操作 connect(m_timer, &QTimer::timeout, this, [ & ] { qDebug() << "Time out! Now I can update the database!"; Q_EMIT this->stopTimer(); this->refreshAllData2DB(); }, Qt::DirectConnection); connect(m_maxProcessTimer, &QTimer::timeout, this, [ & ] { qDebug() << "I've waited too lang, I have to update the database now!"; Q_EMIT this->stopTimer(); this->refreshAllData2DB(); }, Qt::DirectConnection); */ //监控应用进程开启 connect(KWindowSystem::self(), &KWindowSystem::windowAdded, [ = ](WId id) { QString desktopfp = ConvertWinidToDesktop::getConverter().tranIdToDesktop(id); if (!desktopfp.isEmpty()) { this->updateLaunchTimes(desktopfp); } }); } else { qDebug() << "App-db-manager does nothing."; } } AppDBManager::~AppDBManager() { if (m_watcher) { delete m_watcher; } m_watcher = NULL; if (m_snapdWatcher) { delete m_snapdWatcher; } m_snapdWatcher = NULL; // if(m_watchAppDir) { // delete m_watchAppDir; // } // m_watchAppDir = NULL; closeDataBase(); } void AppDBManager::buildAppInfoDB() { qDebug() << "I'm going to build app info database."; 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 修改日期 .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("FIRST_LETTER_ALL")//拼音和英文全拼 .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() { } 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::loadDesktopFilePaths(QString path, QFileInfoList &infolist) { QDir dir(path); dir.setSorting(QDir::DirsFirst); dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); infolist.append(dir.entryInfoList()); } bool AppDBManager::addItem2BackIfNotExist(QString itemName, QString itemDataType, QVariant defult) { bool res(true); QSqlQuery sql(m_database); QString cmd = QString("SELECT * FROM sqlite_master WHERE name = 'appInfo' AND sql like '% %1 %' ").arg(itemName); if (!sql.exec(cmd)) { qWarning() << m_database.lastError() << cmd; res = false; return res; } if (sql.next()) { qDebug() << cmd << "is exist!"; return res; } cmd = QString("ALTER TABLE appInfo ADD '%0' '%1' ").arg(itemName) .arg(itemDataType); if (defult != QVariant()) { //TODO 根据数据类型将初始值转化为对应格式数据 if (itemDataType == "INT(4)") { cmd += QString("DEFAULT %1").arg(defult.toInt()); } else if (itemDataType == "TEXT") { cmd += QString("DEFAULT %1").arg(QString(defult.toByteArray())); } } if (!sql.exec(cmd)) { qWarning() << m_database.lastError() << cmd; res = false; } if (!res) { qDebug() << "Fail to addItem2Back :" << itemName; } return res; } void AppDBManager::refreshAllData2DB() { 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)) 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()); } } } bool AppDBManager::handleLocaleDataUpdate(const QString &desktopfp) { bool res(true); XdgDesktopFile desktopFile; desktopFile.load(desktopfp); 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(desktopfp); if (!sql.exec(cmd)) { qWarning() << m_database.lastError() << cmd; res = false; } if (res) { AppInfoResult result; if (this->createAppInfoResult(desktopfp, result)) { qDebug() << "Update the locale data of " << result.desktopPath; Q_EMIT this->appDBItemUpdate(result); } } else { qDebug() << "Fail to update the locale data of " << desktopfp; } return res; } void AppDBManager::run() { exec(); } void AppDBManager::refreshDataBase() { // if (m_database.transaction()) { // this->updateAllData2DB(); // if (!m_database.commit()) { // qWarning() << "Failed to commit !"; // m_database.rollback(); // } else if (!m_dbChanged) { // qDebug() << "app DataBase has no changes!"; // } else { // Q_EMIT this->finishHandleAppDB(); // } // } else { // qWarning() << "Failed to start transaction mode!!!"; // } } 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); } else { m_database = QSqlDatabase::addDatabase("QSQLITE", CONNECTION_NAME); m_database.setDatabaseName(APP_DATABASE_PATH + APP_DATABASE_NAME); } 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; QSqlDatabase::removeDatabase(CONNECTION_NAME); } QString AppDBManager::getAppDesktopMd5(const 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; } bool AppDBManager::startTransaction() { if (m_database.transaction()) { return true; } else { qWarning() << "Failed to start transaction mode!!!"; return false; } } bool AppDBManager::startCommit() { if (!m_database.commit()) { qWarning() << "Failed to commit !"; m_database.rollback(); return false; } else { return true; } } void AppDBManager::getInstallAppMap(QMap &installAppMap) { // QMutexLocker locker(&s_mutex); // for (auto i=m_installAppMap.begin(); i!=m_installAppMap.end(); ++i) { // installAppMap[i.key().app_name] = i.value(); // } // installAppMap.detach(); } bool AppDBManager::handleDBItemInsert(const QString &desktopfd) { bool res(true); QSqlQuery sql(m_database); XdgDesktopFile desktopfile; desktopfile.load(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 { hanzi = desktopfile.value("Name").toString(); if (!hanzi.contains(QRegExp("[\\x4e00-\\x9fa5]+"))) { isHanzi = false; } } if (isHanzi) { QStringList pinyinList = FileUtils::findMultiToneWords(hanzi); for (int i = 0; iappDBItemAdd(result); qDebug() << "app database add " << desktopfd << "success!"; } else { qDebug() << "app database add " << desktopfd << "failed!"; } return res; } bool AppDBManager::handleDBItemDelete(const QString &desktopfd) { bool res(true); QSqlQuery sql(m_database); QString cmd = QString("SELECT FAVORITES, TOP FROM APPINFO WHERE DESKTOP_FILE_PATH = '%0'").arg(desktopfd); //查询要删除信息的应用是否被收藏或顶置过 if (!sql.exec(cmd)) { qWarning() << m_database.lastError() << cmd; } else if (sql.next()) { int favorites = sql.value("FAVORITES").toInt(); int top = sql.value("TOP").toInt(); if (favorites) { cmd = QString("UPDATE appInfo SET FAVORITES = FAVORITES -1 WHERE FAVORITES > %1").arg(favorites); if (!sql.exec(cmd)) { qWarning() << "I'm going to delete item in db, fail to update the FAVORITES because:" << m_database.lastError() << cmd; } } if (top) { cmd = QString("UPDATE appInfo SET TOP = TOP -1 WHERE TOP > %1").arg(top); if (!sql.exec(cmd)) { qWarning() << "I'm going to delete item in db, fail to update the TOP because:" << m_database.lastError() << cmd; } } } else { qWarning() << "Fail to exec next, because" << m_database.lastError() << "while executing " << cmd; } //执行删除操作 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) { Q_EMIT this->appDBItemDelete(desktopfd); qDebug() << "app database delete " << desktopfd << "success!"; } else { qDebug() << "app database delete " << desktopfd << "failed!"; } return res; } bool AppDBManager::handleDBItemUpdate(const QString &desktopfp) { bool res(true); XdgDesktopFile desktopfile; desktopfile.load(desktopfp); if (desktopfile.value("NoDisplay").toString().contains("true") || desktopfile.value("NotShowIn").toString().contains("UKUI")) { qDebug() << "app" << desktopfp << "is changed, but NoDisplay or NotShowIn is working!"; return this->handleDBItemDelete(desktopfp); } 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 { hanzi = desktopfile.value("Name").toString(); if (!hanzi.contains(QRegExp("[\\x4e00-\\x9fa5]+"))) { isHanzi = false; } } if (isHanzi) { QStringList pinyinList = FileUtils::findMultiToneWords(hanzi); firstLetter2All = pinyinList.at(0); for (int i = 0; icreateAppInfoResult(desktopfp, result)) { qDebug() << "app database update " << result.desktopPath << "success!"; Q_EMIT this->appDBItemUpdate(result); } } else { qDebug() << "app database update " << desktopfp << "failed!"; } return res; } bool AppDBManager::handleLaunchTimesUpdate(const QString &desktopfp, int num) { qDebug() << "launch times will add:" << num; bool res(true); 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()) { int launchTimes = sql.value(0).toInt() + num; 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(launchTimes) .arg(1) .arg(desktopfp); if (!sql.exec(cmd)) { qWarning() << "Set app favorites state failed!" << m_database.lastError(); res = false; } else { AppInfoResult result; if (this->createAppInfoResult(desktopfp, result)) { qDebug() << "app database update " << result.desktopPath << "launch times: " << result.launchTimes << "success!"; Q_EMIT this->appDBItemUpdate(result); } } } else { qWarning() << "Failed to exec next!" << cmd; res = false; } } else { qWarning() << "Failed to exec:" << cmd; res = false; } return res; } bool AppDBManager::handleFavoritesStateUpdate(const QString &desktopfp, int num, bool isOrderChanged) { if (num < 0) { qWarning() << "Invalid favorite num, I quit!!!"; return false; } bool res(true); QSqlQuery sql(m_database); QString cmd; //当直接设置的时候需要查询要设置的favorites标志位是否被占用 if (!isOrderChanged) { cmd = QString("SELECT DESKTOP_FILE_PATH, FAVORITES FROM APPINFO WHERE FAVORITES = %1").arg(num); if (!sql.exec(cmd)) { qWarning() << "Fail to exec:" << cmd << "because:" << m_database.lastError(); } else { while (sql.next()) { if (num && sql.value("FAVORITES").toInt() == num) { res = false; if (sql.value("DESKTOP_FILE_PATH").toString() == desktopfp) { qWarning() << "favorites state has no changes, I quit!"; return res; } else { qWarning() << "the favorites num:" << num << "has been used, fail to update favorites state of" << desktopfp; return res; } } } } } //更新favorites状态 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; } else { AppInfoResult result; if (this->createAppInfoResult(desktopfp, result)) { qDebug() << "app database update " << result.desktopPath << "favorites state: " << result.favorite << "success!"; Q_EMIT this->appDBItemUpdate(result); } } return res; } bool AppDBManager::handleTopStateUpdate(const QString &desktopfp, int num, bool isOrderChanged) { if (num < 0) { qWarning() << "Invalid top num, I quit!!!"; return false; } bool res(true); QSqlQuery sql(m_database); //当直接设置的时候需要查询要设置的top标志位是否被占用 QString cmd; if (!isOrderChanged) { cmd = QString("SELECT DESKTOP_FILE_PATH, TOP FROM APPINFO WHERE TOP = %1").arg(num); if (!sql.exec(cmd)) { qWarning() << "Fail to exec:" << cmd << "because:" << m_database.lastError(); } else { while (sql.next()) { if (num && sql.value("TOP").toInt() == num) { res = false; if (sql.value("DESKTOP_FILE_PATH").toString() == desktopfp) { qWarning() << "top state has no changes, I quit!"; return res; } else { qWarning() << "the top num:" << num << "has been used, fail to update top state of" << desktopfp; return res; } } } } } //更新top状态 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; } else { AppInfoResult result; if (this->createAppInfoResult(desktopfp, result)) { qDebug() << "app database update " << result.desktopPath << "top state: " << result.top << "success!"; Q_EMIT this->appDBItemUpdate(result); } } return res; } bool AppDBManager::handleLockStateUpdate(const QString &desktopfp, int num) { bool res(true); 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; } else { AppInfoResult result; if (this->createAppInfoResult(desktopfp, result)) { qDebug() << "app database update " << result.desktopPath << "lock state: " << result.lock << "success!"; Q_EMIT this->appDBItemUpdate(result); } } return res; } bool AppDBManager::createAppInfoResult(const QString &desktopfp, AppInfoResult &result) { bool res(false); QSqlQuery sql(m_database); QString cmd = QString("SELECT ICON, LOCAL_NAME, FIRST_LETTER_ALL, CATEGORY, " "TOP, FAVORITES, LAUNCH_TIMES, LOCK FROM APPINFO " "WHERE DESKTOP_FILE_PATH='%1'").arg(desktopfp); if(sql.exec(cmd)) { if (sql.next()) { result.desktopPath = desktopfp; result.iconName = sql.value(0).toString(); result.appLocalName = sql.value(1).toString(); result.firstLetter = sql.value(2).toString(); result.category = sql.value(3).toString(); result.top = sql.value(4).toInt(); result.favorite = sql.value(5).toInt(); result.launchTimes = sql.value(6).toInt(); result.lock = sql.value(7).toInt(); res = true; } else { qWarning() << "Fail to exec next. " << cmd << m_database.lastError(); } } else { qWarning() << "Fail to exec " << cmd << m_database.lastError(); } return res; } void AppDBManager::insertDBItem(const QString &desktopfd) { PendingAppInfo item(desktopfd, PendingAppInfo::HandleType::Insert); PendingAppInfoQueue::getAppInfoQueue().enqueue(item); } void AppDBManager::updateDBItem(const QString &desktopfd) { PendingAppInfo item(desktopfd, PendingAppInfo::HandleType::UpdateAll); PendingAppInfoQueue::getAppInfoQueue().enqueue(item); } void AppDBManager::deleteDBItem(const QString &desktopfd) { PendingAppInfo item(desktopfd, PendingAppInfo::HandleType::Delete); PendingAppInfoQueue::getAppInfoQueue().enqueue(item); } void AppDBManager::updateLocaleData(const QString &desktopfp) { PendingAppInfo item(desktopfp, PendingAppInfo::HandleType::UpdateLocaleData); PendingAppInfoQueue::getAppInfoQueue().enqueue(item); } void AppDBManager::updateLaunchTimes(const QString &desktopfp) { PendingAppInfo item(desktopfp, PendingAppInfo::HandleType::UpdateLaunchTimes); item.setLaunchWillAdd(true); item.setLaunchTimes(1); PendingAppInfoQueue::getAppInfoQueue().enqueue(item); } void AppDBManager::updateFavoritesState(const QString &desktopfp, int num, bool isOrderChanged) { PendingAppInfo item(desktopfp, PendingAppInfo::HandleType::UpdateFavorites); item.setFavorites(num); item.setChangeFavoritePos(isOrderChanged); PendingAppInfoQueue::getAppInfoQueue().enqueue(item); } void AppDBManager::updateTopState(const QString &desktopfp, int num, bool isOrderChanged) { PendingAppInfo item(desktopfp, PendingAppInfo::HandleType::UpdateTop); item.setTop(num); item.setChangeTopPos(isOrderChanged); PendingAppInfoQueue::getAppInfoQueue().enqueue(item); } void AppDBManager::udpateLockState(const QString &desktopfp, int num) { PendingAppInfo item(desktopfp, PendingAppInfo::HandleType::UpdateTop); item.setLock(num); PendingAppInfoQueue::getAppInfoQueue().enqueue(item); } bool AppDBManager::changeFavoriteAppPos(const QString &desktopfp, int pos) { if (pos < 1) { qWarning() << "To be moved to a invalid favorites pos , I quit!!"; return false; } bool res(true); QSqlQuery sql(m_database); QString cmd = QString("SELECT FAVORITES FROM APPINFO WHERE DESKTOP_FILE_PATH = '%0'").arg(desktopfp); int previousPos = 0; //记录应用原位置 if (!sql.exec(cmd)) { qWarning() << "Fail to change favorite-app pos, because: " << m_database.lastError() << " when exec :" << cmd; res = false; } else { if (sql.next()) { previousPos = sql.value(0).toInt(); if (previousPos < 1) { qWarning() << QString("app: %1 is not a favorites app, I quit!!").arg(desktopfp); } if (previousPos == pos) { qDebug() << "favorite app's pos has no changes!"; return res; } cmd = QString("SELECT DESKTOP_FILE_PATH, FAVORITES FROM APPINFO WHERE FAVORITES BETWEEN MIN(%1, %2) AND MAX(%1, %2)") .arg(previousPos) .arg(pos); } else { qWarning() << "Fail to change favorite-app pos when exec next, because: " << m_database.lastError(); } } //更新原位置和新位置之间的应用的位置 if (!sql.exec(cmd)) { qWarning() << "Fail to change favorite-app pos, because: " << m_database.lastError() << " when exec :" << cmd; res = false; } else { while (sql.next()) { if (sql.value("FAVORITES").toInt() == previousPos) { this->updateFavoritesState(desktopfp, pos, true); continue; } if (previousPos > pos) { this->updateFavoritesState(sql.value("DESKTOP_FILE_PATH").toString(), sql.value("FAVORITES").toInt() + 1, true); } else { this->updateFavoritesState(sql.value("DESKTOP_FILE_PATH").toString(), sql.value("FAVORITES").toInt() - 1, true); } } } return res; } bool AppDBManager::changeTopAppPos(const QString &desktopfp, int pos) { if (pos < 1) { qWarning() << "To be moved to a invalid top pos, I quit!!"; return false; } bool res(true); QSqlQuery sql(m_database); QString cmd = QString("SELECT TOP FROM APPINFO WHERE DESKTOP_FILE_PATH = '%0'").arg(desktopfp); int previousPos = 0; //记录应用原位置 if (!sql.exec(cmd)) { qWarning() << "Fail to change top-app pos, because: " << m_database.lastError() << " when exec :" << cmd; res = false; } else { if (sql.next()) { previousPos = sql.value(0).toInt(); if (previousPos < 1) { qWarning() << QString("app: %1 is not a favorites app, I quit!!").arg(desktopfp); res = false; return res; } if (previousPos == pos) { qDebug() << "top app's pos has no changes!"; res = false; return res; } cmd = QString("SELECT DESKTOP_FILE_PATH, TOP FROM APPINFO WHERE TOP BETWEEN MIN(%1, %2) AND MAX(%1, %2)") .arg(previousPos) .arg(pos); } else { qWarning() << "Fail to change top-app pos when exec next, because: " << m_database.lastError(); } } //更新原位置和新位置之间的应用的位置 if (!sql.exec(cmd)) { qWarning() << "Fail to change top-app pos, because: " << m_database.lastError() << " when exec :" << cmd; res = false; } else { while (sql.next()) { if (sql.value("TOP").toInt() == previousPos) { this->updateTopState(desktopfp, pos, true); continue; } if (previousPos > pos) { this->updateTopState(sql.value("DESKTOP_FILE_PATH").toString(), sql.value("TOP").toInt() + 1, true); } else { this->updateTopState(sql.value("DESKTOP_FILE_PATH").toString(), sql.value("TOP").toInt() - 1, true); } } } return res; } QVector AppDBManager::getAppInfoResults() { QVector appInfoResults; QSqlQuery sql(m_database); QString cmd = QString("SELECT DESKTOP_FILE_PATH,LOCAL_NAME,ICON,CATEGORY,TOP,FAVORITES,LAUNCH_TIMES,LOCK,FIRST_LETTER_ALL FROM APPINFO"); if (sql.exec(cmd)) { while (sql.next()) { AppInfoResult result; result.desktopPath = sql.value("DESKTOP_FILE_PATH").toString(); result.appLocalName = sql.value("LOCAL_NAME").toString(); result.iconName = sql.value("ICON").toString(); result.category = sql.value("CATEGORY").toString(); result.top = sql.value("TOP").toInt(); result.favorite = sql.value("FAVORITES").toInt(); result.launchTimes = sql.value("LAUNCH_TIMES").toInt(); result.lock = sql.value("LOCK").toInt(); result.firstLetter = sql.value("FIRST_LETTER_ALL").toString(); appInfoResults.append(std::move(result)); } } else { qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); } return appInfoResults; } int AppDBManager::getAppLockState(const QString &desktopfp) { int lockState = -1; 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()) { lockState = sql.value(0).toInt(); } else { qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); } } else { qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); } return lockState; } int AppDBManager::getAppTopState(const QString &desktopfp) { int topState = -1; 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()) { topState = sql.value(0).toInt(); } else { qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); } } else { qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); } return topState; } int AppDBManager::getAppLaunchedState(const QString &desktopfp) { int launchedState = -1; 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()) { launchedState = sql.value(0).toInt(); } else { qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); } } else { qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); } return launchedState; } int AppDBManager::getAppFavoriteState(const QString &desktopfp) { int favoriteState = -1; 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()) { favoriteState = sql.value(0).toInt(); } else { qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); } } else { qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); } return favoriteState; } QString AppDBManager::getAppCategory(const QString &desktopfp) { QString category; 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(); } } else { qWarning() << QString("cmd %0 failed!").arg(cmd) << m_database.lastError(); } return category; }