Desktop Application Framework Module.
The imtapp module provides high-level application framework components for desktop applications, including backup settings, scheduled tasks, and application configuration management.
Overview
This module serves as a framework layer for building desktop applications with ImtCore, providing:
- Backup configuration and settings management
- Scheduled task parameters and configuration
- Application lifecycle support
- Settings persistence and validation
The module integrates with:
- ACF component framework for dependency injection
- imtfile for file path management
- Serialization infrastructure for settings persistence
Architecture
Design Patterns
Data Transfer Object (DTO) Pattern:
- ISchedulerParams and IBackupSettings as pure data containers
- Separate interface from implementation
- Facilitates serialization and persistence
- Enables data validation and transformation
Component Pattern (ACF):
- CSchedulerParamsComp and CBackupSettingsComp as ACF components
- Attribute-based configuration (I_ASSIGN macros)
- Serialization through iser::ISerializable
- Change notification through istd::IChangeable
Composite Pattern:
- IBackupSettings extends ISchedulerParams and IFileNameParam
- Combines scheduling configuration with file location
- Reuses common scheduling infrastructure
- Composition over inheritance
Core Interfaces
The module provides application framework interfaces:
Scheduler Configuration:
ISchedulerParams (iser::IObject)
├─ GetStartTime() / SetStartTime() - Scheduled task start time
├─ GetInterval() / SetInterval() - Task execution interval (seconds)
└─ Extends iser::IObject for serialization
│
├─ CSchedulerParams (data object implementation)
└─ CSchedulerParamsComp (ACF component)
├─ Attributes: "StartTime", "Interval"
├─ Implements iser::ISerializable
└─ Implements istd::IChangeable
Backup Configuration:
IBackupSettings (ISchedulerParams, ifile::IFileNameParam)
├─ Inherits scheduling from ISchedulerParams
├─ Inherits file path from IFileNameParam
└─ Combines backup scheduling with target location
│
├─ CBackupSettings (data object implementation)
└─ CBackupSettingsComp (ACF component)
├─ Inherits scheduler attributes
├─ Adds file path configuration
└─ Serializable backup configuration
Core Components
Scheduler Parameters
ISchedulerParams / CSchedulerParamsComp** - Scheduled task configuration:
auto scheduler = CSchedulerParamsComp::CreateInstance();
QDateTime startTime = QDateTime::currentDateTime().addSecs(3600);
scheduler->SetStartTime(startTime);
int intervalInSeconds = 3600;
scheduler->SetInterval(intervalInSeconds);
QDateTime scheduledTime = scheduler->GetStartTime();
int interval = scheduler->GetInterval();
qDebug() << "Next run:" << scheduledTime
<< "Interval:" << interval << "seconds";
Component Attributes:**
Backup Settings
IBackupSettings / CBackupSettingsComp** - Backup configuration:
auto backupSettings = CBackupSettingsComp::CreateInstance();
backupSettings->SetStartTime(QDateTime::currentDateTime());
backupSettings->SetInterval(86400);
QString backupPath = QStandardPaths::writableLocation(
QStandardPaths::AppDataLocation) + "/backups";
backupSettings->SetFileName(backupPath);
qDebug() << "Backup location:" << backupSettings->GetFileName();
qDebug() << "Backup time:" << backupSettings->GetStartTime();
qDebug() << "Backup interval:" << backupSettings->GetInterval() << "seconds";
Use Cases:**
- Configuring automatic backup schedules
- Persisting backup preferences
- User-configurable backup settings UI
- Integration with backup management systems
Integration Patterns
Integration with Task Scheduler
Pattern: Scheduled Backup Service:**
class CBackupServiceComp : public ACF_COMPONENT(IBackupService)
{
I_REFERENCE(IBackupSettings, m_backupSettings)
I_REFERENCE(IFileCompression, m_compression)
QTimer* m_backupTimer;
public:
void InitializeComponent() override
{
m_backupTimer = new QTimer(this);
connect(m_backupTimer, &QTimer::timeout,
this, &CBackupServiceComp::PerformBackup);
ConfigureScheduler();
}
void ConfigureScheduler()
{
int intervalSeconds = m_backupSettings->GetInterval();
m_backupTimer->setInterval(intervalSeconds * 1000);
QDateTime startTime = m_backupSettings->GetStartTime();
QDateTime now = QDateTime::currentDateTime();
if (startTime > now) {
int delayMs = now.msecsTo(startTime);
QTimer::singleShot(delayMs, this, &CBackupServiceComp::StartScheduler);
} else {
StartScheduler();
}
}
void StartScheduler()
{
m_backupTimer->start();
PerformBackup();
}
void PerformBackup()
{
QString backupPath = m_backupSettings->GetFileName();
QString dataDir = GetApplicationDataDirectory();
QString timestamp = QDateTime::currentDateTime()
.toString("yyyyMMdd_hhmmss");
QString archivePath = QString("%1/backup_%2.zip")
.arg(backupPath)
.arg(timestamp);
m_compression->CompressFolder(dataDir, archivePath, true);
qDebug() << "Backup completed:" << archivePath;
}
};
Integration with Application Settings
Pattern: Persisted Configuration:**
class CApplicationSettingsComp : public ACF_COMPONENT(IApplicationSettings)
{
I_REFERENCE(IBackupSettings, m_backupSettings)
I_REFERENCE(IFilePersistence, m_persistence)
public:
bool LoadSettings()
{
QString settingsPath = GetSettingsFilePath();
if (QFile::exists(settingsPath)) {
int result = m_persistence->LoadFromFile(
m_backupSettings,
settingsPath);
return result == ifile::IFilePersistence::OS_OK;
}
SetDefaultSettings();
return true;
}
bool SaveSettings()
{
QString settingsPath = GetSettingsFilePath();
int result = m_persistence->SaveToFile(
m_backupSettings,
settingsPath);
return result == ifile::IFilePersistence::OS_OK;
}
void SetDefaultSettings()
{
QDateTime nextBackup = QDateTime::currentDateTime();
nextBackup.setTime(QTime(2, 0));
if (nextBackup < QDateTime::currentDateTime()) {
nextBackup = nextBackup.addDays(1);
}
m_backupSettings->SetStartTime(nextBackup);
m_backupSettings->SetInterval(86400);
QString defaultPath = QStandardPaths::writableLocation(
QStandardPaths::AppDataLocation) + "/backups";
m_backupSettings->SetFileName(defaultPath);
}
QString GetSettingsFilePath() const
{
return QStandardPaths::writableLocation(
QStandardPaths::AppConfigLocation) + "/backup_settings.xml";
}
};
Integration with Settings UI
Pattern: Settings Dialog:**
class CBackupSettingsDialogComp : public ACF_COMPONENT(ISettingsDialog)
{
I_REFERENCE(IBackupSettings, m_backupSettings)
QDateTimeEdit* m_startTimeEdit;
QSpinBox* m_intervalSpinBox;
QLineEdit* m_pathEdit;
QPushButton* m_browseButton;
public:
void InitializeUI()
{
m_startTimeEdit = new QDateTimeEdit();
m_startTimeEdit->setDisplayFormat("dd-MM-yyyy HH:mm");
m_intervalSpinBox = new QSpinBox();
m_intervalSpinBox->setRange(60, 604800);
m_intervalSpinBox->setSuffix(" seconds");
m_pathEdit = new QLineEdit();
m_browseButton = new QPushButton("Browse...");
connect(m_browseButton, &QPushButton::clicked,
this, &CBackupSettingsDialogComp::OnBrowse);
LoadFromSettings();
}
void LoadFromSettings()
{
m_startTimeEdit->setDateTime(m_backupSettings->GetStartTime());
m_intervalSpinBox->setValue(m_backupSettings->GetInterval());
m_pathEdit->setText(m_backupSettings->GetFileName());
}
void SaveToSettings()
{
m_backupSettings->SetStartTime(m_startTimeEdit->dateTime());
m_backupSettings->SetInterval(m_intervalSpinBox->value());
m_backupSettings->SetFileName(m_pathEdit->text());
}
void OnBrowse()
{
QString dir = QFileDialog::getExistingDirectory(
nullptr,
"Select Backup Directory",
m_pathEdit->text());
if (!dir.isEmpty()) {
m_pathEdit->setText(dir);
}
}
};
Complete Examples
Complete Backup Service
class CAutoBackupServiceComp : public ACF_COMPONENT(IAutoBackupService)
{
I_REFERENCE(IBackupSettings, m_backupSettings)
I_REFERENCE(IFileCompression, m_compression)
I_REFERENCE(IFilePersistence, m_settingsPersistence)
QTimer* m_schedulerTimer;
bool m_isRunning;
public:
CAutoBackupServiceComp()
: m_schedulerTimer(nullptr)
, m_isRunning(false)
{
}
void InitializeComponent() override
{
LoadSettings();
m_schedulerTimer = new QTimer(this);
m_schedulerTimer->setSingleShot(false);
connect(m_schedulerTimer, &QTimer::timeout,
this, &CAutoBackupServiceComp::OnScheduledBackup);
connect(m_backupSettings, &IBackupSettings::Changed,
this, &CAutoBackupServiceComp::OnSettingsChanged);
}
void Start()
{
if (m_isRunning) {
return;
}
m_isRunning = true;
int intervalMs = m_backupSettings->GetInterval() * 1000;
m_schedulerTimer->setInterval(intervalMs);
QDateTime startTime = m_backupSettings->GetStartTime();
QDateTime now = QDateTime::currentDateTime();
if (startTime > now) {
int delayMs = now.msecsTo(startTime);
QTimer::singleShot(delayMs, [this]() {
OnScheduledBackup();
m_schedulerTimer->start();
});
} else {
m_schedulerTimer->start();
OnScheduledBackup();
}
qDebug() << "Backup service started";
}
void Stop()
{
if (!m_isRunning) {
return;
}
m_schedulerTimer->stop();
m_isRunning = false;
qDebug() << "Backup service stopped";
}
void OnScheduledBackup()
{
try {
QString backupDir = m_backupSettings->GetFileName();
QDir().mkpath(backupDir);
QString timestamp = QDateTime::currentDateTime()
.toString("yyyyMMdd_hhmmss");
QString archivePath = QString("%1/backup_%2.zip")
.arg(backupDir)
.arg(timestamp);
QString dataDir = QStandardPaths::writableLocation(
QStandardPaths::AppDataLocation) + "/data";
qDebug() << "Starting backup:" << archivePath;
bool success = m_compression->CompressFolder(
dataDir,
archivePath,
true
);
if (success) {
qDebug() << "Backup completed successfully:" << archivePath;
CleanupOldBackups(backupDir);
} else {
qWarning() << "Backup failed:" << archivePath;
}
} catch (const std::exception& e) {
qCritical() << "Backup error:" << e.what();
}
}
void OnSettingsChanged()
{
SaveSettings();
if (m_isRunning) {
Stop();
Start();
}
}
void LoadSettings()
{
QString settingsPath = GetSettingsFilePath();
if (QFile::exists(settingsPath)) {
m_settingsPersistence->LoadFromFile(m_backupSettings, settingsPath);
} else {
SetDefaultSettings();
SaveSettings();
}
}
void SaveSettings()
{
QString settingsPath = GetSettingsFilePath();
m_settingsPersistence->SaveToFile(m_backupSettings, settingsPath);
}
void SetDefaultSettings()
{
QDateTime nextBackup = QDateTime::currentDateTime();
nextBackup.setTime(QTime(2, 0, 0));
if (nextBackup < QDateTime::currentDateTime()) {
nextBackup = nextBackup.addDays(1);
}
m_backupSettings->SetStartTime(nextBackup);
m_backupSettings->SetInterval(86400);
QString defaultPath = QStandardPaths::writableLocation(
QStandardPaths::AppDataLocation) + "/backups";
m_backupSettings->SetFileName(defaultPath);
}
void CleanupOldBackups(const QString& backupDir, int keepCount = 10)
{
QDir dir(backupDir);
QStringList backups = dir.entryList(
QStringList() << "backup_*.zip",
QDir::Files,
QDir::Time | QDir::Reversed);
for (int i = keepCount; i < backups.size(); ++i) {
QString oldBackup = dir.filePath(backups[i]);
QFile::remove(oldBackup);
qDebug() << "Removed old backup:" << oldBackup;
}
}
QString GetSettingsFilePath() const
{
return QStandardPaths::writableLocation(
QStandardPaths::AppConfigLocation) + "/backup_settings.xml";
}
};
Best Practices
Input Validation
- Validate start times to ensure they're in the future or current
- Enforce minimum and maximum intervals
- Verify backup paths are writable before saving settings
- Provide user feedback for invalid configurations
Settings Persistence
- Save settings immediately when changed (or provide "Apply" button)
- Use appropriate serialization format (XML for human-readability)
- Handle missing settings files gracefully with defaults
- Backup settings before overwriting
Scheduling Considerations
- Handle time zone changes appropriately
- Consider daylight saving time transitions
- Provide options for missed executions (run immediately or skip)
- Log all scheduled task executions
Integration with Other Modules
With imtfile (File Operations):
- Uses IFileNameParam for file path configuration
- Integration with file compression services
- Backup file management
With imtdb (Database):
- Database backup scheduling
- Configuration persistence in database
- Transaction-based settings updates
With imtgui (UI Components):
- Settings dialog implementations
- Visual scheduler configuration
- Backup status displays
References
Related Modules:
- ifile (ACF) - File name parameter interfaces
- iser (ACF) - Serialization infrastructure
- istd (ACF) - Change notification
- imtfile - File operations and compression
ACF Interfaces:
- iser::ISerializable - Persistence interface
- iser::IObject - Base serializable object
- istd::IChangeable - Change notification
- ifile::IFileNameParam - File path parameter
External Documentation: