diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a0de7e6e..3debc185b 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,8 +71,8 @@ project(rssguard) set(APP_NAME "RSS Guard") set(APP_LOW_NAME "rssguard") -set(APP_VERSION "2.0.0.4") -set(FILE_VERSION "2,0,0,4") +set(APP_VERSION "2.1") +set(FILE_VERSION "2,1,0,0") set(APP_AUTHOR "Martin Rotter") set(APP_URL "http://bitbucket.org/skunkos/rssguard") set(APP_URL_ISSUES "http://bitbucket.org/skunkos/rssguard/issues") diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 547e7e511..759e6d2dc 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -1,4 +1,15 @@ +

2.1

+ +Fixed: + + +Added: + + +

2.0.0.4

Fixed: diff --git a/src/core/feedsmodelcategory.cpp b/src/core/feedsmodelcategory.cpp index 73a23efd6..f57d34805 100755 --- a/src/core/feedsmodelcategory.cpp +++ b/src/core/feedsmodelcategory.cpp @@ -86,9 +86,9 @@ QVariant FeedsModelCategory::data(int column, int role) const { return m_title; } else if (column == FDS_MODEL_COUNTS_INDEX) { - return qApp->settings()->value(APP_CFG_FEEDS, COUNT_FORMAT, DEFAULT_VALUE(COUNT_FORMAT)).toString() - .replace("%unread", QString::number(countOfUnreadMessages())) - .replace("%all", QString::number(countOfAllMessages())); + return qApp->settings()->value(APP_CFG_FEEDS, SETTING(Feeds::CountFormat)).toString() + .replace(PLACEHOLDER_UNREAD_COUNTS, QString::number(countOfUnreadMessages())) + .replace(PLACEHOLDER_ALL_COUNTS, QString::number(countOfAllMessages())); } else { return QVariant(); diff --git a/src/core/feedsmodelfeed.cpp b/src/core/feedsmodelfeed.cpp index 001a2b380..c8d748519 100755 --- a/src/core/feedsmodelfeed.cpp +++ b/src/core/feedsmodelfeed.cpp @@ -175,8 +175,7 @@ QPair FeedsModelFeed::guessFeed(co QByteArray feed_contents; NetworkResult network_result = NetworkFactory::downloadFeedFile(url, qApp->settings()->value(APP_CFG_FEEDS, - UPDATE_TIMEOUT, - DEFAULT_VALUE(UPDATE_TIMEOUT)).toInt(), + SETTING(Feeds::UpdateTimeout)).toInt(), feed_contents, !username.isEmpty(), username, @@ -288,9 +287,9 @@ QVariant FeedsModelFeed::data(int column, int role) const { return m_title; } else if (column == FDS_MODEL_COUNTS_INDEX) { - return qApp->settings()->value(APP_CFG_FEEDS, COUNT_FORMAT, DEFAULT_VALUE(COUNT_FORMAT)).toString() - .replace("%unread", QString::number(countOfUnreadMessages())) - .replace("%all", QString::number(countOfAllMessages())); + return qApp->settings()->value(APP_CFG_FEEDS, SETTING(Feeds::CountFormat)).toString() + .replace(PLACEHOLDER_UNREAD_COUNTS, QString::number(countOfUnreadMessages())) + .replace(PLACEHOLDER_ALL_COUNTS, QString::number(countOfAllMessages())); } else { return QVariant(); @@ -390,7 +389,7 @@ QVariant FeedsModelFeed::data(int column, int role) const { void FeedsModelFeed::update() { QByteArray feed_contents; - int download_timeout = qApp->settings()->value(APP_CFG_FEEDS, UPDATE_TIMEOUT, DEFAULT_VALUE(UPDATE_TIMEOUT)).toInt(); + int download_timeout = qApp->settings()->value(APP_CFG_FEEDS, SETTING(Feeds::UpdateTimeout)).toInt(); m_networkError = NetworkFactory::downloadFeedFile(url(), download_timeout, feed_contents, passwordProtected(), username(), password()).first; if (m_networkError != QNetworkReply::NoError) { diff --git a/src/core/feedsmodelrecyclebin.cpp b/src/core/feedsmodelrecyclebin.cpp index 5fabc9d7f..dd48a9b88 100644 --- a/src/core/feedsmodelrecyclebin.cpp +++ b/src/core/feedsmodelrecyclebin.cpp @@ -62,9 +62,9 @@ QVariant FeedsModelRecycleBin::data(int column, int role) const { return m_title; } else if (column == FDS_MODEL_COUNTS_INDEX) { - return qApp->settings()->value(APP_CFG_FEEDS, COUNT_FORMAT, DEFAULT_VALUE(COUNT_FORMAT)).toString() - .replace("%unread", QString::number(countOfUnreadMessages())) - .replace("%all", QString::number(countOfAllMessages())); + return qApp->settings()->value(APP_CFG_FEEDS, SETTING(Feeds::CountFormat)).toString() + .replace(PLACEHOLDER_UNREAD_COUNTS, QString::number(countOfUnreadMessages())) + .replace(PLACEHOLDER_ALL_COUNTS, QString::number(countOfAllMessages())); } else { return QVariant(); diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 52898f9a1..6670c9610 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -108,8 +108,8 @@ int MessagesModel::messageId(int row_index) const { } void MessagesModel::updateDateFormat() { - if (qApp->settings()->value(APP_CFG_MESSAGES, "use_custom_date").toBool()) { - m_customDateFormat = qApp->settings()->value(APP_CFG_MESSAGES, "custom_date_format").toString(); + if (qApp->settings()->value(APP_CFG_MESSAGES, SETTING(Messages::UseCustomDate)).toBool()) { + m_customDateFormat = qApp->settings()->value(APP_CFG_MESSAGES, SETTING(Messages::CustomDateFormat)).toString(); } else { m_customDateFormat = QString(); diff --git a/src/definitions/definitions.h.in b/src/definitions/definitions.h.in index 10912ade4..216191adf 100755 --- a/src/definitions/definitions.h.in +++ b/src/definitions/definitions.h.in @@ -76,6 +76,9 @@ #define ACCEPT_HEADER_FOR_FEED_DOWNLOADER "application/atom+xml,application/xml;q=0.9,text/xml;q=0.8,*/*;q=0.7" #define MIME_TYPE_ITEM_POINTER "rssguard/itempointer" +#define PLACEHOLDER_UNREAD_COUNTS "%unread" +#define PLACEHOLDER_ALL_COUNTS "%all" + #define BACKUP_NAME_SETTINGS "config" #define BACKUP_SUFFIX_SETTINGS ".ini.backup" #define BACKUP_NAME_DATABASE "database" diff --git a/src/dynamic-shortcuts/dynamicshortcuts.cpp b/src/dynamic-shortcuts/dynamicshortcuts.cpp index 80f1acad2..c36c5e74b 100755 --- a/src/dynamic-shortcuts/dynamicshortcuts.cpp +++ b/src/dynamic-shortcuts/dynamicshortcuts.cpp @@ -44,7 +44,6 @@ void DynamicShortcuts::load(const QList actions) { QString shortcut_for_action = settings->value(APP_CFG_CUTS, action->objectName(), action->shortcut().toString(QKeySequence::PortableText)).toString(); - action->setShortcut(QKeySequence::fromString(shortcut_for_action, - QKeySequence::PortableText)); + action->setShortcut(QKeySequence::fromString(shortcut_for_action, QKeySequence::PortableText)); } } diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index e703c1dca..3d46d588d 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -105,8 +105,8 @@ void FeedMessageViewer::loadSize() { m_feedsView->loadExpandedStates(); // Restore offsets of splitters. - m_feedSplitter->restoreState(QByteArray::fromBase64(settings->value(APP_CFG_GUI, "splitter_feeds").toString().toLocal8Bit())); - m_messageSplitter->restoreState(QByteArray::fromBase64(settings->value(APP_CFG_GUI, "splitter_messages").toString().toLocal8Bit())); + m_feedSplitter->restoreState(QByteArray::fromBase64(settings->value(APP_CFG_GUI, SETTING(GUI::SplitterFeeds)).toString().toLocal8Bit())); + m_messageSplitter->restoreState(QByteArray::fromBase64(settings->value(APP_CFG_GUI, SETTING(GUI::SplitterMessages)).toString().toLocal8Bit())); // Splitters are restored, now, restore widths of columns. m_messagesView->setColumnWidth(MSG_DB_AUTHOR_INDEX, settings->value(APP_CFG_GUI, @@ -128,7 +128,7 @@ void FeedMessageViewer::quit() { qDebug("Feed downloader thread aborted. Deleting it from memory."); m_feedDownloader->deleteLater(); - if (qApp->settings()->value(APP_CFG_MESSAGES, "clear_read_on_exit", false).toBool()) { + if (qApp->settings()->value(APP_CFG_MESSAGES, SETTING(Messages::ClearReadOnExit)).toBool()) { m_feedsView->clearAllReadMessages(); } } @@ -397,8 +397,7 @@ void FeedMessageViewer::vacuumDatabase() { void FeedMessageViewer::refreshVisualProperties() { Qt::ToolButtonStyle button_style = static_cast(qApp->settings()->value(APP_CFG_GUI, - "toolbar_style", - Qt::ToolButtonIconOnly).toInt()); + SETTING(GUI::ToolbarStyle)).toInt()); m_toolBarFeeds->setToolButtonStyle(button_style); m_toolBarMessages->setToolButtonStyle(button_style); diff --git a/src/gui/formsettings.cpp b/src/gui/formsettings.cpp index cb5c6d8c0..5bd0ccc9e 100755 --- a/src/gui/formsettings.cpp +++ b/src/gui/formsettings.cpp @@ -182,7 +182,7 @@ void FormSettings::loadFeedsMessages() { m_ui->m_checkRemoveReadMessagesOnExit->setChecked(settings->value(APP_CFG_MESSAGES, "clear_read_on_exit", false).toBool()); m_ui->m_checkAutoUpdate->setChecked(settings->value(APP_CFG_FEEDS, "auto_update_enabled", false).toBool()); m_ui->m_spinAutoUpdateInterval->setValue(settings->value(APP_CFG_FEEDS, "auto_update_interval", DEFAULT_AUTO_UPDATE_INTERVAL).toInt()); - m_ui->m_spinFeedUpdateTimeout->setValue(settings->value(APP_CFG_FEEDS, UPDATE_TIMEOUT, DEFAULT_VALUE(UPDATE_TIMEOUT)).toInt()); + m_ui->m_spinFeedUpdateTimeout->setValue(settings->value(APP_CFG_FEEDS, SETTING(Feeds::UpdateTimeout)).toInt()); m_ui->m_checkUpdateAllFeedsOnStartup->setChecked(settings->value(APP_CFG_FEEDS, "feeds_update_on_startup", false).toBool()); m_ui->m_cmbCountsFeedList->addItems(QStringList() << "(%unread)" << "[%unread]" << "%unread/%all" << "%unread-%all" << "[%unread|%all]"); m_ui->m_cmbCountsFeedList->setEditText(settings->value(APP_CFG_FEEDS, "count_format", "(%unread)").toString()); @@ -216,7 +216,7 @@ void FormSettings::saveFeedsMessages() { settings->setValue(APP_CFG_MESSAGES, "clear_read_on_exit", m_ui->m_checkRemoveReadMessagesOnExit->isChecked()); settings->setValue(APP_CFG_FEEDS, "auto_update_enabled", m_ui->m_checkAutoUpdate->isChecked()); settings->setValue(APP_CFG_FEEDS, "auto_update_interval", m_ui->m_spinAutoUpdateInterval->value()); - settings->setValue(APP_CFG_FEEDS, UPDATE_TIMEOUT, m_ui->m_spinFeedUpdateTimeout->value()); + settings->setValue(APP_CFG_FEEDS, Feeds::UpdateTimeout, m_ui->m_spinFeedUpdateTimeout->value()); settings->setValue(APP_CFG_FEEDS, "feeds_update_on_startup", m_ui->m_checkUpdateAllFeedsOnStartup->isChecked()); settings->setValue(APP_CFG_FEEDS, "count_format", m_ui->m_cmbCountsFeedList->currentText()); settings->setValue(APP_CFG_MESSAGES, "use_custom_date", m_ui->m_checkMessagesDateTimeFormat->isChecked()); diff --git a/src/gui/formupdate.cpp b/src/gui/formupdate.cpp index f5ccc6ac7..32e8c483a 100755 --- a/src/gui/formupdate.cpp +++ b/src/gui/formupdate.cpp @@ -93,7 +93,7 @@ void FormUpdate::checkForUpdates() { bool is_self_update_for_this_system = isUpdateForThisSystem() && isSelfUpdateSupported(); - if (update.first.m_availableVersion > APP_VERSION) { + if (SystemFactory::isUpdateNewer(update.first.m_availableVersion)) { m_ui->m_lblStatus->setStatus(WidgetWithStatus::Ok, tr("New release available."), tr("This is new version which can be\ndownloaded and installed.")); diff --git a/src/miscellaneous/databasefactory.cpp b/src/miscellaneous/databasefactory.cpp index 59aef9068..8f5a311d3 100755 --- a/src/miscellaneous/databasefactory.cpp +++ b/src/miscellaneous/databasefactory.cpp @@ -104,8 +104,7 @@ void DatabaseFactory::finishRestoration() { if (QFile::exists(backup_database_file)) { qWarning("Backup database file '%s' was detected. Restoring it.", qPrintable(QDir::toNativeSeparators(backup_database_file))); - if (IOFactory::copyFile(backup_database_file, - m_sqliteDatabaseFilePath + QDir::separator() + APP_DB_SQLITE_FILE)) { + if (IOFactory::copyFile(backup_database_file, m_sqliteDatabaseFilePath + QDir::separator() + APP_DB_SQLITE_FILE)) { QFile::remove(backup_database_file); qDebug("Database file was restored successully."); } @@ -132,8 +131,7 @@ QSqlDatabase DatabaseFactory::sqliteInitializeInMemoryDatabase() { database.setDatabaseName(":memory:"); if (!database.open()) { - qFatal("In-memory SQLite database was NOT opened. Delivered error message: '%s'", - qPrintable(database.lastError().text())); + qFatal("In-memory SQLite database was NOT opened. Delivered error message: '%s'", qPrintable(database.lastError().text())); } else { QSqlQuery query_db(database); @@ -191,9 +189,7 @@ QSqlDatabase DatabaseFactory::sqliteInitializeInMemoryDatabase() { copy_contents.exec(QString("ATTACH DATABASE '%1' AS 'storage';").arg(file_database.databaseName())); // Copy all stuff. - QStringList tables; tables << "Information" << "Categories" << - "Feeds" << "FeedsData" << - "Messages"; + QStringList tables; tables << "Information" << "Categories" << "Feeds" << "FeedsData" << "Messages"; foreach (const QString &table, tables) { copy_contents.exec(QString("INSERT INTO main.%1 SELECT * FROM storage.%1;").arg(table)); diff --git a/src/miscellaneous/databasefactory.h b/src/miscellaneous/databasefactory.h index 1c8f796b6..128060598 100755 --- a/src/miscellaneous/databasefactory.h +++ b/src/miscellaneous/databasefactory.h @@ -80,6 +80,7 @@ class DatabaseFactory : public QObject { // Copies selected backup database (file) to active database path. bool initiateRestoration(const QString &database_backup_file_path); + // Finishes restoration from backup file. void finishRestoration(); // @@ -96,6 +97,7 @@ class DatabaseFactory : public QObject { // Otherwise returns MySQL-specific error code. MySQLError mysqlTestConnection(const QString &hostname, int port, const QString &username, const QString &password); + // Interprets MySQL error code. QString mysqlInterpretErrorCode(MySQLError error_code); private: @@ -107,6 +109,7 @@ class DatabaseFactory : public QObject { // application session. void determineDriver(); + // Updates DB schema if necessary. bool updateDatabaseSchema(QSqlDatabase database, const QString &source_db_schema_version); // Holds the type of currently activated database backend. diff --git a/src/miscellaneous/settings.h b/src/miscellaneous/settings.h index 42eff0c23..3a77aa398 100755 --- a/src/miscellaneous/settings.h +++ b/src/miscellaneous/settings.h @@ -24,14 +24,47 @@ #include -#define DEFAULT_VALUE(x) x##_DEF +#define KEY static const char* +#define VALUE(x) static const x +#define SETTING(x) x, x##Def // Feeds. -#define UPDATE_TIMEOUT "feed_update_timeout" -#define UPDATE_TIMEOUT_DEF DOWNLOAD_TIMEOUT +namespace Feeds { + KEY UpdateTimeout = "feed_update_timeout"; + VALUE(int) UpdateTimeoutDef = DOWNLOAD_TIMEOUT; -#define COUNT_FORMAT "count_format" -#define COUNT_FORMAT_DEF "(%unread)" + KEY CountFormat = "count_format"; + VALUE(char*) CountFormatDef = "(%unread)"; +} + +// Messages. +namespace Messages { + KEY UseCustomDate = "use_custom_date"; + VALUE(bool) UseCustomDateDef = false; + + KEY CustomDateFormat = "custom_date_format"; + VALUE(char*) CustomDateFormatDef = ""; + + KEY ClearReadOnExit = "clear_read_on_exit"; + VALUE(bool) ClearReadOnExitDef = false; +} + +// GUI. +namespace GUI { + KEY SplitterFeeds = "splitter_feeds"; + VALUE(char*) SplitterFeedsDef = ""; + + KEY SplitterMessages = "splitter_messages"; + VALUE(char*) SplitterMessagesDef = ""; + + KEY ToolbarStyle = "toolbar_style"; + VALUE(Qt::ToolButtonStyle) ToolbarStyleDef = Qt::ToolButtonIconOnly; +} + +// General. +namespace General { + +} class Settings : public QSettings { diff --git a/src/miscellaneous/systemfactory.cpp b/src/miscellaneous/systemfactory.cpp index 837e8e7d1..ab2e4c1a0 100755 --- a/src/miscellaneous/systemfactory.cpp +++ b/src/miscellaneous/systemfactory.cpp @@ -183,6 +183,31 @@ QPair SystemFactory::checkForUpdates() return result; } +bool SystemFactory::isUpdateNewer(const QString &update_version) { + QStringList current_version_tkn = QString(APP_VERSION).split('.'); + QStringList new_version_tkn = update_version.split('.'); + + while (!current_version_tkn.isEmpty() && !new_version_tkn.isEmpty()) { + int current_number = current_version_tkn.takeFirst().toInt(); + int new_number = new_version_tkn.takeFirst().toInt(); + + if (new_number > current_number) { + // New version is indeed higher thatn current version. + return true; + } + } + + // Versions are either the same or they have unequal sizes. + if (current_version_tkn.isEmpty() && new_version_tkn.isEmpty()) { + // Versions are the same. + return false; + } + else { + // Version are not the same length. New version is really higher if it is longer + its last digit is not 0. + return !new_version_tkn.isEmpty() && new_version_tkn.takeFirst().toInt() != 0; + } +} + UpdateInfo SystemFactory::parseUpdatesFile(const QByteArray &updates_file) { UpdateInfo update; QDomDocument document; document.setContent(updates_file, false); @@ -235,7 +260,7 @@ void SystemFactory::handleBackgroundUpdatesCheck() { QFutureWatcher *future_watcher = static_cast*>(sender()); UpdateCheck updates = future_watcher->result(); - if (updates.second == QNetworkReply::NoError && updates.first.m_availableVersion > APP_VERSION) { + if (updates.second == QNetworkReply::NoError && isUpdateNewer(updates.first.m_availableVersion)) { if (SystemTrayIcon::isSystemTrayActivated()) { qApp->trayIcon()->showMessage(tr("New version available"), tr("Click the bubble for more information."), diff --git a/src/miscellaneous/systemfactory.h b/src/miscellaneous/systemfactory.h index 1083b251d..5405541f8 100644 --- a/src/miscellaneous/systemfactory.h +++ b/src/miscellaneous/systemfactory.h @@ -92,6 +92,8 @@ class SystemFactory : public QObject { // Tries to download list with new updates. QPair checkForUpdates(); + static bool isUpdateNewer(const QString &update_version); + public slots: // Performs asynchronous check for updates, result is emitted via updateCheckedAsynchronously(...) signal. void checkForUpdatesAsynchronously();