diff --git a/src/ui/FortFirewall.pro b/src/ui/FortFirewall.pro index 24d13f40..868e81c9 100644 --- a/src/ui/FortFirewall.pro +++ b/src/ui/FortFirewall.pro @@ -24,6 +24,7 @@ SOURCES += \ log/logentrystattraf.cpp \ log/logmanager.cpp \ log/model/appblockedmodel.cpp \ + log/model/appstatmodel.cpp \ log/model/iplistmodel.cpp \ log/model/stringlistmodel.cpp \ mainwindow.cpp \ @@ -65,6 +66,7 @@ HEADERS += \ log/logentrystattraf.h \ log/logmanager.h \ log/model/appblockedmodel.h \ + log/model/appstatmodel.h \ log/model/iplistmodel.h \ log/model/stringlistmodel.h \ mainwindow.h \ diff --git a/src/ui/db/databasemanager.cpp b/src/ui/db/databasemanager.cpp index 782857bd..363a2fb0 100644 --- a/src/ui/db/databasemanager.cpp +++ b/src/ui/db/databasemanager.cpp @@ -41,16 +41,16 @@ bool DatabaseManager::initialize() return fileExists || createTables(); } -void DatabaseManager::handleProcNew(const QString &appPath) +void DatabaseManager::addApp(const QString &appPath, bool &isNew) { - const qint64 appId = getAppId(appPath); + const qint64 appId = getAppId(appPath, isNew); m_appPaths.append(appPath); m_appIds.append(appId); } -void DatabaseManager::handleStatTraf(quint16 procCount, const quint8 *procBits, - const quint32 *trafBytes) +void DatabaseManager::addTraffic(quint16 procCount, const quint8 *procBits, + const quint32 *trafBytes) { QVector delProcIndexes; @@ -194,7 +194,7 @@ bool DatabaseManager::createTables() return res; } -qint64 DatabaseManager::getAppId(const QString &appPath) +qint64 DatabaseManager::getAppId(const QString &appPath, bool &isNew) { qint64 appId = 0; @@ -212,12 +212,15 @@ qint64 DatabaseManager::getAppId(const QString &appPath) // Create new one if (!appId) { SqliteStmt *stmt = getSqliteStmt(DatabaseSql::sqlInsertAppId); + const qint64 unixTime = QDateTime::currentSecsSinceEpoch(); stmt->bindText(1, appPath); - stmt->bindInt64(2, QDateTime::currentSecsSinceEpoch()); + stmt->bindInt64(2, unixTime); + stmt->bindInt64(3, unixTime); if (stmt->step() == SqliteStmt::StepDone) { appId = m_sqliteDb->lastInsertRowid(); + isNew = true; } stmt->reset(); } @@ -225,6 +228,19 @@ qint64 DatabaseManager::getAppId(const QString &appPath) return appId; } +QStringList DatabaseManager::getAppList() +{ + QStringList list; + + SqliteStmt *stmt = getSqliteStmt(DatabaseSql::sqlSelectAppPaths); + while (stmt->step() == SqliteStmt::StepRow) { + list.append(stmt->columnText()); + } + stmt->reset(); + + return list; +} + SqliteStmt *DatabaseManager::getSqliteStmt(const char *sql) { SqliteStmt *stmt = m_sqliteStmts.value(sql); diff --git a/src/ui/db/databasemanager.h b/src/ui/db/databasemanager.h index d8028ff3..f07012a7 100644 --- a/src/ui/db/databasemanager.h +++ b/src/ui/db/databasemanager.h @@ -22,9 +22,11 @@ public: SqliteDb *sqliteDb() const { return m_sqliteDb; } - void handleProcNew(const QString &path); - void handleStatTraf(quint16 procCount, const quint8 *procBits, - const quint32 *trafBytes); + void addApp(const QString &appPath, bool &isNew); + void addTraffic(quint16 procCount, const quint8 *procBits, + const quint32 *trafBytes); + + QStringList getAppList(); signals: @@ -33,7 +35,7 @@ public slots: private: bool createTables(); - qint64 getAppId(const QString &appPath); + qint64 getAppId(const QString &appPath, bool &isNew); SqliteStmt *getSqliteStmt(const char *sql); diff --git a/src/ui/db/databasesql.cpp b/src/ui/db/databasesql.cpp index 774356ae..e9b19a83 100644 --- a/src/ui/db/databasesql.cpp +++ b/src/ui/db/databasesql.cpp @@ -10,6 +10,7 @@ const char * const DatabaseSql::sqlCreateTables = "CREATE TABLE app(" " id INTEGER PRIMARY KEY," " path TEXT UNIQUE NOT NULL," + " creat_time INTEGER NOT NULL," " unix_time INTEGER NOT NULL," " in_bytes INTEGER NOT NULL," " out_bytes INTEGER NOT NULL" @@ -63,8 +64,12 @@ const char * const DatabaseSql::sqlSelectAppId = ; const char * const DatabaseSql::sqlInsertAppId = - "INSERT INTO app(path, unix_time, in_bytes, out_bytes)" - " VALUES(?1, ?2, 0, 0);" + "INSERT INTO app(path, creat_time, unix_time, in_bytes, out_bytes)" + " VALUES(?1, ?2, ?3, 0, 0);" + ; + +const char * const DatabaseSql::sqlSelectAppPaths = + "SELECT path FROM app ORDER BY creat_time;" ; const char * const DatabaseSql::sqlInsertTrafficAppHour = diff --git a/src/ui/db/databasesql.h b/src/ui/db/databasesql.h index 0c706938..d9b691ed 100644 --- a/src/ui/db/databasesql.h +++ b/src/ui/db/databasesql.h @@ -10,6 +10,8 @@ public: static const char * const sqlSelectAppId; static const char * const sqlInsertAppId; + static const char * const sqlSelectAppPaths; + static const char * const sqlInsertTrafficAppHour; static const char * const sqlInsertTrafficAppDay; static const char * const sqlInsertTrafficAppMonth; diff --git a/src/ui/fort_qml.qrc b/src/ui/fort_qml.qrc index 6d9d51ce..6a859404 100644 --- a/src/ui/fort_qml.qrc +++ b/src/ui/fort_qml.qrc @@ -15,6 +15,7 @@ qml/pages/addresses/AddressesColumn.qml qml/pages/apps/AppsColumn.qml qml/pages/apps/AppsTextColumn.qml + qml/pages/log/AppListView.qml qml/pages/schedule/TaskRow.qml diff --git a/src/ui/fortmanager.cpp b/src/ui/fortmanager.cpp index 48f4f2ff..c40a810a 100644 --- a/src/ui/fortmanager.cpp +++ b/src/ui/fortmanager.cpp @@ -17,6 +17,7 @@ #include "fortsettings.h" #include "log/logmanager.h" #include "log/model/appblockedmodel.h" +#include "log/model/appstatmodel.h" #include "log/model/iplistmodel.h" #include "task/taskinfo.h" #include "task/taskmanager.h" @@ -42,7 +43,6 @@ FortManager::FortManager(FortSettings *fortSettings, m_driverManager->driverWorker(), this)), m_taskManager(new TaskManager(this, this)) { - setupDatabase(); setupDriver(); loadSettings(m_firewallConf); @@ -73,6 +73,8 @@ void FortManager::registerQmlTypes() "Singleton"); qmlRegisterUncreatableType("com.fortfirewall", 1, 0, "AppBlockedModel", "Singleton"); + qmlRegisterUncreatableType("com.fortfirewall", 1, 0, "AppStatModel", + "Singleton"); qmlRegisterUncreatableType("com.fortfirewall", 1, 0, "IpListModel", "Singleton"); @@ -94,11 +96,6 @@ void FortManager::registerQmlTypes() qmlRegisterType("com.fortfirewall", 1, 0, "OsUtil"); } -bool FortManager::setupDatabase() -{ - return m_databaseManager->initialize(); -} - bool FortManager::setupDriver() { if (!m_driverManager->openDevice()) { @@ -106,7 +103,7 @@ bool FortManager::setupDriver() return false; } - m_logManager->setLogReadingEnabled(true); + m_logManager->initialize(); return true; } diff --git a/src/ui/fortmanager.h b/src/ui/fortmanager.h index 1ecced15..dd82f633 100644 --- a/src/ui/fortmanager.h +++ b/src/ui/fortmanager.h @@ -68,8 +68,6 @@ private: static void registerQmlTypes(); - bool setupDatabase(); - bool setupDriver(); void closeDriver(); diff --git a/src/ui/log/logmanager.cpp b/src/ui/log/logmanager.cpp index 809b369a..f09df986 100644 --- a/src/ui/log/logmanager.cpp +++ b/src/ui/log/logmanager.cpp @@ -2,28 +2,30 @@ #include "../driver/driverworker.h" #include "../fortcommon.h" -#include "db/databasemanager.h" #include "logbuffer.h" #include "logentryblocked.h" #include "logentryprocnew.h" #include "logentrystattraf.h" #include "model/appblockedmodel.h" +#include "model/appstatmodel.h" LogManager::LogManager(DatabaseManager *databaseManager, DriverWorker *driverWorker, QObject *parent) : QObject(parent), m_logReadingEnabled(false), - m_databaseManager(databaseManager), m_driverWorker(driverWorker), - m_appBlockedModel(new AppBlockedModel(this)) + m_appBlockedModel(new AppBlockedModel(this)), + m_appStatModel(new AppStatModel(databaseManager, this)) { setupDriverWorker(); } -void LogManager::clearModels() const +void LogManager::initialize() { - m_appBlockedModel->clear(); + setLogReadingEnabled(true); + + m_appStatModel->initialize(); } void LogManager::setErrorMessage(const QString &errorMessage) @@ -105,12 +107,12 @@ void LogManager::readLogEntries(LogBuffer *logBuffer) } case LogEntry::ProcNew: { logBuffer->readEntryProcNew(&entryProcNew); - m_databaseManager->handleProcNew(entryProcNew.path()); + m_appStatModel->handleProcNew(entryProcNew.path()); break; } case LogEntry::StatTraf: { logBuffer->readEntryStatTraf(&entryStatTraf); - m_databaseManager->handleStatTraf( + m_appStatModel->handleStatTraf( entryStatTraf.procCount(), entryStatTraf.procBits(), entryStatTraf.trafBytes()); break; diff --git a/src/ui/log/logmanager.h b/src/ui/log/logmanager.h index d1bff8fd..ccd9c3c2 100644 --- a/src/ui/log/logmanager.h +++ b/src/ui/log/logmanager.h @@ -4,6 +4,7 @@ #include class AppBlockedModel; +class AppStatModel; class DatabaseManager; class DriverWorker; class LogBuffer; @@ -13,6 +14,7 @@ class LogManager : public QObject { Q_OBJECT Q_PROPERTY(AppBlockedModel *appBlockedModel READ appBlockedModel CONSTANT) + Q_PROPERTY(AppStatModel *appStatModel READ appStatModel CONSTANT) Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged) public: @@ -21,16 +23,16 @@ public: QObject *parent = nullptr); AppBlockedModel *appBlockedModel() const { return m_appBlockedModel; } + AppStatModel *appStatModel() const { return m_appStatModel; } QString errorMessage() const { return m_errorMessage; } + void initialize(); + signals: void errorMessageChanged(); public slots: - - void clearModels() const; - void setLogReadingEnabled(bool enabled); private slots: @@ -40,7 +42,6 @@ private slots: private: void setErrorMessage(const QString &errorMessage); - void setupDatabaseManager(); void setupDriverWorker(); void readLogAsync(LogBuffer *logBuffer); @@ -53,12 +54,11 @@ private: private: bool m_logReadingEnabled; - DatabaseManager *m_databaseManager; - DriverWorker *m_driverWorker; QList m_freeBuffers; AppBlockedModel *m_appBlockedModel; + AppStatModel *m_appStatModel; QString m_errorMessage; }; diff --git a/src/ui/log/model/appstatmodel.cpp b/src/ui/log/model/appstatmodel.cpp new file mode 100644 index 00000000..ea295a01 --- /dev/null +++ b/src/ui/log/model/appstatmodel.cpp @@ -0,0 +1,43 @@ +#include "appstatmodel.h" + +#include "../../db/databasemanager.h" + +AppStatModel::AppStatModel(DatabaseManager *databaseManager, + QObject *parent) : + StringListModel(parent), + m_databaseManager(databaseManager) +{ +} + +void AppStatModel::initialize() +{ + m_databaseManager->initialize(); + + updateList(); +} + +void AppStatModel::clear() +{ + StringListModel::clear(); +} + +void AppStatModel::updateList() +{ + setList(m_databaseManager->getAppList()); +} + +void AppStatModel::handleProcNew(const QString &appPath) +{ + bool isNew = false; + m_databaseManager->addApp(appPath, isNew); + + if (isNew) { + insert(appPath); + } +} + +void AppStatModel::handleStatTraf(quint16 procCount, const quint8 *procBits, + const quint32 *trafBytes) +{ + m_databaseManager->addTraffic(procCount, procBits, trafBytes); +} diff --git a/src/ui/log/model/appstatmodel.h b/src/ui/log/model/appstatmodel.h new file mode 100644 index 00000000..0ef4f95f --- /dev/null +++ b/src/ui/log/model/appstatmodel.h @@ -0,0 +1,34 @@ +#ifndef APPSTATMODEL_H +#define APPSTATMODEL_H + +#include "stringlistmodel.h" + +class DatabaseManager; + +class AppStatModel : public StringListModel +{ + Q_OBJECT + +public: + explicit AppStatModel(DatabaseManager *databaseManager, + QObject *parent = nullptr); + + void initialize(); + + void handleProcNew(const QString &appPath); + void handleStatTraf(quint16 procCount, const quint8 *procBits, + const quint32 *trafBytes); + +signals: + +public slots: + void clear() override; + +private: + void updateList(); + +private: + DatabaseManager *m_databaseManager; +}; + +#endif // APPSTATMODEL_H diff --git a/src/ui/log/model/stringlistmodel.h b/src/ui/log/model/stringlistmodel.h index 24c90e11..b2814453 100644 --- a/src/ui/log/model/stringlistmodel.h +++ b/src/ui/log/model/stringlistmodel.h @@ -14,6 +14,7 @@ public: int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + const QStringList &list() const { return m_list; } void setList(const QStringList &list); protected: diff --git a/src/ui/qml/pages/BlockedPage.qml b/src/ui/qml/pages/BlockedPage.qml index c49537a0..8deced1d 100644 --- a/src/ui/qml/pages/BlockedPage.qml +++ b/src/ui/qml/pages/BlockedPage.qml @@ -2,6 +2,7 @@ import QtQuick 2.9 import QtQuick.Layouts 1.3 import QtQuick.Controls 2.2 import "../controls" +import "log" import com.fortfirewall 1.0 BasePage { @@ -16,7 +17,7 @@ BasePage { function clearAppPaths() { appListView.currentIndex = -1; - logManager.clearModels(); + appBlockedModel.clear(); } HostInfoCache { @@ -80,58 +81,12 @@ BasePage { anchors.fill: parent spacing: 20 - ListView { + AppListView { id: appListView Layout.fillWidth: true Layout.fillHeight: true - spacing: 10 model: appBlockedModel - - highlightRangeMode: ListView.ApplyRange - highlightResizeDuration: 0 - highlightMoveDuration: 200 - - highlight: Item { - Rectangle { - anchors.fill: parent - anchors.margins: -7 - radius: 2 - border.width: 3 - border.color: palette.highlight - color: "transparent" - } - } - - delegate: Row { - id: appItem - width: appListView.width - spacing: 6 - - readonly property string appPath: display - - // TODO: Use SHGetFileInfo() to get app's display name and icon - Image { - anchors.verticalCenter: parent.verticalCenter - anchors.verticalCenterOffset: 1 - source: "qrc:/images/application.png" - } - Label { - font.pixelSize: 20 - elide: Text.ElideRight - text: fileUtil.fileName(appItem.appPath) - } - } - - MouseArea { - anchors.fill: parent - onClicked: { - const index = appListView.indexAt(mouse.x, mouse.y); - if (index >= 0) { - appListView.currentIndex = index; - } - } - } } ListView { diff --git a/src/ui/qml/pages/StatisticsPage.qml b/src/ui/qml/pages/StatisticsPage.qml index e8c33db2..67905283 100644 --- a/src/ui/qml/pages/StatisticsPage.qml +++ b/src/ui/qml/pages/StatisticsPage.qml @@ -2,11 +2,17 @@ import QtQuick 2.9 import QtQuick.Layouts 1.3 import QtQuick.Controls 2.2 import "../controls" +import "log" import com.fortfirewall 1.0 BasePage { readonly property LogManager logManager: fortManager.logManager + readonly property AppStatModel appStatModel: logManager.appStatModel + + readonly property string currentAppPath: + (appListView.currentIndex >= 0 && appListView.currentItem) + ? appListView.currentItem.appPath : "" ColumnLayout { anchors.fill: parent @@ -38,6 +44,25 @@ BasePage { Layout.fillWidth: true Layout.fillHeight: true clip: true + + RowLayout { + anchors.fill: parent + spacing: 20 + + AppListView { + id: appListView + Layout.fillWidth: true + Layout.fillHeight: true + + model: appStatModel + } + + } + } + + TextFieldFrame { + Layout.fillWidth: true + text: currentAppPath || "" } } } diff --git a/src/ui/qml/pages/log/AppListView.qml b/src/ui/qml/pages/log/AppListView.qml new file mode 100644 index 00000000..807fba51 --- /dev/null +++ b/src/ui/qml/pages/log/AppListView.qml @@ -0,0 +1,54 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.2 +import com.fortfirewall 1.0 + +ListView { + id: appListView + + spacing: 10 + + highlightRangeMode: ListView.ApplyRange + highlightResizeDuration: 0 + highlightMoveDuration: 200 + + highlight: Item { + Rectangle { + anchors.fill: parent + anchors.margins: -7 + radius: 2 + border.width: 3 + border.color: palette.highlight + color: "transparent" + } + } + + delegate: Row { + id: appItem + width: appListView.width + spacing: 6 + + readonly property string appPath: display + + // TODO: Use SHGetFileInfo() to get app's display name and icon + Image { + anchors.verticalCenter: parent.verticalCenter + anchors.verticalCenterOffset: 1 + source: "qrc:/images/application.png" + } + Label { + font.pixelSize: 20 + elide: Text.ElideRight + text: fileUtil.fileName(appItem.appPath) + } + } + + MouseArea { + anchors.fill: parent + onClicked: { + const index = appListView.indexAt(mouse.x, mouse.y); + if (index >= 0) { + appListView.currentIndex = index; + } + } + } +}