Experimental feature: database/settings backup.

This commit is contained in:
Martin Rotter 2014-10-11 14:41:10 +02:00
parent 145a1d8e04
commit 11e74a0b6a
9 changed files with 84 additions and 43 deletions

View File

@ -75,6 +75,9 @@
#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 BACKUP_SUFFIX_SETTINGS ".ini.backup"
#define BACKUP_SUFFIX_DATABASE ".db.backup"
#define APP_DB_MYSQL_DRIVER "QMYSQL"
#define APP_DB_MYSQL_INIT "db_init_mysql.sql"
#define APP_DB_MYSQL_TEST "MySQLTest"

View File

@ -43,6 +43,7 @@ FormBackupDatabaseSettings::FormBackupDatabaseSettings(QWidget *parent) : QDialo
selectFolder(qApp->documentsFolderPath());
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 &&
qApp->database()->activeDatabaseDriver() != DatabaseFactory::SQLITE_MEMORY) {
@ -55,7 +56,20 @@ FormBackupDatabaseSettings::~FormBackupDatabaseSettings() {
}
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) {
@ -64,7 +78,8 @@ void FormBackupDatabaseSettings::selectFolder(QString path) {
}
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."));
}
}

View File

@ -140,22 +140,6 @@
</customwidgets>
<resources/>
<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>
<sender>m_buttonBox</sender>
<signal>rejected()</signal>

View File

