UI: Programs: Load app icons in separate thread

This commit is contained in:
Nodir Temirkhodjaev 2023-01-26 19:35:39 +03:00
parent 99be09d768
commit 097a64ad30
16 changed files with 142 additions and 37 deletions

View File

@ -9,6 +9,8 @@ TARGET = FortFirewallUILib
TEMPLATE = lib TEMPLATE = lib
SOURCES += \ SOURCES += \
appinfo/appbasejob.cpp \
appinfo/appiconjob.cpp \
appinfo/appinfo.cpp \ appinfo/appinfo.cpp \
appinfo/appinfocache.cpp \ appinfo/appinfocache.cpp \
appinfo/appinfojob.cpp \ appinfo/appinfojob.cpp \
@ -175,6 +177,8 @@ SOURCES += \
util/worker/workerobject.cpp util/worker/workerobject.cpp
HEADERS += \ HEADERS += \
appinfo/appbasejob.h \
appinfo/appiconjob.h \
appinfo/appinfo.h \ appinfo/appinfo.h \
appinfo/appinfocache.h \ appinfo/appinfocache.h \
appinfo/appinfojob.h \ appinfo/appinfojob.h \

View File

@ -0,0 +1,3 @@
#include "appbasejob.h"
AppBaseJob::AppBaseJob(const QString &appPath) : WorkerJob(appPath) { }

View File

@ -0,0 +1,18 @@
#ifndef APPBASEJOB_H
#define APPBASEJOB_H
#include <util/worker/workerjob.h>
class AppBaseJob : public WorkerJob
{
public:
enum AppJobType : qint8 { JobTypeInfo, JobTypeIcon };
explicit AppBaseJob(const QString &appPath);
virtual AppJobType jobType() const = 0;
const QString &appPath() const { return text; }
};
#endif // APPBASEJOB_H

View File

@ -0,0 +1,6 @@
#include "appiconjob.h"
AppIconJob::AppIconJob(const QString &appPath, qint64 iconId) :
AppBaseJob(appPath), m_iconId(iconId)
{
}

View File

@ -0,0 +1,24 @@
#ifndef APPICONJOB_H
#define APPICONJOB_H
#include <QImage>
#include "appbasejob.h"
class AppIconJob : public AppBaseJob
{
public:
explicit AppIconJob(const QString &appPath, qint64 iconId);
virtual AppJobType jobType() const { return JobTypeIcon; }
qint64 iconId() const { return m_iconId; }
public:
QImage image;
private:
const qint64 m_iconId = 0;
};
#endif // APPICONJOB_H

View File

