UI: Add AppInfoCache.

This commit is contained in:
Nodir Temirkhodjaev 2019-04-17 17:30:31 +05:00
parent eb32cbc092
commit 28be2aa62f
16 changed files with 228 additions and 29 deletions

View File

@ -46,6 +46,8 @@ SOURCES += \
task/taskupdatechecker.cpp \ task/taskupdatechecker.cpp \
task/taskworker.cpp \ task/taskworker.cpp \
translationmanager.cpp \ translationmanager.cpp \
util/app/appinfo.cpp \
util/app/appinfocache.cpp \
util/app/appinfomanager.cpp \ util/app/appinfomanager.cpp \
util/app/appinfoworker.cpp \ util/app/appinfoworker.cpp \
util/app/apputil.cpp \ util/app/apputil.cpp \
@ -111,6 +113,8 @@ HEADERS += \
task/taskupdatechecker.h \ task/taskupdatechecker.h \
task/taskworker.h \ task/taskworker.h \
translationmanager.h \ translationmanager.h \
util/app/appinfo.h \
util/app/appinfocache.h \
util/app/appinfomanager.h \ util/app/appinfomanager.h \
util/app/appinfoworker.h \ util/app/appinfoworker.h \
util/app/apputil.h \ util/app/apputil.h \
@ -159,8 +163,13 @@ RESOURCES += fort_qml.qrc
RESOURCES += fort_images.qrc RESOURCES += fort_images.qrc
# Database Migrations # Database Migrations
OTHER_FILES += db/migrations/*.sql OTHER_FILES += \
RESOURCES += db/migrations.qrc db/migrations/*.sql \
util/app/migrations/*.sql
RESOURCES += \
db/migrations.qrc \
util/app/migrations.qrc
# Shadow Build: Copy i18n/ to build path # Shadow Build: Copy i18n/ to build path
!equals(PWD, $${OUT_PWD}) { !equals(PWD, $${OUT_PWD}) {

View File

@ -86,6 +86,7 @@ bool DatabaseManager::initialize()
if (!m_sqliteDb->open(m_filePath)) { if (!m_sqliteDb->open(m_filePath)) {
qCritical(CLOG_DATABASE_MANAGER()) << "File open error:" qCritical(CLOG_DATABASE_MANAGER()) << "File open error:"
<< m_filePath
<< m_sqliteDb->errorMessage(); << m_sqliteDb->errorMessage();
return false; return false;
} }
@ -94,7 +95,7 @@ bool DatabaseManager::initialize()
if (!m_sqliteDb->migrate(":/db/migrations", DATABASE_USER_VERSION, if (!m_sqliteDb->migrate(":/db/migrations", DATABASE_USER_VERSION,
&migrateFunc)) { &migrateFunc)) {
qCritical(CLOG_DATABASE_MANAGER()) << "Migration error"; qCritical(CLOG_DATABASE_MANAGER()) << "Migration error" << m_filePath;
return false; return false;
} }

View File

@ -26,6 +26,7 @@
#include "task/taskinfo.h" #include "task/taskinfo.h"
#include "task/taskmanager.h" #include "task/taskmanager.h"
#include "translationmanager.h" #include "translationmanager.h"
#include "util/app/appinfocache.h"
#include "util/fileutil.h" #include "util/fileutil.h"
#include "util/guiutil.h" #include "util/guiutil.h"
#include "util/hotkeymanager.h" #include "util/hotkeymanager.h"
@ -113,6 +114,8 @@ void FortManager::registerQmlTypes()
qmlRegisterType<AppGroup>("com.fortfirewall", 1, 0, "AppGroup"); qmlRegisterType<AppGroup>("com.fortfirewall", 1, 0, "AppGroup");
qmlRegisterType<FirewallConf>("com.fortfirewall", 1, 0, "FirewallConf"); qmlRegisterType<FirewallConf>("com.fortfirewall", 1, 0, "FirewallConf");
qRegisterMetaType<AppInfo>();
qmlRegisterType<AppInfoCache>("com.fortfirewall", 1, 0, "AppInfoCache");
qmlRegisterType<FileUtil>("com.fortfirewall", 1, 0, "FileUtil"); qmlRegisterType<FileUtil>("com.fortfirewall", 1, 0, "FileUtil");
qmlRegisterType<GuiUtil>("com.fortfirewall", 1, 0, "GuiUtil"); qmlRegisterType<GuiUtil>("com.fortfirewall", 1, 0, "GuiUtil");
qmlRegisterType<HostInfoCache>("com.fortfirewall", 1, 0, "HostInfoCache"); qmlRegisterType<HostInfoCache>("com.fortfirewall", 1, 0, "HostInfoCache");

View File

@ -0,0 +1 @@
#include "appinfo.h"

26
src/ui/util/app/appinfo.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef APPINFO_H
#define APPINFO_H
#include <QPixmap>
class AppInfo
{
Q_GADGET
Q_PROPERTY(QString fileDescription MEMBER fileDescription CONSTANT)
Q_PROPERTY(QString companyName MEMBER companyName CONSTANT)
Q_PROPERTY(QString productName MEMBER productName CONSTANT)
Q_PROPERTY(QString productVersion MEMBER productVersion CONSTANT)
Q_PROPERTY(QPixmap icon MEMBER icon CONSTANT)
public:
QString fileDescription;
QString companyName;
QString productName;
QString productVersion;
QPixmap icon;
};
Q_DECLARE_METATYPE(AppInfo)
#endif // APPINFO_H

View File

@ -0,0 +1,86 @@
#include "appinfocache.h"
#include <QLoggingCategory>
#include "../fileutil.h"
#include "appinfomanager.h"
#include <sqlite/sqlitedb.h>
#include <sqlite/sqlitestmt.h>
Q_DECLARE_LOGGING_CATEGORY(CLOG_APPINFOCACHE)
Q_LOGGING_CATEGORY(CLOG_APPINFOCACHE, "fort.appInfoCache")
#define DATABASE_USER_VERSION 1
AppInfoCache::AppInfoCache(QObject *parent) :
QObject(parent),
m_manager(new AppInfoManager(this)),
m_sqliteDb(new SqliteDb()),
m_cache(1000)
{
connect(m_manager, &AppInfoManager::lookupFinished,
this, &AppInfoCache::handleFinishedLookup);
m_triggerTimer.setSingleShot(true);
m_triggerTimer.setInterval(200);
connect(&m_triggerTimer, &QTimer::timeout,
this, &AppInfoCache::cacheChanged);
setupDb();
}
AppInfoCache::~AppInfoCache()
{
delete m_sqliteDb;
}
void AppInfoCache::setupDb()
{
const QString filePath = FileUtil::appCacheLocation() + "/appinfocache.db";
if (!m_sqliteDb->open(filePath)) {
qCritical(CLOG_APPINFOCACHE()) << "File open error:"
<< filePath
<< m_sqliteDb->errorMessage();
return;
}
if (!m_sqliteDb->migrate(":/appinfocache/migrations", DATABASE_USER_VERSION)) {
qCritical(CLOG_APPINFOCACHE()) << "Migration error" << filePath;
return;
}
}
AppInfo *AppInfoCache::appInfo(const QString &appPath)
{
AppInfo *appInfo = m_cache.object(appPath);
if (appInfo == nullptr) {
appInfo = new AppInfo();
m_cache.insert(appPath, appInfo, 1);
m_manager->lookupApp(appPath);
}
return appInfo;
}
void AppInfoCache::handleFinishedLookup(const QString &appPath,
const AppInfo info)
{
AppInfo *appInfo = m_cache.object(appPath);
if (appInfo == nullptr)
return;
*appInfo = info;
emitCacheChanged();
}
void AppInfoCache::emitCacheChanged()
{
if (!m_triggerTimer.isActive()) {
m_triggerTimer.start();
}
}

View File

@ -0,0 +1,49 @@
#ifndef APPINFOCACHE_H
#define APPINFOCACHE_H
#include <QCache>
#include <QObject>
#include <QTimer>
#include "appinfo.h"
QT_FORWARD_DECLARE_CLASS(AppInfoManager)
QT_FORWARD_DECLARE_CLASS(SqliteDb)
class AppInfoCache : public QObject
{
Q_OBJECT
Q_PROPERTY(bool infoTrigger READ infoTrigger NOTIFY cacheChanged)
public:
explicit AppInfoCache(QObject *parent = nullptr);
~AppInfoCache() override;
bool infoTrigger() const { return true; }
signals:
void cacheChanged();
public slots:
AppInfo *appInfo(const QString &appPath);
private slots:
void handleFinishedLookup(const QString &appPath,
const AppInfo info);
private:
void setupDb();
void emitCacheChanged();
private:
AppInfoManager *m_manager;
SqliteDb *m_sqliteDb;
QCache<QString, AppInfo> m_cache;
QTimer m_triggerTimer;
};
#endif // APPINFOCACHE_H

View File

@ -23,9 +23,7 @@ void AppInfoManager::lookupApp(const QString &appPath)
void AppInfoManager::handleWorkerResult(const QString &appPath, void AppInfoManager::handleWorkerResult(const QString &appPath,
const QVariant &result) const QVariant &result)
{ {
const QVariantList list = result.toList(); auto appInfo = result.value<AppInfo>();
const QString &displayName = list.at(0).toString();
const QImage &icon = list.at(1).value<QImage>();
emit lookupFinished(appPath, displayName, icon); emit lookupFinished(appPath, appInfo);
} }

View File

@ -2,6 +2,7 @@
#define APPINFOMANAGER_H #define APPINFOMANAGER_H
#include "../worker/workermanager.h" #include "../worker/workermanager.h"
#include "appinfo.h"
class AppInfoManager : public WorkerManager class AppInfoManager : public WorkerManager
{ {
@ -11,8 +12,7 @@ public:
explicit AppInfoManager(QObject *parent = nullptr); explicit AppInfoManager(QObject *parent = nullptr);
signals: signals:
void lookupFinished(const QString &appPath, const QString &displayName, void lookupFinished(const QString &appPath, const AppInfo appInfo);
const QImage &icon);
public slots: public slots:
void lookupApp(const QString &appPath); void lookupApp(const QString &appPath);

View File

@ -2,6 +2,7 @@
#include <QImage> #include <QImage>
#include "appinfo.h"
#include "appinfomanager.h" #include "appinfomanager.h"
#include "apputil.h" #include "apputil.h"
@ -12,12 +13,11 @@ AppInfoWorker::AppInfoWorker(AppInfoManager *manager) :
void AppInfoWorker::doJob(const QString &appPath) void AppInfoWorker::doJob(const QString &appPath)
{ {
// TODO AppInfo appInfo;
AppUtil::getInfo(appPath, appInfo);
if (aborted()) return; if (aborted()) return;
const QVariantList result = QVariantList() manager()->handleWorkerResult(appPath, QVariant::fromValue(appInfo));
<< QString() << QImage();
manager()->handleWorkerResult(appPath, result);
} }

View File

@ -8,6 +8,8 @@
#include <objbase.h> #include <objbase.h>
#include <shellapi.h> #include <shellapi.h>
#include "appinfo.h"
// Defined in qpixmap_win.cpp // Defined in qpixmap_win.cpp
Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon); Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon);
@ -67,7 +69,7 @@ QString extractInfoText(LPVOID infoData, const WORD *langInfo,
return QString(); return QString();
} }
bool extractAppInfo(const QString &appPath, AppInfo &appInfo) bool extractVersionInfo(const QString &appPath, AppInfo &appInfo)
{ {
const wchar_t *appPathW = (LPCWSTR) appPath.utf16(); const wchar_t *appPathW = (LPCWSTR) appPath.utf16();
@ -120,12 +122,11 @@ bool extractAppInfo(const QString &appPath, AppInfo &appInfo)
} }
QPixmap AppUtil::getIcon(const QString &appPath)
{
return extractShellIcon(appPath);
}
bool AppUtil::getInfo(const QString &appPath, AppInfo &appInfo) bool AppUtil::getInfo(const QString &appPath, AppInfo &appInfo)
{ {
return extractAppInfo(appPath, appInfo); if (extractVersionInfo(appPath, appInfo)) {
appInfo.icon = extractShellIcon(appPath);
return true;
}
return false;
} }

View File

@ -2,19 +2,12 @@
#define APPUTIL_H #define APPUTIL_H
#include <QObject> #include <QObject>
#include <QPixmap>
typedef struct AppInfo { QT_FORWARD_DECLARE_CLASS(AppInfo)
QString fileDescription;
QString companyName;
QString productName;
QString productVersion;
} AppInfo;
class AppUtil class AppUtil
{ {
public: public:
static QPixmap getIcon(const QString &appPath);
static bool getInfo(const QString &appPath, AppInfo &appInfo); static bool getInfo(const QString &appPath, AppInfo &appInfo);
}; };

View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/appinfocache">
<file>migrations/1.sql</file>
</qresource>
</RCC>

View File

@ -0,0 +1,21 @@
PRAGMA user_version = 1;
PRAGMA journal_mode=WAL;
CREATE TABLE IF NOT EXISTS app(
path TEXT PRIMARY KEY,
file_descr TEXT,
company_name TEXT,
product_name TEXT,
product_ver TEXT,
icon_id INTEGER,
persist BOOL DEFAULT 0,
access_time DATE DEFAULT date('now')
) WITHOUT ROWID;
CREATE TABLE IF NOT EXISTS icon(
icon_id INTEGER PRIMARY KEY,
ref_count INTEGER NOT NULL DEFAULT 0,
hash TEXT NOT NULL,
icon BLOB NOT NULL
);

View File

@ -160,6 +160,11 @@ QString FileUtil::appBinLocation()
return QCoreApplication::applicationDirPath(); return QCoreApplication::applicationDirPath();
} }
QString FileUtil::appCacheLocation()
{
return QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
}
QString FileUtil::appConfigLocation() QString FileUtil::appConfigLocation()
{ {
return QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation); return QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);

View File

@ -42,6 +42,7 @@ public:
static bool writeFileData(const QString &filePath, const QByteArray &data); static bool writeFileData(const QString &filePath, const QByteArray &data);
static QString appBinLocation(); static QString appBinLocation();
static QString appCacheLocation();
static QString appConfigLocation(); static QString appConfigLocation();
static QString applicationsLocation(); static QString applicationsLocation();
}; };