UI: Scheduler: Add "Purge Obsolete Programs" task

- Add "Run On Startup" flag to tasks
This commit is contained in:
Nodir Temirkhodjaev 2024-02-02 20:38:44 +03:00
parent 8cc60c496c
commit 51e3ff910c
24 changed files with 189 additions and 95 deletions

View File

@ -161,6 +161,7 @@ SOURCES += \
task/taskdownloader.cpp \
task/taskeditinfo.cpp \
task/taskinfo.cpp \
task/taskinfoapppurger.cpp \
task/taskinfoupdatechecker.cpp \
task/taskinfozonedownloader.cpp \
task/tasklistmodel.cpp \
@ -365,6 +366,7 @@ HEADERS += \
task/taskdownloader.h \
task/taskeditinfo.h \
task/taskinfo.h \
task/taskinfoapppurger.h \
task/taskinfoupdatechecker.h \
task/taskinfozonedownloader.h \
task/tasklistmodel.h \

View File

@ -151,8 +151,6 @@ void ConfAppManager::setUp()
setupDriveListManager();
purgeAppsOnStart();
setupAppEndTimer();
}
@ -166,13 +164,6 @@ void ConfAppManager::setupDriveListManager()
});
}
void ConfAppManager::purgeAppsOnStart()
{
if (conf()->ini().progPurgeOnStart()) {
purgeApps();
}
}
void ConfAppManager::setupAppEndTimer()
{
auto logManager = IoC<LogManager>();

View File

@ -60,8 +60,6 @@ signals:
protected:
virtual void setupDriveListManager();
virtual void purgeAppsOnStart();
virtual void setupAppEndTimer();
void updateAppEndTimer();

View File

@ -32,7 +32,7 @@ namespace {
const QLoggingCategory LC("conf");
constexpr int DATABASE_USER_VERSION = 31;
constexpr int DATABASE_USER_VERSION = 32;
const char *const sqlSelectAddressGroups = "SELECT addr_group_id, include_all, exclude_all,"
" include_zones, exclude_zones,"
@ -94,18 +94,19 @@ const char *const sqlUpdateAppResetGroup = "UPDATE app"
" SET app_group_id = ?2"
" WHERE app_group_id = ?1;";
const char *const sqlSelectTaskByName = "SELECT task_id, enabled, interval_hours,"
const char *const sqlSelectTaskByName = "SELECT task_id, enabled, run_on_startup, interval_hours,"
" last_run, last_success, data"
" FROM task"
" WHERE name = ?1;";
const char *const sqlInsertTask = "INSERT INTO task(task_id, name, enabled, interval_hours,"
" last_run, last_success, data)"
" VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7);";
const char *const sqlInsertTask = "INSERT INTO task(task_id, name, enabled, run_on_startup,"
" interval_hours, last_run, last_success, data)"
" VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8);";
const char *const sqlUpdateTask = "UPDATE task"
" SET name = ?2, enabled = ?3, interval_hours = ?4,"
" last_run = ?5, last_success = ?6, data = ?7"
" SET name = ?2, enabled = ?3, run_on_startup = ?4,"
" interval_hours = ?5, last_run = ?6, last_success = ?7,"
" data = ?8"
" WHERE task_id = ?1;";
using AppsMap = QHash<qint64, QString>;
@ -890,10 +891,11 @@ bool ConfManager::loadTask(TaskInfo *taskInfo)
taskInfo->setId(stmt.columnInt64(0));
taskInfo->setEnabled(stmt.columnBool(1));
taskInfo->setIntervalHours(stmt.columnInt(2));
taskInfo->setLastRun(stmt.columnDateTime(3));
taskInfo->setLastSuccess(stmt.columnDateTime(4));
taskInfo->setData(stmt.columnBlob(5));
taskInfo->setRunOnStatup(stmt.columnBool(2));
taskInfo->setIntervalHours(stmt.columnInt(3));
taskInfo->setLastRun(stmt.columnDateTime(4));
taskInfo->setLastSuccess(stmt.columnDateTime(5));
taskInfo->setData(stmt.columnBlob(6));
return true;
}
@ -904,8 +906,8 @@ bool ConfManager::saveTask(TaskInfo *taskInfo)
const auto vars = QVariantList()
<< SqliteStmt::nullable(taskInfo->id(), !rowExists) << taskInfo->name()
<< taskInfo->enabled() << taskInfo->intervalHours() << taskInfo->lastRun()
<< taskInfo->lastSuccess() << taskInfo->data();
<< taskInfo->enabled() << taskInfo->runOnStatup() << taskInfo->intervalHours()
<< taskInfo->lastRun() << taskInfo->lastSuccess() << taskInfo->data();
const char *sql = rowExists ? sqlUpdateTask : sqlInsertTask;

View File

@ -93,9 +93,6 @@ public:
}
void setBlockedIpKeepCount(int v) { setValue("stat/blockedIpKeepCount", v); }
bool progPurgeOnStart() const { return valueBool("prog/purgeOnStart"); }
void setProgPurgeOnStart(bool v) { setValue("prog/purgeOnStart", v); }
bool progPurgeOnMounted() const { return valueBool("prog/purgeOnMounted"); }
void setProgPurgeOnMounted(bool v) { setValue("prog/purgeOnMounted", v); }

