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
SOURCES += \
appinfo/appbasejob.cpp \
appinfo/appiconjob.cpp \
appinfo/appinfo.cpp \
appinfo/appinfocache.cpp \
appinfo/appinfojob.cpp \
@ -175,6 +177,8 @@ SOURCES += \
util/worker/workerobject.cpp
HEADERS += \
appinfo/appbasejob.h \
appinfo/appiconjob.h \
appinfo/appinfo.h \
appinfo/appinfocache.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()
{
connect(IoC<AppInfoManager>(), &AppInfoManager::lookupFinished, this,
&AppInfoCache::handleFinishedLookup);
connect(IoC<AppInfoManager>(), &AppInfoManager::lookupInfoFinished, this,
&AppInfoCache::handleFinishedInfoLookup);
connect(IoC<AppInfoManager>(), &AppInfoManager::lookupIconFinished, this,
&AppInfoCache::handleFinishedIconLookup);
}
void AppInfoCache::tearDown()
@ -24,11 +26,6 @@ void AppInfoCache::tearDown()
disconnect(IoC<AppInfoManager>());
}
QImage AppInfoCache::appImage(const AppInfo &info) const
{
return IoC<AppInfoManager>()->loadIconFromDb(info.iconId);
}
QString AppInfoCache::appName(const QString &appPath)
{
AppInfo appInfo = this->appInfo(appPath);
@ -45,13 +42,12 @@ QIcon AppInfoCache::appIcon(const QString &appPath, const QString &nullIconPath)
return pixmap;
const auto info = appInfo(appPath);
const auto image = appImage(info);
if (!image.isNull()) {
pixmap = QPixmap::fromImage(image);
} else {
pixmap = IconCache::file(nullIconPath.isEmpty() ? ":/icons/application.png" : nullIconPath);
if (info.isValid()) {
IoC<AppInfoManager>()->lookupAppIcon(appPath, info.iconId);
}
pixmap = IconCache::file(!nullIconPath.isEmpty() ? nullIconPath : ":/icons/application.png");
IconCache::insert(appPath, pixmap);
return pixmap;
@ -86,7 +82,7 @@ AppInfo AppInfoCache::appInfo(const QString &appPath)
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);
if (!appInfo)
@ -99,6 +95,16 @@ void AppInfoCache::handleFinishedLookup(const QString &appPath, const AppInfo &i
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()
{
m_triggerTimer.startTrigger();

View File

@ -19,7 +19,6 @@ public:
void setUp() override;
void tearDown() override;
QImage appImage(const AppInfo &info) const;
QString appName(const QString &appPath);
QIcon appIcon(const QString &appPath, const QString &nullIconPath = QString());
@ -29,7 +28,8 @@ signals:
void cacheChanged();
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:
void emitCacheChanged();

View File

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

View File

@ -6,6 +6,7 @@
#include <sqlite/sqlitedb.h>
#include <sqlite/sqlitestmt.h>
#include "appiconjob.h"
#include "appinfojob.h"
#include "appinfoutil.h"
#include "appinfoworker.h"
@ -96,22 +97,37 @@ void AppInfoManager::lookupAppInfo(const QString &appPath)
enqueueJob(new AppInfoJob(appPath));
}
void AppInfoManager::lookupAppIcon(const QString &appPath, qint64 iconId)
{
enqueueJob(new AppIconJob(appPath, iconId));
}
void AppInfoManager::handleWorkerResult(WorkerJob *workerJob)
{
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;
}
void AppInfoManager::checkLookupFinished(const QString &appPath)
void AppInfoManager::checkLookupInfoFinished(const QString &appPath)
{
AppInfo 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);
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:
virtual void lookupAppInfo(const QString &appPath);
void lookupAppIcon(const QString &appPath, qint64 iconId);
void handleWorkerResult(WorkerJob *workerJob) override;
void checkLookupFinished(const QString &appPath);
void checkLookupInfoFinished(const QString &appPath);
protected:
WorkerObject *createWorker() override;

View File

@ -2,9 +2,10 @@
#include <QImage>
#include "appiconjob.h"
#include "appinfo.h"
#include "appinfomanager.h"
#include "appinfojob.h"
#include "appinfomanager.h"
#include "appinfoutil.h"
AppInfoWorker::AppInfoWorker(AppInfoManager *manager) : WorkerObject(manager) { }
@ -25,9 +26,25 @@ void AppInfoWorker::run()
void AppInfoWorker::doJob(WorkerJob *workerJob)
{
auto job = static_cast<AppInfoJob *>(workerJob);
const QString &appPath = job->appPath();
auto appJob = static_cast<AppBaseJob *>(workerJob);
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
AppInfo &appInfo = job->appInfo;
bool loadedFromDb = manager()->loadInfoFromDb(appPath, appInfo);
@ -44,6 +61,10 @@ void AppInfoWorker::doJob(WorkerJob *workerJob)
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>
class AppIconJob;
class AppInfo;
class AppInfoJob;
class AppInfoManager;
class AppInfoWorker : public WorkerObject
@ -17,6 +19,10 @@ public:
protected:
void doJob(WorkerJob *workerJob) override;
private:
void loadAppInfo(AppInfoJob *job, const QString &appPath);
void loadAppIcon(AppIconJob *job, const QString &appPath);
};
#endif // APPINFOWORKER_H

View File

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

View File

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

View File

@ -308,9 +308,9 @@ void RpcManager::setupAppInfoManagerSignals()
{
auto appInfoManager = IoC<AppInfoManager>();
connect(appInfoManager, &AppInfoManager::lookupFinished, this,
connect(appInfoManager, &AppInfoManager::lookupInfoFinished, this,
[&](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:
appInfoManager->lookupAppInfo(p.args.value(0).toString());
return true;
case Control::Rpc_AppInfoManager_checkLookupFinished:
appInfoManager->checkLookupFinished(p.args.value(0).toString());
case Control::Rpc_AppInfoManager_checkLookupInfoFinished:
appInfoManager->checkLookupInfoFinished(p.args.value(0).toString());
return true;
default:
return false;