mirror of
https://github.com/tnodir/fort
synced 2024-11-15 03:56:18 +00:00
UI: Show app names & icons.
This commit is contained in:
parent
2aa2f70d1b
commit
a5d97fddd2
78
src/ui/3rdparty/sqlite/sqlitedb.cpp
vendored
78
src/ui/3rdparty/sqlite/sqlitedb.cpp
vendored
@ -1,8 +1,10 @@
|
||||
#include "sqlitedb.h"
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QBuffer>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QImage>
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
@ -59,7 +61,10 @@ QVariant SqliteDb::executeEx(const char *sql,
|
||||
bool *ok)
|
||||
{
|
||||
QVariantList list;
|
||||
|
||||
QStringList bindTexts;
|
||||
QList<QByteArray> bindDatas;
|
||||
|
||||
sqlite3_stmt *stmt = nullptr;
|
||||
int res;
|
||||
|
||||
@ -72,22 +77,29 @@ QVariant SqliteDb::executeEx(const char *sql,
|
||||
int index = 0;
|
||||
for (const QVariant &v : vars) {
|
||||
++index;
|
||||
switch (v.type()) {
|
||||
|
||||
const int vType = v.type();
|
||||
|
||||
switch (vType) {
|
||||
case QVariant::Invalid:
|
||||
res = sqlite3_bind_null(stmt, index);
|
||||
break;
|
||||
case QVariant::Bool:
|
||||
case QVariant::Int:
|
||||
case QVariant::UInt:
|
||||
res = sqlite3_bind_int(stmt, index, v.toInt());
|
||||
break;
|
||||
case QVariant::LongLong:
|
||||
case QVariant::ULongLong:
|
||||
res = sqlite3_bind_int64(stmt, index, v.toLongLong());
|
||||
break;
|
||||
case QVariant::Double:
|
||||
res = sqlite3_bind_double(stmt, index, v.toDouble());
|
||||
break;
|
||||
case QVariant::LongLong:
|
||||
res = sqlite3_bind_int64(stmt, index, v.toLongLong());
|
||||
break;
|
||||
case QVariant::String: {
|
||||
const QString text = v.toString();
|
||||
const int bytesCount = text.size() * int(sizeof(wchar_t));
|
||||
|
||||
bindTexts.append(text);
|
||||
|
||||
res = sqlite3_bind_text16(stmt, index, text.utf16(),
|
||||
@ -96,12 +108,37 @@ QVariant SqliteDb::executeEx(const char *sql,
|
||||
}
|
||||
default: {
|
||||
QByteArray data;
|
||||
QDataStream stream(data);
|
||||
stream << v;
|
||||
|
||||
// Write type
|
||||
QDataStream stream(&data, QIODevice::WriteOnly);
|
||||
stream << vType;
|
||||
|
||||
// Write content
|
||||
{
|
||||
QByteArray bufData;
|
||||
|
||||
QBuffer buf(&bufData);
|
||||
buf.open(QIODevice::WriteOnly);
|
||||
|
||||
switch (vType) {
|
||||
case QVariant::Image: {
|
||||
const QImage image = v.value<QImage>();
|
||||
image.save(&buf, "PNG");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
buf.close();
|
||||
stream << bufData;
|
||||
}
|
||||
|
||||
const char *bits = data.constData();
|
||||
const int bytesCount = data.size();
|
||||
|
||||
bindDatas.append(data);
|
||||
|
||||
res = sqlite3_bind_blob(stmt, index, bits,
|
||||
bytesCount, SQLITE_STATIC);
|
||||
}
|
||||
@ -135,7 +172,27 @@ QVariant SqliteDb::executeEx(const char *sql,
|
||||
|
||||
QByteArray data(bits, bytesCount);
|
||||
QDataStream stream(data);
|
||||
stream >> v;
|
||||
|
||||
// Load type
|
||||
int vType;
|
||||
stream >> vType;
|
||||
|
||||
// Load content
|
||||
{
|
||||
QByteArray bufData;
|
||||
stream >> bufData;
|
||||
|
||||
switch (vType) {
|
||||
case QVariant::Image: {
|
||||
QImage image;
|
||||
image.loadFromData(bufData, "PNG");
|
||||
v = image;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLITE_NULL:
|
||||
@ -156,7 +213,9 @@ QVariant SqliteDb::executeEx(const char *sql,
|
||||
*ok = (res == SQLITE_OK || res == SQLITE_ROW || res == SQLITE_DONE);
|
||||
}
|
||||
|
||||
return (list.size() == 1) ? list.at(0) : list;
|
||||
const int listSize = list.size();
|
||||
return (listSize == 0) ? QVariant()
|
||||
: (list.size() == 1) ? list.at(0) : list;
|
||||
}
|
||||
|
||||
qint64 SqliteDb::lastInsertRowid() const
|
||||
@ -248,7 +307,8 @@ bool SqliteDb::migrate(const QString &sqlDir, int version,
|
||||
|
||||
QFile file(filePath);
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
||||
qWarning() << "SQLite: Cannot open migration file" << filePath;
|
||||
qWarning() << "SQLite: Cannot open migration file" << filePath
|
||||
<< file.errorString();
|
||||
res = false;
|
||||
break;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
QT += core gui qml widgets
|
||||
QT += core gui qml quick widgets
|
||||
|
||||
CONFIG += c++11
|
||||
|
||||
@ -46,8 +46,10 @@ SOURCES += \
|
||||
task/taskupdatechecker.cpp \
|
||||
task/taskworker.cpp \
|
||||
translationmanager.cpp \
|
||||
util/app/appiconprovider.cpp \
|
||||
util/app/appinfo.cpp \
|
||||
util/app/appinfocache.cpp \
|
||||
util/app/appinfojob.cpp \
|
||||
util/app/appinfomanager.cpp \
|
||||
util/app/appinfoworker.cpp \
|
||||
util/app/apputil.cpp \
|
||||
@ -62,8 +64,8 @@ SOURCES += \
|
||||
util/nativeeventfilter.cpp \
|
||||
util/net/hostinfo.cpp \
|
||||
util/net/hostinfocache.cpp \
|
||||
util/net/hostinfojob.cpp \
|
||||
util/net/hostinfomanager.cpp \
|
||||
util/net/hostinfoworker.cpp \
|
||||
util/net/ip4range.cpp \
|
||||
util/net/netdownloader.cpp \
|
||||
util/net/netutil.cpp \
|
||||
@ -74,6 +76,7 @@ SOURCES += \
|
||||
util/window/widgetwindow.cpp \
|
||||
util/window/widgetwindowstatewatcher.cpp \
|
||||
util/window/windowstatewatcher.cpp \
|
||||
util/worker/workerjob.cpp \
|
||||
util/worker/workermanager.cpp \
|
||||
util/worker/workerobject.cpp
|
||||
|
||||
@ -113,8 +116,10 @@ HEADERS += \
|
||||
task/taskupdatechecker.h \
|
||||
task/taskworker.h \
|
||||
translationmanager.h \
|
||||
util/app/appiconprovider.h \
|
||||
util/app/appinfo.h \
|
||||
util/app/appinfocache.h \
|
||||
util/app/appinfojob.h \
|
||||
util/app/appinfomanager.h \
|
||||
util/app/appinfoworker.h \
|
||||
util/app/apputil.h \
|
||||
@ -129,8 +134,8 @@ HEADERS += \
|
||||
util/nativeeventfilter.h \
|
||||
util/net/hostinfo.h \
|
||||
util/net/hostinfocache.h \
|
||||
util/net/hostinfojob.h \
|
||||
util/net/hostinfomanager.h \
|
||||
util/net/hostinfoworker.h \
|
||||
util/net/ip4range.h \
|
||||
util/net/netdownloader.h \
|
||||
util/net/netutil.h \
|
||||
@ -141,6 +146,7 @@ HEADERS += \
|
||||
util/window/widgetwindow.h \
|
||||
util/window/widgetwindowstatewatcher.h \
|
||||
util/window/windowstatewatcher.h \
|
||||
util/worker/workerjob.h \
|
||||
util/worker/workermanager.h \
|
||||
util/worker/workerobject.h
|
||||
|
||||
@ -168,8 +174,8 @@ OTHER_FILES += \
|
||||
util/app/migrations/*.sql
|
||||
|
||||
RESOURCES += \
|
||||
db/migrations.qrc \
|
||||
util/app/migrations.qrc
|
||||
db/db-migrations.qrc \
|
||||
util/app/app-migrations.qrc
|
||||
|
||||
# Shadow Build: Copy i18n/ to build path
|
||||
!equals(PWD, $${OUT_PWD}) {
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "task/taskinfo.h"
|
||||
#include "task/taskmanager.h"
|
||||
#include "translationmanager.h"
|
||||
#include "util/app/appiconprovider.h"
|
||||
#include "util/app/appinfocache.h"
|
||||
#include "util/fileutil.h"
|
||||
#include "util/guiutil.h"
|
||||
@ -59,7 +60,8 @@ FortManager::FortManager(FortSettings *fortSettings,
|
||||
m_driverManager->driverWorker(), this)),
|
||||
m_nativeEventFilter(new NativeEventFilter(this)),
|
||||
m_hotKeyManager(new HotKeyManager(m_nativeEventFilter, this)),
|
||||
m_taskManager(new TaskManager(this, this))
|
||||
m_taskManager(new TaskManager(this, this)),
|
||||
m_appInfoCache(new AppInfoCache(this))
|
||||
{
|
||||
setupLogger();
|
||||
setupDatabaseManager();
|
||||
@ -219,6 +221,10 @@ bool FortManager::setupEngine()
|
||||
context->setContextProperty("fortManager", this);
|
||||
context->setContextProperty("driverManager", m_driverManager);
|
||||
context->setContextProperty("translationManager", TranslationManager::instance());
|
||||
context->setContextProperty("appInfoCache", m_appInfoCache);
|
||||
|
||||
m_engine->addImageProvider(AppIconProvider::id(),
|
||||
new AppIconProvider(m_appInfoCache->manager()));
|
||||
|
||||
m_engine->load(QUrl("qrc:/qml/main.qml"));
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
QT_FORWARD_DECLARE_CLASS(QQmlApplicationEngine)
|
||||
QT_FORWARD_DECLARE_CLASS(QSystemTrayIcon)
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(AppInfoCache)
|
||||
QT_FORWARD_DECLARE_CLASS(DatabaseManager)
|
||||
QT_FORWARD_DECLARE_CLASS(DriverManager)
|
||||
QT_FORWARD_DECLARE_CLASS(FirewallConf)
|
||||
@ -167,6 +168,7 @@ private:
|
||||
NativeEventFilter *m_nativeEventFilter;
|
||||
HotKeyManager *m_hotKeyManager;
|
||||
TaskManager *m_taskManager;
|
||||
AppInfoCache *m_appInfoCache;
|
||||
};
|
||||
|
||||
#endif // FORTMANAGER_H
|
||||
|
@ -9,10 +9,6 @@ ListView {
|
||||
readonly property bool hasCurrentItem:
|
||||
currentIndex >= 0 && currentIndex < count && !!currentItem
|
||||
|
||||
readonly property string currentItemText:
|
||||
(currentIndex >= 0 && currentIndex < count && currentItem)
|
||||
? currentItem.displayText : ""
|
||||
|
||||
Keys.onUpPressed: decrementCurrentIndex()
|
||||
Keys.onDownPressed: incrementCurrentIndex()
|
||||
|
||||
|
@ -15,12 +15,12 @@ BasePage {
|
||||
readonly property Item currentAppItem:
|
||||
appListView.hasCurrentItem ? appListView.currentItem : null
|
||||
readonly property string currentAppPath:
|
||||
(currentAppItem && currentAppItem.displayText) || ""
|
||||
(currentAppItem && currentAppItem.appPath) || ""
|
||||
|
||||
readonly property Item currentIpItem:
|
||||
ipListView.hasCurrentItem ? ipListView.currentItem : null
|
||||
readonly property string currentIpText:
|
||||
(currentIpItem && currentIpItem.displayText) || ""
|
||||
(currentIpItem && currentIpItem.ipAddress) || ""
|
||||
readonly property string currentHostName:
|
||||
(currentIpItem && currentIpItem.hostName) || ""
|
||||
|
||||
|
@ -18,7 +18,7 @@ BasePage {
|
||||
readonly property Item currentAppItem:
|
||||
appListView.hasCurrentItem ? appListView.currentItem : null
|
||||
readonly property string currentAppPath:
|
||||
(currentAppItem && currentAppItem.displayText) || ""
|
||||
(currentAppItem && currentAppItem.appPath) || ""
|
||||
|
||||
readonly property var trafCellWidths: [
|
||||
trafsContainer.width * 0.34,
|
||||
|
@ -1,5 +1,6 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../../controls"
|
||||
import com.fortfirewall 1.0
|
||||
|
||||
@ -13,25 +14,31 @@ ListViewControl {
|
||||
|
||||
onClicked: forceActiveFocus()
|
||||
|
||||
delegate: Row {
|
||||
delegate: RowLayout {
|
||||
id: appItem
|
||||
width: appListView.width
|
||||
spacing: 6
|
||||
|
||||
readonly property string displayText: display
|
||||
readonly property string appPath: display
|
||||
|
||||
readonly property var appInfo:
|
||||
appInfoCache.infoTrigger && appInfoCache.appInfo(appPath)
|
||||
|
||||
// TODO: Use SHGetFileInfo() to get app's display name and icon
|
||||
Image {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.verticalCenterOffset: 1
|
||||
source: (!appItem.displayText && emptyIcon)
|
||||
Layout.topMargin: 1
|
||||
Layout.preferredWidth: 22
|
||||
Layout.preferredHeight: 22
|
||||
source: (!appItem.appPath && emptyIcon)
|
||||
|| appInfo.iconPath
|
||||
|| "qrc:/images/application.png"
|
||||
}
|
||||
Label {
|
||||
font.pixelSize: 20
|
||||
Layout.fillWidth: true
|
||||
font.pixelSize: 18
|
||||
elide: Text.ElideRight
|
||||
text: (!appItem.displayText && emptyText)
|
||||
|| fileUtil.fileName(appItem.displayText)
|
||||
text: (!appItem.appPath && emptyText)
|
||||
|| appInfo.fileDescription
|
||||
|| fileUtil.fileName(appItem.appPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,14 +11,14 @@ ListViewControl {
|
||||
delegate: Label {
|
||||
width: ipListView.width
|
||||
elide: Text.ElideRight
|
||||
text: hostName || displayText
|
||||
text: hostName || ipAddress
|
||||
font.italic: !!hostName
|
||||
|
||||
readonly property string hostName:
|
||||
(firewallConf.resolveAddress
|
||||
&& hostInfoCache.hostTrigger
|
||||
&& hostInfoCache.hostName(displayText)) || ""
|
||||
&& hostInfoCache.hostName(ipAddress)) || ""
|
||||
|
||||
readonly property string displayText: display
|
||||
readonly property string ipAddress: display
|
||||
}
|
||||
}
|
||||
|
38
src/ui/util/app/appiconprovider.cpp
Normal file
38
src/ui/util/app/appiconprovider.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include "appiconprovider.h"
|
||||
|
||||
#include "appinfomanager.h"
|
||||
|
||||
AppIconProvider::AppIconProvider(AppInfoManager *manager) :
|
||||
QQuickImageProvider(QQuickImageProvider::Image),
|
||||
m_manager(manager)
|
||||
{
|
||||
}
|
||||
|
||||
QImage AppIconProvider::requestImage(const QString &id, QSize *size,
|
||||
const QSize &requestedSize)
|
||||
{
|
||||
Q_UNUSED(size)
|
||||
Q_UNUSED(requestedSize)
|
||||
|
||||
QImage icon;
|
||||
|
||||
bool ok;
|
||||
const qint64 iconId = id.toLongLong(&ok, 16);
|
||||
if (ok && iconId != 0) {
|
||||
icon = m_manager->loadIconFromDb(iconId);
|
||||
}
|
||||
|
||||
return icon.isNull() ? QImage(":/images/application.png")
|
||||
: icon;
|
||||
}
|
||||
|
||||
QString AppIconProvider::id()
|
||||
{
|
||||
return QLatin1String("app-icon");
|
||||
}
|
||||
|
||||
QString AppIconProvider::iconPath(qint64 iconId)
|
||||
{
|
||||
return QLatin1String("image://") + id()
|
||||
+ QString("/%1").arg(iconId, 0, 16);
|
||||
}
|
23
src/ui/util/app/appiconprovider.h
Normal file
23
src/ui/util/app/appiconprovider.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef APPICONPROVIDER_H
|
||||
#define APPICONPROVIDER_H
|
||||
|
||||
#include <QQuickImageProvider>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(AppInfoManager)
|
||||
|
||||
class AppIconProvider: public QQuickImageProvider
|
||||
{
|
||||
public:
|
||||
explicit AppIconProvider(AppInfoManager *manager);
|
||||
|
||||
QImage requestImage(const QString &id, QSize *size,
|
||||
const QSize &requestedSize) override;
|
||||
|
||||
static QString id();
|
||||
static QString iconPath(qint64 iconId);
|
||||
|
||||
private:
|
||||
AppInfoManager *m_manager;
|
||||
};
|
||||
|
||||
#endif // APPICONPROVIDER_H
|
@ -1 +1,8 @@
|
||||
#include "appinfo.h"
|
||||
|
||||
#include "appiconprovider.h"
|
||||
|
||||
QString AppInfo::iconPath() const
|
||||
{
|
||||
return AppIconProvider::iconPath(iconId);
|
||||
}
|
||||
|
@ -1,24 +1,27 @@
|
||||
#ifndef APPINFO_H
|
||||
#define APPINFO_H
|
||||
|
||||
#include <QPixmap>
|
||||
#include <QObject>
|
||||
|
||||
class AppInfo
|
||||
{
|
||||
Q_GADGET
|
||||
Q_PROPERTY(QString iconPath READ iconPath CONSTANT)
|
||||
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 iconPath() const;
|
||||
|
||||
public:
|
||||
qint64 iconId = 0;
|
||||
|
||||
QString fileDescription;
|
||||
QString companyName;
|
||||
QString productName;
|
||||
QString productVersion;
|
||||
|
||||
QPixmap icon;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(AppInfo)
|
||||
|
@ -17,7 +17,7 @@ AppInfoCache::AppInfoCache(QObject *parent) :
|
||||
this, &AppInfoCache::cacheChanged);
|
||||
}
|
||||
|
||||
AppInfo *AppInfoCache::appInfo(const QString &appPath)
|
||||
AppInfo AppInfoCache::appInfo(const QString &appPath)
|
||||
{
|
||||
AppInfo *appInfo = m_cache.object(appPath);
|
||||
|
||||
@ -25,10 +25,10 @@ AppInfo *AppInfoCache::appInfo(const QString &appPath)
|
||||
appInfo = new AppInfo();
|
||||
|
||||
m_cache.insert(appPath, appInfo, 1);
|
||||
m_manager->lookupApp(appPath);
|
||||
m_manager->lookupAppInfo(appPath);
|
||||
}
|
||||
|
||||
return appInfo;
|
||||
return *appInfo;
|
||||
}
|
||||
|
||||
void AppInfoCache::handleFinishedLookup(const QString &appPath,
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "appinfo.h"
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(AppIconProvider)
|
||||
QT_FORWARD_DECLARE_CLASS(AppInfoManager)
|
||||
|
||||
class AppInfoCache : public QObject
|
||||
@ -19,11 +20,13 @@ public:
|
||||
|
||||
bool infoTrigger() const { return true; }
|
||||
|
||||
AppInfoManager *manager() const { return m_manager; }
|
||||
|
||||
signals:
|
||||
void cacheChanged();
|
||||
|
||||
public slots:
|
||||
AppInfo *appInfo(const QString &appPath);
|
||||
AppInfo appInfo(const QString &appPath);
|
||||
|
||||
private slots:
|
||||
void handleFinishedLookup(const QString &appPath,
|
||||
|
6
src/ui/util/app/appinfojob.cpp
Normal file
6
src/ui/util/app/appinfojob.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
#include "appinfojob.h"
|
||||
|
||||
AppInfoJob::AppInfoJob(const QString &appPath) :
|
||||
WorkerJob(appPath)
|
||||
{
|
||||
}
|
18
src/ui/util/app/appinfojob.h
Normal file
18
src/ui/util/app/appinfojob.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef APPINFOJOB_H
|
||||
#define APPINFOJOB_H
|
||||
|
||||
#include "../worker/workerjob.h"
|
||||
#include "appinfo.h"
|
||||
|
||||
class AppInfoJob : public WorkerJob
|
||||
{
|
||||
public:
|
||||
explicit AppInfoJob(const QString &appPath);
|
||||
|
||||
QString appPath() const { return text; }
|
||||
|
||||
public:
|
||||
AppInfo appInfo;
|
||||
};
|
||||
|
||||
#endif // APPINFOJOB_H
|
@ -1,13 +1,116 @@
|
||||
#include "appinfomanager.h"
|
||||
|
||||
#include <QImage>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
#include "../fileutil.h"
|
||||
#include "appinfojob.h"
|
||||
#include "appinfoworker.h"
|
||||
#include "apputil.h"
|
||||
#include <sqlite/sqlitedb.h>
|
||||
#include <sqlite/sqlitestmt.h>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(CLOG_APPINFOCACHE)
|
||||
Q_LOGGING_CATEGORY(CLOG_APPINFOCACHE, "fort.appInfoWorker")
|
||||
|
||||
#define DATABASE_USER_VERSION 1
|
||||
|
||||
#define APP_CACHE_MAX_COUNT 2000
|
||||
|
||||
namespace {
|
||||
|
||||
const char * const sqlSelectAppInfo =
|
||||
"SELECT file_descr, company_name,"
|
||||
" product_name, product_ver, icon_id"
|
||||
" FROM app WHERE path = ?1;"
|
||||
;
|
||||
|
||||
const char * const sqlUpdateAppAccessTime =
|
||||
"UPDATE app"
|
||||
" SET access_time = datetime('now')"
|
||||
" WHERE path = ?1;"
|
||||
;
|
||||
|
||||
const char * const sqlSelectIconImage =
|
||||
"SELECT image FROM icon WHERE icon_id = ?1;"
|
||||
;
|
||||
|
||||
const char * const sqlSelectIconIdByHash =
|
||||
"SELECT icon_id FROM icon WHERE hash = ?1;"
|
||||
;
|
||||
|
||||
const char * const sqlInsertIcon =
|
||||
"INSERT INTO icon(ref_count, hash, image)"
|
||||
" VALUES(1, ?1, ?2);"
|
||||
;
|
||||
|
||||
const char * const sqlUpdateIconRefCount =
|
||||
"UPDATE icon"
|
||||
" SET ref_count = ref_count + ?2"
|
||||
" WHERE icon_id = ?1;"
|
||||
;
|
||||
|
||||
const char * const sqlInsertAppInfo =
|
||||
"INSERT INTO app(path, file_descr, company_name,"
|
||||
" product_name, product_ver, icon_id, access_time)"
|
||||
" VALUES(?1, ?2, ?3, ?4, ?5, ?6, datetime('now'));"
|
||||
;
|
||||
|
||||
const char * const sqlSelectAppCount =
|
||||
"SELECT count(*) FROM app;"
|
||||
;
|
||||
|
||||
const char * const sqlSelectAppOlds =
|
||||
"SELECT path, icon_id"
|
||||
" FROM app"
|
||||
" ORDER BY access_time DESC"
|
||||
" LIMIT ?1;"
|
||||
;
|
||||
|
||||
const char * const sqlDeleteIconIfNotUsed =
|
||||
"DELETE FROM icon"
|
||||
" WHERE icon_id = ?1 AND ref_count = 0;"
|
||||
;
|
||||
|
||||
const char * const sqlDeleteApp =
|
||||
"DELETE FROM app WHERE path = ?1;"
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
AppInfoManager::AppInfoManager(QObject *parent) :
|
||||
WorkerManager(parent)
|
||||
WorkerManager(parent),
|
||||
m_sqliteDb(new SqliteDb())
|
||||
{
|
||||
setMaxWorkersCount(1);
|
||||
|
||||
setupDb();
|
||||
}
|
||||
|
||||
AppInfoManager::~AppInfoManager()
|
||||
{
|
||||
delete m_sqliteDb;
|
||||
}
|
||||
|
||||
void AppInfoManager::setupDb()
|
||||
{
|
||||
const QString cachePath = FileUtil::appCacheLocation();
|
||||
|
||||
FileUtil::makePath(cachePath);
|
||||
|
||||
const QString filePath = cachePath + "/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;
|
||||
}
|
||||
}
|
||||
|
||||
WorkerObject *AppInfoManager::createWorker()
|
||||
@ -15,15 +118,183 @@ WorkerObject *AppInfoManager::createWorker()
|
||||
return new AppInfoWorker(this);
|
||||
}
|
||||
|
||||
void AppInfoManager::lookupApp(const QString &appPath)
|
||||
void AppInfoManager::lookupAppInfo(const QString &appPath)
|
||||
{
|
||||
enqueueJob(appPath);
|
||||
enqueueJob(new AppInfoJob(appPath));
|
||||
}
|
||||
|
||||
void AppInfoManager::handleWorkerResult(const QString &appPath,
|
||||
const QVariant &result)
|
||||
void AppInfoManager::handleWorkerResult(WorkerJob *workerJob)
|
||||
{
|
||||
auto appInfo = result.value<AppInfo>();
|
||||
if (!aborted()) {
|
||||
auto job = static_cast<AppInfoJob *>(workerJob);
|
||||
|
||||
emit lookupFinished(appPath, appInfo);
|
||||
emit lookupFinished(job->appPath(), job->appInfo);
|
||||
}
|
||||
|
||||
delete workerJob;
|
||||
}
|
||||
|
||||
bool AppInfoManager::loadInfoFromFs(const QString &appPath, AppInfo &appInfo)
|
||||
{
|
||||
return AppUtil::getInfo(appPath, appInfo);
|
||||
}
|
||||
|
||||
QImage AppInfoManager::loadIconFromFs(const QString &appPath)
|
||||
{
|
||||
return AppUtil::getIcon(appPath);
|
||||
}
|
||||
|
||||
bool AppInfoManager::loadInfoFromDb(const QString &appPath, AppInfo &appInfo)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
const QVariantList vars = QVariantList() << appPath;
|
||||
|
||||
// Load version info
|
||||
const int resultCount = 5;
|
||||
const QVariantList list = m_sqliteDb->executeEx(
|
||||
sqlSelectAppInfo, vars, resultCount)
|
||||
.toList();
|
||||
if (list.size() != resultCount)
|
||||
return false;
|
||||
|
||||
appInfo.fileDescription = list.at(0).toString();
|
||||
appInfo.companyName = list.at(1).toString();
|
||||
appInfo.productName = list.at(2).toString();
|
||||
appInfo.productVersion = list.at(3).toString();
|
||||
appInfo.iconId = list.at(4).toLongLong();
|
||||
|
||||
// Update last access time
|
||||
m_sqliteDb->executeEx(sqlUpdateAppAccessTime, vars);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QImage AppInfoManager::loadIconFromDb(qint64 iconId)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
const QVariant icon = m_sqliteDb->executeEx(
|
||||
sqlSelectIconImage, QVariantList() << iconId);
|
||||
|
||||
return icon.value<QImage>();
|
||||
}
|
||||
|
||||
bool AppInfoManager::saveToDb(const QString &appPath, AppInfo &appInfo,
|
||||
const QImage &appIcon)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
bool ok = true;
|
||||
|
||||
m_sqliteDb->beginTransaction();
|
||||
|
||||
// Save icon image
|
||||
QVariant iconId;
|
||||
{
|
||||
const uint iconHash = qHashBits(appIcon.constBits(),
|
||||
size_t(appIcon.sizeInBytes()));
|
||||
|
||||
iconId = m_sqliteDb->executeEx(sqlSelectIconIdByHash,
|
||||
QVariantList() << iconHash);
|
||||
if (iconId.isNull()) {
|
||||
m_sqliteDb->executeEx(sqlInsertIcon,
|
||||
QVariantList() << iconHash << appIcon,
|
||||
0, &ok);
|
||||
if (ok) {
|
||||
iconId = m_sqliteDb->lastInsertRowid();
|
||||
}
|
||||
} else {
|
||||
m_sqliteDb->executeEx(sqlUpdateIconRefCount,
|
||||
QVariantList() << iconId << +1,
|
||||
0, &ok);
|
||||
}
|
||||
}
|
||||
|
||||
// Save version info
|
||||
if (ok) {
|
||||
const QVariantList vars = QVariantList()
|
||||
<< appPath
|
||||
<< appInfo.fileDescription
|
||||
<< appInfo.companyName
|
||||
<< appInfo.productName
|
||||
<< appInfo.productVersion
|
||||
<< iconId
|
||||
;
|
||||
|
||||
m_sqliteDb->executeEx(sqlInsertAppInfo, vars, 0, &ok);
|
||||
}
|
||||
|
||||
m_sqliteDb->endTransaction(ok);
|
||||
|
||||
if (ok) {
|
||||
appInfo.iconId = iconId.toLongLong();
|
||||
|
||||
// Delete excess info
|
||||
const int appCount = m_sqliteDb->executeEx(sqlSelectAppCount).toInt();
|
||||
const int excessCount = appCount - APP_CACHE_MAX_COUNT;
|
||||
|
||||
if (excessCount > 0) {
|
||||
shrinkDb(excessCount);
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void AppInfoManager::shrinkDb(int excessCount)
|
||||
{
|
||||
QStringList appPaths;
|
||||
QHash<qint64, int> iconIds;
|
||||
|
||||
bool ok = false;
|
||||
|
||||
m_sqliteDb->beginTransaction();
|
||||
|
||||
// Get old app info list
|
||||
{
|
||||
SqliteStmt stmt;
|
||||
if (stmt.prepare(m_sqliteDb->db(), sqlSelectAppOlds,
|
||||
SqliteStmt::PreparePersistent)
|
||||
&& stmt.bindInt(1, excessCount)) {
|
||||
|
||||
while (stmt.step() == SqliteStmt::StepRow) {
|
||||
const QString appPath = stmt.columnText(0);
|
||||
appPaths.append(appPath);
|
||||
|
||||
const qint64 iconId = stmt.columnInt64(1);
|
||||
const int iconCount = iconIds.value(iconId);
|
||||
iconIds.insert(iconId, iconCount + 1);
|
||||
}
|
||||
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete old icons
|
||||
auto iconIt = iconIds.constBegin();
|
||||
while (iconIt != iconIds.constEnd()) {
|
||||
const qint64 iconId = iconIt.key();
|
||||
const int count = iconIt.value();
|
||||
|
||||
m_sqliteDb->executeEx(sqlUpdateIconRefCount,
|
||||
QVariantList() << iconId << -count,
|
||||
0, &ok);
|
||||
if (!ok) goto end;
|
||||
|
||||
m_sqliteDb->executeEx(sqlDeleteIconIfNotUsed,
|
||||
QVariantList() << iconId,
|
||||
0, &ok);
|
||||
if (!ok) goto end;
|
||||
}
|
||||
|
||||
// Delete old app infos
|
||||
for (const QString &path : appPaths) {
|
||||
m_sqliteDb->executeEx(sqlDeleteApp, QVariantList() << path,
|
||||
0, &ok);
|
||||
if (!ok) goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
m_sqliteDb->endTransaction(ok);
|
||||
}
|
||||
|
@ -1,27 +1,49 @@
|
||||
#ifndef APPINFOMANAGER_H
|
||||
#define APPINFOMANAGER_H
|
||||
|
||||
#include <QMutex>
|
||||
|
||||
#include "../worker/workermanager.h"
|
||||
#include "appinfo.h"
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(SqliteDb)
|
||||
|
||||
class AppInfoManager : public WorkerManager
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AppInfoManager(QObject *parent = nullptr);
|
||||
~AppInfoManager() override;
|
||||
|
||||
bool loadInfoFromFs(const QString &appPath, AppInfo &appInfo);
|
||||
QImage loadIconFromFs(const QString &appPath);
|
||||
|
||||
bool loadInfoFromDb(const QString &appPath, AppInfo &appInfo);
|
||||
QImage loadIconFromDb(qint64 iconId);
|
||||
|
||||
bool saveToDb(const QString &appPath, AppInfo &appInfo,
|
||||
const QImage &appIcon);
|
||||
|
||||
signals:
|
||||
void lookupFinished(const QString &appPath, const AppInfo appInfo);
|
||||
|
||||
public slots:
|
||||
void lookupApp(const QString &appPath);
|
||||
void lookupAppInfo(const QString &appPath);
|
||||
|
||||
void handleWorkerResult(const QString &appPath,
|
||||
const QVariant &result) override;
|
||||
void handleWorkerResult(WorkerJob *workerJob) override;
|
||||
|
||||
protected:
|
||||
WorkerObject *createWorker() override;
|
||||
|
||||
private:
|
||||
void setupDb();
|
||||
|
||||
void shrinkDb(int excessCount);
|
||||
|
||||
private:
|
||||
SqliteDb *m_sqliteDb;
|
||||
QMutex m_mutex;
|
||||
};
|
||||
|
||||
#endif // APPINFOMANAGER_H
|
||||
|
@ -1,277 +1,32 @@
|
||||
#include "appinfoworker.h"
|
||||
|
||||
#include <QImage>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
#include "../fileutil.h"
|
||||
#include "appinfo.h"
|
||||
#include "appinfomanager.h"
|
||||
#include "apputil.h"
|
||||
#include <sqlite/sqlitedb.h>
|
||||
#include <sqlite/sqlitestmt.h>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(CLOG_APPINFOCACHE)
|
||||
Q_LOGGING_CATEGORY(CLOG_APPINFOCACHE, "fort.appInfoWorker")
|
||||
|
||||
#define DATABASE_USER_VERSION 1
|
||||
|
||||
namespace {
|
||||
|
||||
const char * const sqlSelectAppInfo =
|
||||
"SELECT file_descr, company_name,"
|
||||
" product_name, product_ver, icon_id"
|
||||
" FROM app WHERE path = ?1;"
|
||||
;
|
||||
|
||||
const char * const sqlUpdateAppAccessTime =
|
||||
"UPDATE app"
|
||||
" SET access_time = datetime('now')"
|
||||
" WHERE path = ?1;"
|
||||
;
|
||||
|
||||
const char * const sqlSelectIconImage =
|
||||
"SELECT image FROM icon WHERE icon_id = ?1;"
|
||||
;
|
||||
|
||||
const char * const sqlSelectIconIdByHash =
|
||||
"SELECT icon_id FROM icon WHERE hash = ?1;"
|
||||
;
|
||||
|
||||
const char * const sqlInsertIcon =
|
||||
"INSERT INTO icon(hash, image)"
|
||||
" VALUES(?1, ?2);"
|
||||
;
|
||||
|
||||
const char * const sqlUpdateIconRefCount =
|
||||
"UPDATE icon"
|
||||
" SET ref_count = ref_count + ?2"
|
||||
" WHERE icon_id = ?1;"
|
||||
;
|
||||
|
||||
const char * const sqlInsertAppInfo =
|
||||
"INSERT INTO app(path, file_descr, company_name,"
|
||||
" product_name, product_ver, icon_id)"
|
||||
" VALUES(?1, ?2, ?3, ?4, ?5, ?6);"
|
||||
;
|
||||
|
||||
const char * const sqlSelectAppCount =
|
||||
"SELECT count(*) FROM app;"
|
||||
;
|
||||
|
||||
const char * const sqlSelectAppOlds =
|
||||
"SELECT path, icon_id"
|
||||
" FROM app"
|
||||
" ORDER BY access_time DESC"
|
||||
" LIMIT ?1;"
|
||||
;
|
||||
|
||||
const char * const sqlDeleteIconIfNotUsed =
|
||||
"DELETE FROM icon"
|
||||
" WHERE icon_id = ?1 AND ref_count = 0;"
|
||||
;
|
||||
|
||||
const char * const sqlDeleteApp =
|
||||
"DELETE FROM app WHERE path = ?1;"
|
||||
;
|
||||
|
||||
}
|
||||
#include "appinfojob.h"
|
||||
|
||||
AppInfoWorker::AppInfoWorker(AppInfoManager *manager) :
|
||||
WorkerObject(manager),
|
||||
m_sqliteDb(new SqliteDb())
|
||||
WorkerObject(manager)
|
||||
{
|
||||
setupDb();
|
||||
}
|
||||
|
||||
AppInfoWorker::~AppInfoWorker()
|
||||
AppInfoManager *AppInfoWorker::manager() const
|
||||
{
|
||||
delete m_sqliteDb;
|
||||
return static_cast<AppInfoManager *>(WorkerObject::manager());
|
||||
}
|
||||
|
||||
void AppInfoWorker::setupDb()
|
||||
void AppInfoWorker::doJob(WorkerJob *workerJob)
|
||||
{
|
||||
const QString cachePath = FileUtil::appCacheLocation() + "/cache";
|
||||
auto job = static_cast<AppInfoJob *>(workerJob);
|
||||
const QString &appPath = job->appPath();
|
||||
|
||||
FileUtil::makePath(cachePath);
|
||||
if (!manager()->loadInfoFromDb(appPath, job->appInfo)
|
||||
&& manager()->loadInfoFromFs(appPath, job->appInfo)) {
|
||||
const QImage appIcon = manager()->loadIconFromFs(appPath);
|
||||
|
||||
const QString filePath = cachePath + "/appinfocache.db";
|
||||
|
||||
if (!m_sqliteDb->open(filePath)) {
|
||||
qCritical(CLOG_APPINFOCACHE()) << "File open error:"
|
||||
<< filePath
|
||||
<< m_sqliteDb->errorMessage();
|
||||
return;
|
||||
manager()->saveToDb(appPath, job->appInfo, appIcon);
|
||||
}
|
||||
|
||||
if (!m_sqliteDb->migrate(":/appinfocache/migrations", DATABASE_USER_VERSION)) {
|
||||
qCritical(CLOG_APPINFOCACHE()) << "Migration error" << filePath;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void AppInfoWorker::doJob(const QString &appPath)
|
||||
{
|
||||
AppInfo appInfo;
|
||||
|
||||
if (!loadFromDb(appPath, appInfo)
|
||||
&& loadFromFs(appPath, appInfo)) {
|
||||
saveToDb(appPath, appInfo);
|
||||
}
|
||||
|
||||
if (aborted()) return;
|
||||
|
||||
manager()->handleWorkerResult(appPath, QVariant::fromValue(appInfo));
|
||||
}
|
||||
|
||||
bool AppInfoWorker::loadFromFs(const QString &appPath, AppInfo &appInfo)
|
||||
{
|
||||
return AppUtil::getInfo(appPath, appInfo);
|
||||
}
|
||||
|
||||
bool AppInfoWorker::loadFromDb(const QString &appPath, AppInfo &appInfo)
|
||||
{
|
||||
const QVariantList vars = QVariantList() << appPath;
|
||||
|
||||
// Load version info
|
||||
const int resultCount = 5;
|
||||
const QVariantList list = m_sqliteDb->executeEx(
|
||||
sqlSelectAppInfo, vars, resultCount)
|
||||
.toList();
|
||||
if (list.size() != resultCount)
|
||||
return false;
|
||||
|
||||
appInfo.fileDescription = list.at(0).toString();
|
||||
appInfo.companyName = list.at(1).toString();
|
||||
appInfo.productName = list.at(2).toString();
|
||||
appInfo.productVersion = list.at(3).toString();
|
||||
|
||||
// Update last access time
|
||||
m_sqliteDb->executeEx(sqlUpdateAppAccessTime, vars);
|
||||
|
||||
// Load icon image
|
||||
const QVariant iconId = list.at(4);
|
||||
const QVariant icon = m_sqliteDb->executeEx(
|
||||
sqlSelectIconImage, QVariantList() << iconId);
|
||||
|
||||
appInfo.icon = icon.value<QPixmap>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AppInfoWorker::saveToDb(const QString &appPath, const AppInfo &appInfo)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
m_sqliteDb->beginTransaction();
|
||||
|
||||
// Save icon image
|
||||
QVariant iconId;
|
||||
{
|
||||
const QPixmap pixmap = appInfo.icon;
|
||||
|
||||
const QImage image = pixmap.toImage();
|
||||
const uint iconHash = qHashBits(image.constBits(),
|
||||
size_t(image.sizeInBytes()));
|
||||
|
||||
iconId = m_sqliteDb->executeEx(sqlSelectIconIdByHash,
|
||||
QVariantList() << iconHash);
|
||||
if (iconId.isNull()) {
|
||||
m_sqliteDb->executeEx(sqlInsertIcon,
|
||||
QVariantList() << iconHash << pixmap,
|
||||
0, &ok);
|
||||
if (ok) {
|
||||
iconId = m_sqliteDb->lastInsertRowid();
|
||||
}
|
||||
} else {
|
||||
m_sqliteDb->executeEx(sqlUpdateIconRefCount,
|
||||
QVariantList() << iconId << +1,
|
||||
0, &ok);
|
||||
}
|
||||
}
|
||||
|
||||
// Save version info
|
||||
if (ok) {
|
||||
const QVariantList vars = QVariantList()
|
||||
<< appPath
|
||||
<< appInfo.fileDescription
|
||||
<< appInfo.companyName
|
||||
<< appInfo.productName
|
||||
<< appInfo.productVersion
|
||||
<< iconId
|
||||
;
|
||||
|
||||
m_sqliteDb->executeEx(sqlInsertAppInfo, vars, 0, &ok);
|
||||
}
|
||||
|
||||
m_sqliteDb->endTransaction(ok);
|
||||
|
||||
// Delete excess info
|
||||
if (ok) {
|
||||
const int appMaxCount = 2000;
|
||||
const int appCount = m_sqliteDb->executeEx(sqlSelectAppCount).toInt();
|
||||
const int excessCount = appCount - appMaxCount;
|
||||
|
||||
if (excessCount > 0) {
|
||||
shrinkDb(excessCount);
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void AppInfoWorker::shrinkDb(int excessCount)
|
||||
{
|
||||
QStringList appPaths;
|
||||
QHash<qint64, int> iconIds;
|
||||
|
||||
bool ok = false;
|
||||
|
||||
m_sqliteDb->beginTransaction();
|
||||
|
||||
// Get old app info list
|
||||
{
|
||||
SqliteStmt stmt;
|
||||
if (stmt.prepare(m_sqliteDb->db(), sqlSelectAppOlds,
|
||||
SqliteStmt::PreparePersistent)
|
||||
&& stmt.bindInt(1, excessCount)) {
|
||||
|
||||
while (stmt.step() == SqliteStmt::StepRow) {
|
||||
const QString appPath = stmt.columnText(0);
|
||||
appPaths.append(appPath);
|
||||
|
||||
const qint64 iconId = stmt.columnInt64(1);
|
||||
const int iconCount = iconIds.value(iconId);
|
||||
iconIds.insert(iconId, iconCount + 1);
|
||||
}
|
||||
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete old icons
|
||||
auto iconIt = iconIds.constBegin();
|
||||
while (iconIt != iconIds.constEnd()) {
|
||||
const qint64 iconId = iconIt.key();
|
||||
const int count = iconIt.value();
|
||||
|
||||
m_sqliteDb->executeEx(sqlUpdateIconRefCount,
|
||||
QVariantList() << iconId << -count,
|
||||
0, &ok);
|
||||
if (!ok) goto end;
|
||||
|
||||
m_sqliteDb->executeEx(sqlDeleteIconIfNotUsed,
|
||||
QVariantList() << iconId,
|
||||
0, &ok);
|
||||
if (!ok) goto end;
|
||||
}
|
||||
|
||||
// Delete old app infos
|
||||
for (const QString &path : appPaths) {
|
||||
m_sqliteDb->executeEx(sqlDeleteApp, QVariantList() << path,
|
||||
0, &ok);
|
||||
if (!ok) goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
m_sqliteDb->endTransaction(ok);
|
||||
WorkerObject::doJob(workerJob);
|
||||
}
|
||||
|
@ -5,28 +5,16 @@
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(AppInfo)
|
||||
QT_FORWARD_DECLARE_CLASS(AppInfoManager)
|
||||
QT_FORWARD_DECLARE_CLASS(SqliteDb)
|
||||
|
||||
class AppInfoWorker : public WorkerObject
|
||||
{
|
||||
public:
|
||||
explicit AppInfoWorker(AppInfoManager *manager);
|
||||
~AppInfoWorker() override;
|
||||
|
||||
AppInfoManager *manager() const;
|
||||
|
||||
protected:
|
||||
void doJob(const QString &appPath) override;
|
||||
|
||||
private:
|
||||
void setupDb();
|
||||
|
||||
bool loadFromFs(const QString &appPath, AppInfo &appInfo);
|
||||
|
||||
bool loadFromDb(const QString &appPath, AppInfo &appInfo);
|
||||
bool saveToDb(const QString &appPath, const AppInfo &appInfo);
|
||||
void shrinkDb(int excessCount);
|
||||
|
||||
private:
|
||||
SqliteDb *m_sqliteDb;
|
||||
void doJob(WorkerJob *workerJob) override;
|
||||
};
|
||||
|
||||
#endif // APPINFOWORKER_H
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "apputil.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QPixmap>
|
||||
|
||||
#include <comdef.h>
|
||||
#include <commctrl.h>
|
||||
@ -45,7 +46,7 @@ QPixmap extractShellIcon(const QString &appPath)
|
||||
const HRESULT hr = SHGetFileInfoW(appPathW, 0, &info,
|
||||
sizeof(SHFILEINFOW), flags);
|
||||
if (SUCCEEDED(hr)) {
|
||||
pixmap = pixmapFromImageList(SHIL_JUMBO, info);
|
||||
pixmap = pixmapFromImageList(SHIL_EXTRALARGE, info);
|
||||
}
|
||||
|
||||
return pixmap;
|
||||
@ -124,9 +125,11 @@ bool extractVersionInfo(const QString &appPath, AppInfo &appInfo)
|
||||
|
||||
bool AppUtil::getInfo(const QString &appPath, AppInfo &appInfo)
|
||||
{
|
||||
if (extractVersionInfo(appPath, appInfo)) {
|
||||
appInfo.icon = extractShellIcon(appPath);
|
||||
return true;
|
||||
return extractVersionInfo(appPath, appInfo);
|
||||
}
|
||||
return false;
|
||||
|
||||
QImage AppUtil::getIcon(const QString &appPath)
|
||||
{
|
||||
return extractShellIcon(appPath)
|
||||
.toImage();
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define APPUTIL_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QImage>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(AppInfo)
|
||||
|
||||
@ -9,6 +10,7 @@ class AppUtil
|
||||
{
|
||||
public:
|
||||
static bool getInfo(const QString &appPath, AppInfo &appInfo);
|
||||
static QImage getIcon(const QString &appPath);
|
||||
};
|
||||
|
||||
#endif // APPUTIL_H
|
||||
|
@ -2,21 +2,21 @@ PRAGMA user_version = 1;
|
||||
|
||||
PRAGMA journal_mode = WAL;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS app(
|
||||
CREATE TABLE app(
|
||||
path TEXT PRIMARY KEY,
|
||||
file_descr TEXT,
|
||||
company_name TEXT,
|
||||
product_name TEXT,
|
||||
product_ver TEXT,
|
||||
icon_id INTEGER,
|
||||
access_time DATETIME DEFAULT datetime('now')
|
||||
access_time DATETIME
|
||||
) WITHOUT ROWID;
|
||||
|
||||
CREATE INDEX idx_app_access_time ON app(access_time);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS icon(
|
||||
CREATE TABLE icon(
|
||||
icon_id INTEGER PRIMARY KEY,
|
||||
ref_count INTEGER NOT NULL DEFAULT 1,
|
||||
ref_count INTEGER NOT NULL,
|
||||
hash INTEGER NOT NULL,
|
||||
image BLOB NOT NULL
|
||||
);
|
||||
|
@ -70,15 +70,16 @@ void Logger::setPath(const QString &path)
|
||||
|
||||
bool Logger::openLogFile()
|
||||
{
|
||||
const QString filename = QLatin1String(LOGGER_FILE_PREFIX)
|
||||
const QString fileName = QLatin1String(LOGGER_FILE_PREFIX)
|
||||
+ DateUtil::now().toString("yyyy-MM-dd_HH-mm-ss_zzz")
|
||||
+ QLatin1String(LOGGER_FILE_SUFFIX);
|
||||
|
||||
m_file.setFileName(m_dir.filePath(filename));
|
||||
m_file.setFileName(m_dir.filePath(fileName));
|
||||
|
||||
if (!m_file.open(QIODevice::WriteOnly | QIODevice::Text
|
||||
| QIODevice::Truncate)) {
|
||||
qWarning() << "Cannot open log file: " << m_file.errorString();
|
||||
qWarning() << "Cannot open log file: " << m_file.fileName()
|
||||
<< m_file.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
13
src/ui/util/net/hostinfojob.cpp
Normal file
13
src/ui/util/net/hostinfojob.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "hostinfojob.h"
|
||||
|
||||
#include "netutil.h"
|
||||
|
||||
HostInfoJob::HostInfoJob(const QString &address) :
|
||||
WorkerJob(address)
|
||||
{
|
||||
}
|
||||
|
||||
void HostInfoJob::doJob()
|
||||
{
|
||||
hostName = NetUtil::getHostName(address());
|
||||
}
|
19
src/ui/util/net/hostinfojob.h
Normal file
19
src/ui/util/net/hostinfojob.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef HOSTINFOJOB_H
|
||||
#define HOSTINFOJOB_H
|
||||
|
||||
#include "../worker/workerjob.h"
|
||||
|
||||
class HostInfoJob : public WorkerJob
|
||||
{
|
||||
public:
|
||||
explicit HostInfoJob(const QString &address);
|
||||
|
||||
QString address() const { return text; }
|
||||
|
||||
void doJob() override;
|
||||
|
||||
public:
|
||||
QString hostName;
|
||||
};
|
||||
|
||||
#endif // HOSTINFOJOB_H
|
@ -1,6 +1,6 @@
|
||||
#include "hostinfomanager.h"
|
||||
|
||||
#include "hostinfoworker.h"
|
||||
#include "hostinfojob.h"
|
||||
|
||||
HostInfoManager::HostInfoManager(QObject *parent) :
|
||||
WorkerManager(parent)
|
||||
@ -10,18 +10,18 @@ HostInfoManager::HostInfoManager(QObject *parent) :
|
||||
QSysInfo::machineHostName(); // Initialize ws2_32.dll
|
||||
}
|
||||
|
||||
WorkerObject *HostInfoManager::createWorker()
|
||||
{
|
||||
return new HostInfoWorker(this);
|
||||
}
|
||||
|
||||
void HostInfoManager::lookupHost(const QString &address)
|
||||
{
|
||||
enqueueJob(address);
|
||||
enqueueJob(new HostInfoJob(address));
|
||||
}
|
||||
|
||||
void HostInfoManager::handleWorkerResult(const QString &address,
|
||||
const QVariant &hostName)
|
||||
void HostInfoManager::handleWorkerResult(WorkerJob *workerJob)
|
||||
{
|
||||
emit lookupFinished(address, hostName.toString());
|
||||
if (!aborted()) {
|
||||
auto job = static_cast<HostInfoJob *>(workerJob);
|
||||
|
||||
emit lookupFinished(job->address(), job->hostName);
|
||||
}
|
||||
|
||||
delete workerJob;
|
||||
}
|
||||
|
@ -16,11 +16,7 @@ signals:
|
||||
public slots:
|
||||
void lookupHost(const QString &address);
|
||||
|
||||
void handleWorkerResult(const QString &address,
|
||||
const QVariant &hostName) override;
|
||||
|
||||
protected:
|
||||
WorkerObject *createWorker() override;
|
||||
void handleWorkerResult(WorkerJob *workerJob) override;
|
||||
};
|
||||
|
||||
#endif // HOSTINFOMANAGER_H
|
||||
|
@ -1,18 +0,0 @@
|
||||
#include "hostinfoworker.h"
|
||||
|
||||
#include "hostinfomanager.h"
|
||||
#include "netutil.h"
|
||||
|
||||
HostInfoWorker::HostInfoWorker(HostInfoManager *manager) :
|
||||
WorkerObject(manager)
|
||||
{
|
||||
}
|
||||
|
||||
void HostInfoWorker::doJob(const QString &address)
|
||||
{
|
||||
const QString hostName = NetUtil::getHostName(address);
|
||||
|
||||
if (aborted()) return;
|
||||
|
||||
manager()->handleWorkerResult(address, hostName);
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
#ifndef HOSTINFOWORKER_H
|
||||
#define HOSTINFOWORKER_H
|
||||
|
||||
#include "../worker/workerobject.h"
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(HostInfoManager)
|
||||
|
||||
class HostInfoWorker : public WorkerObject
|
||||
{
|
||||
public:
|
||||
explicit HostInfoWorker(HostInfoManager *manager);
|
||||
|
||||
protected:
|
||||
void doJob(const QString &address) override;
|
||||
};
|
||||
|
||||
#endif // HOSTINFOWORKER_H
|
6
src/ui/util/worker/workerjob.cpp
Normal file
6
src/ui/util/worker/workerjob.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
#include "workerjob.h"
|
||||
|
||||
WorkerJob::WorkerJob(const QString &_text) :
|
||||
text(_text)
|
||||
{
|
||||
}
|
18
src/ui/util/worker/workerjob.h
Normal file
18
src/ui/util/worker/workerjob.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef WORKERJOB_H
|
||||
#define WORKERJOB_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class WorkerJob
|
||||
{
|
||||
public:
|
||||
explicit WorkerJob(const QString &_text);
|
||||
virtual ~WorkerJob() {}
|
||||
|
||||
virtual void doJob() {}
|
||||
|
||||
public:
|
||||
QString text;
|
||||
};
|
||||
|
||||
#endif // WORKERJOB_H
|
@ -26,7 +26,7 @@ void WorkerManager::setupWorker()
|
||||
|
||||
if (workersCount != 0
|
||||
&& (workersCount >= maxWorkersCount()
|
||||
|| m_queue.isEmpty()))
|
||||
|| m_jobQueue.isEmpty()))
|
||||
return;
|
||||
|
||||
WorkerObject *worker = createWorker(); // autoDelete = true
|
||||
@ -46,11 +46,16 @@ void WorkerManager::workerFinished(WorkerObject *worker)
|
||||
}
|
||||
}
|
||||
|
||||
WorkerObject *WorkerManager::createWorker()
|
||||
{
|
||||
return new WorkerObject(this);
|
||||
}
|
||||
|
||||
void WorkerManager::clear()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
m_queue.clear();
|
||||
m_jobQueue.clear();
|
||||
}
|
||||
|
||||
void WorkerManager::abort()
|
||||
@ -59,42 +64,35 @@ void WorkerManager::abort()
|
||||
|
||||
m_aborted = true;
|
||||
|
||||
if (!m_workers.isEmpty()) {
|
||||
for (WorkerObject *worker : m_workers) {
|
||||
worker->abort();
|
||||
}
|
||||
|
||||
m_waitCondition.wakeAll();
|
||||
|
||||
do {
|
||||
while (!m_workers.isEmpty()) {
|
||||
m_waitCondition.wait(&m_mutex);
|
||||
} while (!m_workers.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
void WorkerManager::enqueueJob(const QString &job)
|
||||
void WorkerManager::enqueueJob(WorkerJob *job)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
setupWorker();
|
||||
|
||||
m_queue.enqueue(job);
|
||||
m_jobQueue.enqueue(job);
|
||||
|
||||
m_waitCondition.wakeOne();
|
||||
}
|
||||
|
||||
bool WorkerManager::dequeueJob(QString &job)
|
||||
WorkerJob *WorkerManager::dequeueJob()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
while (!m_aborted && m_queue.isEmpty()) {
|
||||
while (!m_aborted && m_jobQueue.isEmpty()) {
|
||||
if (!m_waitCondition.wait(&m_mutex, WORKER_TIMEOUT_MSEC))
|
||||
break; // timed out
|
||||
}
|
||||
|
||||
if (m_aborted || m_queue.isEmpty())
|
||||
return false;
|
||||
if (m_aborted || m_jobQueue.isEmpty())
|
||||
return nullptr;
|
||||
|
||||
job = m_queue.dequeue();
|
||||
return true;
|
||||
return m_jobQueue.dequeue();
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <QVariant>
|
||||
#include <QWaitCondition>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(WorkerJob)
|
||||
QT_FORWARD_DECLARE_CLASS(WorkerObject)
|
||||
|
||||
class WorkerManager : public QObject
|
||||
@ -26,22 +27,22 @@ signals:
|
||||
public slots:
|
||||
void clear();
|
||||
|
||||
void enqueueJob(const QString &job);
|
||||
bool dequeueJob(QString &job);
|
||||
void enqueueJob(WorkerJob *job);
|
||||
WorkerJob *dequeueJob();
|
||||
|
||||
void workerFinished(WorkerObject *worker);
|
||||
|
||||
virtual void handleWorkerResult(const QString &job,
|
||||
const QVariant &result) = 0;
|
||||
virtual void handleWorkerResult(WorkerJob *job) = 0;
|
||||
|
||||
protected:
|
||||
virtual WorkerObject *createWorker() = 0;
|
||||
virtual WorkerObject *createWorker();
|
||||
|
||||
bool aborted() const { return m_aborted; }
|
||||
void abort();
|
||||
|
||||
private:
|
||||
void setupWorker();
|
||||
|
||||
void abort();
|
||||
|
||||
private:
|
||||
volatile bool m_aborted;
|
||||
|
||||
@ -49,7 +50,7 @@ private:
|
||||
|
||||
QList<WorkerObject *> m_workers;
|
||||
|
||||
QQueue<QString> m_queue;
|
||||
QQueue<WorkerJob *> m_jobQueue;
|
||||
|
||||
QMutex m_mutex;
|
||||
QWaitCondition m_waitCondition;
|
||||
|
@ -1,19 +1,18 @@
|
||||
#include "workerobject.h"
|
||||
|
||||
#include "workerjob.h"
|
||||
#include "workermanager.h"
|
||||
|
||||
WorkerObject::WorkerObject(WorkerManager *manager) :
|
||||
m_aborted(false),
|
||||
m_manager(manager)
|
||||
{
|
||||
}
|
||||
|
||||
void WorkerObject::run()
|
||||
{
|
||||
while (!aborted()) {
|
||||
QString job;
|
||||
|
||||
if (!manager()->dequeueJob(job))
|
||||
for (; ; ) {
|
||||
WorkerJob *job = manager()->dequeueJob();
|
||||
if (job == nullptr)
|
||||
break;
|
||||
|
||||
doJob(job);
|
||||
@ -21,3 +20,10 @@ void WorkerObject::run()
|
||||
|
||||
manager()->workerFinished(this);
|
||||
}
|
||||
|
||||
void WorkerObject::doJob(WorkerJob *job)
|
||||
{
|
||||
job->doJob();
|
||||
|
||||
manager()->handleWorkerResult(job);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <QObject>
|
||||
#include <QRunnable>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(WorkerJob)
|
||||
QT_FORWARD_DECLARE_CLASS(WorkerManager)
|
||||
|
||||
class WorkerObject : public QRunnable
|
||||
@ -13,17 +14,12 @@ public:
|
||||
|
||||
WorkerManager *manager() const { return m_manager; }
|
||||
|
||||
bool aborted() const { return m_aborted; }
|
||||
virtual void abort() { m_aborted = true; }
|
||||
|
||||
void run() override;
|
||||
|
||||
protected:
|
||||
virtual void doJob(const QString &job) = 0;
|
||||
virtual void doJob(WorkerJob *job);
|
||||
|
||||
private:
|
||||
volatile bool m_aborted;
|
||||
|
||||
WorkerManager *m_manager;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user