View File

@ -158,6 +158,7 @@ CREATE TABLE task(
task_id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
enabled BOOLEAN NOT NULL,
run_on_startup BOOLEAN NOT NULL DEFAULT 0,
interval_hours INTEGER NOT NULL,
last_run INTEGER NOT NULL,
last_success INTEGER NOT NULL,

View File

@ -171,7 +171,6 @@ void OptionsPage::onRetranslateUi()
m_cbAppNotifyMessage->setText(tr("Use System Notifications for New Programs"));
m_cbAppAlertAutoShow->setText(tr("Auto-Show Alert Window for New Programs"));
m_cbAppAlertAlwaysOnTop->setText(tr("Alert Window is Always on top"));
m_cbPurgeOnStart->setText(tr("Purge Obsolete on startup"));
m_cbPurgeOnMounted->setText(tr("Purge Obsolete only on mounted drives"));
m_cbExplorerMenu->setText(tr("Windows Explorer integration"));
@ -539,13 +538,6 @@ void OptionsPage::setupProgBox()
ctrl()->setIniUserEdited();
});
m_cbPurgeOnStart = ControlUtil::createCheckBox(ini()->progPurgeOnStart(), [&](bool checked) {
if (ini()->progPurgeOnStart() != checked) {
ini()->setProgPurgeOnStart(checked);
ctrl()->setIniEdited();
}
});
m_cbPurgeOnMounted =
ControlUtil::createCheckBox(ini()->progPurgeOnMounted(), [&](bool checked) {
if (ini()->progPurgeOnMounted() != checked) {
@ -557,7 +549,7 @@ void OptionsPage::setupProgBox()
// Layout
auto layout = ControlUtil::createVLayoutByWidgets(
{ m_cbLogBlocked, m_cbAppNotifyMessage, m_cbAppAlertAutoShow, m_cbAppAlertAlwaysOnTop,
ControlUtil::createSeparator(), m_cbPurgeOnStart, m_cbPurgeOnMounted });
ControlUtil::createSeparator(), m_cbPurgeOnMounted });
m_gbProg = new QGroupBox();
m_gbProg->setLayout(layout);

View File

@ -101,7 +101,6 @@ private:
QCheckBox *m_cbAppNotifyMessage = nullptr;
QCheckBox *m_cbAppAlertAutoShow = nullptr;
QCheckBox *m_cbAppAlertAlwaysOnTop = nullptr;
QCheckBox *m_cbPurgeOnStart = nullptr;
QCheckBox *m_cbPurgeOnMounted = nullptr;
QCheckBox *m_cbExplorerMenu = nullptr;

View File

@ -46,13 +46,15 @@ void SchedulePage::onRetranslateUi()
{
taskListModel()->refresh();
retranslateTaskInterval();
m_cbTaskRunOnStartup->setText(tr("Run On Startup"));
m_btTaskRun->setText(tr("Run"));
m_btTaskAbort->setText(tr("Abort"));
retranslateTaskDetails();
}
void SchedulePage::retranslateTaskDetails()
void SchedulePage::retranslateTaskInterval()
{
const QStringList list = { tr("Custom"), tr("Hourly"), tr("Each 6 hours"), tr("Each 12 hours"),
tr("Daily"), tr("Weekly"), tr("Monthly") };
@ -119,22 +121,25 @@ void SchedulePage::setupTableTasksHeader()
void SchedulePage::setupTaskDetails()
{
m_taskDetailsRow = new QWidget();
auto layout = new QHBoxLayout();
layout->setContentsMargins(0, 0, 0, 0);
m_taskDetailsRow->setLayout(layout);
setupTaskInterval();
setupTaskRunOnStartup();
m_btTaskRun = ControlUtil::createFlatToolButton(
":/icons/play.png", [&] { taskManager()->runTask(currentTaskInfo()->type()); });
m_btTaskAbort = ControlUtil::createFlatToolButton(
":/icons/cancel.png", [&] { taskManager()->abortTask(currentTaskInfo()->type()); });
auto layout = new QHBoxLayout();
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_cscTaskInterval, 1);
layout->addWidget(ControlUtil::createVSeparator());
layout->addWidget(m_cbTaskRunOnStartup);
layout->addWidget(ControlUtil::createVSeparator());
layout->addWidget(m_btTaskRun);
layout->addWidget(m_btTaskAbort);
m_taskDetailsRow = new QWidget();
m_taskDetailsRow->setLayout(layout);
}
void SchedulePage::setupTaskInterval()
@ -161,6 +166,17 @@ void SchedulePage::setupTaskInterval()
});
}
void SchedulePage::setupTaskRunOnStartup()
{
m_cbTaskRunOnStartup = ControlUtil::createCheckBox(false, [&](bool checked) {
const int taskIndex = currentTaskIndex();
if (taskIndex >= 0) {
const auto index = taskListModel()->index(taskIndex, 2);
taskListModel()->setData(index, checked, TaskListModel::RoleRunOnStartup);
}
});
}
void SchedulePage::setupTableTasksChanged()
{
const auto refreshTableTasksChanged = [&] {
@ -179,6 +195,9 @@ void SchedulePage::setupTableTasksChanged()
m_cscTaskInterval->spinBox()->setValue(
taskListModel()->data(index, TaskListModel::RoleIntervalHours).toInt());
m_cbTaskRunOnStartup->setChecked(
taskListModel()->data(index, TaskListModel::RoleRunOnStartup).toBool());
const bool running = currentTaskInfo()->running();
m_btTaskRun->setEnabled(!running);
m_btTaskAbort->setEnabled(running);

View File

@ -26,13 +26,14 @@ protected slots:
void onRetranslateUi() override;
private:
void retranslateTaskDetails();
void retranslateTaskInterval();
void setupUi();
void setupTableTasks();
void setupTableTasksHeader();
void setupTaskDetails();
void setupTaskInterval();
void setupTaskRunOnStartup();
void setupTableTasksChanged();
int currentTaskIndex() const;
@ -48,6 +49,7 @@ private:
TableView *m_tableTasks = nullptr;
QWidget *m_taskDetailsRow = nullptr;
CheckSpinCombo *m_cscTaskInterval = nullptr;
QCheckBox *m_cbTaskRunOnStartup = nullptr;
QToolButton *m_btTaskRun = nullptr;
QToolButton *m_btTaskAbort = nullptr;
};

View File

@ -4,6 +4,8 @@
#include <conf/confappmanager.h>
#include <manager/windowmanager.h>
#include <model/applistmodel.h>
#include <task/taskinfoapppurger.h>
#include <task/taskmanager.h>
#include <util/ioc/ioccontainer.h>
namespace {
@ -63,7 +65,5 @@ void ProgramsController::deleteApps(const QVector<qint64> &appIdList)
void ProgramsController::purgeApps()
{
if (!confAppManager()->purgeApps()) {
showErrorMessage(tr("Cannot purge obsolete programs"));
}
taskManager()->runTask(TaskInfo::AppPurger);
}

View File

@ -28,8 +28,6 @@ public:
protected:
void setupDriveListManager() override { }
void purgeAppsOnStart() override { }
void setupAppEndTimer() override { }
};

View File

@ -1,7 +1,7 @@
#include "taskeditinfo.h"
TaskEditInfo::TaskEditInfo(bool enabled, quint16 intervalHours) :
m_enabled(enabled), m_intervalHours(intervalHours)
TaskEditInfo::TaskEditInfo(bool enabled, bool runOnStartup, quint16 intervalHours) :
m_enabled(enabled), m_runOnStartup(runOnStartup), m_intervalHours(intervalHours)
{
}

View File

@ -6,12 +6,16 @@
class TaskEditInfo
{
public:
explicit TaskEditInfo(bool enabled = 0, quint16 intervalHours = 0);
explicit TaskEditInfo(
bool enabled = false, bool runOnStartup = false, quint16 intervalHours = 0);
explicit TaskEditInfo(quint32 v);
bool enabled() const { return m_enabled; }
void setEnabled(bool v) { m_enabled = v; }
bool runOnStartup() const { return m_runOnStartup; }
void setRunOnStartup(bool v) { m_runOnStartup = v; }
quint16 intervalHours() const { return m_intervalHours; }
void setIntervalHours(quint16 v) { m_intervalHours = v; }
@ -22,6 +26,7 @@ private:
struct
{
quint16 m_enabled : 1;
quint16 m_runOnStartup : 1;
quint16 m_intervalHours;
};
quint32 m_value = 0;

View File

@ -30,6 +30,14 @@ void TaskInfo::setEnabled(bool enabled)
}
}
void TaskInfo::setRunOnStatup(bool runOnStatup)
{
if (m_runOnStatup != runOnStatup) {
m_runOnStatup = runOnStatup;
emit runOnStatupChanged();
}
}
void TaskInfo::setRunning(bool running)
{
if (m_running != running) {
@ -53,6 +61,8 @@ QString TaskInfo::title() const
return tr("Fort Firewall Update Checker");
case ZoneDownloader:
return tr("Zones Downloader");
case AppPurger:
return tr("Purge Obsolete Programs");
default:
Q_UNREACHABLE();
return QString();
@ -101,6 +111,7 @@ void TaskInfo::editFromVariant(const QVariant &v)
const TaskEditInfo info(v.toUInt());
setEnabled(info.enabled());
setRunOnStatup(info.runOnStartup());
setIntervalHours(info.intervalHours());
}

View File

@ -12,18 +12,14 @@ class TaskWorker;
class TaskInfo : public QObject
{
Q_OBJECT
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
Q_PROPERTY(
int intervalHours READ intervalHours WRITE setIntervalHours NOTIFY intervalHoursChanged)
Q_PROPERTY(QString title READ title CONSTANT)
Q_PROPERTY(TaskInfo::TaskType type READ type WRITE setType NOTIFY typeChanged)
Q_PROPERTY(QDateTime lastRun READ lastRun WRITE setLastRun NOTIFY lastRunChanged)
Q_PROPERTY(
QDateTime lastSuccess READ lastSuccess WRITE setLastSuccess NOTIFY lastSuccessChanged)
Q_PROPERTY(bool running READ running NOTIFY taskWorkerChanged)
public:
enum TaskType : qint8 { TypeNone = -1, UpdateChecker = 0, ZoneDownloader };
enum TaskType : qint8 {
TypeNone = -1,
UpdateChecker = 0,
ZoneDownloader,
AppPurger,
};
Q_ENUM(TaskType)
explicit TaskInfo(TaskInfo::TaskType type, TaskManager &taskManager);
@ -37,6 +33,9 @@ public:
bool enabled() const { return m_enabled; }
void setEnabled(bool enabled);
bool runOnStatup() const { return m_runOnStatup; }
void setRunOnStatup(bool runOnStatup);
bool aborted() const { return m_aborted; }
bool running() const { return m_running; }
@ -74,6 +73,7 @@ public:
signals:
void enabledChanged();
void runOnStatupChanged();
void runningChanged();
void intervalHoursChanged();
void typeChanged();
@ -101,6 +101,7 @@ private:
private:
bool m_enabled : 1 = false;
bool m_runOnStatup : 1 = false;
bool m_running : 1 = false;
bool m_aborted : 1 = false; // transient

View File

@ -0,0 +1,17 @@
#include "taskinfoapppurger.h"
#include <conf/confappmanager.h>
#include <util/ioc/ioccontainer.h>
#include "taskmanager.h"
TaskInfoAppPurger::TaskInfoAppPurger(TaskManager &taskManager) :
TaskInfo(AppPurger, taskManager) { }
void TaskInfoAppPurger::runTaskWorker()
{
// TODO: Use worker to run in a separate thread to not block the UI
const bool ok = IoC<ConfAppManager>()->purgeApps();
handleFinished(ok);
}

View File

@ -0,0 +1,23 @@
#ifndef TASKINFOAPPPURGER_H
#define TASKINFOAPPPURGER_H
#include "taskinfo.h"
class TaskAppPurger;
class TaskInfoAppPurger : public TaskInfo
{
Q_OBJECT
public:
explicit TaskInfoAppPurger(TaskManager &taskManager);
public slots:
bool processResult(bool success) override { return success; }
protected slots:
void setupTaskWorker() override { }
void runTaskWorker() override;
};
#endif // TASKINFOAPPPURGER_H

View File

@ -39,19 +39,6 @@ bool TaskInfoZoneDownloader::processResult(bool success)
return true;
}
void TaskInfoZoneDownloader::loadZones()
{
TaskZoneDownloader worker;
const int rowCount = zoneListModel()->rowCount();
for (m_zoneIndex = 0; m_zoneIndex < rowCount; ++m_zoneIndex) {
setupTaskWorkerByZone(&worker);
addSubResult(&worker, false);
}
emitZonesUpdated();
}
bool TaskInfoZoneDownloader::saveZoneAsText(const QString &filePath, int zoneIndex)
{
TaskZoneDownloader worker;

View File

@ -21,7 +21,6 @@ public:
public slots:
bool processResult(bool success) override;
void loadZones();
bool saveZoneAsText(const QString &filePath, int zoneIndex);
protected slots:

View File

@ -67,6 +67,9 @@ QVariant TaskListModel::data(const QModelIndex &index, int role) const
case RoleEnabled:
return dataCheckState(index);
case RoleRunOnStartup:
return taskRunOnStartup(index.row());
case RoleIntervalHours:
return taskIntervalHours(index.row());
@ -125,6 +128,10 @@ bool TaskListModel::setData(const QModelIndex &index, const QVariant &value, int
setTaskEnabled(index, value.toBool());
return true;
case RoleRunOnStartup:
setTaskRunOnStartup(index, value.toBool());
return true;
case RoleIntervalHours:
setTaskIntervalHours(index, value.toInt());
return true;
@ -148,6 +155,7 @@ void TaskListModel::setupTaskRows()
TaskEditInfo &taskRow = taskRowAt(i);
taskRow.setEnabled(taskInfo->enabled());
taskRow.setRunOnStartup(taskInfo->runOnStatup());
taskRow.setIntervalHours(taskInfo->intervalHours());
}
}
@ -169,16 +177,30 @@ bool TaskListModel::taskEnabled(int row) const
void TaskListModel::setTaskEnabled(const QModelIndex &index, bool v)
{
const int row = index.row();
TaskEditInfo &taskRow = taskRowAt(row);
TaskEditInfo &taskRow = taskRowAt(index);
if (taskRow.enabled() == v)
return;
taskRow.setEnabled(v);
emit dataChanged(index, index, { Qt::CheckStateRole });
emit dataEdited();
emitDataEdited(index, Qt::CheckStateRole);
}
bool TaskListModel::taskRunOnStartup(int row) const
{
const TaskEditInfo &taskRow = taskRowAt(row);
return taskRow.runOnStartup();
}
void TaskListModel::setTaskRunOnStartup(const QModelIndex &index, bool v)
{
TaskEditInfo &taskRow = taskRowAt(index);
if (taskRow.runOnStartup() == v)
return;
taskRow.setRunOnStartup(v);
emitDataEdited(index, Qt::DisplayRole);
}
int TaskListModel::taskIntervalHours(int row) const
@ -189,14 +211,17 @@ int TaskListModel::taskIntervalHours(int row) const
void TaskListModel::setTaskIntervalHours(const QModelIndex &index, int v)
{
const int row = index.row();
TaskEditInfo &taskRow = taskRowAt(row);
TaskEditInfo &taskRow = taskRowAt(index);
if (taskRow.intervalHours() == v)
return;
taskRow.setIntervalHours(v);
emit dataChanged(index, index, { Qt::DisplayRole });
emitDataEdited(index, Qt::DisplayRole);
}
void TaskListModel::emitDataEdited(const QModelIndex &index, int role)
{
emit dataChanged(index, index, { role });
emit dataEdited();
}

View File

@ -15,7 +15,12 @@ class TaskListModel : public TableItemModel
Q_OBJECT
public:
enum Roles { RoleEnabled = Qt::UserRole, RoleIntervalHours, RoleRunning };
enum Roles {
RoleEnabled = Qt::UserRole,
RoleRunOnStartup,
RoleIntervalHours,
RoleRunning,
};
Q_ENUM(Roles)
explicit TaskListModel(TaskManager *taskManager, QObject *parent = nullptr);
@ -53,12 +58,19 @@ private:
bool taskEnabled(int row) const;
void setTaskEnabled(const QModelIndex &index, bool v);
bool taskRunOnStartup(int row) const;
void setTaskRunOnStartup(const QModelIndex &index, bool v);
int taskIntervalHours(int row) const;
void setTaskIntervalHours(const QModelIndex &index, int v);
TaskEditInfo &taskRowAt(int row) { return m_taskRows[row]; }
const TaskEditInfo &taskRowAt(int row) const { return m_taskRows[row]; }
inline TaskEditInfo &taskRowAt(const QModelIndex &index) { return taskRowAt(index.row()); }
void emitDataEdited(const QModelIndex &index, int role);
private:
TaskManager *m_taskManager = nullptr;

View File

@ -4,6 +4,7 @@
#include <util/dateutil.h>
#include <util/ioc/ioccontainer.h>
#include "taskinfoapppurger.h"
#include "taskinfoupdatechecker.h"
#include "taskinfozonedownloader.h"
@ -17,12 +18,17 @@ TaskManager::TaskManager(QObject *parent) : QObject(parent)
TaskInfoUpdateChecker *TaskManager::taskInfoUpdateChecker() const
{
return static_cast<TaskInfoUpdateChecker *>(taskInfoAt(0));
return static_cast<TaskInfoUpdateChecker *>(taskInfoAt(TaskInfo::UpdateChecker));
}
TaskInfoZoneDownloader *TaskManager::taskInfoZoneDownloader() const
{
return static_cast<TaskInfoZoneDownloader *>(taskInfoAt(1));
return static_cast<TaskInfoZoneDownloader *>(taskInfoAt(TaskInfo::ZoneDownloader));
}
TaskInfoAppPurger *TaskManager::taskInfoAppPurger() const
{
return static_cast<TaskInfoAppPurger *>(taskInfoAt(TaskInfo::AppPurger));
}
TaskInfo *TaskManager::taskInfoAt(int row) const
@ -39,15 +45,14 @@ void TaskManager::setUp()
void TaskManager::setupScheduler()
{
taskInfoZoneDownloader()->loadZones();
m_timer.start(3 * 1000); // 3 seconds
m_timer.start(1000); // 1 second
}
void TaskManager::setupTasks()
{
appendTaskInfo(new TaskInfoUpdateChecker(*this));
appendTaskInfo(new TaskInfoZoneDownloader(*this));
appendTaskInfo(new TaskInfoAppPurger(*this));
}
void TaskManager::appendTaskInfo(TaskInfo *taskInfo)
@ -128,11 +133,13 @@ void TaskManager::runExpiredTasks()
enabledTaskExists = true;
if (now >= taskInfo->plannedRun()) {
if ((m_isFirstRun && taskInfo->runOnStatup()) || now >= taskInfo->plannedRun()) {
taskInfo->run();
}
}
m_isFirstRun = false;
if (enabledTaskExists) {
m_timer.start(5 * 60 * 1000); // 5 minutes
} else {
@ -147,6 +154,8 @@ TaskInfo *TaskManager::taskInfoByType(qint8 taskType) const
return taskInfoUpdateChecker();
case TaskInfo::ZoneDownloader:
return taskInfoZoneDownloader();
case TaskInfo::AppPurger:
return taskInfoAppPurger();
default:
Q_UNREACHABLE();
return nullptr;

View File

@ -8,6 +8,7 @@
#include <util/ioc/iocservice.h>
class TaskInfo;
class TaskInfoAppPurger;
class TaskInfoUpdateChecker;
class TaskInfoZoneDownloader;
@ -20,6 +21,7 @@ public:
TaskInfoUpdateChecker *taskInfoUpdateChecker() const;
TaskInfoZoneDownloader *taskInfoZoneDownloader() const;
TaskInfoAppPurger *taskInfoAppPurger() const;
const QList<TaskInfo *> &taskInfoList() const { return m_taskInfoList; }
TaskInfo *taskInfoAt(int row) const;
@ -65,6 +67,8 @@ private:
void appendTaskInfo(TaskInfo *taskInfo);
private:
bool m_isFirstRun = true;
QList<TaskInfo *> m_taskInfoList;
QTimer m_timer;