mirror of
https://github.com/tnodir/fort
synced 2024-11-15 10:15:07 +00:00
UI: Handle end time of apps.
This commit is contained in:
parent
4e4ca1a6d5
commit
2abeff545b
@ -135,14 +135,29 @@ const char * const sqlSelectAppByIndex =
|
|||||||
|
|
||||||
const char * const sqlSelectApps =
|
const char * const sqlSelectApps =
|
||||||
"SELECT g.order_index as group_index,"
|
"SELECT g.order_index as group_index,"
|
||||||
" t.blocked,"
|
" t.path, t.blocked,"
|
||||||
" (alert.app_id IS NOT NULL) as alerted,"
|
" (alert.app_id IS NOT NULL) as alerted"
|
||||||
" t.path"
|
|
||||||
" FROM app t"
|
" FROM app t"
|
||||||
" JOIN app_group g ON g.app_group_id = t.app_group_id"
|
" JOIN app_group g ON g.app_group_id = t.app_group_id"
|
||||||
" LEFT JOIN app_alert alert ON alert.app_id = t.app_id;"
|
" LEFT JOIN app_alert alert ON alert.app_id = t.app_id;"
|
||||||
;
|
;
|
||||||
|
|
||||||
|
const char * const sqlSelectEndAppsCount =
|
||||||
|
"SELECT COUNT(*) FROM app"
|
||||||
|
" WHERE end_time IS NOT NULL AND end_time != 0;"
|
||||||
|
;
|
||||||
|
|
||||||
|
const char * const sqlSelectEndedApps =
|
||||||
|
"SELECT t.app_id,"
|
||||||
|
" g.order_index as group_index,"
|
||||||
|
" t.path,"
|
||||||
|
" (alert.app_id IS NOT NULL) as alerted"
|
||||||
|
" FROM app t"
|
||||||
|
" JOIN app_group g ON g.app_group_id = t.app_group_id"
|
||||||
|
" LEFT JOIN app_alert alert ON alert.app_id = t.app_id"
|
||||||
|
" WHERE end_time <= ?1;"
|
||||||
|
;
|
||||||
|
|
||||||
const char * const sqlInsertApp =
|
const char * const sqlInsertApp =
|
||||||
"INSERT INTO app(app_group_id, path, blocked,"
|
"INSERT INTO app(app_group_id, path, blocked,"
|
||||||
" creat_time, end_time)"
|
" creat_time, end_time)"
|
||||||
@ -187,6 +202,8 @@ ConfManager::ConfManager(const QString &filePath,
|
|||||||
m_fortSettings(fortSettings),
|
m_fortSettings(fortSettings),
|
||||||
m_sqliteDb(new SqliteDb(filePath))
|
m_sqliteDb(new SqliteDb(filePath))
|
||||||
{
|
{
|
||||||
|
m_appEndTimer.setInterval(5 * 60 * 1000); // 5 minutes
|
||||||
|
connect(&m_appEndTimer, &QTimer::timeout, this, &ConfManager::checkAppEndTimes);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfManager::~ConfManager()
|
ConfManager::~ConfManager()
|
||||||
@ -220,6 +237,8 @@ bool ConfManager::initialize()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_appEndTimer.start();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,7 +391,7 @@ bool ConfManager::addApp(const QString &appPath, const QDateTime &endTime,
|
|||||||
<< appPath
|
<< appPath
|
||||||
<< blocked
|
<< blocked
|
||||||
<< QDateTime::currentDateTime()
|
<< QDateTime::currentDateTime()
|
||||||
<< endTime
|
<< (!endTime.isNull() ? endTime : QVariant())
|
||||||
;
|
;
|
||||||
|
|
||||||
m_sqliteDb->executeEx(sqlInsertApp, vars, 0, &ok);
|
m_sqliteDb->executeEx(sqlInsertApp, vars, 0, &ok);
|
||||||
@ -394,6 +413,10 @@ end:
|
|||||||
|
|
||||||
m_sqliteDb->endTransaction(ok);
|
m_sqliteDb->endTransaction(ok);
|
||||||
|
|
||||||
|
if (ok && !endTime.isNull()) {
|
||||||
|
m_appEndTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,7 +454,7 @@ bool ConfManager::updateApp(qint64 appId, const QDateTime &endTime,
|
|||||||
<< appId
|
<< appId
|
||||||
<< appGroupIdByIndex(groupIndex)
|
<< appGroupIdByIndex(groupIndex)
|
||||||
<< blocked
|
<< blocked
|
||||||
<< endTime
|
<< (!endTime.isNull() ? endTime : QVariant())
|
||||||
;
|
;
|
||||||
|
|
||||||
m_sqliteDb->executeEx(sqlUpdateApp, vars, 0, &ok);
|
m_sqliteDb->executeEx(sqlUpdateApp, vars, 0, &ok);
|
||||||
@ -446,6 +469,10 @@ end:
|
|||||||
|
|
||||||
m_sqliteDb->endTransaction(ok);
|
m_sqliteDb->endTransaction(ok);
|
||||||
|
|
||||||
|
if (ok && !endTime.isNull()) {
|
||||||
|
m_appEndTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,10 +484,10 @@ bool ConfManager::walkApps(std::function<walkAppsCallback> func)
|
|||||||
|
|
||||||
while (stmt.step() == SqliteStmt::StepRow) {
|
while (stmt.step() == SqliteStmt::StepRow) {
|
||||||
const int groupIndex = stmt.columnInt(0);
|
const int groupIndex = stmt.columnInt(0);
|
||||||
|
const QString appPath = stmt.columnText(1);
|
||||||
const bool useGroupPerm = false;
|
const bool useGroupPerm = false;
|
||||||
const bool blocked = stmt.columnBool(1);
|
const bool blocked = stmt.columnBool(2);
|
||||||
const bool alerted = stmt.columnBool(2);
|
const bool alerted = stmt.columnBool(3);
|
||||||
const QString appPath = stmt.columnText(3);
|
|
||||||
|
|
||||||
if (!func(groupIndex, useGroupPerm, blocked, alerted, appPath))
|
if (!func(groupIndex, useGroupPerm, blocked, alerted, appPath))
|
||||||
return false;
|
return false;
|
||||||
@ -469,6 +496,53 @@ bool ConfManager::walkApps(std::function<walkAppsCallback> func)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ConfManager::appEndsCount()
|
||||||
|
{
|
||||||
|
SqliteStmt stmt;
|
||||||
|
if (!stmt.prepare(m_sqliteDb->db(), sqlSelectEndAppsCount)
|
||||||
|
|| stmt.step() != SqliteStmt::StepRow)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return stmt.columnInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfManager::updateAppEndTimes()
|
||||||
|
{
|
||||||
|
SqliteStmt stmt;
|
||||||
|
if (!stmt.prepare(m_sqliteDb->db(), sqlSelectEndedApps))
|
||||||
|
return;
|
||||||
|
|
||||||
|
stmt.bindDateTime(1, QDateTime::currentDateTime());
|
||||||
|
|
||||||
|
bool isAppEndTimesUpdated = false;
|
||||||
|
|
||||||
|
while (stmt.step() == SqliteStmt::StepRow) {
|
||||||
|
const qint64 appId = stmt.columnInt64(0);
|
||||||
|
const int groupIndex = stmt.columnInt(1);
|
||||||
|
const QString appPath = stmt.columnText(3);
|
||||||
|
const bool alerted = stmt.columnBool(4);
|
||||||
|
|
||||||
|
if (updateDriverUpdateApp(appPath, groupIndex,
|
||||||
|
false, true, alerted)
|
||||||
|
&& updateApp(appId, QDateTime(), groupIndex, true)) {
|
||||||
|
isAppEndTimesUpdated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAppEndTimesUpdated) {
|
||||||
|
emit appEndTimesUpdated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfManager::checkAppEndTimes()
|
||||||
|
{
|
||||||
|
if (appEndsCount() == 0) {
|
||||||
|
m_appEndTimer.stop();
|
||||||
|
} else {
|
||||||
|
updateAppEndTimes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ConfManager::updateDriverConf(const FirewallConf &conf, bool onlyFlags)
|
bool ConfManager::updateDriverConf(const FirewallConf &conf, bool onlyFlags)
|
||||||
{
|
{
|
||||||
return onlyFlags
|
return onlyFlags
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define CONFMANAGER_H
|
#define CONFMANAGER_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
@ -49,6 +50,7 @@ public:
|
|||||||
QString &appGroupName, QString &appPath,
|
QString &appGroupName, QString &appPath,
|
||||||
QDateTime &endTime, int row);
|
QDateTime &endTime, int row);
|
||||||
qint64 appGroupIdByIndex(int index = 0);
|
qint64 appGroupIdByIndex(int index = 0);
|
||||||
|
|
||||||
bool addApp(const QString &appPath, const QDateTime &endTime,
|
bool addApp(const QString &appPath, const QDateTime &endTime,
|
||||||
int groupIndex, bool blocked, bool alerted);
|
int groupIndex, bool blocked, bool alerted);
|
||||||
bool deleteApp(qint64 appId);
|
bool deleteApp(qint64 appId);
|
||||||
@ -56,6 +58,10 @@ public:
|
|||||||
int groupIndex, bool blocked);
|
int groupIndex, bool blocked);
|
||||||
bool walkApps(std::function<walkAppsCallback> func);
|
bool walkApps(std::function<walkAppsCallback> func);
|
||||||
|
|
||||||
|
int appEndsCount();
|
||||||
|
void updateAppEndTimes();
|
||||||
|
void checkAppEndTimes();
|
||||||
|
|
||||||
bool updateDriverConf(const FirewallConf &conf, bool onlyFlags = false);
|
bool updateDriverConf(const FirewallConf &conf, bool onlyFlags = false);
|
||||||
bool updateDriverDeleteApp(const QString &appPath);
|
bool updateDriverDeleteApp(const QString &appPath);
|
||||||
bool updateDriverUpdateApp(const QString &appPath,
|
bool updateDriverUpdateApp(const QString &appPath,
|
||||||
@ -67,6 +73,7 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void errorMessageChanged();
|
void errorMessageChanged();
|
||||||
void confSaved();
|
void confSaved();
|
||||||
|
void appEndTimesUpdated();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setErrorMessage(const QString &errorMessage);
|
void setErrorMessage(const QString &errorMessage);
|
||||||
@ -88,6 +95,8 @@ private:
|
|||||||
EnvManager *m_envManager = nullptr;
|
EnvManager *m_envManager = nullptr;
|
||||||
FortSettings *m_fortSettings = nullptr;
|
FortSettings *m_fortSettings = nullptr;
|
||||||
SqliteDb *m_sqliteDb = nullptr;
|
SqliteDb *m_sqliteDb = nullptr;
|
||||||
|
|
||||||
|
QTimer m_appEndTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONFMANAGER_H
|
#endif // CONFMANAGER_H
|
||||||
|
@ -175,31 +175,22 @@ QLayout *ProgramsWindow::setupHeader()
|
|||||||
m_btBlockApp = ControlUtil::createLinkButton(":/images/stop.png");
|
m_btBlockApp = ControlUtil::createLinkButton(":/images/stop.png");
|
||||||
|
|
||||||
connect(m_btAddApp, &QAbstractButton::clicked, [&] {
|
connect(m_btAddApp, &QAbstractButton::clicked, [&] {
|
||||||
const AppRow appRow;
|
updateAppEditForm(false);
|
||||||
updateAppEditForm(appRow);
|
|
||||||
});
|
});
|
||||||
connect(m_btEditApp, &QAbstractButton::clicked, [&] {
|
connect(m_btEditApp, &QAbstractButton::clicked, [&] {
|
||||||
const auto appIndex = appListCurrentIndex();
|
updateAppEditForm(true);
|
||||||
if (appIndex >= 0) {
|
|
||||||
const auto appRow = appListModel()->appRow(appIndex);
|
|
||||||
updateAppEditForm(appRow);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
connect(m_btDeleteApp, &QAbstractButton::clicked, [&] {
|
connect(m_btDeleteApp, &QAbstractButton::clicked, [&] {
|
||||||
if (!fortManager()->showQuestionBox(tr("Are you sure to remove the selected program?")))
|
if (fortManager()->showQuestionBox(tr("Are you sure to remove the selected program?"))) {
|
||||||
return;
|
deleteCurrentApp();
|
||||||
|
}
|
||||||
const int appIndex = appListCurrentIndex();
|
|
||||||
appListModel()->deleteApp(appIndex);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_btAllowApp, &QAbstractButton::clicked, [&] {
|
connect(m_btAllowApp, &QAbstractButton::clicked, [&] {
|
||||||
const int appIndex = appListCurrentIndex();
|
updateCurrentApp(false);
|
||||||
appListModel()->updateApp(appIndex, 0, false);
|
|
||||||
});
|
});
|
||||||
connect(m_btBlockApp, &QAbstractButton::clicked, [&] {
|
connect(m_btBlockApp, &QAbstractButton::clicked, [&] {
|
||||||
const int appIndex = appListCurrentIndex();
|
updateCurrentApp(true);
|
||||||
appListModel()->updateApp(appIndex, 0, true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
setupLogBlocked();
|
setupLogBlocked();
|
||||||
@ -310,8 +301,8 @@ void ProgramsWindow::setupAppEditForm()
|
|||||||
.addSecs(hours * 60 * 60);
|
.addSecs(hours * 60 * 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_formAppIsEditing
|
if (m_formAppId != 0
|
||||||
? appListModel()->updateApp(appListCurrentIndex(),
|
? appListModel()->updateApp(m_formAppId, appPath,
|
||||||
groupIndex, blocked, endTime)
|
groupIndex, blocked, endTime)
|
||||||
: appListModel()->addApp(appPath, groupIndex, blocked, endTime)) {
|
: appListModel()->addApp(appPath, groupIndex, blocked, endTime)) {
|
||||||
m_formAppEdit->close();
|
m_formAppEdit->close();
|
||||||
@ -449,13 +440,22 @@ void ProgramsWindow::setupTableAppsChanged()
|
|||||||
connect(m_appListView, &TableView::currentIndexChanged, this, refreshTableAppsChanged);
|
connect(m_appListView, &TableView::currentIndexChanged, this, refreshTableAppsChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgramsWindow::updateAppEditForm(const AppRow &appRow)
|
void ProgramsWindow::updateAppEditForm(bool editCurrentApp)
|
||||||
{
|
{
|
||||||
m_formAppIsEditing = !appRow.appPath.isEmpty();
|
AppRow appRow;
|
||||||
|
if (editCurrentApp) {
|
||||||
|
const auto appIndex = appListCurrentIndex();
|
||||||
|
if (appIndex < 0) return;
|
||||||
|
|
||||||
|
appRow = appListModel()->appRow(appIndex);
|
||||||
|
m_formAppId = appRow.appId;
|
||||||
|
} else {
|
||||||
|
m_formAppId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
m_editPath->setText(appRow.appPath);
|
m_editPath->setText(appRow.appPath);
|
||||||
m_editPath->setReadOnly(m_formAppIsEditing);
|
m_editPath->setReadOnly(editCurrentApp);
|
||||||
m_btSelectFile->setEnabled(!m_formAppIsEditing);
|
m_btSelectFile->setEnabled(!editCurrentApp);
|
||||||
m_comboAppGroup->setCurrentIndex(appRow.groupIndex);
|
m_comboAppGroup->setCurrentIndex(appRow.groupIndex);
|
||||||
m_rbAllowApp->setChecked(!appRow.blocked());
|
m_rbAllowApp->setChecked(!appRow.blocked());
|
||||||
m_rbBlockApp->setChecked(appRow.blocked());
|
m_rbBlockApp->setChecked(appRow.blocked());
|
||||||
@ -464,6 +464,25 @@ void ProgramsWindow::updateAppEditForm(const AppRow &appRow)
|
|||||||
m_formAppEdit->show();
|
m_formAppEdit->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProgramsWindow::updateCurrentApp(bool blocked)
|
||||||
|
{
|
||||||
|
const int appIndex = appListCurrentIndex();
|
||||||
|
if (appIndex >= 0) {
|
||||||
|
const auto appRow = appListModel()->appRow(appIndex);
|
||||||
|
appListModel()->updateApp(appRow.appId, appRow.appPath,
|
||||||
|
appRow.groupIndex, blocked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgramsWindow::deleteCurrentApp()
|
||||||
|
{
|
||||||
|
const int appIndex = appListCurrentIndex();
|
||||||
|
if (appIndex >= 0) {
|
||||||
|
const auto appRow = appListModel()->appRow(appIndex);
|
||||||
|
appListModel()->deleteApp(appRow.appId, appRow.appPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int ProgramsWindow::appListCurrentIndex() const
|
int ProgramsWindow::appListCurrentIndex() const
|
||||||
{
|
{
|
||||||
return m_appListView->currentIndex().row();
|
return m_appListView->currentIndex().row();
|
||||||
|
@ -55,7 +55,10 @@ private:
|
|||||||
void setupAppInfoRow();
|
void setupAppInfoRow();
|
||||||
void setupAppInfoVersion();
|
void setupAppInfoVersion();
|
||||||
void setupTableAppsChanged();
|
void setupTableAppsChanged();
|
||||||
void updateAppEditForm(const AppRow &appRow);
|
|
||||||
|
void updateAppEditForm(bool editCurrentApp);
|
||||||
|
void updateCurrentApp(bool blocked);
|
||||||
|
void deleteCurrentApp();
|
||||||
|
|
||||||
int appListCurrentIndex() const;
|
int appListCurrentIndex() const;
|
||||||
QString appListCurrentPath() const;
|
QString appListCurrentPath() const;
|
||||||
@ -68,7 +71,7 @@ private:
|
|||||||
AppInfoCache *appInfoCache() const;
|
AppInfoCache *appInfoCache() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_formAppIsEditing = false;
|
qint64 m_formAppId = 0;
|
||||||
|
|
||||||
ProgramsController *m_ctrl = nullptr;
|
ProgramsController *m_ctrl = nullptr;
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ AppListModel::AppListModel(ConfManager *confManager,
|
|||||||
m_confManager(confManager)
|
m_confManager(confManager)
|
||||||
{
|
{
|
||||||
connect(m_confManager, &ConfManager::confSaved, this, &AppListModel::reset);
|
connect(m_confManager, &ConfManager::confSaved, this, &AppListModel::reset);
|
||||||
|
connect(m_confManager, &ConfManager::appEndTimesUpdated, this, &AppListModel::refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppListModel::setAppInfoCache(AppInfoCache *v)
|
void AppListModel::setAppInfoCache(AppInfoCache *v)
|
||||||
@ -170,44 +171,36 @@ bool AppListModel::addApp(const QString &appPath, int groupIndex, bool blocked,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AppListModel::updateApp(int row, int groupIndex, bool blocked,
|
bool AppListModel::updateApp(qint64 appId, const QString &appPath,
|
||||||
|
int groupIndex, bool blocked,
|
||||||
const QDateTime &endTime)
|
const QDateTime &endTime)
|
||||||
{
|
{
|
||||||
updateRowCache(row);
|
|
||||||
|
|
||||||
const qint64 appId = m_rowCache.appId;
|
|
||||||
const QString appPath = m_rowCache.appPath;
|
|
||||||
|
|
||||||
if (confManager()->updateDriverUpdateApp(appPath, groupIndex, false, blocked, false)
|
if (confManager()->updateDriverUpdateApp(appPath, groupIndex, false, blocked, false)
|
||||||
&& confManager()->updateApp(appId, endTime, groupIndex, blocked)) {
|
&& confManager()->updateApp(appId, endTime, groupIndex, blocked)) {
|
||||||
const auto itemIndex = index(row, 3);
|
refresh();
|
||||||
invalidateRowCache();
|
|
||||||
emit dataChanged(itemIndex, itemIndex);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppListModel::deleteApp(int row)
|
void AppListModel::deleteApp(qint64 appId, const QString &appPath)
|
||||||
{
|
{
|
||||||
updateRowCache(row);
|
|
||||||
|
|
||||||
const qint64 appId = m_rowCache.appId;
|
|
||||||
const QString appPath = m_rowCache.appPath;
|
|
||||||
|
|
||||||
if (confManager()->updateDriverDeleteApp(appPath)
|
if (confManager()->updateDriverDeleteApp(appPath)
|
||||||
&& confManager()->deleteApp(appId)) {
|
&& confManager()->deleteApp(appId)) {
|
||||||
beginRemoveRows(QModelIndex(), row, row);
|
reset();
|
||||||
invalidateRowCache();
|
|
||||||
endRemoveRows();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppListModel::reset()
|
void AppListModel::reset()
|
||||||
{
|
{
|
||||||
beginResetModel();
|
|
||||||
invalidateRowCache();
|
invalidateRowCache();
|
||||||
endResetModel();
|
TableItemModel::reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppListModel::refresh()
|
||||||
|
{
|
||||||
|
invalidateRowCache();
|
||||||
|
TableItemModel::refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppListModel::invalidateRowCache()
|
void AppListModel::invalidateRowCache()
|
||||||
|
@ -63,12 +63,14 @@ public:
|
|||||||
|
|
||||||
bool addApp(const QString &appPath, int groupIndex, bool blocked,
|
bool addApp(const QString &appPath, int groupIndex, bool blocked,
|
||||||
const QDateTime &endTime = QDateTime());
|
const QDateTime &endTime = QDateTime());
|
||||||
bool updateApp(int row, int groupIndex, bool blocked,
|
bool updateApp(qint64 appId, const QString &appPath,
|
||||||
|
int groupIndex, bool blocked,
|
||||||
const QDateTime &endTime = QDateTime());
|
const QDateTime &endTime = QDateTime());
|
||||||
void deleteApp(int row);
|
void deleteApp(qint64 appId, const QString &appPath);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void reset();
|
void reset();
|
||||||
|
void refresh();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void invalidateRowCache();
|
void invalidateRowCache();
|
||||||
|
Loading…
Reference in New Issue
Block a user