@ -15,8 +15,10 @@ AppInfoCache::AppInfoCache(QObject *parent) : QObject(parent), m_cache(1000)
void AppInfoCache::setUp() void AppInfoCache::setUp()
{ {
connect(IoC<AppInfoManager>(), &AppInfoManager::lookupFinished, this, connect(IoC<AppInfoManager>(), &AppInfoManager::lookupInfoFinished, this,
&AppInfoCache::handleFinishedLookup); &AppInfoCache::handleFinishedInfoLookup);
connect(IoC<AppInfoManager>(), &AppInfoManager::lookupIconFinished, this,
&AppInfoCache::handleFinishedIconLookup);
} }
void AppInfoCache::tearDown() void AppInfoCache::tearDown()
@ -24,11 +26,6 @@ void AppInfoCache::tearDown()
disconnect(IoC<AppInfoManager>()); disconnect(IoC<AppInfoManager>());
} }
QImage AppInfoCache::appImage(const AppInfo &info) const
{
return IoC<AppInfoManager>()->loadIconFromDb(info.iconId);
}
QString AppInfoCache::appName(const QString &appPath) QString AppInfoCache::appName(const QString &appPath)
{ {
AppInfo appInfo = this->appInfo(appPath); AppInfo appInfo = this->appInfo(appPath);
@ -45,13 +42,12 @@ QIcon AppInfoCache::appIcon(const QString &appPath, const QString &nullIconPath)
return pixmap; return pixmap;
const auto info = appInfo(appPath); const auto info = appInfo(appPath);
const auto image = appImage(info); if (info.isValid()) {
if (!image.isNull()) { IoC<AppInfoManager>()->lookupAppIcon(appPath, info.iconId);
pixmap = QPixmap::fromImage(image);
} else {
pixmap = IconCache::file(nullIconPath.isEmpty() ? ":/icons/application.png" : nullIconPath);
} }
pixmap = IconCache::file(!nullIconPath.isEmpty() ? nullIconPath : ":/icons/application.png");
IconCache::insert(appPath, pixmap); IconCache::insert(appPath, pixmap);
return pixmap; return pixmap;
@ -86,7 +82,7 @@ AppInfo AppInfoCache::appInfo(const QString &appPath)
return *appInfo; return *appInfo;
} }
void AppInfoCache::handleFinishedLookup(const QString &appPath, const AppInfo &info) void AppInfoCache::handleFinishedInfoLookup(const QString &appPath, const AppInfo &info)
{ {
AppInfo *appInfo = m_cache.object(appPath); AppInfo *appInfo = m_cache.object(appPath);
if (!appInfo) if (!appInfo)
@ -99,6 +95,16 @@ void AppInfoCache::handleFinishedLookup(const QString &appPath, const AppInfo &i
emitCacheChanged(); emitCacheChanged();
} }
void AppInfoCache::handleFinishedIconLookup(const QString &appPath, const QImage &image)
{
if (image.isNull())
return;
IconCache::insert(appPath, QPixmap::fromImage(image)); // update cached icon
emitCacheChanged();
}
void AppInfoCache::emitCacheChanged() void AppInfoCache::emitCacheChanged()
{ {
m_triggerTimer.startTrigger(); m_triggerTimer.startTrigger();

View File

@ -19,7 +19,6 @@ public:
void setUp() override; void setUp() override;
void tearDown() override; void tearDown() override;
QImage appImage(const AppInfo &info) const;
QString appName(const QString &appPath); QString appName(const QString &appPath);
QIcon appIcon(const QString &appPath, const QString &nullIconPath = QString()); QIcon appIcon(const QString &appPath, const QString &nullIconPath = QString());
@ -29,7 +28,8 @@ signals:
void cacheChanged(); void cacheChanged();
private slots: private slots:
void handleFinishedLookup(const QString &appPath, const AppInfo &info); void handleFinishedInfoLookup(const QString &appPath, const AppInfo &info);
void handleFinishedIconLookup(const QString &appPath, const QImage &image);
private: private:
void emitCacheChanged(); void emitCacheChanged();

View File

@ -1,3 +1,3 @@
#include "appinfojob.h" #include "appinfojob.h"
AppInfoJob::AppInfoJob(const QString &appPath) : WorkerJob(appPath) { } AppInfoJob::AppInfoJob(const QString &appPath) : AppBaseJob(appPath) { }

View File

@ -1,16 +1,15 @@
#ifndef APPINFOJOB_H #ifndef APPINFOJOB_H
#define APPINFOJOB_H #define APPINFOJOB_H
#include <util/worker/workerjob.h> #include "appbasejob.h"
#include "appinfo.h" #include "appinfo.h"
class AppInfoJob : public WorkerJob class AppInfoJob : public AppBaseJob
{ {
public: public:
explicit AppInfoJob(const QString &appPath); explicit AppInfoJob(const QString &appPath);
const QString &appPath() const { return text; } virtual AppJobType jobType() const { return JobTypeInfo; }
public: public:
AppInfo appInfo; AppInfo appInfo;

View File

@ -6,6 +6,7 @@
#include <sqlite/sqlitedb.h> #include <sqlite/sqlitedb.h>
#include <sqlite/sqlitestmt.h> #include <sqlite/sqlitestmt.h>
#include "appiconjob.h"
#include "appinfojob.h" #include "appinfojob.h"
#include "appinfoutil.h" #include "appinfoutil.h"
#include "appinfoworker.h" #include "appinfoworker.h"
@ -96,22 +97,37 @@ void AppInfoManager::lookupAppInfo(const QString &appPath)
enqueueJob(new AppInfoJob(appPath)); enqueueJob(new AppInfoJob(appPath));
} }
void AppInfoManager::lookupAppIcon(const QString &appPath, qint64 iconId)
{
enqueueJob(new AppIconJob(appPath, iconId));
}
void AppInfoManager::handleWorkerResult(WorkerJob *workerJob) void AppInfoManager::handleWorkerResult(WorkerJob *workerJob)
{ {
if (!aborted()) { if (!aborted()) {
const auto job = static_cast<AppInfoJob *>(workerJob); auto appJob = static_cast<AppBaseJob *>(workerJob);
const QString &appPath = appJob->appPath();
emit lookupFinished(job->appPath(), job->appInfo); switch (appJob->jobType()) {
case AppBaseJob::JobTypeInfo: {
auto job = static_cast<AppInfoJob *>(appJob);
emit lookupInfoFinished(appPath, job->appInfo);
} break;
case AppBaseJob::JobTypeIcon: {
auto job = static_cast<AppIconJob *>(appJob);
emit lookupIconFinished(appPath, job->image);
} break;
}
} }
delete workerJob; delete workerJob;
} }
void AppInfoManager::checkLookupFinished(const QString &appPath) void AppInfoManager::checkLookupInfoFinished(const QString &appPath)
{ {
AppInfo appInfo; AppInfo appInfo;
if (loadInfoFromDb(appPath, appInfo)) { if (loadInfoFromDb(appPath, appInfo)) {
emit lookupFinished(appPath, appInfo); emit lookupInfoFinished(appPath, appInfo);
} }
} }

View File

@ -37,14 +37,16 @@ public:
void deleteOldApps(int limitCount = 0); void deleteOldApps(int limitCount = 0);
signals: signals:
void lookupFinished(const QString &appPath, const AppInfo &appInfo); void lookupInfoFinished(const QString &appPath, const AppInfo &appInfo);
void lookupIconFinished(const QString &appPath, const QImage &image);
public slots: public slots:
virtual void lookupAppInfo(const QString &appPath); virtual void lookupAppInfo(const QString &appPath);
void lookupAppIcon(const QString &appPath, qint64 iconId);
void handleWorkerResult(WorkerJob *workerJob) override; void handleWorkerResult(WorkerJob *workerJob) override;
void checkLookupFinished(const QString &appPath); void checkLookupInfoFinished(const QString &appPath);
protected: protected:
WorkerObject *createWorker() override; WorkerObject *createWorker() override;

View File

@ -2,9 +2,10 @@
#include <QImage> #include <QImage>
#include "appiconjob.h"
#include "appinfo.h" #include "appinfo.h"
#include "appinfomanager.h"
#include "appinfojob.h" #include "appinfojob.h"
#include "appinfomanager.h"
#include "appinfoutil.h" #include "appinfoutil.h"
AppInfoWorker::AppInfoWorker(AppInfoManager *manager) : WorkerObject(manager) { } AppInfoWorker::AppInfoWorker(AppInfoManager *manager) : WorkerObject(manager) { }
@ -25,9 +26,25 @@ void AppInfoWorker::run()
void AppInfoWorker::doJob(WorkerJob *workerJob) void AppInfoWorker::doJob(WorkerJob *workerJob)
{ {
auto job = static_cast<AppInfoJob *>(workerJob); auto appJob = static_cast<AppBaseJob *>(workerJob);
const QString &appPath = job->appPath(); const QString &appPath = appJob->appPath();
switch (appJob->jobType()) {
case AppBaseJob::JobTypeInfo: {
auto job = static_cast<AppInfoJob *>(appJob);
loadAppInfo(job, appPath);
} break;
case AppBaseJob::JobTypeIcon: {
auto job = static_cast<AppIconJob *>(appJob);
loadAppIcon(job, appPath);
} break;
}
WorkerObject::doJob(workerJob);
}
void AppInfoWorker::loadAppInfo(AppInfoJob *job, const QString &appPath)
{
// Try to load from DB // Try to load from DB
AppInfo &appInfo = job->appInfo; AppInfo &appInfo = job->appInfo;
bool loadedFromDb = manager()->loadInfoFromDb(appPath, appInfo); bool loadedFromDb = manager()->loadInfoFromDb(appPath, appInfo);
@ -44,6 +61,10 @@ void AppInfoWorker::doJob(WorkerJob *workerJob)
manager()->saveToDb(appPath, appInfo, appIcon); manager()->saveToDb(appPath, appInfo, appIcon);
} }
}
WorkerObject::doJob(workerJob);
void AppInfoWorker::loadAppIcon(AppIconJob *job, const QString &appPath)
{
// Try to load from DB
job->image = manager()->loadIconFromDb(job->iconId());
} }

View File

@ -3,7 +3,9 @@
#include <util/worker/workerobject.h> #include <util/worker/workerobject.h>
class AppIconJob;
class AppInfo; class AppInfo;
class AppInfoJob;
class AppInfoManager; class AppInfoManager;
class AppInfoWorker : public WorkerObject class AppInfoWorker : public WorkerObject
@ -17,6 +19,10 @@ public:
protected: protected:
void doJob(WorkerJob *workerJob) override; void doJob(WorkerJob *workerJob) override;
private:
void loadAppInfo(AppInfoJob *job, const QString &appPath);
void loadAppIcon(AppIconJob *job, const QString &appPath);
}; };
#endif // APPINFOWORKER_H #endif // APPINFOWORKER_H

