Experimental feature: database/settings backup.
This commit is contained in:
parent
145a1d8e04
commit
11e74a0b6a
9 changed files with 84 additions and 43 deletions
|
@ -75,6 +75,9 @@
|
||||||
#define FEEDS_VIEW_INDENTATION 10
|
#define FEEDS_VIEW_INDENTATION 10
|
||||||
#define ACCEPT_HEADER_FOR_FEED_DOWNLOADER "application/atom+xml,application/xml;q=0.9,text/xml;q=0.8,*/*;q=0.7"
|
#define ACCEPT_HEADER_FOR_FEED_DOWNLOADER "application/atom+xml,application/xml;q=0.9,text/xml;q=0.8,*/*;q=0.7"
|
||||||
|
|
||||||
|
#define BACKUP_SUFFIX_SETTINGS ".ini.backup"
|
||||||
|
#define BACKUP_SUFFIX_DATABASE ".db.backup"
|
||||||
|
|
||||||
#define APP_DB_MYSQL_DRIVER "QMYSQL"
|
#define APP_DB_MYSQL_DRIVER "QMYSQL"
|
||||||
#define APP_DB_MYSQL_INIT "db_init_mysql.sql"
|
#define APP_DB_MYSQL_INIT "db_init_mysql.sql"
|
||||||
#define APP_DB_MYSQL_TEST "MySQLTest"
|
#define APP_DB_MYSQL_TEST "MySQLTest"
|
||||||
|
|
|
@ -43,6 +43,7 @@ FormBackupDatabaseSettings::FormBackupDatabaseSettings(QWidget *parent) : QDialo
|
||||||
|
|
||||||
selectFolder(qApp->documentsFolderPath());
|
selectFolder(qApp->documentsFolderPath());
|
||||||
m_ui->m_txtBackupName->lineEdit()->setText(QString(APP_LOW_NAME) + "_" + QDateTime::currentDateTime().toString("yyyyMMddHHmm"));
|
m_ui->m_txtBackupName->lineEdit()->setText(QString(APP_LOW_NAME) + "_" + QDateTime::currentDateTime().toString("yyyyMMddHHmm"));
|
||||||
|
m_ui->m_lblResult->setStatus(WidgetWithStatus::Warning, tr("No operation executed yet."), tr("No operation executed yet."));
|
||||||
|
|
||||||
if (qApp->database()->activeDatabaseDriver() != DatabaseFactory::SQLITE &&
|
if (qApp->database()->activeDatabaseDriver() != DatabaseFactory::SQLITE &&
|
||||||
qApp->database()->activeDatabaseDriver() != DatabaseFactory::SQLITE_MEMORY) {
|
qApp->database()->activeDatabaseDriver() != DatabaseFactory::SQLITE_MEMORY) {
|
||||||
|
@ -55,7 +56,20 @@ FormBackupDatabaseSettings::~FormBackupDatabaseSettings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormBackupDatabaseSettings::performBackup() {
|
void FormBackupDatabaseSettings::performBackup() {
|
||||||
// TODO: Backup.
|
if (qApp->backupDatabaseSettings(m_ui->m_checkBackupDatabase->isChecked(),
|
||||||
|
m_ui->m_checkBackupSettings->isChecked(),
|
||||||
|
m_ui->m_lblSelectFolder->label()->text(),
|
||||||
|
m_ui->m_txtBackupName->lineEdit()->text())) {
|
||||||
|
m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok,
|
||||||
|
tr("Backup was created successfully and stored in target folder."),
|
||||||
|
tr("Backup was created successfully."));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_ui->m_lblResult->setStatus(WidgetWithStatus::Error,
|
||||||
|
tr("Backup failed, database and/or settings is probably not backed."),
|
||||||
|
tr("Backup failed. Check the output folder if your database\nand/or "
|
||||||
|
"settings were backed or not. Also make sure that target foder is writable."));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormBackupDatabaseSettings::selectFolder(QString path) {
|
void FormBackupDatabaseSettings::selectFolder(QString path) {
|
||||||
|
@ -64,7 +78,8 @@ void FormBackupDatabaseSettings::selectFolder(QString path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!path.isEmpty()) {
|
if (!path.isEmpty()) {
|
||||||
m_ui->m_lblSelectFolder->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(path), tr("Good destination folder is specified."));
|
m_ui->m_lblSelectFolder->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(path),
|
||||||
|
tr("Good destination folder is specified."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,22 +140,6 @@
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections>
|
||||||
<connection>
|
|
||||||
<sender>m_buttonBox</sender>
|
|
||||||
<signal>accepted()</signal>
|
|
||||||
<receiver>FormBackupDatabaseSettings</receiver>
|
|
||||||
<slot>accept()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>199</x>
|
|
||||||
<y>283</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>199</x>
|
|
||||||
<y>149</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
<connection>
|
||||||
<sender>m_buttonBox</sender>
|
<sender>m_buttonBox</sender>
|
||||||
<signal>rejected()</signal>
|
<signal>rejected()</signal>
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "miscellaneous/application.h"
|
#include "miscellaneous/application.h"
|
||||||
|
|
||||||
#include "miscellaneous/iconfactory.h"
|
#include "miscellaneous/iconfactory.h"
|
||||||
|
#include "miscellaneous/iofactory.h"
|
||||||
#include "gui/feedsview.h"
|
#include "gui/feedsview.h"
|
||||||
#include "gui/feedmessageviewer.h"
|
#include "gui/feedmessageviewer.h"
|
||||||
#include "gui/messagebox.h"
|
#include "gui/messagebox.h"
|
||||||
|
@ -58,9 +59,34 @@ IconFactory *Application::icons() {
|
||||||
return m_icons;
|
return m_icons;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Application::backupDatabaseSettings(bool backup_database, bool backup_settings,
|
||||||
|
const QString &target_path, const QString &backup_name) {
|
||||||
|
if (!QFileInfo(target_path).isWritable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool final_result = true;
|
||||||
|
|
||||||
|
if (backup_settings) {
|
||||||
|
settings()->sync();
|
||||||
|
final_result = final_result && IOFactory::copyFile(settings()->fileName(),
|
||||||
|
target_path + QDir::separator() + backup_name + BACKUP_SUFFIX_SETTINGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backup_database &&
|
||||||
|
(database()->activeDatabaseDriver() == DatabaseFactory::SQLITE ||
|
||||||
|
database()->activeDatabaseDriver() == DatabaseFactory::SQLITE_MEMORY)) {
|
||||||
|
// We need to save the database first.
|
||||||
|
database()->saveDatabase();
|
||||||
|
final_result = final_result && IOFactory::copyFile(database()->sqliteDatabaseFilePath(),
|
||||||
|
target_path + QDir::separator() + backup_name + BACKUP_SUFFIX_DATABASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return final_result;
|
||||||
|
}
|
||||||
|
|
||||||
void Application::processExecutionMessage(const QString &message) {
|
void Application::processExecutionMessage(const QString &message) {
|
||||||
qDebug("Received '%s' execution message from another application instance.",
|
qDebug("Received '%s' execution message from another application instance.", qPrintable(message));
|
||||||
qPrintable(message));
|
|
||||||
|
|
||||||
if (message == APP_IS_RUNNING) {
|
if (message == APP_IS_RUNNING) {
|
||||||
if (SystemTrayIcon::isSystemTrayActivated()) {
|
if (SystemTrayIcon::isSystemTrayActivated()) {
|
||||||
|
|
|
@ -145,6 +145,8 @@ class Application : public QtSingleApplication {
|
||||||
return home_path;
|
return home_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool backupDatabaseSettings(bool backup_database, bool backup_settings, const QString &target_path, const QString &backup_name);
|
||||||
|
|
||||||
// Access to application tray icon. Always use this in cooperation with
|
// Access to application tray icon. Always use this in cooperation with
|
||||||
// SystemTrayIcon::isSystemTrayActivated().
|
// SystemTrayIcon::isSystemTrayActivated().
|
||||||
SystemTrayIcon *trayIcon();
|
SystemTrayIcon *trayIcon();
|
||||||
|
|
|
@ -82,9 +82,7 @@ QString DatabaseFactory::mysqlInterpretErrorCode(MySQLError error_code) {
|
||||||
|
|
||||||
void DatabaseFactory::sqliteAssemblyDatabaseFilePath() {
|
void DatabaseFactory::sqliteAssemblyDatabaseFilePath() {
|
||||||
if (qApp->settings()->type() == Settings::Portable) {
|
if (qApp->settings()->type() == Settings::Portable) {
|
||||||
m_sqliteDatabaseFilePath = qApp->applicationDirPath() +
|
m_sqliteDatabaseFilePath = qApp->applicationDirPath() + QDir::separator() + QString(APP_DB_SQLITE_PATH);
|
||||||
QDir::separator() +
|
|
||||||
QString(APP_DB_SQLITE_PATH);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_sqliteDatabaseFilePath = qApp->homeFolderPath() + QDir::separator() +
|
m_sqliteDatabaseFilePath = qApp->homeFolderPath() + QDir::separator() +
|
||||||
|
@ -267,6 +265,9 @@ QSqlDatabase DatabaseFactory::sqliteInitializeFileBasedDatabase(const QString &c
|
||||||
return database;
|
return database;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString DatabaseFactory::sqliteDatabaseFilePath() const {
|
||||||
|
return m_sqliteDatabaseFilePath + QDir::separator() + APP_DB_SQLITE_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
QSqlDatabase DatabaseFactory::connection(const QString &connection_name,
|
QSqlDatabase DatabaseFactory::connection(const QString &connection_name,
|
||||||
DesiredType desired_type) {
|
DesiredType desired_type) {
|
||||||
|
@ -315,8 +316,7 @@ void DatabaseFactory::determineDriver() {
|
||||||
"database_driver",
|
"database_driver",
|
||||||
APP_DB_SQLITE_DRIVER).toString();
|
APP_DB_SQLITE_DRIVER).toString();
|
||||||
|
|
||||||
if (db_driver == APP_DB_MYSQL_DRIVER &&
|
if (db_driver == APP_DB_MYSQL_DRIVER && QSqlDatabase::isDriverAvailable(APP_DB_SQLITE_DRIVER)) {
|
||||||
QSqlDatabase::isDriverAvailable(APP_DB_SQLITE_DRIVER)) {
|
|
||||||
// User wants to use MySQL and MySQL is actually available. Use it.
|
// User wants to use MySQL and MySQL is actually available. Use it.
|
||||||
m_activeDatabaseDriver = MYSQL;
|
m_activeDatabaseDriver = MYSQL;
|
||||||
|
|
||||||
|
@ -355,8 +355,7 @@ QSqlDatabase DatabaseFactory::mysqlConnection(const QString &connection_name) {
|
||||||
QSqlDatabase database;
|
QSqlDatabase database;
|
||||||
|
|
||||||
if (QSqlDatabase::contains(connection_name)) {
|
if (QSqlDatabase::contains(connection_name)) {
|
||||||
qDebug("MySQL connection '%s' is already active.",
|
qDebug("MySQL connection '%s' is already active.", qPrintable(connection_name));
|
||||||
qPrintable(connection_name));
|
|
||||||
|
|
||||||
// This database connection was added previously, no need to
|
// This database connection was added previously, no need to
|
||||||
// setup its properties.
|
// setup its properties.
|
||||||
|
@ -390,8 +389,7 @@ QSqlDatabase DatabaseFactory::mysqlConnection(const QString &connection_name) {
|
||||||
|
|
||||||
QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_name) {
|
QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_name) {
|
||||||
// Folders are created. Create new QSQLDatabase object.
|
// Folders are created. Create new QSQLDatabase object.
|
||||||
QSqlDatabase database = QSqlDatabase::addDatabase(APP_DB_MYSQL_DRIVER,
|
QSqlDatabase database = QSqlDatabase::addDatabase(APP_DB_MYSQL_DRIVER, connection_name);
|
||||||
connection_name);
|
|
||||||
|
|
||||||
database.setHostName(qApp->settings()->value(APP_CFG_DB, "mysql_hostname").toString());
|
database.setHostName(qApp->settings()->value(APP_CFG_DB, "mysql_hostname").toString());
|
||||||
database.setPort(qApp->settings()->value(APP_CFG_DB, "mysql_port", APP_DB_MYSQL_PORT).toInt());
|
database.setPort(qApp->settings()->value(APP_CFG_DB, "mysql_port", APP_DB_MYSQL_PORT).toInt());
|
||||||
|
@ -407,8 +405,7 @@ QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_
|
||||||
|
|
||||||
query_db.setForwardOnly(true);
|
query_db.setForwardOnly(true);
|
||||||
|
|
||||||
if (!query_db.exec("USE rssguard") ||
|
if (!query_db.exec("USE rssguard") || !query_db.exec("SELECT inf_value FROM Information WHERE inf_key = 'schema_version'")) {
|
||||||
!query_db.exec("SELECT inf_value FROM Information WHERE inf_key = 'schema_version'")) {
|
|
||||||
// If no "rssguard" database exists
|
// If no "rssguard" database exists
|
||||||
// or schema version is wrong, then initialize it.
|
// or schema version is wrong, then initialize it.
|
||||||
qWarning("Error occurred. MySQL database is not initialized. Initializing now.");
|
qWarning("Error occurred. MySQL database is not initialized. Initializing now.");
|
||||||
|
@ -422,8 +419,7 @@ QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_
|
||||||
qPrintable(APP_MISC_PATH));
|
qPrintable(APP_MISC_PATH));
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList statements = QString(file_init.readAll()).split(APP_DB_COMMENT_SPLIT,
|
QStringList statements = QString(file_init.readAll()).split(APP_DB_COMMENT_SPLIT, QString::SkipEmptyParts);
|
||||||
QString::SkipEmptyParts);
|
|
||||||
database.transaction();
|
database.transaction();
|
||||||
|
|
||||||
foreach(const QString &statement, statements) {
|
foreach(const QString &statement, statements) {
|
||||||
|
@ -441,8 +437,7 @@ QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_
|
||||||
else {
|
else {
|
||||||
query_db.next();
|
query_db.next();
|
||||||
|
|
||||||
qDebug("MySQL database connection '%s' seems to be established.",
|
qDebug("MySQL database connection '%s' seems to be established.", qPrintable(connection_name));
|
||||||
qPrintable(connection_name));
|
|
||||||
qDebug("MySQL database has version '%s'.", qPrintable(query_db.value(0).toString()));
|
qDebug("MySQL database has version '%s'.", qPrintable(query_db.value(0).toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,8 +457,7 @@ bool DatabaseFactory::mysqlVacuumDatabase() {
|
||||||
return query_vacuum.exec("OPTIMIZE TABLE rssguard.feeds;") && query_vacuum.exec("OPTIMIZE TABLE rssguard.messages;");
|
return query_vacuum.exec("OPTIMIZE TABLE rssguard.feeds;") && query_vacuum.exec("OPTIMIZE TABLE rssguard.messages;");
|
||||||
}
|
}
|
||||||
|
|
||||||
QSqlDatabase DatabaseFactory::sqliteConnection(const QString &connection_name,
|
QSqlDatabase DatabaseFactory::sqliteConnection(const QString &connection_name, DatabaseFactory::DesiredType desired_type) {
|
||||||
DatabaseFactory::DesiredType desired_type) {
|
|
||||||
if (desired_type == DatabaseFactory::StrictlyInMemory ||
|
if (desired_type == DatabaseFactory::StrictlyInMemory ||
|
||||||
(desired_type == DatabaseFactory::FromSettings && m_activeDatabaseDriver == SQLITE_MEMORY)) {
|
(desired_type == DatabaseFactory::FromSettings && m_activeDatabaseDriver == SQLITE_MEMORY)) {
|
||||||
// We request in-memory database (either user explicitly
|
// We request in-memory database (either user explicitly
|
||||||
|
@ -498,8 +492,7 @@ QSqlDatabase DatabaseFactory::sqliteConnection(const QString &connection_name,
|
||||||
QSqlDatabase database;
|
QSqlDatabase database;
|
||||||
|
|
||||||
if (QSqlDatabase::contains(connection_name)) {
|
if (QSqlDatabase::contains(connection_name)) {
|
||||||
qDebug("SQLite connection '%s' is already active.",
|
qDebug("SQLite connection '%s' is already active.", qPrintable(connection_name));
|
||||||
qPrintable(connection_name));
|
|
||||||
|
|
||||||
// This database connection was added previously, no need to
|
// This database connection was added previously, no need to
|
||||||
// setup its properties.
|
// setup its properties.
|
||||||
|
|
|
@ -74,6 +74,14 @@ class DatabaseFactory : public QObject {
|
||||||
// Performs cleanup of the database.
|
// Performs cleanup of the database.
|
||||||
bool vacuumDatabase();
|
bool vacuumDatabase();
|
||||||
|
|
||||||
|
// Returns identification of currently active database driver.
|
||||||
|
UsedDriver activeDatabaseDriver() const;
|
||||||
|
|
||||||
|
//
|
||||||
|
// SQLITE stuff.
|
||||||
|
//
|
||||||
|
QString sqliteDatabaseFilePath() const;
|
||||||
|
|
||||||
//
|
//
|
||||||
// MySQL stuff.
|
// MySQL stuff.
|
||||||
//
|
//
|
||||||
|
@ -85,8 +93,6 @@ class DatabaseFactory : public QObject {
|
||||||
|
|
||||||
QString mysqlInterpretErrorCode(MySQLError error_code);
|
QString mysqlInterpretErrorCode(MySQLError error_code);
|
||||||
|
|
||||||
UsedDriver activeDatabaseDriver() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//
|
//
|
||||||
// GENERAL stuff.
|
// GENERAL stuff.
|
||||||
|
|
|
@ -25,6 +25,16 @@
|
||||||
IOFactory::IOFactory() {
|
IOFactory::IOFactory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IOFactory::copyFile(const QString &source, const QString &destination) {
|
||||||
|
if (QFile::exists(destination)) {
|
||||||
|
if (!QFile::remove(destination)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QFile::copy(source, destination);
|
||||||
|
}
|
||||||
|
|
||||||
bool IOFactory::removeFolder(const QString& directory_name,
|
bool IOFactory::removeFolder(const QString& directory_name,
|
||||||
const QStringList& exception_file_list,
|
const QStringList& exception_file_list,
|
||||||
const QStringList& exception_folder_list) {
|
const QStringList& exception_folder_list) {
|
||||||
|
@ -59,7 +69,7 @@ bool IOFactory::removeFolder(const QString& directory_name,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IOFactory::copyFolder(QString source, QString destination) {
|
bool IOFactory::copyFolder(const QString &source, const QString &destination) {
|
||||||
QDir dir_source(source);
|
QDir dir_source(source);
|
||||||
|
|
||||||
if (!dir_source.exists()) {
|
if (!dir_source.exists()) {
|
||||||
|
|
|
@ -26,9 +26,11 @@ class IOFactory {
|
||||||
IOFactory();
|
IOFactory();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
static bool copyFile(const QString &source, const QString &destination);
|
||||||
|
|
||||||
// Copy whole directory recursively.
|
// Copy whole directory recursively.
|
||||||
// Destination path is created if it does not exist.
|
// Destination path is created if it does not exist.
|
||||||
static bool copyFolder(QString source, QString destination);
|
static bool copyFolder(const QString &source, const QString &destination);
|
||||||
|
|
||||||
// Removes directory recursively and skips given folders/files.
|
// Removes directory recursively and skips given folders/files.
|
||||||
static bool removeFolder(const QString &directory_name,
|
static bool removeFolder(const QString &directory_name,
|
||||||
|
|
Loading…
Add table
Reference in a new issue