@ -18,6 +18,7 @@
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/iofactory.h"
#include "gui/feedsview.h"
#include "gui/feedmessageviewer.h"
#include "gui/messagebox.h"
@ -58,9 +59,34 @@ IconFactory *Application::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) {
qDebug("Received '%s' execution message from another application instance.",
qPrintable(message));
qDebug("Received '%s' execution message from another application instance.", qPrintable(message));
if (message == APP_IS_RUNNING) {
if (SystemTrayIcon::isSystemTrayActivated()) {

View File

@ -145,6 +145,8 @@ class Application : public QtSingleApplication {
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
// SystemTrayIcon::isSystemTrayActivated().
SystemTrayIcon *trayIcon();

View File

@ -82,9 +82,7 @@ QString DatabaseFactory::mysqlInterpretErrorCode(MySQLError error_code) {
void DatabaseFactory::sqliteAssemblyDatabaseFilePath() {
if (qApp->settings()->type() == Settings::Portable) {
m_sqliteDatabaseFilePath = qApp->applicationDirPath() +
QDir::separator() +
QString(APP_DB_SQLITE_PATH);
m_sqliteDatabaseFilePath = qApp->applicationDirPath() + QDir::separator() + QString(APP_DB_SQLITE_PATH);
}
else {
m_sqliteDatabaseFilePath = qApp->homeFolderPath() + QDir::separator() +
@ -267,6 +265,9 @@ QSqlDatabase DatabaseFactory::sqliteInitializeFileBasedDatabase(const QString &c
return database;
}
QString DatabaseFactory::sqliteDatabaseFilePath() const {
return m_sqliteDatabaseFilePath + QDir::separator() + APP_DB_SQLITE_FILE;
}
QSqlDatabase DatabaseFactory::connection(const QString &connection_name,
DesiredType desired_type) {
@ -315,8 +316,7 @@ void DatabaseFactory::determineDriver() {
"database_driver",
APP_DB_SQLITE_DRIVER).toString();
if (db_driver == APP_DB_MYSQL_DRIVER &&
QSqlDatabase::isDriverAvailable(APP_DB_SQLITE_DRIVER)) {
if (db_driver == APP_DB_MYSQL_DRIVER && QSqlDatabase::isDriverAvailable(APP_DB_SQLITE_DRIVER)) {
// User wants to use MySQL and MySQL is actually available. Use it.
m_activeDatabaseDriver = MYSQL;
@ -355,8 +355,7 @@ QSqlDatabase DatabaseFactory::mysqlConnection(const QString &connection_name) {
QSqlDatabase database;
if (QSqlDatabase::contains(connection_name)) {
qDebug("MySQL connection '%s' is already active.",
qPrintable(connection_name));
qDebug("MySQL connection '%s' is already active.", qPrintable(connection_name));
// This database connection was added previously, no need to
// setup its properties.
@ -390,8 +389,7 @@ QSqlDatabase DatabaseFactory::mysqlConnection(const QString &connection_name) {
QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_name) {
// Folders are created. Create new QSQLDatabase object.
QSqlDatabase database = QSqlDatabase::addDatabase(APP_DB_MYSQL_DRIVER,
connection_name);
QSqlDatabase database = QSqlDatabase::addDatabase(APP_DB_MYSQL_DRIVER, connection_name);
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());
@ -407,8 +405,7 @@ QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_
query_db.setForwardOnly(true);
if (!query_db.exec("USE rssguard") ||
!query_db.exec("SELECT inf_value FROM Information WHERE inf_key = 'schema_version'")) {
if (!query_db.exec("USE rssguard") || !query_db.exec("SELECT inf_value FROM Information WHERE inf_key = 'schema_version'")) {
// If no "rssguard" database exists
// or schema version is wrong, then initialize it.
qWarning("Error occurred. MySQL database is not initialized. Initializing now.");
@ -422,8 +419,7 @@ QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_
qPrintable(APP_MISC_PATH));
}
QStringList statements = QString(file_init.readAll()).split(APP_DB_COMMENT_SPLIT,
QString::SkipEmptyParts);
QStringList statements = QString(file_init.readAll()).split(APP_DB_COMMENT_SPLIT, QString::SkipEmptyParts);
database.transaction();
foreach(const QString &statement, statements) {
@ -441,8 +437,7 @@ QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_
else {
query_db.next();
qDebug("MySQL database connection '%s' seems to be established.",
qPrintable(connection_name));
qDebug("MySQL database connection '%s' seems to be established.", qPrintable(connection_name));
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;");
}
QSqlDatabase DatabaseFactory::sqliteConnection(const QString &connection_name,
DatabaseFactory::DesiredType desired_type) {
QSqlDatabase DatabaseFactory::sqliteConnection(const QString &connection_name, DatabaseFactory::DesiredType desired_type) {
if (desired_type == DatabaseFactory::StrictlyInMemory ||
(desired_type == DatabaseFactory::FromSettings && m_activeDatabaseDriver == SQLITE_MEMORY)) {
// We request in-memory database (either user explicitly
@ -498,8 +492,7 @@ QSqlDatabase DatabaseFactory::sqliteConnection(const QString &connection_name,
QSqlDatabase database;
if (QSqlDatabase::contains(connection_name)) {
qDebug("SQLite connection '%s' is already active.",
qPrintable(connection_name));
qDebug("SQLite connection '%s' is already active.", qPrintable(connection_name));
// This database connection was added previously, no need to
// setup its properties.

View File

@ -74,6 +74,14 @@ class DatabaseFactory : public QObject {
// Performs cleanup of the database.
bool vacuumDatabase();
// Returns identification of currently active database driver.
UsedDriver activeDatabaseDriver() const;
//
// SQLITE stuff.
//
QString sqliteDatabaseFilePath() const;
//
// MySQL stuff.
//
@ -85,8 +93,6 @@ class DatabaseFactory : public QObject {
QString mysqlInterpretErrorCode(MySQLError error_code);
UsedDriver activeDatabaseDriver() const;
private:
//
// GENERAL stuff.

View File

@ -25,6 +25,16 @@
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,
const QStringList& exception_file_list,
const QStringList& exception_folder_list) {
@ -59,7 +69,7 @@ bool IOFactory::removeFolder(const QString& directory_name,
return result;
}
bool IOFactory::copyFolder(QString source, QString destination) {
bool IOFactory::copyFolder(const QString &source, const QString &destination) {
QDir dir_source(source);
if (!dir_source.exists()) {

View File

@ -26,9 +26,11 @@ class IOFactory {
IOFactory();
public:
static bool copyFile(const QString &source, const QString &destination);
// Copy whole directory recursively.
// 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.
static bool removeFolder(const QString &directory_name,