View File

@ -18,7 +18,7 @@ const char *const commandString(Command cmd)
CASE_STRING(Rpc_RpcManager_initClient) CASE_STRING(Rpc_RpcManager_initClient)
CASE_STRING(Rpc_AppInfoManager_lookupAppInfo) CASE_STRING(Rpc_AppInfoManager_lookupAppInfo)
CASE_STRING(Rpc_AppInfoManager_checkLookupFinished) CASE_STRING(Rpc_AppInfoManager_checkLookupInfoFinished)
CASE_STRING(Rpc_ConfManager_save) CASE_STRING(Rpc_ConfManager_save)
CASE_STRING(Rpc_ConfManager_addApp) CASE_STRING(Rpc_ConfManager_addApp)

View File

@ -17,7 +17,7 @@ enum Command : qint8 {
Rpc_RpcManager_initClient, Rpc_RpcManager_initClient,
Rpc_AppInfoManager_lookupAppInfo, Rpc_AppInfoManager_lookupAppInfo,
Rpc_AppInfoManager_checkLookupFinished, Rpc_AppInfoManager_checkLookupInfoFinished,
Rpc_ConfManager_save, Rpc_ConfManager_save,
Rpc_ConfManager_addApp, Rpc_ConfManager_addApp,

View File

@ -308,9 +308,9 @@ void RpcManager::setupAppInfoManagerSignals()
{ {
auto appInfoManager = IoC<AppInfoManager>(); auto appInfoManager = IoC<AppInfoManager>();
connect(appInfoManager, &AppInfoManager::lookupFinished, this, connect(appInfoManager, &AppInfoManager::lookupInfoFinished, this,
[&](const QString &appPath, const AppInfo & /*appInfo*/) { [&](const QString &appPath, const AppInfo & /*appInfo*/) {
invokeOnClients(Control::Rpc_AppInfoManager_checkLookupFinished, { appPath }); invokeOnClients(Control::Rpc_AppInfoManager_checkLookupInfoFinished, { appPath });
}); });
} }
@ -562,8 +562,8 @@ bool RpcManager::processAppInfoManagerRpc(const ProcessCommandArgs &p)
case Control::Rpc_AppInfoManager_lookupAppInfo: case Control::Rpc_AppInfoManager_lookupAppInfo:
appInfoManager->lookupAppInfo(p.args.value(0).toString()); appInfoManager->lookupAppInfo(p.args.value(0).toString());
return true; return true;
case Control::Rpc_AppInfoManager_checkLookupFinished: case Control::Rpc_AppInfoManager_checkLookupInfoFinished:
appInfoManager->checkLookupFinished(p.args.value(0).toString()); appInfoManager->checkLookupInfoFinished(p.args.value(0).toString());
return true; return true;
default: default:
return false; return false;