From f911773ee7991e7739707f11e54ef0cdf2121a06 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 30 Oct 2015 06:54:59 +0100 Subject: [PATCH 001/203] Begin to work on #3, rename some classes. --- CMakeLists.txt | 37 ++++--- src/core/feeddownloader.cpp | 4 +- src/core/feeddownloader.h | 6 +- src/core/feedsmodel.cpp | 100 +++++++++--------- src/core/feedsmodel.h | 52 ++++----- src/core/feedsproxymodel.cpp | 4 +- src/core/feedsselection.cpp | 4 +- src/core/feedsselection.h | 2 +- src/core/rootitem.cpp | 12 +-- src/core/rootitem.h | 8 +- src/gui/dialogs/formmain.cpp | 6 +- src/gui/dialogs/formmain.ui | 24 +++++ src/gui/feedmessageviewer.cpp | 16 +-- src/gui/feedmessageviewer.h | 8 +- src/gui/feedsview.cpp | 50 ++++----- src/gui/feedsview.h | 20 ++-- .../gui/formstandardcategorydetails.cpp} | 40 ++++--- .../gui/formstandardcategorydetails.h} | 24 ++--- .../gui/formstandardcategorydetails.ui} | 6 +- .../standard/gui/formstandardfeeddetails.cpp} | 84 +++++++-------- .../standard/gui/formstandardfeeddetails.h} | 26 ++--- .../standard/gui/formstandardfeeddetails.ui} | 6 +- .../gui/formstandardimportexport.cpp} | 25 ++--- .../standard/gui/formstandardimportexport.h} | 14 +-- .../standard/gui/formstandardimportexport.ui} | 6 +- .../standard/standardcategory.cpp} | 22 ++-- .../standard/standardcategory.h} | 12 +-- .../standard/standardfeed.cpp} | 60 +++++------ .../standard/standardfeed.h} | 16 +-- .../standardfeedsimportexportmodel.cpp} | 28 ++--- .../standardfeedsimportexportmodel.h} | 0 31 files changed, 377 insertions(+), 345 deletions(-) mode change 100644 => 100755 src/core/feeddownloader.cpp mode change 100644 => 100755 src/core/feeddownloader.h mode change 100644 => 100755 src/core/feedsmodel.h mode change 100644 => 100755 src/core/feedsselection.h mode change 100644 => 100755 src/core/rootitem.cpp mode change 100644 => 100755 src/core/rootitem.h mode change 100644 => 100755 src/gui/feedmessageviewer.h rename src/{gui/dialogs/formcategorydetails.cpp => services/standard/gui/formstandardcategorydetails.cpp} (87%) rename src/{gui/dialogs/formcategorydetails.h => services/standard/gui/formstandardcategorydetails.h} (74%) mode change 100644 => 100755 rename src/{gui/dialogs/formcategorydetails.ui => services/standard/gui/formstandardcategorydetails.ui} (96%) mode change 100644 => 100755 rename src/{gui/dialogs/formfeeddetails.cpp => services/standard/gui/formstandardfeeddetails.cpp} (83%) rename src/{gui/dialogs/formfeeddetails.h => services/standard/gui/formstandardfeeddetails.h} (78%) mode change 100644 => 100755 rename src/{gui/dialogs/formfeeddetails.ui => services/standard/gui/formstandardfeeddetails.ui} (95%) mode change 100644 => 100755 rename src/{gui/dialogs/formimportexport.cpp => services/standard/gui/formstandardimportexport.cpp} (90%) rename src/{gui/dialogs/formimportexport.h => services/standard/gui/formstandardimportexport.h} (80%) mode change 100644 => 100755 rename src/{gui/dialogs/formimportexport.ui => services/standard/gui/formstandardimportexport.ui} (96%) mode change 100644 => 100755 rename src/{core/category.cpp => services/standard/standardcategory.cpp} (89%) mode change 100644 => 100755 rename src/{core/category.h => services/standard/standardcategory.h} (80%) mode change 100644 => 100755 rename src/{core/feed.cpp => services/standard/standardfeed.cpp} (91%) mode change 100644 => 100755 rename src/{core/feed.h => services/standard/standardfeed.h} (89%) mode change 100644 => 100755 rename src/{core/feedsimportexportmodel.cpp => services/standard/standardfeedsimportexportmodel.cpp} (95%) mode change 100644 => 100755 rename src/{core/feedsimportexportmodel.h => services/standard/standardfeedsimportexportmodel.h} (100%) mode change 100644 => 100755 diff --git a/CMakeLists.txt b/CMakeLists.txt index b27fe9a07..d5e9a949e 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -347,10 +347,7 @@ set(APP_SOURCES src/gui/dialogs/formmain.cpp src/gui/dialogs/formsettings.cpp src/gui/dialogs/formabout.cpp - src/gui/dialogs/formcategorydetails.cpp - src/gui/dialogs/formfeeddetails.cpp src/gui/dialogs/formupdate.cpp - src/gui/dialogs/formimportexport.cpp src/gui/dialogs/formdatabasecleanup.cpp src/gui/dialogs/formbackupdatabasesettings.cpp src/gui/dialogs/formrestoredatabasesettings.cpp @@ -412,15 +409,20 @@ set(APP_SOURCES src/core/messagesproxymodel.cpp src/core/feedsmodel.cpp src/core/feedsproxymodel.cpp - src/core/category.cpp src/core/rootitem.cpp - src/core/feed.cpp src/core/parsingfactory.cpp src/core/feeddownloader.cpp - src/core/feedsimportexportmodel.cpp src/core/recyclebin.cpp src/core/feedsselection.cpp + # STANDARD feed service sources. + src/services/standard/standardfeed.cpp + src/services/standard/standardfeedsimportexportmodel.cpp + src/services/standard/standardcategory.cpp + src/services/standard/gui/formstandardcategorydetails.cpp + src/services/standard/gui/formstandardfeeddetails.cpp + src/services/standard/gui/formstandardimportexport.cpp + # NETWORK-WEB sources. src/network-web/basenetworkaccessmanager.cpp src/network-web/webpage.cpp @@ -462,9 +464,6 @@ set(APP_HEADERS src/gui/dialogs/formmain.h src/gui/dialogs/formsettings.h src/gui/dialogs/formabout.h - src/gui/dialogs/formcategorydetails.h - src/gui/dialogs/formfeeddetails.h - src/gui/dialogs/formimportexport.h src/gui/dialogs/formbackupdatabasesettings.h src/gui/dialogs/formrestoredatabasesettings.h src/gui/dialogs/formdatabasecleanup.h @@ -518,7 +517,12 @@ set(APP_HEADERS src/core/feedsmodel.h src/core/feedsproxymodel.h src/core/feeddownloader.h - src/core/feedsimportexportmodel.h + + # STANDARD service headers. + src/services/standard/standardfeedsimportexportmodel.h + src/services/standard/gui/formstandardcategorydetails.h + src/services/standard/gui/formstandardfeeddetails.h + src/services/standard/gui/formstandardimportexport.h # NETWORK-WEB headers. src/network-web/webpage.h @@ -548,13 +552,18 @@ set(APP_FORMS src/gui/dialogs/formmain.ui src/gui/dialogs/formsettings.ui src/gui/dialogs/formabout.ui - src/gui/dialogs/formcategorydetails.ui - src/gui/dialogs/formfeeddetails.ui - src/gui/toolbareditor.ui - src/gui/dialogs/formimportexport.ui src/gui/dialogs/formbackupdatabasesettings.ui src/gui/dialogs/formrestoredatabasesettings.ui src/gui/dialogs/formdatabasecleanup.ui + + src/gui/toolbareditor.ui + + # STANDARD service forms. + src/services/standard/gui/formstandardcategorydetails.ui + src/services/standard/gui/formstandardfeeddetails.ui + src/services/standard/gui/formstandardimportexport.ui + + # NETWORK forms. src/network-web/downloadmanager.ui src/network-web/downloaditem.ui diff --git a/src/core/feeddownloader.cpp b/src/core/feeddownloader.cpp old mode 100644 new mode 100755 index 8482e11a6..8afef756c --- a/src/core/feeddownloader.cpp +++ b/src/core/feeddownloader.cpp @@ -17,7 +17,7 @@ #include "core/feeddownloader.h" -#include "core/feed.h" +#include "services/standard/standardfeed.h" #include "definitions/definitions.h" #include @@ -32,7 +32,7 @@ FeedDownloader::~FeedDownloader() { qDebug("Destroying FeedDownloader instance."); } -void FeedDownloader::updateFeeds(const QList &feeds) { +void FeedDownloader::updateFeeds(const QList &feeds) { qDebug().nospace() << "Performing feed updates in thread: \'" << QThread::currentThreadId() << "\'."; // Job starts now. diff --git a/src/core/feeddownloader.h b/src/core/feeddownloader.h old mode 100644 new mode 100755 index 88f8992b7..eab2aac2e --- a/src/core/feeddownloader.h +++ b/src/core/feeddownloader.h @@ -23,7 +23,7 @@ #include -class Feed; +class StandardFeed; // Represents results of batch feed updates. struct FeedDownloadResults { @@ -55,7 +55,7 @@ class FeedDownloader : public QObject { // New messages are downloaded for each feed and they // are stored persistently in the database. // Appropriate signals are emitted. - void updateFeeds(const QList &feeds); + void updateFeeds(const QList &feeds); signals: // Emitted if feed updates started. @@ -69,7 +69,7 @@ class FeedDownloader : public QObject { // "Current" number indicates count of processed feeds // and "total" number indicates total number of feeds // which were in the initial queue. - void progress(Feed *feed, int current, int total); + void progress(StandardFeed *feed, int current, int total); }; #endif // FEEDDOWNLOADER_H diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index f78b4dd23..7dad793e8 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -18,10 +18,10 @@ #include "core/feedsmodel.h" #include "definitions/definitions.h" -#include "core/category.h" -#include "core/feed.h" +#include "services/standard/standardcategory.h" +#include "services/standard/standardfeed.h" +#include "services/standard/standardfeedsimportexportmodel.h" #include "core/recyclebin.h" -#include "core/feedsimportexportmodel.h" #include "miscellaneous/textfactory.h" #include "miscellaneous/databasefactory.h" #include "miscellaneous/iconfactory.h" @@ -100,7 +100,7 @@ void FeedsModel::executeNextAutoUpdate() { // Pass needed interval data and lets the model decide which feeds // should be updated in this pass. - QList feeds_for_update = feedsForScheduledUpdate(m_globalAutoUpdateEnabled && m_globalAutoUpdateRemainingInterval == 0); + QList feeds_for_update = feedsForScheduledUpdate(m_globalAutoUpdateEnabled && m_globalAutoUpdateRemainingInterval == 0); qApp->feedUpdateLock()->unlock(); @@ -197,8 +197,8 @@ bool FeedsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int if (dragged_item->kind() == RootItem::Feeed) { qDebug("Drag-drop action for feed '%s' detected, editing the feed.", qPrintable(dragged_item->title())); - Feed *actual_feed = dragged_item->toFeed(); - Feed *feed_new = new Feed(*actual_feed); + StandardFeed *actual_feed = dragged_item->toFeed(); + StandardFeed *feed_new = new StandardFeed(*actual_feed); feed_new->setParent(target_item); editFeed(actual_feed, feed_new); @@ -208,8 +208,8 @@ bool FeedsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int else if (dragged_item->kind() == RootItem::Cattegory) { qDebug("Drag-drop action for category '%s' detected, editing the feed.", qPrintable(dragged_item->title())); - Category *actual_category = dragged_item->toCategory(); - Category *category_new = new Category(*actual_category); + StandardCategory *actual_category = dragged_item->toCategory(); + StandardCategory *category_new = new StandardCategory(*actual_category); category_new->clearChildren(); category_new->setParent(target_item); @@ -341,7 +341,7 @@ bool FeedsModel::removeItem(const QModelIndex &index) { return false; } -bool FeedsModel::addCategory(Category *category, RootItem *parent) { +bool FeedsModel::addCategory(StandardCategory *category, RootItem *parent) { // Get index of parent item (parent standard category). QModelIndex parent_index = indexForItem(parent); bool result = category->addItself(parent); @@ -361,7 +361,7 @@ bool FeedsModel::addCategory(Category *category, RootItem *parent) { return result; } -bool FeedsModel::editCategory(Category *original_category, Category *new_category_data) { +bool FeedsModel::editCategory(StandardCategory *original_category, StandardCategory *new_category_data) { RootItem *original_parent = original_category->parent(); RootItem *new_parent = new_category_data->parent(); bool result = original_category->editItself(new_category_data); @@ -388,7 +388,7 @@ bool FeedsModel::editCategory(Category *original_category, Category *new_categor return result; } -bool FeedsModel::addFeed(Feed *feed, RootItem *parent) { +bool FeedsModel::addFeed(StandardFeed *feed, RootItem *parent) { // Get index of parent item (parent standard category or root item). QModelIndex parent_index = indexForItem(parent); bool result = feed->addItself(parent); @@ -406,7 +406,7 @@ bool FeedsModel::addFeed(Feed *feed, RootItem *parent) { return result; } -bool FeedsModel::editFeed(Feed *original_feed, Feed *new_feed_data) { +bool FeedsModel::editFeed(StandardFeed *original_feed, StandardFeed *new_feed_data) { RootItem *original_parent = original_feed->parent(); RootItem *new_parent = new_feed_data->parent(); bool result = original_feed->editItself(new_feed_data); @@ -432,23 +432,23 @@ bool FeedsModel::editFeed(Feed *original_feed, Feed *new_feed_data) { return result; } -QList FeedsModel::feedsForScheduledUpdate(bool auto_update_now) { - QList feeds_for_update; +QList FeedsModel::feedsForScheduledUpdate(bool auto_update_now) { + QList feeds_for_update; - foreach (Feed *feed, allFeeds()) { + foreach (StandardFeed *feed, allFeeds()) { switch (feed->autoUpdateType()) { - case Feed::DontAutoUpdate: + case StandardFeed::DontAutoUpdate: // Do not auto-update this feed ever. continue; - case Feed::DefaultAutoUpdate: + case StandardFeed::DefaultAutoUpdate: if (auto_update_now) { feeds_for_update.append(feed); } break; - case Feed::SpecificAutoUpdate: + case StandardFeed::SpecificAutoUpdate: default: int remaining_interval = feed->autoUpdateRemainingInterval(); @@ -471,7 +471,7 @@ QList FeedsModel::feedsForScheduledUpdate(bool auto_update_now) { return feeds_for_update; } -QList FeedsModel::messagesForFeeds(const QList &feeds) { +QList FeedsModel::messagesForFeeds(const QList &feeds) { QList messages; QSqlDatabase database = qApp->database()->connection(objectName(), @@ -482,7 +482,7 @@ QList FeedsModel::messagesForFeeds(const QList &feeds) { "FROM Messages " "WHERE is_deleted = 0 AND feed = :feed;"); - foreach (Feed *feed, feeds) { + foreach (StandardFeed *feed, feeds) { query_read_msg.bindValue(QSL(":feed"), feed->id()); if (query_read_msg.exec()) { @@ -519,7 +519,7 @@ RootItem *FeedsModel::itemForIndex(const QModelIndex &index) const { } } -Category *FeedsModel::categoryForIndex(const QModelIndex &index) const { +StandardCategory *FeedsModel::categoryForIndex(const QModelIndex &index) const { RootItem *item = itemForIndex(index); if (item->kind() == RootItem::Cattegory) { @@ -567,8 +567,8 @@ QModelIndex FeedsModel::indexForItem(RootItem *item) const { } bool FeedsModel::hasAnyFeedNewMessages() { - foreach (const Feed *feed, allFeeds()) { - if (feed->status() == Feed::NewMessages) { + foreach (const StandardFeed *feed, allFeeds()) { + if (feed->status() == StandardFeed::NewMessages) { return true; } } @@ -603,8 +603,8 @@ bool FeedsModel::mergeModel(FeedsImportExportModel *model, QString &output_messa } if (source_item->kind() == RootItem::Cattegory) { - Category *source_category = source_item->toCategory(); - Category *new_category = new Category(*source_category); + StandardCategory *source_category = source_item->toCategory(); + StandardCategory *new_category = new StandardCategory(*source_category); // Add category to model. new_category->clearChildren(); @@ -630,8 +630,8 @@ bool FeedsModel::mergeModel(FeedsImportExportModel *model, QString &output_messa } } else if (source_item->kind() == RootItem::Feeed) { - Feed *source_feed = source_item->toFeed(); - Feed *new_feed = new Feed(*source_feed); + StandardFeed *source_feed = source_item->toFeed(); + StandardFeed *new_feed = new StandardFeed(*source_feed); // Append this feed and end this iteration. if (!addFeed(new_feed, target_parent)) { @@ -664,11 +664,11 @@ void FeedsModel::reloadChangedLayout(QModelIndexList list) { } } -QStringList FeedsModel::textualFeedIds(const QList &feeds) { +QStringList FeedsModel::textualFeedIds(const QList &feeds) { QStringList stringy_ids; stringy_ids.reserve(feeds.size()); - foreach (Feed *feed, feeds) { + foreach (StandardFeed *feed, feeds) { stringy_ids.append(QString::number(feed->id())); } @@ -701,7 +701,7 @@ void FeedsModel::loadFromDatabase() { while (query_categories.next()) { CategoryAssignmentItem pair; pair.first = query_categories.value(CAT_DB_PARENT_ID_INDEX).toInt(); - pair.second = new Category(query_categories.record()); + pair.second = new StandardCategory(query_categories.record()); categories << pair; } @@ -717,16 +717,16 @@ void FeedsModel::loadFromDatabase() { while (query_feeds.next()) { // Process this feed. - Feed::Type type = static_cast(query_feeds.value(FDS_DB_TYPE_INDEX).toInt()); + StandardFeed::Type type = static_cast(query_feeds.value(FDS_DB_TYPE_INDEX).toInt()); switch (type) { - case Feed::Atom10: - case Feed::Rdf: - case Feed::Rss0X: - case Feed::Rss2X: { + case StandardFeed::Atom10: + case StandardFeed::Rdf: + case StandardFeed::Rss0X: + case StandardFeed::Rss2X: { FeedAssignmentItem pair; pair.first = query_feeds.value(FDS_DB_CATEGORY_INDEX).toInt(); - pair.second = new Feed(query_feeds.record()); + pair.second = new StandardFeed(query_feeds.record()); pair.second->setType(type); feeds << pair; @@ -746,12 +746,12 @@ void FeedsModel::loadFromDatabase() { m_rootItem->appendChild(m_recycleBin); } -QList FeedsModel::feedsForIndex(const QModelIndex &index) { +QList FeedsModel::feedsForIndex(const QModelIndex &index) { RootItem *item = itemForIndex(index); return feedsForItem(item); } -Feed *FeedsModel::feedForIndex(const QModelIndex &index) { +StandardFeed *FeedsModel::feedForIndex(const QModelIndex &index) { RootItem *item = itemForIndex(index); if (item->kind() == RootItem::Feeed) { @@ -762,8 +762,8 @@ Feed *FeedsModel::feedForIndex(const QModelIndex &index) { } } -QList FeedsModel::feedsForIndexes(const QModelIndexList &indexes) { - QList feeds; +QList FeedsModel::feedsForIndexes(const QModelIndexList &indexes) { + QList feeds; // Get selected feeds for each index. foreach (const QModelIndex &index, indexes) { @@ -782,7 +782,7 @@ QList FeedsModel::feedsForIndexes(const QModelIndexList &indexes) { return feeds; } -bool FeedsModel::markFeedsRead(const QList &feeds, int read) { +bool FeedsModel::markFeedsRead(const QList &feeds, int read) { QSqlDatabase db_handle = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings); if (!db_handle.transaction()) { @@ -817,7 +817,7 @@ bool FeedsModel::markFeedsRead(const QList &feeds, int read) { } } -bool FeedsModel::markFeedsDeleted(const QList &feeds, int deleted, bool read_only) { +bool FeedsModel::markFeedsDeleted(const QList &feeds, int deleted, bool read_only) { QSqlDatabase db_handle = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings); if (!db_handle.transaction()) { @@ -863,12 +863,12 @@ bool FeedsModel::markFeedsDeleted(const QList &feeds, int deleted, bool r } } -QHash FeedsModel::allCategories() { +QHash FeedsModel::allCategories() { return categoriesForItem(m_rootItem); } -QHash FeedsModel::categoriesForItem(RootItem *root) { - QHash categories; +QHash FeedsModel::categoriesForItem(RootItem *root) { + QHash categories; QList parents; parents.append(root->childItems()); @@ -880,7 +880,7 @@ QHash FeedsModel::categoriesForItem(RootItem *root) { // This item is category, add it to the output list and // scan its children. int category_id = item->id(); - Category *category = item->toCategory(); + StandardCategory *category = item->toCategory(); if (!categories.contains(category_id)) { categories.insert(category_id, category); @@ -893,13 +893,13 @@ QHash FeedsModel::categoriesForItem(RootItem *root) { return categories; } -QList FeedsModel::allFeeds() { +QList FeedsModel::allFeeds() { return feedsForItem(m_rootItem); } -QList FeedsModel::feedsForItem(RootItem *root) { +QList FeedsModel::feedsForItem(RootItem *root) { QList children = root->getRecursiveChildren(); - QList feeds; + QList feeds; foreach (RootItem *child, children) { if (child->kind() == RootItem::Feeed) { @@ -911,7 +911,7 @@ QList FeedsModel::feedsForItem(RootItem *root) { } void FeedsModel::assembleFeeds(FeedAssignment feeds) { - QHash categories = allCategories(); + QHash categories = allCategories(); foreach (const FeedAssignmentItem &feed, feeds) { if (feed.first == NO_PARENT_CATEGORY) { diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h old mode 100644 new mode 100755 index a4eb30c3d..ad029b443 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -26,23 +26,23 @@ #include -class Category; -class Feed; +class StandardCategory; +class StandardFeed; class RecycleBin; class FeedsImportExportModel; class QTimer; -typedef QList > CategoryAssignment; -typedef QPair CategoryAssignmentItem; +typedef QList > CategoryAssignment; +typedef QPair CategoryAssignmentItem; -typedef QList > FeedAssignment; -typedef QPair FeedAssignmentItem; +typedef QList > FeedAssignment; +typedef QPair FeedAssignmentItem; class FeedsModel : public QAbstractItemModel { Q_OBJECT - friend class Feed; - friend class Category; + friend class StandardFeed; + friend class StandardCategory; public: // Constructors and destructors. @@ -79,57 +79,57 @@ class FeedsModel : public QAbstractItemModel { bool removeItem(const QModelIndex &index); // Standard category manipulators. - bool addCategory(Category *category, RootItem *parent); - bool editCategory(Category *original_category, Category *new_category_data); + bool addCategory(StandardCategory *category, RootItem *parent); + bool editCategory(StandardCategory *original_category, StandardCategory *new_category_data); // Standard feed manipulators. - bool addFeed(Feed *feed, RootItem *parent); + bool addFeed(StandardFeed *feed, RootItem *parent); // New feed is just temporary feed, it is not added to the model. // It is used to fetch its data to the original feed // and the original feed is moved if needed. - bool editFeed(Feed *original_feed, Feed *new_feed_data); + bool editFeed(StandardFeed *original_feed, StandardFeed *new_feed_data); // Returns the list of feeds which should be updated // according to auto-update schedule. // Variable "auto_update_now" is true, when global timeout // for scheduled auto-update was met and global auto-update strategy is enabled // so feeds with "default" auto-update strategy should be updated. - QList feedsForScheduledUpdate(bool auto_update_now); + QList feedsForScheduledUpdate(bool auto_update_now); // Returns (undeleted) messages for given feeds. // This is usually used for displaying whole feeds // in "newspaper" mode. - QList messagesForFeeds(const QList &feeds); + QList messagesForFeeds(const QList &feeds); // Returns all categories, each pair // consists of ID of parent item and pointer to category. - QHash allCategories(); + QHash allCategories(); // Returns categories from the subtree with given root node, each pair // consists of ID of parent item and pointer to category. - QHash categoriesForItem(RootItem *root); + QHash categoriesForItem(RootItem *root); // Returns list of all feeds contained in the model. - QList allFeeds(); + QList allFeeds(); // Get list of feeds from tree with particular item // as root. If root itself is a feed, then it is returned. - QList feedsForItem(RootItem *root); + QList feedsForItem(RootItem *root); // Returns list of ALL CHILD feeds which belong to given parent indexes. - QList feedsForIndexes(const QModelIndexList &indexes); + QList feedsForIndexes(const QModelIndexList &indexes); // Returns ALL CHILD feeds contained within single index. - QList feedsForIndex(const QModelIndex &index); + QList feedsForIndex(const QModelIndex &index); // Returns pointer to feed if it lies on given index // or NULL if no feed lies on given index. - Feed *feedForIndex(const QModelIndex &index); + StandardFeed *feedForIndex(const QModelIndex &index); // Returns pointer to category if it lies on given index // or NULL if no category lies on given index. - Category *categoryForIndex(const QModelIndex &index) const; + StandardCategory *categoryForIndex(const QModelIndex &index) const; // Returns pointer to recycle bin if lies on given index // or NULL if no recycle bin lies on given index. @@ -166,8 +166,8 @@ class FeedsModel : public QAbstractItemModel { public slots: // Feeds operations. - bool markFeedsRead(const QList &feeds, int read); - bool markFeedsDeleted(const QList &feeds, int deleted, bool read_only); + bool markFeedsRead(const QList &feeds, int read); + bool markFeedsDeleted(const QList &feeds, int deleted, bool read_only); // Signals that properties (probably counts) // of ALL items have changed. @@ -185,7 +185,7 @@ class FeedsModel : public QAbstractItemModel { protected: // Returns converted ids of given feeds // which are suitable as IN clause for SQL queries. - QStringList textualFeedIds(const QList &feeds); + QStringList textualFeedIds(const QList &feeds); // Loads feed/categories from the database. void loadFromDatabase(); @@ -199,7 +199,7 @@ class FeedsModel : public QAbstractItemModel { void requireItemValidationAfterDragDrop(const QModelIndex &source_index); // Emitted when model requests update of some feeds. - void feedsUpdateRequested(const QList feeds); + void feedsUpdateRequested(const QList feeds); private: RootItem *m_rootItem; diff --git a/src/core/feedsproxymodel.cpp b/src/core/feedsproxymodel.cpp index 36215a3d8..9c1b54f6c 100755 --- a/src/core/feedsproxymodel.cpp +++ b/src/core/feedsproxymodel.cpp @@ -20,9 +20,9 @@ #include "definitions/definitions.h" #include "miscellaneous/application.h" #include "core/feedsmodel.h" -#include "core/category.h" -#include "core/feed.h" #include "core/rootitem.h" +#include "services/standard/standardcategory.h" +#include "services/standard/standardfeed.h" FeedsProxyModel::FeedsProxyModel(QObject *parent) diff --git a/src/core/feedsselection.cpp b/src/core/feedsselection.cpp index 4b7328c1b..e01624d21 100755 --- a/src/core/feedsselection.cpp +++ b/src/core/feedsselection.cpp @@ -18,8 +18,8 @@ #include "core/feedsselection.h" #include "core/rootitem.h" -#include "core/category.h" -#include "core/feed.h" +#include "services/standard/standardcategory.h" +#include "services/standard/standardfeed.h" #include "definitions/definitions.h" diff --git a/src/core/feedsselection.h b/src/core/feedsselection.h old mode 100644 new mode 100755 index 2eb1d27cb..1295bdffa --- a/src/core/feedsselection.h +++ b/src/core/feedsselection.h @@ -23,7 +23,7 @@ class RootItem; -class Feed; +class StandardFeed; class FeedsSelection { public: diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp old mode 100644 new mode 100755 index a262b8d96..a9789c816 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -17,8 +17,8 @@ #include "core/rootitem.h" -#include "core/category.h" -#include "core/feed.h" +#include "services/standard/standardcategory.h" +#include "services/standard/standardfeed.h" #include "core/recyclebin.h" #include "miscellaneous/application.h" @@ -118,12 +118,12 @@ RecycleBin *RootItem::toRecycleBin() { return static_cast(this); } -Category *RootItem::toCategory() { - return static_cast(this); +StandardCategory *RootItem::toCategory() { + return static_cast(this); } -Feed *RootItem::toFeed() { - return static_cast(this); +StandardFeed *RootItem::toFeed() { + return static_cast(this); } RootItem *RootItem::child(RootItem::Kind kind_of_child, const QString &identifier) { diff --git a/src/core/rootitem.h b/src/core/rootitem.h old mode 100644 new mode 100755 index 7ee0e49ef..964fa6122 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -24,8 +24,8 @@ #include class RecycleBin; -class Category; -class Feed; +class StandardCategory; +class StandardFeed; // Represents ROOT item of FeedsModel. // NOTE: This class is derived to add functionality for @@ -183,8 +183,8 @@ class RootItem { // Converters RecycleBin *toRecycleBin(); - Category *toCategory(); - Feed *toFeed(); + StandardCategory *toCategory(); + StandardFeed *toFeed(); // Compares two model items. static bool isEqual(RootItem *lhs, RootItem *rhs); diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index 35ef10a99..b9fad65a0 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -36,10 +36,10 @@ #include "gui/dialogs/formabout.h" #include "gui/dialogs/formsettings.h" #include "gui/dialogs/formupdate.h" -#include "gui/dialogs/formimportexport.h" #include "gui/dialogs/formbackupdatabasesettings.h" #include "gui/dialogs/formrestoredatabasesettings.h" #include "gui/notifications/notification.h" +#include "services/standard/gui/formstandardimportexport.h" #include #include @@ -411,14 +411,14 @@ void FormMain::loadWebBrowserMenu(int index) { } void FormMain::exportFeeds() { - QPointer form = new FormImportExport(this); + QPointer form = new FormStandardImportExport(this); form.data()->setMode(FeedsImportExportModel::Export); form.data()->exec(); delete form.data(); } void FormMain::importFeeds() { - QPointer form = new FormImportExport(this); + QPointer form = new FormStandardImportExport(this); form.data()->setMode(FeedsImportExportModel::Import); form.data()->exec(); delete form.data(); diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index 9aeaa3567..bca5de13f 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -184,9 +184,18 @@ + + + &Services + + + + + + @@ -680,6 +689,21 @@ E + + + &Add new service + + + + + &Delete selected service + + + + + &Edit selected service + + diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 28639c7cd..cbc77346b 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -25,9 +25,9 @@ #include "miscellaneous/databasecleaner.h" #include "core/messagesproxymodel.h" #include "core/feeddownloader.h" -#include "core/feed.h" #include "core/feedsselection.h" -#include "core/feedsimportexportmodel.h" +#include "services/standard/standardfeed.h" +#include "services/standard/standardfeedsimportexportmodel.h" #include "network-web/webbrowser.h" #include "gui/messagesview.h" #include "gui/feedsview.h" @@ -252,7 +252,7 @@ void FeedMessageViewer::onFeedUpdatesStarted() { qApp->mainForm()->statusBar()->showProgressFeeds(0, tr("Feed update started")); } -void FeedMessageViewer::onFeedUpdatesProgress(Feed *feed, int current, int total) { +void FeedMessageViewer::onFeedUpdatesProgress(StandardFeed *feed, int current, int total) { // Some feed got updated. m_feedsView->updateCountsOfParticularFeed(feed, true); qApp->mainForm()->statusBar()->showProgressFeeds((current * 100.0) / total, @@ -369,7 +369,7 @@ void FeedMessageViewer::createConnections() { form_main->m_ui->m_tabWidget, SLOT(addBrowserWithMessages(QList))); // Downloader connections. - connect(m_feedsView, SIGNAL(feedsUpdateRequested(QList)), this, SLOT(updateFeeds(QList))); + connect(m_feedsView, SIGNAL(feedsUpdateRequested(QList)), this, SLOT(updateFeeds(QList))); // Toolbar forwardings. connect(form_main->m_ui->m_actionCleanupDatabase, @@ -548,7 +548,7 @@ void FeedMessageViewer::refreshVisualProperties() { m_toolBarMessages->setToolButtonStyle(button_style); } -void FeedMessageViewer::updateFeeds(QList feeds) { +void FeedMessageViewer::updateFeeds(QList feeds) { if (!qApp->feedUpdateLock()->tryLock()) { qApp->showGuiMessage(tr("Cannot update all items"), tr("You cannot update all items because another another critical operation is ongoing."), @@ -561,14 +561,14 @@ void FeedMessageViewer::updateFeeds(QList feeds) { m_feedDownloaderThread = new QThread(); // Downloader setup. - qRegisterMetaType >("QList"); + qRegisterMetaType >("QList"); m_feedDownloader->moveToThread(m_feedDownloaderThread); - connect(this, SIGNAL(feedsUpdateRequested(QList)), m_feedDownloader, SLOT(updateFeeds(QList))); + connect(this, SIGNAL(feedsUpdateRequested(QList)), m_feedDownloader, SLOT(updateFeeds(QList))); connect(m_feedDownloaderThread, SIGNAL(finished()), m_feedDownloaderThread, SLOT(deleteLater())); connect(m_feedDownloader, SIGNAL(finished(FeedDownloadResults)), this, SLOT(onFeedUpdatesFinished(FeedDownloadResults))); connect(m_feedDownloader, SIGNAL(started()), this, SLOT(onFeedUpdatesStarted())); - connect(m_feedDownloader, SIGNAL(progress(Feed*,int,int)), this, SLOT(onFeedUpdatesProgress(Feed*,int,int))); + connect(m_feedDownloader, SIGNAL(progress(StandardFeed*,int,int)), this, SLOT(onFeedUpdatesProgress(StandardFeed*,int,int))); // Connections are made, start the feed downloader thread. m_feedDownloaderThread->start(); diff --git a/src/gui/feedmessageviewer.h b/src/gui/feedmessageviewer.h old mode 100644 new mode 100755 index 539f4cb35..8c087427f --- a/src/gui/feedmessageviewer.h +++ b/src/gui/feedmessageviewer.h @@ -30,7 +30,7 @@ class MessagesToolBar; class FeedsToolBar; class FeedsView; class DatabaseCleaner; -class Feed; +class StandardFeed; class QToolBar; class QSplitter; class QProgressBar; @@ -103,7 +103,7 @@ class FeedMessageViewer : public TabContent { // Reloads some changeable visual settings. void refreshVisualProperties(); - void updateFeeds(QList feeds); + void updateFeeds(QList feeds); private slots: // Updates counts of messages for example in tray icon. @@ -111,7 +111,7 @@ class FeedMessageViewer : public TabContent { // Reacts on feed updates. void onFeedUpdatesStarted(); - void onFeedUpdatesProgress(Feed *feed, int current, int total); + void onFeedUpdatesProgress(StandardFeed *feed, int current, int total); void onFeedUpdatesFinished(FeedDownloadResults results); // Switches visibility of feed list and related @@ -135,7 +135,7 @@ class FeedMessageViewer : public TabContent { signals: // Emitted if user/application requested updating of some feeds. - void feedsUpdateRequested(const QList feeds); + void feedsUpdateRequested(const QList feeds); private: bool m_toolBarsEnabled; diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 89f634c06..0c01a9698 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -18,21 +18,21 @@ #include "gui/feedsview.h" #include "definitions/definitions.h" -#include "core/feed.h" #include "core/feedsmodel.h" #include "core/feedsproxymodel.h" #include "core/rootitem.h" -#include "core/category.h" #include "core/recyclebin.h" -#include "core/feed.h" +#include "services/standard/standardcategory.h" +#include "services/standard/standardfeed.h" +#include "services/standard/standardfeed.h" #include "miscellaneous/systemfactory.h" #include "miscellaneous/mutex.h" #include "gui/systemtrayicon.h" #include "gui/messagebox.h" #include "gui/styleditemdelegatewithoutfocus.h" #include "gui/dialogs/formmain.h" -#include "gui/dialogs/formcategorydetails.h" -#include "gui/dialogs/formfeeddetails.h" +#include "services/standard/gui/formstandardcategorydetails.h" +#include "services/standard/gui/formstandardfeeddetails.h" #include #include @@ -56,7 +56,7 @@ FeedsView::FeedsView(QWidget *parent) // Connections. connect(m_sourceModel, SIGNAL(requireItemValidationAfterDragDrop(QModelIndex)), this, SLOT(validateItemAfterDragDrop(QModelIndex))); - connect(m_sourceModel, SIGNAL(feedsUpdateRequested(QList)), this, SIGNAL(feedsUpdateRequested(QList))); + connect(m_sourceModel, SIGNAL(feedsUpdateRequested(QList)), this, SIGNAL(feedsUpdateRequested(QList))); connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder))); setModel(m_proxyModel); @@ -73,18 +73,18 @@ void FeedsView::setSortingEnabled(bool enable) { connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder))); } -QList FeedsView::selectedFeeds() const { +QList FeedsView::selectedFeeds() const { QModelIndex current_index = currentIndex(); if (current_index.isValid()) { return m_sourceModel->feedsForIndex(m_proxyModel->mapToSource(current_index)); } else { - return QList(); + return QList(); } } -QList FeedsView::allFeeds() const { +QList FeedsView::allFeeds() const { return m_sourceModel->allFeeds(); } @@ -99,12 +99,12 @@ RootItem *FeedsView::selectedItem() const { return selected_item == m_sourceModel->rootItem() ? NULL : selected_item; } -Category *FeedsView::selectedCategory() const { +StandardCategory *FeedsView::selectedCategory() const { QModelIndex current_mapped = m_proxyModel->mapToSource(currentIndex()); return m_sourceModel->categoryForIndex(current_mapped); } -Feed *FeedsView::selectedFeed() const { +StandardFeed *FeedsView::selectedFeed() const { QModelIndex current_mapped = m_proxyModel->mapToSource(currentIndex()); return m_sourceModel->feedForIndex(current_mapped); } @@ -118,7 +118,7 @@ void FeedsView::saveExpandedStates() { Settings *settings = qApp->settings(); // Iterate all categories and save their expand statuses. - foreach (Category *category, sourceModel()->allCategories().values()) { + foreach (StandardCategory *category, sourceModel()->allCategories().values()) { settings->setValue(GROUP(Categories), QString::number(category->id()), isExpanded(model()->mapFromSource(sourceModel()->indexForItem(category)))); @@ -129,7 +129,7 @@ void FeedsView::loadExpandedStates() { Settings *settings = qApp->settings(); // Iterate all categories and save their expand statuses. - foreach (Category *category, sourceModel()->allCategories().values()) { + foreach (StandardCategory *category, sourceModel()->allCategories().values()) { setExpanded(model()->mapFromSource(sourceModel()->indexForItem(category)), settings->value(GROUP(Categories), QString::number(category->id()), true).toBool()); } @@ -204,7 +204,7 @@ void FeedsView::addNewCategory() { return; } - QPointer form_pointer = new FormCategoryDetails(m_sourceModel, this); + QPointer form_pointer = new FormStandardCategoryDetails(m_sourceModel, this); form_pointer.data()->exec(NULL, selectedItem()); @@ -214,8 +214,8 @@ void FeedsView::addNewCategory() { qApp->feedUpdateLock()->unlock(); } -void FeedsView::editCategory(Category *category) { - QPointer form_pointer = new FormCategoryDetails(m_sourceModel, this); +void FeedsView::editCategory(StandardCategory *category) { + QPointer form_pointer = new FormStandardCategoryDetails(m_sourceModel, this); form_pointer.data()->exec(category, NULL); @@ -233,7 +233,7 @@ void FeedsView::addNewFeed() { return; } - QPointer form_pointer = new FormFeedDetails(m_sourceModel, this); + QPointer form_pointer = new FormStandardFeedDetails(m_sourceModel, this); form_pointer.data()->exec(NULL, selectedItem()); @@ -243,8 +243,8 @@ void FeedsView::addNewFeed() { qApp->feedUpdateLock()->unlock(); } -void FeedsView::editFeed(Feed *feed) { - QPointer form_pointer = new FormFeedDetails(m_sourceModel, this); +void FeedsView::editFeed(StandardFeed *feed) { + QPointer form_pointer = new FormStandardFeedDetails(m_sourceModel, this); form_pointer.data()->exec(feed, NULL); @@ -302,8 +302,8 @@ void FeedsView::editSelectedItem() { return; } - Category *category; - Feed *feed; + StandardCategory *category; + StandardFeed *feed; if ((category = selectedCategory()) != NULL) { editCategory(category); @@ -388,7 +388,7 @@ void FeedsView::markAllFeedsRead() { } void FeedsView::fetchMetadataForSelectedFeed() { - Feed *selected_feed = selectedFeed(); + StandardFeed *selected_feed = selectedFeed(); if (selected_feed != NULL) { selected_feed->fetchMetadataForItself(); @@ -429,7 +429,7 @@ void FeedsView::restoreRecycleBin() { } void FeedsView::updateCountsOfSelectedFeeds(bool update_total_too) { - foreach (Feed *feed, selectedFeeds()) { + foreach (StandardFeed *feed, selectedFeeds()) { feed->updateCounts(update_total_too); } @@ -455,7 +455,7 @@ void FeedsView::updateCountsOfRecycleBin(bool update_total_too) { } void FeedsView::updateCountsOfAllFeeds(bool update_total_too) { - foreach (Feed *feed, allFeeds()) { + foreach (StandardFeed *feed, allFeeds()) { feed->updateCounts(update_total_too); } @@ -469,7 +469,7 @@ void FeedsView::updateCountsOfAllFeeds(bool update_total_too) { notifyWithCounts(); } -void FeedsView::updateCountsOfParticularFeed(Feed *feed, bool update_total_too) { +void FeedsView::updateCountsOfParticularFeed(StandardFeed *feed, bool update_total_too) { QModelIndex index = m_sourceModel->indexForItem(feed); if (index.isValid()) { diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index 61c249175..0a8615f94 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -28,8 +28,8 @@ class FeedsProxyModel; -class Feed; -class Category; +class StandardFeed; +class StandardCategory; class QTimer; class FeedsView : public QTreeView { @@ -53,14 +53,14 @@ class FeedsView : public QTreeView { // Returns list of selected/all feeds. // NOTE: This is recursive method which returns all descendants. - QList selectedFeeds() const; - QList allFeeds() const; + QList selectedFeeds() const; + QList allFeeds() const; // Returns pointers to selected feed/category if they are really // selected. RootItem *selectedItem() const; - Category *selectedCategory() const; - Feed *selectedFeed() const; + StandardCategory *selectedCategory() const; + StandardFeed *selectedFeed() const; RecycleBin *selectedRecycleBin() const; // Saves/loads expand states of all nodes (feeds/categories) of the list to/from settings. @@ -104,11 +104,11 @@ class FeedsView : public QTreeView { // Standard category manipulators. void addNewCategory(); - void editCategory(Category *category); + void editCategory(StandardCategory *category); // Standard feed manipulators. void addNewFeed(); - void editFeed(Feed *feed); + void editFeed(StandardFeed *feed); // Is called when counts of messages are changed externally, // typically from message view. @@ -124,7 +124,7 @@ class FeedsView : public QTreeView { void updateCountsOfAllFeeds(bool update_total_too); // Reloads counts for particular feed. - void updateCountsOfParticularFeed(Feed *feed, bool update_total_too); + void updateCountsOfParticularFeed(StandardFeed *feed, bool update_total_too); // Notifies other components about messages // counts. @@ -168,7 +168,7 @@ class FeedsView : public QTreeView { signals: // Emitted if user/application requested updating of some feeds. - void feedsUpdateRequested(const QList feeds); + void feedsUpdateRequested(const QList feeds); // Emitted if counts of messages are changed. void messageCountsChanged(int unread_messages, int total_messages, bool any_feed_has_unread_messages); diff --git a/src/gui/dialogs/formcategorydetails.cpp b/src/services/standard/gui/formstandardcategorydetails.cpp similarity index 87% rename from src/gui/dialogs/formcategorydetails.cpp rename to src/services/standard/gui/formstandardcategorydetails.cpp index bac6ad7ec..55af700e2 100755 --- a/src/gui/dialogs/formcategorydetails.cpp +++ b/src/services/standard/gui/formstandardcategorydetails.cpp @@ -15,12 +15,12 @@ // You should have received a copy of the GNU General Public License // along with RSS Guard. If not, see . -#include "gui/dialogs/formcategorydetails.h" +#include "services/standard/gui/formstandardcategorydetails.h" #include "definitions/definitions.h" #include "core/rootitem.h" -#include "core/category.h" #include "core/feedsmodel.h" +#include "services/standard/standardcategory.h" #include "miscellaneous/iconfactory.h" #include "gui/feedsview.h" #include "gui/baselineedit.h" @@ -38,9 +38,7 @@ #include -FormCategoryDetails::FormCategoryDetails(FeedsModel *model, - QWidget *parent) - : QDialog(parent), +FormStandardCategoryDetails::FormStandardCategoryDetails(FeedsModel *model, QWidget *parent) : QDialog(parent), m_editableCategory(NULL), m_feedsModel(model) { initialize(); @@ -51,11 +49,11 @@ FormCategoryDetails::FormCategoryDetails(FeedsModel *model, onDescriptionChanged(QString()); } -FormCategoryDetails::~FormCategoryDetails() { +FormStandardCategoryDetails::~FormStandardCategoryDetails() { qDebug("Destroying FormCategoryDetails instance."); } -void FormCategoryDetails::createConnections() { +void FormStandardCategoryDetails::createConnections() { // General connections. connect(m_ui->m_buttonBox, SIGNAL(accepted()), this, SLOT(apply())); connect(m_ui->m_txtTitle->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(onTitleChanged(QString))); @@ -67,7 +65,7 @@ void FormCategoryDetails::createConnections() { connect(m_actionUseDefaultIcon, SIGNAL(triggered()), this, SLOT(onUseDefaultIcon())); } -void FormCategoryDetails::setEditableCategory(Category *editable_category) { +void FormStandardCategoryDetails::setEditableCategory(StandardCategory *editable_category) { m_editableCategory = editable_category; m_ui->m_cmbParentCategory->setCurrentIndex(m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) editable_category->parent()))); @@ -76,7 +74,7 @@ void FormCategoryDetails::setEditableCategory(Category *editable_category) { m_ui->m_btnIcon->setIcon(editable_category->icon()); } -int FormCategoryDetails::exec(Category *input_category, RootItem *parent_to_select) { +int FormStandardCategoryDetails::exec(StandardCategory *input_category, RootItem *parent_to_select) { // Load categories. loadCategories(m_feedsModel->allCategories().values(), m_feedsModel->rootItem(), input_category); @@ -112,9 +110,9 @@ int FormCategoryDetails::exec(Category *input_category, RootItem *parent_to_sele return QDialog::exec(); } -void FormCategoryDetails::apply() { +void FormStandardCategoryDetails::apply() { RootItem *parent = static_cast(m_ui->m_cmbParentCategory->itemData(m_ui->m_cmbParentCategory->currentIndex()).value()); - Category *new_category = new Category(); + StandardCategory *new_category = new StandardCategory(); new_category->setTitle(m_ui->m_txtTitle->lineEdit()->text()); new_category->setCreationDate(QDateTime::currentDateTime()); @@ -147,7 +145,7 @@ void FormCategoryDetails::apply() { } } -void FormCategoryDetails::onTitleChanged(const QString &new_title){ +void FormStandardCategoryDetails::onTitleChanged(const QString &new_title){ if (new_title.simplified().size() >= MIN_CATEGORY_NAME_LENGTH) { m_ui->m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); m_ui->m_txtTitle->setStatus(WidgetWithStatus::Ok, tr("Category name is ok.")); @@ -158,7 +156,7 @@ void FormCategoryDetails::onTitleChanged(const QString &new_title){ } } -void FormCategoryDetails::onDescriptionChanged(const QString &new_description) { +void FormStandardCategoryDetails::onDescriptionChanged(const QString &new_description) { if (new_description.simplified().isEmpty()) { m_ui->m_txtDescription->setStatus(LineEditWithStatus::Warning, tr("Description is empty.")); } @@ -167,11 +165,11 @@ void FormCategoryDetails::onDescriptionChanged(const QString &new_description) { } } -void FormCategoryDetails::onNoIconSelected() { +void FormStandardCategoryDetails::onNoIconSelected() { m_ui->m_btnIcon->setIcon(QIcon()); } -void FormCategoryDetails::onLoadIconFromFile() { +void FormStandardCategoryDetails::onLoadIconFromFile() { QFileDialog dialog(this, tr("Select icon file for the category"), qApp->homeFolderPath(), tr("Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga)")); dialog.setFileMode(QFileDialog::ExistingFile); @@ -190,12 +188,12 @@ void FormCategoryDetails::onLoadIconFromFile() { } } -void FormCategoryDetails::onUseDefaultIcon() { +void FormStandardCategoryDetails::onUseDefaultIcon() { m_ui->m_btnIcon->setIcon(qApp->icons()->fromTheme(QSL("folder-category"))); } -void FormCategoryDetails::initialize() { - m_ui = new Ui::FormCategoryDetails(); +void FormStandardCategoryDetails::initialize() { + m_ui = new Ui::FormStandardCategoryDetails(); m_ui->setupUi(this); // Set text boxes. @@ -241,14 +239,14 @@ void FormCategoryDetails::initialize() { m_ui->m_txtTitle->lineEdit()->setFocus(Qt::TabFocusReason); } -void FormCategoryDetails::loadCategories(const QList categories, +void FormStandardCategoryDetails::loadCategories(const QList categories, RootItem *root_item, - Category *input_category) { + StandardCategory *input_category) { m_ui->m_cmbParentCategory->addItem(root_item->icon(), root_item->title(), QVariant::fromValue((void*) root_item)); - foreach (Category *category, categories) { + foreach (StandardCategory *category, categories) { if (input_category != NULL && (category == input_category || category->isChildOf(input_category))) { // This category cannot be selected as the new // parent for currently edited category, so diff --git a/src/gui/dialogs/formcategorydetails.h b/src/services/standard/gui/formstandardcategorydetails.h old mode 100644 new mode 100755 similarity index 74% rename from src/gui/dialogs/formcategorydetails.h rename to src/services/standard/gui/formstandardcategorydetails.h index 67abd4196..51c9f60c4 --- a/src/gui/dialogs/formcategorydetails.h +++ b/src/services/standard/gui/formstandardcategorydetails.h @@ -18,33 +18,33 @@ #ifndef FORMCATEGORYDETAILS_H #define FORMCATEGORYDETAILS_H -#include "ui_formcategorydetails.h" +#include "ui_formstandardcategorydetails.h" #include namespace Ui { - class FormCategoryDetails; + class FormStandardCategoryDetails; } -class Category; -class Category; +class StandardCategory; +class StandardCategory; class FeedsModel; class RootItem; class QMenu; class QAction; -class FormCategoryDetails : public QDialog { +class FormStandardCategoryDetails : public QDialog { Q_OBJECT public: // Constructors and destructors. - explicit FormCategoryDetails(FeedsModel *model, QWidget *parent = 0); - virtual ~FormCategoryDetails(); + explicit FormStandardCategoryDetails(FeedsModel *model, QWidget *parent = 0); + virtual ~FormStandardCategoryDetails(); public slots: // Executes add/edit standard category dialog. - int exec(Category *input_category, RootItem *parent_to_select); + int exec(StandardCategory *input_category, RootItem *parent_to_select); protected slots: // Applies changes. @@ -64,7 +64,7 @@ class FormCategoryDetails : public QDialog { void createConnections(); // Sets the category which will be edited. - void setEditableCategory(Category *editable_category); + void setEditableCategory(StandardCategory *editable_category); // Initializes the dialog. void initialize(); @@ -72,11 +72,11 @@ class FormCategoryDetails : public QDialog { // Loads categories into the dialog + give root "category" // and make sure that no childs of input category (including) // input category are loaded. - void loadCategories(const QList categories, RootItem *root_item, Category *input_category); + void loadCategories(const QList categories, RootItem *root_item, StandardCategory *input_category); private: - Ui::FormCategoryDetails *m_ui; - Category *m_editableCategory; + Ui::FormStandardCategoryDetails *m_ui; + StandardCategory *m_editableCategory; FeedsModel *m_feedsModel; QMenu *m_iconMenu; diff --git a/src/gui/dialogs/formcategorydetails.ui b/src/services/standard/gui/formstandardcategorydetails.ui old mode 100644 new mode 100755 similarity index 96% rename from src/gui/dialogs/formcategorydetails.ui rename to src/services/standard/gui/formstandardcategorydetails.ui index 7c2fd546c..67bbed086 --- a/src/gui/dialogs/formcategorydetails.ui +++ b/src/services/standard/gui/formstandardcategorydetails.ui @@ -1,7 +1,7 @@ - FormCategoryDetails - + FormStandardCategoryDetails + 0 @@ -153,7 +153,7 @@ m_buttonBox rejected() - FormCategoryDetails + FormStandardCategoryDetails reject() diff --git a/src/gui/dialogs/formfeeddetails.cpp b/src/services/standard/gui/formstandardfeeddetails.cpp similarity index 83% rename from src/gui/dialogs/formfeeddetails.cpp rename to src/services/standard/gui/formstandardfeeddetails.cpp index e022cb814..f1884a1c4 100755 --- a/src/gui/dialogs/formfeeddetails.cpp +++ b/src/services/standard/gui/formstandardfeeddetails.cpp @@ -15,13 +15,13 @@ // You should have received a copy of the GNU General Public License // along with RSS Guard. If not, see . -#include "gui/dialogs/formfeeddetails.h" +#include "services/standard/gui/formstandardfeeddetails.h" #include "definitions/definitions.h" #include "core/feedsmodel.h" #include "core/rootitem.h" -#include "core/category.h" -#include "core/feed.h" +#include "services/standard/standardcategory.h" +#include "services/standard/standardfeed.h" #include "miscellaneous/textfactory.h" #include "miscellaneous/iconfactory.h" #include "network-web/networkfactory.h" @@ -39,7 +39,7 @@ #include -FormFeedDetails::FormFeedDetails(FeedsModel *model, QWidget *parent) +FormStandardFeedDetails::FormStandardFeedDetails(FeedsModel *model, QWidget *parent) : QDialog(parent), m_editableFeed(NULL), m_feedsModel(model) { @@ -54,11 +54,11 @@ FormFeedDetails::FormFeedDetails(FeedsModel *model, QWidget *parent) onPasswordChanged(QString()); } -FormFeedDetails::~FormFeedDetails() { +FormStandardFeedDetails::~FormStandardFeedDetails() { delete m_ui; } -int FormFeedDetails::exec(Feed *input_feed, RootItem *parent_to_select) { +int FormStandardFeedDetails::exec(StandardFeed *input_feed, RootItem *parent_to_select) { // Load categories. loadCategories(m_feedsModel->allCategories().values(), m_feedsModel->rootItem()); @@ -103,7 +103,7 @@ int FormFeedDetails::exec(Feed *input_feed, RootItem *parent_to_select) { return QDialog::exec(); } -void FormFeedDetails::onTitleChanged(const QString &new_title){ +void FormStandardFeedDetails::onTitleChanged(const QString &new_title){ if (new_title.simplified().size() >= MIN_CATEGORY_NAME_LENGTH) { m_ui->m_txtTitle->setStatus(LineEditWithStatus::Ok, tr("Feed name is ok.")); } @@ -114,7 +114,7 @@ void FormFeedDetails::onTitleChanged(const QString &new_title){ checkOkButtonEnabled(); } -void FormFeedDetails::onDescriptionChanged(const QString &new_description) { +void FormStandardFeedDetails::onDescriptionChanged(const QString &new_description) { if (new_description.simplified().isEmpty()) { m_ui->m_txtDescription->setStatus(LineEditWithStatus::Warning, tr("Description is empty.")); } @@ -123,7 +123,7 @@ void FormFeedDetails::onDescriptionChanged(const QString &new_description) { } } -void FormFeedDetails::onUrlChanged(const QString &new_url) { +void FormStandardFeedDetails::onUrlChanged(const QString &new_url) { if (QRegExp(URL_REGEXP).exactMatch(new_url)) { // New url is well-formed. m_ui->m_txtUrl->setStatus(LineEditWithStatus::Ok, tr("The url is ok.")); @@ -140,7 +140,7 @@ void FormFeedDetails::onUrlChanged(const QString &new_url) { checkOkButtonEnabled(); } -void FormFeedDetails::onUsernameChanged(const QString &new_username) { +void FormStandardFeedDetails::onUsernameChanged(const QString &new_username) { bool is_username_ok = !m_ui->m_gbAuthentication->isChecked() || !new_username.simplified().isEmpty(); m_ui->m_txtUsername->setStatus(is_username_ok ? @@ -151,7 +151,7 @@ void FormFeedDetails::onUsernameChanged(const QString &new_username) { tr("Username is empty.")); } -void FormFeedDetails::onPasswordChanged(const QString &new_password) { +void FormStandardFeedDetails::onPasswordChanged(const QString &new_password) { bool is_password_ok = !m_ui->m_gbAuthentication->isChecked() || !new_password.simplified().isEmpty(); m_ui->m_txtPassword->setStatus(is_password_ok ? @@ -162,27 +162,27 @@ void FormFeedDetails::onPasswordChanged(const QString &new_password) { tr("Password is empty.")); } -void FormFeedDetails::onAuthenticationSwitched() { +void FormStandardFeedDetails::onAuthenticationSwitched() { onUsernameChanged(m_ui->m_txtUsername->lineEdit()->text()); onPasswordChanged(m_ui->m_txtPassword->lineEdit()->text()); } -void FormFeedDetails::onAutoUpdateTypeChanged(int new_index) { - Feed::AutoUpdateType auto_update_type = static_cast(m_ui->m_cmbAutoUpdateType->itemData(new_index).toInt()); +void FormStandardFeedDetails::onAutoUpdateTypeChanged(int new_index) { + StandardFeed::AutoUpdateType auto_update_type = static_cast(m_ui->m_cmbAutoUpdateType->itemData(new_index).toInt()); switch (auto_update_type) { - case Feed::DontAutoUpdate: - case Feed::DefaultAutoUpdate: + case StandardFeed::DontAutoUpdate: + case StandardFeed::DefaultAutoUpdate: m_ui->m_spinAutoUpdateInterval->setEnabled(false); break; - case Feed::SpecificAutoUpdate: + case StandardFeed::SpecificAutoUpdate: default: m_ui->m_spinAutoUpdateInterval->setEnabled(true); } } -void FormFeedDetails::checkOkButtonEnabled() { +void FormStandardFeedDetails::checkOkButtonEnabled() { LineEditWithStatus::StatusType title_status = m_ui->m_txtTitle->status(); LineEditWithStatus::StatusType url_status = m_ui->m_txtUrl->status(); @@ -191,11 +191,11 @@ void FormFeedDetails::checkOkButtonEnabled() { url_status == LineEditWithStatus::Warning)); } -void FormFeedDetails::onNoIconSelected() { +void FormStandardFeedDetails::onNoIconSelected() { m_ui->m_btnIcon->setIcon(QIcon()); } -void FormFeedDetails::onLoadIconFromFile() { +void FormStandardFeedDetails::onLoadIconFromFile() { QFileDialog dialog(this, tr("Select icon file for the feed"), qApp->homeFolderPath(), tr("Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga)")); dialog.setFileMode(QFileDialog::ExistingFile); @@ -214,14 +214,14 @@ void FormFeedDetails::onLoadIconFromFile() { } } -void FormFeedDetails::onUseDefaultIcon() { +void FormStandardFeedDetails::onUseDefaultIcon() { m_ui->m_btnIcon->setIcon(qApp->icons()->fromTheme(QSL("folder-feed"))); } -void FormFeedDetails::apply() { +void FormStandardFeedDetails::apply() { RootItem *parent = static_cast(m_ui->m_cmbParentCategory->itemData(m_ui->m_cmbParentCategory->currentIndex()).value()); - Feed::Type type = static_cast(m_ui->m_cmbType->itemData(m_ui->m_cmbType->currentIndex()).value()); - Feed *new_feed = new Feed(); + StandardFeed::Type type = static_cast(m_ui->m_cmbType->itemData(m_ui->m_cmbType->currentIndex()).value()); + StandardFeed *new_feed = new StandardFeed(); // Setup data for new_feed. new_feed->setTitle(m_ui->m_txtTitle->lineEdit()->text()); @@ -234,7 +234,7 @@ void FormFeedDetails::apply() { new_feed->setPasswordProtected(m_ui->m_gbAuthentication->isChecked()); new_feed->setUsername(m_ui->m_txtUsername->lineEdit()->text()); new_feed->setPassword(m_ui->m_txtPassword->lineEdit()->text()); - new_feed->setAutoUpdateType(static_cast(m_ui->m_cmbAutoUpdateType->itemData(m_ui->m_cmbAutoUpdateType->currentIndex()).toInt())); + new_feed->setAutoUpdateType(static_cast(m_ui->m_cmbAutoUpdateType->itemData(m_ui->m_cmbAutoUpdateType->currentIndex()).toInt())); new_feed->setAutoUpdateInitialInterval(m_ui->m_spinAutoUpdateInterval->value()); new_feed->setParent(parent); @@ -262,8 +262,8 @@ void FormFeedDetails::apply() { } } -void FormFeedDetails::guessFeed() { - QPair result = Feed::guessFeed(m_ui->m_txtUrl->lineEdit()->text(), +void FormStandardFeedDetails::guessFeed() { + QPair result = StandardFeed::guessFeed(m_ui->m_txtUrl->lineEdit()->text(), m_ui->m_txtUsername->lineEdit()->text(), m_ui->m_txtPassword->lineEdit()->text()); @@ -306,8 +306,8 @@ void FormFeedDetails::guessFeed() { } } -void FormFeedDetails::guessIconOnly() { - QPair result = Feed::guessFeed(m_ui->m_txtUrl->lineEdit()->text(), +void FormStandardFeedDetails::guessIconOnly() { + QPair result = StandardFeed::guessFeed(m_ui->m_txtUrl->lineEdit()->text(), m_ui->m_txtUsername->lineEdit()->text(), m_ui->m_txtPassword->lineEdit()->text()); @@ -337,7 +337,7 @@ void FormFeedDetails::guessIconOnly() { } } -void FormFeedDetails::createConnections() { +void FormStandardFeedDetails::createConnections() { // General connections. connect(m_ui->m_buttonBox, SIGNAL(accepted()), this, SLOT(apply())); connect(m_ui->m_txtTitle->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(onTitleChanged(QString))); @@ -356,7 +356,7 @@ void FormFeedDetails::createConnections() { connect(m_actionUseDefaultIcon, SIGNAL(triggered()), this, SLOT(onUseDefaultIcon())); } -void FormFeedDetails::setEditableFeed(Feed *editable_feed) { +void FormStandardFeedDetails::setEditableFeed(StandardFeed *editable_feed) { m_editableFeed = editable_feed; m_ui->m_cmbParentCategory->setCurrentIndex(m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) editable_feed->parent()))); @@ -373,8 +373,8 @@ void FormFeedDetails::setEditableFeed(Feed *editable_feed) { m_ui->m_spinAutoUpdateInterval->setValue(editable_feed->autoUpdateInitialInterval()); } -void FormFeedDetails::initialize() { - m_ui = new Ui::FormFeedDetails(); +void FormStandardFeedDetails::initialize() { + m_ui = new Ui::FormStandardFeedDetails(); m_ui->setupUi(this); // Set flags and attributes. @@ -405,10 +405,10 @@ void FormFeedDetails::initialize() { #endif // Add standard feed types. - m_ui->m_cmbType->addItem(Feed::typeToString(Feed::Atom10), QVariant::fromValue((int) Feed::Atom10)); - m_ui->m_cmbType->addItem(Feed::typeToString(Feed::Rdf), QVariant::fromValue((int) Feed::Rdf)); - m_ui->m_cmbType->addItem(Feed::typeToString(Feed::Rss0X), QVariant::fromValue((int) Feed::Rss0X)); - m_ui->m_cmbType->addItem(Feed::typeToString(Feed::Rss2X), QVariant::fromValue((int) Feed::Rss2X)); + m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Atom10), QVariant::fromValue((int) StandardFeed::Atom10)); + m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Rdf), QVariant::fromValue((int) StandardFeed::Rdf)); + m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Rss0X), QVariant::fromValue((int) StandardFeed::Rss0X)); + m_ui->m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Rss2X), QVariant::fromValue((int) StandardFeed::Rss2X)); // Load available encodings. QList encodings = QTextCodec::availableCodecs(); @@ -449,9 +449,9 @@ void FormFeedDetails::initialize() { // Setup auto-update options. m_ui->m_spinAutoUpdateInterval->setValue(DEFAULT_AUTO_UPDATE_INTERVAL); - m_ui->m_cmbAutoUpdateType->addItem(tr("Auto-update using global interval"), QVariant::fromValue((int) Feed::DefaultAutoUpdate)); - m_ui->m_cmbAutoUpdateType->addItem(tr("Auto-update every"), QVariant::fromValue((int) Feed::SpecificAutoUpdate)); - m_ui->m_cmbAutoUpdateType->addItem(tr("Do not auto-update at all"), QVariant::fromValue((int) Feed::DontAutoUpdate)); + m_ui->m_cmbAutoUpdateType->addItem(tr("Auto-update using global interval"), QVariant::fromValue((int) StandardFeed::DefaultAutoUpdate)); + m_ui->m_cmbAutoUpdateType->addItem(tr("Auto-update every"), QVariant::fromValue((int) StandardFeed::SpecificAutoUpdate)); + m_ui->m_cmbAutoUpdateType->addItem(tr("Do not auto-update at all"), QVariant::fromValue((int) StandardFeed::DontAutoUpdate)); // Set tab order. setTabOrder(m_ui->m_cmbParentCategory, m_ui->m_cmbType); @@ -475,13 +475,13 @@ void FormFeedDetails::initialize() { m_ui->m_txtUrl->lineEdit()->setFocus(Qt::TabFocusReason); } -void FormFeedDetails::loadCategories(const QList categories, +void FormStandardFeedDetails::loadCategories(const QList categories, RootItem *root_item) { m_ui->m_cmbParentCategory->addItem(root_item->icon(), root_item->title(), QVariant::fromValue((void*) root_item)); - foreach (Category *category, categories) { + foreach (StandardCategory *category, categories) { m_ui->m_cmbParentCategory->addItem(category->data(FDS_MODEL_TITLE_INDEX, Qt::DecorationRole).value(), category->title(), diff --git a/src/gui/dialogs/formfeeddetails.h b/src/services/standard/gui/formstandardfeeddetails.h old mode 100644 new mode 100755 similarity index 78% rename from src/gui/dialogs/formfeeddetails.h rename to src/services/standard/gui/formstandardfeeddetails.h index 550b0bcb9..6b3ed95a7 --- a/src/gui/dialogs/formfeeddetails.h +++ b/src/services/standard/gui/formstandardfeeddetails.h @@ -18,31 +18,31 @@ #ifndef FORMSTANDARDFEEDDETAILS_H #define FORMSTANDARDFEEDDETAILS_H -#include "ui_formfeeddetails.h" - #include +#include "ui_formstandardfeeddetails.h" + namespace Ui { - class FormFeedDetails; + class FormStandardFeedDetails; } class FeedsModel; -class Feed; -class Category; +class StandardFeed; +class StandardCategory; class RootItem; -class FormFeedDetails : public QDialog { +class FormStandardFeedDetails : public QDialog { Q_OBJECT public: // Constructors and destructors. - explicit FormFeedDetails(FeedsModel *model, QWidget *parent = 0); - virtual ~FormFeedDetails(); + explicit FormStandardFeedDetails(FeedsModel *model, QWidget *parent = 0); + virtual ~FormStandardFeedDetails(); public slots: // Executes add/edit standard feed dialog. - int exec(Feed *input_feed, RootItem *parent_to_select); + int exec(StandardFeed *input_feed, RootItem *parent_to_select); protected slots: // Applies changes. @@ -72,18 +72,18 @@ class FormFeedDetails : public QDialog { void createConnections(); // Sets the feed which will be edited. - void setEditableFeed(Feed *editable_feed); + void setEditableFeed(StandardFeed *editable_feed); // Initializes the dialog. void initialize(); // Loads categories into the dialog from the model. - void loadCategories(const QList categories, + void loadCategories(const QList categories, RootItem *root_item); private: - Ui::FormFeedDetails *m_ui; - Feed *m_editableFeed; + Ui::FormStandardFeedDetails *m_ui; + StandardFeed *m_editableFeed; FeedsModel *m_feedsModel; QMenu *m_iconMenu; diff --git a/src/gui/dialogs/formfeeddetails.ui b/src/services/standard/gui/formstandardfeeddetails.ui old mode 100644 new mode 100755 similarity index 95% rename from src/gui/dialogs/formfeeddetails.ui rename to src/services/standard/gui/formstandardfeeddetails.ui index dd8755df2..fa1511ab4 --- a/src/gui/dialogs/formfeeddetails.ui +++ b/src/services/standard/gui/formstandardfeeddetails.ui @@ -1,7 +1,7 @@ - FormFeedDetails - + FormStandardFeedDetails + 0 @@ -325,7 +325,7 @@ m_buttonBox rejected() - FormFeedDetails + FormStandardFeedDetails reject() diff --git a/src/gui/dialogs/formimportexport.cpp b/src/services/standard/gui/formstandardimportexport.cpp similarity index 90% rename from src/gui/dialogs/formimportexport.cpp rename to src/services/standard/gui/formstandardimportexport.cpp index d56421e75..e0c4188b3 100755 --- a/src/gui/dialogs/formimportexport.cpp +++ b/src/services/standard/gui/formstandardimportexport.cpp @@ -15,9 +15,9 @@ // You should have received a copy of the GNU General Public License // along with RSS Guard. If not, see . -#include "gui/dialogs/formimportexport.h" +#include "services/standard/gui/formstandardimportexport.h" -#include "core/feedsimportexportmodel.h" +#include "services/standard/standardfeedsimportexportmodel.h" #include "core/feedsmodel.h" #include "miscellaneous/application.h" #include "gui/feedmessageviewer.h" @@ -28,7 +28,8 @@ #include -FormImportExport::FormImportExport(QWidget *parent) : QDialog(parent), m_ui(new Ui::FormImportExport) { +FormStandardImportExport::FormStandardImportExport(QWidget *parent) + : QDialog(parent), m_ui(new Ui::FormStandardImportExport) { m_ui->setupUi(this); m_model = new FeedsImportExportModel(m_ui->m_treeFeeds); @@ -44,11 +45,11 @@ FormImportExport::FormImportExport(QWidget *parent) : QDialog(parent), m_ui(new connect(m_ui->m_btnUncheckAllItems, SIGNAL(clicked()), m_model, SLOT(uncheckAllItems())); } -FormImportExport::~FormImportExport() { +FormStandardImportExport::~FormStandardImportExport() { delete m_ui; } -void FormImportExport::setMode(const FeedsImportExportModel::Mode &mode) { +void FormStandardImportExport::setMode(const FeedsImportExportModel::Mode &mode) { m_model->setMode(mode); switch (mode) { @@ -80,7 +81,7 @@ void FormImportExport::setMode(const FeedsImportExportModel::Mode &mode) { m_ui->m_buttonBox->button(QDialogButtonBox::Ok)->setDisabled(true); } -void FormImportExport::selectFile() { +void FormStandardImportExport::selectFile() { switch (m_model->mode()) { case FeedsImportExportModel::Import: selectImportFile(); @@ -96,7 +97,7 @@ void FormImportExport::selectFile() { } } -void FormImportExport::selectExportFile() { +void FormStandardImportExport::selectExportFile() { QString filter_opml20 = tr("OPML 2.0 files (*.opml)"); QString filter; @@ -124,7 +125,7 @@ void FormImportExport::selectExportFile() { m_ui->m_buttonBox->button(QDialogButtonBox::Ok)->setDisabled(selected_file.isEmpty()); } -void FormImportExport::selectImportFile() { +void FormStandardImportExport::selectImportFile() { QString filter_opml20 = tr("OPML 2.0 files (*.opml)"); QString filter; @@ -148,7 +149,7 @@ void FormImportExport::selectImportFile() { } } -void FormImportExport::parseImportFile(const QString &file_name) { +void FormStandardImportExport::parseImportFile(const QString &file_name) { QFile input_file(file_name); QByteArray input_data; @@ -186,7 +187,7 @@ void FormImportExport::parseImportFile(const QString &file_name) { m_ui->m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(parsing_result); } -void FormImportExport::performAction() { +void FormStandardImportExport::performAction() { switch (m_model->mode()) { case FeedsImportExportModel::Import: importFeeds(); @@ -201,7 +202,7 @@ void FormImportExport::performAction() { } } -void FormImportExport::exportFeeds() { +void FormStandardImportExport::exportFeeds() { switch (m_conversionType) { case OPML20: { QByteArray result_data; @@ -237,7 +238,7 @@ void FormImportExport::exportFeeds() { } } -void FormImportExport::importFeeds() { +void FormStandardImportExport::importFeeds() { QString output_message; if (qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->mergeModel(m_model, output_message)) { diff --git a/src/gui/dialogs/formimportexport.h b/src/services/standard/gui/formstandardimportexport.h old mode 100644 new mode 100755 similarity index 80% rename from src/gui/dialogs/formimportexport.h rename to src/services/standard/gui/formstandardimportexport.h index cab60cc05..fc1fa85dd --- a/src/gui/dialogs/formimportexport.h +++ b/src/services/standard/gui/formstandardimportexport.h @@ -20,15 +20,15 @@ #include -#include "ui_formimportexport.h" -#include "core/feedsimportexportmodel.h" +#include "ui_formstandardimportexport.h" +#include "services/standard/standardfeedsimportexportmodel.h" namespace Ui { - class FormExport; + class FormStandardImportExport; } -class FormImportExport : public QDialog { +class FormStandardImportExport : public QDialog { Q_OBJECT public: @@ -37,8 +37,8 @@ class FormImportExport : public QDialog { }; // Constructors. - explicit FormImportExport(QWidget *parent = 0); - virtual ~FormImportExport(); + explicit FormStandardImportExport(QWidget *parent = 0); + virtual ~FormStandardImportExport(); void setMode(const FeedsImportExportModel::Mode &mode); @@ -54,7 +54,7 @@ class FormImportExport : public QDialog { void exportFeeds(); void importFeeds(); - Ui::FormImportExport *m_ui; + Ui::FormStandardImportExport *m_ui; ConversionType m_conversionType; FeedsImportExportModel *m_model; }; diff --git a/src/gui/dialogs/formimportexport.ui b/src/services/standard/gui/formstandardimportexport.ui old mode 100644 new mode 100755 similarity index 96% rename from src/gui/dialogs/formimportexport.ui rename to src/services/standard/gui/formstandardimportexport.ui index 46af7e659..53b635d74 --- a/src/gui/dialogs/formimportexport.ui +++ b/src/services/standard/gui/formstandardimportexport.ui @@ -1,7 +1,7 @@ - FormImportExport - + FormStandardImportExport + 0 @@ -149,7 +149,7 @@ m_buttonBox rejected() - FormImportExport + FormStandardImportExport reject() diff --git a/src/core/category.cpp b/src/services/standard/standardcategory.cpp old mode 100644 new mode 100755 similarity index 89% rename from src/core/category.cpp rename to src/services/standard/standardcategory.cpp index cf2fb0bdd..b87ae4b6f --- a/src/core/category.cpp +++ b/src/services/standard/standardcategory.cpp @@ -15,7 +15,7 @@ // You should have received a copy of the GNU General Public License // along with RSS Guard. If not, see . -#include "core/category.h" +#include "services/standard/standardcategory.h" #include "definitions/definitions.h" #include "miscellaneous/databasefactory.h" @@ -29,11 +29,11 @@ #include -Category::Category(RootItem *parent_item) : RootItem(parent_item) { +StandardCategory::StandardCategory(RootItem *parent_item) : RootItem(parent_item) { init(); } -Category::Category(const Category &other) +StandardCategory::StandardCategory(const StandardCategory &other) : RootItem(NULL) { m_kind = other.kind(); m_id = other.id(); @@ -45,15 +45,15 @@ Category::Category(const Category &other) m_parentItem = other.parent(); } -Category::~Category() { +StandardCategory::~StandardCategory() { qDebug("Destroying Category instance."); } -void Category::init() { +void StandardCategory::init() { m_kind = RootItem::Cattegory; } -QVariant Category::data(int column, int role) const { +QVariant StandardCategory::data(int column, int role) const { switch (role) { case Qt::ToolTipRole: if (column == FDS_MODEL_TITLE_INDEX) { @@ -121,7 +121,7 @@ QVariant Category::data(int column, int role) const { } } -bool Category::removeItself() { +bool StandardCategory::removeItself() { bool children_removed = true; // Remove all child items (feeds, categories.) @@ -146,7 +146,7 @@ bool Category::removeItself() { } } -bool Category::addItself(RootItem *parent) { +bool StandardCategory::addItself(RootItem *parent) { // Now, add category to persistent storage. // Children are removed, remove this standard category too. QSqlDatabase database = qApp->database()->connection(QSL("Category"), DatabaseFactory::FromSettings); @@ -185,10 +185,10 @@ bool Category::addItself(RootItem *parent) { return true; } -bool Category::editItself(Category *new_category_data) { +bool StandardCategory::editItself(StandardCategory *new_category_data) { QSqlDatabase database = qApp->database()->connection(QSL("Category"), DatabaseFactory::FromSettings); QSqlQuery query_update_category(database); - Category *original_category = this; + StandardCategory *original_category = this; RootItem *new_parent = new_category_data->parent(); query_update_category.setForwardOnly(true); @@ -215,7 +215,7 @@ bool Category::editItself(Category *new_category_data) { return true; } -Category::Category(const QSqlRecord &record) : RootItem(NULL) { +StandardCategory::StandardCategory(const QSqlRecord &record) : RootItem(NULL) { init(); setId(record.value(CAT_DB_ID_INDEX).toInt()); diff --git a/src/core/category.h b/src/services/standard/standardcategory.h old mode 100644 new mode 100755 similarity index 80% rename from src/core/category.h rename to src/services/standard/standardcategory.h index 3cf04adb1..c0a952b8a --- a/src/core/category.h +++ b/src/services/standard/standardcategory.h @@ -29,15 +29,15 @@ class FeedsModel; // Base class for all categories contained in FeedsModel. // NOTE: This class should be derived to create PARTICULAR category types. // NOTE: This class should not be instantiated directly. -class Category : public RootItem { +class StandardCategory : public RootItem { Q_DECLARE_TR_FUNCTIONS(Category) public: // Constructors and destructors - explicit Category(RootItem *parent_item = NULL); - explicit Category(const Category &other); - explicit Category(const QSqlRecord &record); - virtual ~Category(); + explicit StandardCategory(RootItem *parent_item = NULL); + explicit StandardCategory(const StandardCategory &other); + explicit StandardCategory(const QSqlRecord &record); + virtual ~StandardCategory(); // Returns the actual data representation of standard category. QVariant data(int column, int role) const; @@ -47,7 +47,7 @@ class Category : public RootItem { bool removeItself(); bool addItself(RootItem *parent); - bool editItself(Category *new_category_data); + bool editItself(StandardCategory *new_category_data); private: void init(); diff --git a/src/core/feed.cpp b/src/services/standard/standardfeed.cpp old mode 100644 new mode 100755 similarity index 91% rename from src/core/feed.cpp rename to src/services/standard/standardfeed.cpp index 210a8932e..812529db0 --- a/src/core/feed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -15,7 +15,7 @@ // You should have received a copy of the GNU General Public License // along with RSS Guard. If not, see . -#include "core/feed.h" +#include "services/standard/standardfeed.h" #include "definitions/definitions.h" #include "core/parsingfactory.h" @@ -38,7 +38,7 @@ #include -void Feed::init() { +void StandardFeed::init() { m_passwordProtected = false; m_username = QString(); m_password = QString(); @@ -55,12 +55,12 @@ void Feed::init() { m_kind = RootItem::Feeed; } -Feed::Feed(RootItem *parent_item) +StandardFeed::StandardFeed(RootItem *parent_item) : RootItem(parent_item) { init(); } -Feed::Feed(const Feed &other) +StandardFeed::StandardFeed(const StandardFeed &other) : RootItem(NULL) { m_passwordProtected = other.passwordProtected(); m_username = other.username(); @@ -85,24 +85,24 @@ Feed::Feed(const Feed &other) m_description = other.description(); } -Feed::~Feed() { +StandardFeed::~StandardFeed() { qDebug("Destroying Feed instance."); } -int Feed::childCount() const { +int StandardFeed::childCount() const { // Because feed has no children. return 0; } -int Feed::countOfAllMessages() const { +int StandardFeed::countOfAllMessages() const { return m_totalCount; } -int Feed::countOfUnreadMessages() const { +int StandardFeed::countOfUnreadMessages() const { return m_unreadCount; } -QString Feed::typeToString(Feed::Type type) { +QString StandardFeed::typeToString(StandardFeed::Type type) { switch (type) { case Atom10: return QSL("ATOM 1.0"); @@ -119,7 +119,7 @@ QString Feed::typeToString(Feed::Type type) { } } -void Feed::updateCounts(bool including_total_count, bool update_feed_statuses) { +void StandardFeed::updateCounts(bool including_total_count, bool update_feed_statuses) { QSqlDatabase database = qApp->database()->connection(QSL("Feed"), DatabaseFactory::FromSettings); QSqlQuery query_all(database); @@ -143,8 +143,8 @@ void Feed::updateCounts(bool including_total_count, bool update_feed_statuses) { } } -void Feed::fetchMetadataForItself() { - QPair metadata = guessFeed(url(), username(), password()); +void StandardFeed::fetchMetadataForItself() { + QPair metadata = guessFeed(url(), username(), password()); if (metadata.first != NULL && metadata.second == QNetworkReply::NoError) { // Some properties are not updated when new metadata are fetched. @@ -166,8 +166,8 @@ void Feed::fetchMetadataForItself() { } } -QPair Feed::guessFeed(const QString &url, const QString &username, const QString &password) { - QPair result; result.first = NULL; +QPair StandardFeed::guessFeed(const QString &url, const QString &username, const QString &password) { + QPair result; result.first = NULL; QByteArray feed_contents; NetworkResult network_result = NetworkFactory::downloadFeedFile(url, @@ -196,7 +196,7 @@ QPair Feed::guessFeed(const QString &url, con } if (result.first == NULL) { - result.first = new Feed(); + result.first = new StandardFeed(); } QTextCodec *custom_codec = QTextCodec::codecForName(xml_schema_encoding.toLocal8Bit()); @@ -308,7 +308,7 @@ QPair Feed::guessFeed(const QString &url, con return result; } -QVariant Feed::data(int column, int role) const { +QVariant StandardFeed::data(int column, int role) const { switch (role) { case Qt::DisplayRole: if (column == FDS_MODEL_TITLE_INDEX) { @@ -373,7 +373,7 @@ QVariant Feed::data(int column, int role) const { "Network status: %6\n" "Encoding: %4\n" "Auto-update status: %5").arg(m_title, - Feed::typeToString(m_type), + StandardFeed::typeToString(m_type), m_description.isEmpty() ? QString() : QString('\n') + m_description, m_encoding, auto_update_string, @@ -415,7 +415,7 @@ QVariant Feed::data(int column, int role) const { } } -int Feed::update() { +int StandardFeed::update() { QByteArray feed_contents; int download_timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); m_networkError = NetworkFactory::downloadFeedFile(url(), download_timeout, feed_contents, @@ -448,16 +448,16 @@ int Feed::update() { QList messages; switch (type()) { - case Feed::Rss0X: - case Feed::Rss2X: + case StandardFeed::Rss0X: + case StandardFeed::Rss2X: messages = ParsingFactory::parseAsRSS20(formatted_feed_contents); break; - case Feed::Rdf: + case StandardFeed::Rdf: messages = ParsingFactory::parseAsRDF(formatted_feed_contents); break; - case Feed::Atom10: + case StandardFeed::Atom10: messages = ParsingFactory::parseAsATOM10(formatted_feed_contents); default: @@ -467,7 +467,7 @@ int Feed::update() { return updateMessages(messages); } -bool Feed::removeItself() { +bool StandardFeed::removeItself() { QSqlDatabase database = qApp->database()->connection(QSL("Feed"), DatabaseFactory::FromSettings); QSqlQuery query_remove(database); @@ -488,7 +488,7 @@ bool Feed::removeItself() { return query_remove.exec(); } -bool Feed::addItself(RootItem *parent) { +bool StandardFeed::addItself(RootItem *parent) { // Now, add feed to persistent storage. QSqlDatabase database = qApp->database()->connection(QSL("Feed"), DatabaseFactory::FromSettings); QSqlQuery query_add_feed(database); @@ -532,10 +532,10 @@ bool Feed::addItself(RootItem *parent) { return true; } -bool Feed::editItself(Feed *new_feed_data) { +bool StandardFeed::editItself(StandardFeed *new_feed_data) { QSqlDatabase database = qApp->database()->connection(QSL("Feed"), DatabaseFactory::FromSettings); QSqlQuery query_update_feed(database); - Feed *original_feed = this; + StandardFeed *original_feed = this; RootItem *new_parent = new_feed_data->parent(); query_update_feed.setForwardOnly(true); @@ -579,7 +579,7 @@ bool Feed::editItself(Feed *new_feed_data) { return true; } -int Feed::updateMessages(const QList &messages) { +int StandardFeed::updateMessages(const QList &messages) { int feed_id = id(); int updated_messages = 0; QSqlDatabase database = qApp->database()->connection(QSL("Feed"), DatabaseFactory::FromSettings); @@ -706,11 +706,11 @@ int Feed::updateMessages(const QList &messages) { return updated_messages; } -QNetworkReply::NetworkError Feed::networkError() const { +QNetworkReply::NetworkError StandardFeed::networkError() const { return m_networkError; } -Feed::Feed(const QSqlRecord &record) : RootItem(NULL) { +StandardFeed::StandardFeed(const QSqlRecord &record) : RootItem(NULL) { m_kind = RootItem::Feeed; setTitle(record.value(FDS_DB_TITLE_INDEX).toString()); @@ -723,7 +723,7 @@ Feed::Feed(const QSqlRecord &record) : RootItem(NULL) { setPasswordProtected(record.value(FDS_DB_PROTECTED_INDEX).toBool()); setUsername(record.value(FDS_DB_USERNAME_INDEX).toString()); setPassword(TextFactory::decrypt(record.value(FDS_DB_PASSWORD_INDEX).toString())); - setAutoUpdateType(static_cast(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt())); + setAutoUpdateType(static_cast(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt())); setAutoUpdateInitialInterval(record.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt()); updateCounts(); } diff --git a/src/core/feed.h b/src/services/standard/standardfeed.h old mode 100644 new mode 100755 similarity index 89% rename from src/core/feed.h rename to src/services/standard/standardfeed.h index 68df38152..d3d23b3cc --- a/src/core/feed.h +++ b/src/services/standard/standardfeed.h @@ -33,7 +33,7 @@ class FeedsModel; // Represents BASE class for feeds contained in FeedsModel. // NOTE: This class should be derived to create PARTICULAR feed types. -class Feed : public RootItem { +class StandardFeed : public RootItem { Q_DECLARE_TR_FUNCTIONS(Feed) public: @@ -63,10 +63,10 @@ class Feed : public RootItem { }; // Constructors and destructors. - explicit Feed(RootItem *parent_item = NULL); - explicit Feed(const Feed &other); - explicit Feed(const QSqlRecord &record); - virtual ~Feed(); + explicit StandardFeed(RootItem *parent_item = NULL); + explicit StandardFeed(const StandardFeed &other); + explicit StandardFeed(const QSqlRecord &record); + virtual ~StandardFeed(); // Returns 0, feeds have no children. int childCount() const; @@ -87,7 +87,7 @@ class Feed : public RootItem { // storage. bool removeItself(); bool addItself(RootItem *parent); - bool editItself(Feed *new_feed_data); + bool editItself(StandardFeed *new_feed_data); // Other getters/setters. inline Type type() const { @@ -180,7 +180,7 @@ class Feed : public RootItem { // Returns pointer to guessed feed (if at least partially // guessed) and retrieved error/status code from network layer // or NULL feed. - static QPair guessFeed(const QString &url, const QString &username, const QString &password); + static QPair guessFeed(const QString &url, const QString &username, const QString &password); // Converts particular feed type to string. static QString typeToString(Type type); @@ -219,6 +219,6 @@ class Feed : public RootItem { QString m_url; }; -Q_DECLARE_METATYPE(Feed::Type) +Q_DECLARE_METATYPE(StandardFeed::Type) #endif // FEEDSMODELFEED_H diff --git a/src/core/feedsimportexportmodel.cpp b/src/services/standard/standardfeedsimportexportmodel.cpp old mode 100644 new mode 100755 similarity index 95% rename from src/core/feedsimportexportmodel.cpp rename to src/services/standard/standardfeedsimportexportmodel.cpp index b73d9a1c9..96c01a16f --- a/src/core/feedsimportexportmodel.cpp +++ b/src/services/standard/standardfeedsimportexportmodel.cpp @@ -15,10 +15,10 @@ // You should have received a copy of the GNU General Public License // along with RSS Guard. If not, see . -#include "core/feedsimportexportmodel.h" +#include "services/standard/standardfeedsimportexportmodel.h" -#include "core/feed.h" -#include "core/category.h" +#include "services/standard/standardfeed.h" +#include "services/standard/standardcategory.h" #include "definitions/definitions.h" #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" @@ -111,7 +111,7 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray &result) { } case RootItem::Feeed: { - Feed *child_feed = child_item->toFeed(); + StandardFeed *child_feed = child_item->toFeed(); QDomElement outline_feed = opml_document.createElement("outline"); outline_feed.setAttribute(QSL("text"), child_feed->title()); outline_feed.setAttribute(QSL("xmlUrl"), child_feed->url()); @@ -121,16 +121,16 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray &result) { outline_feed.setAttribute(QSL("rssguard:icon"), QString(qApp->icons()->toByteArray(child_feed->icon()))); switch (child_feed->type()) { - case Feed::Rss0X: - case Feed::Rss2X: + case StandardFeed::Rss0X: + case StandardFeed::Rss2X: outline_feed.setAttribute(QSL("version"), QSL("RSS")); break; - case Feed::Rdf: + case StandardFeed::Rdf: outline_feed.setAttribute(QSL("version"), QSL("RSS1")); break; - case Feed::Atom10: + case StandardFeed::Atom10: outline_feed.setAttribute(QSL("version"), QSL("ATOM")); break; @@ -192,23 +192,23 @@ bool FeedsImportExportModel::importAsOPML20(const QByteArray &data) { QString feed_description = child_element.attribute(QSL("description")); QIcon feed_icon = qApp->icons()->fromByteArray(child_element.attribute(QSL("rssguard:icon")).toLocal8Bit()); - Feed *new_feed = new Feed(active_model_item); + StandardFeed *new_feed = new StandardFeed(active_model_item); new_feed->setTitle(feed_title); new_feed->setDescription(feed_description); new_feed->setEncoding(feed_encoding); new_feed->setUrl(feed_url); new_feed->setCreationDate(QDateTime::currentDateTime()); new_feed->setIcon(feed_icon.isNull() ? qApp->icons()->fromTheme(QSL("folder-feed")) : feed_icon); - new_feed->setAutoUpdateType(Feed::DefaultAutoUpdate); + new_feed->setAutoUpdateType(StandardFeed::DefaultAutoUpdate); if (feed_type == QL1S("RSS1")) { - new_feed->setType(Feed::Rdf); + new_feed->setType(StandardFeed::Rdf); } else if (feed_type == QL1S("ATOM")) { - new_feed->setType(Feed::Atom10); + new_feed->setType(StandardFeed::Atom10); } else { - new_feed->setType(Feed::Rss2X); + new_feed->setType(StandardFeed::Rss2X); } active_model_item->appendChild(new_feed); @@ -230,7 +230,7 @@ bool FeedsImportExportModel::importAsOPML20(const QByteArray &data) { } } - Category *new_category = new Category(active_model_item); + StandardCategory *new_category = new StandardCategory(active_model_item); new_category->setTitle(category_title); new_category->setIcon(category_icon.isNull() ? qApp->icons()->fromTheme(QSL("folder-category")) : category_icon); new_category->setCreationDate(QDateTime::currentDateTime()); diff --git a/src/core/feedsimportexportmodel.h b/src/services/standard/standardfeedsimportexportmodel.h old mode 100644 new mode 100755 similarity index 100% rename from src/core/feedsimportexportmodel.h rename to src/services/standard/standardfeedsimportexportmodel.h From 6e22510e7c2626336895ffc47d575623e77bc492 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 30 Oct 2015 08:32:02 +0100 Subject: [PATCH 002/203] Some beginning work, created some service entry points. --- CMakeLists.txt | 8 +++ src/core/rootitem.h | 1 - src/gui/feedmessageviewer.cpp | 2 +- src/miscellaneous/application.cpp | 16 ++++- src/miscellaneous/application.h | 4 ++ src/services/abstract/feed.cpp | 25 +++++++ src/services/abstract/feed.h | 30 ++++++++ src/services/abstract/serviceentrypoint.cpp | 25 +++++++ src/services/abstract/serviceentrypoint.h | 72 +++++++++++++++++++ src/services/abstract/serviceroot.cpp | 26 +++++++ src/services/abstract/serviceroot.h | 29 ++++++++ src/services/standard/standardfeed.h | 2 +- .../standard/standardserviceentrypoint.cpp | 69 ++++++++++++++++++ .../standard/standardserviceentrypoint.h | 41 +++++++++++ .../tt-rss/ttrssserviceentrypoint.cpp | 70 ++++++++++++++++++ src/services/tt-rss/ttrssserviceentrypoint.h | 42 +++++++++++ 16 files changed, 458 insertions(+), 4 deletions(-) create mode 100755 src/services/abstract/feed.cpp create mode 100755 src/services/abstract/feed.h create mode 100755 src/services/abstract/serviceentrypoint.cpp create mode 100755 src/services/abstract/serviceentrypoint.h create mode 100755 src/services/abstract/serviceroot.cpp create mode 100755 src/services/abstract/serviceroot.h create mode 100755 src/services/standard/standardserviceentrypoint.cpp create mode 100755 src/services/standard/standardserviceentrypoint.h create mode 100755 src/services/tt-rss/ttrssserviceentrypoint.cpp create mode 100755 src/services/tt-rss/ttrssserviceentrypoint.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d5e9a949e..fe4915afa 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -415,6 +415,10 @@ set(APP_SOURCES src/core/recyclebin.cpp src/core/feedsselection.cpp + # ABSTRACT service sources. + src/services/abstract/serviceentrypoint.cpp + src/services/abstract/serviceroot.cpp + # STANDARD feed service sources. src/services/standard/standardfeed.cpp src/services/standard/standardfeedsimportexportmodel.cpp @@ -422,6 +426,10 @@ set(APP_SOURCES src/services/standard/gui/formstandardcategorydetails.cpp src/services/standard/gui/formstandardfeeddetails.cpp src/services/standard/gui/formstandardimportexport.cpp + src/services/standard/standardserviceentrypoint.cpp + + # TT-RSS feed service sources. + src/services/tt-rss/ttrssserviceentrypoint.cpp # NETWORK-WEB sources. src/network-web/basenetworkaccessmanager.cpp diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 964fa6122..b54cd6616 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -19,7 +19,6 @@ #define ROOTITEM_H #include - #include #include diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index cbc77346b..922dd667e 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -561,7 +561,7 @@ void FeedMessageViewer::updateFeeds(QList feeds) { m_feedDownloaderThread = new QThread(); // Downloader setup. - qRegisterMetaType >("QList"); + qRegisterMetaType >("QList"); m_feedDownloader->moveToThread(m_feedDownloaderThread); connect(this, SIGNAL(feedsUpdateRequested(QList)), m_feedDownloader, SLOT(updateFeeds(QList))); diff --git a/src/miscellaneous/application.cpp b/src/miscellaneous/application.cpp index 669a52653..e4f7190ca 100755 --- a/src/miscellaneous/application.cpp +++ b/src/miscellaneous/application.cpp @@ -28,6 +28,9 @@ #include "exceptions/applicationexception.h" #include "adblock/adblockmanager.h" +#include "services/standard/standardserviceentrypoint.h" +#include "services/tt-rss/ttrssserviceentrypoint.h" + #include #include #include @@ -35,7 +38,7 @@ Application::Application(const QString &id, int &argc, char **argv) : QtSingleApplication(id, argc, argv), - m_updateFeedsLock(NULL), m_userActions(QList()), m_mainForm(NULL), + m_updateFeedsLock(NULL), m_feedServices(QList()), m_userActions(QList()), m_mainForm(NULL), m_trayIcon(NULL), m_settings(NULL), m_system(NULL), m_skins(NULL), m_localization(NULL), m_icons(NULL), m_database(NULL), m_downloadManager(NULL), m_shouldRestart(false), m_notification(NULL) { @@ -46,6 +49,17 @@ Application::Application(const QString &id, int &argc, char **argv) Application::~Application() { delete m_updateFeedsLock; + qDeleteAll(m_feedServices); +} + +QList Application::feedServices() { + if (m_feedServices.isEmpty()) { + // NOTE: All installed services create their entry points here. + m_feedServices.append(new StandardServiceEntryPoint()); + m_feedServices.append(new TtRssServiceEntryPoint()); + } + + return m_feedServices; } QList Application::userActions() { diff --git a/src/miscellaneous/application.h b/src/miscellaneous/application.h index d8930ee0b..d23a7a847 100755 --- a/src/miscellaneous/application.h +++ b/src/miscellaneous/application.h @@ -30,6 +30,7 @@ #include "gui/systemtrayicon.h" #include "gui/notifications/notification.h" #include "network-web/downloadmanager.h" +#include "services/abstract/serviceentrypoint.h" #include @@ -54,6 +55,8 @@ class Application : public QtSingleApplication { explicit Application(const QString &id, int &argc, char **argv); virtual ~Application(); + QList feedServices(); + QList userActions(); inline SystemFactory *system() { @@ -183,6 +186,7 @@ class Application : public QtSingleApplication { // tries to lock the lock for writing), then no other // action will be allowed to lock for reading. Mutex *m_updateFeedsLock; + QList m_feedServices; QList m_userActions; FormMain *m_mainForm; SystemTrayIcon *m_trayIcon; diff --git a/src/services/abstract/feed.cpp b/src/services/abstract/feed.cpp new file mode 100755 index 000000000..7436aa231 --- /dev/null +++ b/src/services/abstract/feed.cpp @@ -0,0 +1,25 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#include "services/abstract/feed.h" + + +Feed::Feed() { +} + +Feed::~Feed() { +} diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h new file mode 100755 index 000000000..93b945a67 --- /dev/null +++ b/src/services/abstract/feed.h @@ -0,0 +1,30 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#ifndef FEED_H +#define FEED_H + +#include "core/rootitem.h" + + +class Feed : public RootItem { + public: + explicit Feed(); + virtual ~Feed(); +}; + +#endif // FEED_H diff --git a/src/services/abstract/serviceentrypoint.cpp b/src/services/abstract/serviceentrypoint.cpp new file mode 100755 index 000000000..a368e207c --- /dev/null +++ b/src/services/abstract/serviceentrypoint.cpp @@ -0,0 +1,25 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#include "services/abstract/serviceentrypoint.h" + + +ServiceEntryPoint::ServiceEntryPoint() { +} + +ServiceEntryPoint::~ServiceEntryPoint() { +} diff --git a/src/services/abstract/serviceentrypoint.h b/src/services/abstract/serviceentrypoint.h new file mode 100755 index 000000000..f8b16b7f1 --- /dev/null +++ b/src/services/abstract/serviceentrypoint.h @@ -0,0 +1,72 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#ifndef SERVICE_H +#define SERVICE_H + +#include +#include +#include + + +// TOP LEVEL class which provides basic information about the "service" +class ServiceEntryPoint { + public: + // Constructors. + explicit ServiceEntryPoint(); + virtual ~ServiceEntryPoint(); + + // Must this service account be activated by default? + // NOTE: This is true particularly for "standard" service + // which operates with normal RSS/ATOM feeds. + virtual bool isDefaultService() = 0; + + // Can this service account be added just once? + // NOTE: This is true particularly for "standard" service + // which operates with normal RSS/ATOM feeds. + virtual bool isSingleInstanceService() = 0; + + // Can this service account be added by user via GUI? + // NOTE: This is true particularly for "standard" service + // which operates with normal RSS/ATOM feeds. + virtual bool canBeAdded() = 0; + + // Can this service account by deleted by user via GUI? + // NOTE: This is false particularly for "standard" service + // which operates with normal RSS/ATOM feeds. + virtual bool canBeDeleted() = 0; + + // Can properties of this service account be edited by user via GUI? + virtual bool canBeEdited() = 0; + + // Human readable service name, for example "TT-RSS". + virtual QString name() = 0; + + // Human readable service description, for example "Services which offers TT-RSS integration.". + virtual QString description() = 0; + + // Version of the service, using of semantic versioning is recommended. + virtual QString version() = 0; + + // Author of the service. + virtual QString author() = 0; + + // Icon of the service. + virtual QIcon icon() = 0; +}; + +#endif // SERVICE_H diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp new file mode 100755 index 000000000..0d437c68c --- /dev/null +++ b/src/services/abstract/serviceroot.cpp @@ -0,0 +1,26 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#include "services/abstract/serviceroot.h" + + +ServiceRoot::ServiceRoot() { +} + +ServiceRoot::~ServiceRoot() { +} + diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h new file mode 100755 index 000000000..41b318e60 --- /dev/null +++ b/src/services/abstract/serviceroot.h @@ -0,0 +1,29 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#ifndef SERVICEROOT_H +#define SERVICEROOT_H + +// THIS IS the root node of the service. +// TODO: Inherit proper base root class for this. +class ServiceRoot { + public: + explicit ServiceRoot(); + virtual ~ServiceRoot(); +}; + +#endif // SERVICEROOT_H diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index d3d23b3cc..41dfeec43 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -34,7 +34,7 @@ class FeedsModel; // Represents BASE class for feeds contained in FeedsModel. // NOTE: This class should be derived to create PARTICULAR feed types. class StandardFeed : public RootItem { - Q_DECLARE_TR_FUNCTIONS(Feed) + Q_DECLARE_TR_FUNCTIONS(StandardFeed) public: // Describes possible types of feeds. diff --git a/src/services/standard/standardserviceentrypoint.cpp b/src/services/standard/standardserviceentrypoint.cpp new file mode 100755 index 000000000..62d5fc901 --- /dev/null +++ b/src/services/standard/standardserviceentrypoint.cpp @@ -0,0 +1,69 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + + +#include "services/standard/standardserviceentrypoint.h" + +#include "definitions/definitions.h" +#include "miscellaneous/application.h" + + +StandardServiceEntryPoint::StandardServiceEntryPoint() { +} + +StandardServiceEntryPoint::~StandardServiceEntryPoint() { +} + +bool StandardServiceEntryPoint::isDefaultService() { + return true; +} + +bool StandardServiceEntryPoint::isSingleInstanceService() { + return true; +} + +bool StandardServiceEntryPoint::canBeAdded() { + return false; +} + +bool StandardServiceEntryPoint::canBeDeleted() { + return false; +} + +bool StandardServiceEntryPoint::canBeEdited() { + return false; +} + +QString StandardServiceEntryPoint::name() { + return QSL("Standard (RSS/RDF/ATOM)"); +} + +QString StandardServiceEntryPoint::description() { + return QSL("This service offers integration with standard online RSS/RDF/ATOM feeds and podcasts."); +} + +QString StandardServiceEntryPoint::version() { + return APP_VERSION; +} + +QString StandardServiceEntryPoint::author() { + return APP_AUTHOR; +} + +QIcon StandardServiceEntryPoint::icon() { + return QIcon(APP_ICON_PATH); +} diff --git a/src/services/standard/standardserviceentrypoint.h b/src/services/standard/standardserviceentrypoint.h new file mode 100755 index 000000000..1aef07b39 --- /dev/null +++ b/src/services/standard/standardserviceentrypoint.h @@ -0,0 +1,41 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#ifndef STANDARDSERVICEENTRYPOINT_H +#define STANDARDSERVICEENTRYPOINT_H + +#include "services/abstract/serviceentrypoint.h" + + +class StandardServiceEntryPoint : public ServiceEntryPoint { + public: + explicit StandardServiceEntryPoint(); + virtual ~StandardServiceEntryPoint(); + + bool isDefaultService(); + bool isSingleInstanceService(); + bool canBeAdded(); + bool canBeDeleted(); + bool canBeEdited(); + QString name(); + QString description(); + QString version(); + QString author(); + QIcon icon(); +}; + +#endif // STANDARDSERVICEENTRYPOINT_H diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp new file mode 100755 index 000000000..d1fc413da --- /dev/null +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -0,0 +1,70 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#include "services/tt-rss/ttrssserviceentrypoint.h" + +#include "definitions/definitions.h" +#include "miscellaneous/application.h" + + +TtRssServiceEntryPoint::TtRssServiceEntryPoint(){ +} + + +TtRssServiceEntryPoint::~TtRssServiceEntryPoint() { + +} + +bool TtRssServiceEntryPoint::isDefaultService() { + return false; +} + +bool TtRssServiceEntryPoint::isSingleInstanceService() { + return false; +} + +bool TtRssServiceEntryPoint::canBeAdded() { + return true; +} + +bool TtRssServiceEntryPoint::canBeDeleted() { + return true; +} + +bool TtRssServiceEntryPoint::canBeEdited() { + return true; +} + +QString TtRssServiceEntryPoint::name() { + return QSL("TT-RSS (TinyTiny RSS)"); +} + +QString TtRssServiceEntryPoint::description() { + return QSL("This service offers integration with TinyTiny RSS."); +} + +QString TtRssServiceEntryPoint::version() { + return QSL("0.0.1"); +} + +QString TtRssServiceEntryPoint::author() { + return APP_AUTHOR; +} + +QIcon TtRssServiceEntryPoint::icon() { + return QIcon(APP_ICON_PATH); +} diff --git a/src/services/tt-rss/ttrssserviceentrypoint.h b/src/services/tt-rss/ttrssserviceentrypoint.h new file mode 100755 index 000000000..5294af5ad --- /dev/null +++ b/src/services/tt-rss/ttrssserviceentrypoint.h @@ -0,0 +1,42 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + + +#ifndef TTRSSSERVICEENTRYPOINT_H +#define TTRSSSERVICEENTRYPOINT_H + +#include "services/abstract/serviceentrypoint.h" + + +class TtRssServiceEntryPoint : public ServiceEntryPoint { + public: + explicit TtRssServiceEntryPoint(); + virtual ~TtRssServiceEntryPoint(); + + bool isDefaultService(); + bool isSingleInstanceService(); + bool canBeAdded(); + bool canBeDeleted(); + bool canBeEdited(); + QString name(); + QString description(); + QString version(); + QString author(); + QIcon icon(); +}; + +#endif // TTRSSSERVICEENTRYPOINT_H From fd94a1bd8f34179c74b6381015623e2a7a1d470d Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 30 Oct 2015 10:47:43 +0100 Subject: [PATCH 003/203] Work is ongoing - refactored some of "edit" methods. Very sloppy, though. --- CMakeLists.txt | 1 + src/core/feeddownloader.cpp | 4 +- src/core/feeddownloader.h | 6 +- src/core/feedsmodel.cpp | 41 +++++------ src/core/feedsmodel.h | 24 +++---- src/core/rootitem.h | 11 +++ src/gui/dialogs/formmain.ui | 6 +- src/gui/feedmessageviewer.cpp | 12 ++-- src/gui/feedmessageviewer.h | 6 +- src/gui/feedsview.cpp | 57 ++++++--------- src/gui/feedsview.h | 14 ++-- src/services/abstract/feed.cpp | 13 +++- src/services/abstract/feed.h | 70 +++++++++++++++++- src/services/standard/standardcategory.cpp | 15 ++++ src/services/standard/standardcategory.h | 10 +++ src/services/standard/standardfeed.cpp | 29 ++++---- src/services/standard/standardfeed.h | 82 +++++----------------- 17 files changed, 229 insertions(+), 172 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fe4915afa..a41b733be 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -417,6 +417,7 @@ set(APP_SOURCES # ABSTRACT service sources. src/services/abstract/serviceentrypoint.cpp + src/services/abstract/feed.cpp src/services/abstract/serviceroot.cpp # STANDARD feed service sources. diff --git a/src/core/feeddownloader.cpp b/src/core/feeddownloader.cpp index 8afef756c..505c947e6 100755 --- a/src/core/feeddownloader.cpp +++ b/src/core/feeddownloader.cpp @@ -17,7 +17,7 @@ #include "core/feeddownloader.h" -#include "services/standard/standardfeed.h" +#include "services/abstract/feed.h" #include "definitions/definitions.h" #include @@ -32,7 +32,7 @@ FeedDownloader::~FeedDownloader() { qDebug("Destroying FeedDownloader instance."); } -void FeedDownloader::updateFeeds(const QList &feeds) { +void FeedDownloader::updateFeeds(const QList &feeds) { qDebug().nospace() << "Performing feed updates in thread: \'" << QThread::currentThreadId() << "\'."; // Job starts now. diff --git a/src/core/feeddownloader.h b/src/core/feeddownloader.h index eab2aac2e..88f8992b7 100755 --- a/src/core/feeddownloader.h +++ b/src/core/feeddownloader.h @@ -23,7 +23,7 @@ #include -class StandardFeed; +class Feed; // Represents results of batch feed updates. struct FeedDownloadResults { @@ -55,7 +55,7 @@ class FeedDownloader : public QObject { // New messages are downloaded for each feed and they // are stored persistently in the database. // Appropriate signals are emitted. - void updateFeeds(const QList &feeds); + void updateFeeds(const QList &feeds); signals: // Emitted if feed updates started. @@ -69,7 +69,7 @@ class FeedDownloader : public QObject { // "Current" number indicates count of processed feeds // and "total" number indicates total number of feeds // which were in the initial queue. - void progress(StandardFeed *feed, int current, int total); + void progress(Feed *feed, int current, int total); }; #endif // FEEDDOWNLOADER_H diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 7dad793e8..ac4905a2b 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -18,8 +18,9 @@ #include "core/feedsmodel.h" #include "definitions/definitions.h" -#include "services/standard/standardcategory.h" +#include "services/abstract/feed.h" #include "services/standard/standardfeed.h" +#include "services/standard/standardcategory.h" #include "services/standard/standardfeedsimportexportmodel.h" #include "core/recyclebin.h" #include "miscellaneous/textfactory.h" @@ -100,7 +101,7 @@ void FeedsModel::executeNextAutoUpdate() { // Pass needed interval data and lets the model decide which feeds // should be updated in this pass. - QList feeds_for_update = feedsForScheduledUpdate(m_globalAutoUpdateEnabled && m_globalAutoUpdateRemainingInterval == 0); + QList feeds_for_update = feedsForScheduledUpdate(m_globalAutoUpdateEnabled && m_globalAutoUpdateRemainingInterval == 0); qApp->feedUpdateLock()->unlock(); @@ -432,10 +433,10 @@ bool FeedsModel::editFeed(StandardFeed *original_feed, StandardFeed *new_feed_da return result; } -QList FeedsModel::feedsForScheduledUpdate(bool auto_update_now) { - QList feeds_for_update; +QList FeedsModel::feedsForScheduledUpdate(bool auto_update_now) { + QList feeds_for_update; - foreach (StandardFeed *feed, allFeeds()) { + foreach (Feed *feed, allFeeds()) { switch (feed->autoUpdateType()) { case StandardFeed::DontAutoUpdate: // Do not auto-update this feed ever. @@ -471,7 +472,7 @@ QList FeedsModel::feedsForScheduledUpdate(bool auto_update_now) { return feeds_for_update; } -QList FeedsModel::messagesForFeeds(const QList &feeds) { +QList FeedsModel::messagesForFeeds(const QList &feeds) { QList messages; QSqlDatabase database = qApp->database()->connection(objectName(), @@ -482,7 +483,7 @@ QList FeedsModel::messagesForFeeds(const QList &feeds) { "FROM Messages " "WHERE is_deleted = 0 AND feed = :feed;"); - foreach (StandardFeed *feed, feeds) { + foreach (Feed *feed, feeds) { query_read_msg.bindValue(QSL(":feed"), feed->id()); if (query_read_msg.exec()) { @@ -567,7 +568,7 @@ QModelIndex FeedsModel::indexForItem(RootItem *item) const { } bool FeedsModel::hasAnyFeedNewMessages() { - foreach (const StandardFeed *feed, allFeeds()) { + foreach (const Feed *feed, allFeeds()) { if (feed->status() == StandardFeed::NewMessages) { return true; } @@ -664,11 +665,11 @@ void FeedsModel::reloadChangedLayout(QModelIndexList list) { } } -QStringList FeedsModel::textualFeedIds(const QList &feeds) { +QStringList FeedsModel::textualFeedIds(const QList &feeds) { QStringList stringy_ids; stringy_ids.reserve(feeds.size()); - foreach (StandardFeed *feed, feeds) { + foreach (Feed *feed, feeds) { stringy_ids.append(QString::number(feed->id())); } @@ -746,24 +747,24 @@ void FeedsModel::loadFromDatabase() { m_rootItem->appendChild(m_recycleBin); } -QList FeedsModel::feedsForIndex(const QModelIndex &index) { +QList FeedsModel::feedsForIndex(const QModelIndex &index) { RootItem *item = itemForIndex(index); return feedsForItem(item); } -StandardFeed *FeedsModel::feedForIndex(const QModelIndex &index) { +Feed *FeedsModel::feedForIndex(const QModelIndex &index) { RootItem *item = itemForIndex(index); if (item->kind() == RootItem::Feeed) { - return item->toFeed(); + return static_cast(item); } else { return NULL; } } -QList FeedsModel::feedsForIndexes(const QModelIndexList &indexes) { - QList feeds; +QList FeedsModel::feedsForIndexes(const QModelIndexList &indexes) { + QList feeds; // Get selected feeds for each index. foreach (const QModelIndex &index, indexes) { @@ -782,7 +783,7 @@ QList FeedsModel::feedsForIndexes(const QModelIndexList &indexes) return feeds; } -bool FeedsModel::markFeedsRead(const QList &feeds, int read) { +bool FeedsModel::markFeedsRead(const QList &feeds, int read) { QSqlDatabase db_handle = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings); if (!db_handle.transaction()) { @@ -817,7 +818,7 @@ bool FeedsModel::markFeedsRead(const QList &feeds, int read) { } } -bool FeedsModel::markFeedsDeleted(const QList &feeds, int deleted, bool read_only) { +bool FeedsModel::markFeedsDeleted(const QList &feeds, int deleted, bool read_only) { QSqlDatabase db_handle = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings); if (!db_handle.transaction()) { @@ -893,13 +894,13 @@ QHash FeedsModel::categoriesForItem(RootItem *root) { return categories; } -QList FeedsModel::allFeeds() { +QList FeedsModel::allFeeds() { return feedsForItem(m_rootItem); } -QList FeedsModel::feedsForItem(RootItem *root) { +QList FeedsModel::feedsForItem(RootItem *root) { QList children = root->getRecursiveChildren(); - QList feeds; + QList feeds; foreach (RootItem *child, children) { if (child->kind() == RootItem::Feeed) { diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index ad029b443..98ea28b7d 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -27,7 +27,7 @@ class StandardCategory; -class StandardFeed; +class Feed; class RecycleBin; class FeedsImportExportModel; class QTimer; @@ -95,12 +95,12 @@ class FeedsModel : public QAbstractItemModel { // Variable "auto_update_now" is true, when global timeout // for scheduled auto-update was met and global auto-update strategy is enabled // so feeds with "default" auto-update strategy should be updated. - QList feedsForScheduledUpdate(bool auto_update_now); + QList feedsForScheduledUpdate(bool auto_update_now); // Returns (undeleted) messages for given feeds. // This is usually used for displaying whole feeds // in "newspaper" mode. - QList messagesForFeeds(const QList &feeds); + QList messagesForFeeds(const QList &feeds); // Returns all categories, each pair // consists of ID of parent item and pointer to category. @@ -111,21 +111,21 @@ class FeedsModel : public QAbstractItemModel { QHash categoriesForItem(RootItem *root); // Returns list of all feeds contained in the model. - QList allFeeds(); + QList allFeeds(); // Get list of feeds from tree with particular item // as root. If root itself is a feed, then it is returned. - QList feedsForItem(RootItem *root); + QList feedsForItem(RootItem *root); // Returns list of ALL CHILD feeds which belong to given parent indexes. - QList feedsForIndexes(const QModelIndexList &indexes); + QList feedsForIndexes(const QModelIndexList &indexes); // Returns ALL CHILD feeds contained within single index. - QList feedsForIndex(const QModelIndex &index); + QList feedsForIndex(const QModelIndex &index); // Returns pointer to feed if it lies on given index // or NULL if no feed lies on given index. - StandardFeed *feedForIndex(const QModelIndex &index); + Feed *feedForIndex(const QModelIndex &index); // Returns pointer to category if it lies on given index // or NULL if no category lies on given index. @@ -166,8 +166,8 @@ class FeedsModel : public QAbstractItemModel { public slots: // Feeds operations. - bool markFeedsRead(const QList &feeds, int read); - bool markFeedsDeleted(const QList &feeds, int deleted, bool read_only); + bool markFeedsRead(const QList &feeds, int read); + bool markFeedsDeleted(const QList &feeds, int deleted, bool read_only); // Signals that properties (probably counts) // of ALL items have changed. @@ -185,7 +185,7 @@ class FeedsModel : public QAbstractItemModel { protected: // Returns converted ids of given feeds // which are suitable as IN clause for SQL queries. - QStringList textualFeedIds(const QList &feeds); + QStringList textualFeedIds(const QList &feeds); // Loads feed/categories from the database. void loadFromDatabase(); @@ -199,7 +199,7 @@ class FeedsModel : public QAbstractItemModel { void requireItemValidationAfterDragDrop(const QModelIndex &source_index); // Emitted when model requests update of some feeds. - void feedsUpdateRequested(const QList feeds); + void feedsUpdateRequested(const QList feeds); private: RootItem *m_rootItem; diff --git a/src/core/rootitem.h b/src/core/rootitem.h index b54cd6616..96914ed7f 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -67,6 +67,17 @@ class RootItem { child->setParent(this); } + virtual bool canBeEdited() { + return false; + } + + virtual bool canBeDeleted() { + return false; + } + + virtual void edit() { + } + virtual int row() const; virtual QVariant data(int column, int role) const; diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index bca5de13f..f1179c599 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -691,17 +691,17 @@ - &Add new service + &Add new service account - &Delete selected service + &Delete selected service account - &Edit selected service + &Edit selected service account diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 922dd667e..0d2f93bc6 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -252,7 +252,7 @@ void FeedMessageViewer::onFeedUpdatesStarted() { qApp->mainForm()->statusBar()->showProgressFeeds(0, tr("Feed update started")); } -void FeedMessageViewer::onFeedUpdatesProgress(StandardFeed *feed, int current, int total) { +void FeedMessageViewer::onFeedUpdatesProgress(Feed *feed, int current, int total) { // Some feed got updated. m_feedsView->updateCountsOfParticularFeed(feed, true); qApp->mainForm()->statusBar()->showProgressFeeds((current * 100.0) / total, @@ -369,7 +369,7 @@ void FeedMessageViewer::createConnections() { form_main->m_ui->m_tabWidget, SLOT(addBrowserWithMessages(QList))); // Downloader connections. - connect(m_feedsView, SIGNAL(feedsUpdateRequested(QList)), this, SLOT(updateFeeds(QList))); + connect(m_feedsView, SIGNAL(feedsUpdateRequested(QList)), this, SLOT(updateFeeds(QList))); // Toolbar forwardings. connect(form_main->m_ui->m_actionCleanupDatabase, @@ -548,7 +548,7 @@ void FeedMessageViewer::refreshVisualProperties() { m_toolBarMessages->setToolButtonStyle(button_style); } -void FeedMessageViewer::updateFeeds(QList feeds) { +void FeedMessageViewer::updateFeeds(QList feeds) { if (!qApp->feedUpdateLock()->tryLock()) { qApp->showGuiMessage(tr("Cannot update all items"), tr("You cannot update all items because another another critical operation is ongoing."), @@ -561,14 +561,14 @@ void FeedMessageViewer::updateFeeds(QList feeds) { m_feedDownloaderThread = new QThread(); // Downloader setup. - qRegisterMetaType >("QList"); + qRegisterMetaType >("QList"); m_feedDownloader->moveToThread(m_feedDownloaderThread); - connect(this, SIGNAL(feedsUpdateRequested(QList)), m_feedDownloader, SLOT(updateFeeds(QList))); + connect(this, SIGNAL(feedsUpdateRequested(QList)), m_feedDownloader, SLOT(updateFeeds(QList))); connect(m_feedDownloaderThread, SIGNAL(finished()), m_feedDownloaderThread, SLOT(deleteLater())); connect(m_feedDownloader, SIGNAL(finished(FeedDownloadResults)), this, SLOT(onFeedUpdatesFinished(FeedDownloadResults))); connect(m_feedDownloader, SIGNAL(started()), this, SLOT(onFeedUpdatesStarted())); - connect(m_feedDownloader, SIGNAL(progress(StandardFeed*,int,int)), this, SLOT(onFeedUpdatesProgress(StandardFeed*,int,int))); + connect(m_feedDownloader, SIGNAL(progress(Feed*,int,int)), this, SLOT(onFeedUpdatesProgress(Feed*,int,int))); // Connections are made, start the feed downloader thread. m_feedDownloaderThread->start(); diff --git a/src/gui/feedmessageviewer.h b/src/gui/feedmessageviewer.h index 8c087427f..22020203d 100755 --- a/src/gui/feedmessageviewer.h +++ b/src/gui/feedmessageviewer.h @@ -103,7 +103,7 @@ class FeedMessageViewer : public TabContent { // Reloads some changeable visual settings. void refreshVisualProperties(); - void updateFeeds(QList feeds); + void updateFeeds(QList feeds); private slots: // Updates counts of messages for example in tray icon. @@ -111,7 +111,7 @@ class FeedMessageViewer : public TabContent { // Reacts on feed updates. void onFeedUpdatesStarted(); - void onFeedUpdatesProgress(StandardFeed *feed, int current, int total); + void onFeedUpdatesProgress(Feed *feed, int current, int total); void onFeedUpdatesFinished(FeedDownloadResults results); // Switches visibility of feed list and related @@ -135,7 +135,7 @@ class FeedMessageViewer : public TabContent { signals: // Emitted if user/application requested updating of some feeds. - void feedsUpdateRequested(const QList feeds); + void feedsUpdateRequested(const QList feeds); private: bool m_toolBarsEnabled; diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 0c01a9698..cba9fa970 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -22,15 +22,15 @@ #include "core/feedsproxymodel.h" #include "core/rootitem.h" #include "core/recyclebin.h" -#include "services/standard/standardcategory.h" -#include "services/standard/standardfeed.h" -#include "services/standard/standardfeed.h" #include "miscellaneous/systemfactory.h" #include "miscellaneous/mutex.h" #include "gui/systemtrayicon.h" #include "gui/messagebox.h" #include "gui/styleditemdelegatewithoutfocus.h" #include "gui/dialogs/formmain.h" +#include "services/abstract/feed.h" +#include "services/standard/standardcategory.h" +#include "services/standard/standardfeed.h" #include "services/standard/gui/formstandardcategorydetails.h" #include "services/standard/gui/formstandardfeeddetails.h" @@ -56,7 +56,7 @@ FeedsView::FeedsView(QWidget *parent) // Connections. connect(m_sourceModel, SIGNAL(requireItemValidationAfterDragDrop(QModelIndex)), this, SLOT(validateItemAfterDragDrop(QModelIndex))); - connect(m_sourceModel, SIGNAL(feedsUpdateRequested(QList)), this, SIGNAL(feedsUpdateRequested(QList))); + connect(m_sourceModel, SIGNAL(feedsUpdateRequested(QList)), this, SIGNAL(feedsUpdateRequested(QList))); connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder))); setModel(m_proxyModel); @@ -73,18 +73,18 @@ void FeedsView::setSortingEnabled(bool enable) { connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder))); } -QList FeedsView::selectedFeeds() const { +QList FeedsView::selectedFeeds() const { QModelIndex current_index = currentIndex(); if (current_index.isValid()) { return m_sourceModel->feedsForIndex(m_proxyModel->mapToSource(current_index)); } else { - return QList(); + return QList(); } } -QList FeedsView::allFeeds() const { +QList FeedsView::allFeeds() const { return m_sourceModel->allFeeds(); } @@ -104,7 +104,7 @@ StandardCategory *FeedsView::selectedCategory() const { return m_sourceModel->categoryForIndex(current_mapped); } -StandardFeed *FeedsView::selectedFeed() const { +Feed *FeedsView::selectedFeed() const { QModelIndex current_mapped = m_proxyModel->mapToSource(currentIndex()); return m_sourceModel->feedForIndex(current_mapped); } @@ -214,14 +214,6 @@ void FeedsView::addNewCategory() { qApp->feedUpdateLock()->unlock(); } -void FeedsView::editCategory(StandardCategory *category) { - QPointer form_pointer = new FormStandardCategoryDetails(m_sourceModel, this); - - form_pointer.data()->exec(category, NULL); - - delete form_pointer.data(); -} - void FeedsView::addNewFeed() { if (!qApp->feedUpdateLock()->tryLock()) { // Lock was not obtained because @@ -243,14 +235,6 @@ void FeedsView::addNewFeed() { qApp->feedUpdateLock()->unlock(); } -void FeedsView::editFeed(StandardFeed *feed) { - QPointer form_pointer = new FormStandardFeedDetails(m_sourceModel, this); - - form_pointer.data()->exec(feed, NULL); - - delete form_pointer.data(); -} - void FeedsView::receiveMessageCountsChange(FeedsSelection::SelectionMode mode, bool total_msg_count_changed, bool any_msg_restored) { @@ -297,19 +281,19 @@ void FeedsView::editSelectedItem() { qApp->showGuiMessage(tr("Cannot edit item"), tr("Selected item cannot be edited because another critical operation is ongoing."), QSystemTrayIcon::Warning, qApp->mainForm(), true); - // Thus, cannot delete and quit the method. return; } - StandardCategory *category; - StandardFeed *feed; - - if ((category = selectedCategory()) != NULL) { - editCategory(category); + if (selectedItem()->canBeEdited()) { + selectedItem()->edit(); } - else if ((feed = selectedFeed()) != NULL) { - editFeed(feed); + else { + qApp->showGuiMessage(tr("Cannot edit item"), + tr("Selected item cannot be edited, this is not (yet?) supported."), + QSystemTrayIcon::Warning, + qApp->mainForm(), + true); } // Changes are done, unlock the update master lock. @@ -388,7 +372,8 @@ void FeedsView::markAllFeedsRead() { } void FeedsView::fetchMetadataForSelectedFeed() { - StandardFeed *selected_feed = selectedFeed(); + // TODO: fix + StandardFeed *selected_feed = (StandardFeed*) selectedFeed(); if (selected_feed != NULL) { selected_feed->fetchMetadataForItself(); @@ -429,7 +414,7 @@ void FeedsView::restoreRecycleBin() { } void FeedsView::updateCountsOfSelectedFeeds(bool update_total_too) { - foreach (StandardFeed *feed, selectedFeeds()) { + foreach (Feed *feed, selectedFeeds()) { feed->updateCounts(update_total_too); } @@ -455,7 +440,7 @@ void FeedsView::updateCountsOfRecycleBin(bool update_total_too) { } void FeedsView::updateCountsOfAllFeeds(bool update_total_too) { - foreach (StandardFeed *feed, allFeeds()) { + foreach (Feed *feed, allFeeds()) { feed->updateCounts(update_total_too); } @@ -469,7 +454,7 @@ void FeedsView::updateCountsOfAllFeeds(bool update_total_too) { notifyWithCounts(); } -void FeedsView::updateCountsOfParticularFeed(StandardFeed *feed, bool update_total_too) { +void FeedsView::updateCountsOfParticularFeed(Feed *feed, bool update_total_too) { QModelIndex index = m_sourceModel->indexForItem(feed); if (index.isValid()) { diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index 0a8615f94..26d47dc5e 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -28,7 +28,7 @@ class FeedsProxyModel; -class StandardFeed; +class Feed; class StandardCategory; class QTimer; @@ -53,14 +53,14 @@ class FeedsView : public QTreeView { // Returns list of selected/all feeds. // NOTE: This is recursive method which returns all descendants. - QList selectedFeeds() const; - QList allFeeds() const; + QList selectedFeeds() const; + QList allFeeds() const; // Returns pointers to selected feed/category if they are really // selected. RootItem *selectedItem() const; StandardCategory *selectedCategory() const; - StandardFeed *selectedFeed() const; + Feed *selectedFeed() const; RecycleBin *selectedRecycleBin() const; // Saves/loads expand states of all nodes (feeds/categories) of the list to/from settings. @@ -104,11 +104,9 @@ class FeedsView : public QTreeView { // Standard category manipulators. void addNewCategory(); - void editCategory(StandardCategory *category); // Standard feed manipulators. void addNewFeed(); - void editFeed(StandardFeed *feed); // Is called when counts of messages are changed externally, // typically from message view. @@ -124,7 +122,7 @@ class FeedsView : public QTreeView { void updateCountsOfAllFeeds(bool update_total_too); // Reloads counts for particular feed. - void updateCountsOfParticularFeed(StandardFeed *feed, bool update_total_too); + void updateCountsOfParticularFeed(Feed *feed, bool update_total_too); // Notifies other components about messages // counts. @@ -168,7 +166,7 @@ class FeedsView : public QTreeView { signals: // Emitted if user/application requested updating of some feeds. - void feedsUpdateRequested(const QList feeds); + void feedsUpdateRequested(const QList feeds); // Emitted if counts of messages are changed. void messageCountsChanged(int unread_messages, int total_messages, bool any_feed_has_unread_messages); diff --git a/src/services/abstract/feed.cpp b/src/services/abstract/feed.cpp index 7436aa231..b3d8c61e8 100755 --- a/src/services/abstract/feed.cpp +++ b/src/services/abstract/feed.cpp @@ -17,9 +17,20 @@ #include "services/abstract/feed.h" +#include "definitions/definitions.h" -Feed::Feed() { + +Feed::Feed(RootItem *parent) : RootItem(parent) { + m_status = Normal; + m_autoUpdateType = DontAutoUpdate; + m_autoUpdateInitialInterval = DEFAULT_AUTO_UPDATE_INTERVAL; + m_autoUpdateRemainingInterval = DEFAULT_AUTO_UPDATE_INTERVAL; } Feed::~Feed() { } + +int Feed::childCount() const { + // Because feed has no children. + return 0; +} diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index 93b945a67..df2b28776 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -21,10 +21,78 @@ #include "core/rootitem.h" +// Base class for "feed" nodes. class Feed : public RootItem { public: - explicit Feed(); + // Specifies the auto-update strategy for the feed. + enum AutoUpdateType { + DontAutoUpdate = 0, + DefaultAutoUpdate = 1, + SpecificAutoUpdate = 2 + }; + + // Specifies the actual "status" of the feed. + // For example if it has new messages, error + // occurred, and so on. + enum Status { + Normal = 0, + NewMessages = 1, + NetworkError = 2 + }; + + // Constructors. + explicit Feed(RootItem *parent = NULL); virtual ~Feed(); + + // Returns 0, feeds have no children. + int childCount() const; + + // Performs synchronous update and returns number of newly updated messages. + virtual int update() = 0; + + // Updates counts of all/unread messages for this feed. + virtual void updateCounts(bool including_total_count = true, bool update_feed_statuses = true) = 0; + + inline int autoUpdateInitialInterval() const { + return m_autoUpdateInitialInterval; + } + + inline void setAutoUpdateInitialInterval(int auto_update_interval) { + // If new initial auto-update interval is set, then + // we should reset time that remains to the next auto-update. + m_autoUpdateInitialInterval = auto_update_interval; + m_autoUpdateRemainingInterval = auto_update_interval; + } + + inline AutoUpdateType autoUpdateType() const { + return m_autoUpdateType; + } + + inline void setAutoUpdateType(const AutoUpdateType &autoUpdateType) { + m_autoUpdateType = autoUpdateType; + } + + inline int autoUpdateRemainingInterval() const { + return m_autoUpdateRemainingInterval; + } + + inline void setAutoUpdateRemainingInterval(int autoUpdateRemainingInterval) { + m_autoUpdateRemainingInterval = autoUpdateRemainingInterval; + } + + inline Status status() const { + return m_status; + } + + inline void setStatus(const Status &status) { + m_status = status; + } + + protected: + Status m_status; + AutoUpdateType m_autoUpdateType; + int m_autoUpdateInitialInterval; + int m_autoUpdateRemainingInterval; }; #endif // FEED_H diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index b87ae4b6f..eeae4d9c5 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -23,10 +23,15 @@ #include "miscellaneous/settings.h" #include "miscellaneous/iconfactory.h" #include "core/feedsmodel.h" +#include "gui/dialogs/formmain.h" +#include "gui/feedmessageviewer.h" +#include "gui/feedsview.h" +#include "services/standard/gui/formstandardcategorydetails.h" #include #include #include +#include StandardCategory::StandardCategory(RootItem *parent_item) : RootItem(parent_item) { @@ -121,6 +126,16 @@ QVariant StandardCategory::data(int column, int role) const { } } +void StandardCategory::edit() { + // TODO: fix passing of the model + QPointer form_pointer = new FormStandardCategoryDetails(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel(), + qApp->mainForm()); + + form_pointer.data()->exec(this, NULL); + + delete form_pointer.data(); +} + bool StandardCategory::removeItself() { bool children_removed = true; diff --git a/src/services/standard/standardcategory.h b/src/services/standard/standardcategory.h index c0a952b8a..eb18a7cc8 100755 --- a/src/services/standard/standardcategory.h +++ b/src/services/standard/standardcategory.h @@ -42,6 +42,16 @@ class StandardCategory : public RootItem { // Returns the actual data representation of standard category. QVariant data(int column, int role) const; + bool canBeEdited() { + return true; + } + + bool canBeDeleted() { + return true; + } + + void edit(); + // Removes category and all its children from persistent // database. bool removeItself(); diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 812529db0..13d8a244d 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -26,12 +26,17 @@ #include "miscellaneous/iconfactory.h" #include "miscellaneous/simplecrypt/simplecrypt.h" #include "network-web/networkfactory.h" +#include "gui/dialogs/formmain.h" +#include "gui/feedmessageviewer.h" +#include "gui/feedsview.h" +#include "services/standard/gui/formstandardfeeddetails.h" #include #include #include #include #include +#include #include #include #include @@ -42,26 +47,22 @@ void StandardFeed::init() { m_passwordProtected = false; m_username = QString(); m_password = QString(); - m_status = Normal; m_networkError = QNetworkReply::NoError; m_type = Rss0X; m_totalCount = 0; m_unreadCount = 0; - m_autoUpdateType = DontAutoUpdate; - m_autoUpdateInitialInterval = DEFAULT_AUTO_UPDATE_INTERVAL; - m_autoUpdateRemainingInterval = DEFAULT_AUTO_UPDATE_INTERVAL; m_encoding = QString(); m_url = QString(); m_kind = RootItem::Feeed; } StandardFeed::StandardFeed(RootItem *parent_item) - : RootItem(parent_item) { + : Feed(parent_item) { init(); } StandardFeed::StandardFeed(const StandardFeed &other) - : RootItem(NULL) { + : Feed(NULL) { m_passwordProtected = other.passwordProtected(); m_username = other.username(); m_password = other.password(); @@ -89,11 +90,6 @@ StandardFeed::~StandardFeed() { qDebug("Destroying Feed instance."); } -int StandardFeed::childCount() const { - // Because feed has no children. - return 0; -} - int StandardFeed::countOfAllMessages() const { return m_totalCount; } @@ -102,6 +98,15 @@ int StandardFeed::countOfUnreadMessages() const { return m_unreadCount; } +void StandardFeed::edit() { + // TODO: fix passing of the model + QPointer form_pointer = new FormStandardFeedDetails(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel(), + qApp->mainForm()); + form_pointer.data()->exec(this, NULL); + + delete form_pointer.data(); +} + QString StandardFeed::typeToString(StandardFeed::Type type) { switch (type) { case Atom10: @@ -710,7 +715,7 @@ QNetworkReply::NetworkError StandardFeed::networkError() const { return m_networkError; } -StandardFeed::StandardFeed(const QSqlRecord &record) : RootItem(NULL) { +StandardFeed::StandardFeed(const QSqlRecord &record) : Feed(NULL) { m_kind = RootItem::Feeed; setTitle(record.value(FDS_DB_TITLE_INDEX).toString()); diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index 41dfeec43..3c00b8e01 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -18,7 +18,7 @@ #ifndef FEEDSMODELFEED_H #define FEEDSMODELFEED_H -#include "core/rootitem.h" +#include "services/abstract/feed.h" #include #include @@ -33,7 +33,7 @@ class FeedsModel; // Represents BASE class for feeds contained in FeedsModel. // NOTE: This class should be derived to create PARTICULAR feed types. -class StandardFeed : public RootItem { +class StandardFeed : public Feed { Q_DECLARE_TR_FUNCTIONS(StandardFeed) public: @@ -46,43 +46,37 @@ class StandardFeed : public RootItem { Atom10 = 3 }; - // Specifies the auto-update strategy for the feed. - enum AutoUpdateType { - DontAutoUpdate = 0, - DefaultAutoUpdate = 1, - SpecificAutoUpdate = 2 - }; - - // Specifies the actual "status" of the feed. - // For example if it has new messages, error - // occurred, and so on. - enum Status { - Normal = 0, - NewMessages = 1, - NetworkError = 2 - }; - // Constructors and destructors. explicit StandardFeed(RootItem *parent_item = NULL); explicit StandardFeed(const StandardFeed &other); explicit StandardFeed(const QSqlRecord &record); virtual ~StandardFeed(); - // Returns 0, feeds have no children. - int childCount() const; - // Getters/setters for count of messages. // NOTE: For feeds, counts are stored internally // and can be updated from the database. int countOfAllMessages() const; int countOfUnreadMessages() const; + bool canBeEdited() { + return true; + } + + bool canBeDeleted() { + return true; + } + + void edit(); + // Obtains data related to this feed. QVariant data(int column, int role) const; // Perform fetching of new messages. Returns number of newly updated messages. int update(); + // Updates counts of all/unread messages for this feed. + void updateCounts(bool including_total_count = true, bool update_feed_statuses = true); + // Removes this standard feed from persistent // storage. bool removeItself(); @@ -138,41 +132,6 @@ class StandardFeed : public RootItem { m_url = url; } - inline int autoUpdateInitialInterval() const { - return m_autoUpdateInitialInterval; - } - - inline void setAutoUpdateInitialInterval(int auto_update_interval) { - // If new initial auto-update interval is set, then - // we should reset time that remains to the next auto-update. - m_autoUpdateInitialInterval = auto_update_interval; - m_autoUpdateRemainingInterval = auto_update_interval; - } - - inline AutoUpdateType autoUpdateType() const { - return m_autoUpdateType; - } - - inline void setAutoUpdateType(const AutoUpdateType &autoUpdateType) { - m_autoUpdateType = autoUpdateType; - } - - inline int autoUpdateRemainingInterval() const { - return m_autoUpdateRemainingInterval; - } - - inline void setAutoUpdateRemainingInterval(int autoUpdateRemainingInterval) { - m_autoUpdateRemainingInterval = autoUpdateRemainingInterval; - } - - inline Status status() const { - return m_status; - } - - inline void setStatus(const Status &status) { - m_status = status; - } - QNetworkReply::NetworkError networkError() const; // Tries to guess feed hidden under given URL @@ -186,9 +145,7 @@ class StandardFeed : public RootItem { static QString typeToString(Type type); public slots: - // Updates counts of all/unread messages for this feed. - void updateCounts(bool including_total_count = true, bool update_feed_statuses = true); - + // Fetches metadata for the feed. void fetchMetadataForItself(); protected: @@ -205,16 +162,11 @@ class StandardFeed : public RootItem { QString m_username; QString m_password; - Status m_status; - QNetworkReply::NetworkError m_networkError; Type m_type; + QNetworkReply::NetworkError m_networkError; int m_totalCount; int m_unreadCount; - AutoUpdateType m_autoUpdateType; - int m_autoUpdateInitialInterval; - int m_autoUpdateRemainingInterval; - QString m_encoding; QString m_url; }; From 54f17741aedf0a1dccb00d003e081a01864a3caf Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 30 Oct 2015 10:56:33 +0100 Subject: [PATCH 004/203] Remove drag&drop support for now. It will be probably re-introduced after the plugin system is fully stable. --- src/core/feedsmodel.cpp | 90 ----------------------------------------- src/core/feedsmodel.h | 6 --- src/gui/feedsview.cpp | 1 - 3 files changed, 97 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index ac4905a2b..183ce17dd 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -138,96 +138,6 @@ void FeedsModel::updateAutoUpdateStatus() { } } -QMimeData *FeedsModel::mimeData(const QModelIndexList &indexes) const { - QMimeData *mime_data = new QMimeData(); - QByteArray encoded_data; - QDataStream stream(&encoded_data, QIODevice::WriteOnly); - - foreach (const QModelIndex &index, indexes) { - if (index.column() != 0) { - continue; - } - - RootItem *item_for_index = itemForIndex(index); - - if (item_for_index->kind() != RootItem::Root) { - stream << (quintptr) item_for_index; - } - } - - mime_data->setData(MIME_TYPE_ITEM_POINTER, encoded_data); - return mime_data; -} - -QStringList FeedsModel::mimeTypes() const { - return QStringList() << MIME_TYPE_ITEM_POINTER; -} - -bool FeedsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { - Q_UNUSED(row) - Q_UNUSED(column) - - if (action == Qt::IgnoreAction) { - return true; - } - else if (action != Qt::MoveAction) { - return false; - } - - QByteArray dragged_items_data = data->data(MIME_TYPE_ITEM_POINTER); - - if (dragged_items_data.isEmpty()) { - return false; - } - else { - QDataStream stream(&dragged_items_data, QIODevice::ReadOnly); - - while (!stream.atEnd()) { - quintptr pointer_to_item; - stream >> pointer_to_item; - - // We have item we want to drag, we also determine the target item. - RootItem *dragged_item = (RootItem*) pointer_to_item; - RootItem *target_item = itemForIndex(parent); - - if (dragged_item == target_item || dragged_item->parent() == target_item) { - qDebug("Dragged item is equal to target item or its parent is equal to target item. Cancelling drag-drop action."); - return false; - } - - if (dragged_item->kind() == RootItem::Feeed) { - qDebug("Drag-drop action for feed '%s' detected, editing the feed.", qPrintable(dragged_item->title())); - - StandardFeed *actual_feed = dragged_item->toFeed(); - StandardFeed *feed_new = new StandardFeed(*actual_feed); - - feed_new->setParent(target_item); - editFeed(actual_feed, feed_new); - - emit requireItemValidationAfterDragDrop(indexForItem(actual_feed)); - } - else if (dragged_item->kind() == RootItem::Cattegory) { - qDebug("Drag-drop action for category '%s' detected, editing the feed.", qPrintable(dragged_item->title())); - - StandardCategory *actual_category = dragged_item->toCategory(); - StandardCategory *category_new = new StandardCategory(*actual_category); - - category_new->clearChildren(); - category_new->setParent(target_item); - editCategory(actual_category, category_new); - - emit requireItemValidationAfterDragDrop(indexForItem(actual_category)); - } - } - - return true; - } -} - -Qt::DropActions FeedsModel::supportedDropActions() const { - return Qt::MoveAction; -} - Qt::ItemFlags FeedsModel::flags(const QModelIndex &index) const { Qt::ItemFlags base_flags = QAbstractItemModel::flags(index); RootItem *item_for_index = itemForIndex(index); diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 98ea28b7d..c0b8114d7 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -55,10 +55,6 @@ class FeedsModel : public QAbstractItemModel { return itemForIndex(index)->data(index.column(), role); } - QMimeData *mimeData(const QModelIndexList &indexes) const; - QStringList mimeTypes() const; - bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); - Qt::DropActions supportedDropActions() const; Qt::ItemFlags flags(const QModelIndex &index) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; QModelIndex index(int row, int column, const QModelIndex &parent) const; @@ -196,8 +192,6 @@ class FeedsModel : public QAbstractItemModel { void assembleFeeds(FeedAssignment feeds); signals: - void requireItemValidationAfterDragDrop(const QModelIndex &source_index); - // Emitted when model requests update of some feeds. void feedsUpdateRequested(const QList feeds); diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index cba9fa970..d7031146c 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -55,7 +55,6 @@ FeedsView::FeedsView(QWidget *parent) m_sourceModel = m_proxyModel->sourceModel(); // Connections. - connect(m_sourceModel, SIGNAL(requireItemValidationAfterDragDrop(QModelIndex)), this, SLOT(validateItemAfterDragDrop(QModelIndex))); connect(m_sourceModel, SIGNAL(feedsUpdateRequested(QList)), this, SIGNAL(feedsUpdateRequested(QList))); connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder))); From 4eb76509a8359f54e6e97002aceea01ec10943c6 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 30 Oct 2015 11:01:35 +0100 Subject: [PATCH 005/203] Remove flags method. --- src/core/feedsmodel.cpp | 20 -------------------- src/core/feedsmodel.h | 1 - 2 files changed, 21 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 183ce17dd..7eab47079 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -138,26 +138,6 @@ void FeedsModel::updateAutoUpdateStatus() { } } -Qt::ItemFlags FeedsModel::flags(const QModelIndex &index) const { - Qt::ItemFlags base_flags = QAbstractItemModel::flags(index); - RootItem *item_for_index = itemForIndex(index); - - switch (item_for_index->kind()) { - case RootItem::Bin: - return base_flags; - - case RootItem::Cattegory: - return base_flags | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; - - case RootItem::Feeed: - return base_flags | Qt::ItemIsDragEnabled; - - case RootItem::Root: - default: - return base_flags | Qt::ItemIsDropEnabled; - } -} - QVariant FeedsModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation != Qt::Horizontal) { return QVariant(); diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index c0b8114d7..215bb9057 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -55,7 +55,6 @@ class FeedsModel : public QAbstractItemModel { return itemForIndex(index)->data(index.column(), role); } - Qt::ItemFlags flags(const QModelIndex &index) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; QModelIndex index(int row, int column, const QModelIndex &parent) const; QModelIndex parent(const QModelIndex &child) const; From d390ea2df6a37670d6ca2a4443bae2f2efee59e3 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 30 Oct 2015 11:14:15 +0100 Subject: [PATCH 006/203] Added so-far empty service root node classes. --- CMakeLists.txt | 2 ++ src/services/abstract/serviceroot.cpp | 2 +- src/services/abstract/serviceroot.h | 10 +++++++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a41b733be..ce27c7ea2 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -428,9 +428,11 @@ set(APP_SOURCES src/services/standard/gui/formstandardfeeddetails.cpp src/services/standard/gui/formstandardimportexport.cpp src/services/standard/standardserviceentrypoint.cpp + src/services/standard/standardserviceroot.cpp # TT-RSS feed service sources. src/services/tt-rss/ttrssserviceentrypoint.cpp + src/services/tt-rss/ttrssserviceroot.cpp # NETWORK-WEB sources. src/network-web/basenetworkaccessmanager.cpp diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index 0d437c68c..109f00ead 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -18,7 +18,7 @@ #include "services/abstract/serviceroot.h" -ServiceRoot::ServiceRoot() { +ServiceRoot::ServiceRoot(RootItem *parent) : RootItem(parent) { } ServiceRoot::~ServiceRoot() { diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 41b318e60..1355f1fb7 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -18,11 +18,15 @@ #ifndef SERVICEROOT_H #define SERVICEROOT_H +#include "core/rootitem.h" + + // THIS IS the root node of the service. -// TODO: Inherit proper base root class for this. -class ServiceRoot { +// NOTE: The root usually contains some core functionality of the +// service like service account username/password etc. +class ServiceRoot : public RootItem { public: - explicit ServiceRoot(); + explicit ServiceRoot(RootItem *parent = NULL); virtual ~ServiceRoot(); }; From fa373df15c2587c212661aa39dde8d4ec062ce09 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 30 Oct 2015 11:41:02 +0100 Subject: [PATCH 007/203] Added service root node classes and refactored editing of feeds/cats. --- src/core/feedsmodel.cpp | 44 +++---------------- src/core/feedsmodel.h | 11 ++--- src/core/rootitem.h | 2 +- src/gui/feedsview.cpp | 2 +- .../gui/formstandardcategorydetails.cpp | 11 +++-- .../standard/gui/formstandardfeeddetails.cpp | 18 +++++--- src/services/standard/standardcategory.cpp | 2 +- src/services/standard/standardcategory.h | 2 +- src/services/standard/standardfeed.cpp | 2 +- src/services/standard/standardfeed.h | 2 +- src/services/standard/standardserviceroot.cpp | 26 +++++++++++ src/services/standard/standardserviceroot.h | 30 +++++++++++++ src/services/tt-rss/ttrssserviceroot.cpp | 26 +++++++++++ src/services/tt-rss/ttrssserviceroot.h | 30 +++++++++++++ 14 files changed, 147 insertions(+), 61 deletions(-) create mode 100755 src/services/standard/standardserviceroot.cpp create mode 100755 src/services/standard/standardserviceroot.h create mode 100755 src/services/tt-rss/ttrssserviceroot.cpp create mode 100755 src/services/tt-rss/ttrssserviceroot.h diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 7eab47079..5a53493cb 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -252,33 +252,6 @@ bool FeedsModel::addCategory(StandardCategory *category, RootItem *parent) { return result; } -bool FeedsModel::editCategory(StandardCategory *original_category, StandardCategory *new_category_data) { - RootItem *original_parent = original_category->parent(); - RootItem *new_parent = new_category_data->parent(); - bool result = original_category->editItself(new_category_data); - - if (result && original_parent != new_parent) { - // User edited category and set it new parent item, - // se we need to move the item in the model too. - int original_index_of_category = original_parent->childItems().indexOf(original_category); - int new_index_of_category = new_parent->childCount(); - - // Remove the original item from the model... - beginRemoveRows(indexForItem(original_parent), original_index_of_category, original_index_of_category); - original_parent->removeChild(original_category); - endRemoveRows(); - - // ...and insert it under the new parent. - beginInsertRows(indexForItem(new_parent), new_index_of_category, new_index_of_category); - new_parent->appendChild(original_category); - endInsertRows(); - } - - // Cleanup temporary new category data. - delete new_category_data; - return result; -} - bool FeedsModel::addFeed(StandardFeed *feed, RootItem *parent) { // Get index of parent item (parent standard category or root item). QModelIndex parent_index = indexForItem(parent); @@ -297,30 +270,25 @@ bool FeedsModel::addFeed(StandardFeed *feed, RootItem *parent) { return result; } -bool FeedsModel::editFeed(StandardFeed *original_feed, StandardFeed *new_feed_data) { - RootItem *original_parent = original_feed->parent(); - RootItem *new_parent = new_feed_data->parent(); - bool result = original_feed->editItself(new_feed_data); +void FeedsModel::reassignNodeToNewParent(RootItem *original_node, RootItem *new_parent) { + RootItem *original_parent = original_node->parent(); - if (result && original_parent != new_parent) { + if (original_parent != new_parent) { // User edited category and set it new parent item, // se we need to move the item in the model too. - int original_index_of_feed = original_parent->childItems().indexOf(original_feed); + int original_index_of_feed = original_parent->childItems().indexOf(original_node); int new_index_of_feed = new_parent->childCount(); // Remove the original item from the model... beginRemoveRows(indexForItem(original_parent), original_index_of_feed, original_index_of_feed); - original_parent->removeChild(original_feed); + original_parent->removeChild(original_node); endRemoveRows(); // ... and insert it under the new parent. beginInsertRows(indexForItem(new_parent), new_index_of_feed, new_index_of_feed); - new_parent->appendChild(original_feed); + new_parent->appendChild(original_node); endInsertRows(); } - - delete new_feed_data; - return result; } QList FeedsModel::feedsForScheduledUpdate(bool auto_update_now) { diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 215bb9057..96ca0b432 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -41,9 +41,6 @@ typedef QPair FeedAssignmentItem; class FeedsModel : public QAbstractItemModel { Q_OBJECT - friend class StandardFeed; - friend class StandardCategory; - public: // Constructors and destructors. explicit FeedsModel(QObject *parent = 0); @@ -75,15 +72,13 @@ class FeedsModel : public QAbstractItemModel { // Standard category manipulators. bool addCategory(StandardCategory *category, RootItem *parent); - bool editCategory(StandardCategory *original_category, StandardCategory *new_category_data); // Standard feed manipulators. bool addFeed(StandardFeed *feed, RootItem *parent); - // New feed is just temporary feed, it is not added to the model. - // It is used to fetch its data to the original feed - // and the original feed is moved if needed. - bool editFeed(StandardFeed *original_feed, StandardFeed *new_feed_data); + // Checks if new parent node is different from one used by original node. + // If it is, then it reassigns original_node to new parent. + void reassignNodeToNewParent(RootItem *original_node, RootItem *new_parent); // Returns the list of feeds which should be updated // according to auto-update schedule. diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 96914ed7f..5fbfd56fc 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -75,7 +75,7 @@ class RootItem { return false; } - virtual void edit() { + virtual void editViaDialog() { } virtual int row() const; diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index d7031146c..9793ca65a 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -285,7 +285,7 @@ void FeedsView::editSelectedItem() { } if (selectedItem()->canBeEdited()) { - selectedItem()->edit(); + selectedItem()->editViaDialog(); } else { qApp->showGuiMessage(tr("Cannot edit item"), diff --git a/src/services/standard/gui/formstandardcategorydetails.cpp b/src/services/standard/gui/formstandardcategorydetails.cpp index 55af700e2..34bba3718 100755 --- a/src/services/standard/gui/formstandardcategorydetails.cpp +++ b/src/services/standard/gui/formstandardcategorydetails.cpp @@ -133,14 +133,19 @@ void FormStandardCategoryDetails::apply() { } } else { - if (m_feedsModel->editCategory(m_editableCategory, new_category)) { + bool edited = m_editableCategory->editItself(new_category); + + if (edited) { + m_feedsModel->reassignNodeToNewParent(m_editableCategory, new_category->parent()); + + // Remove new temporary feed data holder object. + delete new_category; accept(); } else { qApp->showGuiMessage(tr("Cannot edit category"), tr("Category was not edited due to error."), - QSystemTrayIcon::Critical, - qApp->mainForm(), true); + QSystemTrayIcon::Critical, this, true); } } } diff --git a/src/services/standard/gui/formstandardfeeddetails.cpp b/src/services/standard/gui/formstandardfeeddetails.cpp index f1884a1c4..adf3cf666 100755 --- a/src/services/standard/gui/formstandardfeeddetails.cpp +++ b/src/services/standard/gui/formstandardfeeddetails.cpp @@ -251,7 +251,13 @@ void FormStandardFeedDetails::apply() { } else { // Edit the feed. - if (m_feedsModel->editFeed(m_editableFeed, new_feed)) { + bool edited = m_editableFeed->editItself(new_feed); + + if (edited) { + m_feedsModel->reassignNodeToNewParent(m_editableFeed, new_feed->parent()); + + // Remove new temporary feed data holder object. + delete new_feed; accept(); } else { @@ -264,8 +270,8 @@ void FormStandardFeedDetails::apply() { void FormStandardFeedDetails::guessFeed() { QPair result = StandardFeed::guessFeed(m_ui->m_txtUrl->lineEdit()->text(), - m_ui->m_txtUsername->lineEdit()->text(), - m_ui->m_txtPassword->lineEdit()->text()); + m_ui->m_txtUsername->lineEdit()->text(), + m_ui->m_txtPassword->lineEdit()->text()); if (result.first != NULL) { // Icon or whole feed was guessed. @@ -308,8 +314,8 @@ void FormStandardFeedDetails::guessFeed() { void FormStandardFeedDetails::guessIconOnly() { QPair result = StandardFeed::guessFeed(m_ui->m_txtUrl->lineEdit()->text(), - m_ui->m_txtUsername->lineEdit()->text(), - m_ui->m_txtPassword->lineEdit()->text()); + m_ui->m_txtUsername->lineEdit()->text(), + m_ui->m_txtPassword->lineEdit()->text()); if (result.first != NULL) { // Icon or whole feed was guessed. @@ -476,7 +482,7 @@ void FormStandardFeedDetails::initialize() { } void FormStandardFeedDetails::loadCategories(const QList categories, - RootItem *root_item) { + RootItem *root_item) { m_ui->m_cmbParentCategory->addItem(root_item->icon(), root_item->title(), QVariant::fromValue((void*) root_item)); diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index eeae4d9c5..41e46b865 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -126,7 +126,7 @@ QVariant StandardCategory::data(int column, int role) const { } } -void StandardCategory::edit() { +void StandardCategory::editViaDialog() { // TODO: fix passing of the model QPointer form_pointer = new FormStandardCategoryDetails(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel(), qApp->mainForm()); diff --git a/src/services/standard/standardcategory.h b/src/services/standard/standardcategory.h index eb18a7cc8..9affc61b6 100755 --- a/src/services/standard/standardcategory.h +++ b/src/services/standard/standardcategory.h @@ -50,7 +50,7 @@ class StandardCategory : public RootItem { return true; } - void edit(); + void editViaDialog(); // Removes category and all its children from persistent // database. diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 13d8a244d..5d83d2626 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -98,7 +98,7 @@ int StandardFeed::countOfUnreadMessages() const { return m_unreadCount; } -void StandardFeed::edit() { +void StandardFeed::editViaDialog() { // TODO: fix passing of the model QPointer form_pointer = new FormStandardFeedDetails(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel(), qApp->mainForm()); diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index 3c00b8e01..52fe743b5 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -66,7 +66,7 @@ class StandardFeed : public Feed { return true; } - void edit(); + void editViaDialog(); // Obtains data related to this feed. QVariant data(int column, int role) const; diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp new file mode 100755 index 000000000..9fb60c691 --- /dev/null +++ b/src/services/standard/standardserviceroot.cpp @@ -0,0 +1,26 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#include "services/standard/standardserviceroot.h" + + +StandardServiceRoot::StandardServiceRoot(RootItem *parent) : ServiceRoot(parent) { +} + +StandardServiceRoot::~StandardServiceRoot() { +} + diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h new file mode 100755 index 000000000..3664cc37f --- /dev/null +++ b/src/services/standard/standardserviceroot.h @@ -0,0 +1,30 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#ifndef STANDARDSERVICEROOT_H +#define STANDARDSERVICEROOT_H + +#include "services/abstract/serviceroot.h" + + +class StandardServiceRoot : public ServiceRoot { + public: + explicit StandardServiceRoot(RootItem *parent = NULL); + virtual ~StandardServiceRoot(); +}; + +#endif // STANDARDSERVICEROOT_H diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp new file mode 100755 index 000000000..338d30bae --- /dev/null +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -0,0 +1,26 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#include "services/tt-rss/ttrssserviceroot.h" + + +TtRssServiceRoot::TtRssServiceRoot(RootItem *parent) : ServiceRoot(parent) { +} + +TtRssServiceRoot::~TtRssServiceRoot() { +} + diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h new file mode 100755 index 000000000..e98f585bf --- /dev/null +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -0,0 +1,30 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#ifndef TTRSSSERVICEROOT_H +#define TTRSSSERVICEROOT_H + +#include "services/abstract/serviceroot.h" + + +class TtRssServiceRoot : public ServiceRoot { + public: + explicit TtRssServiceRoot(RootItem *parent = NULL); + virtual ~TtRssServiceRoot(); +}; + +#endif // TTRSSSERVICEROOT_H From 52b41e19f4a24b4f2425cd4df03a98247cb0ae16 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 30 Oct 2015 12:15:27 +0100 Subject: [PATCH 008/203] Added some information to service roots implementations. --- src/core/rootitem.cpp | 8 +- src/miscellaneous/systemfactory.cpp | 14 +++ src/miscellaneous/systemfactory.h | 3 + src/services/standard/standardserviceroot.cpp | 78 +++++++++++++++++ src/services/standard/standardserviceroot.h | 8 ++ src/services/tt-rss/ttrssserviceroot.cpp | 85 +++++++++++++++++++ src/services/tt-rss/ttrssserviceroot.h | 9 ++ 7 files changed, 199 insertions(+), 6 deletions(-) diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index a9789c816..3d3b6ac63 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -69,9 +69,7 @@ int RootItem::countOfAllMessages() const { int total_count = 0; foreach (RootItem *child_item, m_childItems) { - if (child_item->kind() != RootItem::Bin) { - total_count += child_item->countOfAllMessages(); - } + total_count += child_item->countOfAllMessages(); } return total_count; @@ -143,9 +141,7 @@ int RootItem::countOfUnreadMessages() const { int total_count = 0; foreach (RootItem *child_item, m_childItems) { - if (child_item->kind() != RootItem::Bin) { - total_count += child_item->countOfUnreadMessages(); - } + total_count += child_item->countOfUnreadMessages(); } return total_count; diff --git a/src/miscellaneous/systemfactory.cpp b/src/miscellaneous/systemfactory.cpp index 6d3e7f2eb..1e80fa486 100755 --- a/src/miscellaneous/systemfactory.cpp +++ b/src/miscellaneous/systemfactory.cpp @@ -172,6 +172,20 @@ bool SystemFactory::removeTrolltechJunkRegistryKeys() { } #endif +QString SystemFactory::getUsername() const { + QString name = qgetenv("USER"); + + if (name.isEmpty()) { + name = qgetenv("USERNAME"); + } + + if (name.isEmpty()) { + name = tr("anonymous"); + } + + return name; +} + QPair SystemFactory::checkForUpdates() { QPair result; QByteArray releases_xml; diff --git a/src/miscellaneous/systemfactory.h b/src/miscellaneous/systemfactory.h index aa5fcacaa..90852be91 100755 --- a/src/miscellaneous/systemfactory.h +++ b/src/miscellaneous/systemfactory.h @@ -80,6 +80,9 @@ class SystemFactory : public QObject { QString getAutostartDesktopFileLocation(); #endif + // Retrieves username of currently logged-in user. + QString getUsername() const; + // Tries to download list with new updates. QPair checkForUpdates(); diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 9fb60c691..e1ee257f3 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -17,10 +17,88 @@ #include "services/standard/standardserviceroot.h" +#include "definitions/definitions.h" +#include "miscellaneous/application.h" +#include "miscellaneous/settings.h" +#include "services/standard/standardserviceentrypoint.h" + StandardServiceRoot::StandardServiceRoot(RootItem *parent) : ServiceRoot(parent) { + m_title = qApp->system()->getUsername() + "@" + APP_LOW_NAME; + m_icon = StandardServiceEntryPoint().icon(); } StandardServiceRoot::~StandardServiceRoot() { } +bool StandardServiceRoot::canBeEdited() { + return false; +} + +bool StandardServiceRoot::canBeDeleted() { + return false; +} + +QVariant StandardServiceRoot::data(int column, int role) const { + switch (role) { + case Qt::DisplayRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return m_title; + } + else if (column == FDS_MODEL_COUNTS_INDEX) { + return qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::CountFormat)).toString() + .replace(PLACEHOLDER_UNREAD_COUNTS, QString::number(countOfUnreadMessages())) + .replace(PLACEHOLDER_ALL_COUNTS, QString::number(countOfAllMessages())); + } + else { + return QVariant(); + } + + case Qt::EditRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return m_title; + } + else if (column == FDS_MODEL_COUNTS_INDEX) { + return countOfUnreadMessages(); + } + else { + return QVariant(); + } + + case Qt::DecorationRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return m_icon; + } + else { + return QVariant(); + } + + case Qt::ToolTipRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return + m_title + "\n" + + tr("This is service account for standard RSS/RDF/ATOM feeds."); + } + else if (column == FDS_MODEL_COUNTS_INDEX) { + //: Tooltip for "unread" column of feed list. + return tr("%n unread message(s).", 0, countOfUnreadMessages()); + } + else { + return QVariant(); + } + + case Qt::TextAlignmentRole: + if (column == FDS_MODEL_COUNTS_INDEX) { + return Qt::AlignCenter; + } + else { + return QVariant(); + } + + case Qt::FontRole: + return countOfUnreadMessages() > 0 ? m_boldFont : m_normalFont; + + default: + return QVariant(); + } +} diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 3664cc37f..244282b0a 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -20,11 +20,19 @@ #include "services/abstract/serviceroot.h" +#include + class StandardServiceRoot : public ServiceRoot { + Q_DECLARE_TR_FUNCTIONS(StandardServiceRoot) + public: explicit StandardServiceRoot(RootItem *parent = NULL); virtual ~StandardServiceRoot(); + + bool canBeEdited(); + bool canBeDeleted(); + QVariant data(int column, int role) const; }; #endif // STANDARDSERVICEROOT_H diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 338d30bae..e1e52c269 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -17,10 +17,95 @@ #include "services/tt-rss/ttrssserviceroot.h" +#include "miscellaneous/application.h" +#include "miscellaneous/settings.h" +#include "services/tt-rss/ttrssserviceentrypoint.h" + TtRssServiceRoot::TtRssServiceRoot(RootItem *parent) : ServiceRoot(parent) { + // TODO: nadpis se bude měnit podle nastavení uživatelského + // jména a serveru tohoto ttrss učtu + m_title = qApp->system()->getUsername() + "@ttrss"; + m_icon = TtRssServiceEntryPoint().icon(); } TtRssServiceRoot::~TtRssServiceRoot() { } +void TtRssServiceRoot::editViaDialog() { + // TODO: zobrazit custom edit dialog pro ttrss +} + +bool TtRssServiceRoot::canBeEdited() { + return true; +} + +bool TtRssServiceRoot::canBeDeleted() { + return true; +} + +QVariant TtRssServiceRoot::data(int column, int role) const { + switch (role) { + case Qt::DisplayRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return m_title; + } + else if (column == FDS_MODEL_COUNTS_INDEX) { + return qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::CountFormat)).toString() + .replace(PLACEHOLDER_UNREAD_COUNTS, QString::number(countOfUnreadMessages())) + .replace(PLACEHOLDER_ALL_COUNTS, QString::number(countOfAllMessages())); + } + else { + return QVariant(); + } + + case Qt::EditRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return m_title; + } + else if (column == FDS_MODEL_COUNTS_INDEX) { + return countOfUnreadMessages(); + } + else { + return QVariant(); + } + + case Qt::DecorationRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return m_icon; + } + else { + return QVariant(); + } + + case Qt::ToolTipRole: + // TODO: zobrazovat pokročile informace a statistiky. + if (column == FDS_MODEL_TITLE_INDEX) { + return + m_title + "\n" + + tr("This is service account TT-RSS (TinyTiny RSS) server."); + } + else if (column == FDS_MODEL_COUNTS_INDEX) { + //: Tooltip for "unread" column of feed list. + return tr("%n unread message(s).", 0, countOfUnreadMessages()); + } + else { + return QVariant(); + } + + case Qt::TextAlignmentRole: + if (column == FDS_MODEL_COUNTS_INDEX) { + return Qt::AlignCenter; + } + else { + return QVariant(); + } + + case Qt::FontRole: + return countOfUnreadMessages() > 0 ? m_boldFont : m_normalFont; + + default: + return QVariant(); + } +} + diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index e98f585bf..986c99e21 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -20,11 +20,20 @@ #include "services/abstract/serviceroot.h" +#include + class TtRssServiceRoot : public ServiceRoot { + Q_DECLARE_TR_FUNCTIONS(StandardServiceRoot) + public: explicit TtRssServiceRoot(RootItem *parent = NULL); virtual ~TtRssServiceRoot(); + + bool canBeEdited(); + bool canBeDeleted(); + void editViaDialog(); + QVariant data(int column, int role) const; }; #endif // TTRSSSERVICEROOT_H From e465b1ec0faee2120eed9094cb41714b545bb219 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 30 Oct 2015 13:07:42 +0100 Subject: [PATCH 009/203] Added very experimental brand new tree handling for standard service account. Also note, that recycle bin func is now broken, since there now each service account has OWN recycle bin, therefore there might be more than one recycle bin. --- CMakeLists.txt | 2 +- src/core/feedsmodel.cpp | 126 ++------------- src/core/feedsmodel.h | 23 +-- src/core/rootitem.cpp | 5 - src/core/rootitem.h | 3 +- src/gui/dialogs/formmain.cpp | 10 -- src/gui/dialogs/formmain.ui | 24 --- src/gui/feedmessageviewer.cpp | 9 -- src/gui/feedsview.cpp | 49 +++--- src/gui/feedsview.h | 3 - src/gui/messagesview.cpp | 10 +- src/gui/tabwidget.cpp | 1 - src/services/abstract/serviceentrypoint.h | 8 + .../standard/standardrecyclebin.cpp} | 22 +-- .../standard/standardrecyclebin.h} | 8 +- .../standard/standardserviceentrypoint.cpp | 9 ++ .../standard/standardserviceentrypoint.h | 2 + src/services/standard/standardserviceroot.cpp | 146 +++++++++++++++++- src/services/standard/standardserviceroot.h | 27 ++++ .../tt-rss/ttrssserviceentrypoint.cpp | 4 + src/services/tt-rss/ttrssserviceentrypoint.h | 2 + 21 files changed, 244 insertions(+), 249 deletions(-) rename src/{core/recyclebin.cpp => services/standard/standardrecyclebin.cpp} (86%) mode change 100644 => 100755 rename src/{core/recyclebin.h => services/standard/standardrecyclebin.h} (84%) mode change 100644 => 100755 diff --git a/CMakeLists.txt b/CMakeLists.txt index ce27c7ea2..0df1f5a53 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -412,7 +412,6 @@ set(APP_SOURCES src/core/rootitem.cpp src/core/parsingfactory.cpp src/core/feeddownloader.cpp - src/core/recyclebin.cpp src/core/feedsselection.cpp # ABSTRACT service sources. @@ -429,6 +428,7 @@ set(APP_SOURCES src/services/standard/gui/formstandardimportexport.cpp src/services/standard/standardserviceentrypoint.cpp src/services/standard/standardserviceroot.cpp + src/services/standard/standardrecyclebin.cpp # TT-RSS feed service sources. src/services/tt-rss/ttrssserviceentrypoint.cpp diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 5a53493cb..cd6bc51e7 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -19,10 +19,10 @@ #include "definitions/definitions.h" #include "services/abstract/feed.h" +#include "services/abstract/serviceroot.h" #include "services/standard/standardfeed.h" #include "services/standard/standardcategory.h" #include "services/standard/standardfeedsimportexportmodel.h" -#include "core/recyclebin.h" #include "miscellaneous/textfactory.h" #include "miscellaneous/databasefactory.h" #include "miscellaneous/iconfactory.h" @@ -41,7 +41,7 @@ FeedsModel::FeedsModel(QObject *parent) - : QAbstractItemModel(parent), m_recycleBin(new RecycleBin()), m_autoUpdateTimer(new QTimer(this)) { + : QAbstractItemModel(parent), m_autoUpdateTimer(new QTimer(this)) { setObjectName(QSL("FeedsModel")); // Create root item. @@ -63,7 +63,7 @@ FeedsModel::FeedsModel(QObject *parent) connect(m_autoUpdateTimer, SIGNAL(timeout()), this, SLOT(executeNextAutoUpdate())); - loadFromDatabase(); + loadActivatedServiceAccounts(); // Setup the timer. updateAutoUpdateStatus(); @@ -389,17 +389,6 @@ StandardCategory *FeedsModel::categoryForIndex(const QModelIndex &index) const { } } -RecycleBin *FeedsModel::recycleBinForIndex(const QModelIndex &index) const { - RootItem *item = itemForIndex(index); - - if (item->kind() == RootItem::Bin) { - return item->toRecycleBin(); - } - else { - return NULL; - } -} - QModelIndex FeedsModel::indexForItem(RootItem *item) const { if (item == NULL || item->kind() == RootItem::Root) { // Root item lies on invalid index. @@ -539,70 +528,19 @@ void FeedsModel::reloadWholeLayout() { emit layoutChanged(); } -void FeedsModel::loadFromDatabase() { +void FeedsModel::loadActivatedServiceAccounts() { // Delete all childs of the root node and clear them from the memory. qDeleteAll(m_rootItem->childItems()); m_rootItem->clearChildren(); - QSqlDatabase database = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings); - CategoryAssignment categories; - FeedAssignment feeds; + foreach (ServiceEntryPoint *entry_point, qApp->feedServices()) { + // Load all stored root nodes from the entry point and add those to the model. + QList roots = entry_point->initializeSubtree(); - // Obtain data for categories from the database. - QSqlQuery query_categories(database); - query_categories.setForwardOnly(true); - - if (!query_categories.exec(QSL("SELECT * FROM Categories;")) || query_categories.lastError().isValid()) { - qFatal("Query for obtaining categories failed. Error message: '%s'.", - qPrintable(query_categories.lastError().text())); - } - - while (query_categories.next()) { - CategoryAssignmentItem pair; - pair.first = query_categories.value(CAT_DB_PARENT_ID_INDEX).toInt(); - pair.second = new StandardCategory(query_categories.record()); - - categories << pair; - } - - // All categories are now loaded. - QSqlQuery query_feeds(database); - query_feeds.setForwardOnly(true); - - if (!query_feeds.exec(QSL("SELECT * FROM Feeds;")) || query_feeds.lastError().isValid()) { - qFatal("Query for obtaining feeds failed. Error message: '%s'.", - qPrintable(query_feeds.lastError().text())); - } - - while (query_feeds.next()) { - // Process this feed. - StandardFeed::Type type = static_cast(query_feeds.value(FDS_DB_TYPE_INDEX).toInt()); - - switch (type) { - case StandardFeed::Atom10: - case StandardFeed::Rdf: - case StandardFeed::Rss0X: - case StandardFeed::Rss2X: { - FeedAssignmentItem pair; - pair.first = query_feeds.value(FDS_DB_CATEGORY_INDEX).toInt(); - pair.second = new StandardFeed(query_feeds.record()); - pair.second->setType(type); - - feeds << pair; - break; - } - - default: - break; + foreach (ServiceRoot *root, roots) { + m_rootItem->appendChild(root); } } - - // All data are now obtained, lets create the hierarchy. - assembleCategories(categories); - assembleFeeds(feeds); - - // As the last item, add recycle bin, which is needed. - m_rootItem->appendChild(m_recycleBin); } QList FeedsModel::feedsForIndex(const QModelIndex &index) { @@ -768,49 +706,3 @@ QList FeedsModel::feedsForItem(RootItem *root) { return feeds; } - -void FeedsModel::assembleFeeds(FeedAssignment feeds) { - QHash categories = allCategories(); - - foreach (const FeedAssignmentItem &feed, feeds) { - if (feed.first == NO_PARENT_CATEGORY) { - // This is top-level feed, add it to the root item. - m_rootItem->appendChild(feed.second); - } - else if (categories.contains(feed.first)) { - // This feed belongs to this category. - categories.value(feed.first)->appendChild(feed.second); - } - else { - qWarning("Feed '%s' is loose, skipping it.", qPrintable(feed.second->title())); - } - } -} - -RecycleBin *FeedsModel::recycleBin() const { - return m_recycleBin; -} - -void FeedsModel::assembleCategories(CategoryAssignment categories) { - QHash assignments; - assignments.insert(NO_PARENT_CATEGORY, m_rootItem); - - // Add top-level categories. - while (!categories.isEmpty()) { - for (int i = 0; i < categories.size(); i++) { - if (assignments.contains(categories.at(i).first)) { - // Parent category of this category is already added. - assignments.value(categories.at(i).first)->appendChild(categories.at(i).second); - - // Now, added category can be parent for another categories, add it. - assignments.insert(categories.at(i).second->id(), - categories.at(i).second); - - // Remove the category from the list, because it was - // added to the final collection. - categories.removeAt(i); - i--; - } - } - } -} diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 96ca0b432..e8854e403 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -28,16 +28,10 @@ class StandardCategory; class Feed; -class RecycleBin; +class StandardRecycleBin; class FeedsImportExportModel; class QTimer; -typedef QList > CategoryAssignment; -typedef QPair CategoryAssignmentItem; - -typedef QList > FeedAssignment; -typedef QPair FeedAssignmentItem; - class FeedsModel : public QAbstractItemModel { Q_OBJECT @@ -121,10 +115,6 @@ class FeedsModel : public QAbstractItemModel { // or NULL if no category lies on given index. StandardCategory *categoryForIndex(const QModelIndex &index) const; - // Returns pointer to recycle bin if lies on given index - // or NULL if no recycle bin lies on given index. - RecycleBin *recycleBinForIndex(const QModelIndex &index) const; - // Returns feed/category which lies at the specified index or // root item if index is invalid. RootItem *itemForIndex(const QModelIndex &index) const; @@ -144,9 +134,6 @@ class FeedsModel : public QAbstractItemModel { // it to active structure. bool mergeModel(FeedsImportExportModel *model, QString &output_message); - // Access to recycle bin. - RecycleBin *recycleBin() const; - // Resets global auto-update intervals according to settings // and starts/stop the timer as needed. void updateAutoUpdateStatus(); @@ -178,12 +165,7 @@ class FeedsModel : public QAbstractItemModel { QStringList textualFeedIds(const QList &feeds); // Loads feed/categories from the database. - void loadFromDatabase(); - - // Takes lists of feeds/categories and assembles - // them into the tree structure. - void assembleCategories(CategoryAssignment categories); - void assembleFeeds(FeedAssignment feeds); + void loadActivatedServiceAccounts(); signals: // Emitted when model requests update of some feeds. @@ -191,7 +173,6 @@ class FeedsModel : public QAbstractItemModel { private: RootItem *m_rootItem; - RecycleBin *m_recycleBin; QList m_headerData; QList m_tooltipData; QIcon m_countsIcon; diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index 3d3b6ac63..79bac83e7 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -19,7 +19,6 @@ #include "services/standard/standardcategory.h" #include "services/standard/standardfeed.h" -#include "core/recyclebin.h" #include "miscellaneous/application.h" #include @@ -112,10 +111,6 @@ bool RootItem::removeChild(RootItem *child) { return m_childItems.removeOne(child); } -RecycleBin *RootItem::toRecycleBin() { - return static_cast(this); -} - StandardCategory *RootItem::toCategory() { return static_cast(this); } diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 5fbfd56fc..6e8fca168 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -22,7 +22,7 @@ #include #include -class RecycleBin; +class StandardRecycleBin; class StandardCategory; class StandardFeed; @@ -192,7 +192,6 @@ class RootItem { } // Converters - RecycleBin *toRecycleBin(); StandardCategory *toCategory(); StandardFeed *toFeed(); diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index b9fad65a0..1c06b20d1 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -137,11 +137,6 @@ QList FormMain::allActions() { actions << m_ui->m_actionFetchFeedMetadata; actions << m_ui->m_actionExpandCollapseFeedCategory; - // Add recycle bin actions. - actions << m_ui->m_actionRestoreRecycleBin; - actions << m_ui->m_actionEmptyRecycleBin; - actions << m_ui->m_actionRestoreSelectedMessagesFromRecycleBin; - return actions; } @@ -237,11 +232,6 @@ void FormMain::setupIcons() { m_ui->m_actionSwitchMessageListOrientation->setIcon(icon_theme_factory->fromTheme(QSL("view-switch-layout-direction"))); m_ui->m_menuShowHide->setIcon(icon_theme_factory->fromTheme(QSL("view-switch"))); - // Recycle bin. - m_ui->m_actionEmptyRecycleBin->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-empty"))); - m_ui->m_actionRestoreRecycleBin->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-restore-all"))); - m_ui->m_actionRestoreSelectedMessagesFromRecycleBin->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-restore-one"))); - // Web browser. m_ui->m_actionAddBrowser->setIcon(icon_theme_factory->fromTheme(QSL("list-add"))); m_ui->m_actionCloseCurrentTab->setIcon(icon_theme_factory->fromTheme(QSL("list-remove"))); diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index f1179c599..cf173caa5 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -176,14 +176,6 @@ - - - &Recycle bin - - - - - &Services @@ -197,7 +189,6 @@ - @@ -606,21 +597,6 @@ Display &wiki - - - &Empty recycle bin - - - - - &Restore all messages - - - - - Restore &selected messages - - &Restart diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 0d2f93bc6..94ec10de0 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -290,7 +290,6 @@ void FeedMessageViewer::toggleShowOnlyUnreadFeeds() { void FeedMessageViewer::updateMessageButtonsAvailability() { bool one_message_selected = m_messagesView->selectionModel()->selectedRows().size() == 1; bool atleast_one_message_selected = !m_messagesView->selectionModel()->selectedRows().isEmpty(); - bool recycle_bin_selected = m_messagesView->sourceModel()->loadedSelection().mode() == FeedsSelection::MessagesFromRecycleBin; FormMain *form_main = qApp->mainForm(); form_main->m_ui->m_actionDeleteSelectedMessages->setEnabled(atleast_one_message_selected); @@ -301,8 +300,6 @@ void FeedMessageViewer::updateMessageButtonsAvailability() { form_main->m_ui->m_actionOpenSelectedSourceArticlesInternally->setEnabled(atleast_one_message_selected); form_main->m_ui->m_actionSendMessageViaEmail->setEnabled(one_message_selected); form_main->m_ui->m_actionSwitchImportanceOfSelectedMessages->setEnabled(atleast_one_message_selected); - - form_main->m_ui->m_actionRestoreSelectedMessagesFromRecycleBin->setEnabled(recycle_bin_selected && atleast_one_message_selected); } void FeedMessageViewer::updateFeedButtonsAvailability() { @@ -378,8 +375,6 @@ void FeedMessageViewer::createConnections() { SIGNAL(triggered()), m_messagesView, SLOT(switchSelectedMessagesImportance())); connect(form_main->m_ui->m_actionDeleteSelectedMessages, SIGNAL(triggered()), m_messagesView, SLOT(deleteSelectedMessages())); - connect(form_main->m_ui->m_actionRestoreSelectedMessagesFromRecycleBin, - SIGNAL(triggered()), m_messagesView, SLOT(restoreSelectedMessages())); connect(form_main->m_ui->m_actionMarkSelectedMessagesAsRead, SIGNAL(triggered()), m_messagesView, SLOT(markSelectedMessagesRead())); connect(form_main->m_ui->m_actionMarkSelectedMessagesAsUnread, @@ -418,10 +413,6 @@ void FeedMessageViewer::createConnections() { SIGNAL(triggered()), m_feedsView, SLOT(editSelectedItem())); connect(form_main->m_ui->m_actionViewSelectedItemsNewspaperMode, SIGNAL(triggered()), m_feedsView, SLOT(openSelectedFeedsInNewspaperMode())); - connect(form_main->m_ui->m_actionEmptyRecycleBin, - SIGNAL(triggered()), m_feedsView, SLOT(emptyRecycleBin())); - connect(form_main->m_ui->m_actionRestoreRecycleBin, - SIGNAL(triggered()), m_feedsView, SLOT(restoreRecycleBin())); connect(form_main->m_ui->m_actionDeleteSelectedFeedCategory, SIGNAL(triggered()), m_feedsView, SLOT(deleteSelectedItem())); connect(form_main->m_ui->m_actionSwitchFeedsList, diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 9793ca65a..fe501e073 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -21,7 +21,6 @@ #include "core/feedsmodel.h" #include "core/feedsproxymodel.h" #include "core/rootitem.h" -#include "core/recyclebin.h" #include "miscellaneous/systemfactory.h" #include "miscellaneous/mutex.h" #include "gui/systemtrayicon.h" @@ -46,8 +45,7 @@ FeedsView::FeedsView(QWidget *parent) : QTreeView(parent), m_contextMenuCategories(NULL), m_contextMenuFeeds(NULL), - m_contextMenuEmptySpace(NULL), - m_contextMenuRecycleBin(NULL) { + m_contextMenuEmptySpace(NULL) { setObjectName(QSL("FeedsView")); // Allocate models. @@ -108,11 +106,6 @@ Feed *FeedsView::selectedFeed() const { return m_sourceModel->feedForIndex(current_mapped); } -RecycleBin *FeedsView::selectedRecycleBin() const{ - QModelIndex current_mapped = m_proxyModel->mapToSource(currentIndex()); - return m_sourceModel->recycleBinForIndex(current_mapped); -} - void FeedsView::saveExpandedStates() { Settings *settings = qApp->settings(); @@ -398,7 +391,8 @@ void FeedsView::emptyRecycleBin() { tr("You are about to permanenty delete all messages from your recycle bin."), tr("Do you really want to empty your recycle bin?"), QString(), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) { - m_sourceModel->recycleBin()->empty(); + // TODO: pridat metodu cisteni standardniho kose nebo vsech kosu. + //m_sourceModel->recycleBin()->empty(); updateCountsOfSelectedFeeds(true); emit feedsNeedToBeReloaded(true); @@ -406,7 +400,8 @@ void FeedsView::emptyRecycleBin() { } void FeedsView::restoreRecycleBin() { - m_sourceModel->recycleBin()->restore(); + // TODO: pridat metodu cisteni standardniho kose nebo vsech kosu. + //m_sourceModel->recycleBin()->restore(); updateCountsOfAllFeeds(true); emit feedsNeedToBeReloaded(true); @@ -421,10 +416,14 @@ void FeedsView::updateCountsOfSelectedFeeds(bool update_total_too) { if (update_total_too) { // Number of items in recycle bin has changed. - m_sourceModel->recycleBin()->updateCounts(true); + + // TODO: pridat metodu cisteni standardniho kose nebo vsech kosu. + //m_sourceModel->recycleBin()->updateCounts(true); // We need to refresh data for recycle bin too. - selected_indexes.append(m_sourceModel->indexForItem(m_sourceModel->recycleBin())); + + // TODO: pridat metodu cisteni standardniho kose nebo vsech kosu. + //selected_indexes.append(m_sourceModel->indexForItem(m_sourceModel->recycleBin())); } // Make sure that selected view reloads changed indexes. @@ -433,8 +432,10 @@ void FeedsView::updateCountsOfSelectedFeeds(bool update_total_too) { } void FeedsView::updateCountsOfRecycleBin(bool update_total_too) { - m_sourceModel->recycleBin()->updateCounts(update_total_too); - m_sourceModel->reloadChangedLayout(QModelIndexList() << m_sourceModel->indexForItem(m_sourceModel->recycleBin())); + + // TODO: pridat metodu cisteni standardniho kose nebo vsech kosu. + //m_sourceModel->recycleBin()->updateCounts(update_total_too); + //m_sourceModel->reloadChangedLayout(QModelIndexList() << m_sourceModel->indexForItem(m_sourceModel->recycleBin())); notifyWithCounts(); } @@ -445,7 +446,9 @@ void FeedsView::updateCountsOfAllFeeds(bool update_total_too) { if (update_total_too) { // Number of items in recycle bin has changed. - m_sourceModel->recycleBin()->updateCounts(true); + + // TODO: pridat metodu cisteni standardniho kose nebo vsech kosu. + //m_sourceModel->recycleBin()->updateCounts(true); } // Make sure that all views reloads its data. @@ -534,14 +537,6 @@ void FeedsView::initializeContextMenuEmptySpace() { qApp->mainForm()->m_ui->m_actionAddFeed); } -void FeedsView::initializeContextMenuRecycleBin() { - m_contextMenuRecycleBin = new QMenu(tr("Context menu for recycle bin"), this); - m_contextMenuRecycleBin->addActions(QList() << - qApp->mainForm()->m_ui->m_actionRestoreRecycleBin << - qApp->mainForm()->m_ui->m_actionRestoreSelectedMessagesFromRecycleBin << - qApp->mainForm()->m_ui->m_actionEmptyRecycleBin); -} - void FeedsView::setupAppearance() { #if QT_VERSION >= 0x050000 // Setup column resize strategies. @@ -617,14 +612,6 @@ void FeedsView::contextMenuEvent(QContextMenuEvent *event) { m_contextMenuFeeds->exec(event->globalPos()); } - else if (clicked_item->kind() == RootItem::Bin) { - // Display context menu for recycle bin. - if (m_contextMenuRecycleBin == NULL) { - initializeContextMenuRecycleBin(); - } - - m_contextMenuRecycleBin->exec(event->globalPos()); - } } else { // Display menu for empty space. diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index 26d47dc5e..d96a61932 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -61,7 +61,6 @@ class FeedsView : public QTreeView { RootItem *selectedItem() const; StandardCategory *selectedCategory() const; Feed *selectedFeed() const; - RecycleBin *selectedRecycleBin() const; // Saves/loads expand states of all nodes (feeds/categories) of the list to/from settings. void saveExpandedStates(); @@ -146,7 +145,6 @@ class FeedsView : public QTreeView { void initializeContextMenuCategories(); void initializeContextMenuFeeds(); void initializeContextMenuEmptySpace(); - void initializeContextMenuRecycleBin(); // Sets up appearance of this widget. void setupAppearance(); @@ -184,7 +182,6 @@ class FeedsView : public QTreeView { QMenu *m_contextMenuCategories; QMenu *m_contextMenuFeeds; QMenu *m_contextMenuEmptySpace; - QMenu *m_contextMenuRecycleBin; FeedsModel *m_sourceModel; FeedsProxyModel *m_proxyModel; diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index 4a904594b..7484ed092 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -146,13 +146,6 @@ void MessagesView::contextMenuEvent(QContextMenuEvent *event) { initializeContextMenu(); } - if (sourceModel()->loadedSelection().mode() == FeedsSelection::MessagesFromRecycleBin) { - m_contextMenu->addAction(qApp->mainForm()->m_ui->m_actionRestoreSelectedMessagesFromRecycleBin); - } - else { - m_contextMenu->removeAction(qApp->mainForm()->m_ui->m_actionRestoreSelectedMessagesFromRecycleBin); - } - m_contextMenu->exec(event->globalPos()); } @@ -166,8 +159,7 @@ void MessagesView::initializeContextMenu() { qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsRead << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsUnread << qApp->mainForm()->m_ui->m_actionSwitchImportanceOfSelectedMessages << - qApp->mainForm()->m_ui->m_actionDeleteSelectedMessages << - qApp->mainForm()->m_ui->m_actionRestoreSelectedMessagesFromRecycleBin); + qApp->mainForm()->m_ui->m_actionDeleteSelectedMessages); } void MessagesView::mousePressEvent(QMouseEvent *event) { diff --git a/src/gui/tabwidget.cpp b/src/gui/tabwidget.cpp index f850dd92b..2c0831e54 100755 --- a/src/gui/tabwidget.cpp +++ b/src/gui/tabwidget.cpp @@ -71,7 +71,6 @@ void TabWidget::openMainMenu() { m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuView); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuFeeds); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuMessages); - m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuRecycleBin); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuWebBrowser); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuTools); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuHelp); diff --git a/src/services/abstract/serviceentrypoint.h b/src/services/abstract/serviceentrypoint.h index f8b16b7f1..f6a257989 100755 --- a/src/services/abstract/serviceentrypoint.h +++ b/src/services/abstract/serviceentrypoint.h @@ -23,6 +23,8 @@ #include +class ServiceRoot; + // TOP LEVEL class which provides basic information about the "service" class ServiceEntryPoint { public: @@ -30,6 +32,12 @@ class ServiceEntryPoint { explicit ServiceEntryPoint(); virtual ~ServiceEntryPoint(); + // Performs initialization of all service accounts created using this entry + // point from persistent DB. + // Returns list of root nodes which will be afterwards added + // to the global feed model. + virtual QList initializeSubtree() = 0; + // Must this service account be activated by default? // NOTE: This is true particularly for "standard" service // which operates with normal RSS/ATOM feeds. diff --git a/src/core/recyclebin.cpp b/src/services/standard/standardrecyclebin.cpp old mode 100644 new mode 100755 similarity index 86% rename from src/core/recyclebin.cpp rename to src/services/standard/standardrecyclebin.cpp index df086ff39..fa26177ba --- a/src/core/recyclebin.cpp +++ b/src/services/standard/standardrecyclebin.cpp @@ -15,7 +15,7 @@ // You should have received a copy of the GNU General Public License // along with RSS Guard. If not, see . -#include "core/recyclebin.h" +#include "services/standard/standardrecyclebin.h" #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" @@ -23,7 +23,7 @@ #include -RecycleBin::RecycleBin(RootItem *parent) +StandardRecycleBin::StandardRecycleBin(RootItem *parent) : RootItem(parent) { m_kind = RootItem::Bin; m_icon = qApp->icons()->fromTheme(QSL("folder-recycle-bin")); @@ -35,27 +35,27 @@ RecycleBin::RecycleBin(RootItem *parent) updateCounts(true); } -RecycleBin::~RecycleBin() { +StandardRecycleBin::~StandardRecycleBin() { qDebug("Destroying RecycleBin instance."); } -int RecycleBin::childCount() const { +int StandardRecycleBin::childCount() const { return 0; } -void RecycleBin::appendChild(RootItem *child) { +void StandardRecycleBin::appendChild(RootItem *child) { Q_UNUSED(child) } -int RecycleBin::countOfUnreadMessages() const { +int StandardRecycleBin::countOfUnreadMessages() const { return m_unreadCount; } -int RecycleBin::countOfAllMessages() const { +int StandardRecycleBin::countOfAllMessages() const { return m_totalCount; } -QVariant RecycleBin::data(int column, int role) const { +QVariant StandardRecycleBin::data(int column, int role) const { switch (role) { case Qt::DisplayRole: if (column == FDS_MODEL_TITLE_INDEX) { @@ -108,7 +108,7 @@ QVariant RecycleBin::data(int column, int role) const { } } -bool RecycleBin::empty() { +bool StandardRecycleBin::empty() { QSqlDatabase db_handle = qApp->database()->connection(QSL("RecycleBin"), DatabaseFactory::FromSettings); if (!db_handle.transaction()) { @@ -135,7 +135,7 @@ bool RecycleBin::empty() { } } -bool RecycleBin::restore() { +bool StandardRecycleBin::restore() { QSqlDatabase db_handle = qApp->database()->connection(QSL("RecycleBin"), DatabaseFactory::FromSettings); if (!db_handle.transaction()) { @@ -162,7 +162,7 @@ bool RecycleBin::restore() { } } -void RecycleBin::updateCounts(bool update_total_count) { +void StandardRecycleBin::updateCounts(bool update_total_count) { QSqlDatabase database = qApp->database()->connection(QSL("RecycleBin"), DatabaseFactory::FromSettings); QSqlQuery query_all(database); query_all.setForwardOnly(true); diff --git a/src/core/recyclebin.h b/src/services/standard/standardrecyclebin.h old mode 100644 new mode 100755 similarity index 84% rename from src/core/recyclebin.h rename to src/services/standard/standardrecyclebin.h index 0ffcebda5..1675b9e5c --- a/src/core/recyclebin.h +++ b/src/services/standard/standardrecyclebin.h @@ -23,12 +23,12 @@ #include -class RecycleBin : public RootItem { - Q_DECLARE_TR_FUNCTIONS(RecycleBin) +class StandardRecycleBin : public RootItem { + Q_DECLARE_TR_FUNCTIONS(StandardRecycleBin) public: - explicit RecycleBin(RootItem *parent = NULL); - virtual ~RecycleBin(); + explicit StandardRecycleBin(RootItem *parent = NULL); + virtual ~StandardRecycleBin(); int childCount() const; void appendChild(RootItem *child); diff --git a/src/services/standard/standardserviceentrypoint.cpp b/src/services/standard/standardserviceentrypoint.cpp index 62d5fc901..01f85fda8 100755 --- a/src/services/standard/standardserviceentrypoint.cpp +++ b/src/services/standard/standardserviceentrypoint.cpp @@ -20,6 +20,7 @@ #include "definitions/definitions.h" #include "miscellaneous/application.h" +#include "services/standard/standardserviceroot.h" StandardServiceEntryPoint::StandardServiceEntryPoint() { @@ -67,3 +68,11 @@ QString StandardServiceEntryPoint::author() { QIcon StandardServiceEntryPoint::icon() { return QIcon(APP_ICON_PATH); } + +QList StandardServiceEntryPoint::initializeSubtree() { + StandardServiceRoot *root = new StandardServiceRoot(); + QList roots; + + roots.append(root); + return roots; +} diff --git a/src/services/standard/standardserviceentrypoint.h b/src/services/standard/standardserviceentrypoint.h index 1aef07b39..6729922dd 100755 --- a/src/services/standard/standardserviceentrypoint.h +++ b/src/services/standard/standardserviceentrypoint.h @@ -36,6 +36,8 @@ class StandardServiceEntryPoint : public ServiceEntryPoint { QString version(); QString author(); QIcon icon(); + + QList initializeSubtree(); }; #endif // STANDARDSERVICEENTRYPOINT_H diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index e1ee257f3..12592850d 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -21,11 +21,20 @@ #include "miscellaneous/application.h" #include "miscellaneous/settings.h" #include "services/standard/standardserviceentrypoint.h" +#include "services/standard/standardrecyclebin.h" +#include "services/standard/standardfeed.h" +#include "services/standard/standardcategory.h" + +#include +#include -StandardServiceRoot::StandardServiceRoot(RootItem *parent) : ServiceRoot(parent) { +StandardServiceRoot::StandardServiceRoot(RootItem *parent) + : ServiceRoot(parent), m_recycleBin(new StandardRecycleBin(this)) { m_title = qApp->system()->getUsername() + "@" + APP_LOW_NAME; m_icon = StandardServiceEntryPoint().icon(); + + loadFromDatabase(); } StandardServiceRoot::~StandardServiceRoot() { @@ -102,3 +111,138 @@ QVariant StandardServiceRoot::data(int column, int role) const { return QVariant(); } } + +void StandardServiceRoot::loadFromDatabase(){ + // TODO: todo + QSqlDatabase database = qApp->database()->connection("StandardServiceRoot", DatabaseFactory::FromSettings); + CategoryAssignment categories; + FeedAssignment feeds; + + // Obtain data for categories from the database. + QSqlQuery query_categories(database); + query_categories.setForwardOnly(true); + + if (!query_categories.exec(QSL("SELECT * FROM Categories;")) || query_categories.lastError().isValid()) { + qFatal("Query for obtaining categories failed. Error message: '%s'.", + qPrintable(query_categories.lastError().text())); + } + + while (query_categories.next()) { + CategoryAssignmentItem pair; + pair.first = query_categories.value(CAT_DB_PARENT_ID_INDEX).toInt(); + pair.second = new StandardCategory(query_categories.record()); + + categories << pair; + } + + // All categories are now loaded. + QSqlQuery query_feeds(database); + query_feeds.setForwardOnly(true); + + if (!query_feeds.exec(QSL("SELECT * FROM Feeds;")) || query_feeds.lastError().isValid()) { + qFatal("Query for obtaining feeds failed. Error message: '%s'.", + qPrintable(query_feeds.lastError().text())); + } + + while (query_feeds.next()) { + // Process this feed. + StandardFeed::Type type = static_cast(query_feeds.value(FDS_DB_TYPE_INDEX).toInt()); + + switch (type) { + case StandardFeed::Atom10: + case StandardFeed::Rdf: + case StandardFeed::Rss0X: + case StandardFeed::Rss2X: { + FeedAssignmentItem pair; + pair.first = query_feeds.value(FDS_DB_CATEGORY_INDEX).toInt(); + pair.second = new StandardFeed(query_feeds.record()); + pair.second->setType(type); + + feeds << pair; + break; + } + + default: + break; + } + } + + // All data are now obtained, lets create the hierarchy. + assembleCategories(categories); + assembleFeeds(feeds); + + // As the last item, add recycle bin, which is needed. + appendChild(m_recycleBin); +} + +QHash StandardServiceRoot::categoriesForItem(RootItem *root) { + QHash categories; + QList parents; + + parents.append(root->childItems()); + + while (!parents.isEmpty()) { + RootItem *item = parents.takeFirst(); + + if (item->kind() == RootItem::Cattegory) { + // This item is category, add it to the output list and + // scan its children. + int category_id = item->id(); + StandardCategory *category = item->toCategory(); + + if (!categories.contains(category_id)) { + categories.insert(category_id, category); + } + + parents.append(category->childItems()); + } + } + + return categories; +} + +void StandardServiceRoot::assembleFeeds(FeedAssignment feeds) { + QHash categories = categoriesForItem(this); + + foreach (const FeedAssignmentItem &feed, feeds) { + if (feed.first == NO_PARENT_CATEGORY) { + // This is top-level feed, add it to the root item. + appendChild(feed.second); + } + else if (categories.contains(feed.first)) { + // This feed belongs to this category. + categories.value(feed.first)->appendChild(feed.second); + } + else { + qWarning("Feed '%s' is loose, skipping it.", qPrintable(feed.second->title())); + } + } +} + +StandardRecycleBin *StandardServiceRoot::recycleBin() const { + return m_recycleBin; +} + +void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { + QHash assignments; + assignments.insert(NO_PARENT_CATEGORY, this); + + // Add top-level categories. + while (!categories.isEmpty()) { + for (int i = 0; i < categories.size(); i++) { + if (assignments.contains(categories.at(i).first)) { + // Parent category of this category is already added. + assignments.value(categories.at(i).first)->appendChild(categories.at(i).second); + + // Now, added category can be parent for another categories, add it. + assignments.insert(categories.at(i).second->id(), + categories.at(i).second); + + // Remove the category from the list, because it was + // added to the final collection. + categories.removeAt(i); + i--; + } + } + } +} diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 244282b0a..5e1013feb 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -23,6 +23,16 @@ #include +class StandardRecycleBin; +class StandardCategory; +class StandardFeed; + +typedef QList > CategoryAssignment; +typedef QPair CategoryAssignmentItem; + +typedef QList > FeedAssignment; +typedef QPair FeedAssignmentItem; + class StandardServiceRoot : public ServiceRoot { Q_DECLARE_TR_FUNCTIONS(StandardServiceRoot) @@ -33,6 +43,23 @@ class StandardServiceRoot : public ServiceRoot { bool canBeEdited(); bool canBeDeleted(); QVariant data(int column, int role) const; + + // Returns all standard categories which are lying under given root node. + // This does NOT include the root node even if the node is category. + QHash categoriesForItem(RootItem *root); + + // Access to standard recycle bin. + StandardRecycleBin *recycleBin() const; + + private: + void loadFromDatabase(); + + // Takes lists of feeds/categories and assembles + // them into the tree structure. + void assembleCategories(CategoryAssignment categories); + void assembleFeeds(FeedAssignment feeds); + + StandardRecycleBin *m_recycleBin; }; #endif // STANDARDSERVICEROOT_H diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp index d1fc413da..7efd1d1f1 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.cpp +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -68,3 +68,7 @@ QString TtRssServiceEntryPoint::author() { QIcon TtRssServiceEntryPoint::icon() { return QIcon(APP_ICON_PATH); } + +QList TtRssServiceEntryPoint::initializeSubtree() { + return QList(); +} diff --git a/src/services/tt-rss/ttrssserviceentrypoint.h b/src/services/tt-rss/ttrssserviceentrypoint.h index 5294af5ad..63402ffdd 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.h +++ b/src/services/tt-rss/ttrssserviceentrypoint.h @@ -37,6 +37,8 @@ class TtRssServiceEntryPoint : public ServiceEntryPoint { QString version(); QString author(); QIcon icon(); + + QList initializeSubtree(); }; #endif // TTRSSSERVICEENTRYPOINT_H From f912e24b7d6df3af15a163d90cf387413542c4bb Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 3 Nov 2015 10:06:34 +0100 Subject: [PATCH 010/203] Made many changes, removed loads of obsolote and ugly code. Added some abstract classes. --- CMakeLists.txt | 2 + resources/text/CHANGELOG | 13 ++ src/core/feedsmodel.cpp | 167 ++---------------- src/core/feedsmodel.h | 23 +-- src/core/feedsproxymodel.cpp | 8 +- src/core/feedsselection.cpp | 10 +- src/core/rootitem.cpp | 38 ++-- src/core/rootitem.h | 36 ++-- src/gui/dialogs/formmain.cpp | 8 + src/gui/feedmessageviewer.cpp | 3 + src/gui/feedsview.cpp | 61 ++----- src/gui/feedsview.h | 9 +- src/miscellaneous/application.h | 2 + src/miscellaneous/settings.h | 1 + src/network-web/webbrowser.cpp | 4 +- src/services/abstract/category.cpp | 9 + src/services/abstract/category.h | 13 ++ src/services/abstract/feed.cpp | 4 + src/services/abstract/feed.h | 7 +- src/services/abstract/serviceentrypoint.h | 3 +- src/services/abstract/serviceroot.cpp | 5 +- src/services/abstract/serviceroot.h | 11 +- .../gui/formstandardcategorydetails.cpp | 24 +-- .../gui/formstandardcategorydetails.h | 6 +- .../standard/gui/formstandardfeeddetails.cpp | 17 +- .../standard/gui/formstandardfeeddetails.h | 6 +- .../standard/gui/formstandardimportexport.cpp | 12 +- .../standard/gui/formstandardimportexport.h | 6 +- src/services/standard/standardcategory.cpp | 13 +- src/services/standard/standardcategory.h | 6 +- src/services/standard/standardfeed.cpp | 9 +- .../standardfeedsimportexportmodel.cpp | 27 ++- .../standard/standardfeedsimportexportmodel.h | 1 - src/services/standard/standarditem.cpp | 18 ++ src/services/standard/standarditem.h | 19 ++ src/services/standard/standardrecyclebin.cpp | 2 +- .../standard/standardserviceentrypoint.cpp | 4 +- .../standard/standardserviceentrypoint.h | 2 +- src/services/standard/standardserviceroot.cpp | 105 +++++++++-- src/services/standard/standardserviceroot.h | 14 +- .../tt-rss/ttrssserviceentrypoint.cpp | 2 +- src/services/tt-rss/ttrssserviceentrypoint.h | 2 +- src/services/tt-rss/ttrssserviceroot.cpp | 3 +- src/services/tt-rss/ttrssserviceroot.h | 4 +- 44 files changed, 378 insertions(+), 361 deletions(-) create mode 100755 src/services/abstract/category.cpp create mode 100755 src/services/abstract/category.h create mode 100755 src/services/standard/standarditem.cpp create mode 100755 src/services/standard/standarditem.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0df1f5a53..cd6c78b8a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -417,6 +417,7 @@ set(APP_SOURCES # ABSTRACT service sources. src/services/abstract/serviceentrypoint.cpp src/services/abstract/feed.cpp + src/services/abstract/category.cpp src/services/abstract/serviceroot.cpp # STANDARD feed service sources. @@ -429,6 +430,7 @@ set(APP_SOURCES src/services/standard/standardserviceentrypoint.cpp src/services/standard/standardserviceroot.cpp src/services/standard/standardrecyclebin.cpp + src/services/standard/standarditem.cpp # TT-RSS feed service sources. src/services/tt-rss/ttrssserviceentrypoint.cpp diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 936cec063..030cf17d3 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -12,6 +12,19 @@ +

2.5.3

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

2.5.2

Added: diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index cd6bc51e7..494d12bc8 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -232,42 +232,15 @@ bool FeedsModel::removeItem(const QModelIndex &index) { return false; } -bool FeedsModel::addCategory(StandardCategory *category, RootItem *parent) { +void FeedsModel::assignNodeToNewParent(RootItem *item, RootItem *parent) { // Get index of parent item (parent standard category). QModelIndex parent_index = indexForItem(parent); - bool result = category->addItself(parent); - if (result) { - // Category was added to the persistent storage, - // so add it to the model. - beginInsertRows(parent_index, parent->childCount(), parent->childCount()); - parent->appendChild(category); - endInsertRows(); - } - else { - // We cannot delete (*this) in its method, thus delete it here. - delete category; - } + // TODO: todle jde sloučit s metodou reassignNodeToNewParent. - return result; -} - -bool FeedsModel::addFeed(StandardFeed *feed, RootItem *parent) { - // Get index of parent item (parent standard category or root item). - QModelIndex parent_index = indexForItem(parent); - bool result = feed->addItself(parent); - - if (result) { - // Feed was added to the persistent storage so add it to the model. - beginInsertRows(parent_index, parent->childCount(), parent->childCount()); - parent->appendChild(feed); - endInsertRows(); - } - else { - delete feed; - } - - return result; + beginInsertRows(parent_index, parent->childCount(), parent->childCount()); + parent->appendChild(item); + endInsertRows(); } void FeedsModel::reassignNodeToNewParent(RootItem *original_node, RootItem *new_parent) { @@ -378,10 +351,10 @@ RootItem *FeedsModel::itemForIndex(const QModelIndex &index) const { } } -StandardCategory *FeedsModel::categoryForIndex(const QModelIndex &index) const { +Category *FeedsModel::categoryForIndex(const QModelIndex &index) const { RootItem *item = itemForIndex(index); - if (item->kind() == RootItem::Cattegory) { + if (item->kind() == RootItemKind::Category) { return item->toCategory(); } else { @@ -390,14 +363,14 @@ StandardCategory *FeedsModel::categoryForIndex(const QModelIndex &index) const { } QModelIndex FeedsModel::indexForItem(RootItem *item) const { - if (item == NULL || item->kind() == RootItem::Root) { + if (item == NULL || item->kind() == RootItemKind::Root) { // Root item lies on invalid index. return QModelIndex(); } QStack chain; - while (item->kind() != RootItem::Root) { + while (item->kind() != RootItemKind::Root) { chain.push(item); item = item->parent(); } @@ -424,84 +397,6 @@ bool FeedsModel::hasAnyFeedNewMessages() { return false; } -bool FeedsModel::mergeModel(FeedsImportExportModel *model, QString &output_message) { - if (model == NULL || model->rootItem() == NULL) { - output_message = tr("Invalid tree data."); - qDebug("Root item for merging two models is null."); - return false; - } - - QStack original_parents; original_parents.push(m_rootItem); - QStack new_parents; new_parents.push(model->rootItem()); - bool some_feed_category_error = false; - - // We are definitely about to add some new items into the model. - //emit layoutAboutToBeChanged(); - - // Iterate all new items we would like to merge into current model. - while (!new_parents.isEmpty()) { - RootItem *target_parent = original_parents.pop(); - RootItem *source_parent = new_parents.pop(); - - foreach (RootItem *source_item, source_parent->childItems()) { - if (!model->isItemChecked(source_item)) { - // We can skip this item, because it is not checked and should not be imported. - // NOTE: All descendants are thus skipped too. - continue; - } - - if (source_item->kind() == RootItem::Cattegory) { - StandardCategory *source_category = source_item->toCategory(); - StandardCategory *new_category = new StandardCategory(*source_category); - - // Add category to model. - new_category->clearChildren(); - - if (addCategory(new_category, target_parent)) { - // Process all children of this category. - original_parents.push(new_category); - new_parents.push(source_category); - } - else { - // Add category failed, but this can mean that the same category (with same title) - // already exists. If such a category exists in current parent, then find it and - // add descendants to it. - RootItem *existing_category = target_parent->child(RootItem::Cattegory, new_category->title()); - - if (existing_category != NULL) { - original_parents.push(existing_category); - new_parents.push(source_category); - } - else { - some_feed_category_error = true; - } - } - } - else if (source_item->kind() == RootItem::Feeed) { - StandardFeed *source_feed = source_item->toFeed(); - StandardFeed *new_feed = new StandardFeed(*source_feed); - - // Append this feed and end this iteration. - if (!addFeed(new_feed, target_parent)) { - some_feed_category_error = true; - } - } - } - } - - // Changes are done now. Finalize the new model. - //emit layoutChanged(); - - if (some_feed_category_error) { - output_message = tr("Import successfull, but some feeds/categories were not imported due to error."); - } - else { - output_message = tr("Import was completely successfull."); - } - - return !some_feed_category_error; -} - void FeedsModel::reloadChangedLayout(QModelIndexList list) { while (!list.isEmpty()) { QModelIndex indx = list.takeFirst(); @@ -535,7 +430,7 @@ void FeedsModel::loadActivatedServiceAccounts() { foreach (ServiceEntryPoint *entry_point, qApp->feedServices()) { // Load all stored root nodes from the entry point and add those to the model. - QList roots = entry_point->initializeSubtree(); + QList roots = entry_point->initializeSubtree(this); foreach (ServiceRoot *root, roots) { m_rootItem->appendChild(root); @@ -551,8 +446,8 @@ QList FeedsModel::feedsForIndex(const QModelIndex &index) { Feed *FeedsModel::feedForIndex(const QModelIndex &index) { RootItem *item = itemForIndex(index); - if (item->kind() == RootItem::Feeed) { - return static_cast(item); + if (item->kind() == RootItemKind::Feed) { + return item->toFeed(); } else { return NULL; @@ -579,7 +474,7 @@ QList FeedsModel::feedsForIndexes(const QModelIndexList &indexes) { return feeds; } -bool FeedsModel::markFeedsRead(const QList &feeds, int read) { +bool FeedsModel::markFeedsRead(const QList &feeds, int read) { QSqlDatabase db_handle = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings); if (!db_handle.transaction()) { @@ -660,36 +555,6 @@ bool FeedsModel::markFeedsDeleted(const QList &feeds, int deleted, bool r } } -QHash FeedsModel::allCategories() { - return categoriesForItem(m_rootItem); -} - -QHash FeedsModel::categoriesForItem(RootItem *root) { - QHash categories; - QList parents; - - parents.append(root->childItems()); - - while (!parents.isEmpty()) { - RootItem *item = parents.takeFirst(); - - if (item->kind() == RootItem::Cattegory) { - // This item is category, add it to the output list and - // scan its children. - int category_id = item->id(); - StandardCategory *category = item->toCategory(); - - if (!categories.contains(category_id)) { - categories.insert(category_id, category); - } - - parents.append(category->childItems()); - } - } - - return categories; -} - QList FeedsModel::allFeeds() { return feedsForItem(m_rootItem); } @@ -699,8 +564,10 @@ QList FeedsModel::feedsForItem(RootItem *root) { QList feeds; foreach (RootItem *child, children) { - if (child->kind() == RootItem::Feeed) { - feeds.append(child->toFeed()); + Feed *converted = dynamic_cast(child); + + if (converted != NULL) { + feeds.append(converted); } } diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index e8854e403..4470ccc0d 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -26,9 +26,9 @@ #include +class Category; class StandardCategory; class Feed; -class StandardRecycleBin; class FeedsImportExportModel; class QTimer; @@ -64,11 +64,8 @@ class FeedsModel : public QAbstractItemModel { // Removes item with given index. bool removeItem(const QModelIndex &index); - // Standard category manipulators. - bool addCategory(StandardCategory *category, RootItem *parent); - - // Standard feed manipulators. - bool addFeed(StandardFeed *feed, RootItem *parent); + // Assigns item to the new parent. + void assignNodeToNewParent(RootItem *item, RootItem *parent); // Checks if new parent node is different from one used by original node. // If it is, then it reassigns original_node to new parent. @@ -86,14 +83,6 @@ class FeedsModel : public QAbstractItemModel { // in "newspaper" mode. QList messagesForFeeds(const QList &feeds); - // Returns all categories, each pair - // consists of ID of parent item and pointer to category. - QHash allCategories(); - - // Returns categories from the subtree with given root node, each pair - // consists of ID of parent item and pointer to category. - QHash categoriesForItem(RootItem *root); - // Returns list of all feeds contained in the model. QList allFeeds(); @@ -113,7 +102,7 @@ class FeedsModel : public QAbstractItemModel { // Returns pointer to category if it lies on given index // or NULL if no category lies on given index. - StandardCategory *categoryForIndex(const QModelIndex &index) const; + Category *categoryForIndex(const QModelIndex &index) const; // Returns feed/category which lies at the specified index or // root item if index is invalid. @@ -130,10 +119,6 @@ class FeedsModel : public QAbstractItemModel { return m_rootItem; } - // Takes structure residing under given root item and adds feeds/categories from - // it to active structure. - bool mergeModel(FeedsImportExportModel *model, QString &output_message); - // Resets global auto-update intervals according to settings // and starts/stop the timer as needed. void updateAutoUpdateStatus(); diff --git a/src/core/feedsproxymodel.cpp b/src/core/feedsproxymodel.cpp index 9c1b54f6c..d2b6fbd9f 100755 --- a/src/core/feedsproxymodel.cpp +++ b/src/core/feedsproxymodel.cpp @@ -155,15 +155,15 @@ bool FeedsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right return QString::localeAwareCompare(left_item->title(), right_item->title()) < 0; } } - else if (left_item->kind() == RootItem::Bin) { + else if (left_item->kind() == RootItemKind::Bin) { // Left item is recycle bin. Make sure it is "biggest" item if we have selected ascending order. return sortOrder() == Qt::DescendingOrder; } - else if (right_item->kind() == RootItem::Bin) { + else if (right_item->kind() == RootItemKind::Bin) { // Right item is recycle bin. Make sure it is "smallest" item if we have selected descending order. return sortOrder() == Qt::AscendingOrder; } - else if (left_item->kind() == RootItem::Feeed) { + else if (left_item->kind() == RootItemKind::Feed) { // Left item is feed, right item is category. return false; } @@ -193,7 +193,7 @@ bool FeedsProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source RootItem *item = m_sourceModel->itemForIndex(idx); - if (item->kind() == RootItem::Bin) { + if (item->kind() == RootItemKind::Bin) { // Recycle bin is always displayed. return true; } diff --git a/src/core/feedsselection.cpp b/src/core/feedsselection.cpp index e01624d21..ba563eb95 100755 --- a/src/core/feedsselection.cpp +++ b/src/core/feedsselection.cpp @@ -39,11 +39,11 @@ FeedsSelection::SelectionMode FeedsSelection::mode() { } switch (m_selectedItem->kind()) { - case RootItem::Bin: + case RootItemKind::Bin: return FeedsSelection::MessagesFromRecycleBin; - case RootItem::Cattegory: - case RootItem::Feeed: + case RootItemKind::Category: + case RootItemKind::Feed: return FeedsSelection::MessagesFromFeeds; default: @@ -57,12 +57,12 @@ RootItem *FeedsSelection::selectedItem() const { QString FeedsSelection::generateListOfIds() { if (m_selectedItem != NULL && - (m_selectedItem->kind() == RootItem::Feeed || m_selectedItem->kind() == RootItem::Cattegory)) { + (m_selectedItem->kind() == RootItemKind::Feed || m_selectedItem->kind() == RootItemKind::Category)) { QList children = m_selectedItem->getRecursiveChildren(); QStringList stringy_ids; foreach (RootItem *child, children) { - if (child->kind() == RootItem::Feeed) { + if (child->kind() == RootItemKind::Feed) { stringy_ids.append(QString::number(child->id())); } } diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index 79bac83e7..62f7cf587 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -25,7 +25,7 @@ RootItem::RootItem(RootItem *parent_item) - : m_kind(RootItem::Root), + : m_kind(RootItemKind::Root), m_id(NO_PARENT_CATEGORY), m_title(QString()), m_description(QString()), @@ -77,8 +77,9 @@ int RootItem::countOfAllMessages() const { QList RootItem::getRecursiveChildren() { QList children; - if (kind() == RootItem::Feeed) { - // Root itself is a FEED. + if (childCount() == 0) { + // Root itself has no children, it is either feed or + // empty category? children.append(this); } else { @@ -89,14 +90,14 @@ QList RootItem::getRecursiveChildren() { // Iterate all nested categories. while (!traversable_items.isEmpty()) { - RootItem *active_category = traversable_items.takeFirst(); + RootItem *active_item = traversable_items.takeFirst(); - foreach (RootItem *child, active_category->childItems()) { - if (child->kind() == RootItem::Feeed) { - // This child is feed. + foreach (RootItem *child, active_item->childItems()) { + if (child->childCount() == 0) { + // This child is feed or empty category. children.append(child); } - else if (child->kind() == RootItem::Cattegory) { + else { // This child is category, add its child feeds too. traversable_items.append(child); } @@ -111,25 +112,12 @@ bool RootItem::removeChild(RootItem *child) { return m_childItems.removeOne(child); } -StandardCategory *RootItem::toCategory() { - return static_cast(this); +Category *RootItem::toCategory() { + return static_cast(this); } -StandardFeed *RootItem::toFeed() { - return static_cast(this); -} - -RootItem *RootItem::child(RootItem::Kind kind_of_child, const QString &identifier) { - foreach (RootItem *child, childItems()) { - if (child->kind() == kind_of_child) { - if ((kind_of_child == Cattegory && child->title() == identifier) || - (kind_of_child == Feeed && child->toFeed()->url() == identifier)) { - return child; - } - } - } - - return NULL; +Feed *RootItem::toFeed() { + return static_cast(this); } int RootItem::countOfUnreadMessages() const { diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 6e8fca168..812528ed9 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -22,23 +22,24 @@ #include #include -class StandardRecycleBin; -class StandardCategory; -class StandardFeed; +class Category; +class Feed; + +namespace RootItemKind { + // Describes the kind of the item. + enum Kind { + Root = 1001, + Bin = 1002, + Feed = 1003, + Category = 1004 + }; +} // Represents ROOT item of FeedsModel. // NOTE: This class is derived to add functionality for // all other non-root items of FeedsModel. class RootItem { public: - // Describes the kind of the item. - enum Kind { - Root = 1001, - Bin = 1002, - Feeed = 1003, - Cattegory = 1004 - }; - // Constructors and destructors. explicit RootItem(RootItem *parent_item = NULL); virtual ~RootItem(); @@ -56,8 +57,6 @@ class RootItem { return m_childItems.value(row); } - virtual RootItem *child(RootItem::Kind kind_of_child, const QString &identifier); - inline virtual int childCount() const { return m_childItems.size(); } @@ -110,7 +109,7 @@ class RootItem { RootItem *this_item = this; - while (this_item->kind() != RootItem::Root) { + while (this_item->kind() != RootItemKind::Root) { if (root->childItems().contains(this_item)) { return true; } @@ -122,6 +121,7 @@ class RootItem { return false; } + // Is "this" item parent if given child? bool isParentOf(RootItem *child) { if (child == NULL) { return false; @@ -144,7 +144,7 @@ class RootItem { bool removeChild(int index); bool removeChild(RootItem *child); - inline Kind kind() const { + inline RootItemKind::Kind kind() const { return m_kind; } @@ -192,8 +192,8 @@ class RootItem { } // Converters - StandardCategory *toCategory(); - StandardFeed *toFeed(); + Category *toCategory(); + Feed *toFeed(); // Compares two model items. static bool isEqual(RootItem *lhs, RootItem *rhs); @@ -202,7 +202,7 @@ class RootItem { protected: void setupFonts(); - Kind m_kind; + RootItemKind::Kind m_kind; int m_id; QString m_title; QString m_description; diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index 1c06b20d1..4baef3183 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -401,17 +401,25 @@ void FormMain::loadWebBrowserMenu(int index) { } void FormMain::exportFeeds() { + // TODO: dodelat globalni pristup ke globalnimu standard service rootu, + // ten předat + /* QPointer form = new FormStandardImportExport(this); form.data()->setMode(FeedsImportExportModel::Export); form.data()->exec(); delete form.data(); + */ } void FormMain::importFeeds() { + // TODO: dodelat globalni pristup ke globalnimu standard service rootu, + // ten předat + /* QPointer form = new FormStandardImportExport(this); form.data()->setMode(FeedsImportExportModel::Import); form.data()->exec(); delete form.data(); + */ } void FormMain::backupDatabaseSettings() { diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 94ec10de0..df6fc5af8 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -209,9 +209,12 @@ void FeedMessageViewer::loadInitialFeeds() { model.importAsOPML20(IOFactory::readTextFile(file_to_load)); model.checkAllItems(); + // TODO: dodělat, předpokládá nějaký rozumný přístup k standardnímu root servicu. + /* if (m_feedsView->sourceModel()->mergeModel(&model, output_msg)) { m_feedsView->expandAll(); } + */ } catch (ApplicationException &ex) { MessageBox::show(this, QMessageBox::Critical, tr("Error when loading initial feeds"), ex.message()); diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index fe501e073..d780bcf61 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -96,7 +96,7 @@ RootItem *FeedsView::selectedItem() const { return selected_item == m_sourceModel->rootItem() ? NULL : selected_item; } -StandardCategory *FeedsView::selectedCategory() const { +Category *FeedsView::selectedCategory() const { QModelIndex current_mapped = m_proxyModel->mapToSource(currentIndex()); return m_sourceModel->categoryForIndex(current_mapped); } @@ -109,22 +109,27 @@ Feed *FeedsView::selectedFeed() const { void FeedsView::saveExpandedStates() { Settings *settings = qApp->settings(); + // TODO: doědlat + // Iterate all categories and save their expand statuses. - foreach (StandardCategory *category, sourceModel()->allCategories().values()) { + + /*foreach (Category *category, sourceModel()->allCategories().values()) { settings->setValue(GROUP(Categories), QString::number(category->id()), isExpanded(model()->mapFromSource(sourceModel()->indexForItem(category)))); - } + }*/ } void FeedsView::loadExpandedStates() { Settings *settings = qApp->settings(); + // TODO: doědlat + // Iterate all categories and save their expand statuses. - foreach (StandardCategory *category, sourceModel()->allCategories().values()) { + /*foreach (Category *category, sourceModel()->allCategories().values()) { setExpanded(model()->mapFromSource(sourceModel()->indexForItem(category)), settings->value(GROUP(Categories), QString::number(category->id()), true).toBool()); - } + }*/ } void FeedsView::invalidateReadFeedsFilter(bool set_new_value, bool show_unread_only) { @@ -185,48 +190,6 @@ void FeedsView::clearAllFeeds() { setAllFeedsClearStatus(1); } -void FeedsView::addNewCategory() { - if (!qApp->feedUpdateLock()->tryLock()) { - // Lock was not obtained because - // it is used probably by feed updater or application - // is quitting. - qApp->showGuiMessage(tr("Cannot add standard category"), - tr("You cannot add new standard category now because another critical operation is ongoing."), - QSystemTrayIcon::Warning, qApp->mainForm(), true); - return; - } - - QPointer form_pointer = new FormStandardCategoryDetails(m_sourceModel, this); - - form_pointer.data()->exec(NULL, selectedItem()); - - delete form_pointer.data(); - - // Changes are done, unlock the update master lock. - qApp->feedUpdateLock()->unlock(); -} - -void FeedsView::addNewFeed() { - if (!qApp->feedUpdateLock()->tryLock()) { - // Lock was not obtained because - // it is used probably by feed updater or application - // is quitting. - qApp->showGuiMessage(tr("Cannot add standard feed"), - tr("You cannot add new standard feed now because another critical operation is ongoing."), - QSystemTrayIcon::Warning, qApp->mainForm(), true); - return; - } - - QPointer form_pointer = new FormStandardFeedDetails(m_sourceModel, this); - - form_pointer.data()->exec(NULL, selectedItem()); - - delete form_pointer.data(); - - // Changes are done, unlock the update master lock. - qApp->feedUpdateLock()->unlock(); -} - void FeedsView::receiveMessageCountsChange(FeedsSelection::SelectionMode mode, bool total_msg_count_changed, bool any_msg_restored) { @@ -594,7 +557,7 @@ void FeedsView::contextMenuEvent(QContextMenuEvent *event) { QModelIndex mapped_index = model()->mapToSource(clicked_index); RootItem *clicked_item = sourceModel()->itemForIndex(mapped_index); - if (clicked_item->kind() == RootItem::Cattegory) { + if (clicked_item->kind() == RootItemKind::Category) { // Display context menu for categories. if (m_contextMenuCategories == NULL) { // Context menu is not initialized, initialize. @@ -603,7 +566,7 @@ void FeedsView::contextMenuEvent(QContextMenuEvent *event) { m_contextMenuCategories->exec(event->globalPos()); } - else if (clicked_item->kind() == RootItem::Feeed) { + else if (clicked_item->kind() == RootItemKind::Feed) { // Display context menu for feeds. if (m_contextMenuFeeds == NULL) { // Context menu is not initialized, initialize. diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index d96a61932..c1725f2c6 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -29,6 +29,7 @@ class FeedsProxyModel; class Feed; +class Category; class StandardCategory; class QTimer; @@ -59,7 +60,7 @@ class FeedsView : public QTreeView { // Returns pointers to selected feed/category if they are really // selected. RootItem *selectedItem() const; - StandardCategory *selectedCategory() const; + Category *selectedCategory() const; Feed *selectedFeed() const; // Saves/loads expand states of all nodes (feeds/categories) of the list to/from settings. @@ -101,12 +102,6 @@ class FeedsView : public QTreeView { void editSelectedItem(); void deleteSelectedItem(); - // Standard category manipulators. - void addNewCategory(); - - // Standard feed manipulators. - void addNewFeed(); - // Is called when counts of messages are changed externally, // typically from message view. void receiveMessageCountsChange(FeedsSelection::SelectionMode mode, bool total_msg_count_changed, bool any_msg_restored); diff --git a/src/miscellaneous/application.h b/src/miscellaneous/application.h index d23a7a847..c9aa87cb5 100755 --- a/src/miscellaneous/application.h +++ b/src/miscellaneous/application.h @@ -55,6 +55,8 @@ class Application : public QtSingleApplication { explicit Application(const QString &id, int &argc, char **argv); virtual ~Application(); + // List of all installed "feed service plugins", including obligatory + // "standard" service entry point. QList feedServices(); QList userActions(); diff --git a/src/miscellaneous/settings.h b/src/miscellaneous/settings.h index 5c9d4ac7a..c254e7cee 100755 --- a/src/miscellaneous/settings.h +++ b/src/miscellaneous/settings.h @@ -360,6 +360,7 @@ class Settings : public QSettings { // Creates settings file in correct location. static Settings *setupSettings(QObject *parent); + // Returns properties of the actual application-wide settings. static SettingsProperties determineProperties(); private: diff --git a/src/network-web/webbrowser.cpp b/src/network-web/webbrowser.cpp index eda30878a..c1da07cae 100755 --- a/src/network-web/webbrowser.cpp +++ b/src/network-web/webbrowser.cpp @@ -214,7 +214,9 @@ void WebBrowser::onIconChanged() { void WebBrowser::addFeedFromWebsite(const QString &feed_link) { qApp->clipboard()->setText(feed_link); - qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->addNewFeed(); + + // TODO: dodělat + //qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->addNewFeed(); } void WebBrowser::onTitleChanged(const QString &new_title) { diff --git a/src/services/abstract/category.cpp b/src/services/abstract/category.cpp new file mode 100755 index 000000000..52707e0ac --- /dev/null +++ b/src/services/abstract/category.cpp @@ -0,0 +1,9 @@ +#include "services/abstract/category.h" + + +Category::Category(RootItem *parent) : RootItem(parent) { +} + +Category::~Category() { +} + diff --git a/src/services/abstract/category.h b/src/services/abstract/category.h new file mode 100755 index 000000000..aaf55caef --- /dev/null +++ b/src/services/abstract/category.h @@ -0,0 +1,13 @@ +#ifndef CATEGORY_H +#define CATEGORY_H + +#include "core/rootitem.h" + + +class Category : public RootItem { + public: + explicit Category(RootItem *parent = NULL); + virtual ~Category(); +}; + +#endif // CATEGORY_H diff --git a/src/services/abstract/feed.cpp b/src/services/abstract/feed.cpp index b3d8c61e8..c7a030a5f 100755 --- a/src/services/abstract/feed.cpp +++ b/src/services/abstract/feed.cpp @@ -34,3 +34,7 @@ int Feed::childCount() const { // Because feed has no children. return 0; } + +void Feed::appendChild(RootItem *child) { + Q_UNUSED(child) +} diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index df2b28776..62ba9d2b2 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -37,7 +37,9 @@ class Feed : public RootItem { enum Status { Normal = 0, NewMessages = 1, - NetworkError = 2 + NetworkError = 2, + ParsingError = 3, + OtherError = 4 }; // Constructors. @@ -47,6 +49,9 @@ class Feed : public RootItem { // Returns 0, feeds have no children. int childCount() const; + // Appending of childs to feed is not allowed. + void appendChild(RootItem *child); + // Performs synchronous update and returns number of newly updated messages. virtual int update() = 0; diff --git a/src/services/abstract/serviceentrypoint.h b/src/services/abstract/serviceentrypoint.h index f6a257989..ecfc75334 100755 --- a/src/services/abstract/serviceentrypoint.h +++ b/src/services/abstract/serviceentrypoint.h @@ -24,6 +24,7 @@ class ServiceRoot; +class FeedsModel; // TOP LEVEL class which provides basic information about the "service" class ServiceEntryPoint { @@ -36,7 +37,7 @@ class ServiceEntryPoint { // point from persistent DB. // Returns list of root nodes which will be afterwards added // to the global feed model. - virtual QList initializeSubtree() = 0; + virtual QList initializeSubtree(FeedsModel *main_model) = 0; // Must this service account be activated by default? // NOTE: This is true particularly for "standard" service diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index 109f00ead..5a455e306 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -17,10 +17,11 @@ #include "services/abstract/serviceroot.h" +#include "core/feedsmodel.h" -ServiceRoot::ServiceRoot(RootItem *parent) : RootItem(parent) { + +ServiceRoot::ServiceRoot(FeedsModel *feeds_model, RootItem *parent) : RootItem(parent), m_feedsModel(feeds_model) { } ServiceRoot::~ServiceRoot() { } - diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 1355f1fb7..94e6b472e 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -21,13 +21,22 @@ #include "core/rootitem.h" +class FeedsModel; + // THIS IS the root node of the service. // NOTE: The root usually contains some core functionality of the // service like service account username/password etc. class ServiceRoot : public RootItem { public: - explicit ServiceRoot(RootItem *parent = NULL); + explicit ServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL); virtual ~ServiceRoot(); + + inline FeedsModel *feedsModel() const { + return m_feedsModel; + } + + protected: + FeedsModel *m_feedsModel; }; #endif // SERVICEROOT_H diff --git a/src/services/standard/gui/formstandardcategorydetails.cpp b/src/services/standard/gui/formstandardcategorydetails.cpp index 34bba3718..b3fd72720 100755 --- a/src/services/standard/gui/formstandardcategorydetails.cpp +++ b/src/services/standard/gui/formstandardcategorydetails.cpp @@ -20,13 +20,14 @@ #include "definitions/definitions.h" #include "core/rootitem.h" #include "core/feedsmodel.h" -#include "services/standard/standardcategory.h" #include "miscellaneous/iconfactory.h" #include "gui/feedsview.h" #include "gui/baselineedit.h" #include "gui/messagebox.h" #include "gui/systemtrayicon.h" #include "gui/dialogs/formmain.h" +#include "services/standard/standardcategory.h" +#include "services/standard/standardserviceroot.h" #include #include @@ -38,9 +39,8 @@ #include -FormStandardCategoryDetails::FormStandardCategoryDetails(FeedsModel *model, QWidget *parent) : QDialog(parent), - m_editableCategory(NULL), - m_feedsModel(model) { +FormStandardCategoryDetails::FormStandardCategoryDetails(StandardServiceRoot *service_root, QWidget *parent) + : QDialog(parent), m_editableCategory(NULL), m_serviceRoot(service_root) { initialize(); createConnections(); @@ -76,7 +76,7 @@ void FormStandardCategoryDetails::setEditableCategory(StandardCategory *editable int FormStandardCategoryDetails::exec(StandardCategory *input_category, RootItem *parent_to_select) { // Load categories. - loadCategories(m_feedsModel->allCategories().values(), m_feedsModel->rootItem(), input_category); + loadCategories(m_serviceRoot->allCategories().values(), m_serviceRoot, input_category); if (input_category == NULL) { // User is adding new category. @@ -88,10 +88,10 @@ int FormStandardCategoryDetails::exec(StandardCategory *input_category, RootItem // Load parent from suggested item. if (parent_to_select != NULL) { - if (parent_to_select->kind() == RootItem::Cattegory) { + if (parent_to_select->kind() == RootItemKind::Category) { m_ui->m_cmbParentCategory->setCurrentIndex(m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select))); } - else if (parent_to_select->kind() == RootItem::Feeed) { + else if (parent_to_select->kind() == RootItemKind::Feed) { int target_item = m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select->parent())); if (target_item >= 0) { @@ -122,10 +122,12 @@ void FormStandardCategoryDetails::apply() { if (m_editableCategory == NULL) { // Add the category. - if (m_feedsModel->addCategory(new_category, parent)) { + if (new_category->addItself(parent)) { + m_serviceRoot->feedsModel()->assignNodeToNewParent(new_category, parent); accept(); } else { + delete new_category; qApp->showGuiMessage(tr("Cannot add category"), tr("Category was not added due to error."), QSystemTrayIcon::Critical, @@ -136,7 +138,7 @@ void FormStandardCategoryDetails::apply() { bool edited = m_editableCategory->editItself(new_category); if (edited) { - m_feedsModel->reassignNodeToNewParent(m_editableCategory, new_category->parent()); + m_serviceRoot->feedsModel()->reassignNodeToNewParent(m_editableCategory, new_category->parent()); // Remove new temporary feed data holder object. delete new_category; @@ -245,8 +247,8 @@ void FormStandardCategoryDetails::initialize() { } void FormStandardCategoryDetails::loadCategories(const QList categories, - RootItem *root_item, - StandardCategory *input_category) { + RootItem *root_item, + StandardCategory *input_category) { m_ui->m_cmbParentCategory->addItem(root_item->icon(), root_item->title(), QVariant::fromValue((void*) root_item)); diff --git a/src/services/standard/gui/formstandardcategorydetails.h b/src/services/standard/gui/formstandardcategorydetails.h index 51c9f60c4..3717b3251 100755 --- a/src/services/standard/gui/formstandardcategorydetails.h +++ b/src/services/standard/gui/formstandardcategorydetails.h @@ -28,7 +28,7 @@ namespace Ui { } class StandardCategory; -class StandardCategory; +class StandardServiceRoot; class FeedsModel; class RootItem; class QMenu; @@ -39,7 +39,7 @@ class FormStandardCategoryDetails : public QDialog { public: // Constructors and destructors. - explicit FormStandardCategoryDetails(FeedsModel *model, QWidget *parent = 0); + explicit FormStandardCategoryDetails(StandardServiceRoot *service_root, QWidget *parent = 0); virtual ~FormStandardCategoryDetails(); public slots: @@ -77,7 +77,7 @@ class FormStandardCategoryDetails : public QDialog { private: Ui::FormStandardCategoryDetails *m_ui; StandardCategory *m_editableCategory; - FeedsModel *m_feedsModel; + StandardServiceRoot *m_serviceRoot; QMenu *m_iconMenu; QAction *m_actionLoadIconFromFile; diff --git a/src/services/standard/gui/formstandardfeeddetails.cpp b/src/services/standard/gui/formstandardfeeddetails.cpp index adf3cf666..7fa6d6c8c 100755 --- a/src/services/standard/gui/formstandardfeeddetails.cpp +++ b/src/services/standard/gui/formstandardfeeddetails.cpp @@ -20,6 +20,7 @@ #include "definitions/definitions.h" #include "core/feedsmodel.h" #include "core/rootitem.h" +#include "services/standard/standardserviceroot.h" #include "services/standard/standardcategory.h" #include "services/standard/standardfeed.h" #include "miscellaneous/textfactory.h" @@ -39,10 +40,10 @@ #include -FormStandardFeedDetails::FormStandardFeedDetails(FeedsModel *model, QWidget *parent) +FormStandardFeedDetails::FormStandardFeedDetails(StandardServiceRoot *service_root, QWidget *parent) : QDialog(parent), m_editableFeed(NULL), - m_feedsModel(model) { + m_serviceRoot(service_root) { initialize(); createConnections(); @@ -60,7 +61,7 @@ FormStandardFeedDetails::~FormStandardFeedDetails() { int FormStandardFeedDetails::exec(StandardFeed *input_feed, RootItem *parent_to_select) { // Load categories. - loadCategories(m_feedsModel->allCategories().values(), m_feedsModel->rootItem()); + loadCategories(m_serviceRoot->allCategories().values(), m_serviceRoot); if (input_feed == NULL) { // User is adding new category. @@ -77,10 +78,10 @@ int FormStandardFeedDetails::exec(StandardFeed *input_feed, RootItem *parent_to_ } if (parent_to_select != NULL) { - if (parent_to_select->kind() == RootItem::Cattegory) { + if (parent_to_select->kind() == RootItemKind::Category) { m_ui->m_cmbParentCategory->setCurrentIndex(m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select))); } - else if (parent_to_select->kind() == RootItem::Feeed) { + else if (parent_to_select->kind() == RootItemKind::Feed) { int target_item = m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select->parent())); if (target_item >= 0) { @@ -240,10 +241,12 @@ void FormStandardFeedDetails::apply() { if (m_editableFeed == NULL) { // Add the feed. - if (m_feedsModel->addFeed(new_feed, parent)) { + if (new_feed->addItself(parent)) { + m_serviceRoot->feedsModel()->assignNodeToNewParent(new_feed, parent); accept(); } else { + delete new_feed; qApp->showGuiMessage(tr("Cannot add feed"), tr("Feed was not added due to error."), QSystemTrayIcon::Critical, this, true); @@ -254,7 +257,7 @@ void FormStandardFeedDetails::apply() { bool edited = m_editableFeed->editItself(new_feed); if (edited) { - m_feedsModel->reassignNodeToNewParent(m_editableFeed, new_feed->parent()); + m_serviceRoot->feedsModel()->reassignNodeToNewParent(m_editableFeed, new_feed->parent()); // Remove new temporary feed data holder object. delete new_feed; diff --git a/src/services/standard/gui/formstandardfeeddetails.h b/src/services/standard/gui/formstandardfeeddetails.h index 6b3ed95a7..d3651f969 100755 --- a/src/services/standard/gui/formstandardfeeddetails.h +++ b/src/services/standard/gui/formstandardfeeddetails.h @@ -27,7 +27,7 @@ namespace Ui { class FormStandardFeedDetails; } -class FeedsModel; +class StandardServiceRoot; class StandardFeed; class StandardCategory; class RootItem; @@ -37,7 +37,7 @@ class FormStandardFeedDetails : public QDialog { public: // Constructors and destructors. - explicit FormStandardFeedDetails(FeedsModel *model, QWidget *parent = 0); + explicit FormStandardFeedDetails(StandardServiceRoot *service_root, QWidget *parent = 0); virtual ~FormStandardFeedDetails(); public slots: @@ -84,7 +84,7 @@ class FormStandardFeedDetails : public QDialog { private: Ui::FormStandardFeedDetails *m_ui; StandardFeed *m_editableFeed; - FeedsModel *m_feedsModel; + StandardServiceRoot *m_serviceRoot; QMenu *m_iconMenu; QAction *m_actionLoadIconFromFile; diff --git a/src/services/standard/gui/formstandardimportexport.cpp b/src/services/standard/gui/formstandardimportexport.cpp index e0c4188b3..d8e4cf418 100755 --- a/src/services/standard/gui/formstandardimportexport.cpp +++ b/src/services/standard/gui/formstandardimportexport.cpp @@ -18,6 +18,7 @@ #include "services/standard/gui/formstandardimportexport.h" #include "services/standard/standardfeedsimportexportmodel.h" +#include "services/standard/standardserviceroot.h" #include "core/feedsmodel.h" #include "miscellaneous/application.h" #include "gui/feedmessageviewer.h" @@ -28,8 +29,8 @@ #include -FormStandardImportExport::FormStandardImportExport(QWidget *parent) - : QDialog(parent), m_ui(new Ui::FormStandardImportExport) { +FormStandardImportExport::FormStandardImportExport(StandardServiceRoot *service_root, QWidget *parent) + : QDialog(parent), m_ui(new Ui::FormStandardImportExport), m_serviceRoot(service_root) { m_ui->setupUi(this); m_model = new FeedsImportExportModel(m_ui->m_treeFeeds); @@ -54,7 +55,7 @@ void FormStandardImportExport::setMode(const FeedsImportExportModel::Mode &mode) switch (mode) { case FeedsImportExportModel::Export: { - m_model->setRootItem(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->rootItem()); + m_model->setRootItem(m_serviceRoot); m_model->checkAllItems(); m_ui->m_treeFeeds->setModel(m_model); m_ui->m_treeFeeds->expandAll(); @@ -117,7 +118,6 @@ void FormStandardImportExport::selectExportFile() { selected_file += QL1S(".opml"); } } - // NOTE: Add other types here. m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(selected_file), tr("File is selected.")); } @@ -141,7 +141,6 @@ void FormStandardImportExport::selectImportFile() { if (selected_filter == filter_opml20) { m_conversionType = OPML20; } - // NOTE: Add other types here. m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(selected_file), tr("File is selected.")); parseImportFile(selected_file); @@ -241,7 +240,8 @@ void FormStandardImportExport::exportFeeds() { void FormStandardImportExport::importFeeds() { QString output_message; - if (qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->mergeModel(m_model, output_message)) { + if (m_serviceRoot->mergeImportExportModel(m_model, output_message)) { + // TODO: Hate this global access, what about signal? qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->expandAll(); m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, output_message, output_message); } diff --git a/src/services/standard/gui/formstandardimportexport.h b/src/services/standard/gui/formstandardimportexport.h index fc1fa85dd..4b36f1ebc 100755 --- a/src/services/standard/gui/formstandardimportexport.h +++ b/src/services/standard/gui/formstandardimportexport.h @@ -23,11 +23,12 @@ #include "ui_formstandardimportexport.h" #include "services/standard/standardfeedsimportexportmodel.h" - namespace Ui { class FormStandardImportExport; } +class StandardServiceRoot; + class FormStandardImportExport : public QDialog { Q_OBJECT @@ -37,7 +38,7 @@ class FormStandardImportExport : public QDialog { }; // Constructors. - explicit FormStandardImportExport(QWidget *parent = 0); + explicit FormStandardImportExport(StandardServiceRoot *service_root, QWidget *parent = 0); virtual ~FormStandardImportExport(); void setMode(const FeedsImportExportModel::Mode &mode); @@ -57,6 +58,7 @@ class FormStandardImportExport : public QDialog { Ui::FormStandardImportExport *m_ui; ConversionType m_conversionType; FeedsImportExportModel *m_model; + StandardServiceRoot *m_serviceRoot; }; #endif // FORMEXPORT_H diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index 41e46b865..7d822c215 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -34,12 +34,12 @@ #include -StandardCategory::StandardCategory(RootItem *parent_item) : RootItem(parent_item) { +StandardCategory::StandardCategory(RootItem *parent_item) : Category(parent_item) { init(); } StandardCategory::StandardCategory(const StandardCategory &other) - : RootItem(NULL) { + : Category(NULL) { m_kind = other.kind(); m_id = other.id(); m_title = other.title(); @@ -55,7 +55,7 @@ StandardCategory::~StandardCategory() { } void StandardCategory::init() { - m_kind = RootItem::Cattegory; + m_kind = RootItemKind::Category; } QVariant StandardCategory::data(int column, int role) const { @@ -127,13 +127,16 @@ QVariant StandardCategory::data(int column, int role) const { } void StandardCategory::editViaDialog() { - // TODO: fix passing of the model + // TODO: předávat service root. +/* QPointer form_pointer = new FormStandardCategoryDetails(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel(), qApp->mainForm()); + form_pointer.data()->exec(this, NULL); delete form_pointer.data(); + */ } bool StandardCategory::removeItself() { @@ -230,7 +233,7 @@ bool StandardCategory::editItself(StandardCategory *new_category_data) { return true; } -StandardCategory::StandardCategory(const QSqlRecord &record) : RootItem(NULL) { +StandardCategory::StandardCategory(const QSqlRecord &record) : Category(NULL) { init(); setId(record.value(CAT_DB_ID_INDEX).toInt()); diff --git a/src/services/standard/standardcategory.h b/src/services/standard/standardcategory.h index 9affc61b6..b50f2bfaf 100755 --- a/src/services/standard/standardcategory.h +++ b/src/services/standard/standardcategory.h @@ -18,7 +18,7 @@ #ifndef FEEDSMODELCATEGORY_H #define FEEDSMODELCATEGORY_H -#include "core/rootitem.h" +#include "services/abstract/category.h" #include #include @@ -29,8 +29,8 @@ class FeedsModel; // Base class for all categories contained in FeedsModel. // NOTE: This class should be derived to create PARTICULAR category types. // NOTE: This class should not be instantiated directly. -class StandardCategory : public RootItem { - Q_DECLARE_TR_FUNCTIONS(Category) +class StandardCategory : public Category { + Q_DECLARE_TR_FUNCTIONS(StandardCategory) public: // Constructors and destructors diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 5d83d2626..6091e2f77 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -53,7 +53,7 @@ void StandardFeed::init() { m_unreadCount = 0; m_encoding = QString(); m_url = QString(); - m_kind = RootItem::Feeed; + m_kind = RootItemKind::Feed; } StandardFeed::StandardFeed(RootItem *parent_item) @@ -76,7 +76,7 @@ StandardFeed::StandardFeed(const StandardFeed &other) m_autoUpdateRemainingInterval = other.autoUpdateRemainingInterval(); m_encoding = other.encoding(); m_url = other.url(); - m_kind = RootItem::Feeed; + m_kind = RootItemKind::Feed; m_title = other.title(); m_id = other.id(); m_icon = other.icon(); @@ -100,11 +100,14 @@ int StandardFeed::countOfUnreadMessages() const { void StandardFeed::editViaDialog() { // TODO: fix passing of the model + + /* QPointer form_pointer = new FormStandardFeedDetails(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel(), qApp->mainForm()); form_pointer.data()->exec(this, NULL); delete form_pointer.data(); + */ } QString StandardFeed::typeToString(StandardFeed::Type type) { @@ -716,7 +719,7 @@ QNetworkReply::NetworkError StandardFeed::networkError() const { } StandardFeed::StandardFeed(const QSqlRecord &record) : Feed(NULL) { - m_kind = RootItem::Feeed; + m_kind = RootItemKind::Feed; setTitle(record.value(FDS_DB_TITLE_INDEX).toString()); setId(record.value(FDS_DB_ID_INDEX).toInt()); diff --git a/src/services/standard/standardfeedsimportexportmodel.cpp b/src/services/standard/standardfeedsimportexportmodel.cpp index 96c01a16f..3133be8a3 100755 --- a/src/services/standard/standardfeedsimportexportmodel.cpp +++ b/src/services/standard/standardfeedsimportexportmodel.cpp @@ -99,7 +99,7 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray &result) { } switch (child_item->kind()) { - case RootItem::Cattegory: { + case RootItemKind::Category: { QDomElement outline_category = opml_document.createElement(QSL("outline")); outline_category.setAttribute(QSL("text"), child_item->title()); outline_category.setAttribute(QSL("description"), child_item->description()); @@ -110,8 +110,8 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray &result) { break; } - case RootItem::Feeed: { - StandardFeed *child_feed = child_item->toFeed(); + case RootItemKind::Feed: { + StandardFeed *child_feed = static_cast(child_item); QDomElement outline_feed = opml_document.createElement("outline"); outline_feed.setAttribute(QSL("text"), child_feed->title()); outline_feed.setAttribute(QSL("xmlUrl"), child_feed->url()); @@ -264,7 +264,7 @@ void FeedsImportExportModel::setMode(const FeedsImportExportModel::Mode &mode) { void FeedsImportExportModel::checkAllItems() { foreach (RootItem *root_child, m_rootItem->childItems()) { - if (root_child->kind() != RootItem::Bin) { + if (root_child->kind() != RootItemKind::Bin) { setData(indexForItem(root_child), Qt::Checked, Qt::CheckStateRole); } } @@ -272,7 +272,7 @@ void FeedsImportExportModel::checkAllItems() { void FeedsImportExportModel::uncheckAllItems() { foreach (RootItem *root_child, m_rootItem->childItems()) { - if (root_child->kind() != RootItem::Bin) { + if (root_child->kind() != RootItemKind::Bin) { setData(indexForItem(root_child), Qt::Unchecked, Qt::CheckStateRole); } } @@ -295,7 +295,7 @@ QModelIndex FeedsImportExportModel::index(int row, int column, const QModelIndex } QModelIndex FeedsImportExportModel::indexForItem(RootItem *item) const { - if (item == NULL || item->kind() == RootItem::Root) { + if (item == NULL || item->kind() == RootItemKind::Root) { // Root item lies on invalid index. return QModelIndex(); } @@ -324,7 +324,7 @@ QModelIndex FeedsImportExportModel::indexForItem(RootItem *item) const { for (int i = 0; i < row_count; i++) { RootItem *possible_category = active_item->child(i); - if (possible_category->kind() == RootItem::Cattegory) { + if (possible_category->kind() == RootItemKind::Category) { parents << index(i, 0, active_index); } } @@ -362,7 +362,6 @@ int FeedsImportExportModel::rowCount(const QModelIndex &parent) const { int FeedsImportExportModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) - return 1; } @@ -383,9 +382,9 @@ QVariant FeedsImportExportModel::data(const QModelIndex &index, int role) const } else if (role == Qt::DecorationRole) { switch (item->kind()) { - case RootItem::Cattegory: - case RootItem::Bin: - case RootItem::Feeed: + case RootItemKind::Category: + case RootItemKind::Bin: + case RootItemKind::Feed: return item->icon(); default: @@ -394,10 +393,10 @@ QVariant FeedsImportExportModel::data(const QModelIndex &index, int role) const } else if (role == Qt::DisplayRole) { switch (item->kind()) { - case RootItem::Cattegory: + case RootItemKind::Category: return QVariant(item->data(index.column(), role).toString() + tr(" (category)")); - case RootItem::Feeed: + case RootItemKind::Feed: return QVariant(item->data(index.column(), role).toString() + tr(" (feed)")); default: @@ -462,7 +461,7 @@ bool FeedsImportExportModel::setData(const QModelIndex &index, const QVariant &v } Qt::ItemFlags FeedsImportExportModel::flags(const QModelIndex &index) const { - if (!index.isValid() || itemForIndex(index)->kind() == RootItem::Bin) { + if (!index.isValid() || itemForIndex(index)->kind() == RootItemKind::Bin) { return Qt::NoItemFlags; } diff --git a/src/services/standard/standardfeedsimportexportmodel.h b/src/services/standard/standardfeedsimportexportmodel.h index 972ed5e3c..e5bc8c54f 100755 --- a/src/services/standard/standardfeedsimportexportmodel.h +++ b/src/services/standard/standardfeedsimportexportmodel.h @@ -73,7 +73,6 @@ class FeedsImportExportModel : public QAbstractItemModel { QHash m_checkStates; RootItem *m_rootItem; - // When it's true, then bool m_recursiveChange; Mode m_mode; }; diff --git a/src/services/standard/standarditem.cpp b/src/services/standard/standarditem.cpp new file mode 100755 index 000000000..bde2b13d8 --- /dev/null +++ b/src/services/standard/standarditem.cpp @@ -0,0 +1,18 @@ +#include "services/standard/standarditem.h" + +#include "services/standard/standardserviceroot.h" + + +StandardItem::StandardItem(StandardServiceRoot *service_root) : m_serviceRoot(service_root) { +} + +StandardItem::~StandardItem() { +} + +StandardServiceRoot *StandardItem::serviceRoot() const { + return m_serviceRoot; +} + +void StandardItem::setServiceRoot(StandardServiceRoot *service_root) { + m_serviceRoot = service_root; +} diff --git a/src/services/standard/standarditem.h b/src/services/standard/standarditem.h new file mode 100755 index 000000000..efe3210d1 --- /dev/null +++ b/src/services/standard/standarditem.h @@ -0,0 +1,19 @@ +#ifndef STANDARDITEM_H +#define STANDARDITEM_H + + +class StandardServiceRoot; + +class StandardItem { + public: + explicit StandardItem(StandardServiceRoot *service_root); + virtual ~StandardItem(); + + StandardServiceRoot *serviceRoot() const; + void setServiceRoot(StandardServiceRoot *service_root); + + protected: + StandardServiceRoot *m_serviceRoot; +}; + +#endif // STANDARDITEM_H diff --git a/src/services/standard/standardrecyclebin.cpp b/src/services/standard/standardrecyclebin.cpp index fa26177ba..ace8c3ee9 100755 --- a/src/services/standard/standardrecyclebin.cpp +++ b/src/services/standard/standardrecyclebin.cpp @@ -25,7 +25,7 @@ StandardRecycleBin::StandardRecycleBin(RootItem *parent) : RootItem(parent) { - m_kind = RootItem::Bin; + m_kind = RootItemKind::Bin; m_icon = qApp->icons()->fromTheme(QSL("folder-recycle-bin")); m_id = ID_RECYCLE_BIN; m_title = tr("Recycle bin"); diff --git a/src/services/standard/standardserviceentrypoint.cpp b/src/services/standard/standardserviceentrypoint.cpp index 01f85fda8..de70987d7 100755 --- a/src/services/standard/standardserviceentrypoint.cpp +++ b/src/services/standard/standardserviceentrypoint.cpp @@ -69,8 +69,8 @@ QIcon StandardServiceEntryPoint::icon() { return QIcon(APP_ICON_PATH); } -QList StandardServiceEntryPoint::initializeSubtree() { - StandardServiceRoot *root = new StandardServiceRoot(); +QList StandardServiceEntryPoint::initializeSubtree(FeedsModel *main_model) { + StandardServiceRoot *root = new StandardServiceRoot(main_model); QList roots; roots.append(root); diff --git a/src/services/standard/standardserviceentrypoint.h b/src/services/standard/standardserviceentrypoint.h index 6729922dd..1bf1e1654 100755 --- a/src/services/standard/standardserviceentrypoint.h +++ b/src/services/standard/standardserviceentrypoint.h @@ -37,7 +37,7 @@ class StandardServiceEntryPoint : public ServiceEntryPoint { QString author(); QIcon icon(); - QList initializeSubtree(); + QList initializeSubtree(FeedsModel *main_model); }; #endif // STANDARDSERVICEENTRYPOINT_H diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 12592850d..adf773f35 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -20,17 +20,20 @@ #include "definitions/definitions.h" #include "miscellaneous/application.h" #include "miscellaneous/settings.h" +#include "core/feedsmodel.h" #include "services/standard/standardserviceentrypoint.h" #include "services/standard/standardrecyclebin.h" #include "services/standard/standardfeed.h" #include "services/standard/standardcategory.h" +#include "services/standard/standardfeedsimportexportmodel.h" #include #include +#include -StandardServiceRoot::StandardServiceRoot(RootItem *parent) - : ServiceRoot(parent), m_recycleBin(new StandardRecycleBin(this)) { +StandardServiceRoot::StandardServiceRoot(FeedsModel *feeds_model, RootItem *parent) + : ServiceRoot(feeds_model, parent), m_recycleBin(new StandardRecycleBin(this)) { m_title = qApp->system()->getUsername() + "@" + APP_LOW_NAME; m_icon = StandardServiceEntryPoint().icon(); @@ -113,7 +116,6 @@ QVariant StandardServiceRoot::data(int column, int role) const { } void StandardServiceRoot::loadFromDatabase(){ - // TODO: todo QSqlDatabase database = qApp->database()->connection("StandardServiceRoot", DatabaseFactory::FromSettings); CategoryAssignment categories; FeedAssignment feeds; @@ -175,8 +177,8 @@ void StandardServiceRoot::loadFromDatabase(){ appendChild(m_recycleBin); } -QHash StandardServiceRoot::categoriesForItem(RootItem *root) { - QHash categories; +QHash StandardServiceRoot::categoriesForItem(RootItem *root) { + QHash categories; QList parents; parents.append(root->childItems()); @@ -184,11 +186,11 @@ QHash StandardServiceRoot::categoriesForItem(RootItem *r while (!parents.isEmpty()) { RootItem *item = parents.takeFirst(); - if (item->kind() == RootItem::Cattegory) { + if (item->kind() == RootItemKind::Category) { // This item is category, add it to the output list and // scan its children. int category_id = item->id(); - StandardCategory *category = item->toCategory(); + StandardCategory *category = static_cast(item); if (!categories.contains(category_id)) { categories.insert(category_id, category); @@ -201,8 +203,12 @@ QHash StandardServiceRoot::categoriesForItem(RootItem *r return categories; } +QHash StandardServiceRoot::allCategories() { + return categoriesForItem(this); +} + void StandardServiceRoot::assembleFeeds(FeedAssignment feeds) { - QHash categories = categoriesForItem(this); + QHash categories = categoriesForItem(this); foreach (const FeedAssignmentItem &feed, feeds) { if (feed.first == NO_PARENT_CATEGORY) { @@ -223,6 +229,86 @@ StandardRecycleBin *StandardServiceRoot::recycleBin() const { return m_recycleBin; } +bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, QString &output_message) { + QStack original_parents; original_parents.push(this); + QStack new_parents; new_parents.push(model->rootItem()); + bool some_feed_category_error = false; + + // Iterate all new items we would like to merge into current model. + while (!new_parents.isEmpty()) { + RootItem *target_parent = original_parents.pop(); + RootItem *source_parent = new_parents.pop(); + + foreach (RootItem *source_item, source_parent->childItems()) { + if (!model->isItemChecked(source_item)) { + // We can skip this item, because it is not checked and should not be imported. + // NOTE: All descendants are thus skipped too. + continue; + } + + if (source_item->kind() == RootItemKind::Category) { + StandardCategory *source_category = static_cast(source_item); + StandardCategory *new_category = new StandardCategory(*source_category); + QString new_category_title = new_category->title(); + + // Add category to model. + new_category->clearChildren(); + + if (new_category->addItself(target_parent)) { + m_feedsModel->assignNodeToNewParent(new_category, target_parent); + + // Process all children of this category. + original_parents.push(new_category); + new_parents.push(source_category); + } + else { + delete new_category; + + // Add category failed, but this can mean that the same category (with same title) + // already exists. If such a category exists in current parent, then find it and + // add descendants to it. + RootItem *existing_category = NULL; + foreach (RootItem *child, target_parent->childItems()) { + if (child->kind() == RootItemKind::Category && child->title() == new_category_title) { + existing_category = child; + } + } + + if (existing_category != NULL) { + original_parents.push(existing_category); + new_parents.push(source_category); + } + else { + some_feed_category_error = true; + } + } + } + else if (source_item->kind() == RootItemKind::Feed) { + StandardFeed *source_feed = static_cast(source_item); + StandardFeed *new_feed = new StandardFeed(*source_feed); + + // Append this feed and end this iteration. + if (!new_feed->addItself(target_parent)) { + delete new_feed; + some_feed_category_error = true; + } + } + } + } + + // Changes are done now. Finalize the new model. + //emit layoutChanged(); + + if (some_feed_category_error) { + output_message = tr("Import successfull, but some feeds/categories were not imported due to error."); + } + else { + output_message = tr("Import was completely successfull."); + } + + return !some_feed_category_error; +} + void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { QHash assignments; assignments.insert(NO_PARENT_CATEGORY, this); @@ -235,8 +321,7 @@ void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { assignments.value(categories.at(i).first)->appendChild(categories.at(i).second); // Now, added category can be parent for another categories, add it. - assignments.insert(categories.at(i).second->id(), - categories.at(i).second); + assignments.insert(categories.at(i).second->id(), categories.at(i).second); // Remove the category from the list, because it was // added to the final collection. diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 5e1013feb..f43d08239 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -26,6 +26,7 @@ class StandardRecycleBin; class StandardCategory; class StandardFeed; +class FeedsImportExportModel; typedef QList > CategoryAssignment; typedef QPair CategoryAssignmentItem; @@ -37,7 +38,7 @@ class StandardServiceRoot : public ServiceRoot { Q_DECLARE_TR_FUNCTIONS(StandardServiceRoot) public: - explicit StandardServiceRoot(RootItem *parent = NULL); + explicit StandardServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL); virtual ~StandardServiceRoot(); bool canBeEdited(); @@ -46,11 +47,20 @@ class StandardServiceRoot : public ServiceRoot { // Returns all standard categories which are lying under given root node. // This does NOT include the root node even if the node is category. - QHash categoriesForItem(RootItem *root); + QHash categoriesForItem(RootItem *root); + + // Returns all categories from this root, each pair + // consists of ID of parent item and pointer to category. + QHash allCategories(); // Access to standard recycle bin. StandardRecycleBin *recycleBin() const; + // Takes structure residing under given root item and adds feeds/categories from + // it to active structure. + // NOTE: This is used for import/export of the model. + bool mergeImportExportModel(FeedsImportExportModel *model, QString &output_message); + private: void loadFromDatabase(); diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp index 7efd1d1f1..c37c17f2a 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.cpp +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -69,6 +69,6 @@ QIcon TtRssServiceEntryPoint::icon() { return QIcon(APP_ICON_PATH); } -QList TtRssServiceEntryPoint::initializeSubtree() { +QList TtRssServiceEntryPoint::initializeSubtree(FeedsModel *main_model) { return QList(); } diff --git a/src/services/tt-rss/ttrssserviceentrypoint.h b/src/services/tt-rss/ttrssserviceentrypoint.h index 63402ffdd..6447cc567 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.h +++ b/src/services/tt-rss/ttrssserviceentrypoint.h @@ -38,7 +38,7 @@ class TtRssServiceEntryPoint : public ServiceEntryPoint { QString author(); QIcon icon(); - QList initializeSubtree(); + QList initializeSubtree(FeedsModel *main_model); }; #endif // TTRSSSERVICEENTRYPOINT_H diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index e1e52c269..07dd463f8 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -20,9 +20,10 @@ #include "miscellaneous/application.h" #include "miscellaneous/settings.h" #include "services/tt-rss/ttrssserviceentrypoint.h" +#include "core/feedsmodel.h" -TtRssServiceRoot::TtRssServiceRoot(RootItem *parent) : ServiceRoot(parent) { +TtRssServiceRoot::TtRssServiceRoot(FeedsModel *feeds_model, RootItem *parent) : ServiceRoot(feeds_model, parent) { // TODO: nadpis se bude měnit podle nastavení uživatelského // jména a serveru tohoto ttrss učtu m_title = qApp->system()->getUsername() + "@ttrss"; diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 986c99e21..a747a9773 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -23,11 +23,13 @@ #include +class FeedsModel; + class TtRssServiceRoot : public ServiceRoot { Q_DECLARE_TR_FUNCTIONS(StandardServiceRoot) public: - explicit TtRssServiceRoot(RootItem *parent = NULL); + explicit TtRssServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL); virtual ~TtRssServiceRoot(); bool canBeEdited(); From a104844814bc0d63d4d5925e27f27d68973c2e00 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 3 Nov 2015 13:16:11 +0100 Subject: [PATCH 011/203] Some methods cleaned, work mainly on model. --- src/core/feedsmodel.cpp | 33 +++++++++---------- src/core/feedsmodel.h | 18 +++++----- src/miscellaneous/systemfactory.h | 6 ++++ src/services/abstract/feed.h | 2 ++ src/services/standard/standardfeed.cpp | 8 ++--- src/services/standard/standardserviceroot.cpp | 4 ++- 6 files changed, 39 insertions(+), 32 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 494d12bc8..79ed1d64c 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -19,10 +19,9 @@ #include "definitions/definitions.h" #include "services/abstract/feed.h" +#include "services/abstract/category.h" #include "services/abstract/serviceroot.h" -#include "services/standard/standardfeed.h" -#include "services/standard/standardcategory.h" -#include "services/standard/standardfeedsimportexportmodel.h" +#include "services/standard/standardserviceroot.h" #include "miscellaneous/textfactory.h" #include "miscellaneous/databasefactory.h" #include "miscellaneous/iconfactory.h" @@ -269,18 +268,18 @@ QList FeedsModel::feedsForScheduledUpdate(bool auto_update_now) { foreach (Feed *feed, allFeeds()) { switch (feed->autoUpdateType()) { - case StandardFeed::DontAutoUpdate: + case Feed::DontAutoUpdate: // Do not auto-update this feed ever. continue; - case StandardFeed::DefaultAutoUpdate: + case Feed::DefaultAutoUpdate: if (auto_update_now) { feeds_for_update.append(feed); } break; - case StandardFeed::SpecificAutoUpdate: + case Feed::SpecificAutoUpdate: default: int remaining_interval = feed->autoUpdateRemainingInterval(); @@ -306,8 +305,7 @@ QList FeedsModel::feedsForScheduledUpdate(bool auto_update_now) { QList FeedsModel::messagesForFeeds(const QList &feeds) { QList messages; - QSqlDatabase database = qApp->database()->connection(objectName(), - DatabaseFactory::FromSettings); + QSqlDatabase database = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings); QSqlQuery query_read_msg(database); query_read_msg.setForwardOnly(true); query_read_msg.prepare("SELECT title, url, author, date_created, contents " @@ -389,7 +387,7 @@ QModelIndex FeedsModel::indexForItem(RootItem *item) const { bool FeedsModel::hasAnyFeedNewMessages() { foreach (const Feed *feed, allFeeds()) { - if (feed->status() == StandardFeed::NewMessages) { + if (feed->status() == Feed::NewMessages) { return true; } } @@ -424,15 +422,16 @@ void FeedsModel::reloadWholeLayout() { } void FeedsModel::loadActivatedServiceAccounts() { - // Delete all childs of the root node and clear them from the memory. - qDeleteAll(m_rootItem->childItems()); - m_rootItem->clearChildren(); - + // Iterate all globally available feed "service plugins". foreach (ServiceEntryPoint *entry_point, qApp->feedServices()) { // Load all stored root nodes from the entry point and add those to the model. QList roots = entry_point->initializeSubtree(this); foreach (ServiceRoot *root, roots) { + if (SystemFactory::isInstanceOf(root)) { + + } + m_rootItem->appendChild(root); } } @@ -454,6 +453,7 @@ Feed *FeedsModel::feedForIndex(const QModelIndex &index) { } } +/* QList FeedsModel::feedsForIndexes(const QModelIndexList &indexes) { QList feeds; @@ -473,6 +473,7 @@ QList FeedsModel::feedsForIndexes(const QModelIndexList &indexes) { return feeds; } +*/ bool FeedsModel::markFeedsRead(const QList &feeds, int read) { QSqlDatabase db_handle = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings); @@ -564,10 +565,8 @@ QList FeedsModel::feedsForItem(RootItem *root) { QList feeds; foreach (RootItem *child, children) { - Feed *converted = dynamic_cast(child); - - if (converted != NULL) { - feeds.append(converted); + if (child->kind() == RootItemKind::Feed) { + feeds.append(child->toFeed()); } } diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 4470ccc0d..8bec2362c 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -27,9 +27,7 @@ class Category; -class StandardCategory; class Feed; -class FeedsImportExportModel; class QTimer; class FeedsModel : public QAbstractItemModel { @@ -62,6 +60,7 @@ class FeedsModel : public QAbstractItemModel { } // Removes item with given index. + // NOTE: Also deletes item from memory. bool removeItem(const QModelIndex &index); // Assigns item to the new parent. @@ -91,9 +90,9 @@ class FeedsModel : public QAbstractItemModel { QList feedsForItem(RootItem *root); // Returns list of ALL CHILD feeds which belong to given parent indexes. - QList feedsForIndexes(const QModelIndexList &indexes); + //QList feedsForIndexes(const QModelIndexList &indexes); - // Returns ALL CHILD feeds contained within single index. + // Returns ALL RECURSIVE CHILD feeds contained within single index. QList feedsForIndex(const QModelIndex &index); // Returns pointer to feed if it lies on given index @@ -144,7 +143,11 @@ class FeedsModel : public QAbstractItemModel { // Is executed when next auto-update round could be done. void executeNextAutoUpdate(); - protected: + signals: + // Emitted when model requests update of some feeds. + void feedsUpdateRequested(const QList feeds); + + private: // Returns converted ids of given feeds // which are suitable as IN clause for SQL queries. QStringList textualFeedIds(const QList &feeds); @@ -152,11 +155,6 @@ class FeedsModel : public QAbstractItemModel { // Loads feed/categories from the database. void loadActivatedServiceAccounts(); - signals: - // Emitted when model requests update of some feeds. - void feedsUpdateRequested(const QList feeds); - - private: RootItem *m_rootItem; QList m_headerData; QList m_tooltipData; diff --git a/src/miscellaneous/systemfactory.h b/src/miscellaneous/systemfactory.h index 90852be91..59917f0e1 100755 --- a/src/miscellaneous/systemfactory.h +++ b/src/miscellaneous/systemfactory.h @@ -86,6 +86,12 @@ class SystemFactory : public QObject { // Tries to download list with new updates. QPair checkForUpdates(); + // Check whether given pointer belongs to instance of given class or not. + template + static bool isInstanceOf(T *ptr) { + return dynamic_cast(ptr) != NULL; + } + // Checks if update is newer than current application version. static bool isUpdateNewer(const QString &update_version); diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index 62ba9d2b2..8d6c5fb40 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -58,6 +58,8 @@ class Feed : public RootItem { // Updates counts of all/unread messages for this feed. virtual void updateCounts(bool including_total_count = true, bool update_feed_statuses = true) = 0; + + inline int autoUpdateInitialInterval() const { return m_autoUpdateInitialInterval; } diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 6091e2f77..078fba56b 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -66,14 +66,10 @@ StandardFeed::StandardFeed(const StandardFeed &other) m_passwordProtected = other.passwordProtected(); m_username = other.username(); m_password = other.password(); - m_status = other.status(); m_networkError = other.networkError(); m_type = other.type(); m_totalCount = other.countOfAllMessages(); m_unreadCount = other.countOfUnreadMessages(); - m_autoUpdateType = other.autoUpdateType(); - m_autoUpdateInitialInterval = other.autoUpdateInitialInterval(); - m_autoUpdateRemainingInterval = other.autoUpdateRemainingInterval(); m_encoding = other.encoding(); m_url = other.url(); m_kind = RootItemKind::Feed; @@ -84,6 +80,10 @@ StandardFeed::StandardFeed(const StandardFeed &other) m_parentItem = other.parent(); m_creationDate = other.creationDate(); m_description = other.description(); + m_status = other.status(); + m_autoUpdateType = other.autoUpdateType(); + m_autoUpdateInitialInterval = other.autoUpdateInitialInterval(); + m_autoUpdateRemainingInterval = other.autoUpdateRemainingInterval(); } StandardFeed::~StandardFeed() { diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index adf773f35..4328ce1e6 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -34,8 +34,10 @@ StandardServiceRoot::StandardServiceRoot(FeedsModel *feeds_model, RootItem *parent) : ServiceRoot(feeds_model, parent), m_recycleBin(new StandardRecycleBin(this)) { - m_title = qApp->system()->getUsername() + "@" + APP_LOW_NAME; + m_title = qApp->system()->getUsername() + QL1S("@") + QL1S(APP_LOW_NAME); m_icon = StandardServiceEntryPoint().icon(); + m_description = tr("This is obligatory service account for standard RSS/RDF/ATOM feeds."); + m_creationDate = QDateTime::currentDateTime(); loadFromDatabase(); } From dad3cc85551d461fd139d2b50c18eb08f7bdafc7 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 3 Nov 2015 13:49:15 +0100 Subject: [PATCH 012/203] Work on model. --- src/core/feedsmodel.cpp | 39 ++++++++++++++++++++++++++++----------- src/core/feedsmodel.h | 13 +++++++++---- src/gui/feedsview.cpp | 4 ++-- 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 79ed1d64c..837e6a02c 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -231,14 +231,14 @@ bool FeedsModel::removeItem(const QModelIndex &index) { return false; } -void FeedsModel::assignNodeToNewParent(RootItem *item, RootItem *parent) { - // Get index of parent item (parent standard category). - QModelIndex parent_index = indexForItem(parent); +void FeedsModel::assignNodeToNewParent(RootItem *item, RootItem *new_parent) { + QModelIndex parent_index = indexForItem(new_parent); + int new_index_of_item = new_parent->childCount(); - // TODO: todle jde sloučit s metodou reassignNodeToNewParent. + // TODO: sloučit do funkce reassignNodeToNewParent. - beginInsertRows(parent_index, parent->childCount(), parent->childCount()); - parent->appendChild(item); + beginInsertRows(parent_index, new_index_of_item, new_index_of_item); + new_parent->appendChild(item); endInsertRows(); } @@ -246,18 +246,18 @@ void FeedsModel::reassignNodeToNewParent(RootItem *original_node, RootItem *new_ RootItem *original_parent = original_node->parent(); if (original_parent != new_parent) { - // User edited category and set it new parent item, + // User edited item and set it new parent item, // se we need to move the item in the model too. - int original_index_of_feed = original_parent->childItems().indexOf(original_node); - int new_index_of_feed = new_parent->childCount(); + int original_index_of_item = original_parent->childItems().indexOf(original_node); + int new_index_of_item = new_parent->childCount(); // Remove the original item from the model... - beginRemoveRows(indexForItem(original_parent), original_index_of_feed, original_index_of_feed); + beginRemoveRows(indexForItem(original_parent), original_index_of_item, original_index_of_item); original_parent->removeChild(original_node); endRemoveRows(); // ... and insert it under the new parent. - beginInsertRows(indexForItem(new_parent), new_index_of_feed, new_index_of_feed); + beginInsertRows(indexForItem(new_parent), new_index_of_item, new_index_of_item); new_parent->appendChild(original_node); endInsertRows(); } @@ -334,6 +334,10 @@ QList FeedsModel::messagesForFeeds(const QList &feeds) { return messages; } +QList FeedsModel::allCategories() { + return categoriesForItem(m_rootItem); +} + int FeedsModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) @@ -572,3 +576,16 @@ QList FeedsModel::feedsForItem(RootItem *root) { return feeds; } + +QList FeedsModel::categoriesForItem(RootItem *root) { + QList children = root->getRecursiveChildren(); + QList categories; + + foreach (RootItem *child, children) { + if (child->kind() == RootItemKind::Category) { + categories.append(child->toCategory()); + } + } + + return categories; +} diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 8bec2362c..3c4c6b23e 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -23,8 +23,6 @@ #include "core/messagesmodel.h" #include "core/rootitem.h" -#include - class Category; class Feed; @@ -64,7 +62,7 @@ class FeedsModel : public QAbstractItemModel { bool removeItem(const QModelIndex &index); // Assigns item to the new parent. - void assignNodeToNewParent(RootItem *item, RootItem *parent); + void assignNodeToNewParent(RootItem *item, RootItem *new_parent); // Checks if new parent node is different from one used by original node. // If it is, then it reassigns original_node to new parent. @@ -82,11 +80,18 @@ class FeedsModel : public QAbstractItemModel { // in "newspaper" mode. QList messagesForFeeds(const QList &feeds); + // Returns list of all categories contained in the model. + QList allCategories(); + + // Get list of categories from tree with particular item + // as root. + QList categoriesForItem(RootItem *root); + // Returns list of all feeds contained in the model. QList allFeeds(); // Get list of feeds from tree with particular item - // as root. If root itself is a feed, then it is returned. + // as root. QList feedsForItem(RootItem *root); // Returns list of ALL CHILD feeds which belong to given parent indexes. diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index d780bcf61..7beb4f10e 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -112,8 +112,8 @@ void FeedsView::saveExpandedStates() { // TODO: doědlat // Iterate all categories and save their expand statuses. - - /*foreach (Category *category, sourceModel()->allCategories().values()) { +/* + foreach (Category *category, sourceModel()->allCategories().values()) { settings->setValue(GROUP(Categories), QString::number(category->id()), isExpanded(model()->mapFromSource(sourceModel()->indexForItem(category)))); From bd3673615d92508c71ba4b8e76410532dad9536b Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 3 Nov 2015 14:24:07 +0100 Subject: [PATCH 013/203] Saving/loading of expand states is partially working now. --- src/core/feedsmodel.cpp | 16 ++++++++++++---- src/core/rootitem.cpp | 1 + src/core/rootitem.h | 9 +++++---- src/gui/feedsview.cpp | 22 ++++++++++++---------- src/services/abstract/serviceroot.cpp | 1 + 5 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 837e6a02c..faa773715 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -578,13 +578,21 @@ QList FeedsModel::feedsForItem(RootItem *root) { } QList FeedsModel::categoriesForItem(RootItem *root) { - QList children = root->getRecursiveChildren(); QList categories; + QList parents; - foreach (RootItem *child, children) { - if (child->kind() == RootItemKind::Category) { - categories.append(child->toCategory()); + parents.append(root); + + while (!parents.isEmpty()) { + RootItem *item = parents.takeFirst(); + + if (item->kind() == RootItemKind::Category) { + // This item is category, add it to the output list and + // scan its children. + categories.append( item->toCategory()); } + + parents.append(item->childItems()); } return categories; diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index 62f7cf587..b06e00271 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -91,6 +91,7 @@ QList RootItem::getRecursiveChildren() { // Iterate all nested categories. while (!traversable_items.isEmpty()) { RootItem *active_item = traversable_items.takeFirst(); + children.append(active_item); foreach (RootItem *child, active_item->childItems()) { if (child->childCount() == 0) { diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 812528ed9..b36cf12c5 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -28,10 +28,11 @@ class Feed; namespace RootItemKind { // Describes the kind of the item. enum Kind { - Root = 1001, - Bin = 1002, - Feed = 1003, - Category = 1004 + Root = 1001, + Bin = 1002, + Feed = 1003, + Category = 1004, + ServiceRoot = 1005 }; } diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 7beb4f10e..21dc93101 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -109,27 +109,29 @@ Feed *FeedsView::selectedFeed() const { void FeedsView::saveExpandedStates() { Settings *settings = qApp->settings(); - // TODO: doědlat - // Iterate all categories and save their expand statuses. -/* - foreach (Category *category, sourceModel()->allCategories().values()) { + foreach (Category *category, sourceModel()->allCategories()) { + QString setting_name = QString::number(qHash(category->title())) + QL1S("-") + QString::number(category->id()); + settings->setValue(GROUP(Categories), - QString::number(category->id()), + setting_name, isExpanded(model()->mapFromSource(sourceModel()->indexForItem(category)))); - }*/ + } } void FeedsView::loadExpandedStates() { Settings *settings = qApp->settings(); - // TODO: doědlat + // TODO: nastavit všechny service rooty automaticky na expanded + // toto obnáší vytvoření metody sourceModel()->serviceRoots() // Iterate all categories and save their expand statuses. - /*foreach (Category *category, sourceModel()->allCategories().values()) { + foreach (Category *category, sourceModel()->allCategories()) { + QString setting_name = QString::number(qHash(category->title())) + QL1S("-") + QString::number(category->id()); + setExpanded(model()->mapFromSource(sourceModel()->indexForItem(category)), - settings->value(GROUP(Categories), QString::number(category->id()), true).toBool()); - }*/ + settings->value(GROUP(Categories), setting_name, true).toBool()); + } } void FeedsView::invalidateReadFeedsFilter(bool set_new_value, bool show_unread_only) { diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index 5a455e306..ebd5f21d3 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -21,6 +21,7 @@ ServiceRoot::ServiceRoot(FeedsModel *feeds_model, RootItem *parent) : RootItem(parent), m_feedsModel(feeds_model) { + m_kind = RootItemKind::ServiceRoot; } ServiceRoot::~ServiceRoot() { From d89787741c7623fe6fd9ae5e34126f9cbc8f6986 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 3 Nov 2015 19:06:21 +0100 Subject: [PATCH 014/203] Fix comp on Linux. --- src/services/standard/standardserviceroot.cpp | 5 ++--- src/services/tt-rss/ttrssserviceroot.cpp | 4 +--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 4328ce1e6..666bea5c7 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -30,6 +30,7 @@ #include #include #include +#include StandardServiceRoot::StandardServiceRoot(FeedsModel *feeds_model, RootItem *parent) @@ -89,9 +90,7 @@ QVariant StandardServiceRoot::data(int column, int role) const { case Qt::ToolTipRole: if (column == FDS_MODEL_TITLE_INDEX) { - return - m_title + "\n" + - tr("This is service account for standard RSS/RDF/ATOM feeds."); + return tr("This is service account for standard RSS/RDF/ATOM feeds."); } else if (column == FDS_MODEL_COUNTS_INDEX) { //: Tooltip for "unread" column of feed list. diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 07dd463f8..f612272d2 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -82,9 +82,7 @@ QVariant TtRssServiceRoot::data(int column, int role) const { case Qt::ToolTipRole: // TODO: zobrazovat pokročile informace a statistiky. if (column == FDS_MODEL_TITLE_INDEX) { - return - m_title + "\n" + - tr("This is service account TT-RSS (TinyTiny RSS) server."); + return tr("This is service account TT-RSS (TinyTiny RSS) server."); } else if (column == FDS_MODEL_COUNTS_INDEX) { //: Tooltip for "unread" column of feed list. From 7dd09cfd8961c5df54e355e84edbbaee944db1ad Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 4 Nov 2015 06:56:26 +0100 Subject: [PATCH 015/203] Added method to feed interface to obtain all undeleted messages. --- CMakeLists.txt | 1 + src/core/feedsmodel.cpp | 26 +-------- src/core/message.cpp | 50 +++++++++++++++++ src/core/message.h | 44 +++++++++++++++ src/core/messagesmodel.h | 78 +------------------------- src/services/abstract/feed.h | 5 +- src/services/standard/standardfeed.cpp | 30 ++++++++++ src/services/standard/standardfeed.h | 4 +- 8 files changed, 135 insertions(+), 103 deletions(-) create mode 100755 src/core/message.cpp create mode 100755 src/core/message.h diff --git a/CMakeLists.txt b/CMakeLists.txt index cd6c78b8a..6e387d3d8 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -413,6 +413,7 @@ set(APP_SOURCES src/core/parsingfactory.cpp src/core/feeddownloader.cpp src/core/feedsselection.cpp + src/core/message.cpp # ABSTRACT service sources. src/services/abstract/serviceentrypoint.cpp diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index faa773715..7f136c76e 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -305,30 +305,8 @@ QList FeedsModel::feedsForScheduledUpdate(bool auto_update_now) { QList FeedsModel::messagesForFeeds(const QList &feeds) { QList messages; - QSqlDatabase database = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings); - QSqlQuery query_read_msg(database); - query_read_msg.setForwardOnly(true); - query_read_msg.prepare("SELECT title, url, author, date_created, contents " - "FROM Messages " - "WHERE is_deleted = 0 AND feed = :feed;"); - - foreach (Feed *feed, feeds) { - query_read_msg.bindValue(QSL(":feed"), feed->id()); - - if (query_read_msg.exec()) { - while (query_read_msg.next()) { - Message message; - - message.m_feedId = feed->id(); - message.m_title = query_read_msg.value(0).toString(); - message.m_url = query_read_msg.value(1).toString(); - message.m_author = query_read_msg.value(2).toString(); - message.m_created = TextFactory::parseDateTime(query_read_msg.value(3).value()); - message.m_contents = query_read_msg.value(4).toString(); - - messages.append(message); - } - } + foreach (const Feed *feed, feeds) { + messages.append(feed->undeletedMessages()); } return messages; diff --git a/src/core/message.cpp b/src/core/message.cpp new file mode 100755 index 000000000..0dbcc1e86 --- /dev/null +++ b/src/core/message.cpp @@ -0,0 +1,50 @@ +#include "core/message.h" + + +Enclosure::Enclosure(const QString &url, const QString &mime) : m_url(url), m_mimeType(mime) { +} + +QList Enclosures::decodeEnclosuresFromString(const QString &enclosures_data) { + QList enclosures; + + foreach (const QString &single_enclosure, enclosures_data.split(ENCLOSURES_OUTER_SEPARATOR, QString::SkipEmptyParts)) { + Enclosure enclosure; + + if (single_enclosure.contains(ECNLOSURES_INNER_SEPARATOR)) { + QStringList mime_url = single_enclosure.split(ECNLOSURES_INNER_SEPARATOR); + + enclosure.m_mimeType = QByteArray::fromBase64(mime_url.at(0).toLocal8Bit()); + enclosure.m_url = QByteArray::fromBase64(mime_url.at(1).toLocal8Bit()); + } + else { + enclosure.m_url = QByteArray::fromBase64(single_enclosure.toLocal8Bit()); + } + + enclosures.append(enclosure); + } + + return enclosures; +} + +QString Enclosures::encodeEnclosuresToString(const QList &enclosures) { + QStringList enclosures_str; + + foreach (const Enclosure &enclosure, enclosures) { + if (enclosure.m_mimeType.isEmpty()) { + enclosures_str.append(enclosure.m_url.toLocal8Bit().toBase64()); + } + else { + enclosures_str.append(QString(enclosure.m_mimeType.toLocal8Bit().toBase64()) + + ECNLOSURES_INNER_SEPARATOR + + enclosure.m_url.toLocal8Bit().toBase64()); + } + } + + return enclosures_str.join(QString(ENCLOSURES_OUTER_SEPARATOR)); +} + +Message::Message() { + m_title = m_url = m_author = m_contents = ""; + m_feedId = 0; + m_enclosures = QList(); +} diff --git a/src/core/message.h b/src/core/message.h new file mode 100755 index 000000000..f76a4544f --- /dev/null +++ b/src/core/message.h @@ -0,0 +1,44 @@ +#ifndef MESSAGE_H +#define MESSAGE_H + +#include "definitions/definitions.h" + +#include +#include + +// Represents single enclosuresh + +struct Enclosure { + QString m_url; + QString m_mimeType; + + explicit Enclosure(const QString &url = QString(), const QString &mime = QString()); +}; + +// Represents single enclosure. +class Enclosures { + public: + static QList decodeEnclosuresFromString(const QString &enclosures_data); + static QString encodeEnclosuresToString(const QList &enclosures); +}; + +// Represents single message. +class Message { + public: + explicit Message(); + + QString m_title; + QString m_url; + QString m_author; + QString m_contents; + QDateTime m_created; + int m_feedId; + + QList m_enclosures; + + // Is true if "created" date was obtained directly + // from the feed, otherwise is false + bool m_createdFromFeed; +}; + +#endif // MESSAGE_H diff --git a/src/core/messagesmodel.h b/src/core/messagesmodel.h index 3c2138d7c..ad0d42a24 100755 --- a/src/core/messagesmodel.h +++ b/src/core/messagesmodel.h @@ -21,89 +21,13 @@ #include "definitions/definitions.h" #include "core/feedsselection.h" +#include "core/message.h" #include #include #include -#include -// Represents single enclosuresh - -struct Enclosure { - QString m_url; - QString m_mimeType; - - explicit Enclosure(const QString &url = QString(), const QString &mime = QString()) : m_url(url), m_mimeType(mime) { - } -}; - -// Represents single enclosure. -class Enclosures { - public: - static QList decodeEnclosuresFromString(const QString &enclosures_data) { - QList enclosures; - - foreach (const QString &single_enclosure, enclosures_data.split(ENCLOSURES_OUTER_SEPARATOR, QString::SkipEmptyParts)) { - Enclosure enclosure; - - if (single_enclosure.contains(ECNLOSURES_INNER_SEPARATOR)) { - QStringList mime_url = single_enclosure.split(ECNLOSURES_INNER_SEPARATOR); - - enclosure.m_mimeType = QByteArray::fromBase64(mime_url.at(0).toLocal8Bit()); - enclosure.m_url = QByteArray::fromBase64(mime_url.at(1).toLocal8Bit()); - } - else { - enclosure.m_url = QByteArray::fromBase64(single_enclosure.toLocal8Bit()); - } - - enclosures.append(enclosure); - } - - return enclosures; - } - - static QString encodeEnclosuresToString(const QList &enclosures) { - QStringList enclosures_str; - - foreach (const Enclosure &enclosure, enclosures) { - if (enclosure.m_mimeType.isEmpty()) { - enclosures_str.append(enclosure.m_url.toLocal8Bit().toBase64()); - } - else { - enclosures_str.append(QString(enclosure.m_mimeType.toLocal8Bit().toBase64()) + - ECNLOSURES_INNER_SEPARATOR + - enclosure.m_url.toLocal8Bit().toBase64()); - } - } - - return enclosures_str.join(QString(ENCLOSURES_OUTER_SEPARATOR)); - } -}; - -// Represents single message. -class Message { - public: - explicit Message() { - m_title = m_url = m_author = m_contents = ""; - m_feedId = 0; - m_enclosures = QList(); - } - - QString m_title; - QString m_url; - QString m_author; - QString m_contents; - QDateTime m_created; - int m_feedId; - - QList m_enclosures; - - // Is true if "created" date was obtained directly - // from the feed, otherwise is false - bool m_createdFromFeed; -}; - class MessagesModel : public QSqlTableModel { Q_OBJECT diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index 8d6c5fb40..ad41f8d04 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -20,6 +20,8 @@ #include "core/rootitem.h" +#include "core/message.h" + // Base class for "feed" nodes. class Feed : public RootItem { @@ -58,7 +60,8 @@ class Feed : public RootItem { // Updates counts of all/unread messages for this feed. virtual void updateCounts(bool including_total_count = true, bool update_feed_statuses = true) = 0; - + // Get ALL undeleted messages from this feed in one single list. + virtual QList undeletedMessages() const = 0; inline int autoUpdateInitialInterval() const { return m_autoUpdateInitialInterval; diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 078fba56b..a8bd20436 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -110,6 +110,36 @@ void StandardFeed::editViaDialog() { */ } +QList StandardFeed::undeletedMessages() const { + QList messages; + + QSqlDatabase database = qApp->database()->connection("StandardFeed", DatabaseFactory::FromSettings); + QSqlQuery query_read_msg(database); + query_read_msg.setForwardOnly(true); + query_read_msg.prepare("SELECT title, url, author, date_created, contents " + "FROM Messages " + "WHERE is_deleted = 0 AND feed = :feed;"); + + query_read_msg.bindValue(QSL(":feed"), id()); + + if (query_read_msg.exec()) { + while (query_read_msg.next()) { + Message message; + + message.m_feedId = id(); + message.m_title = query_read_msg.value(0).toString(); + message.m_url = query_read_msg.value(1).toString(); + message.m_author = query_read_msg.value(2).toString(); + message.m_created = TextFactory::parseDateTime(query_read_msg.value(3).value()); + message.m_contents = query_read_msg.value(4).toString(); + + messages.append(message); + } + } + + return messages; +} + QString StandardFeed::typeToString(StandardFeed::Type type) { switch (type) { case Atom10: diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index 52fe743b5..4696709a1 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -68,6 +68,8 @@ class StandardFeed : public Feed { void editViaDialog(); + QList undeletedMessages() const; + // Obtains data related to this feed. QVariant data(int column, int role) const; @@ -157,7 +159,7 @@ class StandardFeed : public Feed { private: void init(); - private: + private: bool m_passwordProtected; QString m_username; QString m_password; From d48873ab45e4f6a0ecefa863714b13afa4bd79cd Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 4 Nov 2015 08:42:52 +0100 Subject: [PATCH 016/203] Unified category/feed accessors in model. --- src/core/feedsmodel.cpp | 26 +++++++++----------------- src/core/feedsmodel.h | 2 +- src/core/feedsselection.cpp | 2 +- src/core/rootitem.cpp | 34 +++++++++------------------------- src/core/rootitem.h | 4 +++- src/gui/feedsview.cpp | 2 ++ 6 files changed, 25 insertions(+), 45 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 7f136c76e..826eb2d6e 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -312,10 +312,6 @@ QList FeedsModel::messagesForFeeds(const QList &feeds) { return messages; } -QList FeedsModel::allCategories() { - return categoriesForItem(m_rootItem); -} - int FeedsModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) @@ -543,7 +539,7 @@ QList FeedsModel::allFeeds() { } QList FeedsModel::feedsForItem(RootItem *root) { - QList children = root->getRecursiveChildren(); + QList children = root->getSubTree(); QList feeds; foreach (RootItem *child, children) { @@ -555,22 +551,18 @@ QList FeedsModel::feedsForItem(RootItem *root) { return feeds; } +QList FeedsModel::allCategories() { + return categoriesForItem(m_rootItem); +} + QList FeedsModel::categoriesForItem(RootItem *root) { + QList children = root->getSubTree(); QList categories; - QList parents; - parents.append(root); - - while (!parents.isEmpty()) { - RootItem *item = parents.takeFirst(); - - if (item->kind() == RootItemKind::Category) { - // This item is category, add it to the output list and - // scan its children. - categories.append( item->toCategory()); + foreach (RootItem *child, children) { + if (child->kind() == RootItemKind::Category) { + categories.append(child->toCategory()); } - - parents.append(item->childItems()); } return categories; diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 3c4c6b23e..57f413307 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -20,7 +20,7 @@ #include -#include "core/messagesmodel.h" +#include "core/message.h" #include "core/rootitem.h" diff --git a/src/core/feedsselection.cpp b/src/core/feedsselection.cpp index ba563eb95..8b3b1c31d 100755 --- a/src/core/feedsselection.cpp +++ b/src/core/feedsselection.cpp @@ -58,7 +58,7 @@ RootItem *FeedsSelection::selectedItem() const { QString FeedsSelection::generateListOfIds() { if (m_selectedItem != NULL && (m_selectedItem->kind() == RootItemKind::Feed || m_selectedItem->kind() == RootItemKind::Category)) { - QList children = m_selectedItem->getRecursiveChildren(); + QList children = m_selectedItem->getSubTree(); QStringList stringy_ids; foreach (RootItem *child, children) { diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index b06e00271..1192110bd 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -74,36 +74,20 @@ int RootItem::countOfAllMessages() const { return total_count; } -QList RootItem::getRecursiveChildren() { +QList RootItem::getSubTree() { QList children; - if (childCount() == 0) { - // Root itself has no children, it is either feed or - // empty category? - children.append(this); - } - else { - // Root itself is a CATEGORY or ROOT item. - QList traversable_items; + // Root itself is a CATEGORY or ROOT item. + QList traversable_items; - traversable_items.append(this); + traversable_items.append(this); - // Iterate all nested categories. - while (!traversable_items.isEmpty()) { - RootItem *active_item = traversable_items.takeFirst(); - children.append(active_item); + // Iterate all nested categories. + while (!traversable_items.isEmpty()) { + RootItem *active_item = traversable_items.takeFirst(); - foreach (RootItem *child, active_item->childItems()) { - if (child->childCount() == 0) { - // This child is feed or empty category. - children.append(child); - } - else { - // This child is category, add its child feeds too. - traversable_items.append(child); - } - } - } + children.append(active_item); + traversable_items.append(active_item->childItems()); } return children; diff --git a/src/core/rootitem.h b/src/core/rootitem.h index b36cf12c5..8f6988be0 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -138,7 +138,9 @@ class RootItem { m_childItems.clear(); } - QList getRecursiveChildren(); + // Returns flat list of all items from subtree where this item is a root. + // Returned list includes this item too. + QList getSubTree(); // Removes particular child at given index. // NOTE: Child is NOT freed from the memory. diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 21dc93101..ac1359377 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -330,12 +330,14 @@ void FeedsView::markAllFeedsRead() { void FeedsView::fetchMetadataForSelectedFeed() { // TODO: fix + /* StandardFeed *selected_feed = (StandardFeed*) selectedFeed(); if (selected_feed != NULL) { selected_feed->fetchMetadataForItself(); m_sourceModel->reloadChangedLayout(QModelIndexList() << m_proxyModel->mapToSource(selectionModel()->selectedRows(0).at(0))); } + */ } void FeedsView::clearAllReadMessages() { From 0176a73e51756d83d2ba7b2d4cc2646d0ed1574a Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 4 Nov 2015 09:12:40 +0100 Subject: [PATCH 017/203] Tweaked README, refactored root item & model. --- README.md | 4 +- src/core/feedsmodel.cpp | 33 ++-------------- src/core/feedsmodel.h | 8 ---- src/core/feedsselection.cpp | 8 ++-- src/core/rootitem.cpp | 44 ++++++++++++++++++++-- src/core/rootitem.h | 12 +++++- src/services/abstract/feed.h | 7 ++++ src/services/standard/standardcategory.cpp | 3 +- src/services/standard/standardcategory.h | 2 +- src/services/standard/standardfeed.cpp | 3 +- src/services/standard/standardfeed.h | 2 +- src/services/tt-rss/ttrssserviceroot.cpp | 3 +- src/services/tt-rss/ttrssserviceroot.h | 4 +- 13 files changed, 75 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 0ab270a00..716888781 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,4 @@ RSS Guard is written in C++. It is pretty fast even with tons of messages loaded Philosophy ---------- -RSS Guard tends to be independent software. It's free, it's open-source. RSS Guard will never depend on other services - this includes online news aggregators like Feedly, The Old Reader and others. - -That's why RSS Guard will never integrate those services unless someone else codes support for them on his own. Remember, RSS Guard supports online synchronization via MySQL/MariaDB or you can use Dropbox to synchronize SQLite data storage. \ No newline at end of file +RSS Guard tends to be independent software. It's free, it's open-source. RSS Guard accepts donations but only to SUPPORT its development. \ No newline at end of file diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 826eb2d6e..feea8347a 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -416,8 +416,7 @@ void FeedsModel::loadActivatedServiceAccounts() { } QList FeedsModel::feedsForIndex(const QModelIndex &index) { - RootItem *item = itemForIndex(index); - return feedsForItem(item); + return itemForIndex(index)->getSubTreeFeeds(); } Feed *FeedsModel::feedForIndex(const QModelIndex &index) { @@ -535,35 +534,9 @@ bool FeedsModel::markFeedsDeleted(const QList &feeds, int deleted, bool r } QList FeedsModel::allFeeds() { - return feedsForItem(m_rootItem); -} - -QList FeedsModel::feedsForItem(RootItem *root) { - QList children = root->getSubTree(); - QList feeds; - - foreach (RootItem *child, children) { - if (child->kind() == RootItemKind::Feed) { - feeds.append(child->toFeed()); - } - } - - return feeds; + return m_rootItem->getSubTreeFeeds(); } QList FeedsModel::allCategories() { - return categoriesForItem(m_rootItem); -} - -QList FeedsModel::categoriesForItem(RootItem *root) { - QList children = root->getSubTree(); - QList categories; - - foreach (RootItem *child, children) { - if (child->kind() == RootItemKind::Category) { - categories.append(child->toCategory()); - } - } - - return categories; + return m_rootItem->getSubTreeCategories(); } diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 57f413307..c7540410b 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -83,17 +83,9 @@ class FeedsModel : public QAbstractItemModel { // Returns list of all categories contained in the model. QList allCategories(); - // Get list of categories from tree with particular item - // as root. - QList categoriesForItem(RootItem *root); - // Returns list of all feeds contained in the model. QList allFeeds(); - // Get list of feeds from tree with particular item - // as root. - QList feedsForItem(RootItem *root); - // Returns list of ALL CHILD feeds which belong to given parent indexes. //QList feedsForIndexes(const QModelIndexList &indexes); diff --git a/src/core/feedsselection.cpp b/src/core/feedsselection.cpp index 8b3b1c31d..c21d6e0ac 100755 --- a/src/core/feedsselection.cpp +++ b/src/core/feedsselection.cpp @@ -58,13 +58,11 @@ RootItem *FeedsSelection::selectedItem() const { QString FeedsSelection::generateListOfIds() { if (m_selectedItem != NULL && (m_selectedItem->kind() == RootItemKind::Feed || m_selectedItem->kind() == RootItemKind::Category)) { - QList children = m_selectedItem->getSubTree(); + QList children = m_selectedItem->getSubTreeFeeds(); QStringList stringy_ids; - foreach (RootItem *child, children) { - if (child->kind() == RootItemKind::Feed) { - stringy_ids.append(QString::number(child->id())); - } + foreach (Feed *child, children) { + stringy_ids.append(QString::number(child->id())); } return stringy_ids.join(QSL(", ")); diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index 1192110bd..a6b13d141 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -76,13 +76,11 @@ int RootItem::countOfAllMessages() const { QList RootItem::getSubTree() { QList children; - - // Root itself is a CATEGORY or ROOT item. QList traversable_items; traversable_items.append(this); - // Iterate all nested categories. + // Iterate all nested items. while (!traversable_items.isEmpty()) { RootItem *active_item = traversable_items.takeFirst(); @@ -93,6 +91,46 @@ QList RootItem::getSubTree() { return children; } +QList RootItem::getSubTreeCategories() { + QList children; + QList traversable_items; + + traversable_items.append(this); + + // Iterate all nested items. + while (!traversable_items.isEmpty()) { + RootItem *active_item = traversable_items.takeFirst(); + + if (active_item->kind() == RootItemKind::Category) { + children.append(active_item->toCategory()); + } + + traversable_items.append(active_item->childItems()); + } + + return children; +} + +QList RootItem::getSubTreeFeeds() { + QList children; + QList traversable_items; + + traversable_items.append(this); + + // Iterate all nested items. + while (!traversable_items.isEmpty()) { + RootItem *active_item = traversable_items.takeFirst(); + + if (active_item->kind() == RootItemKind::Feed) { + children.append(active_item->toFeed()); + } + + traversable_items.append(active_item->childItems()); + } + + return children; +} + bool RootItem::removeChild(RootItem *child) { return m_childItems.removeOne(child); } diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 8f6988be0..9491033e0 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -67,15 +67,21 @@ class RootItem { child->setParent(this); } + // TODO: pracovat s těmito věcmi virtual bool canBeEdited() { return false; } + virtual bool editViaDialog() { + return false; + } + virtual bool canBeDeleted() { return false; } - virtual void editViaDialog() { + virtual bool deleteViaGui() { + return false; } virtual int row() const; @@ -141,6 +147,8 @@ class RootItem { // Returns flat list of all items from subtree where this item is a root. // Returned list includes this item too. QList getSubTree(); + QList getSubTreeCategories(); + QList getSubTreeFeeds(); // Removes particular child at given index. // NOTE: Child is NOT freed from the memory. @@ -151,7 +159,7 @@ class RootItem { return m_kind; } - // Each item has icon. + // Each item can have icon. inline QIcon icon() const { return m_icon; } diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index ad41f8d04..f239b48bc 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -44,6 +44,11 @@ class Feed : public RootItem { OtherError = 4 }; + enum ReadStatus { + Read = 0, + Unread = 1 + }; + // Constructors. explicit Feed(RootItem *parent = NULL); virtual ~Feed(); @@ -63,6 +68,8 @@ class Feed : public RootItem { // Get ALL undeleted messages from this feed in one single list. virtual QList undeletedMessages() const = 0; + //virtual bool markRead(ReadStatus read_status) = 0; + inline int autoUpdateInitialInterval() const { return m_autoUpdateInitialInterval; } diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index 7d822c215..b321eeed0 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -126,7 +126,7 @@ QVariant StandardCategory::data(int column, int role) const { } } -void StandardCategory::editViaDialog() { +bool StandardCategory::editViaDialog() { // TODO: předávat service root. /* QPointer form_pointer = new FormStandardCategoryDetails(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel(), @@ -137,6 +137,7 @@ void StandardCategory::editViaDialog() { delete form_pointer.data(); */ + return false; } bool StandardCategory::removeItself() { diff --git a/src/services/standard/standardcategory.h b/src/services/standard/standardcategory.h index b50f2bfaf..4f1cd8e41 100755 --- a/src/services/standard/standardcategory.h +++ b/src/services/standard/standardcategory.h @@ -50,7 +50,7 @@ class StandardCategory : public Category { return true; } - void editViaDialog(); + bool editViaDialog(); // Removes category and all its children from persistent // database. diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index a8bd20436..86104f076 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -98,7 +98,7 @@ int StandardFeed::countOfUnreadMessages() const { return m_unreadCount; } -void StandardFeed::editViaDialog() { +bool StandardFeed::editViaDialog() { // TODO: fix passing of the model /* @@ -108,6 +108,7 @@ void StandardFeed::editViaDialog() { delete form_pointer.data(); */ + return false; } QList StandardFeed::undeletedMessages() const { diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index 4696709a1..9196f069a 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -66,7 +66,7 @@ class StandardFeed : public Feed { return true; } - void editViaDialog(); + bool editViaDialog(); QList undeletedMessages() const; diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index f612272d2..fbb350b7b 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -33,8 +33,9 @@ TtRssServiceRoot::TtRssServiceRoot(FeedsModel *feeds_model, RootItem *parent) : TtRssServiceRoot::~TtRssServiceRoot() { } -void TtRssServiceRoot::editViaDialog() { +bool TtRssServiceRoot::editViaDialog() { // TODO: zobrazit custom edit dialog pro ttrss + return false; } bool TtRssServiceRoot::canBeEdited() { diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index a747a9773..b8259193d 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -26,7 +26,7 @@ class FeedsModel; class TtRssServiceRoot : public ServiceRoot { - Q_DECLARE_TR_FUNCTIONS(StandardServiceRoot) + Q_DECLARE_TR_FUNCTIONS(TtRssServiceRoot) public: explicit TtRssServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL); @@ -34,7 +34,7 @@ class TtRssServiceRoot : public ServiceRoot { bool canBeEdited(); bool canBeDeleted(); - void editViaDialog(); + bool editViaDialog(); QVariant data(int column, int role) const; }; From f85b723b4336e34ec1c1c510c5a779cdd121c3b1 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 4 Nov 2015 09:35:49 +0100 Subject: [PATCH 018/203] Unified methods for getting subtrees. --- src/core/feedsmodel.cpp | 46 +++++++++++++++++++++-------------------- src/core/feedsmodel.h | 17 ++++++++++++--- src/core/rootitem.cpp | 29 ++++++++++++++++++++++++-- src/core/rootitem.h | 18 +++++++++++----- src/gui/feedsview.cpp | 26 +++++++++++++---------- 5 files changed, 93 insertions(+), 43 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index feea8347a..e94e245fe 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -263,6 +263,30 @@ void FeedsModel::reassignNodeToNewParent(RootItem *original_node, RootItem *new_ } } +QList FeedsModel::serviceRoots() { + QList roots; + + foreach (RootItem *root, m_rootItem->childItems()) { + if (root->kind() == RootItemKind::ServiceRoot) { + roots.append(root->toServiceRoot()); + } + } + + return roots; +} + +StandardServiceRoot *FeedsModel::standardServiceRoot() { + foreach (RootItem *root, m_rootItem->childItems()) { + StandardServiceRoot *std_service_root; + + if ((std_service_root = dynamic_cast(root)) != NULL) { + return std_service_root; + } + } + + return NULL; +} + QList FeedsModel::feedsForScheduledUpdate(bool auto_update_now) { QList feeds_for_update; @@ -430,28 +454,6 @@ Feed *FeedsModel::feedForIndex(const QModelIndex &index) { } } -/* -QList FeedsModel::feedsForIndexes(const QModelIndexList &indexes) { - QList feeds; - - // Get selected feeds for each index. - foreach (const QModelIndex &index, indexes) { - feeds.append(feedsForIndex(index)); - } - - // Now we obtained all feeds from corresponding indexes. - if (indexes.size() != feeds.size()) { - // Selection contains duplicate feeds (for - // example situation where feed and its parent category are both - // selected). So, remove duplicates from the list. - qSort(feeds.begin(), feeds.end(), RootItem::lessThan); - feeds.erase(std::unique(feeds.begin(), feeds.end(), RootItem::isEqual), feeds.end()); - } - - return feeds; -} -*/ - bool FeedsModel::markFeedsRead(const QList &feeds, int read) { QSqlDatabase db_handle = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings); diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index c7540410b..55173ee79 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -26,6 +26,8 @@ class Category; class Feed; +class ServiceRoot; +class StandardServiceRoot; class QTimer; class FeedsModel : public QAbstractItemModel { @@ -68,6 +70,15 @@ class FeedsModel : public QAbstractItemModel { // If it is, then it reassigns original_node to new parent. void reassignNodeToNewParent(RootItem *original_node, RootItem *new_parent); + // Returns all activated service roots. + // NOTE: Service root nodes are lying directly UNDER + // the model root item. + QList serviceRoots(); + + // Direct and the only global accessor to standard service root. + // NOTE: Standard service root is always activated. + StandardServiceRoot *standardServiceRoot(); + // Returns the list of feeds which should be updated // according to auto-update schedule. // Variable "auto_update_now" is true, when global timeout @@ -86,9 +97,6 @@ class FeedsModel : public QAbstractItemModel { // Returns list of all feeds contained in the model. QList allFeeds(); - // Returns list of ALL CHILD feeds which belong to given parent indexes. - //QList feedsForIndexes(const QModelIndexList &indexes); - // Returns ALL RECURSIVE CHILD feeds contained within single index. QList feedsForIndex(const QModelIndex &index); @@ -105,6 +113,9 @@ class FeedsModel : public QAbstractItemModel { RootItem *itemForIndex(const QModelIndex &index) const; // Returns source QModelIndex on which lies given item. + // NOTE: This goes through all available indexes and + // checks their bound items manually, there is no + // other way to to this. QModelIndex indexForItem(RootItem *item) const; // Determines if any feed has any new messages. diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index a6b13d141..a46f0a906 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -17,8 +17,9 @@ #include "core/rootitem.h" -#include "services/standard/standardcategory.h" -#include "services/standard/standardfeed.h" +#include "services/abstract/serviceroot.h" +#include "services/abstract/feed.h" +#include "services/abstract/category.h" #include "miscellaneous/application.h" #include @@ -91,6 +92,26 @@ QList RootItem::getSubTree() { return children; } +QList RootItem::getSubTree(RootItemKind::Kind kind_of_item) { + QList children; + QList traversable_items; + + traversable_items.append(this); + + // Iterate all nested items. + while (!traversable_items.isEmpty()) { + RootItem *active_item = traversable_items.takeFirst(); + + if ((active_item->kind() & kind_of_item) > 0) { + children.append(active_item); + } + + traversable_items.append(active_item->childItems()); + } + + return children; +} + QList RootItem::getSubTreeCategories() { QList children; QList traversable_items; @@ -143,6 +164,10 @@ Feed *RootItem::toFeed() { return static_cast(this); } +ServiceRoot *RootItem::toServiceRoot() { + return static_cast(this); +} + int RootItem::countOfUnreadMessages() const { int total_count = 0; diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 9491033e0..163e80ce9 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -22,18 +22,24 @@ #include #include + class Category; class Feed; +class ServiceRoot; namespace RootItemKind { // Describes the kind of the item. enum Kind { - Root = 1001, - Bin = 1002, - Feed = 1003, - Category = 1004, - ServiceRoot = 1005 + Root = 1, + Bin = 2, + Feed = 4, + Category = 8, + ServiceRoot = 16 }; + + inline Kind operator|(Kind a, Kind b) { + return static_cast(static_cast(a) | static_cast(b)); + } } // Represents ROOT item of FeedsModel. @@ -147,6 +153,7 @@ class RootItem { // Returns flat list of all items from subtree where this item is a root. // Returned list includes this item too. QList getSubTree(); + QList getSubTree(RootItemKind::Kind kind_of_item); QList getSubTreeCategories(); QList getSubTreeFeeds(); @@ -205,6 +212,7 @@ class RootItem { // Converters Category *toCategory(); Feed *toFeed(); + ServiceRoot *toServiceRoot(); // Compares two model items. static bool isEqual(RootItem *lhs, RootItem *rhs); diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index ac1359377..d69e1ea53 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -91,9 +91,10 @@ RootItem *FeedsView::selectedItem() const { if (selected_rows.isEmpty()) { return NULL; } - - RootItem *selected_item = m_sourceModel->itemForIndex(m_proxyModel->mapToSource(selected_rows.at(0))); - return selected_item == m_sourceModel->rootItem() ? NULL : selected_item; + else { + RootItem *selected_item = m_sourceModel->itemForIndex(m_proxyModel->mapToSource(selected_rows.at(0))); + return selected_item == m_sourceModel->rootItem() ? NULL : selected_item; + } } Category *FeedsView::selectedCategory() const { @@ -108,28 +109,31 @@ Feed *FeedsView::selectedFeed() const { void FeedsView::saveExpandedStates() { Settings *settings = qApp->settings(); + QList expandable_items; + + expandable_items.append(sourceModel()->rootItem()->getSubTree(RootItemKind::Category)); // Iterate all categories and save their expand statuses. - foreach (Category *category, sourceModel()->allCategories()) { - QString setting_name = QString::number(qHash(category->title())) + QL1S("-") + QString::number(category->id()); + foreach (RootItem *item, expandable_items) { + QString setting_name = QString::number(qHash(item->title())) + QL1S("-") + QString::number(item->id()); settings->setValue(GROUP(Categories), setting_name, - isExpanded(model()->mapFromSource(sourceModel()->indexForItem(category)))); + isExpanded(model()->mapFromSource(sourceModel()->indexForItem(item)))); } } void FeedsView::loadExpandedStates() { Settings *settings = qApp->settings(); + QList expandable_items; - // TODO: nastavit všechny service rooty automaticky na expanded - // toto obnáší vytvoření metody sourceModel()->serviceRoots() + expandable_items.append(sourceModel()->rootItem()->getSubTree(RootItemKind::Category | RootItemKind::ServiceRoot)); // Iterate all categories and save their expand statuses. - foreach (Category *category, sourceModel()->allCategories()) { - QString setting_name = QString::number(qHash(category->title())) + QL1S("-") + QString::number(category->id()); + foreach (RootItem *item, expandable_items) { + QString setting_name = QString::number(qHash(item->title())) + QL1S("-") + QString::number(item->id()); - setExpanded(model()->mapFromSource(sourceModel()->indexForItem(category)), + setExpanded(model()->mapFromSource(sourceModel()->indexForItem(item)), settings->value(GROUP(Categories), setting_name, true).toBool()); } } From 80dbf26e626557da6402e0f911d938d481c08f77 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 4 Nov 2015 09:38:07 +0100 Subject: [PATCH 019/203] Added some licenses. --- src/core/message.cpp | 17 +++++++++++++++++ src/core/message.h | 19 ++++++++++++++++++- src/gui/feedsview.h | 1 - src/services/abstract/category.cpp | 17 +++++++++++++++++ src/services/abstract/category.h | 17 +++++++++++++++++ 5 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/core/message.cpp b/src/core/message.cpp index 0dbcc1e86..59ad7a598 100755 --- a/src/core/message.cpp +++ b/src/core/message.cpp @@ -1,3 +1,20 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + #include "core/message.h" diff --git a/src/core/message.h b/src/core/message.h index f76a4544f..01330bbab 100755 --- a/src/core/message.h +++ b/src/core/message.h @@ -1,3 +1,20 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + #ifndef MESSAGE_H #define MESSAGE_H @@ -6,8 +23,8 @@ #include #include -// Represents single enclosuresh +// Represents single enclosure. struct Enclosure { QString m_url; QString m_mimeType; diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index c1725f2c6..885bafcf4 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -30,7 +30,6 @@ class FeedsProxyModel; class Feed; class Category; -class StandardCategory; class QTimer; class FeedsView : public QTreeView { diff --git a/src/services/abstract/category.cpp b/src/services/abstract/category.cpp index 52707e0ac..667e27fa0 100755 --- a/src/services/abstract/category.cpp +++ b/src/services/abstract/category.cpp @@ -1,3 +1,20 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + #include "services/abstract/category.h" diff --git a/src/services/abstract/category.h b/src/services/abstract/category.h index aaf55caef..cff422dda 100755 --- a/src/services/abstract/category.h +++ b/src/services/abstract/category.h @@ -1,3 +1,20 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + #ifndef CATEGORY_H #define CATEGORY_H From f131be94b967fee969571c827136146c20df9bae Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 4 Nov 2015 14:05:33 +0100 Subject: [PATCH 020/203] Merging of initial feeds now works, so does editing of standard feed/category. Needs a lot of polishment though. --- src/core/rootitem.cpp | 15 +++++++++++++++ src/core/rootitem.h | 3 +++ src/gui/feedmessageviewer.cpp | 7 +++---- src/services/abstract/feed.h | 4 ++-- .../standard/gui/formstandardcategorydetails.cpp | 5 ++--- .../standard/gui/formstandardfeeddetails.cpp | 5 ++--- src/services/standard/standardcategory.cpp | 13 ++++++------- src/services/standard/standardcategory.h | 3 +++ src/services/standard/standardfeed.cpp | 12 ++++++------ src/services/standard/standardfeed.h | 3 +++ src/services/standard/standardserviceroot.cpp | 5 ++++- 11 files changed, 49 insertions(+), 26 deletions(-) diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index a46f0a906..4546b4172 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -152,6 +152,21 @@ QList RootItem::getSubTreeFeeds() { return children; } +ServiceRoot *RootItem::getParentServiceRoot() { + RootItem *working_parent = this; + + while (working_parent->kind() != RootItemKind::Root) { + if (working_parent->kind() == RootItemKind::ServiceRoot) { + return working_parent->toServiceRoot(); + } + else { + working_parent = working_parent->parent(); + } + } + + return NULL; +} + bool RootItem::removeChild(RootItem *child) { return m_childItems.removeOne(child); } diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 163e80ce9..dfc32b62a 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -157,6 +157,9 @@ class RootItem { QList getSubTreeCategories(); QList getSubTreeFeeds(); + // Returns the service root node which is direct or indirect parent of current item. + ServiceRoot *getParentServiceRoot(); + // Removes particular child at given index. // NOTE: Child is NOT freed from the memory. bool removeChild(int index); diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index df6fc5af8..6bb8cc241 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -26,6 +26,7 @@ #include "core/messagesproxymodel.h" #include "core/feeddownloader.h" #include "core/feedsselection.h" +#include "services/standard/standardserviceroot.h" #include "services/standard/standardfeed.h" #include "services/standard/standardfeedsimportexportmodel.h" #include "network-web/webbrowser.h" @@ -209,12 +210,10 @@ void FeedMessageViewer::loadInitialFeeds() { model.importAsOPML20(IOFactory::readTextFile(file_to_load)); model.checkAllItems(); - // TODO: dodělat, předpokládá nějaký rozumný přístup k standardnímu root servicu. - /* - if (m_feedsView->sourceModel()->mergeModel(&model, output_msg)) { + // TODO: double-check. + if (m_feedsView->sourceModel()->standardServiceRoot()->mergeImportExportModel(&model, output_msg)) { m_feedsView->expandAll(); } - */ } catch (ApplicationException &ex) { MessageBox::show(this, QMessageBox::Critical, tr("Error when loading initial feeds"), ex.message()); diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index f239b48bc..64aecd6f8 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -45,8 +45,8 @@ class Feed : public RootItem { }; enum ReadStatus { - Read = 0, - Unread = 1 + Unread = 0, + Read = 1 }; // Constructors. diff --git a/src/services/standard/gui/formstandardcategorydetails.cpp b/src/services/standard/gui/formstandardcategorydetails.cpp index b3fd72720..e1c5ec5a0 100755 --- a/src/services/standard/gui/formstandardcategorydetails.cpp +++ b/src/services/standard/gui/formstandardcategorydetails.cpp @@ -139,9 +139,6 @@ void FormStandardCategoryDetails::apply() { if (edited) { m_serviceRoot->feedsModel()->reassignNodeToNewParent(m_editableCategory, new_category->parent()); - - // Remove new temporary feed data holder object. - delete new_category; accept(); } else { @@ -149,6 +146,8 @@ void FormStandardCategoryDetails::apply() { tr("Category was not edited due to error."), QSystemTrayIcon::Critical, this, true); } + + delete new_category; } } diff --git a/src/services/standard/gui/formstandardfeeddetails.cpp b/src/services/standard/gui/formstandardfeeddetails.cpp index 7fa6d6c8c..80a6d7d97 100755 --- a/src/services/standard/gui/formstandardfeeddetails.cpp +++ b/src/services/standard/gui/formstandardfeeddetails.cpp @@ -258,9 +258,6 @@ void FormStandardFeedDetails::apply() { if (edited) { m_serviceRoot->feedsModel()->reassignNodeToNewParent(m_editableFeed, new_feed->parent()); - - // Remove new temporary feed data holder object. - delete new_feed; accept(); } else { @@ -268,6 +265,8 @@ void FormStandardFeedDetails::apply() { tr("Feed was not edited due to error."), QSystemTrayIcon::Critical, this, true); } + + delete new_feed; } } diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index b321eeed0..4a16421db 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -27,6 +27,7 @@ #include "gui/feedmessageviewer.h" #include "gui/feedsview.h" #include "services/standard/gui/formstandardcategorydetails.h" +#include "services/standard/standardserviceroot.h" #include #include @@ -54,6 +55,10 @@ StandardCategory::~StandardCategory() { qDebug("Destroying Category instance."); } +StandardServiceRoot *StandardCategory::serviceRoot() { + return static_cast(getParentServiceRoot()); +} + void StandardCategory::init() { m_kind = RootItemKind::Category; } @@ -127,16 +132,10 @@ QVariant StandardCategory::data(int column, int role) const { } bool StandardCategory::editViaDialog() { - // TODO: předávat service root. -/* - QPointer form_pointer = new FormStandardCategoryDetails(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel(), - qApp->mainForm()); - + QPointer form_pointer = new FormStandardCategoryDetails(serviceRoot(), qApp->mainForm()); form_pointer.data()->exec(this, NULL); - delete form_pointer.data(); - */ return false; } diff --git a/src/services/standard/standardcategory.h b/src/services/standard/standardcategory.h index 4f1cd8e41..499e329b4 100755 --- a/src/services/standard/standardcategory.h +++ b/src/services/standard/standardcategory.h @@ -25,6 +25,7 @@ class FeedsModel; +class StandardServiceRoot; // Base class for all categories contained in FeedsModel. // NOTE: This class should be derived to create PARTICULAR category types. @@ -39,6 +40,8 @@ class StandardCategory : public Category { explicit StandardCategory(const QSqlRecord &record); virtual ~StandardCategory(); + StandardServiceRoot *serviceRoot(); + // Returns the actual data representation of standard category. QVariant data(int column, int role) const; diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 86104f076..4386a4dbc 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -29,6 +29,7 @@ #include "gui/dialogs/formmain.h" #include "gui/feedmessageviewer.h" #include "gui/feedsview.h" +#include "services/standard/standardserviceroot.h" #include "services/standard/gui/formstandardfeeddetails.h" #include @@ -98,16 +99,15 @@ int StandardFeed::countOfUnreadMessages() const { return m_unreadCount; } +StandardServiceRoot *StandardFeed::serviceRoot() { + return static_cast(getParentServiceRoot()); +} + bool StandardFeed::editViaDialog() { - // TODO: fix passing of the model + QPointer form_pointer = new FormStandardFeedDetails(serviceRoot(), qApp->mainForm()); - /* - QPointer form_pointer = new FormStandardFeedDetails(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel(), - qApp->mainForm()); form_pointer.data()->exec(this, NULL); - delete form_pointer.data(); - */ return false; } diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index 9196f069a..425c39baf 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -30,6 +30,7 @@ class Message; class FeedsModel; +class StandardServiceRoot; // Represents BASE class for feeds contained in FeedsModel. // NOTE: This class should be derived to create PARTICULAR feed types. @@ -52,6 +53,8 @@ class StandardFeed : public Feed { explicit StandardFeed(const QSqlRecord &record); virtual ~StandardFeed(); + StandardServiceRoot *serviceRoot(); + // Getters/setters for count of messages. // NOTE: For feeds, counts are stored internally // and can be updated from the database. diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 666bea5c7..08c5101cc 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -289,7 +289,10 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, StandardFeed *new_feed = new StandardFeed(*source_feed); // Append this feed and end this iteration. - if (!new_feed->addItself(target_parent)) { + if (new_feed->addItself(target_parent)) { + m_feedsModel->assignNodeToNewParent(new_feed, target_parent); + } + else { delete new_feed; some_feed_category_error = true; } From 39666e7baee440d3eb2f8cc00003101a4fa509f6 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 5 Nov 2015 08:07:08 +0100 Subject: [PATCH 021/203] Fixed some network manager bug, refactoring of feed model. --- resources/text/CHANGELOG | 4 +-- src/core/feedsmodel.cpp | 30 +++++++------------ src/core/feedsmodel.h | 3 -- src/network-web/downloadmanager.cpp | 9 ++++++ src/network-web/downloadmanager.h | 1 + .../gui/formstandardcategorydetails.cpp | 2 +- .../standard/gui/formstandardfeeddetails.cpp | 2 +- src/services/standard/standardserviceroot.cpp | 4 +-- 8 files changed, 27 insertions(+), 28 deletions(-) mode change 100644 => 100755 src/network-web/downloadmanager.h diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 030cf17d3..37dbd535d 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -16,12 +16,12 @@ Added:
    -
  • +
  • Brand new "service plugin system" - HIGHLY EXPERIMENTAL and REWRITTEN from scratch. Some UI features (for example drag-drop) are temporarily unavailable. Expect bugs and misunderstandings now!
Fixed:
    -
  • +
  • When removing download item from download manager via DELETE key, then "Cleanup" button is correctly disabled.

diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index e94e245fe..ce3bf81cd 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -231,30 +231,22 @@ bool FeedsModel::removeItem(const QModelIndex &index) { return false; } -void FeedsModel::assignNodeToNewParent(RootItem *item, RootItem *new_parent) { - QModelIndex parent_index = indexForItem(new_parent); - int new_index_of_item = new_parent->childCount(); - - // TODO: sloučit do funkce reassignNodeToNewParent. - - beginInsertRows(parent_index, new_index_of_item, new_index_of_item); - new_parent->appendChild(item); - endInsertRows(); -} - void FeedsModel::reassignNodeToNewParent(RootItem *original_node, RootItem *new_parent) { RootItem *original_parent = original_node->parent(); if (original_parent != new_parent) { - // User edited item and set it new parent item, - // se we need to move the item in the model too. - int original_index_of_item = original_parent->childItems().indexOf(original_node); - int new_index_of_item = new_parent->childCount(); + if (original_parent != NULL) { + int original_index_of_item = original_parent->childItems().indexOf(original_node); - // Remove the original item from the model... - beginRemoveRows(indexForItem(original_parent), original_index_of_item, original_index_of_item); - original_parent->removeChild(original_node); - endRemoveRows(); + if (original_index_of_item >= 0) { + // Remove the original item from the model... + beginRemoveRows(indexForItem(original_parent), original_index_of_item, original_index_of_item); + original_parent->removeChild(original_node); + endRemoveRows(); + } + } + + int new_index_of_item = new_parent->childCount(); // ... and insert it under the new parent. beginInsertRows(indexForItem(new_parent), new_index_of_item, new_index_of_item); diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 55173ee79..168b322fd 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -63,9 +63,6 @@ class FeedsModel : public QAbstractItemModel { // NOTE: Also deletes item from memory. bool removeItem(const QModelIndex &index); - // Assigns item to the new parent. - void assignNodeToNewParent(RootItem *item, RootItem *new_parent); - // Checks if new parent node is different from one used by original node. // If it is, then it reassigns original_node to new parent. void reassignNodeToNewParent(RootItem *original_node, RootItem *new_parent); diff --git a/src/network-web/downloadmanager.cpp b/src/network-web/downloadmanager.cpp index 62c96616b..ab039fe63 100755 --- a/src/network-web/downloadmanager.cpp +++ b/src/network-web/downloadmanager.cpp @@ -559,6 +559,10 @@ QNetworkAccessManager *DownloadManager::networkManager() const { return m_networkManager; } +int DownloadManager::totalDownloads() const { + return m_downloads.size(); +} + void DownloadManager::itemFinished() { emit downloadFinished(); } @@ -789,6 +793,11 @@ bool DownloadModel::removeRows(int row, int count, const QModelIndex &parent) { } m_downloadManager->m_autoSaver->changeOccurred(); + + if (m_downloadManager->totalDownloads() == 0) { + m_downloadManager->m_ui->m_btnCleanup->setEnabled(false); + } + return true; } diff --git a/src/network-web/downloadmanager.h b/src/network-web/downloadmanager.h old mode 100644 new mode 100755 index ea522af12..b479b1d14 --- a/src/network-web/downloadmanager.h +++ b/src/network-web/downloadmanager.h @@ -111,6 +111,7 @@ class DownloadManager : public TabContent { WebBrowser *webBrowser(); QNetworkAccessManager *networkManager() const; + int totalDownloads() const; int activeDownloads() const; int downloadProgress() const; diff --git a/src/services/standard/gui/formstandardcategorydetails.cpp b/src/services/standard/gui/formstandardcategorydetails.cpp index e1c5ec5a0..5c8d94b3d 100755 --- a/src/services/standard/gui/formstandardcategorydetails.cpp +++ b/src/services/standard/gui/formstandardcategorydetails.cpp @@ -123,7 +123,7 @@ void FormStandardCategoryDetails::apply() { if (m_editableCategory == NULL) { // Add the category. if (new_category->addItself(parent)) { - m_serviceRoot->feedsModel()->assignNodeToNewParent(new_category, parent); + m_serviceRoot->feedsModel()->reassignNodeToNewParent(new_category, parent); accept(); } else { diff --git a/src/services/standard/gui/formstandardfeeddetails.cpp b/src/services/standard/gui/formstandardfeeddetails.cpp index 80a6d7d97..bfecd6312 100755 --- a/src/services/standard/gui/formstandardfeeddetails.cpp +++ b/src/services/standard/gui/formstandardfeeddetails.cpp @@ -242,7 +242,7 @@ void FormStandardFeedDetails::apply() { if (m_editableFeed == NULL) { // Add the feed. if (new_feed->addItself(parent)) { - m_serviceRoot->feedsModel()->assignNodeToNewParent(new_feed, parent); + m_serviceRoot->feedsModel()->reassignNodeToNewParent(new_feed, parent); accept(); } else { diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 08c5101cc..1777337f3 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -256,7 +256,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, new_category->clearChildren(); if (new_category->addItself(target_parent)) { - m_feedsModel->assignNodeToNewParent(new_category, target_parent); + m_feedsModel->reassignNodeToNewParent(new_category, target_parent); // Process all children of this category. original_parents.push(new_category); @@ -290,7 +290,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, // Append this feed and end this iteration. if (new_feed->addItself(target_parent)) { - m_feedsModel->assignNodeToNewParent(new_feed, target_parent); + m_feedsModel->reassignNodeToNewParent(new_feed, target_parent); } else { delete new_feed; From 5c0f7771892decfbe156f2dbcb6ef21d4aad2245 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 6 Nov 2015 08:25:37 +0100 Subject: [PATCH 022/203] Deleting of items is now moved to interface. --- src/core/feedsmodel.cpp | 21 +++----- src/core/feedsmodel.h | 2 +- src/core/rootitem.h | 29 +++++++---- src/gui/feedsview.cpp | 59 +++++++++++++++------- src/services/standard/standardcategory.cpp | 14 ++++- src/services/standard/standardcategory.h | 3 +- src/services/standard/standardfeed.cpp | 6 ++- src/services/standard/standardfeed.h | 3 +- src/services/tt-rss/ttrssserviceroot.cpp | 2 +- src/services/tt-rss/ttrssserviceroot.h | 2 +- 10 files changed, 90 insertions(+), 51 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index ce3bf81cd..7899416eb 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -208,27 +208,20 @@ int FeedsModel::rowCount(const QModelIndex &parent) const { } } -bool FeedsModel::removeItem(const QModelIndex &index) { +void FeedsModel::removeItem(const QModelIndex &index) { if (index.isValid()) { QModelIndex parent_index = index.parent(); RootItem *deleting_item = itemForIndex(index); RootItem *parent_item = deleting_item->parent(); - // Try to persistently remove the item. - if (deleting_item->removeItself()) { - // Item was persistently removed. - // Remove it from the model. - beginRemoveRows(parent_index, index.row(), index.row()); - parent_item->removeChild(deleting_item); - endRemoveRows(); + // Item was persistently removed. + // Remove it from the model. + beginRemoveRows(parent_index, index.row(), index.row()); + parent_item->removeChild(deleting_item); + endRemoveRows(); - delete deleting_item; - return true; - } + delete deleting_item; } - - // Item was not removed successfully. - return false; } void FeedsModel::reassignNodeToNewParent(RootItem *original_node, RootItem *new_parent) { diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 168b322fd..004e66b25 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -61,7 +61,7 @@ class FeedsModel : public QAbstractItemModel { // Removes item with given index. // NOTE: Also deletes item from memory. - bool removeItem(const QModelIndex &index); + void removeItem(const QModelIndex &index); // Checks if new parent node is different from one used by original node. // If it is, then it reassigns original_node to new parent. diff --git a/src/core/rootitem.h b/src/core/rootitem.h index dfc32b62a..482519dee 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -78,7 +78,7 @@ class RootItem { return false; } - virtual bool editViaDialog() { + virtual bool editViaGui() { return false; } @@ -90,6 +90,23 @@ class RootItem { return false; } + virtual bool canBeMarkedAsRead() { + return true; + } + + virtual bool markAsRead() { + return true; + } + + virtual bool canBeMarkedAsUnread() { + return true; + } + + virtual bool markAsUnread() { + return true; + } + + virtual int row() const; virtual QVariant data(int column, int role) const; @@ -98,16 +115,6 @@ class RootItem { virtual int countOfUnreadMessages() const; virtual int countOfAllMessages() const; - // This method is used to permanently - // "remove" (or "unregister") this item. - // This typically removes item and its - // "children" (for example messages or child feeds) - // from the database. - // Returns true if "I" was removed. - virtual bool removeItself() { - return false; - } - // Access to children. inline QList childItems() const { return m_childItems; diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index d69e1ea53..705ffb3e7 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -247,7 +247,7 @@ void FeedsView::editSelectedItem() { } if (selectedItem()->canBeEdited()) { - selectedItem()->editViaDialog(); + selectedItem()->editViaGui(); } else { qApp->showGuiMessage(tr("Cannot edit item"), @@ -282,24 +282,47 @@ void FeedsView::deleteSelectedItem() { return; } - if (MessageBox::show(qApp->mainForm(), QMessageBox::Question, tr("Delete feed/category"), - tr("You are about to delete selected feed or category."), tr("Do you really want to delete selected item?"), - QString(), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::No) { - // User changed his mind. - qApp->feedUpdateLock()->unlock(); - return; - } + RootItem *selected_item = selectedItem(); - if (m_sourceModel->removeItem(m_proxyModel->mapToSource(current_index))) { - // Item WAS removed, update counts. - notifyWithCounts(); - } - else { - // Item WAS NOT removed, either database-related error occurred - // or update is undergoing. - qApp->showGuiMessage(tr("Deletion of item failed."), - tr("Selected item was not deleted due to error."), - QSystemTrayIcon::Warning, qApp->mainForm(), true); + if (selected_item != NULL) { + if (selected_item->canBeDeleted()) { + // Ask user first. + if (MessageBox::show(qApp->mainForm(), + QMessageBox::Question, + tr("Deleting \"%1\"").arg(selected_item->title()), + tr("You are about to completely delete item \"%1\".").arg(selected_item->title()), + tr("Are you sure?"), + QString(), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::No) { + // User refused. + qApp->feedUpdateLock()->unlock(); + return; + } + + // We have deleteable item selected, remove it via GUI. + if (!selected_item->deleteViaGui()) { + qApp->showGuiMessage(tr("Cannot delete \"%1\"").arg(selected_item->title()), + tr("This item cannot be deleted because something critically failed. Submit bug report."), + QSystemTrayIcon::Critical, + qApp->mainForm(), + true); + } + else { + // Item is gone, cleared from database. We can clear it from model now. + // NOTE: Cleared from memory here too. + // TODO: možná toto přesunout taky to metody deleteViaGui + // a delete selected_item jen volat tady, editViaGui taky obstará všechno, + // ale tam je to zas komplexnější. + m_sourceModel->removeItem(m_proxyModel->mapToSource(current_index)); + notifyWithCounts(); + } + } + else { + qApp->showGuiMessage(tr("Cannot delete \"%1\"").arg(selected_item->title()), + tr("This item cannot be deleted, because it does not support it\nor this functionality is not implemented yet."), + QSystemTrayIcon::Critical, + qApp->mainForm(), + true); + } } // Changes are done, unlock the update master lock. diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index 4a16421db..a5d62b8ff 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -28,6 +28,7 @@ #include "gui/feedsview.h" #include "services/standard/gui/formstandardcategorydetails.h" #include "services/standard/standardserviceroot.h" +#include "services/standard/standardfeed.h" #include #include @@ -131,7 +132,7 @@ QVariant StandardCategory::data(int column, int role) const { } } -bool StandardCategory::editViaDialog() { +bool StandardCategory::editViaGui() { QPointer form_pointer = new FormStandardCategoryDetails(serviceRoot(), qApp->mainForm()); form_pointer.data()->exec(this, NULL); @@ -139,12 +140,21 @@ bool StandardCategory::editViaDialog() { return false; } +bool StandardCategory::deleteViaGui() { + return removeItself(); +} + bool StandardCategory::removeItself() { bool children_removed = true; // Remove all child items (feeds, categories.) foreach (RootItem *child, m_childItems) { - children_removed &= child->removeItself(); + if (child->kind() == RootItemKind::Category) { + children_removed &= static_cast(child)->removeItself(); + } + else if (child->kind() == RootItemKind::Feed) { + children_removed &= static_cast(child)->removeItself(); + } } if (children_removed) { diff --git a/src/services/standard/standardcategory.h b/src/services/standard/standardcategory.h index 499e329b4..b7c8d7ae1 100755 --- a/src/services/standard/standardcategory.h +++ b/src/services/standard/standardcategory.h @@ -53,7 +53,8 @@ class StandardCategory : public Category { return true; } - bool editViaDialog(); + bool editViaGui(); + bool deleteViaGui(); // Removes category and all its children from persistent // database. diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 4386a4dbc..82e7f4c23 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -103,7 +103,7 @@ StandardServiceRoot *StandardFeed::serviceRoot() { return static_cast(getParentServiceRoot()); } -bool StandardFeed::editViaDialog() { +bool StandardFeed::editViaGui() { QPointer form_pointer = new FormStandardFeedDetails(serviceRoot(), qApp->mainForm()); form_pointer.data()->exec(this, NULL); @@ -111,6 +111,10 @@ bool StandardFeed::editViaDialog() { return false; } +bool StandardFeed::deleteViaGui() { + return removeItself(); +} + QList StandardFeed::undeletedMessages() const { QList messages; diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index 425c39baf..710f6ae3f 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -69,7 +69,8 @@ class StandardFeed : public Feed { return true; } - bool editViaDialog(); + bool editViaGui(); + bool deleteViaGui(); QList undeletedMessages() const; diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index fbb350b7b..74cc6cd04 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -33,7 +33,7 @@ TtRssServiceRoot::TtRssServiceRoot(FeedsModel *feeds_model, RootItem *parent) : TtRssServiceRoot::~TtRssServiceRoot() { } -bool TtRssServiceRoot::editViaDialog() { +bool TtRssServiceRoot::editViaGui() { // TODO: zobrazit custom edit dialog pro ttrss return false; } diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index b8259193d..a5df9c6a2 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -34,7 +34,7 @@ class TtRssServiceRoot : public ServiceRoot { bool canBeEdited(); bool canBeDeleted(); - bool editViaDialog(); + bool editViaGui(); QVariant data(int column, int role) const; }; From 3d59902aeba258ebd1eb2f4e63635c630cdf2a55 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 6 Nov 2015 09:41:36 +0100 Subject: [PATCH 023/203] RootItem now inherits QObject, fetching metadata works for standard feeds, custom context menus moved to interface so that each item can provide specific menu items. --- CMakeLists.txt | 20 ++++- src/core/feedsmodel.cpp | 5 ++ src/core/feedsmodel.h | 3 + src/core/rootitem.cpp | 4 + src/core/rootitem.h | 11 ++- src/gui/dialogs/formmain.cpp | 14 +--- src/gui/dialogs/formmain.ui | 49 +++--------- src/gui/feedmessageviewer.cpp | 17 +---- src/gui/feedsview.cpp | 74 +++++++++---------- src/gui/feedsview.h | 5 +- src/services/abstract/category.h | 2 + src/services/abstract/feed.h | 2 + src/services/abstract/serviceroot.h | 2 + src/services/standard/standardcategory.h | 2 +- src/services/standard/standardfeed.cpp | 10 ++- src/services/standard/standardfeed.h | 4 +- src/services/standard/standarditem.cpp | 18 ----- src/services/standard/standarditem.h | 19 ----- src/services/standard/standardrecyclebin.h | 2 +- src/services/standard/standardserviceroot.cpp | 12 +++ src/services/standard/standardserviceroot.h | 4 +- src/services/tt-rss/ttrssserviceroot.h | 2 +- 22 files changed, 131 insertions(+), 150 deletions(-) delete mode 100755 src/services/standard/standarditem.cpp delete mode 100755 src/services/standard/standarditem.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e387d3d8..9af5020df 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -422,16 +422,15 @@ set(APP_SOURCES src/services/abstract/serviceroot.cpp # STANDARD feed service sources. - src/services/standard/standardfeed.cpp - src/services/standard/standardfeedsimportexportmodel.cpp - src/services/standard/standardcategory.cpp src/services/standard/gui/formstandardcategorydetails.cpp src/services/standard/gui/formstandardfeeddetails.cpp src/services/standard/gui/formstandardimportexport.cpp + src/services/standard/standardfeedsimportexportmodel.cpp src/services/standard/standardserviceentrypoint.cpp + src/services/standard/standardcategory.cpp + src/services/standard/standardfeed.cpp src/services/standard/standardserviceroot.cpp src/services/standard/standardrecyclebin.cpp - src/services/standard/standarditem.cpp # TT-RSS feed service sources. src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -531,12 +530,25 @@ set(APP_HEADERS src/core/feedsmodel.h src/core/feedsproxymodel.h src/core/feeddownloader.h + src/core/rootitem.h + + # ABSTRACT service headers. + src/services/abstract/feed.h + src/services/abstract/category.h + src/services/abstract/serviceroot.h # STANDARD service headers. src/services/standard/standardfeedsimportexportmodel.h src/services/standard/gui/formstandardcategorydetails.h src/services/standard/gui/formstandardfeeddetails.h src/services/standard/gui/formstandardimportexport.h + src/services/standard/standardcategory.h + src/services/standard/standardfeed.h + src/services/standard/standardserviceroot.h + src/services/standard/standardrecyclebin.h + + # TT-RSS service headers. + src/services/tt-rss/ttrssserviceroot.h # NETWORK-WEB headers. src/network-web/webpage.h diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 7899416eb..53b424c29 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -392,6 +392,11 @@ void FeedsModel::reloadChangedLayout(QModelIndexList list) { } } +void FeedsModel::reloadChangedItem(RootItem *item) { + QModelIndex index_item = indexForItem(item); + reloadChangedLayout(QModelIndexList() << index_item); +} + QStringList FeedsModel::textualFeedIds(const QList &feeds) { QStringList stringy_ids; stringy_ids.reserve(feeds.size()); diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 004e66b25..1fdc26b72 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -144,6 +144,9 @@ class FeedsModel : public QAbstractItemModel { // NOTE: This reloads all parent valid indexes too. void reloadChangedLayout(QModelIndexList list); + // Invalidates data under index for the item. + void reloadChangedItem(RootItem *item); + private slots: // Is executed when next auto-update round could be done. void executeNextAutoUpdate(); diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index 4546b4172..dc48504c4 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -41,6 +41,10 @@ RootItem::~RootItem() { qDeleteAll(m_childItems); } +QList RootItem::specificActions() { + return QList(); +} + void RootItem::setupFonts() { m_normalFont = Application::font("FeedsView"); m_boldFont = m_normalFont; diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 482519dee..8d25ecf89 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -26,6 +26,7 @@ class Category; class Feed; class ServiceRoot; +class QAction; namespace RootItemKind { // Describes the kind of the item. @@ -45,7 +46,9 @@ namespace RootItemKind { // Represents ROOT item of FeedsModel. // NOTE: This class is derived to add functionality for // all other non-root items of FeedsModel. -class RootItem { +class RootItem : public QObject { + Q_OBJECT + public: // Constructors and destructors. explicit RootItem(RootItem *parent_item = NULL); @@ -73,6 +76,12 @@ class RootItem { child->setParent(this); } + // Returns list of specific actions which can be done with the item. + // NOTE: This method should always create new actions in memory + // before returning them because caller takes ownership of any + // actions returned from here. + virtual QList specificActions(); + // TODO: pracovat s těmito věcmi virtual bool canBeEdited() { return false; diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index 4baef3183..738509e84 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -125,16 +125,13 @@ QList FormMain::allActions() { actions << m_ui->m_actionDeleteSelectedMessages; actions << m_ui->m_actionUpdateAllFeeds; actions << m_ui->m_actionUpdateSelectedFeeds; - actions << m_ui->m_actionEditSelectedFeedCategory; - actions << m_ui->m_actionDeleteSelectedFeedCategory; + actions << m_ui->m_actionEditSelectedItem; + actions << m_ui->m_actionDeleteSelectedItem; actions << m_ui->m_actionViewSelectedItemsNewspaperMode; - actions << m_ui->m_actionAddCategory; - actions << m_ui->m_actionAddFeed; actions << m_ui->m_actionSelectNextFeedCategory; actions << m_ui->m_actionSelectPreviousFeedCategory; actions << m_ui->m_actionSelectNextMessage; actions << m_ui->m_actionSelectPreviousMessage; - actions << m_ui->m_actionFetchFeedMetadata; actions << m_ui->m_actionExpandCollapseFeedCategory; return actions; @@ -248,11 +245,9 @@ void FormMain::setupIcons() { m_ui->m_actionUpdateSelectedFeeds->setIcon(icon_theme_factory->fromTheme(QSL("item-update-selected"))); m_ui->m_actionClearSelectedFeeds->setIcon(icon_theme_factory->fromTheme(QSL("mail-remove"))); m_ui->m_actionClearAllFeeds->setIcon(icon_theme_factory->fromTheme(QSL("mail-remove"))); - m_ui->m_actionDeleteSelectedFeedCategory->setIcon(icon_theme_factory->fromTheme(QSL("item-remove"))); + m_ui->m_actionDeleteSelectedItem->setIcon(icon_theme_factory->fromTheme(QSL("item-remove"))); m_ui->m_actionDeleteSelectedMessages->setIcon(icon_theme_factory->fromTheme(QSL("mail-remove"))); - m_ui->m_actionAddCategory->setIcon(icon_theme_factory->fromTheme(QSL("folder-category"))); - m_ui->m_actionAddFeed->setIcon(icon_theme_factory->fromTheme(QSL("folder-feed"))); - m_ui->m_actionEditSelectedFeedCategory->setIcon(icon_theme_factory->fromTheme(QSL("item-edit"))); + m_ui->m_actionEditSelectedItem->setIcon(icon_theme_factory->fromTheme(QSL("item-edit"))); m_ui->m_actionMarkAllFeedsRead->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-read"))); m_ui->m_actionMarkSelectedFeedsAsRead->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-read"))); m_ui->m_actionMarkSelectedFeedsAsUnread->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-unread"))); @@ -269,7 +264,6 @@ void FormMain::setupIcons() { m_ui->m_actionSelectNextMessage->setIcon(icon_theme_factory->fromTheme(QSL("go-down"))); m_ui->m_actionSelectPreviousMessage->setIcon(icon_theme_factory->fromTheme(QSL("go-up"))); m_ui->m_actionShowOnlyUnreadFeeds->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-unread"))); - m_ui->m_actionFetchFeedMetadata->setIcon(icon_theme_factory->fromTheme(QSL("download-manager"))); m_ui->m_actionExpandCollapseFeedCategory->setIcon(icon_theme_factory->fromTheme(QSL("expand-collapse"))); // Setup icons for underlying components: opened web browsers... diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index cf173caa5..974aadb67 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -132,18 +132,15 @@
- Add &new feed/category + Add &new item - - - - - + + @@ -272,7 +269,7 @@
- Update &all feeds + Update &all items Ctrl+Shift+U @@ -280,20 +277,20 @@ - Update &selected feeds + Update &selected items Ctrl+U - + - &Edit selected feed/category + &Edit selected item - + - &Delete selected feed/category + &Delete selected item @@ -340,14 +337,6 @@ Deletes all messages from selected feeds.
- - - New &feed - - - Add new feed. - - Open selected source articles in &external browser @@ -363,14 +352,6 @@ Open selected source articles in &internal browser - - - New &category - - - Add new category. - - No actions available @@ -436,7 +417,7 @@ - Select &next feed/category + Select &next item S @@ -444,7 +425,7 @@ - Select &previous feed/category + Select &previous item A @@ -649,14 +630,6 @@ Ctrl+Shift+U - - - &Fetch feed metadata - - - Ctrl+Shift+F - - &Expand/collapse selected feed/category diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 6bb8cc241..1c2cb6c56 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -309,20 +309,17 @@ void FeedMessageViewer::updateFeedButtonsAvailability() { bool feed_selected = !m_feedsView->selectionModel()->selectedRows().isEmpty(); FormMain *form_main = qApp->mainForm(); - form_main->m_ui->m_actionAddCategory->setEnabled(!critical_action_running); - form_main->m_ui->m_actionAddFeed->setEnabled(!critical_action_running); form_main->m_ui->m_actionBackupDatabaseSettings->setEnabled(!critical_action_running); form_main->m_ui->m_actionCleanupDatabase->setEnabled(!critical_action_running); form_main->m_ui->m_actionClearSelectedFeeds->setEnabled(feed_selected); - form_main->m_ui->m_actionDeleteSelectedFeedCategory->setEnabled(!critical_action_running && feed_selected); - form_main->m_ui->m_actionEditSelectedFeedCategory->setEnabled(!critical_action_running && feed_selected); + form_main->m_ui->m_actionDeleteSelectedItem->setEnabled(!critical_action_running && feed_selected); + form_main->m_ui->m_actionEditSelectedItem->setEnabled(!critical_action_running && feed_selected); form_main->m_ui->m_actionImportFeeds->setEnabled(!critical_action_running); form_main->m_ui->m_actionMarkSelectedFeedsAsRead->setEnabled(feed_selected); form_main->m_ui->m_actionMarkSelectedFeedsAsUnread->setEnabled(feed_selected); form_main->m_ui->m_actionUpdateAllFeeds->setEnabled(!critical_action_running); form_main->m_ui->m_actionUpdateSelectedFeeds->setEnabled(!critical_action_running && feed_selected); form_main->m_ui->m_actionViewSelectedItemsNewspaperMode->setEnabled(feed_selected); - form_main->m_ui->m_actionFetchFeedMetadata->setEnabled(feed_selected); form_main->m_ui->m_actionExpandCollapseFeedCategory->setEnabled(feed_selected); form_main->m_ui->m_menuAddItem->setEnabled(!critical_action_running); } @@ -395,8 +392,6 @@ void FeedMessageViewer::createConnections() { SIGNAL(triggered()), m_feedsView, SLOT(markSelectedFeedsRead())); connect(form_main->m_ui->m_actionExpandCollapseFeedCategory, SIGNAL(triggered()), m_feedsView, SLOT(expandCollapseCurrentItem())); - connect(form_main->m_ui->m_actionFetchFeedMetadata, SIGNAL(triggered()), - m_feedsView, SLOT(fetchMetadataForSelectedFeed())); connect(form_main->m_ui->m_actionMarkSelectedFeedsAsUnread, SIGNAL(triggered()), m_feedsView, SLOT(markSelectedFeedsUnread())); connect(form_main->m_ui->m_actionClearSelectedFeeds, @@ -407,15 +402,11 @@ void FeedMessageViewer::createConnections() { SIGNAL(triggered()), m_feedsView, SLOT(updateSelectedFeeds())); connect(form_main->m_ui->m_actionUpdateAllFeeds, SIGNAL(triggered()), m_feedsView, SLOT(updateAllFeeds())); - connect(form_main->m_ui->m_actionAddCategory, - SIGNAL(triggered()), m_feedsView, SLOT(addNewCategory())); - connect(form_main->m_ui->m_actionAddFeed, - SIGNAL(triggered()), m_feedsView, SLOT(addNewFeed())); - connect(form_main->m_ui->m_actionEditSelectedFeedCategory, + connect(form_main->m_ui->m_actionEditSelectedItem, SIGNAL(triggered()), m_feedsView, SLOT(editSelectedItem())); connect(form_main->m_ui->m_actionViewSelectedItemsNewspaperMode, SIGNAL(triggered()), m_feedsView, SLOT(openSelectedFeedsInNewspaperMode())); - connect(form_main->m_ui->m_actionDeleteSelectedFeedCategory, + connect(form_main->m_ui->m_actionDeleteSelectedItem, SIGNAL(triggered()), m_feedsView, SLOT(deleteSelectedItem())); connect(form_main->m_ui->m_actionSwitchFeedsList, SIGNAL(triggered()), this, SLOT(switchFeedComponentVisibility())); diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 705ffb3e7..ab3a57ac6 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -355,18 +355,6 @@ void FeedsView::markAllFeedsRead() { markAllFeedsReadStatus(1); } -void FeedsView::fetchMetadataForSelectedFeed() { - // TODO: fix - /* - StandardFeed *selected_feed = (StandardFeed*) selectedFeed(); - - if (selected_feed != NULL) { - selected_feed->fetchMetadataForItself(); - m_sourceModel->reloadChangedLayout(QModelIndexList() << m_proxyModel->mapToSource(selectionModel()->selectedRows(0).at(0))); - } - */ -} - void FeedsView::clearAllReadMessages() { m_sourceModel->markFeedsDeleted(allFeeds(), 1, 1); } @@ -495,40 +483,58 @@ void FeedsView::selectPreviousItem() { } } -void FeedsView::initializeContextMenuCategories() { - m_contextMenuCategories = new QMenu(tr("Context menu for categories"), this); +void FeedsView::initializeContextMenuCategories(RootItem *clicked_item) { + if (m_contextMenuCategories == NULL) { + m_contextMenuCategories = new QMenu(tr("Context menu for categories"), this); + } + else { + m_contextMenuCategories->clear(); + } + + QList specific_actions = clicked_item->specificActions(); + m_contextMenuCategories->addActions(QList() << qApp->mainForm()->m_ui->m_actionUpdateSelectedFeeds << - qApp->mainForm()->m_ui->m_actionEditSelectedFeedCategory << + qApp->mainForm()->m_ui->m_actionEditSelectedItem << qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode << qApp->mainForm()->m_ui->m_actionMarkSelectedFeedsAsRead << qApp->mainForm()->m_ui->m_actionMarkSelectedFeedsAsUnread << - qApp->mainForm()->m_ui->m_actionDeleteSelectedFeedCategory); - m_contextMenuCategories->addSeparator(); - m_contextMenuCategories->addActions(QList() << - qApp->mainForm()->m_ui->m_actionAddCategory << - qApp->mainForm()->m_ui->m_actionAddFeed); + qApp->mainForm()->m_ui->m_actionDeleteSelectedItem); + + if (!specific_actions.isEmpty()) { + m_contextMenuCategories->addSeparator(); + m_contextMenuCategories->addActions(specific_actions); + } } -void FeedsView::initializeContextMenuFeeds() { - m_contextMenuFeeds = new QMenu(tr("Context menu for categories"), this); +void FeedsView::initializeContextMenuFeeds(RootItem *clicked_item) { + if (m_contextMenuFeeds == NULL) { + m_contextMenuFeeds = new QMenu(tr("Context menu for categories"), this); + } + else { + m_contextMenuFeeds->clear(); + } + + QList specific_actions = clicked_item->specificActions(); + m_contextMenuFeeds->addActions(QList() << qApp->mainForm()->m_ui->m_actionUpdateSelectedFeeds << - qApp->mainForm()->m_ui->m_actionEditSelectedFeedCategory << + qApp->mainForm()->m_ui->m_actionEditSelectedItem << qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode << qApp->mainForm()->m_ui->m_actionMarkSelectedFeedsAsRead << qApp->mainForm()->m_ui->m_actionMarkSelectedFeedsAsUnread << - qApp->mainForm()->m_ui->m_actionDeleteSelectedFeedCategory << - qApp->mainForm()->m_ui->m_actionFetchFeedMetadata); + qApp->mainForm()->m_ui->m_actionDeleteSelectedItem); + + if (!specific_actions.isEmpty()) { + m_contextMenuFeeds->addSeparator(); + m_contextMenuFeeds->addActions(specific_actions); + } } void FeedsView::initializeContextMenuEmptySpace() { m_contextMenuEmptySpace = new QMenu(tr("Context menu for empty space"), this); m_contextMenuEmptySpace->addAction(qApp->mainForm()->m_ui->m_actionUpdateAllFeeds); m_contextMenuEmptySpace->addSeparator(); - m_contextMenuEmptySpace->addActions(QList() << - qApp->mainForm()->m_ui->m_actionAddCategory << - qApp->mainForm()->m_ui->m_actionAddFeed); } void FeedsView::setupAppearance() { @@ -590,20 +596,12 @@ void FeedsView::contextMenuEvent(QContextMenuEvent *event) { if (clicked_item->kind() == RootItemKind::Category) { // Display context menu for categories. - if (m_contextMenuCategories == NULL) { - // Context menu is not initialized, initialize. - initializeContextMenuCategories(); - } - + initializeContextMenuCategories(clicked_item); m_contextMenuCategories->exec(event->globalPos()); } else if (clicked_item->kind() == RootItemKind::Feed) { // Display context menu for feeds. - if (m_contextMenuFeeds == NULL) { - // Context menu is not initialized, initialize. - initializeContextMenuFeeds(); - } - + initializeContextMenuFeeds(clicked_item); m_contextMenuFeeds->exec(event->globalPos()); } } diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index 885bafcf4..1b01477b2 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -69,7 +69,6 @@ class FeedsView : public QTreeView { public slots: void invalidateReadFeedsFilter(bool set_new_value = false, bool show_unread_only = false); void expandCollapseCurrentItem(); - void fetchMetadataForSelectedFeed(); // Feed updating. void updateAllFeeds(); @@ -136,8 +135,8 @@ class FeedsView : public QTreeView { protected: // Initializes context menus. - void initializeContextMenuCategories(); - void initializeContextMenuFeeds(); + void initializeContextMenuCategories(RootItem *clicked_item); + void initializeContextMenuFeeds(RootItem *clicked_item); void initializeContextMenuEmptySpace(); // Sets up appearance of this widget. diff --git a/src/services/abstract/category.h b/src/services/abstract/category.h index cff422dda..961eed509 100755 --- a/src/services/abstract/category.h +++ b/src/services/abstract/category.h @@ -22,6 +22,8 @@ class Category : public RootItem { + Q_OBJECT + public: explicit Category(RootItem *parent = NULL); virtual ~Category(); diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index 64aecd6f8..6083c5b86 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -25,6 +25,8 @@ // Base class for "feed" nodes. class Feed : public RootItem { + Q_OBJECT + public: // Specifies the auto-update strategy for the feed. enum AutoUpdateType { diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 94e6b472e..86315accc 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -27,6 +27,8 @@ class FeedsModel; // NOTE: The root usually contains some core functionality of the // service like service account username/password etc. class ServiceRoot : public RootItem { + Q_OBJECT + public: explicit ServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL); virtual ~ServiceRoot(); diff --git a/src/services/standard/standardcategory.h b/src/services/standard/standardcategory.h index b7c8d7ae1..1edab3bab 100755 --- a/src/services/standard/standardcategory.h +++ b/src/services/standard/standardcategory.h @@ -31,7 +31,7 @@ class StandardServiceRoot; // NOTE: This class should be derived to create PARTICULAR category types. // NOTE: This class should not be instantiated directly. class StandardCategory : public Category { - Q_DECLARE_TR_FUNCTIONS(StandardCategory) + Q_OBJECT public: // Constructors and destructors diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 82e7f4c23..7f9511148 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -99,6 +99,10 @@ int StandardFeed::countOfUnreadMessages() const { return m_unreadCount; } +QList StandardFeed::specificActions() { + return serviceRoot()->getMenuForFeed(this); +} + StandardServiceRoot *StandardFeed::serviceRoot() { return static_cast(getParentServiceRoot()); } @@ -201,10 +205,14 @@ void StandardFeed::fetchMetadataForItself() { editItself(metadata.first); delete metadata.first; + + // Notify the model about fact, that it needs to reload new information about + // this item, particularly the icon. + serviceRoot()->feedsModel()->reloadChangedItem(this); } else { qApp->showGuiMessage(tr("Metadata not fetched"), - tr("Metadata was not fetched because: %1").arg(NetworkFactory::networkErrorText(metadata.second)), + tr("Metadata was not fetched because: %1.").arg(NetworkFactory::networkErrorText(metadata.second)), QSystemTrayIcon::Critical); } } diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index 710f6ae3f..2abb87439 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -35,7 +35,7 @@ class StandardServiceRoot; // Represents BASE class for feeds contained in FeedsModel. // NOTE: This class should be derived to create PARTICULAR feed types. class StandardFeed : public Feed { - Q_DECLARE_TR_FUNCTIONS(StandardFeed) + Q_OBJECT public: // Describes possible types of feeds. @@ -61,6 +61,8 @@ class StandardFeed : public Feed { int countOfAllMessages() const; int countOfUnreadMessages() const; + QList specificActions(); + bool canBeEdited() { return true; } diff --git a/src/services/standard/standarditem.cpp b/src/services/standard/standarditem.cpp deleted file mode 100755 index bde2b13d8..000000000 --- a/src/services/standard/standarditem.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "services/standard/standarditem.h" - -#include "services/standard/standardserviceroot.h" - - -StandardItem::StandardItem(StandardServiceRoot *service_root) : m_serviceRoot(service_root) { -} - -StandardItem::~StandardItem() { -} - -StandardServiceRoot *StandardItem::serviceRoot() const { - return m_serviceRoot; -} - -void StandardItem::setServiceRoot(StandardServiceRoot *service_root) { - m_serviceRoot = service_root; -} diff --git a/src/services/standard/standarditem.h b/src/services/standard/standarditem.h deleted file mode 100755 index efe3210d1..000000000 --- a/src/services/standard/standarditem.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef STANDARDITEM_H -#define STANDARDITEM_H - - -class StandardServiceRoot; - -class StandardItem { - public: - explicit StandardItem(StandardServiceRoot *service_root); - virtual ~StandardItem(); - - StandardServiceRoot *serviceRoot() const; - void setServiceRoot(StandardServiceRoot *service_root); - - protected: - StandardServiceRoot *m_serviceRoot; -}; - -#endif // STANDARDITEM_H diff --git a/src/services/standard/standardrecyclebin.h b/src/services/standard/standardrecyclebin.h index 1675b9e5c..393e58ee9 100755 --- a/src/services/standard/standardrecyclebin.h +++ b/src/services/standard/standardrecyclebin.h @@ -24,7 +24,7 @@ class StandardRecycleBin : public RootItem { - Q_DECLARE_TR_FUNCTIONS(StandardRecycleBin) + Q_OBJECT public: explicit StandardRecycleBin(RootItem *parent = NULL); diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 1777337f3..d776f406f 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -20,6 +20,7 @@ #include "definitions/definitions.h" #include "miscellaneous/application.h" #include "miscellaneous/settings.h" +#include "miscellaneous/iconfactory.h" #include "core/feedsmodel.h" #include "services/standard/standardserviceentrypoint.h" #include "services/standard/standardrecyclebin.h" @@ -208,6 +209,17 @@ QHash StandardServiceRoot::allCategories() { return categoriesForItem(this); } +QList StandardServiceRoot::getMenuForFeed(StandardFeed *feed) { + QList list; + + // Fetch feed metadata. + QAction *action_fetch_metadata = new QAction(qApp->icons()->fromTheme(QSL("download-manager")), tr("Fetch metadata"), NULL); + connect(action_fetch_metadata, SIGNAL(triggered()), feed, SLOT(fetchMetadataForItself())); + + list.append(action_fetch_metadata); + return list; +} + void StandardServiceRoot::assembleFeeds(FeedAssignment feeds) { QHash categories = categoriesForItem(this); diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index f43d08239..835b9c81a 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -35,7 +35,7 @@ typedef QList > FeedAssignment; typedef QPair FeedAssignmentItem; class StandardServiceRoot : public ServiceRoot { - Q_DECLARE_TR_FUNCTIONS(StandardServiceRoot) + Q_OBJECT public: explicit StandardServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL); @@ -53,6 +53,8 @@ class StandardServiceRoot : public ServiceRoot { // consists of ID of parent item and pointer to category. QHash allCategories(); + QList getMenuForFeed(StandardFeed *feed); + // Access to standard recycle bin. StandardRecycleBin *recycleBin() const; diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index a5df9c6a2..957517850 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -26,7 +26,7 @@ class FeedsModel; class TtRssServiceRoot : public ServiceRoot { - Q_DECLARE_TR_FUNCTIONS(TtRssServiceRoot) + Q_OBJECT public: explicit TtRssServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL); From 779f42f5dd94450781a929f9443e809b1a3cf4a8 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 6 Nov 2015 11:30:39 +0100 Subject: [PATCH 024/203] Import/export now works, some minor fixing. --- src/core/rootitem.cpp | 2 +- src/core/rootitem.h | 2 +- src/gui/dialogs/formmain.cpp | 16 +++++------ src/gui/dialogs/formmain.h | 27 +++++++++---------- src/gui/feedsview.cpp | 9 +++++-- src/services/abstract/serviceroot.h | 10 +++++++ src/services/standard/standardcategory.cpp | 3 +-- src/services/standard/standardfeed.cpp | 2 +- src/services/standard/standardfeed.h | 2 +- .../standardfeedsimportexportmodel.cpp | 5 ++-- .../standard/standardserviceentrypoint.cpp | 2 +- src/services/standard/standardserviceroot.cpp | 17 ++++++++---- src/services/standard/standardserviceroot.h | 4 ++- 13 files changed, 60 insertions(+), 41 deletions(-) diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index dc48504c4..0892160ac 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -41,7 +41,7 @@ RootItem::~RootItem() { qDeleteAll(m_childItems); } -QList RootItem::specificActions() { +QList RootItem::specificContextMenuActions() { return QList(); } diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 8d25ecf89..3591023e7 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -80,7 +80,7 @@ class RootItem : public QObject { // NOTE: This method should always create new actions in memory // before returning them because caller takes ownership of any // actions returned from here. - virtual QList specificActions(); + virtual QList specificContextMenuActions(); // TODO: pracovat s těmito věcmi virtual bool canBeEdited() { diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index 738509e84..c1b8e7d60 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -395,25 +395,21 @@ void FormMain::loadWebBrowserMenu(int index) { } void FormMain::exportFeeds() { - // TODO: dodelat globalni pristup ke globalnimu standard service rootu, - // ten předat - /* - QPointer form = new FormStandardImportExport(this); + // TODO: crash + QPointer form = new FormStandardImportExport(tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->standardServiceRoot(), + this); form.data()->setMode(FeedsImportExportModel::Export); form.data()->exec(); delete form.data(); - */ } void FormMain::importFeeds() { - // TODO: dodelat globalni pristup ke globalnimu standard service rootu, - // ten předat - /* - QPointer form = new FormStandardImportExport(this); + // TODO: crash + QPointer form = new FormStandardImportExport(tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->standardServiceRoot(), + this); form.data()->setMode(FeedsImportExportModel::Import); form.data()->exec(); delete form.data(); - */ } void FormMain::backupDatabaseSettings() { diff --git a/src/gui/dialogs/formmain.h b/src/gui/dialogs/formmain.h index 39d2c62bf..7537acdcd 100755 --- a/src/gui/dialogs/formmain.h +++ b/src/gui/dialogs/formmain.h @@ -64,19 +64,6 @@ class FormMain : public QMainWindow { void loadSize(); void saveSize(); - protected: - // Creates all needed menus and sets them up. - void prepareMenus(); - - // Creates needed connections for this window. - void createConnections(); - - // Event handler reimplementations. - void changeEvent(QEvent *event); - - // Sets up proper icons for this widget. - void setupIcons(); - public slots: // Displays window on top or switches its visibility. void display(); @@ -90,7 +77,7 @@ class FormMain : public QMainWindow { // Switches visibility of main menu. void switchMainMenu(); - protected slots: + private slots: // Loads web browser menu if user selects to change tabs. void loadWebBrowserMenu(int index); @@ -108,6 +95,18 @@ class FormMain : public QMainWindow { void donate(); private: + // Event handler reimplementations. + void changeEvent(QEvent *event); + + // Creates all needed menus and sets them up. + void prepareMenus(); + + // Creates needed connections for this window. + void createConnections(); + + // Sets up proper icons for this widget. + void setupIcons(); + Ui::FormMain *m_ui; QMenu *m_trayMenu; StatusBar *m_statusBar; diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index ab3a57ac6..759e320fd 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -491,7 +491,7 @@ void FeedsView::initializeContextMenuCategories(RootItem *clicked_item) { m_contextMenuCategories->clear(); } - QList specific_actions = clicked_item->specificActions(); + QList specific_actions = clicked_item->specificContextMenuActions(); m_contextMenuCategories->addActions(QList() << qApp->mainForm()->m_ui->m_actionUpdateSelectedFeeds << @@ -512,10 +512,12 @@ void FeedsView::initializeContextMenuFeeds(RootItem *clicked_item) { m_contextMenuFeeds = new QMenu(tr("Context menu for categories"), this); } else { + // FIXME: Položky jsou mazány při opětovném otevření kontextového nabíky ale je lepší je mazat + // hned při zavření kontextove nabíky. m_contextMenuFeeds->clear(); } - QList specific_actions = clicked_item->specificActions(); + QList specific_actions = clicked_item->specificContextMenuActions(); m_contextMenuFeeds->addActions(QList() << qApp->mainForm()->m_ui->m_actionUpdateSelectedFeeds << @@ -604,6 +606,9 @@ void FeedsView::contextMenuEvent(QContextMenuEvent *event) { initializeContextMenuFeeds(clicked_item); m_contextMenuFeeds->exec(event->globalPos()); } + else { + + } } else { // Display menu for empty space. diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 86315accc..ebcc8a11a 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -33,6 +33,16 @@ class ServiceRoot : public RootItem { explicit ServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL); virtual ~ServiceRoot(); + // Returns list of specific actions for "Add new item" main window menu. + // So typical list of returned actions could look like: + // a) Add new feed + // b) Add new category + // c) ... + // NOTE: This method should always create new actions in memory + // before returning them because caller takes ownership of any + // actions returned from here. + virtual QList specificAddItemActions() = 0; + inline FeedsModel *feedsModel() const { return m_feedsModel; } diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index a5d62b8ff..24503c6e3 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -158,7 +158,7 @@ bool StandardCategory::removeItself() { } if (children_removed) { - // Children are removed, remove this standard category too. + // Children are removed, remove this standard category too. QSqlDatabase database = qApp->database()->connection(QSL("Category"), DatabaseFactory::FromSettings); QSqlQuery query_remove(database); @@ -176,7 +176,6 @@ bool StandardCategory::removeItself() { bool StandardCategory::addItself(RootItem *parent) { // Now, add category to persistent storage. - // Children are removed, remove this standard category too. QSqlDatabase database = qApp->database()->connection(QSL("Category"), DatabaseFactory::FromSettings); QSqlQuery query_add(database); diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 7f9511148..c175a1b66 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -99,7 +99,7 @@ int StandardFeed::countOfUnreadMessages() const { return m_unreadCount; } -QList StandardFeed::specificActions() { +QList StandardFeed::specificContextMenuActions() { return serviceRoot()->getMenuForFeed(this); } diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index 2abb87439..af642320f 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -61,7 +61,7 @@ class StandardFeed : public Feed { int countOfAllMessages() const; int countOfUnreadMessages() const; - QList specificActions(); + QList specificContextMenuActions(); bool canBeEdited() { return true; diff --git a/src/services/standard/standardfeedsimportexportmodel.cpp b/src/services/standard/standardfeedsimportexportmodel.cpp index 3133be8a3..837ebc3f6 100755 --- a/src/services/standard/standardfeedsimportexportmodel.cpp +++ b/src/services/standard/standardfeedsimportexportmodel.cpp @@ -19,6 +19,7 @@ #include "services/standard/standardfeed.h" #include "services/standard/standardcategory.h" +#include "services/standard/standardserviceroot.h" #include "definitions/definitions.h" #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" @@ -166,7 +167,7 @@ bool FeedsImportExportModel::importAsOPML20(const QByteArray &data) { return false; } - RootItem *root_item = new RootItem(); + StandardServiceRoot *root_item = new StandardServiceRoot(false, NULL, NULL); QStack model_items; model_items.push(root_item); QStack elements_to_process; elements_to_process.push(opml_document.documentElement().elementsByTagName(QSL("body")).at(0).toElement()); @@ -295,7 +296,7 @@ QModelIndex FeedsImportExportModel::index(int row, int column, const QModelIndex } QModelIndex FeedsImportExportModel::indexForItem(RootItem *item) const { - if (item == NULL || item->kind() == RootItemKind::Root) { + if (item == NULL || item->kind() == RootItemKind::ServiceRoot || item->kind() == RootItemKind::Root) { // Root item lies on invalid index. return QModelIndex(); } diff --git a/src/services/standard/standardserviceentrypoint.cpp b/src/services/standard/standardserviceentrypoint.cpp index de70987d7..3156a927c 100755 --- a/src/services/standard/standardserviceentrypoint.cpp +++ b/src/services/standard/standardserviceentrypoint.cpp @@ -70,7 +70,7 @@ QIcon StandardServiceEntryPoint::icon() { } QList StandardServiceEntryPoint::initializeSubtree(FeedsModel *main_model) { - StandardServiceRoot *root = new StandardServiceRoot(main_model); + StandardServiceRoot *root = new StandardServiceRoot(true, main_model); QList roots; roots.append(root); diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index d776f406f..0536b69be 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -34,14 +34,16 @@ #include -StandardServiceRoot::StandardServiceRoot(FeedsModel *feeds_model, RootItem *parent) +StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent) : ServiceRoot(feeds_model, parent), m_recycleBin(new StandardRecycleBin(this)) { m_title = qApp->system()->getUsername() + QL1S("@") + QL1S(APP_LOW_NAME); m_icon = StandardServiceEntryPoint().icon(); m_description = tr("This is obligatory service account for standard RSS/RDF/ATOM feeds."); m_creationDate = QDateTime::currentDateTime(); - loadFromDatabase(); + if (load_from_db) { + loadFromDatabase(); + } } StandardServiceRoot::~StandardServiceRoot() { @@ -312,9 +314,6 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, } } - // Changes are done now. Finalize the new model. - //emit layoutChanged(); - if (some_feed_category_error) { output_message = tr("Import successfull, but some feeds/categories were not imported due to error."); } @@ -325,6 +324,14 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, return !some_feed_category_error; } +QList StandardServiceRoot::specificAddItemActions() { + QList actions; + + // TODO: vracet add feed, add category + actions.append(new QAction("abc", NULL)); + return actions; +} + void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { QHash assignments; assignments.insert(NO_PARENT_CATEGORY, this); diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 835b9c81a..9309b35f3 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -38,7 +38,7 @@ class StandardServiceRoot : public ServiceRoot { Q_OBJECT public: - explicit StandardServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL); + explicit StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent = NULL); virtual ~StandardServiceRoot(); bool canBeEdited(); @@ -63,6 +63,8 @@ class StandardServiceRoot : public ServiceRoot { // NOTE: This is used for import/export of the model. bool mergeImportExportModel(FeedsImportExportModel *model, QString &output_message); + QList specificAddItemActions(); + private: void loadFromDatabase(); From c3384af89e2a411b0bb19e7133cb26fe76a02d0f Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 6 Nov 2015 12:47:12 +0100 Subject: [PATCH 025/203] Some work on "add item" interface menus. --- src/core/feedsmodel.cpp | 2 -- src/gui/dialogs/formmain.cpp | 36 +++++++++++++++++-- src/gui/dialogs/formmain.h | 2 ++ src/gui/feedsview.cpp | 15 ++++++++ src/services/standard/standardfeed.cpp | 2 +- src/services/standard/standardserviceroot.cpp | 2 +- src/services/standard/standardserviceroot.h | 4 ++- 7 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 53b424c29..e5f73fa0f 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -63,8 +63,6 @@ FeedsModel::FeedsModel(QObject *parent) connect(m_autoUpdateTimer, SIGNAL(timeout()), this, SLOT(executeNextAutoUpdate())); loadActivatedServiceAccounts(); - - // Setup the timer. updateAutoUpdateStatus(); } diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index c1b8e7d60..e9382209a 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -39,6 +39,7 @@ #include "gui/dialogs/formbackupdatabasesettings.h" #include "gui/dialogs/formrestoredatabasesettings.h" #include "gui/notifications/notification.h" +#include "services/abstract/serviceroot.h" #include "services/standard/gui/formstandardimportexport.h" #include @@ -171,6 +172,37 @@ void FormMain::switchMainMenu() { m_ui->m_menuBar->setVisible(m_ui->m_actionSwitchMainMenu->isChecked()); } +void FormMain::updateAddItemMenu() { + // TODO: clear nevymaže z paměti. - edit, stačí nastavit parent na to menu + // a při clear to i vymaže z paměti. + m_ui->m_menuAddItem->clear(); + + foreach (ServiceRoot *activated_root, tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->serviceRoots()) { + QMenu *root_menu = new QMenu(activated_root->title(), m_ui->m_menuAddItem); + QList root_actions = activated_root->specificAddItemActions(); + + root_menu->setIcon(activated_root->icon()); + root_menu->setToolTip(activated_root->description()); + + if (root_actions.isEmpty()) { + QAction *no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")), + tr("No possible actions"), + m_ui->m_menuAddItem); + no_action->setEnabled(false); + root_menu->addAction(no_action); + } + else { + foreach (QAction *action, root_actions) { + action->setParent(root_menu); + } + + root_menu->addActions(root_actions); + } + + m_ui->m_menuAddItem->addMenu(root_menu); + } +} + void FormMain::switchVisibility(bool force_hide) { if (force_hide || isVisible()) { if (SystemTrayIcon::isSystemTrayActivated()) { @@ -335,6 +367,8 @@ void FormMain::createConnections() { connect(m_statusBar->fullscreenSwitcher(), SIGNAL(toggled(bool)), m_ui->m_actionFullscreen, SLOT(setChecked(bool))); connect(m_ui->m_actionFullscreen, SIGNAL(toggled(bool)), m_statusBar->fullscreenSwitcher(), SLOT(setChecked(bool))); + connect(m_ui->m_menuAddItem, SIGNAL(aboutToShow()), this, SLOT(updateAddItemMenu())); + // Menu "File" connections. connect(m_ui->m_actionExportFeeds, SIGNAL(triggered()), this, SLOT(exportFeeds())); connect(m_ui->m_actionImportFeeds, SIGNAL(triggered()), this, SLOT(importFeeds())); @@ -395,7 +429,6 @@ void FormMain::loadWebBrowserMenu(int index) { } void FormMain::exportFeeds() { - // TODO: crash QPointer form = new FormStandardImportExport(tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->standardServiceRoot(), this); form.data()->setMode(FeedsImportExportModel::Export); @@ -404,7 +437,6 @@ void FormMain::exportFeeds() { } void FormMain::importFeeds() { - // TODO: crash QPointer form = new FormStandardImportExport(tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->standardServiceRoot(), this); form.data()->setMode(FeedsImportExportModel::Import); diff --git a/src/gui/dialogs/formmain.h b/src/gui/dialogs/formmain.h index 7537acdcd..2f212f8f8 100755 --- a/src/gui/dialogs/formmain.h +++ b/src/gui/dialogs/formmain.h @@ -78,6 +78,8 @@ class FormMain : public QMainWindow { void switchMainMenu(); private slots: + void updateAddItemMenu(); + // Loads web browser menu if user selects to change tabs. void loadWebBrowserMenu(int index); diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 759e320fd..d3ba8f629 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -488,6 +488,9 @@ void FeedsView::initializeContextMenuCategories(RootItem *clicked_item) { m_contextMenuCategories = new QMenu(tr("Context menu for categories"), this); } else { + + // TODO: clear nevymaže z paměti. + // http://doc.qt.io/qt-4.8/qmenu.html#clear m_contextMenuCategories->clear(); } @@ -503,6 +506,11 @@ void FeedsView::initializeContextMenuCategories(RootItem *clicked_item) { if (!specific_actions.isEmpty()) { m_contextMenuCategories->addSeparator(); + + foreach (QAction *action, specific_actions) { + action->setParent(m_contextMenuCategories); + } + m_contextMenuCategories->addActions(specific_actions); } } @@ -514,6 +522,8 @@ void FeedsView::initializeContextMenuFeeds(RootItem *clicked_item) { else { // FIXME: Položky jsou mazány při opětovném otevření kontextového nabíky ale je lepší je mazat // hned při zavření kontextove nabíky. + + // TODO: clear nevymaže z paměti. m_contextMenuFeeds->clear(); } @@ -529,6 +539,11 @@ void FeedsView::initializeContextMenuFeeds(RootItem *clicked_item) { if (!specific_actions.isEmpty()) { m_contextMenuFeeds->addSeparator(); + + foreach (QAction *action, specific_actions) { + action->setParent(m_contextMenuFeeds); + } + m_contextMenuFeeds->addActions(specific_actions); } } diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index c175a1b66..3e59e98c1 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -100,7 +100,7 @@ int StandardFeed::countOfUnreadMessages() const { } QList StandardFeed::specificContextMenuActions() { - return serviceRoot()->getMenuForFeed(this); + return serviceRoot()->getContextMenuForFeed(this); } StandardServiceRoot *StandardFeed::serviceRoot() { diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 0536b69be..c028dadf3 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -211,7 +211,7 @@ QHash StandardServiceRoot::allCategories() { return categoriesForItem(this); } -QList StandardServiceRoot::getMenuForFeed(StandardFeed *feed) { +QList StandardServiceRoot::getContextMenuForFeed(StandardFeed *feed) { QList list; // Fetch feed metadata. diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 9309b35f3..60409ea29 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -53,7 +53,8 @@ class StandardServiceRoot : public ServiceRoot { // consists of ID of parent item and pointer to category. QHash allCategories(); - QList getMenuForFeed(StandardFeed *feed); + // Returns context specific menu actions for given feed. + QList getContextMenuForFeed(StandardFeed *feed); // Access to standard recycle bin. StandardRecycleBin *recycleBin() const; @@ -63,6 +64,7 @@ class StandardServiceRoot : public ServiceRoot { // NOTE: This is used for import/export of the model. bool mergeImportExportModel(FeedsImportExportModel *model, QString &output_message); + // Return "add feed" and "add category" items. QList specificAddItemActions(); private: From fa976120b864bc96902050843d0bd7a3bc7ca96f Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 8 Nov 2015 10:53:13 +0100 Subject: [PATCH 026/203] Work on menus. --- src/gui/dialogs/formmain.cpp | 20 ++++++------------ src/gui/feedsview.cpp | 3 ++- src/services/abstract/serviceroot.h | 11 +++++----- src/services/standard/standardserviceroot.cpp | 21 +++++++++++++------ src/services/standard/standardserviceroot.h | 6 +++++- 5 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index e9382209a..52aac9651 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -173,31 +173,23 @@ void FormMain::switchMainMenu() { } void FormMain::updateAddItemMenu() { - // TODO: clear nevymaže z paměti. - edit, stačí nastavit parent na to menu - // a při clear to i vymaže z paměti. + // NOTE: Clear here deletes items from memory but only those OWNED by the menu. m_ui->m_menuAddItem->clear(); foreach (ServiceRoot *activated_root, tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->serviceRoots()) { - QMenu *root_menu = new QMenu(activated_root->title(), m_ui->m_menuAddItem); - QList root_actions = activated_root->specificAddItemActions(); + QMenu *root_menu = activated_root->addItemMenu(); - root_menu->setIcon(activated_root->icon()); - root_menu->setToolTip(activated_root->description()); + if (root_menu == NULL) { + root_menu = new QMenu(activated_root->title(), m_ui->m_menuAddItem); + root_menu->setIcon(activated_root->icon()); + root_menu->setToolTip(activated_root->description()); - if (root_actions.isEmpty()) { QAction *no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")), tr("No possible actions"), m_ui->m_menuAddItem); no_action->setEnabled(false); root_menu->addAction(no_action); } - else { - foreach (QAction *action, root_actions) { - action->setParent(root_menu); - } - - root_menu->addActions(root_actions); - } m_ui->m_menuAddItem->addMenu(root_menu); } diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index d3ba8f629..3696162ef 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -622,7 +622,8 @@ void FeedsView::contextMenuEvent(QContextMenuEvent *event) { m_contextMenuFeeds->exec(event->globalPos()); } else { - + // TODO: volaz specificke menu polozky? zobrazovat menu pro dalsi typy + // polozek jako odpadkovy kos atp. } } else { diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index ebcc8a11a..242c4a99d 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -22,6 +22,7 @@ class FeedsModel; +class QMenu; // THIS IS the root node of the service. // NOTE: The root usually contains some core functionality of the @@ -38,17 +39,17 @@ class ServiceRoot : public RootItem { // a) Add new feed // b) Add new category // c) ... - // NOTE: This method should always create new actions in memory - // before returning them because caller takes ownership of any - // actions returned from here. - virtual QList specificAddItemActions() = 0; + // NOTE: Caller does NOT take ownership of created menu! + virtual QMenu* addItemMenu() = 0; + + // TODO: dodělat menu, které se zobrazi v menubaru "Services -> tato služba". inline FeedsModel *feedsModel() const { return m_feedsModel; } protected: - FeedsModel *m_feedsModel; + FeedsModel *m_feedsModel; }; #endif // SERVICEROOT_H diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index c028dadf3..b480a713d 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -32,10 +32,11 @@ #include #include #include +#include StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent) - : ServiceRoot(feeds_model, parent), m_recycleBin(new StandardRecycleBin(this)) { + : ServiceRoot(feeds_model, parent), m_recycleBin(new StandardRecycleBin(this)), m_addItemMenu(NULL) { m_title = qApp->system()->getUsername() + QL1S("@") + QL1S(APP_LOW_NAME); m_icon = StandardServiceEntryPoint().icon(); m_description = tr("This is obligatory service account for standard RSS/RDF/ATOM feeds."); @@ -47,6 +48,9 @@ StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_mo } StandardServiceRoot::~StandardServiceRoot() { + if (m_addItemMenu != NULL) { + delete m_addItemMenu; + } } bool StandardServiceRoot::canBeEdited() { @@ -324,12 +328,17 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, return !some_feed_category_error; } -QList StandardServiceRoot::specificAddItemActions() { - QList actions; +QMenu *StandardServiceRoot::addItemMenu() { + if (m_addItemMenu == NULL) { + m_addItemMenu = new QMenu(title(), NULL); + m_addItemMenu->setIcon(icon()); + m_addItemMenu->setToolTip(description()); - // TODO: vracet add feed, add category - actions.append(new QAction("abc", NULL)); - return actions; + // TODO: Add items. + m_addItemMenu->addAction(new QAction("abc", m_addItemMenu)); + } + + return m_addItemMenu; } void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 60409ea29..598d552be 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -27,6 +27,7 @@ class StandardRecycleBin; class StandardCategory; class StandardFeed; class FeedsImportExportModel; +class QMenu; typedef QList > CategoryAssignment; typedef QPair CategoryAssignmentItem; @@ -65,7 +66,7 @@ class StandardServiceRoot : public ServiceRoot { bool mergeImportExportModel(FeedsImportExportModel *model, QString &output_message); // Return "add feed" and "add category" items. - QList specificAddItemActions(); + QMenu *addItemMenu(); private: void loadFromDatabase(); @@ -76,6 +77,9 @@ class StandardServiceRoot : public ServiceRoot { void assembleFeeds(FeedAssignment feeds); StandardRecycleBin *m_recycleBin; + + // Menus. + QMenu *m_addItemMenu; }; #endif // STANDARDSERVICEROOT_H From 2d97915d86c25d614e0b05775434ca8f3b264ee4 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 8 Nov 2015 19:48:29 +0100 Subject: [PATCH 027/203] Work on menus - 2. --- src/core/rootitem.h | 4 +-- src/gui/dialogs/formmain.cpp | 13 ++++--- src/gui/feedsview.cpp | 13 ------- src/services/abstract/serviceroot.h | 6 ++-- src/services/standard/standardserviceroot.cpp | 35 +++++++++---------- src/services/standard/standardserviceroot.h | 7 ++-- 6 files changed, 33 insertions(+), 45 deletions(-) diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 3591023e7..16da2c970 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -77,9 +77,7 @@ class RootItem : public QObject { } // Returns list of specific actions which can be done with the item. - // NOTE: This method should always create new actions in memory - // before returning them because caller takes ownership of any - // actions returned from here. + // NOTE: Ownership of returned actions is not switched to caller, free them when needed. virtual QList specificContextMenuActions(); // TODO: pracovat s těmito věcmi diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index 52aac9651..ec213982f 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -177,19 +177,22 @@ void FormMain::updateAddItemMenu() { m_ui->m_menuAddItem->clear(); foreach (ServiceRoot *activated_root, tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->serviceRoots()) { - QMenu *root_menu = activated_root->addItemMenu(); + QMenu *root_menu = new QMenu(activated_root->title(), m_ui->m_menuAddItem); + root_menu->setIcon(activated_root->icon()); + root_menu->setToolTip(activated_root->description()); - if (root_menu == NULL) { - root_menu = new QMenu(activated_root->title(), m_ui->m_menuAddItem); - root_menu->setIcon(activated_root->icon()); - root_menu->setToolTip(activated_root->description()); + QList root_actions = activated_root->addItemMenu(); + if (root_actions.isEmpty()) { QAction *no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")), tr("No possible actions"), m_ui->m_menuAddItem); no_action->setEnabled(false); root_menu->addAction(no_action); } + else { + root_menu->addActions(root_actions); + } m_ui->m_menuAddItem->addMenu(root_menu); } diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 3696162ef..c38b2598f 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -488,9 +488,6 @@ void FeedsView::initializeContextMenuCategories(RootItem *clicked_item) { m_contextMenuCategories = new QMenu(tr("Context menu for categories"), this); } else { - - // TODO: clear nevymaže z paměti. - // http://doc.qt.io/qt-4.8/qmenu.html#clear m_contextMenuCategories->clear(); } @@ -506,11 +503,6 @@ void FeedsView::initializeContextMenuCategories(RootItem *clicked_item) { if (!specific_actions.isEmpty()) { m_contextMenuCategories->addSeparator(); - - foreach (QAction *action, specific_actions) { - action->setParent(m_contextMenuCategories); - } - m_contextMenuCategories->addActions(specific_actions); } } @@ -539,11 +531,6 @@ void FeedsView::initializeContextMenuFeeds(RootItem *clicked_item) { if (!specific_actions.isEmpty()) { m_contextMenuFeeds->addSeparator(); - - foreach (QAction *action, specific_actions) { - action->setParent(m_contextMenuFeeds); - } - m_contextMenuFeeds->addActions(specific_actions); } } diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 242c4a99d..89b47efb0 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -22,7 +22,7 @@ class FeedsModel; -class QMenu; +class QAction; // THIS IS the root node of the service. // NOTE: The root usually contains some core functionality of the @@ -40,9 +40,7 @@ class ServiceRoot : public RootItem { // b) Add new category // c) ... // NOTE: Caller does NOT take ownership of created menu! - virtual QMenu* addItemMenu() = 0; - - // TODO: dodělat menu, které se zobrazi v menubaru "Services -> tato služba". + virtual QList addItemMenu() = 0; inline FeedsModel *feedsModel() const { return m_feedsModel; diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index b480a713d..147e4ca0a 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -32,11 +32,12 @@ #include #include #include -#include +#include StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent) - : ServiceRoot(feeds_model, parent), m_recycleBin(new StandardRecycleBin(this)), m_addItemMenu(NULL) { + : ServiceRoot(feeds_model, parent), m_recycleBin(new StandardRecycleBin(this)), + m_addItemMenu(QList()), m_feedContextMenu(QList()), m_actionFeedFetchMetadata(NULL) { m_title = qApp->system()->getUsername() + QL1S("@") + QL1S(APP_LOW_NAME); m_icon = StandardServiceEntryPoint().icon(); m_description = tr("This is obligatory service account for standard RSS/RDF/ATOM feeds."); @@ -48,9 +49,8 @@ StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_mo } StandardServiceRoot::~StandardServiceRoot() { - if (m_addItemMenu != NULL) { - delete m_addItemMenu; - } + qDeleteAll(m_addItemMenu); + qDeleteAll(m_feedContextMenu); } bool StandardServiceRoot::canBeEdited() { @@ -216,14 +216,17 @@ QHash StandardServiceRoot::allCategories() { } QList StandardServiceRoot::getContextMenuForFeed(StandardFeed *feed) { - QList list; + if (m_feedContextMenu.isEmpty()) { + // Initialize. + m_actionFeedFetchMetadata = new QAction(qApp->icons()->fromTheme(QSL("download-manager")), tr("Fetch metadata"), NULL); + m_feedContextMenu.append(m_actionFeedFetchMetadata); + } - // Fetch feed metadata. - QAction *action_fetch_metadata = new QAction(qApp->icons()->fromTheme(QSL("download-manager")), tr("Fetch metadata"), NULL); - connect(action_fetch_metadata, SIGNAL(triggered()), feed, SLOT(fetchMetadataForItself())); + // Make connections. + disconnect(m_actionFeedFetchMetadata, SIGNAL(triggered()), 0, 0); + connect(m_actionFeedFetchMetadata, SIGNAL(triggered()), feed, SLOT(fetchMetadataForItself())); - list.append(action_fetch_metadata); - return list; + return m_feedContextMenu; } void StandardServiceRoot::assembleFeeds(FeedAssignment feeds) { @@ -328,14 +331,10 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, return !some_feed_category_error; } -QMenu *StandardServiceRoot::addItemMenu() { - if (m_addItemMenu == NULL) { - m_addItemMenu = new QMenu(title(), NULL); - m_addItemMenu->setIcon(icon()); - m_addItemMenu->setToolTip(description()); - +QList StandardServiceRoot::addItemMenu() { + if (m_addItemMenu.isEmpty()) { // TODO: Add items. - m_addItemMenu->addAction(new QAction("abc", m_addItemMenu)); + m_addItemMenu.append(new QAction("abc", this)); } return m_addItemMenu; diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 598d552be..7c2b9ab92 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -66,7 +66,7 @@ class StandardServiceRoot : public ServiceRoot { bool mergeImportExportModel(FeedsImportExportModel *model, QString &output_message); // Return "add feed" and "add category" items. - QMenu *addItemMenu(); + QList addItemMenu(); private: void loadFromDatabase(); @@ -79,7 +79,10 @@ class StandardServiceRoot : public ServiceRoot { StandardRecycleBin *m_recycleBin; // Menus. - QMenu *m_addItemMenu; + QList m_addItemMenu; + QList m_feedContextMenu; + + QAction *m_actionFeedFetchMetadata; }; #endif // STANDARDSERVICEROOT_H From b3fc86c6960e6028111b82ae1b731eedb0636691 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 9 Nov 2015 09:40:26 +0100 Subject: [PATCH 028/203] Refactored item/model data getters. --- resources/text/CHANGELOG | 3 +- src/core/rootitem.cpp | 88 ++++++++++++--- src/core/rootitem.h | 20 +++- src/services/abstract/feed.h | 4 +- src/services/abstract/serviceroot.cpp | 2 +- .../standard/gui/formstandardfeeddetails.cpp | 2 +- src/services/standard/standardcategory.cpp | 74 +++--------- src/services/standard/standardfeed.cpp | 105 +++++------------- src/services/standard/standardfeed.h | 3 - src/services/standard/standardrecyclebin.cpp | 22 ++-- src/services/standard/standardserviceroot.cpp | 53 +-------- src/services/standard/standardserviceroot.h | 6 +- src/services/tt-rss/ttrssserviceroot.cpp | 49 +------- 13 files changed, 160 insertions(+), 271 deletions(-) diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 37dbd535d..a5c6fd6ca 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -16,11 +16,12 @@ Added:
    -
  • Brand new "service plugin system" - HIGHLY EXPERIMENTAL and REWRITTEN from scratch. Some UI features (for example drag-drop) are temporarily unavailable. Expect bugs and misunderstandings now!
  • +
  • Brand new "service plugin system" - HIGHLY EXPERIMENTAL and REWRITTEN from scratch. Some UI features (for example drag-drop) are temporarily unavailable. Expect bugs and misunderstandings now! Major parts of RSS Guard were completely rewritten.
Fixed:
    +
  • Encoding selection widget in feed add/edit dialog now detects encodings via case insensitive string matching.
  • When removing download item from download manager via DELETE key, then "Cleanup" button is correctly disabled.
diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index 0892160ac..8084919a6 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -26,7 +26,8 @@ RootItem::RootItem(RootItem *parent_item) - : m_kind(RootItemKind::Root), + : QObject(NULL), + m_kind(RootItemKind::Root), m_id(NO_PARENT_CATEGORY), m_title(QString()), m_description(QString()), @@ -50,6 +51,26 @@ void RootItem::setupFonts() { m_boldFont = m_normalFont; m_boldFont.setBold(true); } +QFont RootItem::boldFont() const +{ + return m_boldFont; +} + +void RootItem::setBoldFont(const QFont &boldFont) +{ + m_boldFont = boldFont; +} + +QFont RootItem::normalFont() const +{ + return m_normalFont; +} + +void RootItem::setNormalFont(const QFont &normalFont) +{ + m_normalFont = normalFont; +} + int RootItem::row() const { if (m_parentItem) { @@ -65,8 +86,56 @@ QVariant RootItem::data(int column, int role) const { Q_UNUSED(column) Q_UNUSED(role) - // Do not return anything for the root item. - return QVariant(); + switch (role) { + case Qt::EditRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return title(); + } + else if (column == FDS_MODEL_COUNTS_INDEX) { + return countOfUnreadMessages(); + } + else { + return QVariant(); + } + + case Qt::FontRole: + return countOfUnreadMessages() > 0 ? boldFont() : normalFont(); + + case Qt::DisplayRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return title(); + } + else if (column == FDS_MODEL_COUNTS_INDEX) { + int count_all = countOfAllMessages(); + int count_unread = countOfUnreadMessages(); + + return qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::CountFormat)).toString() + .replace(PLACEHOLDER_UNREAD_COUNTS, count_unread < 0 ? QSL('-') : QString::number(count_unread)) + .replace(PLACEHOLDER_ALL_COUNTS, count_all < 0 ? QSL('-') : QString::number(count_all)); + } + else { + return QVariant(); + } + + case Qt::DecorationRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return icon(); + } + else { + return QVariant(); + } + + case Qt::TextAlignmentRole: + if (column == FDS_MODEL_COUNTS_INDEX) { + return Qt::AlignCenter; + } + else { + return QVariant(); + } + + default: + return QVariant(); + } } int RootItem::countOfAllMessages() const { @@ -206,16 +275,3 @@ bool RootItem::removeChild(int index) { return false; } } - -bool RootItem::isEqual(RootItem *lhs, RootItem *rhs) { - return (lhs->kind() == rhs->kind()) && (lhs->id() == rhs->id()); -} - -bool RootItem::lessThan(RootItem *lhs, RootItem *rhs) { - if (lhs->kind() == rhs->kind()) { - return lhs->id() < rhs->id(); - } - else { - return false; - } -} diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 16da2c970..a1785b2c5 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -127,6 +127,10 @@ class RootItem : public QObject { return m_childItems; } + inline void setChildItems(QList child_items) { + m_childItems = child_items; + } + // Checks whether THIS object is child (direct or indirect) // of the given root. bool isChildOf(RootItem *root) { @@ -183,6 +187,10 @@ class RootItem : public QObject { return m_kind; } + inline void setKind(RootItemKind::Kind kind) { + m_kind = kind; + } + // Each item can have icon. inline QIcon icon() const { return m_icon; @@ -226,16 +234,18 @@ class RootItem : public QObject { m_description = description; } + QFont normalFont() const; + void setNormalFont(const QFont &normalFont); + + QFont boldFont() const; + void setBoldFont(const QFont &boldFont); + // Converters Category *toCategory(); Feed *toFeed(); ServiceRoot *toServiceRoot(); - // Compares two model items. - static bool isEqual(RootItem *lhs, RootItem *rhs); - static bool lessThan(RootItem *lhs, RootItem *rhs); - - protected: + private: void setupFonts(); RootItemKind::Kind m_kind; diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index 6083c5b86..b04ce1532 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -70,8 +70,6 @@ class Feed : public RootItem { // Get ALL undeleted messages from this feed in one single list. virtual QList undeletedMessages() const = 0; - //virtual bool markRead(ReadStatus read_status) = 0; - inline int autoUpdateInitialInterval() const { return m_autoUpdateInitialInterval; } @@ -107,7 +105,7 @@ class Feed : public RootItem { m_status = status; } - protected: + private: Status m_status; AutoUpdateType m_autoUpdateType; int m_autoUpdateInitialInterval; diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index ebd5f21d3..994dbdaa9 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -21,7 +21,7 @@ ServiceRoot::ServiceRoot(FeedsModel *feeds_model, RootItem *parent) : RootItem(parent), m_feedsModel(feeds_model) { - m_kind = RootItemKind::ServiceRoot; + setKind(RootItemKind::ServiceRoot); } ServiceRoot::~ServiceRoot() { diff --git a/src/services/standard/gui/formstandardfeeddetails.cpp b/src/services/standard/gui/formstandardfeeddetails.cpp index bfecd6312..e6a64cb5a 100755 --- a/src/services/standard/gui/formstandardfeeddetails.cpp +++ b/src/services/standard/gui/formstandardfeeddetails.cpp @@ -372,7 +372,7 @@ void FormStandardFeedDetails::setEditableFeed(StandardFeed *editable_feed) { m_ui->m_txtDescription->lineEdit()->setText(editable_feed->description()); m_ui->m_btnIcon->setIcon(editable_feed->icon()); m_ui->m_cmbType->setCurrentIndex(m_ui->m_cmbType->findData(QVariant::fromValue((int) editable_feed->type()))); - m_ui->m_cmbEncoding->setCurrentIndex(m_ui->m_cmbEncoding->findData(editable_feed->encoding(), Qt::DisplayRole)); + m_ui->m_cmbEncoding->setCurrentIndex(m_ui->m_cmbEncoding->findData(editable_feed->encoding(), Qt::DisplayRole, Qt::MatchFixedString)); m_ui->m_gbAuthentication->setChecked(editable_feed->passwordProtected()); m_ui->m_txtUsername->lineEdit()->setText(editable_feed->username()); m_ui->m_txtPassword->lineEdit()->setText(editable_feed->password()); diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index 24503c6e3..6fa73df5a 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -42,14 +42,15 @@ StandardCategory::StandardCategory(RootItem *parent_item) : Category(parent_item StandardCategory::StandardCategory(const StandardCategory &other) : Category(NULL) { - m_kind = other.kind(); - m_id = other.id(); - m_title = other.title(); - m_description = other.description(); - m_icon = other.icon(); - m_creationDate = other.creationDate(); - m_childItems = other.childItems(); - m_parentItem = other.parent(); + init(); + + setId(other.id()); + setTitle(other.title()); + setDescription(other.description()); + setIcon(other.icon()); + setCreationDate(other.creationDate()); + setChildItems(other.childItems()); + setParent(other.parent()); } StandardCategory::~StandardCategory() { @@ -61,7 +62,7 @@ StandardServiceRoot *StandardCategory::serviceRoot() { } void StandardCategory::init() { - m_kind = RootItemKind::Category; + setKind(RootItemKind::Category); } QVariant StandardCategory::data(int column, int role) const { @@ -70,9 +71,9 @@ QVariant StandardCategory::data(int column, int role) const { if (column == FDS_MODEL_TITLE_INDEX) { //: Tooltip for standard feed. return tr("%1 (category)" - "%2%3").arg(m_title, - m_description.isEmpty() ? QString() : QString('\n') + m_description, - m_childItems.size() == 0 ? + "%2%3").arg(title(), + description().isEmpty() ? QString() : QSL('\n') + description(), + childCount() == 0 ? tr("\nThis category does not contain any nested items.") : QString()); } @@ -84,51 +85,8 @@ QVariant StandardCategory::data(int column, int role) const { return QVariant(); } - case Qt::EditRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return m_title; - } - else if (column == FDS_MODEL_COUNTS_INDEX) { - return countOfUnreadMessages(); - } - else { - return QVariant(); - } - - case Qt::FontRole: - return countOfUnreadMessages() > 0 ? m_boldFont : m_normalFont; - - case Qt::DisplayRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return m_title; - } - else if (column == FDS_MODEL_COUNTS_INDEX) { - return qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::CountFormat)).toString() - .replace(PLACEHOLDER_UNREAD_COUNTS, QString::number(countOfUnreadMessages())) - .replace(PLACEHOLDER_ALL_COUNTS, QString::number(countOfAllMessages())); - } - else { - return QVariant(); - } - - case Qt::DecorationRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return m_icon; - } - else { - return QVariant(); - } - - case Qt::TextAlignmentRole: - if (column == FDS_MODEL_COUNTS_INDEX) { - return Qt::AlignCenter; - } - else { - return QVariant(); - } - default: - return QVariant(); + return Category::data(column, role); } } @@ -148,7 +106,7 @@ bool StandardCategory::removeItself() { bool children_removed = true; // Remove all child items (feeds, categories.) - foreach (RootItem *child, m_childItems) { + foreach (RootItem *child, childItems()) { if (child->kind() == RootItemKind::Category) { children_removed &= static_cast(child)->removeItself(); } @@ -158,7 +116,7 @@ bool StandardCategory::removeItself() { } if (children_removed) { - // Children are removed, remove this standard category too. + // Children are removed, remove this standard category too. QSqlDatabase database = qApp->database()->connection(QSL("Category"), DatabaseFactory::FromSettings); QSqlQuery query_remove(database); diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 3e59e98c1..54ee4c106 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -44,7 +44,8 @@ #include -void StandardFeed::init() { +StandardFeed::StandardFeed(RootItem *parent_item) + : Feed(parent_item) { m_passwordProtected = false; m_username = QString(); m_password = QString(); @@ -54,12 +55,8 @@ void StandardFeed::init() { m_unreadCount = 0; m_encoding = QString(); m_url = QString(); - m_kind = RootItemKind::Feed; -} -StandardFeed::StandardFeed(RootItem *parent_item) - : Feed(parent_item) { - init(); + setKind(RootItemKind::Feed); } StandardFeed::StandardFeed(const StandardFeed &other) @@ -73,18 +70,20 @@ StandardFeed::StandardFeed(const StandardFeed &other) m_unreadCount = other.countOfUnreadMessages(); m_encoding = other.encoding(); m_url = other.url(); - m_kind = RootItemKind::Feed; - m_title = other.title(); - m_id = other.id(); - m_icon = other.icon(); - m_childItems = other.childItems(); - m_parentItem = other.parent(); - m_creationDate = other.creationDate(); - m_description = other.description(); - m_status = other.status(); - m_autoUpdateType = other.autoUpdateType(); - m_autoUpdateInitialInterval = other.autoUpdateInitialInterval(); - m_autoUpdateRemainingInterval = other.autoUpdateRemainingInterval(); + + setStatus(other.status()); + setAutoUpdateType(other.autoUpdateType()); + setAutoUpdateInitialInterval(other.autoUpdateInitialInterval()); + setAutoUpdateRemainingInterval(other.autoUpdateRemainingInterval()); + + setKind(RootItemKind::Feed); + setTitle(other.title()); + setId(other.id()); + setIcon(other.icon()); + setChildItems(other.childItems()); + setParent(other.parent()); + setCreationDate(other.creationDate()); + setDescription(other.description()); } StandardFeed::~StandardFeed() { @@ -182,8 +181,8 @@ void StandardFeed::updateCounts(bool including_total_count, bool update_feed_sta if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE feed = %1 AND is_deleted = 0 AND is_read = 0;").arg(id())) && query_all.next()) { int new_unread_count = query_all.value(0).toInt(); - if (update_feed_statuses && m_status == NewMessages && new_unread_count < m_unreadCount) { - m_status = Normal; + if (update_feed_statuses && status() == NewMessages && new_unread_count < m_unreadCount) { + setStatus(Normal); } m_unreadCount = new_unread_count; @@ -361,43 +360,11 @@ QPair StandardFeed::guessFeed(const Q QVariant StandardFeed::data(int column, int role) const { switch (role) { - case Qt::DisplayRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return m_title; - } - else if (column == FDS_MODEL_COUNTS_INDEX) { - return qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::CountFormat)).toString() - .replace(PLACEHOLDER_UNREAD_COUNTS, QString::number(countOfUnreadMessages())) - .replace(PLACEHOLDER_ALL_COUNTS, QString::number(countOfAllMessages())); - } - else { - return QVariant(); - } - - case Qt::EditRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return m_title; - } - else if (column == FDS_MODEL_COUNTS_INDEX) { - return countOfUnreadMessages(); - } - else { - return QVariant(); - } - - case Qt::DecorationRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return m_icon; - } - else { - return QVariant(); - } - case Qt::ToolTipRole: if (column == FDS_MODEL_TITLE_INDEX) { QString auto_update_string; - switch (m_autoUpdateType) { + switch (autoUpdateType()) { case DontAutoUpdate: //: Describes feed auto-update status. auto_update_string = tr("does not use auto-update"); @@ -414,7 +381,7 @@ QVariant StandardFeed::data(int column, int role) const { auto_update_string = tr("uses specific settings " "(%n minute(s) to next auto-update)", 0, - m_autoUpdateRemainingInterval); + autoUpdateRemainingInterval()); break; } @@ -423,10 +390,10 @@ QVariant StandardFeed::data(int column, int role) const { "%3\n\n" "Network status: %6\n" "Encoding: %4\n" - "Auto-update status: %5").arg(m_title, - StandardFeed::typeToString(m_type), - m_description.isEmpty() ? QString() : QString('\n') + m_description, - m_encoding, + "Auto-update status: %5").arg(title(), + StandardFeed::typeToString(type()), + description().isEmpty() ? QString() : QString('\n') + description(), + encoding(), auto_update_string, NetworkFactory::networkErrorText(m_networkError)); } @@ -438,19 +405,8 @@ QVariant StandardFeed::data(int column, int role) const { return QVariant(); } - case Qt::TextAlignmentRole: - if (column == FDS_MODEL_COUNTS_INDEX) { - return Qt::AlignCenter; - } - else { - return QVariant(); - } - - case Qt::FontRole: - return countOfUnreadMessages() > 0 ? m_boldFont : m_normalFont; - case Qt::ForegroundRole: - switch (m_status) { + switch (status()) { case NewMessages: return QColor(Qt::blue); @@ -462,7 +418,7 @@ QVariant StandardFeed::data(int column, int role) const { } default: - return QVariant(); + return Feed::data(column, role); } } @@ -474,11 +430,11 @@ int StandardFeed::update() { if (m_networkError != QNetworkReply::NoError) { qWarning("Error during fetching of new messages for feed '%s' (id %d).", qPrintable(url()), id()); - m_status = NetworkError; + setStatus(NetworkError); return 0; } else { - m_status = Normal; + setStatus(Normal); } // Encode downloaded data for further parsing. @@ -762,8 +718,7 @@ QNetworkReply::NetworkError StandardFeed::networkError() const { } StandardFeed::StandardFeed(const QSqlRecord &record) : Feed(NULL) { - m_kind = RootItemKind::Feed; - + setKind(RootItemKind::Feed); setTitle(record.value(FDS_DB_TITLE_INDEX).toString()); setId(record.value(FDS_DB_ID_INDEX).toInt()); setDescription(record.value(FDS_DB_DESCRIPTION_INDEX).toString()); diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index af642320f..f4c8d0c6a 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -162,9 +162,6 @@ class StandardFeed : public Feed { // available. int updateMessages(const QList &messages); - private: - void init(); - private: bool m_passwordProtected; QString m_username; diff --git a/src/services/standard/standardrecyclebin.cpp b/src/services/standard/standardrecyclebin.cpp index ace8c3ee9..45305466e 100755 --- a/src/services/standard/standardrecyclebin.cpp +++ b/src/services/standard/standardrecyclebin.cpp @@ -25,13 +25,12 @@ StandardRecycleBin::StandardRecycleBin(RootItem *parent) : RootItem(parent) { - m_kind = RootItemKind::Bin; - m_icon = qApp->icons()->fromTheme(QSL("folder-recycle-bin")); - m_id = ID_RECYCLE_BIN; - m_title = tr("Recycle bin"); - m_description = tr("Recycle bin contains all deleted messages from all feeds."); - m_creationDate = QDateTime::currentDateTime(); - + setKind(RootItemKind::Bin); + setIcon(qApp->icons()->fromTheme(QSL("folder-recycle-bin"))); + setId(ID_RECYCLE_BIN); + setTitle(tr("Recycle bin")); + setDescription(tr("Recycle bin contains all deleted messages from all feeds.")); + setCreationDate(QDateTime::currentDateTime()); updateCounts(true); } @@ -59,7 +58,7 @@ QVariant StandardRecycleBin::data(int column, int role) const { switch (role) { case Qt::DisplayRole: if (column == FDS_MODEL_TITLE_INDEX) { - return m_title; + return title(); } else if (column == FDS_MODEL_COUNTS_INDEX) { return qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::CountFormat)).toString() @@ -72,7 +71,7 @@ QVariant StandardRecycleBin::data(int column, int role) const { case Qt::EditRole: if (column == FDS_MODEL_TITLE_INDEX) { - return m_title; + return title(); } else if (column == FDS_MODEL_COUNTS_INDEX) { return countOfUnreadMessages(); @@ -82,11 +81,12 @@ QVariant StandardRecycleBin::data(int column, int role) const { } case Qt::FontRole: - return countOfUnreadMessages() > 0 ? m_boldFont : m_normalFont; + // TODO: přesunout společny části do předka a volat ho odtud. + return countOfUnreadMessages() > 0 ? boldFont() : normalFont(); case Qt::DecorationRole: if (column == FDS_MODEL_TITLE_INDEX) { - return m_icon; + return icon(); } else { return QVariant(); diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 147e4ca0a..2f6b076ac 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -38,10 +38,10 @@ StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent) : ServiceRoot(feeds_model, parent), m_recycleBin(new StandardRecycleBin(this)), m_addItemMenu(QList()), m_feedContextMenu(QList()), m_actionFeedFetchMetadata(NULL) { - m_title = qApp->system()->getUsername() + QL1S("@") + QL1S(APP_LOW_NAME); - m_icon = StandardServiceEntryPoint().icon(); - m_description = tr("This is obligatory service account for standard RSS/RDF/ATOM feeds."); - m_creationDate = QDateTime::currentDateTime(); + setTitle(qApp->system()->getUsername() + QL1S("@") + QL1S(APP_LOW_NAME)); + setIcon(StandardServiceEntryPoint().icon()); + setDescription(tr("This is obligatory service account for standard RSS/RDF/ATOM feeds.")); + setCreationDate(QDateTime::currentDateTime()); if (load_from_db) { loadFromDatabase(); @@ -63,38 +63,6 @@ bool StandardServiceRoot::canBeDeleted() { QVariant StandardServiceRoot::data(int column, int role) const { switch (role) { - case Qt::DisplayRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return m_title; - } - else if (column == FDS_MODEL_COUNTS_INDEX) { - return qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::CountFormat)).toString() - .replace(PLACEHOLDER_UNREAD_COUNTS, QString::number(countOfUnreadMessages())) - .replace(PLACEHOLDER_ALL_COUNTS, QString::number(countOfAllMessages())); - } - else { - return QVariant(); - } - - case Qt::EditRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return m_title; - } - else if (column == FDS_MODEL_COUNTS_INDEX) { - return countOfUnreadMessages(); - } - else { - return QVariant(); - } - - case Qt::DecorationRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return m_icon; - } - else { - return QVariant(); - } - case Qt::ToolTipRole: if (column == FDS_MODEL_TITLE_INDEX) { return tr("This is service account for standard RSS/RDF/ATOM feeds."); @@ -107,19 +75,8 @@ QVariant StandardServiceRoot::data(int column, int role) const { return QVariant(); } - case Qt::TextAlignmentRole: - if (column == FDS_MODEL_COUNTS_INDEX) { - return Qt::AlignCenter; - } - else { - return QVariant(); - } - - case Qt::FontRole: - return countOfUnreadMessages() > 0 ? m_boldFont : m_normalFont; - default: - return QVariant(); + return ServiceRoot::data(column, role); } } diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 7c2b9ab92..230f40188 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -46,6 +46,9 @@ class StandardServiceRoot : public ServiceRoot { bool canBeDeleted(); QVariant data(int column, int role) const; + // Return "add feed" and "add category" items. + QList addItemMenu(); + // Returns all standard categories which are lying under given root node. // This does NOT include the root node even if the node is category. QHash categoriesForItem(RootItem *root); @@ -65,9 +68,6 @@ class StandardServiceRoot : public ServiceRoot { // NOTE: This is used for import/export of the model. bool mergeImportExportModel(FeedsImportExportModel *model, QString &output_message); - // Return "add feed" and "add category" items. - QList addItemMenu(); - private: void loadFromDatabase(); diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 74cc6cd04..406512724 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -26,8 +26,8 @@ TtRssServiceRoot::TtRssServiceRoot(FeedsModel *feeds_model, RootItem *parent) : ServiceRoot(feeds_model, parent) { // TODO: nadpis se bude měnit podle nastavení uživatelského // jména a serveru tohoto ttrss učtu - m_title = qApp->system()->getUsername() + "@ttrss"; - m_icon = TtRssServiceEntryPoint().icon(); + setTitle(qApp->system()->getUsername() + "@ttrss"); + setIcon(TtRssServiceEntryPoint().icon()); } TtRssServiceRoot::~TtRssServiceRoot() { @@ -48,38 +48,6 @@ bool TtRssServiceRoot::canBeDeleted() { QVariant TtRssServiceRoot::data(int column, int role) const { switch (role) { - case Qt::DisplayRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return m_title; - } - else if (column == FDS_MODEL_COUNTS_INDEX) { - return qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::CountFormat)).toString() - .replace(PLACEHOLDER_UNREAD_COUNTS, QString::number(countOfUnreadMessages())) - .replace(PLACEHOLDER_ALL_COUNTS, QString::number(countOfAllMessages())); - } - else { - return QVariant(); - } - - case Qt::EditRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return m_title; - } - else if (column == FDS_MODEL_COUNTS_INDEX) { - return countOfUnreadMessages(); - } - else { - return QVariant(); - } - - case Qt::DecorationRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return m_icon; - } - else { - return QVariant(); - } - case Qt::ToolTipRole: // TODO: zobrazovat pokročile informace a statistiky. if (column == FDS_MODEL_TITLE_INDEX) { @@ -93,19 +61,8 @@ QVariant TtRssServiceRoot::data(int column, int role) const { return QVariant(); } - case Qt::TextAlignmentRole: - if (column == FDS_MODEL_COUNTS_INDEX) { - return Qt::AlignCenter; - } - else { - return QVariant(); - } - - case Qt::FontRole: - return countOfUnreadMessages() > 0 ? m_boldFont : m_normalFont; - default: - return QVariant(); + return ServiceRoot::data(column, role); } } From 27aa11ff837ad662cfcfa7d2344daac518e7652b Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 9 Nov 2015 09:42:48 +0100 Subject: [PATCH 029/203] Fix style. --- src/core/rootitem.cpp | 18 +++++++----------- src/core/rootitem.h | 4 ++-- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index 8084919a6..47bec016c 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -51,27 +51,23 @@ void RootItem::setupFonts() { m_boldFont = m_normalFont; m_boldFont.setBold(true); } -QFont RootItem::boldFont() const -{ + +QFont RootItem::boldFont() const { return m_boldFont; } -void RootItem::setBoldFont(const QFont &boldFont) -{ - m_boldFont = boldFont; +void RootItem::setBoldFont(const QFont &bold_font) { + m_boldFont = bold_font; } -QFont RootItem::normalFont() const -{ +QFont RootItem::normalFont() const { return m_normalFont; } -void RootItem::setNormalFont(const QFont &normalFont) -{ - m_normalFont = normalFont; +void RootItem::setNormalFont(const QFont &normal_font) { + m_normalFont = normal_font; } - int RootItem::row() const { if (m_parentItem) { return m_parentItem->m_childItems.indexOf(const_cast(this)); diff --git a/src/core/rootitem.h b/src/core/rootitem.h index a1785b2c5..5bd5ef8f2 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -235,10 +235,10 @@ class RootItem : public QObject { } QFont normalFont() const; - void setNormalFont(const QFont &normalFont); + void setNormalFont(const QFont &normal_font); QFont boldFont() const; - void setBoldFont(const QFont &boldFont); + void setBoldFont(const QFont &bold_font); // Converters Category *toCategory(); From 9fac1568c57edb553ef7d66b36dcc08df21b26c6 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 9 Nov 2015 10:17:48 +0100 Subject: [PATCH 030/203] Added global service root menu to main form etc. --- src/core/rootitem.cpp | 2 +- src/core/rootitem.h | 4 ++- src/gui/dialogs/formmain.cpp | 34 +++++++++++++++++++ src/gui/dialogs/formmain.h | 1 + src/gui/feedsview.cpp | 8 ++--- src/services/abstract/serviceroot.h | 7 +++- src/services/standard/standardfeed.cpp | 2 +- src/services/standard/standardfeed.h | 2 +- src/services/standard/standardserviceroot.cpp | 4 +++ src/services/standard/standardserviceroot.h | 3 ++ 10 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index 47bec016c..e92ef64f4 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -42,7 +42,7 @@ RootItem::~RootItem() { qDeleteAll(m_childItems); } -QList RootItem::specificContextMenuActions() { +QList RootItem::contextMenuActions() { return QList(); } diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 5bd5ef8f2..450153e77 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -77,8 +77,10 @@ class RootItem : public QObject { } // Returns list of specific actions which can be done with the item. + // Do not include general actions here like actions: + // Mark as read, Update, ... // NOTE: Ownership of returned actions is not switched to caller, free them when needed. - virtual QList specificContextMenuActions(); + virtual QList contextMenuActions(); // TODO: pracovat s těmito věcmi virtual bool canBeEdited() { diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index ec213982f..c7879b9c5 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -198,6 +198,39 @@ void FormMain::updateAddItemMenu() { } } +void FormMain::updateServicesMenu() { + m_ui->m_menuServices->clear(); + + foreach (ServiceRoot *activated_root, tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->serviceRoots()) { + QMenu *root_menu = new QMenu(activated_root->title(), m_ui->m_menuServices); + root_menu->setIcon(activated_root->icon()); + root_menu->setToolTip(activated_root->description()); + + QList root_actions = activated_root->serviceMenu(); + + if (root_actions.isEmpty()) { + QAction *no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")), + tr("No possible actions"), + m_ui->m_menuServices); + no_action->setEnabled(false); + root_menu->addAction(no_action); + } + else { + root_menu->addActions(root_actions); + } + + m_ui->m_menuServices->addMenu(root_menu); + } + + if (!m_ui->m_menuServices->isEmpty()) { + m_ui->m_menuServices->addSeparator(); + } + + m_ui->m_menuServices->addAction(m_ui->m_actionServiceAdd); + m_ui->m_menuServices->addAction(m_ui->m_actionServiceEdit); + m_ui->m_menuServices->addAction(m_ui->m_actionServiceDelete); +} + void FormMain::switchVisibility(bool force_hide) { if (force_hide || isVisible()) { if (SystemTrayIcon::isSystemTrayActivated()) { @@ -363,6 +396,7 @@ void FormMain::createConnections() { connect(m_ui->m_actionFullscreen, SIGNAL(toggled(bool)), m_statusBar->fullscreenSwitcher(), SLOT(setChecked(bool))); connect(m_ui->m_menuAddItem, SIGNAL(aboutToShow()), this, SLOT(updateAddItemMenu())); + connect(m_ui->m_menuServices, SIGNAL(aboutToShow()), this, SLOT(updateServicesMenu())); // Menu "File" connections. connect(m_ui->m_actionExportFeeds, SIGNAL(triggered()), this, SLOT(exportFeeds())); diff --git a/src/gui/dialogs/formmain.h b/src/gui/dialogs/formmain.h index 2f212f8f8..97149e9c2 100755 --- a/src/gui/dialogs/formmain.h +++ b/src/gui/dialogs/formmain.h @@ -79,6 +79,7 @@ class FormMain : public QMainWindow { private slots: void updateAddItemMenu(); + void updateServicesMenu(); // Loads web browser menu if user selects to change tabs. void loadWebBrowserMenu(int index); diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index c38b2598f..9fac64286 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -491,7 +491,7 @@ void FeedsView::initializeContextMenuCategories(RootItem *clicked_item) { m_contextMenuCategories->clear(); } - QList specific_actions = clicked_item->specificContextMenuActions(); + QList specific_actions = clicked_item->contextMenuActions(); m_contextMenuCategories->addActions(QList() << qApp->mainForm()->m_ui->m_actionUpdateSelectedFeeds << @@ -512,14 +512,10 @@ void FeedsView::initializeContextMenuFeeds(RootItem *clicked_item) { m_contextMenuFeeds = new QMenu(tr("Context menu for categories"), this); } else { - // FIXME: Položky jsou mazány při opětovném otevření kontextového nabíky ale je lepší je mazat - // hned při zavření kontextove nabíky. - - // TODO: clear nevymaže z paměti. m_contextMenuFeeds->clear(); } - QList specific_actions = clicked_item->specificContextMenuActions(); + QList specific_actions = clicked_item->contextMenuActions(); m_contextMenuFeeds->addActions(QList() << qApp->mainForm()->m_ui->m_actionUpdateSelectedFeeds << diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 89b47efb0..a8471eea3 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -42,12 +42,17 @@ class ServiceRoot : public RootItem { // NOTE: Caller does NOT take ownership of created menu! virtual QList addItemMenu() = 0; + // Returns list of specific actions to be shown in main window menu + // bar in sections "Services -> 'this service'". + // NOTE: Caller does NOT take ownership of created menu! + virtual QList serviceMenu() = 0; + inline FeedsModel *feedsModel() const { return m_feedsModel; } protected: - FeedsModel *m_feedsModel; + FeedsModel *m_feedsModel; }; #endif // SERVICEROOT_H diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 54ee4c106..530b0a939 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -98,7 +98,7 @@ int StandardFeed::countOfUnreadMessages() const { return m_unreadCount; } -QList StandardFeed::specificContextMenuActions() { +QList StandardFeed::contextMenuActions() { return serviceRoot()->getContextMenuForFeed(this); } diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index f4c8d0c6a..395710995 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -61,7 +61,7 @@ class StandardFeed : public Feed { int countOfAllMessages() const; int countOfUnreadMessages() const; - QList specificContextMenuActions(); + QList contextMenuActions(); bool canBeEdited() { return true; diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 2f6b076ac..9bb171d59 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -297,6 +297,10 @@ QList StandardServiceRoot::addItemMenu() { return m_addItemMenu; } +QList StandardServiceRoot::serviceMenu() { + return QList(); +} + void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { QHash assignments; assignments.insert(NO_PARENT_CATEGORY, this); diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 230f40188..406d0e74a 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -49,6 +49,9 @@ class StandardServiceRoot : public ServiceRoot { // Return "add feed" and "add category" items. QList addItemMenu(); + // Return menu to be shown in "Services -> service" menu. + QList serviceMenu(); + // Returns all standard categories which are lying under given root node. // This does NOT include the root node even if the node is category. QHash categoriesForItem(RootItem *root); From b84fd00891031590ae3c0022f98e951bb1cf8e95 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 10 Nov 2015 08:59:10 +0100 Subject: [PATCH 031/203] Work on system. --- src/core/feedsmodel.cpp | 5 +-- src/main.cpp | 18 ++------ src/miscellaneous/application.cpp | 28 ++++++++---- src/miscellaneous/application.h | 14 ++++-- src/miscellaneous/systemfactory.cpp | 2 +- src/services/abstract/serviceroot.cpp | 4 ++ src/services/abstract/serviceroot.h | 15 +++++-- src/services/standard/standardserviceroot.cpp | 45 ++++++++++++++++++- src/services/standard/standardserviceroot.h | 3 ++ 9 files changed, 97 insertions(+), 37 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index e5f73fa0f..e5b8f93c4 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -418,11 +418,8 @@ void FeedsModel::loadActivatedServiceAccounts() { QList roots = entry_point->initializeSubtree(this); foreach (ServiceRoot *root, roots) { - if (SystemFactory::isInstanceOf(root)) { - - } - m_rootItem->appendChild(root); + root->start(); } } } diff --git a/src/main.cpp b/src/main.cpp index 6a6c2fcde..9ce0874b6 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -107,27 +107,15 @@ int main(int argc, char *argv[]) { else { qDebug("Showing the main window when the application is starting."); main_window.show(); - - if (qApp->settings()->value(GROUP(General), SETTING(General::FirstRun)).toBool()) { - // This is the first time user runs this application. - qApp->settings()->setValue(GROUP(General), General::FirstRun, false); - - if (MessageBox::show(&main_window, QMessageBox::Question, QObject::tr("Load initial feeds"), - QObject::tr("You started %1 for the first time, now you can load initial set of feeds.").arg(APP_NAME), - QObject::tr("Do you want to load initial set of feeds?"), - QString(), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - qApp->mainForm()->tabWidget()->feedMessageViewer()->loadInitialFeeds(); - } - } } // Display tray icon if it is enabled and available. if (SystemTrayIcon::isSystemTrayActivated()) { qApp->showTrayIcon(); + } - if (qApp->settings()->value(GROUP(General), SETTING(General::UpdateOnStartup)).toBool()) { - QTimer::singleShot(STARTUP_UPDATE_DELAY, application.system(), SLOT(checkForUpdatesOnStartup())); - } + if (qApp->settings()->value(GROUP(General), SETTING(General::UpdateOnStartup)).toBool()) { + QTimer::singleShot(STARTUP_UPDATE_DELAY, application.system(), SLOT(checkForUpdatesOnStartup())); } // Setup single-instance behavior. diff --git a/src/miscellaneous/application.cpp b/src/miscellaneous/application.cpp index e4f7190ca..b47449d5b 100755 --- a/src/miscellaneous/application.cpp +++ b/src/miscellaneous/application.cpp @@ -28,6 +28,7 @@ #include "exceptions/applicationexception.h" #include "adblock/adblockmanager.h" +#include "services/abstract/serviceroot.h" #include "services/standard/standardserviceentrypoint.h" #include "services/tt-rss/ttrssserviceentrypoint.h" @@ -70,6 +71,22 @@ QList Application::userActions() { return m_userActions; } +bool Application::isFirstRun() { + return settings()->value(GROUP(General), SETTING(General::FirstRun)).toBool(); +} + +bool Application::isFirstRun(const QString &version) { + return settings()->value(GROUP(General), QString(General::FirstRun) + QL1C('_') + version, true).toBool(); +} + +void Application::eliminateFirstRun() { + settings()->setValue(GROUP(General), General::FirstRun, false); +} + +void Application::eliminateFirstRun(const QString &version) { + settings()->setValue(GROUP(General), QString(General::FirstRun) + QL1C('_') + version, false); +} + IconFactory *Application::icons() { if (m_icons == NULL) { m_icons = new IconFactory(this); @@ -216,6 +233,9 @@ void Application::onSaveState(QSessionManager &manager) { } void Application::onAboutToQuit() { + eliminateFirstRun(); + eliminateFirstRun(APP_VERSION); + // Make sure that we obtain close lock BEFORE even trying to quit the application. bool locked_safely = feedUpdateLock()->tryLock(4 * CLOSE_LOCK_TIMEOUT); @@ -264,14 +284,6 @@ void Application::onAboutToQuit() { } } -bool Application::shouldRestart() const { - return m_shouldRestart; -} - -void Application::setShouldRestart(bool shouldRestart) { - m_shouldRestart = shouldRestart; -} - void Application::restart() { m_shouldRestart = true; quit(); diff --git a/src/miscellaneous/application.h b/src/miscellaneous/application.h index c9aa87cb5..7899cec46 100755 --- a/src/miscellaneous/application.h +++ b/src/miscellaneous/application.h @@ -59,8 +59,15 @@ class Application : public QtSingleApplication { // "standard" service entry point. QList feedServices(); + // Globally accessible actions. QList userActions(); + // Check whether this application starts for the first time (ever). + bool isFirstRun(); + + // Check whether GIVEN VERSION of the application starts for the first time. + bool isFirstRun(const QString &version); + inline SystemFactory *system() { if (m_system == NULL) { m_system = new SystemFactory(this); @@ -159,10 +166,8 @@ class Application : public QtSingleApplication { return static_cast(QCoreApplication::instance()); } - bool shouldRestart() const; - void setShouldRestart(bool shouldRestart); - public slots: + // Restarts the application. void restart(); // Processes incoming message from another RSS Guard instance. @@ -175,6 +180,9 @@ class Application : public QtSingleApplication { void onAboutToQuit(); private: + void eliminateFirstRun(); + void eliminateFirstRun(const QString &version); + // This read-write lock is used by application on its close. // Application locks this lock for WRITING. // This means that if application locks that lock, then diff --git a/src/miscellaneous/systemfactory.cpp b/src/miscellaneous/systemfactory.cpp index 1e80fa486..ea424ef60 100755 --- a/src/miscellaneous/systemfactory.cpp +++ b/src/miscellaneous/systemfactory.cpp @@ -272,6 +272,6 @@ void SystemFactory::checkForUpdatesOnStartup() { qApp->showGuiMessage(tr("New version available"), tr("Click the bubble for more information."), QSystemTrayIcon::Information, - NULL, false, QIcon(), qApp->mainForm(), SLOT(showUpdates())); + NULL, true, QIcon(), qApp->mainForm(), SLOT(showUpdates())); } } diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index 994dbdaa9..516331c7d 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -26,3 +26,7 @@ ServiceRoot::ServiceRoot(FeedsModel *feeds_model, RootItem *parent) : RootItem(p ServiceRoot::~ServiceRoot() { } + +FeedsModel *ServiceRoot::feedsModel() const { + return m_feedsModel; +} diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index a8471eea3..08ecd307d 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -47,11 +47,18 @@ class ServiceRoot : public RootItem { // NOTE: Caller does NOT take ownership of created menu! virtual QList serviceMenu() = 0; - inline FeedsModel *feedsModel() const { - return m_feedsModel; - } + // Start/stop services. + // Start method is called when feed model gets initialized OR after user adds new service. + // + // Stop method is called just before application exits OR when + // user explicitly deletes existing service instance. + virtual void start() = 0; + virtual void stop() = 0; - protected: + // Access to feed model. + FeedsModel *feedsModel() const; + + private: FeedsModel *m_feedsModel; }; diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 9bb171d59..cf71c528b 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -22,6 +22,9 @@ #include "miscellaneous/settings.h" #include "miscellaneous/iconfactory.h" #include "core/feedsmodel.h" +#include "gui/messagebox.h" +#include "gui/dialogs/formmain.h" +#include "exceptions/applicationexception.h" #include "services/standard/standardserviceentrypoint.h" #include "services/standard/standardrecyclebin.h" #include "services/standard/standardfeed.h" @@ -53,6 +56,44 @@ StandardServiceRoot::~StandardServiceRoot() { qDeleteAll(m_feedContextMenu); } +void StandardServiceRoot::start() { + if (qApp->isFirstRun()) { + if (MessageBox::show(qApp->mainForm(), QMessageBox::Question, QObject::tr("Load initial feeds"), + QObject::tr("You started %1 for the first time, now you can load initial set of feeds.").arg(APP_NAME), + QObject::tr("Do you want to load initial set of feeds?"), + QString(), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + QString target_opml_file = APP_INITIAL_FEEDS_PATH + QDir::separator() + FEED_INITIAL_OPML_PATTERN; + QString current_locale = qApp->localization()->loadedLanguage(); + QString file_to_load; + + if (QFile::exists(target_opml_file.arg(current_locale))) { + file_to_load = target_opml_file.arg(current_locale); + } + else if (QFile::exists(target_opml_file.arg(DEFAULT_LOCALE))) { + file_to_load = target_opml_file.arg(DEFAULT_LOCALE); + } + + FeedsImportExportModel model; + QString output_msg; + + try { + model.importAsOPML20(IOFactory::readTextFile(file_to_load)); + model.checkAllItems(); + + // TODO: Expand all items here? + mergeImportExportModel(&model, output_msg); + } + catch (ApplicationException &ex) { + MessageBox::show(qApp->mainForm(), QMessageBox::Critical, tr("Error when loading initial feeds"), ex.message()); + } + } + } +} + +void StandardServiceRoot::stop() { + +} + bool StandardServiceRoot::canBeEdited() { return false; } @@ -234,7 +275,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, new_category->clearChildren(); if (new_category->addItself(target_parent)) { - m_feedsModel->reassignNodeToNewParent(new_category, target_parent); + feedsModel()->reassignNodeToNewParent(new_category, target_parent); // Process all children of this category. original_parents.push(new_category); @@ -268,7 +309,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, // Append this feed and end this iteration. if (new_feed->addItself(target_parent)) { - m_feedsModel->reassignNodeToNewParent(new_feed, target_parent); + feedsModel()->reassignNodeToNewParent(new_feed, target_parent); } else { delete new_feed; diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 406d0e74a..7af1838ab 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -42,6 +42,9 @@ class StandardServiceRoot : public ServiceRoot { explicit StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent = NULL); virtual ~StandardServiceRoot(); + void start(); + void stop(); + bool canBeEdited(); bool canBeDeleted(); QVariant data(int column, int role) const; From c3ea32cf3d4cd7b3b63f0c03667b6653742c08db Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 10 Nov 2015 09:31:26 +0100 Subject: [PATCH 032/203] Some work on msg viewer and buttons. --- src/gui/dialogs/formmain.ui | 6 ++++ src/gui/feedmessageviewer.cpp | 53 ++++++++++++----------------------- src/gui/feedmessageviewer.h | 11 ++------ src/services/abstract/feed.h | 5 ---- 4 files changed, 26 insertions(+), 49 deletions(-) diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index 974aadb67..1f1f339af 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -644,11 +644,17 @@
+ + false + &Delete selected service account + + false + &Edit selected service account diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 1c2cb6c56..82ea7662a 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -191,33 +191,12 @@ void FeedMessageViewer::quit() { } } -void FeedMessageViewer::loadInitialFeeds() { - QString target_opml_file = APP_INITIAL_FEEDS_PATH + QDir::separator() + FEED_INITIAL_OPML_PATTERN; - QString current_locale = qApp->localization()->loadedLanguage(); - QString file_to_load; +bool FeedMessageViewer::areToolBarsEnabled() const { + return m_toolBarsEnabled; +} - if (QFile::exists(target_opml_file.arg(current_locale))) { - file_to_load = target_opml_file.arg(current_locale); - } - else if (QFile::exists(target_opml_file.arg(DEFAULT_LOCALE))) { - file_to_load = target_opml_file.arg(DEFAULT_LOCALE); - } - - FeedsImportExportModel model; - QString output_msg; - - try { - model.importAsOPML20(IOFactory::readTextFile(file_to_load)); - model.checkAllItems(); - - // TODO: double-check. - if (m_feedsView->sourceModel()->standardServiceRoot()->mergeImportExportModel(&model, output_msg)) { - m_feedsView->expandAll(); - } - } - catch (ApplicationException &ex) { - MessageBox::show(this, QMessageBox::Critical, tr("Error when loading initial feeds"), ex.message()); - } +bool FeedMessageViewer::areListHeadersEnabled() const { + return m_listHeadersEnabled; } void FeedMessageViewer::switchMessageSplitterOrientation() { @@ -306,21 +285,25 @@ void FeedMessageViewer::updateMessageButtonsAvailability() { void FeedMessageViewer::updateFeedButtonsAvailability() { bool critical_action_running = qApp->feedUpdateLock()->isLocked(); - bool feed_selected = !m_feedsView->selectionModel()->selectedRows().isEmpty(); + RootItem *selected_item = feedsView()->selectedItem(); + bool anything_selected = selected_item != NULL; + bool feed_selected = anything_selected && selected_item->kind() == RootItemKind::Feed; + bool category_selected = anything_selected && selected_item->kind() == RootItemKind::Category; + bool service_selected = anything_selected && selected_item->kind() == RootItemKind::ServiceRoot; FormMain *form_main = qApp->mainForm(); form_main->m_ui->m_actionBackupDatabaseSettings->setEnabled(!critical_action_running); form_main->m_ui->m_actionCleanupDatabase->setEnabled(!critical_action_running); - form_main->m_ui->m_actionClearSelectedFeeds->setEnabled(feed_selected); - form_main->m_ui->m_actionDeleteSelectedItem->setEnabled(!critical_action_running && feed_selected); - form_main->m_ui->m_actionEditSelectedItem->setEnabled(!critical_action_running && feed_selected); + form_main->m_ui->m_actionClearSelectedFeeds->setEnabled(feed_selected || category_selected || service_selected); + form_main->m_ui->m_actionDeleteSelectedItem->setEnabled(!critical_action_running && anything_selected); + form_main->m_ui->m_actionEditSelectedItem->setEnabled(!critical_action_running && anything_selected); form_main->m_ui->m_actionImportFeeds->setEnabled(!critical_action_running); - form_main->m_ui->m_actionMarkSelectedFeedsAsRead->setEnabled(feed_selected); - form_main->m_ui->m_actionMarkSelectedFeedsAsUnread->setEnabled(feed_selected); + form_main->m_ui->m_actionMarkSelectedFeedsAsRead->setEnabled(feed_selected || category_selected || service_selected); + form_main->m_ui->m_actionMarkSelectedFeedsAsUnread->setEnabled(feed_selected || category_selected || service_selected); form_main->m_ui->m_actionUpdateAllFeeds->setEnabled(!critical_action_running); - form_main->m_ui->m_actionUpdateSelectedFeeds->setEnabled(!critical_action_running && feed_selected); - form_main->m_ui->m_actionViewSelectedItemsNewspaperMode->setEnabled(feed_selected); - form_main->m_ui->m_actionExpandCollapseFeedCategory->setEnabled(feed_selected); + form_main->m_ui->m_actionUpdateSelectedFeeds->setEnabled(!critical_action_running && (feed_selected || category_selected || service_selected)); + form_main->m_ui->m_actionViewSelectedItemsNewspaperMode->setEnabled(feed_selected || category_selected || service_selected); + form_main->m_ui->m_actionExpandCollapseFeedCategory->setEnabled(feed_selected || category_selected || service_selected); form_main->m_ui->m_menuAddItem->setEnabled(!critical_action_running); } diff --git a/src/gui/feedmessageviewer.h b/src/gui/feedmessageviewer.h index 22020203d..a448bdd88 100755 --- a/src/gui/feedmessageviewer.h +++ b/src/gui/feedmessageviewer.h @@ -79,17 +79,10 @@ class FeedMessageViewer : public TabContent { // stops any child widgets/workers. void quit(); - inline bool areToolBarsEnabled() const { - return m_toolBarsEnabled; - } - - inline bool areListHeadersEnabled() const { - return m_listHeadersEnabled; - } + bool areToolBarsEnabled() const; + bool areListHeadersEnabled() const; public slots: - void loadInitialFeeds(); - // Switches orientation horizontal/vertical. void switchMessageSplitterOrientation(); diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index b04ce1532..c3911a0b2 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -46,11 +46,6 @@ class Feed : public RootItem { OtherError = 4 }; - enum ReadStatus { - Unread = 0, - Read = 1 - }; - // Constructors. explicit Feed(RootItem *parent = NULL); virtual ~Feed(); From 5515c9c7c1a30b83d2f39994dc859ee3a9d501f2 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 10 Nov 2015 13:47:24 +0100 Subject: [PATCH 033/203] Added ability to add feeds/categories to standard service. --- src/network-web/webbrowser.cpp | 5 ++-- .../gui/formstandardcategorydetails.cpp | 3 +- .../standard/gui/formstandardfeeddetails.cpp | 3 +- src/services/standard/standardserviceroot.cpp | 29 +++++++++++++++++-- src/services/standard/standardserviceroot.h | 4 +++ 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/network-web/webbrowser.cpp b/src/network-web/webbrowser.cpp index c1da07cae..7a41612f2 100755 --- a/src/network-web/webbrowser.cpp +++ b/src/network-web/webbrowser.cpp @@ -27,6 +27,7 @@ #include "gui/tabwidget.h" #include "gui/feedmessageviewer.h" #include "gui/feedsview.h" +#include "services/standard/standardserviceroot.h" #include #include @@ -214,9 +215,7 @@ void WebBrowser::onIconChanged() { void WebBrowser::addFeedFromWebsite(const QString &feed_link) { qApp->clipboard()->setText(feed_link); - - // TODO: dodělat - //qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->addNewFeed(); + qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->standardServiceRoot()->addNewFeed(); } void WebBrowser::onTitleChanged(const QString &new_title) { diff --git a/src/services/standard/gui/formstandardcategorydetails.cpp b/src/services/standard/gui/formstandardcategorydetails.cpp index 5c8d94b3d..5c78d9958 100755 --- a/src/services/standard/gui/formstandardcategorydetails.cpp +++ b/src/services/standard/gui/formstandardcategorydetails.cpp @@ -118,7 +118,6 @@ void FormStandardCategoryDetails::apply() { new_category->setCreationDate(QDateTime::currentDateTime()); new_category->setDescription(m_ui->m_txtDescription->lineEdit()->text()); new_category->setIcon(m_ui->m_btnIcon->icon()); - new_category->setParent(parent); if (m_editableCategory == NULL) { // Add the category. @@ -135,6 +134,8 @@ void FormStandardCategoryDetails::apply() { } } else { + new_category->setParent(parent); + bool edited = m_editableCategory->editItself(new_category); if (edited) { diff --git a/src/services/standard/gui/formstandardfeeddetails.cpp b/src/services/standard/gui/formstandardfeeddetails.cpp index e6a64cb5a..c6ccde65b 100755 --- a/src/services/standard/gui/formstandardfeeddetails.cpp +++ b/src/services/standard/gui/formstandardfeeddetails.cpp @@ -237,7 +237,6 @@ void FormStandardFeedDetails::apply() { new_feed->setPassword(m_ui->m_txtPassword->lineEdit()->text()); new_feed->setAutoUpdateType(static_cast(m_ui->m_cmbAutoUpdateType->itemData(m_ui->m_cmbAutoUpdateType->currentIndex()).toInt())); new_feed->setAutoUpdateInitialInterval(m_ui->m_spinAutoUpdateInterval->value()); - new_feed->setParent(parent); if (m_editableFeed == NULL) { // Add the feed. @@ -253,6 +252,8 @@ void FormStandardFeedDetails::apply() { } } else { + new_feed->setParent(parent); + // Edit the feed. bool edited = m_editableFeed->editItself(new_feed); diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index cf71c528b..f475e3aab 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -30,12 +30,15 @@ #include "services/standard/standardfeed.h" #include "services/standard/standardcategory.h" #include "services/standard/standardfeedsimportexportmodel.h" +#include "services/standard/gui/formstandardcategorydetails.h" +#include "services/standard/gui/formstandardfeeddetails.h" #include #include #include #include #include +#include StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent) @@ -329,17 +332,37 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, return !some_feed_category_error; } +void StandardServiceRoot::addNewCategory() { + QPointer form_pointer = new FormStandardCategoryDetails(this, qApp->mainForm()); + + form_pointer.data()->exec(NULL, NULL); + delete form_pointer.data(); +} + +void StandardServiceRoot::addNewFeed() { + QPointer form_pointer = new FormStandardFeedDetails(this, qApp->mainForm()); + + form_pointer.data()->exec(NULL, NULL); + delete form_pointer.data(); +} + QList StandardServiceRoot::addItemMenu() { if (m_addItemMenu.isEmpty()) { - // TODO: Add items. - m_addItemMenu.append(new QAction("abc", this)); + QAction *action_new_category = new QAction(qApp->icons()->fromTheme("folder-category"), tr("Add new category"), this); + connect(action_new_category, SIGNAL(triggered()), this, SLOT(addNewCategory())); + + QAction *action_new_feed = new QAction(qApp->icons()->fromTheme("folder-feed"), tr("Add new feed"), this); + connect(action_new_feed, SIGNAL(triggered()), this, SLOT(addNewFeed())); + + m_addItemMenu.append(action_new_category); + m_addItemMenu.append(action_new_feed); } return m_addItemMenu; } QList StandardServiceRoot::serviceMenu() { - return QList(); + return m_addItemMenu; } void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 7af1838ab..77cfb15fb 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -74,6 +74,10 @@ class StandardServiceRoot : public ServiceRoot { // NOTE: This is used for import/export of the model. bool mergeImportExportModel(FeedsImportExportModel *model, QString &output_message); + public slots: + void addNewCategory(); + void addNewFeed(); + private: void loadFromDatabase(); From cdb51c1a9a9868c953ce7eb77da35e7340b8551f Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 11 Nov 2015 07:40:54 +0100 Subject: [PATCH 034/203] Refactored recycle bin. --- src/services/standard/standardrecyclebin.cpp | 46 +------------------- 1 file changed, 1 insertion(+), 45 deletions(-) diff --git a/src/services/standard/standardrecyclebin.cpp b/src/services/standard/standardrecyclebin.cpp index 45305466e..7fe019083 100755 --- a/src/services/standard/standardrecyclebin.cpp +++ b/src/services/standard/standardrecyclebin.cpp @@ -56,55 +56,11 @@ int StandardRecycleBin::countOfAllMessages() const { QVariant StandardRecycleBin::data(int column, int role) const { switch (role) { - case Qt::DisplayRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return title(); - } - else if (column == FDS_MODEL_COUNTS_INDEX) { - return qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::CountFormat)).toString() - .replace(PLACEHOLDER_UNREAD_COUNTS, QString::number(countOfUnreadMessages())) - .replace(PLACEHOLDER_ALL_COUNTS, QString::number(countOfAllMessages())); - } - else { - return QVariant(); - } - - case Qt::EditRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return title(); - } - else if (column == FDS_MODEL_COUNTS_INDEX) { - return countOfUnreadMessages(); - } - else { - return QVariant(); - } - - case Qt::FontRole: - // TODO: přesunout společny části do předka a volat ho odtud. - return countOfUnreadMessages() > 0 ? boldFont() : normalFont(); - - case Qt::DecorationRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return icon(); - } - else { - return QVariant(); - } - case Qt::ToolTipRole: return tr("Recycle bin\n%1").arg(tr("%n deleted message(s).", 0, countOfAllMessages())); - case Qt::TextAlignmentRole: - if (column == FDS_MODEL_COUNTS_INDEX) { - return Qt::AlignCenter; - } - else { - return QVariant(); - } - default: - return QVariant(); + return RootItem::data(column, role); } } From 17ee15b87f6329ea00250df0bac9e1db221f4704 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 11 Nov 2015 08:21:17 +0100 Subject: [PATCH 035/203] Moved import/export actions to service root. Main form class is now not specific and contains only general code. --- src/gui/dialogs/formmain.cpp | 32 ++----------- src/gui/dialogs/formmain.h | 2 - src/gui/dialogs/formmain.ui | 47 ++++++------------- src/gui/feedmessageviewer.cpp | 11 +++-- src/gui/feedsview.cpp | 6 +-- src/miscellaneous/settings.cpp | 2 +- src/services/standard/standardserviceroot.cpp | 33 +++++++++++-- src/services/standard/standardserviceroot.h | 6 +++ 8 files changed, 65 insertions(+), 74 deletions(-) diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index c7879b9c5..9788c50dc 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -92,8 +92,6 @@ QList FormMain::allActions() { // Add basic actions. actions << m_ui->m_actionSettings; actions << m_ui->m_actionDownloadManager; - actions << m_ui->m_actionImportFeeds; - actions << m_ui->m_actionExportFeeds; actions << m_ui->m_actionRestoreDatabaseSettings; actions << m_ui->m_actionBackupDatabaseSettings; actions << m_ui->m_actionRestart; @@ -124,8 +122,8 @@ QList FormMain::allActions() { actions << m_ui->m_actionMarkSelectedMessagesAsUnread; actions << m_ui->m_actionSwitchImportanceOfSelectedMessages; actions << m_ui->m_actionDeleteSelectedMessages; - actions << m_ui->m_actionUpdateAllFeeds; - actions << m_ui->m_actionUpdateSelectedFeeds; + actions << m_ui->m_actionUpdateAllItems; + actions << m_ui->m_actionUpdateSelectedItems; actions << m_ui->m_actionEditSelectedItem; actions << m_ui->m_actionDeleteSelectedItem; actions << m_ui->m_actionViewSelectedItemsNewspaperMode; @@ -150,7 +148,7 @@ void FormMain::prepareMenus() { // Add needed items to the menu. m_trayMenu->addAction(m_ui->m_actionSwitchMainWindow); m_trayMenu->addSeparator(); - m_trayMenu->addAction(m_ui->m_actionUpdateAllFeeds); + m_trayMenu->addAction(m_ui->m_actionUpdateAllItems); m_trayMenu->addAction(m_ui->m_actionMarkAllFeedsRead); m_trayMenu->addSeparator(); m_trayMenu->addAction(m_ui->m_actionSettings); @@ -272,8 +270,6 @@ void FormMain::setupIcons() { m_ui->m_actionCleanupDatabase->setIcon(icon_theme_factory->fromTheme(QSL("cleanup-database"))); m_ui->m_actionReportBugGitHub->setIcon(icon_theme_factory->fromTheme(QSL("application-report-bug"))); m_ui->m_actionReportBugBitBucket->setIcon(icon_theme_factory->fromTheme(QSL("application-report-bug"))); - m_ui->m_actionExportFeeds->setIcon(icon_theme_factory->fromTheme(QSL("document-export"))); - m_ui->m_actionImportFeeds->setIcon(icon_theme_factory->fromTheme(QSL("document-import"))); m_ui->m_actionBackupDatabaseSettings->setIcon(icon_theme_factory->fromTheme(QSL("document-export"))); m_ui->m_actionRestoreDatabaseSettings->setIcon(icon_theme_factory->fromTheme(QSL("document-import"))); m_ui->m_actionDonate->setIcon(icon_theme_factory->fromTheme(QSL("application-donate"))); @@ -301,8 +297,8 @@ void FormMain::setupIcons() { // Feeds/messages. m_ui->m_menuAddItem->setIcon(icon_theme_factory->fromTheme(QSL("item-new"))); - m_ui->m_actionUpdateAllFeeds->setIcon(icon_theme_factory->fromTheme(QSL("item-update-all"))); - m_ui->m_actionUpdateSelectedFeeds->setIcon(icon_theme_factory->fromTheme(QSL("item-update-selected"))); + m_ui->m_actionUpdateAllItems->setIcon(icon_theme_factory->fromTheme(QSL("item-update-all"))); + m_ui->m_actionUpdateSelectedItems->setIcon(icon_theme_factory->fromTheme(QSL("item-update-selected"))); m_ui->m_actionClearSelectedFeeds->setIcon(icon_theme_factory->fromTheme(QSL("mail-remove"))); m_ui->m_actionClearAllFeeds->setIcon(icon_theme_factory->fromTheme(QSL("mail-remove"))); m_ui->m_actionDeleteSelectedItem->setIcon(icon_theme_factory->fromTheme(QSL("item-remove"))); @@ -399,8 +395,6 @@ void FormMain::createConnections() { connect(m_ui->m_menuServices, SIGNAL(aboutToShow()), this, SLOT(updateServicesMenu())); // Menu "File" connections. - connect(m_ui->m_actionExportFeeds, SIGNAL(triggered()), this, SLOT(exportFeeds())); - connect(m_ui->m_actionImportFeeds, SIGNAL(triggered()), this, SLOT(importFeeds())); connect(m_ui->m_actionBackupDatabaseSettings, SIGNAL(triggered()), this, SLOT(backupDatabaseSettings())); connect(m_ui->m_actionRestoreDatabaseSettings, SIGNAL(triggered()), this, SLOT(restoreDatabaseSettings())); connect(m_ui->m_actionRestart, SIGNAL(triggered()), qApp, SLOT(restart())); @@ -457,22 +451,6 @@ void FormMain::loadWebBrowserMenu(int index) { m_ui->m_actionCloseCurrentTab->setEnabled(m_ui->m_tabWidget->tabBar()->tabType(index) == TabBar::Closable); } -void FormMain::exportFeeds() { - QPointer form = new FormStandardImportExport(tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->standardServiceRoot(), - this); - form.data()->setMode(FeedsImportExportModel::Export); - form.data()->exec(); - delete form.data(); -} - -void FormMain::importFeeds() { - QPointer form = new FormStandardImportExport(tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->standardServiceRoot(), - this); - form.data()->setMode(FeedsImportExportModel::Import); - form.data()->exec(); - delete form.data(); -} - void FormMain::backupDatabaseSettings() { QPointer form = new FormBackupDatabaseSettings(this); form.data()->exec(); diff --git a/src/gui/dialogs/formmain.h b/src/gui/dialogs/formmain.h index 97149e9c2..55ea35fd5 100755 --- a/src/gui/dialogs/formmain.h +++ b/src/gui/dialogs/formmain.h @@ -85,8 +85,6 @@ class FormMain : public QMainWindow { void loadWebBrowserMenu(int index); // Displays various dialogs. - void exportFeeds(); - void importFeeds(); void backupDatabaseSettings(); void restoreDatabaseSettings(); void showSettings(); diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index 1f1f339af..5c39e7d99 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -55,9 +55,6 @@ &File - - - @@ -135,8 +132,8 @@ Add &new item
- - + + @@ -267,20 +264,20 @@ Close current web browser tab. - + Update &all items - Ctrl+Shift+U + Ctrl+Shift+U - + Update &selected items - Ctrl+U + Ctrl+U @@ -310,7 +307,7 @@ - &Mark selected feeds as read + &Mark selected items as read Mark all messages (without message filters) from selected feeds as read. @@ -318,7 +315,7 @@ - &Mark selected feeds as unread + &Mark selected items as unread Mark all messages (without message filters) from selected feeds as unread. @@ -331,7 +328,7 @@ - &Clean selected feeds + &Clean selected items Deletes all messages from selected feeds. @@ -365,7 +362,7 @@ - &Mark all feeds as &read + &Mark all items as &read Marks all messages in all feeds read. This does not take message filters into account. @@ -373,7 +370,7 @@ - View selected feeds in &newspaper mode + View selected items in &newspaper mode Displays all messages from selected feeds/categories in a new "newspaper mode" tab. Note that messages are not set as read automatically. @@ -406,7 +403,7 @@ - &Clean all feeds + &Clean all items Deletes all messages from all feeds. @@ -544,22 +541,6 @@ H - - - &Import feeds - - - Imports feeds you want from selected file. - - - - - &Export feeds - - - Exports feeds you want to selected file. - - Report a bug (BitBucket)... @@ -624,7 +605,7 @@ true - Show only unread feeds/categories + Show only unread items Ctrl+Shift+U @@ -632,7 +613,7 @@ - &Expand/collapse selected feed/category + &Expand/collapse selected item E diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 82ea7662a..d07f6e500 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -292,16 +292,17 @@ void FeedMessageViewer::updateFeedButtonsAvailability() { bool service_selected = anything_selected && selected_item->kind() == RootItemKind::ServiceRoot; FormMain *form_main = qApp->mainForm(); + form_main->m_ui->m_actionServiceEdit->setEnabled(!critical_action_running && service_selected); + form_main->m_ui->m_actionServiceDelete->setEnabled(!critical_action_running && service_selected); form_main->m_ui->m_actionBackupDatabaseSettings->setEnabled(!critical_action_running); form_main->m_ui->m_actionCleanupDatabase->setEnabled(!critical_action_running); form_main->m_ui->m_actionClearSelectedFeeds->setEnabled(feed_selected || category_selected || service_selected); form_main->m_ui->m_actionDeleteSelectedItem->setEnabled(!critical_action_running && anything_selected); form_main->m_ui->m_actionEditSelectedItem->setEnabled(!critical_action_running && anything_selected); - form_main->m_ui->m_actionImportFeeds->setEnabled(!critical_action_running); form_main->m_ui->m_actionMarkSelectedFeedsAsRead->setEnabled(feed_selected || category_selected || service_selected); form_main->m_ui->m_actionMarkSelectedFeedsAsUnread->setEnabled(feed_selected || category_selected || service_selected); - form_main->m_ui->m_actionUpdateAllFeeds->setEnabled(!critical_action_running); - form_main->m_ui->m_actionUpdateSelectedFeeds->setEnabled(!critical_action_running && (feed_selected || category_selected || service_selected)); + form_main->m_ui->m_actionUpdateAllItems->setEnabled(!critical_action_running); + form_main->m_ui->m_actionUpdateSelectedItems->setEnabled(!critical_action_running && (feed_selected || category_selected || service_selected)); form_main->m_ui->m_actionViewSelectedItemsNewspaperMode->setEnabled(feed_selected || category_selected || service_selected); form_main->m_ui->m_actionExpandCollapseFeedCategory->setEnabled(feed_selected || category_selected || service_selected); form_main->m_ui->m_menuAddItem->setEnabled(!critical_action_running); @@ -381,9 +382,9 @@ void FeedMessageViewer::createConnections() { SIGNAL(triggered()), m_feedsView, SLOT(clearSelectedFeeds())); connect(form_main->m_ui->m_actionClearAllFeeds, SIGNAL(triggered()), m_feedsView, SLOT(clearAllFeeds())); - connect(form_main->m_ui->m_actionUpdateSelectedFeeds, + connect(form_main->m_ui->m_actionUpdateSelectedItems, SIGNAL(triggered()), m_feedsView, SLOT(updateSelectedFeeds())); - connect(form_main->m_ui->m_actionUpdateAllFeeds, + connect(form_main->m_ui->m_actionUpdateAllItems, SIGNAL(triggered()), m_feedsView, SLOT(updateAllFeeds())); connect(form_main->m_ui->m_actionEditSelectedItem, SIGNAL(triggered()), m_feedsView, SLOT(editSelectedItem())); diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 9fac64286..0b37f0d83 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -494,7 +494,7 @@ void FeedsView::initializeContextMenuCategories(RootItem *clicked_item) { QList specific_actions = clicked_item->contextMenuActions(); m_contextMenuCategories->addActions(QList() << - qApp->mainForm()->m_ui->m_actionUpdateSelectedFeeds << + qApp->mainForm()->m_ui->m_actionUpdateSelectedItems << qApp->mainForm()->m_ui->m_actionEditSelectedItem << qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode << qApp->mainForm()->m_ui->m_actionMarkSelectedFeedsAsRead << @@ -518,7 +518,7 @@ void FeedsView::initializeContextMenuFeeds(RootItem *clicked_item) { QList specific_actions = clicked_item->contextMenuActions(); m_contextMenuFeeds->addActions(QList() << - qApp->mainForm()->m_ui->m_actionUpdateSelectedFeeds << + qApp->mainForm()->m_ui->m_actionUpdateSelectedItems << qApp->mainForm()->m_ui->m_actionEditSelectedItem << qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode << qApp->mainForm()->m_ui->m_actionMarkSelectedFeedsAsRead << @@ -533,7 +533,7 @@ void FeedsView::initializeContextMenuFeeds(RootItem *clicked_item) { void FeedsView::initializeContextMenuEmptySpace() { m_contextMenuEmptySpace = new QMenu(tr("Context menu for empty space"), this); - m_contextMenuEmptySpace->addAction(qApp->mainForm()->m_ui->m_actionUpdateAllFeeds); + m_contextMenuEmptySpace->addAction(qApp->mainForm()->m_ui->m_actionUpdateAllItems); m_contextMenuEmptySpace->addSeparator(); } diff --git a/src/miscellaneous/settings.cpp b/src/miscellaneous/settings.cpp index dd67b27cc..ece288281 100755 --- a/src/miscellaneous/settings.cpp +++ b/src/miscellaneous/settings.cpp @@ -82,7 +82,7 @@ DKEY GUI::ToolbarStyle = "toolbar_style"; DVALUE(Qt::ToolButtonStyle) GUI::ToolbarStyleDef = Qt::ToolButtonIconOnly; DKEY GUI::FeedsToolbarActions = "feeds_toolbar"; -DVALUE(char*) GUI::FeedsToolbarActionsDef = "m_actionUpdateAllFeeds,m_actionMarkAllFeedsRead"; +DVALUE(char*) GUI::FeedsToolbarActionsDef = "m_actionUpdateAllItems,m_actionMarkAllFeedsRead"; DKEY GUI::MainWindowInitialSize = "window_size"; DKEY GUI::MainWindowInitialPosition = "window_position"; diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index f475e3aab..0137b45b9 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -21,6 +21,7 @@ #include "miscellaneous/application.h" #include "miscellaneous/settings.h" #include "miscellaneous/iconfactory.h" +#include "miscellaneous/mutex.h" #include "core/feedsmodel.h" #include "gui/messagebox.h" #include "gui/dialogs/formmain.h" @@ -32,6 +33,7 @@ #include "services/standard/standardfeedsimportexportmodel.h" #include "services/standard/gui/formstandardcategorydetails.h" #include "services/standard/gui/formstandardfeeddetails.h" +#include "services/standard/gui/formstandardimportexport.h" #include #include @@ -43,6 +45,7 @@ StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent) : ServiceRoot(feeds_model, parent), m_recycleBin(new StandardRecycleBin(this)), + m_actionExportFeeds(NULL), m_actionImportFeeds(NULL), m_serviceMenu(QList()), m_addItemMenu(QList()), m_feedContextMenu(QList()), m_actionFeedFetchMetadata(NULL) { setTitle(qApp->system()->getUsername() + QL1S("@") + QL1S(APP_LOW_NAME)); setIcon(StandardServiceEntryPoint().icon()); @@ -55,6 +58,7 @@ StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_mo } StandardServiceRoot::~StandardServiceRoot() { + qDeleteAll(m_serviceMenu); qDeleteAll(m_addItemMenu); qDeleteAll(m_feedContextMenu); } @@ -334,18 +338,30 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, void StandardServiceRoot::addNewCategory() { QPointer form_pointer = new FormStandardCategoryDetails(this, qApp->mainForm()); - form_pointer.data()->exec(NULL, NULL); delete form_pointer.data(); } void StandardServiceRoot::addNewFeed() { QPointer form_pointer = new FormStandardFeedDetails(this, qApp->mainForm()); - form_pointer.data()->exec(NULL, NULL); delete form_pointer.data(); } +void StandardServiceRoot::importFeeds() { + QPointer form = new FormStandardImportExport(this, qApp->mainForm()); + form.data()->setMode(FeedsImportExportModel::Import); + form.data()->exec(); + delete form.data(); +} + +void StandardServiceRoot::exportFeeds() { + QPointer form = new FormStandardImportExport(this, qApp->mainForm()); + form.data()->setMode(FeedsImportExportModel::Export); + form.data()->exec(); + delete form.data(); +} + QList StandardServiceRoot::addItemMenu() { if (m_addItemMenu.isEmpty()) { QAction *action_new_category = new QAction(qApp->icons()->fromTheme("folder-category"), tr("Add new category"), this); @@ -362,7 +378,18 @@ QList StandardServiceRoot::addItemMenu() { } QList StandardServiceRoot::serviceMenu() { - return m_addItemMenu; + if (m_serviceMenu.isEmpty()) { + m_actionExportFeeds = new QAction(qApp->icons()->fromTheme("document-export"), tr("Export feeds"), this); + m_actionImportFeeds = new QAction(qApp->icons()->fromTheme("document-import"), tr("Import feeds"), this); + + connect(m_actionExportFeeds, SIGNAL(triggered()), this, SLOT(exportFeeds())); + connect(m_actionImportFeeds, SIGNAL(triggered()), this, SLOT(importFeeds())); + + m_serviceMenu.append(m_actionExportFeeds); + m_serviceMenu.append(m_actionImportFeeds); + } + + return m_serviceMenu; } void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 77cfb15fb..08f7ae4fb 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -77,6 +77,8 @@ class StandardServiceRoot : public ServiceRoot { public slots: void addNewCategory(); void addNewFeed(); + void importFeeds(); + void exportFeeds(); private: void loadFromDatabase(); @@ -89,6 +91,10 @@ class StandardServiceRoot : public ServiceRoot { StandardRecycleBin *m_recycleBin; // Menus. + QAction *m_actionExportFeeds; + QAction *m_actionImportFeeds; + + QList m_serviceMenu; QList m_addItemMenu; QList m_feedContextMenu; From 0eefcae22e9444ccddd64621c22ec0bd20dd629a Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 11 Nov 2015 08:28:59 +0100 Subject: [PATCH 036/203] Renamed some actions, added missing actions to enable changing shortcuts on them. --- src/gui/dialogs/formmain.cpp | 38 +++++++++++---------- src/gui/dialogs/formmain.h | 1 - src/gui/dialogs/formmain.ui | 60 +++++++++++++++++----------------- src/gui/feedmessageviewer.cpp | 26 +++++++-------- src/gui/feedsview.cpp | 8 ++--- src/gui/tabwidget.cpp | 1 + src/miscellaneous/settings.cpp | 2 +- 7 files changed, 69 insertions(+), 67 deletions(-) diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index 9788c50dc..f4c0bb91f 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -114,10 +114,12 @@ QList FormMain::allActions() { actions << m_ui->m_actionOpenSelectedSourceArticlesExternally; actions << m_ui->m_actionOpenSelectedSourceArticlesInternally; actions << m_ui->m_actionOpenSelectedMessagesInternally; - actions << m_ui->m_actionMarkAllFeedsRead; - actions << m_ui->m_actionMarkSelectedFeedsAsRead; - actions << m_ui->m_actionMarkSelectedFeedsAsUnread; - actions << m_ui->m_actionClearSelectedFeeds; + actions << m_ui->m_actionMarkAllItemsRead; + actions << m_ui->m_actionMarkSelectedItemsAsRead; + actions << m_ui->m_actionMarkSelectedItemsAsUnread; + actions << m_ui->m_actionClearSelectedItems; + actions << m_ui->m_actionClearAllItems; + actions << m_ui->m_actionShowOnlyUnreadItems; actions << m_ui->m_actionMarkSelectedMessagesAsRead; actions << m_ui->m_actionMarkSelectedMessagesAsUnread; actions << m_ui->m_actionSwitchImportanceOfSelectedMessages; @@ -127,11 +129,11 @@ QList FormMain::allActions() { actions << m_ui->m_actionEditSelectedItem; actions << m_ui->m_actionDeleteSelectedItem; actions << m_ui->m_actionViewSelectedItemsNewspaperMode; - actions << m_ui->m_actionSelectNextFeedCategory; - actions << m_ui->m_actionSelectPreviousFeedCategory; + actions << m_ui->m_actionSelectNextItem; + actions << m_ui->m_actionSelectPreviousItem; actions << m_ui->m_actionSelectNextMessage; actions << m_ui->m_actionSelectPreviousMessage; - actions << m_ui->m_actionExpandCollapseFeedCategory; + actions << m_ui->m_actionExpandCollapseItem; return actions; } @@ -149,7 +151,7 @@ void FormMain::prepareMenus() { m_trayMenu->addAction(m_ui->m_actionSwitchMainWindow); m_trayMenu->addSeparator(); m_trayMenu->addAction(m_ui->m_actionUpdateAllItems); - m_trayMenu->addAction(m_ui->m_actionMarkAllFeedsRead); + m_trayMenu->addAction(m_ui->m_actionMarkAllItemsRead); m_trayMenu->addSeparator(); m_trayMenu->addAction(m_ui->m_actionSettings); m_trayMenu->addAction(m_ui->m_actionQuit); @@ -299,14 +301,14 @@ void FormMain::setupIcons() { m_ui->m_menuAddItem->setIcon(icon_theme_factory->fromTheme(QSL("item-new"))); m_ui->m_actionUpdateAllItems->setIcon(icon_theme_factory->fromTheme(QSL("item-update-all"))); m_ui->m_actionUpdateSelectedItems->setIcon(icon_theme_factory->fromTheme(QSL("item-update-selected"))); - m_ui->m_actionClearSelectedFeeds->setIcon(icon_theme_factory->fromTheme(QSL("mail-remove"))); - m_ui->m_actionClearAllFeeds->setIcon(icon_theme_factory->fromTheme(QSL("mail-remove"))); + m_ui->m_actionClearSelectedItems->setIcon(icon_theme_factory->fromTheme(QSL("mail-remove"))); + m_ui->m_actionClearAllItems->setIcon(icon_theme_factory->fromTheme(QSL("mail-remove"))); m_ui->m_actionDeleteSelectedItem->setIcon(icon_theme_factory->fromTheme(QSL("item-remove"))); m_ui->m_actionDeleteSelectedMessages->setIcon(icon_theme_factory->fromTheme(QSL("mail-remove"))); m_ui->m_actionEditSelectedItem->setIcon(icon_theme_factory->fromTheme(QSL("item-edit"))); - m_ui->m_actionMarkAllFeedsRead->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-read"))); - m_ui->m_actionMarkSelectedFeedsAsRead->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-read"))); - m_ui->m_actionMarkSelectedFeedsAsUnread->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-unread"))); + m_ui->m_actionMarkAllItemsRead->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-read"))); + m_ui->m_actionMarkSelectedItemsAsRead->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-read"))); + m_ui->m_actionMarkSelectedItemsAsUnread->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-unread"))); m_ui->m_actionMarkSelectedMessagesAsRead->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-read"))); m_ui->m_actionMarkSelectedMessagesAsUnread->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-unread"))); m_ui->m_actionSwitchImportanceOfSelectedMessages->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-favorite"))); @@ -315,12 +317,12 @@ void FormMain::setupIcons() { m_ui->m_actionOpenSelectedMessagesInternally->setIcon(icon_theme_factory->fromTheme(QSL("item-open-internal"))); m_ui->m_actionSendMessageViaEmail->setIcon(icon_theme_factory->fromTheme(QSL("item-send-email"))); m_ui->m_actionViewSelectedItemsNewspaperMode->setIcon(icon_theme_factory->fromTheme(QSL("item-newspaper"))); - m_ui->m_actionSelectNextFeedCategory->setIcon(icon_theme_factory->fromTheme(QSL("go-down"))); - m_ui->m_actionSelectPreviousFeedCategory->setIcon(icon_theme_factory->fromTheme(QSL("go-up"))); + m_ui->m_actionSelectNextItem->setIcon(icon_theme_factory->fromTheme(QSL("go-down"))); + m_ui->m_actionSelectPreviousItem->setIcon(icon_theme_factory->fromTheme(QSL("go-up"))); m_ui->m_actionSelectNextMessage->setIcon(icon_theme_factory->fromTheme(QSL("go-down"))); m_ui->m_actionSelectPreviousMessage->setIcon(icon_theme_factory->fromTheme(QSL("go-up"))); - m_ui->m_actionShowOnlyUnreadFeeds->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-unread"))); - m_ui->m_actionExpandCollapseFeedCategory->setIcon(icon_theme_factory->fromTheme(QSL("expand-collapse"))); + m_ui->m_actionShowOnlyUnreadItems->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-unread"))); + m_ui->m_actionExpandCollapseItem->setIcon(icon_theme_factory->fromTheme(QSL("expand-collapse"))); // Setup icons for underlying components: opened web browsers... foreach (WebBrowser *browser, WebBrowser::runningWebBrowsers()) { @@ -361,7 +363,7 @@ void FormMain::loadSize() { m_ui->m_actionSwitchListHeaders->setChecked(settings->value(GROUP(GUI), SETTING(GUI::ListHeadersVisible)).toBool()); // Make sure that only unread feeds are shown if user has that feature set on. - m_ui->m_actionShowOnlyUnreadFeeds->setChecked(settings->value(GROUP(Feeds), SETTING(Feeds::ShowOnlyUnreadFeeds)).toBool()); + m_ui->m_actionShowOnlyUnreadItems->setChecked(settings->value(GROUP(Feeds), SETTING(Feeds::ShowOnlyUnreadFeeds)).toBool()); } void FormMain::saveSize() { diff --git a/src/gui/dialogs/formmain.h b/src/gui/dialogs/formmain.h index 55ea35fd5..c71b5d82c 100755 --- a/src/gui/dialogs/formmain.h +++ b/src/gui/dialogs/formmain.h @@ -21,7 +21,6 @@ #include "ui_formmain.h" #include -#include class StatusBar; diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index 5c39e7d99..c3d135bac 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -139,19 +139,19 @@ - - + + - - + + - - + + - - - + + +
@@ -180,8 +180,8 @@ - + @@ -305,20 +305,20 @@ Switch &importance of selected messages - + &Mark selected items as read - Mark all messages (without message filters) from selected feeds as read. + Mark all messages (without message filters) from selected items as read. - + &Mark selected items as unread - Mark all messages (without message filters) from selected feeds as unread. + Mark all messages (without message filters) from selected items as unread. @@ -326,12 +326,12 @@ &Delete selected messages - + &Clean selected items - Deletes all messages from selected feeds. + Deletes all messages from selected items. @@ -360,12 +360,12 @@ - + &Mark all items as &read - Marks all messages in all feeds read. This does not take message filters into account. + Marks all messages in all items read. This does not take message filters into account. @@ -373,7 +373,7 @@ View selected items in &newspaper mode - Displays all messages from selected feeds/categories in a new "newspaper mode" tab. Note that messages are not set as read automatically. + Displays all messages from selected item in a new "newspaper mode" tab. Note that messages are not set as read automatically. @@ -401,31 +401,31 @@ L - + &Clean all items - Deletes all messages from all feeds. + Deletes all messages from all items. - Ctrl+Shift+C + Ctrl+Shift+C - + Select &next item - S + S - + Select &previous item - A + A @@ -600,7 +600,7 @@ Ctrl+Shift+Del - + true @@ -608,15 +608,15 @@ Show only unread items - Ctrl+Shift+U + Ctrl+Shift+U - + &Expand/collapse selected item - E + E diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index d07f6e500..ff15a2382 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -296,15 +296,15 @@ void FeedMessageViewer::updateFeedButtonsAvailability() { form_main->m_ui->m_actionServiceDelete->setEnabled(!critical_action_running && service_selected); form_main->m_ui->m_actionBackupDatabaseSettings->setEnabled(!critical_action_running); form_main->m_ui->m_actionCleanupDatabase->setEnabled(!critical_action_running); - form_main->m_ui->m_actionClearSelectedFeeds->setEnabled(feed_selected || category_selected || service_selected); + form_main->m_ui->m_actionClearSelectedItems->setEnabled(feed_selected || category_selected || service_selected); form_main->m_ui->m_actionDeleteSelectedItem->setEnabled(!critical_action_running && anything_selected); form_main->m_ui->m_actionEditSelectedItem->setEnabled(!critical_action_running && anything_selected); - form_main->m_ui->m_actionMarkSelectedFeedsAsRead->setEnabled(feed_selected || category_selected || service_selected); - form_main->m_ui->m_actionMarkSelectedFeedsAsUnread->setEnabled(feed_selected || category_selected || service_selected); + form_main->m_ui->m_actionMarkSelectedItemsAsRead->setEnabled(feed_selected || category_selected || service_selected); + form_main->m_ui->m_actionMarkSelectedItemsAsUnread->setEnabled(feed_selected || category_selected || service_selected); form_main->m_ui->m_actionUpdateAllItems->setEnabled(!critical_action_running); form_main->m_ui->m_actionUpdateSelectedItems->setEnabled(!critical_action_running && (feed_selected || category_selected || service_selected)); form_main->m_ui->m_actionViewSelectedItemsNewspaperMode->setEnabled(feed_selected || category_selected || service_selected); - form_main->m_ui->m_actionExpandCollapseFeedCategory->setEnabled(feed_selected || category_selected || service_selected); + form_main->m_ui->m_actionExpandCollapseItem->setEnabled(feed_selected || category_selected || service_selected); form_main->m_ui->m_menuAddItem->setEnabled(!critical_action_running); } @@ -370,17 +370,17 @@ void FeedMessageViewer::createConnections() { SIGNAL(triggered()), m_messagesView, SLOT(openSelectedMessagesInternally())); connect(form_main->m_ui->m_actionSendMessageViaEmail, SIGNAL(triggered()), m_messagesView, SLOT(sendSelectedMessageViaEmail())); - connect(form_main->m_ui->m_actionMarkAllFeedsRead, + connect(form_main->m_ui->m_actionMarkAllItemsRead, SIGNAL(triggered()), m_feedsView, SLOT(markAllFeedsRead())); - connect(form_main->m_ui->m_actionMarkSelectedFeedsAsRead, + connect(form_main->m_ui->m_actionMarkSelectedItemsAsRead, SIGNAL(triggered()), m_feedsView, SLOT(markSelectedFeedsRead())); - connect(form_main->m_ui->m_actionExpandCollapseFeedCategory, + connect(form_main->m_ui->m_actionExpandCollapseItem, SIGNAL(triggered()), m_feedsView, SLOT(expandCollapseCurrentItem())); - connect(form_main->m_ui->m_actionMarkSelectedFeedsAsUnread, + connect(form_main->m_ui->m_actionMarkSelectedItemsAsUnread, SIGNAL(triggered()), m_feedsView, SLOT(markSelectedFeedsUnread())); - connect(form_main->m_ui->m_actionClearSelectedFeeds, + connect(form_main->m_ui->m_actionClearSelectedItems, SIGNAL(triggered()), m_feedsView, SLOT(clearSelectedFeeds())); - connect(form_main->m_ui->m_actionClearAllFeeds, + connect(form_main->m_ui->m_actionClearAllItems, SIGNAL(triggered()), m_feedsView, SLOT(clearAllFeeds())); connect(form_main->m_ui->m_actionUpdateSelectedItems, SIGNAL(triggered()), m_feedsView, SLOT(updateSelectedFeeds())); @@ -394,13 +394,13 @@ void FeedMessageViewer::createConnections() { SIGNAL(triggered()), m_feedsView, SLOT(deleteSelectedItem())); connect(form_main->m_ui->m_actionSwitchFeedsList, SIGNAL(triggered()), this, SLOT(switchFeedComponentVisibility())); - connect(form_main->m_ui->m_actionSelectNextFeedCategory, + connect(form_main->m_ui->m_actionSelectNextItem, SIGNAL(triggered()), m_feedsView, SLOT(selectNextItem())); connect(form_main->m_ui->m_actionSwitchToolBars, SIGNAL(toggled(bool)), this, SLOT(setToolBarsEnabled(bool))); connect(form_main->m_ui->m_actionSwitchListHeaders, SIGNAL(toggled(bool)), this, SLOT(setListHeadersEnabled(bool))); - connect(form_main->m_ui->m_actionSelectPreviousFeedCategory, + connect(form_main->m_ui->m_actionSelectPreviousItem, SIGNAL(triggered()), m_feedsView, SLOT(selectPreviousItem())); connect(form_main->m_ui->m_actionSelectNextMessage, SIGNAL(triggered()), m_messagesView, SLOT(selectNextItem())); @@ -408,7 +408,7 @@ void FeedMessageViewer::createConnections() { SIGNAL(triggered()), m_messagesView, SLOT(selectPreviousItem())); connect(form_main->m_ui->m_actionSwitchMessageListOrientation, SIGNAL(triggered()), this, SLOT(switchMessageSplitterOrientation())); - connect(form_main->m_ui->m_actionShowOnlyUnreadFeeds, SIGNAL(toggled(bool)), + connect(form_main->m_ui->m_actionShowOnlyUnreadItems, SIGNAL(toggled(bool)), this, SLOT(toggleShowOnlyUnreadFeeds())); } diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 0b37f0d83..6e60b6d94 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -497,8 +497,8 @@ void FeedsView::initializeContextMenuCategories(RootItem *clicked_item) { qApp->mainForm()->m_ui->m_actionUpdateSelectedItems << qApp->mainForm()->m_ui->m_actionEditSelectedItem << qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode << - qApp->mainForm()->m_ui->m_actionMarkSelectedFeedsAsRead << - qApp->mainForm()->m_ui->m_actionMarkSelectedFeedsAsUnread << + qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsRead << + qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsUnread << qApp->mainForm()->m_ui->m_actionDeleteSelectedItem); if (!specific_actions.isEmpty()) { @@ -521,8 +521,8 @@ void FeedsView::initializeContextMenuFeeds(RootItem *clicked_item) { qApp->mainForm()->m_ui->m_actionUpdateSelectedItems << qApp->mainForm()->m_ui->m_actionEditSelectedItem << qApp->mainForm()->m_ui->m_actionViewSelectedItemsNewspaperMode << - qApp->mainForm()->m_ui->m_actionMarkSelectedFeedsAsRead << - qApp->mainForm()->m_ui->m_actionMarkSelectedFeedsAsUnread << + qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsRead << + qApp->mainForm()->m_ui->m_actionMarkSelectedItemsAsUnread << qApp->mainForm()->m_ui->m_actionDeleteSelectedItem); if (!specific_actions.isEmpty()) { diff --git a/src/gui/tabwidget.cpp b/src/gui/tabwidget.cpp index 2c0831e54..0c82fd4b0 100755 --- a/src/gui/tabwidget.cpp +++ b/src/gui/tabwidget.cpp @@ -69,6 +69,7 @@ void TabWidget::openMainMenu() { m_menuMain = new QMenu(tr("Main menu"), this); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuFile); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuView); + m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuServices); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuFeeds); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuMessages); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuWebBrowser); diff --git a/src/miscellaneous/settings.cpp b/src/miscellaneous/settings.cpp index ece288281..56c8cbac1 100755 --- a/src/miscellaneous/settings.cpp +++ b/src/miscellaneous/settings.cpp @@ -82,7 +82,7 @@ DKEY GUI::ToolbarStyle = "toolbar_style"; DVALUE(Qt::ToolButtonStyle) GUI::ToolbarStyleDef = Qt::ToolButtonIconOnly; DKEY GUI::FeedsToolbarActions = "feeds_toolbar"; -DVALUE(char*) GUI::FeedsToolbarActionsDef = "m_actionUpdateAllItems,m_actionMarkAllFeedsRead"; +DVALUE(char*) GUI::FeedsToolbarActionsDef = "m_actionUpdateAllItems,m_actionMarkAllItemsRead"; DKEY GUI::MainWindowInitialSize = "window_size"; DKEY GUI::MainWindowInitialPosition = "window_position"; From d0b00915f3f1f29748b86fcaf2e085b92754167b Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 11 Nov 2015 08:30:19 +0100 Subject: [PATCH 037/203] Changed shortcut for action. --- src/gui/dialogs/formmain.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index c3d135bac..d1693d88f 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -608,7 +608,7 @@ Show only unread items - Ctrl+Shift+U + U From d5ff059543b1757a9fa3b68646ff7c95ec1b8e8a Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 12 Nov 2015 10:53:17 +0100 Subject: [PATCH 038/203] Many refactorings in model/items, some tiny preparations for messages operation - they moved into feed classes. --- src/core/feedsmodel.cpp | 81 ++-------------- src/core/feedsmodel.h | 13 ++- src/core/rootitem.cpp | 42 +++++++++ src/core/rootitem.h | 53 +++++------ src/gui/feedmessageviewer.cpp | 16 ++-- src/gui/feedsview.cpp | 77 ++++++---------- src/gui/feedsview.h | 42 +++------ src/services/abstract/feed.h | 2 +- src/services/standard/standardcategory.cpp | 8 ++ src/services/standard/standardcategory.h | 3 + src/services/standard/standardfeed.cpp | 16 +++- src/services/standard/standardfeed.h | 7 +- src/services/standard/standardserviceroot.cpp | 92 +++++++++++++++++++ src/services/standard/standardserviceroot.h | 7 ++ 14 files changed, 259 insertions(+), 200 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index e5b8f93c4..828dac9ef 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -439,85 +439,16 @@ Feed *FeedsModel::feedForIndex(const QModelIndex &index) { } } -bool FeedsModel::markFeedsRead(const QList &feeds, int read) { - QSqlDatabase db_handle = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings); - - if (!db_handle.transaction()) { - qWarning("Starting transaction for feeds read change."); - return false; +bool FeedsModel::markItemRead(RootItem *item, RootItem::ReadStatus read) { + if (item->canBeMarkedAsReadUnread(read)) { + return item->markAsReadUnread(read); } - QSqlQuery query_read_msg(db_handle); - query_read_msg.setForwardOnly(true); - - if (!query_read_msg.prepare(QString("UPDATE Messages SET is_read = :read " - "WHERE feed IN (%1) AND is_deleted = 0;").arg(textualFeedIds(feeds).join(QSL(", "))))) { - qWarning("Query preparation failed for feeds read change."); - - db_handle.rollback(); - return false; - } - - query_read_msg.bindValue(QSL(":read"), read); - - if (!query_read_msg.exec()) { - qDebug("Query execution for feeds read change failed."); - db_handle.rollback(); - } - - // Commit changes. - if (db_handle.commit()) { - return true; - } - else { - return db_handle.rollback(); - } + return false; } -bool FeedsModel::markFeedsDeleted(const QList &feeds, int deleted, bool read_only) { - QSqlDatabase db_handle = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings); - - if (!db_handle.transaction()) { - qWarning("Starting transaction for feeds clearing."); - return false; - } - - QSqlQuery query_delete_msg(db_handle); - query_delete_msg.setForwardOnly(true); - - if (read_only) { - if (!query_delete_msg.prepare(QString("UPDATE Messages SET is_deleted = :deleted " - "WHERE feed IN (%1) AND is_deleted = 0 AND is_read = 1;").arg(textualFeedIds(feeds).join(QSL(", "))))) { - qWarning("Query preparation failed for feeds clearing."); - - db_handle.rollback(); - return false; - } - } - else { - if (!query_delete_msg.prepare(QString("UPDATE Messages SET is_deleted = :deleted " - "WHERE feed IN (%1) AND is_deleted = 0;").arg(textualFeedIds(feeds).join(QSL(", "))))) { - qWarning("Query preparation failed for feeds clearing."); - - db_handle.rollback(); - return false; - } - } - - query_delete_msg.bindValue(QSL(":deleted"), deleted); - - if (!query_delete_msg.exec()) { - qDebug("Query execution for feeds clearing failed."); - db_handle.rollback(); - } - - // Commit changes. - if (db_handle.commit()) { - return true; - } - else { - return db_handle.rollback(); - } +bool FeedsModel::markItemCleared(RootItem *item, bool clean_read_only) { + return item->cleanMessages(clean_read_only); } QList FeedsModel::allFeeds() { diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 1fdc26b72..48d612b39 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -132,8 +132,8 @@ class FeedsModel : public QAbstractItemModel { public slots: // Feeds operations. - bool markFeedsRead(const QList &feeds, int read); - bool markFeedsDeleted(const QList &feeds, int deleted, bool read_only); + bool markItemRead(RootItem *item, RootItem::ReadStatus read); + bool markItemCleared(RootItem *item, bool clean_read_only); // Signals that properties (probably counts) // of ALL items have changed. @@ -147,6 +147,12 @@ class FeedsModel : public QAbstractItemModel { // Invalidates data under index for the item. void reloadChangedItem(RootItem *item); + // Notifies other components about messages + // counts. + inline void notifyWithCounts() { + emit messageCountsChanged(countOfUnreadMessages(), countOfAllMessages(), hasAnyFeedNewMessages()); + } + private slots: // Is executed when next auto-update round could be done. void executeNextAutoUpdate(); @@ -155,6 +161,9 @@ class FeedsModel : public QAbstractItemModel { // Emitted when model requests update of some feeds. void feedsUpdateRequested(const QList feeds); + // Emitted if counts of messages are changed. + void messageCountsChanged(int unread_messages, int total_messages, bool any_feed_has_unread_messages); + private: // Returns converted ids of given feeds // which are suitable as IN clause for SQL queries. diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index e92ef64f4..5d062e320 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -46,6 +46,48 @@ QList RootItem::contextMenuActions() { return QList(); } +bool RootItem::canBeEdited() { + return false; +} + +bool RootItem::editViaGui() { + return false; +} + +bool RootItem::canBeDeleted() { + return false; +} + +bool RootItem::deleteViaGui() { + return false; +} + +bool RootItem::canBeMarkedAsReadUnread(ReadStatus status) { + return true; +} + +bool RootItem::markAsReadUnread(ReadStatus status) { + bool result = true; + + foreach (RootItem *child, m_childItems) { + if (child->canBeMarkedAsReadUnread(status)) { + result &= child->markAsReadUnread(status); + } + } + + return result; +} + +bool RootItem::cleanMessages(bool clear_only_read) { + bool result = true; + + foreach (RootItem *child, m_childItems) { + result &= child->cleanMessages(clear_only_read); + } + + return result; +} + void RootItem::setupFonts() { m_normalFont = Application::font("FeedsView"); m_boldFont = m_normalFont; diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 450153e77..4ccc84947 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -50,6 +50,16 @@ class RootItem : public QObject { Q_OBJECT public: + enum ReadStatus { + Read, + Unread + }; + + enum CleanStatus { + Clean, + Unclean + }; + // Constructors and destructors. explicit RootItem(RootItem *parent_item = NULL); virtual ~RootItem(); @@ -82,39 +92,20 @@ class RootItem : public QObject { // NOTE: Ownership of returned actions is not switched to caller, free them when needed. virtual QList contextMenuActions(); - // TODO: pracovat s těmito věcmi - virtual bool canBeEdited() { - return false; - } + virtual bool canBeEdited(); + virtual bool editViaGui(); + virtual bool canBeDeleted(); + virtual bool deleteViaGui(); - virtual bool editViaGui() { - return false; - } - - virtual bool canBeDeleted() { - return false; - } - - virtual bool deleteViaGui() { - return false; - } - - virtual bool canBeMarkedAsRead() { - return true; - } - - virtual bool markAsRead() { - return true; - } - - virtual bool canBeMarkedAsUnread() { - return true; - } - - virtual bool markAsUnread() { - return true; - } + virtual bool canBeMarkedAsReadUnread(ReadStatus status); + virtual bool markAsReadUnread(ReadStatus status); + // This method should "clean" all messages it contains. + // What "clean" means? It means delete message -> move them to recycle bin + // or eventually remove them completely if there is no recycle bin functionality. + // If this method is called on "recycle bin" instance of your + // service account, it should not do anything. + virtual bool cleanMessages(bool clear_only_read); virtual int row() const; virtual QVariant data(int column, int role) const; diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index ff15a2382..ae3c18d0c 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -75,7 +75,7 @@ FeedMessageViewer::FeedMessageViewer(QWidget *parent) createConnections(); // Now, update all feeds if user has set it. - m_feedsView->updateAllFeedsOnStartup(); + m_feedsView->updateAllItemsOnStartup(); } FeedMessageViewer::~FeedMessageViewer() { @@ -337,7 +337,7 @@ void FeedMessageViewer::createConnections() { connect(m_feedsView, SIGNAL(feedsNeedToBeReloaded(bool)), m_messagesView, SLOT(reloadSelections(bool))); // If counts of unread/all messages change, update the tray icon. - connect(m_feedsView, SIGNAL(messageCountsChanged(int,int,bool)), this, SLOT(updateTrayIconStatus(int,int,bool))); + connect(m_feedsView->sourceModel(), SIGNAL(messageCountsChanged(int,int,bool)), this, SLOT(updateTrayIconStatus(int,int,bool))); // Message openers. connect(m_messagesView, SIGNAL(openLinkMiniBrowser(QString)), m_messagesBrowser, SLOT(navigateToUrl(QString))); @@ -371,25 +371,25 @@ void FeedMessageViewer::createConnections() { connect(form_main->m_ui->m_actionSendMessageViaEmail, SIGNAL(triggered()), m_messagesView, SLOT(sendSelectedMessageViaEmail())); connect(form_main->m_ui->m_actionMarkAllItemsRead, - SIGNAL(triggered()), m_feedsView, SLOT(markAllFeedsRead())); + SIGNAL(triggered()), m_feedsView, SLOT(markAllItemsRead())); connect(form_main->m_ui->m_actionMarkSelectedItemsAsRead, - SIGNAL(triggered()), m_feedsView, SLOT(markSelectedFeedsRead())); + SIGNAL(triggered()), m_feedsView, SLOT(markSelectedItemsRead())); connect(form_main->m_ui->m_actionExpandCollapseItem, SIGNAL(triggered()), m_feedsView, SLOT(expandCollapseCurrentItem())); connect(form_main->m_ui->m_actionMarkSelectedItemsAsUnread, - SIGNAL(triggered()), m_feedsView, SLOT(markSelectedFeedsUnread())); + SIGNAL(triggered()), m_feedsView, SLOT(markSelectedItemsUnread())); connect(form_main->m_ui->m_actionClearSelectedItems, SIGNAL(triggered()), m_feedsView, SLOT(clearSelectedFeeds())); connect(form_main->m_ui->m_actionClearAllItems, SIGNAL(triggered()), m_feedsView, SLOT(clearAllFeeds())); connect(form_main->m_ui->m_actionUpdateSelectedItems, - SIGNAL(triggered()), m_feedsView, SLOT(updateSelectedFeeds())); + SIGNAL(triggered()), m_feedsView, SLOT(updateSelectedItems())); connect(form_main->m_ui->m_actionUpdateAllItems, - SIGNAL(triggered()), m_feedsView, SLOT(updateAllFeeds())); + SIGNAL(triggered()), m_feedsView, SLOT(updateAllItems())); connect(form_main->m_ui->m_actionEditSelectedItem, SIGNAL(triggered()), m_feedsView, SLOT(editSelectedItem())); connect(form_main->m_ui->m_actionViewSelectedItemsNewspaperMode, - SIGNAL(triggered()), m_feedsView, SLOT(openSelectedFeedsInNewspaperMode())); + SIGNAL(triggered()), m_feedsView, SLOT(openSelectedItemsInNewspaperMode())); connect(form_main->m_ui->m_actionDeleteSelectedItem, SIGNAL(triggered()), m_feedsView, SLOT(deleteSelectedItem())); connect(form_main->m_ui->m_actionSwitchFeedsList, diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 6e60b6d94..25abe83f6 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -159,43 +159,35 @@ void FeedsView::expandCollapseCurrentItem() { } } -void FeedsView::updateAllFeeds() { +void FeedsView::updateAllItems() { emit feedsUpdateRequested(allFeeds()); } -void FeedsView::updateSelectedFeeds() { +void FeedsView::updateSelectedItems() { emit feedsUpdateRequested(selectedFeeds()); } -void FeedsView::updateAllFeedsOnStartup() { +void FeedsView::updateAllItemsOnStartup() { if (qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::FeedsUpdateOnStartup)).toBool()) { qDebug("Requesting update for all feeds on application startup."); - QTimer::singleShot(STARTUP_UPDATE_DELAY, this, SLOT(updateAllFeeds())); + QTimer::singleShot(STARTUP_UPDATE_DELAY, this, SLOT(updateAllItems())); } } -void FeedsView::setSelectedFeedsClearStatus(int clear) { - m_sourceModel->markFeedsDeleted(selectedFeeds(), clear, 0); +void FeedsView::clearSelectedFeeds() { + m_sourceModel->markItemCleared(selectedItem(), false); updateCountsOfSelectedFeeds(true); emit feedsNeedToBeReloaded(true); } -void FeedsView::setAllFeedsClearStatus(int clear) { - m_sourceModel->markFeedsDeleted(allFeeds(), clear, 0); +void FeedsView::clearAllFeeds() { + m_sourceModel->markItemCleared(m_sourceModel->rootItem(), false); updateCountsOfAllFeeds(true); emit feedsNeedToBeReloaded(true); } -void FeedsView::clearSelectedFeeds() { - setSelectedFeedsClearStatus(1); -} - -void FeedsView::clearAllFeeds() { - setAllFeedsClearStatus(1); -} - void FeedsView::receiveMessageCountsChange(FeedsSelection::SelectionMode mode, bool total_msg_count_changed, bool any_msg_restored) { @@ -313,7 +305,7 @@ void FeedsView::deleteSelectedItem() { // a delete selected_item jen volat tady, editViaGui taky obstará všechno, // ale tam je to zas komplexnější. m_sourceModel->removeItem(m_proxyModel->mapToSource(current_index)); - notifyWithCounts(); + m_sourceModel->notifyWithCounts(); } } else { @@ -329,42 +321,42 @@ void FeedsView::deleteSelectedItem() { qApp->feedUpdateLock()->unlock(); } -void FeedsView::markSelectedFeedsReadStatus(int read) { - m_sourceModel->markFeedsRead(selectedFeeds(), read); +void FeedsView::markSelectedItemReadStatus(RootItem::ReadStatus read) { + m_sourceModel->markItemRead(selectedItem(), read); updateCountsOfSelectedFeeds(false); emit feedsNeedToBeReloaded(read == 1); } -void FeedsView::markSelectedFeedsRead() { - markSelectedFeedsReadStatus(1); +void FeedsView::markSelectedItemsRead() { + markSelectedItemReadStatus(RootItem::Read); } -void FeedsView::markSelectedFeedsUnread() { - markSelectedFeedsReadStatus(0); +void FeedsView::markSelectedItemsUnread() { + markSelectedItemReadStatus(RootItem::Unread); } -void FeedsView::markAllFeedsReadStatus(int read) { - m_sourceModel->markFeedsRead(allFeeds(), read); +void FeedsView::markAllItemsReadStatus(RootItem::ReadStatus read) { + m_sourceModel->markItemRead(m_sourceModel->rootItem(), read); updateCountsOfAllFeeds(false); emit feedsNeedToBeReloaded(read == 1); } -void FeedsView::markAllFeedsRead() { - markAllFeedsReadStatus(1); +void FeedsView::markAllItemsRead() { + markAllItemsReadStatus(RootItem::Read); } void FeedsView::clearAllReadMessages() { - m_sourceModel->markFeedsDeleted(allFeeds(), 1, 1); + m_sourceModel->markItemCleared(m_sourceModel->rootItem(), true); } -void FeedsView::openSelectedFeedsInNewspaperMode() { +void FeedsView::openSelectedItemsInNewspaperMode() { QList messages = m_sourceModel->messagesForFeeds(selectedFeeds()); if (!messages.isEmpty()) { emit openMessagesInNewspaperView(messages); - QTimer::singleShot(0, this, SLOT(markSelectedFeedsRead())); + QTimer::singleShot(0, this, SLOT(markSelectedItemsRead())); } } @@ -410,7 +402,7 @@ void FeedsView::updateCountsOfSelectedFeeds(bool update_total_too) { // Make sure that selected view reloads changed indexes. m_sourceModel->reloadChangedLayout(selected_indexes); - notifyWithCounts(); + m_sourceModel->notifyWithCounts(); } void FeedsView::updateCountsOfRecycleBin(bool update_total_too) { @@ -418,7 +410,7 @@ void FeedsView::updateCountsOfRecycleBin(bool update_total_too) { // TODO: pridat metodu cisteni standardniho kose nebo vsech kosu. //m_sourceModel->recycleBin()->updateCounts(update_total_too); //m_sourceModel->reloadChangedLayout(QModelIndexList() << m_sourceModel->indexForItem(m_sourceModel->recycleBin())); - notifyWithCounts(); + m_sourceModel->notifyWithCounts(); } void FeedsView::updateCountsOfAllFeeds(bool update_total_too) { @@ -435,29 +427,22 @@ void FeedsView::updateCountsOfAllFeeds(bool update_total_too) { // Make sure that all views reloads its data. m_sourceModel->reloadWholeLayout(); - notifyWithCounts(); + m_sourceModel->notifyWithCounts(); } void FeedsView::updateCountsOfParticularFeed(Feed *feed, bool update_total_too) { QModelIndex index = m_sourceModel->indexForItem(feed); if (index.isValid()) { - feed->updateCounts(update_total_too, false); + feed->updateCounts(update_total_too); m_sourceModel->reloadChangedLayout(QModelIndexList() << index); } invalidateReadFeedsFilter(); - notifyWithCounts(); + m_sourceModel->notifyWithCounts(); } void FeedsView::selectNextItem() { - // NOTE: Bug #122 requested to not expand in here. - /* - if (!isExpanded(currentIndex())) { - expand(currentIndex()); - } - */ - QModelIndex index_next = moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier); if (index_next.isValid()) { @@ -469,14 +454,6 @@ void FeedsView::selectNextItem() { void FeedsView::selectPreviousItem() { QModelIndex index_previous = moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier); - // NOTE: Bug #122 requested to not expand in here. - /* - if (!isExpanded(index_previous)) { - expand(index_previous); - index_previous = moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier); - } - */ - if (index_previous.isValid()) { setCurrentIndex(index_previous); setFocus(); diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index 1b01477b2..34950f403 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -71,27 +71,23 @@ class FeedsView : public QTreeView { void expandCollapseCurrentItem(); // Feed updating. - void updateAllFeeds(); - void updateAllFeedsOnStartup(); - void updateSelectedFeeds(); + void updateAllItems(); + void updateAllItemsOnStartup(); + void updateSelectedItems(); // Feed read/unread manipulators. - void markSelectedFeedsReadStatus(int read); - void markSelectedFeedsRead(); - void markSelectedFeedsUnread(); - void markAllFeedsReadStatus(int read); - void markAllFeedsRead(); + void markSelectedItemsRead(); + void markSelectedItemsUnread(); + void markAllItemsRead(); // Newspaper accessors. - void openSelectedFeedsInNewspaperMode(); + void openSelectedItemsInNewspaperMode(); // Recycle bin operators. void emptyRecycleBin(); void restoreRecycleBin(); // Feed clearers. - void setSelectedFeedsClearStatus(int clear); - void setAllFeedsClearStatus(int clear); void clearSelectedFeeds(); void clearAllFeeds(); void clearAllReadMessages(); @@ -116,14 +112,6 @@ class FeedsView : public QTreeView { // Reloads counts for particular feed. void updateCountsOfParticularFeed(Feed *feed, bool update_total_too); - // Notifies other components about messages - // counts. - inline void notifyWithCounts() { - emit messageCountsChanged(m_sourceModel->countOfUnreadMessages(), - m_sourceModel->countOfAllMessages(), - m_sourceModel->hasAnyFeedNewMessages()); - } - // Selects next/previous item (feed/category) in the list. void selectNextItem(); void selectPreviousItem(); @@ -133,7 +121,14 @@ class FeedsView : public QTreeView { setVisible(!isVisible()); } - protected: + private slots: + void markSelectedItemReadStatus(RootItem::ReadStatus read); + void markAllItemsReadStatus(RootItem::ReadStatus read); + + void saveSortState(int column, Qt::SortOrder order); + void validateItemAfterDragDrop(const QModelIndex &source_index); + + private: // Initializes context menus. void initializeContextMenuCategories(RootItem *clicked_item); void initializeContextMenuFeeds(RootItem *clicked_item); @@ -151,17 +146,10 @@ class FeedsView : public QTreeView { // Show custom context menu. void contextMenuEvent(QContextMenuEvent *event); - private slots: - void saveSortState(int column, Qt::SortOrder order); - void validateItemAfterDragDrop(const QModelIndex &source_index); - signals: // Emitted if user/application requested updating of some feeds. void feedsUpdateRequested(const QList feeds); - // Emitted if counts of messages are changed. - void messageCountsChanged(int unread_messages, int total_messages, bool any_feed_has_unread_messages); - // Emitted if currently selected feeds needs to be reloaded. void feedsNeedToBeReloaded(bool mark_current_index_read); diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index c3911a0b2..fdfde7f54 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -60,7 +60,7 @@ class Feed : public RootItem { virtual int update() = 0; // Updates counts of all/unread messages for this feed. - virtual void updateCounts(bool including_total_count = true, bool update_feed_statuses = true) = 0; + virtual void updateCounts(bool including_total_count) = 0; // Get ALL undeleted messages from this feed in one single list. virtual QList undeletedMessages() const = 0; diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index 6fa73df5a..76cb49c0e 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -102,6 +102,14 @@ bool StandardCategory::deleteViaGui() { return removeItself(); } +bool StandardCategory::markAsReadUnread(ReadStatus status) { + return serviceRoot()->markFeedsReadUnread(getSubTreeFeeds(), status); +} + +bool StandardCategory::cleanMessages(bool clean_read_only) { + return serviceRoot()->cleanFeeds(getSubTreeFeeds(), clean_read_only); +} + bool StandardCategory::removeItself() { bool children_removed = true; diff --git a/src/services/standard/standardcategory.h b/src/services/standard/standardcategory.h index 1edab3bab..d318ec99f 100755 --- a/src/services/standard/standardcategory.h +++ b/src/services/standard/standardcategory.h @@ -56,6 +56,9 @@ class StandardCategory : public Category { bool editViaGui(); bool deleteViaGui(); + bool markAsReadUnread(ReadStatus status); + bool cleanMessages(bool clean_read_only); + // Removes category and all its children from persistent // database. bool removeItself(); diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 530b0a939..584a7d3c3 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -118,6 +118,14 @@ bool StandardFeed::deleteViaGui() { return removeItself(); } +bool StandardFeed::markAsReadUnread(ReadStatus status) { + return serviceRoot()->markFeedsReadUnread(QList() << this, status); +} + +bool StandardFeed::cleanMessages(bool clean_read_only) { + return serviceRoot()->cleanFeeds(QList() << this, clean_read_only); +} + QList StandardFeed::undeletedMessages() const { QList messages; @@ -165,7 +173,7 @@ QString StandardFeed::typeToString(StandardFeed::Type type) { } } -void StandardFeed::updateCounts(bool including_total_count, bool update_feed_statuses) { +void StandardFeed::updateCounts(bool including_total_count) { QSqlDatabase database = qApp->database()->connection(QSL("Feed"), DatabaseFactory::FromSettings); QSqlQuery query_all(database); @@ -181,7 +189,7 @@ void StandardFeed::updateCounts(bool including_total_count, bool update_feed_sta if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE feed = %1 AND is_deleted = 0 AND is_read = 0;").arg(id())) && query_all.next()) { int new_unread_count = query_all.value(0).toInt(); - if (update_feed_statuses && status() == NewMessages && new_unread_count < m_unreadCount) { + if (status() == NewMessages && new_unread_count < m_unreadCount) { setStatus(Normal); } @@ -433,7 +441,7 @@ int StandardFeed::update() { setStatus(NetworkError); return 0; } - else { + else if (status() != NewMessages) { setStatus(Normal); } @@ -731,5 +739,5 @@ StandardFeed::StandardFeed(const QSqlRecord &record) : Feed(NULL) { setPassword(TextFactory::decrypt(record.value(FDS_DB_PASSWORD_INDEX).toString())); setAutoUpdateType(static_cast(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt())); setAutoUpdateInitialInterval(record.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt()); - updateCounts(); + updateCounts(true); } diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index 395710995..24577662b 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -74,6 +74,9 @@ class StandardFeed : public Feed { bool editViaGui(); bool deleteViaGui(); + bool markAsReadUnread(ReadStatus status); + bool cleanMessages(bool clean_read_only); + QList undeletedMessages() const; // Obtains data related to this feed. @@ -83,7 +86,7 @@ class StandardFeed : public Feed { int update(); // Updates counts of all/unread messages for this feed. - void updateCounts(bool including_total_count = true, bool update_feed_statuses = true); + void updateCounts(bool including_total_count); // Removes this standard feed from persistent // storage. @@ -156,7 +159,7 @@ class StandardFeed : public Feed { // Fetches metadata for the feed. void fetchMetadataForItself(); - protected: + private: // Persistently stores given messages into the database // and updates existing messages if newer version is // available. diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 0137b45b9..7e934bd6d 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -128,6 +128,87 @@ QVariant StandardServiceRoot::data(int column, int role) const { } } +bool StandardServiceRoot::markFeedsReadUnread(QList items, ReadStatus read) { + QSqlDatabase db_handle = qApp->database()->connection(QSL("StandardServiceRoot"), DatabaseFactory::FromSettings); + + if (!db_handle.transaction()) { + qWarning("Starting transaction for feeds read change."); + return false; + } + + QSqlQuery query_read_msg(db_handle); + query_read_msg.setForwardOnly(true); + + if (!query_read_msg.prepare(QString("UPDATE Messages SET is_read = :read " + "WHERE feed IN (%1) AND is_deleted = 0;").arg(textualFeedIds(items).join(QSL(", "))))) { + qWarning("Query preparation failed for feeds read change."); + + db_handle.rollback(); + return false; + } + + query_read_msg.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0); + + if (!query_read_msg.exec()) { + qDebug("Query execution for feeds read change failed."); + db_handle.rollback(); + } + + // Commit changes. + if (db_handle.commit()) { + return true; + } + else { + return db_handle.rollback(); + } +} + +bool StandardServiceRoot::cleanFeeds(QList items, bool clean_read_only) { + QSqlDatabase db_handle = qApp->database()->connection(QSL("StandardServiceRoot"), DatabaseFactory::FromSettings); + + if (!db_handle.transaction()) { + qWarning("Starting transaction for feeds clearing."); + return false; + } + + QSqlQuery query_delete_msg(db_handle); + query_delete_msg.setForwardOnly(true); + + if (clean_read_only) { + if (!query_delete_msg.prepare(QString("UPDATE Messages SET is_deleted = :deleted " + "WHERE feed IN (%1) AND is_deleted = 0 AND is_read = 1;").arg(textualFeedIds(items).join(QSL(", "))))) { + qWarning("Query preparation failed for feeds clearing."); + + db_handle.rollback(); + return false; + } + } + else { + if (!query_delete_msg.prepare(QString("UPDATE Messages SET is_deleted = :deleted " + "WHERE feed IN (%1) AND is_deleted = 0;").arg(textualFeedIds(items).join(QSL(", "))))) { + qWarning("Query preparation failed for feeds clearing."); + + db_handle.rollback(); + return false; + } + } + + query_delete_msg.bindValue(QSL(":deleted"), 1); + + if (!query_delete_msg.exec()) { + qDebug("Query execution for feeds clearing failed."); + db_handle.rollback(); + } + + // Commit changes. + if (db_handle.commit()) { + return true; + } + else { + return db_handle.rollback(); + } +} + void StandardServiceRoot::loadFromDatabase(){ QSqlDatabase database = qApp->database()->connection("StandardServiceRoot", DatabaseFactory::FromSettings); CategoryAssignment categories; @@ -362,6 +443,17 @@ void StandardServiceRoot::exportFeeds() { delete form.data(); } +QStringList StandardServiceRoot::textualFeedIds(const QList &feeds) { + QStringList stringy_ids; + stringy_ids.reserve(feeds.size()); + + foreach (Feed *feed, feeds) { + stringy_ids.append(QString::number(feed->id())); + } + + return stringy_ids; +} + QList StandardServiceRoot::addItemMenu() { if (m_addItemMenu.isEmpty()) { QAction *action_new_category = new QAction(qApp->icons()->fromTheme("folder-category"), tr("Add new category"), this); diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 08f7ae4fb..cf86bb7cb 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -74,6 +74,9 @@ class StandardServiceRoot : public ServiceRoot { // NOTE: This is used for import/export of the model. bool mergeImportExportModel(FeedsImportExportModel *model, QString &output_message); + bool markFeedsReadUnread(QList items, ReadStatus read); + bool cleanFeeds(QList items, bool clean_read_only); + public slots: void addNewCategory(); void addNewFeed(); @@ -81,6 +84,10 @@ class StandardServiceRoot : public ServiceRoot { void exportFeeds(); private: + // Returns converted ids of given feeds + // which are suitable as IN clause for SQL queries. + QStringList textualFeedIds(const QList &feeds); + void loadFromDatabase(); // Takes lists of feeds/categories and assembles From e3d6d8e4948aaa178e22b3077872343b92966892 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 12 Nov 2015 10:59:41 +0100 Subject: [PATCH 039/203] Standard recycle bin now able to mark read/unread. --- src/gui/feedmessageviewer.cpp | 4 +-- src/services/standard/standardrecyclebin.cpp | 9 +++++ src/services/standard/standardrecyclebin.h | 6 ++++ src/services/standard/standardserviceroot.cpp | 34 +++++++++++++++++++ src/services/standard/standardserviceroot.h | 1 + 5 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index ae3c18d0c..c5ccaf78e 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -299,8 +299,8 @@ void FeedMessageViewer::updateFeedButtonsAvailability() { form_main->m_ui->m_actionClearSelectedItems->setEnabled(feed_selected || category_selected || service_selected); form_main->m_ui->m_actionDeleteSelectedItem->setEnabled(!critical_action_running && anything_selected); form_main->m_ui->m_actionEditSelectedItem->setEnabled(!critical_action_running && anything_selected); - form_main->m_ui->m_actionMarkSelectedItemsAsRead->setEnabled(feed_selected || category_selected || service_selected); - form_main->m_ui->m_actionMarkSelectedItemsAsUnread->setEnabled(feed_selected || category_selected || service_selected); + form_main->m_ui->m_actionMarkSelectedItemsAsRead->setEnabled(anything_selected); + form_main->m_ui->m_actionMarkSelectedItemsAsUnread->setEnabled(anything_selected); form_main->m_ui->m_actionUpdateAllItems->setEnabled(!critical_action_running); form_main->m_ui->m_actionUpdateSelectedItems->setEnabled(!critical_action_running && (feed_selected || category_selected || service_selected)); form_main->m_ui->m_actionViewSelectedItemsNewspaperMode->setEnabled(feed_selected || category_selected || service_selected); diff --git a/src/services/standard/standardrecyclebin.cpp b/src/services/standard/standardrecyclebin.cpp index 7fe019083..61a8a8c52 100755 --- a/src/services/standard/standardrecyclebin.cpp +++ b/src/services/standard/standardrecyclebin.cpp @@ -19,6 +19,7 @@ #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" +#include "services/standard/standardserviceroot.h" #include @@ -38,6 +39,10 @@ StandardRecycleBin::~StandardRecycleBin() { qDebug("Destroying RecycleBin instance."); } +StandardServiceRoot *StandardRecycleBin::serviceRoot() { + return static_cast(getParentServiceRoot()); +} + int StandardRecycleBin::childCount() const { return 0; } @@ -64,6 +69,10 @@ QVariant StandardRecycleBin::data(int column, int role) const { } } +bool StandardRecycleBin::markAsReadUnread(RootItem::ReadStatus status) { + return serviceRoot()->markRecycleBinReadUnread(status); +} + bool StandardRecycleBin::empty() { QSqlDatabase db_handle = qApp->database()->connection(QSL("RecycleBin"), DatabaseFactory::FromSettings); diff --git a/src/services/standard/standardrecyclebin.h b/src/services/standard/standardrecyclebin.h index 393e58ee9..7cbbf2d59 100755 --- a/src/services/standard/standardrecyclebin.h +++ b/src/services/standard/standardrecyclebin.h @@ -23,6 +23,8 @@ #include +class StandardServiceRoot; + class StandardRecycleBin : public RootItem { Q_OBJECT @@ -30,12 +32,16 @@ class StandardRecycleBin : public RootItem { explicit StandardRecycleBin(RootItem *parent = NULL); virtual ~StandardRecycleBin(); + StandardServiceRoot *serviceRoot(); + int childCount() const; void appendChild(RootItem *child); int countOfUnreadMessages() const; int countOfAllMessages() const; QVariant data(int column, int role) const; + bool markAsReadUnread(ReadStatus status); + bool empty(); bool restore(); diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 7e934bd6d..6a91d8315 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -163,6 +163,40 @@ bool StandardServiceRoot::markFeedsReadUnread(QList items, ReadStatus rea } } +bool StandardServiceRoot::markRecycleBinReadUnread(RootItem::ReadStatus read) { + QSqlDatabase db_handle = qApp->database()->connection(QSL("StandardServiceRoot"), DatabaseFactory::FromSettings); + + if (!db_handle.transaction()) { + qWarning("Starting transaction for recycle bin read change."); + return false; + } + + QSqlQuery query_read_msg(db_handle); + query_read_msg.setForwardOnly(true); + + if (!query_read_msg.prepare("UPDATE Messages SET is_read = :read WHERE is_deleted = 1;")) { + qWarning("Query preparation failed for recycle bin read change."); + + db_handle.rollback(); + return false; + } + + query_read_msg.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0); + + if (!query_read_msg.exec()) { + qDebug("Query execution for recycle bin read change failed."); + db_handle.rollback(); + } + + // Commit changes. + if (db_handle.commit()) { + return true; + } + else { + return db_handle.rollback(); + } +} + bool StandardServiceRoot::cleanFeeds(QList items, bool clean_read_only) { QSqlDatabase db_handle = qApp->database()->connection(QSL("StandardServiceRoot"), DatabaseFactory::FromSettings); diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index cf86bb7cb..98d2813b7 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -75,6 +75,7 @@ class StandardServiceRoot : public ServiceRoot { bool mergeImportExportModel(FeedsImportExportModel *model, QString &output_message); bool markFeedsReadUnread(QList items, ReadStatus read); + bool markRecycleBinReadUnread(ReadStatus read); bool cleanFeeds(QList items, bool clean_read_only); public slots: From bbbfe23a051d8b89d73ed578041294f597f5c695 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 12 Nov 2015 19:48:29 +0100 Subject: [PATCH 040/203] Fix Linux comp. --- src/core/rootitem.cpp | 4 ++-- src/services/standard/standardcategory.cpp | 2 +- src/services/standard/standardserviceroot.h | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index 5d062e320..ea0d35090 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -148,8 +148,8 @@ QVariant RootItem::data(int column, int role) const { int count_unread = countOfUnreadMessages(); return qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::CountFormat)).toString() - .replace(PLACEHOLDER_UNREAD_COUNTS, count_unread < 0 ? QSL('-') : QString::number(count_unread)) - .replace(PLACEHOLDER_ALL_COUNTS, count_all < 0 ? QSL('-') : QString::number(count_all)); + .replace(PLACEHOLDER_UNREAD_COUNTS, count_unread < 0 ? QSL("-") : QString::number(count_unread)) + .replace(PLACEHOLDER_ALL_COUNTS, count_all < 0 ? QSL("-") : QString::number(count_all)); } else { return QVariant(); diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index 76cb49c0e..3f125e9bc 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -72,7 +72,7 @@ QVariant StandardCategory::data(int column, int role) const { //: Tooltip for standard feed. return tr("%1 (category)" "%2%3").arg(title(), - description().isEmpty() ? QString() : QSL('\n') + description(), + description().isEmpty() ? QString() : QSL("\n") + description(), childCount() == 0 ? tr("\nThis category does not contain any nested items.") : QString()); diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 98d2813b7..5f02dfb0a 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -21,6 +21,7 @@ #include "services/abstract/serviceroot.h" #include +#include class StandardRecycleBin; From 8bef6daf00edef14d582df57ff3992b9e6911dbc Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 12 Nov 2015 19:54:49 +0100 Subject: [PATCH 041/203] Fix loading of initial feeds. --- src/services/standard/standardfeed.cpp | 28 +++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 584a7d3c3..8dbd7a42f 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -521,7 +521,14 @@ bool StandardFeed::addItself(RootItem *parent) { query_add_feed.bindValue(QSL(":url"), url()); query_add_feed.bindValue(QSL(":protected"), (int) passwordProtected()); query_add_feed.bindValue(QSL(":username"), username()); - query_add_feed.bindValue(QSL(":password"), TextFactory::encrypt(password())); + + if (password().isEmpty()) { + query_add_feed.bindValue(QSL(":password"), password()); + } + else { + query_add_feed.bindValue(QSL(":password"), TextFactory::encrypt(password())); + } + query_add_feed.bindValue(QSL(":update_type"), (int) autoUpdateType()); query_add_feed.bindValue(QSL(":update_interval"), autoUpdateInitialInterval()); query_add_feed.bindValue(QSL(":type"), (int) type()); @@ -565,7 +572,14 @@ bool StandardFeed::editItself(StandardFeed *new_feed_data) { query_update_feed.bindValue(QSL(":url"), new_feed_data->url()); query_update_feed.bindValue(QSL(":protected"), (int) new_feed_data->passwordProtected()); query_update_feed.bindValue(QSL(":username"), new_feed_data->username()); - query_update_feed.bindValue(QSL(":password"), TextFactory::encrypt(new_feed_data->password())); + + if (password().isEmpty()) { + query_update_feed.bindValue(QSL(":password"), new_feed_data->password()); + } + else { + query_update_feed.bindValue(QSL(":password"), TextFactory::encrypt(new_feed_data->password())); + } + query_update_feed.bindValue(QSL(":update_type"), (int) new_feed_data->autoUpdateType()); query_update_feed.bindValue(QSL(":update_interval"), new_feed_data->autoUpdateInitialInterval()); query_update_feed.bindValue(QSL(":type"), new_feed_data->type()); @@ -736,7 +750,15 @@ StandardFeed::StandardFeed(const QSqlRecord &record) : Feed(NULL) { setUrl(record.value(FDS_DB_URL_INDEX).toString()); setPasswordProtected(record.value(FDS_DB_PROTECTED_INDEX).toBool()); setUsername(record.value(FDS_DB_USERNAME_INDEX).toString()); - setPassword(TextFactory::decrypt(record.value(FDS_DB_PASSWORD_INDEX).toString())); + + if (record.value(FDS_DB_PASSWORD_INDEX).toString().isEmpty()) { + setPassword(record.value(FDS_DB_PASSWORD_INDEX).toString()); + } + else { + setPassword(TextFactory::decrypt(record.value(FDS_DB_PASSWORD_INDEX).toString())); + } + + setAutoUpdateType(static_cast(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt())); setAutoUpdateInitialInterval(record.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt()); updateCounts(true); From ad0771ffe019c5e43218b9eb99f14e757ce9dde6 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 13 Nov 2015 08:44:37 +0100 Subject: [PATCH 042/203] Some changes for notifications and some tiny preps for messages part of new "plugin" API. --- resources/text/CHANGELOG | 2 ++ src/core/messagesmodel.cpp | 7 +++--- src/core/messagesmodel.h | 3 ++- src/core/rootitem.cpp | 6 +++++ src/core/rootitem.h | 3 +++ src/definitions/definitions.h.in | 2 +- src/gui/dialogs/formabout.ui | 8 +++---- src/gui/messagesview.cpp | 8 +++---- src/gui/messagesview.h | 32 +++++++++++++------------- src/gui/notifications/notification.cpp | 0 src/main.cpp | 10 +++++++- src/services/abstract/feed.h | 3 --- 12 files changed, 51 insertions(+), 33 deletions(-) mode change 100644 => 100755 src/gui/dialogs/formabout.ui mode change 100644 => 100755 src/gui/notifications/notification.cpp diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index a5c6fd6ca..0985b6079 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -21,6 +21,8 @@ Fixed:
    +
  • Improved popup informing about changes in newly installed version.
  • +
  • Icons in notification popups are now smaller (22 x 22 pixels).
  • Encoding selection widget in feed add/edit dialog now detects encodings via case insensitive string matching.
  • When removing download item from download manager via DELETE key, then "Cleanup" button is correctly disabled.
diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 2ac6e9e42..cae3e6e30 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -394,7 +394,7 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int } } -bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, int read) { +bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootItem::ReadStatus read) { QSqlDatabase db_handle = database(); QSqlQuery query_read_msg(db_handle); QStringList message_ids; @@ -406,8 +406,9 @@ bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, int re message_ids.append(QString::number(messageId(message.row()))); } - if (query_read_msg.exec(QString(QSL("UPDATE Messages SET is_read = %2 WHERE id IN (%1);")).arg(message_ids.join(QSL(", ")), - QString::number(read)))) { + if (query_read_msg.exec(QString(QSL("UPDATE Messages SET is_read = %2 WHERE id IN (%1);")) + .arg(message_ids.join(QSL(", ")), + read == RootItem::Read ? QSL("1") : QSL("0")))) { select(); fetchAll(); diff --git a/src/core/messagesmodel.h b/src/core/messagesmodel.h index ad0d42a24..312982288 100755 --- a/src/core/messagesmodel.h +++ b/src/core/messagesmodel.h @@ -22,6 +22,7 @@ #include "core/feedsselection.h" #include "core/message.h" +#include "core/rootitem.h" #include #include @@ -80,7 +81,7 @@ class MessagesModel : public QSqlTableModel { // changes ARE written to the database. bool switchBatchMessageImportance(const QModelIndexList &messages); bool setBatchMessagesDeleted(const QModelIndexList &messages, int deleted); - bool setBatchMessagesRead(const QModelIndexList &messages, int read); + bool setBatchMessagesRead(const QModelIndexList &messages, RootItem::ReadStatus read); bool setBatchMessagesRestored(const QModelIndexList &messages); // Fetches ALL available data to the model. diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index ea0d35090..6cd3d9412 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -88,6 +88,12 @@ bool RootItem::cleanMessages(bool clear_only_read) { return result; } +void RootItem::updateCounts(bool including_total_count) { + foreach (RootItem *child, m_childItems) { + child->updateCounts(including_total_count); + } +} + void RootItem::setupFonts() { m_normalFont = Application::font("FeedsView"); m_boldFont = m_normalFont; diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 4ccc84947..1faf2f308 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -107,6 +107,9 @@ class RootItem : public QObject { // service account, it should not do anything. virtual bool cleanMessages(bool clear_only_read); + // Updates counts of all/unread messages for this feed. + virtual void updateCounts(bool including_total_count); + virtual int row() const; virtual QVariant data(int column, int role) const; diff --git a/src/definitions/definitions.h.in b/src/definitions/definitions.h.in index adc147a8d..1a44da62a 100755 --- a/src/definitions/definitions.h.in +++ b/src/definitions/definitions.h.in @@ -82,7 +82,7 @@ #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 "@APP_LOW_NAME@/itempointer" #define DOWNLOADER_ICON_SIZE 48 -#define NOTIFICATION_ICON_SIZE 64 +#define NOTIFICATION_ICON_SIZE 32 #define GOOGLE_SEARCH_URL "https://www.google.com/search?q=%1&ie=utf-8&oe=utf-8" #define GOOGLE_SUGGEST_URL "http://suggestqueries.google.com/complete/search?output=toolbar&hl=en&q=%1" #define ENCRYPTION_FILE_NAME "key.private" diff --git a/src/gui/dialogs/formabout.ui b/src/gui/dialogs/formabout.ui old mode 100644 new mode 100755 index 696b2d41e..c30ecdfc5 --- a/src/gui/dialogs/formabout.ui +++ b/src/gui/dialogs/formabout.ui @@ -104,7 +104,7 @@ - 3 + 2 @@ -166,8 +166,8 @@ p, li { white-space: pre-wrap; } 0 0 - 685 - 184 + 98 + 69 @@ -242,7 +242,7 @@ p, li { white-space: pre-wrap; } 0 0 - 83 + 98 69 diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index 7484ed092..d80cc415f 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -318,14 +318,14 @@ void MessagesView::sendSelectedMessageViaEmail() { } void MessagesView::markSelectedMessagesRead() { - setSelectedMessagesReadStatus(1); + setSelectedMessagesReadStatus(RootItem::Read); } void MessagesView::markSelectedMessagesUnread() { - setSelectedMessagesReadStatus(0); + setSelectedMessagesReadStatus(RootItem::Unread); } -void MessagesView::setSelectedMessagesReadStatus(int read) { +void MessagesView::setSelectedMessagesReadStatus(RootItem::ReadStatus read) { QModelIndex current_index = selectionModel()->currentIndex(); if (!current_index.isValid()) { @@ -342,7 +342,7 @@ void MessagesView::setSelectedMessagesReadStatus(int read) { selected_indexes = m_proxyModel->mapListFromSource(mapped_indexes, true); current_index = m_proxyModel->mapFromSource(m_sourceModel->index(mapped_current_index.row(), mapped_current_index.column())); - if (read == 0) { + if (read == RootItem::Unread) { // User selected to mark some messages as unread, if one // of them will be marked as current, then it will be read again. m_batchUnreadSwitch = true; diff --git a/src/gui/messagesview.h b/src/gui/messagesview.h index c84c4dd77..5d97a6318 100755 --- a/src/gui/messagesview.h +++ b/src/gui/messagesview.h @@ -21,6 +21,7 @@ #include "core/messagesmodel.h" #include "core/feedsselection.h" +#include "core/rootitem.h" #include #include @@ -47,9 +48,6 @@ class MessagesView : public QTreeView { return m_sourceModel; } - // Creates needed connections. - void createConnections(); - public slots: void keyboardSearch(const QString &search); @@ -70,7 +68,7 @@ class MessagesView : public QTreeView { void sendSelectedMessageViaEmail(); // Works with SELECTED messages only. - void setSelectedMessagesReadStatus(int read); + void setSelectedMessagesReadStatus(RootItem::ReadStatus read); void markSelectedMessagesRead(); void markSelectedMessagesUnread(); void switchSelectedMessagesImportance(); @@ -94,7 +92,20 @@ class MessagesView : public QTreeView { // Saves current sort state. void saveSortState(int column, Qt::SortOrder order); - protected: + signals: + // Link/message openers. + void openLinkNewTab(const QString &link); + void openLinkMiniBrowser(const QString &link); + void openMessagesInNewspaperView(const QList &messages); + + // Notify others about message selections. + void currentMessagesChanged(const QList &messages); + void currentMessagesRemoved(); + + private: + // Creates needed connections. + void createConnections(); + // Initializes context menu. void initializeContextMenu(); @@ -108,17 +119,6 @@ class MessagesView : public QTreeView { void currentChanged(const QModelIndex ¤t, const QModelIndex &previous); void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); - signals: - // Link/message openers. - void openLinkNewTab(const QString &link); - void openLinkMiniBrowser(const QString &link); - void openMessagesInNewspaperView(const QList &messages); - - // Notify others about message selections. - void currentMessagesChanged(const QList &messages); - void currentMessagesRemoved(); - - private: QMenu *m_contextMenu; MessagesProxyModel *m_proxyModel; diff --git a/src/gui/notifications/notification.cpp b/src/gui/notifications/notification.cpp old mode 100644 new mode 100755 diff --git a/src/main.cpp b/src/main.cpp index 9ce0874b6..2ed89e78e 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -120,7 +120,15 @@ int main(int argc, char *argv[]) { // Setup single-instance behavior. QObject::connect(&application, SIGNAL(messageReceived(QString)), &application, SLOT(processExecutionMessage(QString))); - qApp->showGuiMessage(QSL(APP_NAME), QObject::tr("Welcome to %1 %2.").arg(APP_NAME, APP_VERSION), QSystemTrayIcon::NoIcon); + + if (qApp->isFirstRun() || qApp->isFirstRun(APP_VERSION)) { + qApp->showGuiMessage(QSL(APP_NAME), QObject::tr("Welcome to %1.\n\nPlease, check NEW stuff included in this\n" + "version by clicking this popup notification.").arg(APP_LONG_NAME), + QSystemTrayIcon::NoIcon, 0, false, QIcon(), &main_window, SLOT(showAbout())); + } + else { + qApp->showGuiMessage(QSL(APP_NAME), QObject::tr("Welcome to %1.").arg(APP_LONG_NAME), QSystemTrayIcon::NoIcon); + } // Enter global event loop. return Application::exec(); diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index fdfde7f54..992f3174d 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -59,9 +59,6 @@ class Feed : public RootItem { // Performs synchronous update and returns number of newly updated messages. virtual int update() = 0; - // Updates counts of all/unread messages for this feed. - virtual void updateCounts(bool including_total_count) = 0; - // Get ALL undeleted messages from this feed in one single list. virtual QList undeletedMessages() const = 0; From 9cb84ec3137cf3bdd0c2f1b0fe1081ca308495d7 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 13 Nov 2015 09:08:06 +0100 Subject: [PATCH 043/203] Removed unusued method. --- src/gui/messagesview.cpp | 34 +++------------------------------- src/gui/messagesview.h | 1 - 2 files changed, 3 insertions(+), 32 deletions(-) diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index d80cc415f..e8eb2c609 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -354,6 +354,9 @@ void MessagesView::setSelectedMessagesReadStatus(RootItem::ReadStatus read) { m_batchUnreadSwitch = false; } + +// TODO: restore messages je uplně stejně jako tahle fce +// akorat se vola jina metoda na source modelu. void MessagesView::deleteSelectedMessages() { QModelIndex current_index = selectionModel()->currentIndex(); @@ -382,37 +385,6 @@ void MessagesView::deleteSelectedMessages() { } } -void MessagesView::restoreSelectedMessages() { - QModelIndex current_index = selectionModel()->currentIndex(); - - if (!current_index.isValid()) { - return; - } - - QModelIndexList selected_indexes = selectionModel()->selectedRows(); - QModelIndexList mapped_indexes = m_proxyModel->mapListToSource(selected_indexes); - - if (m_sourceModel->setBatchMessagesRestored(mapped_indexes)) { - sortByColumn(header()->sortIndicatorSection(), header()->sortIndicatorOrder()); - - int row_count = m_sourceModel->rowCount(); - if (row_count > 0) { - QModelIndex last_item = current_index.row() < row_count ? - m_proxyModel->index(current_index.row(), - MSG_DB_TITLE_INDEX) : - m_proxyModel->index(row_count - 1, - MSG_DB_TITLE_INDEX); - - setCurrentIndex(last_item); - scrollTo(last_item); - reselectIndexes(QModelIndexList() << last_item); - } - else { - emit currentMessagesRemoved(); - } - } -} - void MessagesView::switchSelectedMessagesImportance() { QModelIndex current_index = selectionModel()->currentIndex(); diff --git a/src/gui/messagesview.h b/src/gui/messagesview.h index 5d97a6318..b03621912 100755 --- a/src/gui/messagesview.h +++ b/src/gui/messagesview.h @@ -73,7 +73,6 @@ class MessagesView : public QTreeView { void markSelectedMessagesUnread(); void switchSelectedMessagesImportance(); void deleteSelectedMessages(); - void restoreSelectedMessages(); void selectNextItem(); void selectPreviousItem(); From f712ae1cf754b555aa560c816333a5c25020d85e Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 13 Nov 2015 11:18:47 +0100 Subject: [PATCH 044/203] Some cleaning of messages model. --- src/core/messagesmodel.cpp | 34 ++++++++++++++++------------------ src/core/messagesmodel.h | 30 +++++++++++++----------------- src/gui/feedmessageviewer.cpp | 2 +- src/gui/messagestoolbar.cpp | 2 +- src/gui/messagestoolbar.h | 2 +- src/gui/messagesview.cpp | 7 +++---- src/gui/messagesview.h | 2 +- 7 files changed, 36 insertions(+), 43 deletions(-) mode change 100644 => 100755 src/gui/messagestoolbar.h diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index cae3e6e30..49014e078 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -30,7 +30,7 @@ MessagesModel::MessagesModel(QObject *parent) : QSqlTableModel(parent, qApp->database()->connection(QSL("MessagesModel"), DatabaseFactory::FromSettings)), - m_messageFilter(NoHighlighting), m_customDateFormat(QString()) { + m_messageHighlighter(NoHighlighting), m_customDateFormat(QString()) { setObjectName(QSL("MessagesModel")); setupFonts(); setupIcons(); @@ -55,11 +55,9 @@ void MessagesModel::setupIcons() { m_unreadIcon = qApp->icons()->fromTheme(QSL("mail-mark-unread")); } -FeedsSelection MessagesModel::loadedSelection() const { - return m_currentSelection; -} +void MessagesModel::fetchAllData() { + select(); -void MessagesModel::fetchAll() { while (canFetchMore()) { fetchMore(); } @@ -84,12 +82,16 @@ void MessagesModel::loadMessages(const FeedsSelection &selection) { qDebug("Loading messages from feeds: %s.", qPrintable(assembled_ids)); } - select(); - fetchAll(); + fetchAllData(); } -void MessagesModel::filterMessages(MessagesModel::MessageFilter filter) { - m_messageFilter = filter; +bool MessagesModel::submitAll() { + qFatal("Submitting changes via model is not allowed."); + return false; +} + +void MessagesModel::highlightMessages(MessagesModel::MessageHighlighter highlight) { + m_messageHighlighter = highlight; emit layoutAboutToBeChanged(); emit layoutChanged(); } @@ -196,7 +198,7 @@ QVariant MessagesModel::data(const QModelIndex &idx, int role) const { return QSqlTableModel::data(index(idx.row(), MSG_DB_READ_INDEX)).toInt() == 1 ? m_normalFont : m_boldFont; case Qt::ForegroundRole: - switch (m_messageFilter) { + switch (m_messageHighlighter) { case HighlightImportant: return QSqlTableModel::data(index(idx.row(), MSG_DB_IMPORTANT_INDEX)).toInt() == 1 ? QColor(Qt::blue) : QVariant(); @@ -348,8 +350,7 @@ bool MessagesModel::switchBatchMessageImportance(const QModelIndexList &messages if (query_read_msg.exec(QString(QSL("UPDATE Messages SET is_important = NOT is_important WHERE id IN (%1);")) .arg(message_ids.join(QSL(", "))))) { - select(); - fetchAll(); + fetchAllData(); //emit messageCountsChanged(false); return true; @@ -383,8 +384,7 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int } if (query_read_msg.exec(sql_delete_query)) { - select(); - fetchAll(); + fetchAllData(); emit messageCountsChanged(m_currentSelection.mode(), true, false); return true; @@ -409,8 +409,7 @@ bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootIt if (query_read_msg.exec(QString(QSL("UPDATE Messages SET is_read = %2 WHERE id IN (%1);")) .arg(message_ids.join(QSL(", ")), read == RootItem::Read ? QSL("1") : QSL("0")))) { - select(); - fetchAll(); + fetchAllData(); emit messageCountsChanged(m_currentSelection.mode(), false, false); return true; @@ -440,8 +439,7 @@ bool MessagesModel::setBatchMessagesRestored(const QModelIndexList &messages) { QString sql_delete_query = QString(QSL("UPDATE Messages SET is_deleted = 0 WHERE id IN (%1);")).arg(message_ids.join(QSL(", "))); if (query_read_msg.exec(sql_delete_query)) { - select(); - fetchAll(); + fetchAllData(); emit messageCountsChanged(m_currentSelection.mode(), true, true); return true; diff --git a/src/core/messagesmodel.h b/src/core/messagesmodel.h index 312982288..d9b747502 100755 --- a/src/core/messagesmodel.h +++ b/src/core/messagesmodel.h @@ -35,7 +35,7 @@ class MessagesModel : public QSqlTableModel { public: // Enum which describes basic filtering schemes // for messages. - enum MessageFilter { + enum MessageHighlighter { NoHighlighting = 100, HighlightUnread = 101, HighlightImportant = 102 @@ -55,15 +55,6 @@ class MessagesModel : public QSqlTableModel { Message messageAt(int row_index) const; int messageId(int row_index) const; - FeedsSelection loadedSelection() const; - - public slots: - // To disable persistent changes submissions. - inline bool submitAll() { - qFatal("Submitting changes via model is not allowed."); - return false; - } - void updateDateFormat(); void reloadWholeLayout(); @@ -85,18 +76,24 @@ class MessagesModel : public QSqlTableModel { bool setBatchMessagesRestored(const QModelIndexList &messages); // Fetches ALL available data to the model. - void fetchAll(); + void fetchAllData(); + // Filters messages + void highlightMessages(MessageHighlighter highlight); + + public slots: // Loads messages of given feeds. void loadMessages(const FeedsSelection &selection); - void filterMessages(MessageFilter filter); - signals: // Emitted if some persistent change is made which affects count of "unread/all" messages. void messageCountsChanged(FeedsSelection::SelectionMode mode, bool total_msg_count_changed, bool any_msg_restored); - protected: + private slots: + // To disable persistent changes submissions. + bool submitAll(); + + private: // Sets up header data. void setupHeaderData(); @@ -106,8 +103,7 @@ class MessagesModel : public QSqlTableModel { // Sets up all icons which are used directly by this model. void setupIcons(); - private: - MessageFilter m_messageFilter; + MessageHighlighter m_messageHighlighter; QString m_customDateFormat; FeedsSelection m_currentSelection; @@ -122,6 +118,6 @@ class MessagesModel : public QSqlTableModel { QIcon m_unreadIcon; }; -Q_DECLARE_METATYPE(MessagesModel::MessageFilter) +Q_DECLARE_METATYPE(MessagesModel::MessageHighlighter) #endif // MESSAGESMODEL_H diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index c5ccaf78e..32208b220 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -313,7 +313,7 @@ void FeedMessageViewer::createConnections() { // Filtering & searching. connect(m_toolBarMessages, SIGNAL(messageSearchPatternChanged(QString)), m_messagesView, SLOT(searchMessages(QString))); - connect(m_toolBarMessages, SIGNAL(messageFilterChanged(MessagesModel::MessageFilter)), m_messagesView, SLOT(filterMessages(MessagesModel::MessageFilter))); + connect(m_toolBarMessages, SIGNAL(messageFilterChanged(MessagesModel::MessageHighlighter)), m_messagesView, SLOT(filterMessages(MessagesModel::MessageHighlighter))); // Message changers. connect(m_messagesView, SIGNAL(currentMessagesRemoved()), m_messagesBrowser, SLOT(clear())); diff --git a/src/gui/messagestoolbar.cpp b/src/gui/messagestoolbar.cpp index 6d511e4ef..c907a5682 100755 --- a/src/gui/messagestoolbar.cpp +++ b/src/gui/messagestoolbar.cpp @@ -103,7 +103,7 @@ void MessagesToolBar::handleMessageHighlighterChange(QAction *action) { m_btnMessageHighlighter->setIcon(action->icon()); m_btnMessageHighlighter->setToolTip(action->text()); - emit messageFilterChanged(action->data().value()); + emit messageFilterChanged(action->data().value()); } void MessagesToolBar::initializeSearchBox() { diff --git a/src/gui/messagestoolbar.h b/src/gui/messagestoolbar.h old mode 100644 new mode 100755 index 673df7a2f..e1f33d559 --- a/src/gui/messagestoolbar.h +++ b/src/gui/messagestoolbar.h @@ -56,7 +56,7 @@ class MessagesToolBar : public BaseToolBar { void messageSearchPatternChanged(const QString &pattern); // Emitted if message filter is changed. - void messageFilterChanged(MessagesModel::MessageFilter filter); + void messageFilterChanged(MessagesModel::MessageHighlighter filter); private slots: // Called when highlighter gets changed. diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index e8eb2c609..ae2cd009f 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -78,8 +78,7 @@ void MessagesView::reloadSelections(bool mark_current_index_read) { QModelIndexList mapped_indexes = m_proxyModel->mapListToSource(selected_indexes); // Reload the model now. - m_sourceModel->select(); - m_sourceModel->fetchAll(); + m_sourceModel->fetchAllData(); sortByColumn(header()->sortIndicatorSection(), header()->sortIndicatorOrder()); @@ -451,8 +450,8 @@ void MessagesView::searchMessages(const QString &pattern) { } } -void MessagesView::filterMessages(MessagesModel::MessageFilter filter) { - m_sourceModel->filterMessages(filter); +void MessagesView::filterMessages(MessagesModel::MessageHighlighter filter) { + m_sourceModel->highlightMessages(filter); } void MessagesView::adjustColumns() { diff --git a/src/gui/messagesview.h b/src/gui/messagesview.h index b03621912..2e43e0dd8 100755 --- a/src/gui/messagesview.h +++ b/src/gui/messagesview.h @@ -79,7 +79,7 @@ class MessagesView : public QTreeView { // Searchs the visible message according to given pattern. void searchMessages(const QString &pattern); - void filterMessages(MessagesModel::MessageFilter filter); + void filterMessages(MessagesModel::MessageHighlighter filter); private slots: // Marks given indexes as selected. From 42b88b8db74ed25073c8a779e4d505d7295cceb3 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 16 Nov 2015 07:05:21 +0100 Subject: [PATCH 045/203] Some fixes for parsing. --- src/core/parsingfactory.cpp | 2 +- src/gui/feedsview.cpp | 58 +++++++++++++++++------- src/gui/feedsview.h | 8 ++-- src/services/tt-rss/ttrssserviceroot.cpp | 1 - 4 files changed, 47 insertions(+), 22 deletions(-) diff --git a/src/core/parsingfactory.cpp b/src/core/parsingfactory.cpp index fc8a96145..af0ccd3ac 100755 --- a/src/core/parsingfactory.cpp +++ b/src/core/parsingfactory.cpp @@ -73,7 +73,7 @@ QList ParsingFactory::parseAsATOM10(const QString &data) { for (int i = 0; i < elem_links.size(); i++) { QDomElement link = elem_links.at(i).toElement(); - if (link.attribute(QSL("rel")) == QL1S("enclosure")) { + if (link.attribute(QSL("rel")) == QSL("enclosure")) { new_message.m_enclosures.append(Enclosure(link.attribute(QSL("href")), link.attribute(QSL("type")))); qDebug("Adding enclosure '%s' for the message.", qPrintable(new_message.m_enclosures.last().m_url)); diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 25abe83f6..654f54014 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -45,7 +45,8 @@ FeedsView::FeedsView(QWidget *parent) : QTreeView(parent), m_contextMenuCategories(NULL), m_contextMenuFeeds(NULL), - m_contextMenuEmptySpace(NULL) { + m_contextMenuEmptySpace(NULL), + m_contextMenuOtherItems(NULL) { setObjectName(QSL("FeedsView")); // Allocate models. @@ -460,7 +461,7 @@ void FeedsView::selectPreviousItem() { } } -void FeedsView::initializeContextMenuCategories(RootItem *clicked_item) { +QMenu *FeedsView::initializeContextMenuCategories(RootItem *clicked_item) { if (m_contextMenuCategories == NULL) { m_contextMenuCategories = new QMenu(tr("Context menu for categories"), this); } @@ -482,9 +483,11 @@ void FeedsView::initializeContextMenuCategories(RootItem *clicked_item) { m_contextMenuCategories->addSeparator(); m_contextMenuCategories->addActions(specific_actions); } + + return m_contextMenuCategories; } -void FeedsView::initializeContextMenuFeeds(RootItem *clicked_item) { +QMenu *FeedsView::initializeContextMenuFeeds(RootItem *clicked_item) { if (m_contextMenuFeeds == NULL) { m_contextMenuFeeds = new QMenu(tr("Context menu for categories"), this); } @@ -506,12 +509,39 @@ void FeedsView::initializeContextMenuFeeds(RootItem *clicked_item) { m_contextMenuFeeds->addSeparator(); m_contextMenuFeeds->addActions(specific_actions); } + + return m_contextMenuFeeds; } -void FeedsView::initializeContextMenuEmptySpace() { - m_contextMenuEmptySpace = new QMenu(tr("Context menu for empty space"), this); - m_contextMenuEmptySpace->addAction(qApp->mainForm()->m_ui->m_actionUpdateAllItems); - m_contextMenuEmptySpace->addSeparator(); +QMenu *FeedsView::initializeContextMenuEmptySpace() { + if (m_contextMenuEmptySpace == NULL) { + m_contextMenuEmptySpace = new QMenu(tr("Context menu for empty space"), this); + m_contextMenuEmptySpace->addAction(qApp->mainForm()->m_ui->m_actionUpdateAllItems); + m_contextMenuEmptySpace->addSeparator(); + } + + return m_contextMenuEmptySpace; +} + +QMenu *FeedsView::initializeContextMenuOtherItem(RootItem *clicked_item) { + if (m_contextMenuOtherItems == NULL) { + m_contextMenuOtherItems = new QMenu(tr("Context menu for other items"), this); + } + else { + m_contextMenuOtherItems->clear(); + } + + QList specific_actions = clicked_item->contextMenuActions(); + + if (!specific_actions.isEmpty()) { + m_contextMenuOtherItems->addSeparator(); + m_contextMenuOtherItems->addActions(specific_actions); + } + else { + m_contextMenuOtherItems->addAction(qApp->mainForm()->m_ui->m_actionNoActions); + } + + return m_contextMenuOtherItems; } void FeedsView::setupAppearance() { @@ -573,27 +603,21 @@ void FeedsView::contextMenuEvent(QContextMenuEvent *event) { if (clicked_item->kind() == RootItemKind::Category) { // Display context menu for categories. - initializeContextMenuCategories(clicked_item); - m_contextMenuCategories->exec(event->globalPos()); + initializeContextMenuCategories(clicked_item)->exec(event->globalPos()); } else if (clicked_item->kind() == RootItemKind::Feed) { // Display context menu for feeds. - initializeContextMenuFeeds(clicked_item); - m_contextMenuFeeds->exec(event->globalPos()); + initializeContextMenuFeeds(clicked_item)->exec(event->globalPos()); } else { // TODO: volaz specificke menu polozky? zobrazovat menu pro dalsi typy // polozek jako odpadkovy kos atp. + initializeContextMenuOtherItem(clicked_item)->exec(event->globalPos()); } } else { // Display menu for empty space. - if (m_contextMenuEmptySpace == NULL) { - // Context menu is not initialized, initialize. - initializeContextMenuEmptySpace(); - } - - m_contextMenuEmptySpace->exec(event->globalPos()); + initializeContextMenuEmptySpace()->exec(event->globalPos()); } } diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index 34950f403..0d357c6a5 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -130,9 +130,10 @@ class FeedsView : public QTreeView { private: // Initializes context menus. - void initializeContextMenuCategories(RootItem *clicked_item); - void initializeContextMenuFeeds(RootItem *clicked_item); - void initializeContextMenuEmptySpace(); + QMenu *initializeContextMenuCategories(RootItem *clicked_item); + QMenu *initializeContextMenuFeeds(RootItem *clicked_item); + QMenu *initializeContextMenuEmptySpace(); + QMenu *initializeContextMenuOtherItem(RootItem *clicked_item); // Sets up appearance of this widget. void setupAppearance(); @@ -163,6 +164,7 @@ class FeedsView : public QTreeView { QMenu *m_contextMenuCategories; QMenu *m_contextMenuFeeds; QMenu *m_contextMenuEmptySpace; + QMenu *m_contextMenuOtherItems; FeedsModel *m_sourceModel; FeedsProxyModel *m_proxyModel; diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 406512724..e5a9b51a1 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -34,7 +34,6 @@ TtRssServiceRoot::~TtRssServiceRoot() { } bool TtRssServiceRoot::editViaGui() { - // TODO: zobrazit custom edit dialog pro ttrss return false; } From 34222b55b33d576520d5ef9f6d00a99bc7909934 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 16 Nov 2015 08:38:29 +0100 Subject: [PATCH 046/203] Fixed #130. --- resources/text/CHANGELOG | 1 + src/core/parsingfactory.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 0985b6079..02bb88db0 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -21,6 +21,7 @@ Fixed:
    +
  • Fixed obtaining of contents in RSS 2.0 feed entries. (bug #130)
  • Improved popup informing about changes in newly installed version.
  • Icons in notification popups are now smaller (22 x 22 pixels).
  • Encoding selection widget in feed add/edit dialog now detects encodings via case insensitive string matching.
  • diff --git a/src/core/parsingfactory.cpp b/src/core/parsingfactory.cpp index af0ccd3ac..017d372d9 100755 --- a/src/core/parsingfactory.cpp +++ b/src/core/parsingfactory.cpp @@ -203,12 +203,12 @@ QList ParsingFactory::parseAsRSS20(const QString &data) { // Deal with titles & descriptions. QString elem_title = message_item.namedItem(QSL("title")).toElement().text().simplified(); - QString elem_description = message_item.namedItem(QSL("description")).toElement().text(); + QString elem_description = message_item.namedItem(QSL("encoded")).toElement().text(); QString elem_enclosure = message_item.namedItem(QSL("enclosure")).toElement().attribute(QSL("url")); QString elem_enclosure_type = message_item.namedItem(QSL("enclosure")).toElement().attribute(QSL("type")); if (elem_description.isEmpty()) { - elem_description = message_item.namedItem(QSL("encoded")).toElement().text(); + elem_description = message_item.namedItem(QSL("description")).toElement().text(); } // Now we obtained maximum of information for title & description. From 86095778a3d54cd2fcde8a23477184282c3dba14 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 17 Nov 2015 07:41:23 +0100 Subject: [PATCH 047/203] Some changes to API, some lang stuff. --- localization/rssguard-cs_CZ.ts | 104 ++++++++++++------ src/core/rootitem.h | 50 +++++---- src/gui/dialogs/formabout.cpp | 2 +- src/gui/dialogs/formsettings.cpp | 2 +- src/gui/dialogs/formsettings.ui | 2 +- src/services/abstract/feed.cpp | 9 -- src/services/abstract/feed.h | 6 - src/services/standard/standardserviceroot.cpp | 10 +- src/services/standard/standardserviceroot.h | 1 + 9 files changed, 111 insertions(+), 75 deletions(-) diff --git a/localization/rssguard-cs_CZ.ts b/localization/rssguard-cs_CZ.ts index b518b6ae4..19e1a9560 100644 --- a/localization/rssguard-cs_CZ.ts +++ b/localization/rssguard-cs_CZ.ts @@ -1,4 +1,6 @@ - + + + AdBlockAddSubscriptionDialog @@ -100,7 +102,7 @@ Berte také na paměti, že některé prostředky webových stránek jsou intern AdBlockIcon Adblock - + Show Adblock &settings @@ -212,7 +214,11 @@ Tato kategorie neobsahuje žádné položky. %n unread message(s). Tooltip for "unread" column of feed list. - %n nepřečtená zpráva.%n nepřečtené zprávy.%n nepřečtených zpráv. + + %n nepřečtená zpráva. + %n nepřečtené zprávy. + %n nepřečtených zpráv. + @@ -292,10 +298,14 @@ Tato kategorie neobsahuje žádné položky. Click me to add feeds from this website. This website contains %n feed(s). - Pro přidání kanálů z této stránky na mě klikni. -Tato stránka obsahuje %n kanál.Pro přidání kanálů z této stránky na mě klikni. -Tato stránka obsahuje %n kanály.Pro přidání kanálů z této stránky na mě klikni. -Tato stránka obsahuje %n kanálů. + + Pro přidání kanálů z této stránky na mě klikni. +Tato stránka obsahuje %n kanál. + Pro přidání kanálů z této stránky na mě klikni. +Tato stránka obsahuje %n kanály. + Pro přidání kanálů z této stránky na mě klikni. +Tato stránka obsahuje %n kanálů. + @@ -373,14 +383,14 @@ Tato stránka obsahuje %n kanálů. Stahování dokončeno - File '%1' is downloaded. + File '%1' is downloaded. Click here to open parent directory. Soubor '%1' je stažen. Klikněte sem pro otevření nadřazeného adresáře. URL: %1 - + Local file: %1 @@ -399,11 +409,19 @@ Klikněte sem pro otevření nadřazeného adresáře. %n minutes remaining - %n minuta do konce%n minuty do konce%n minut do konce + + %n minuta do konce + %n minuty do konce + %n minut do konce + %n seconds remaining - %n vteřina do konce%n vteřiny do konce%n vteřin do konce + + %n vteřina do konce + %n vteřiny do konce + %n vteřin do konce + bytes @@ -411,19 +429,23 @@ Klikněte sem pro otevření nadřazeného adresáře. kB - + MB - + GB - + Downloading %n file(s)... - Stahuji %n soubor...Stahuji %n soubory...Stahuji %n souborů... + + Stahuji %n soubor... + Stahuji %n soubory... + Stahuji %n souborů... + @@ -441,7 +463,11 @@ Klikněte sem pro otevření nadřazeného adresáře. uses specific settings (%n minute(s) to next auto-update) Describes feed auto-update status. - používá specifické nastavení (%n minuta do další aktualizace)používá specifické nastavení (%n minuty do další aktualizace)používá specifické nastavení (%n minut do další aktualizace) + + používá specifické nastavení (%n minuta do další aktualizace) + používá specifické nastavení (%n minuty do další aktualizace) + používá specifické nastavení (%n minut do další aktualizace) + %1 (%2)%3 @@ -459,7 +485,11 @@ Automatický update: %5 %n unread message(s). Tooltip for "unread" column of feed list. - %n nepřečtená zpráva.%n nepřečtené zprávy.%n nepřečtených zpráv. + + %n nepřečtená zpráva. + %n nepřečtené zprávy. + %n nepřečtených zpráv. + Metadata not fetched @@ -568,7 +598,11 @@ Automatický update: %5 I will auto-update %n feed(s). - Budu aktualizovat %n kanál.Budu aktualizovat %n kanály.Budu aktualizovat %n kanálů. + + Budu aktualizovat %n kanál. + Budu aktualizovat %n kanály. + Budu aktualizovat %n kanálů. + @@ -952,7 +986,11 @@ Automatický update: %5 day(s) - den dny dnů + + den + dny + dnů + Shrink database file @@ -1055,7 +1093,7 @@ Automatický update: %5 URL - + Fetch it now @@ -1862,7 +1900,7 @@ Automatický update: %5 Proxy - + Icons && skins @@ -1891,7 +1929,7 @@ Automatický update: %5 Port - + Username @@ -1927,15 +1965,15 @@ Automatický update: %5 Email - + Socks5 - + Http - + (not supported on this platform) @@ -2160,7 +2198,7 @@ Autoři této aplikace nenesou žádnou odpovědnost za ztrátu Vašich dat. ms - + Update all feed on application startup @@ -2451,7 +2489,7 @@ File filter for external e-mail selection dialog. Mozilla Thunderbird - + Working database which you have full access to. @@ -2657,7 +2695,7 @@ Přejít na web aplikace a stáhnout jej ručně. MessagesModel Id - + Read @@ -2681,7 +2719,7 @@ Přejít na web aplikace a stáhnout jej ručně. Url - + Author @@ -2964,7 +3002,11 @@ Přejít na web aplikace a stáhnout jej ručně. %n deleted message(s). - %n smazaná zpráva.%n smazané zprávy.%n smazaných zpráv. + + %n smazaná zpráva. + %n smazané zprávy. + %n smazaných zpráv. + @@ -3321,4 +3363,4 @@ Nepřečtené zprávy: %2 Hledat "%1" přes Google... - \ No newline at end of file + diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 1faf2f308..b44864276 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -64,27 +64,9 @@ class RootItem : public QObject { explicit RootItem(RootItem *parent_item = NULL); virtual ~RootItem(); - // Basic operations. - inline virtual RootItem *parent() const { - return m_parentItem; - } - - inline virtual void setParent(RootItem *parent_item) { - m_parentItem = parent_item; - } - - inline virtual RootItem *child(int row) { - return m_childItems.value(row); - } - - inline virtual int childCount() const { - return m_childItems.size(); - } - - inline virtual void appendChild(RootItem *child) { - m_childItems.append(child); - child->setParent(this); - } + ///////////////////////////////////////// + // /* Members to override. + ///////////////////////////////////////// // Returns list of specific actions which can be done with the item. // Do not include general actions here like actions: @@ -118,6 +100,32 @@ class RootItem : public QObject { virtual int countOfUnreadMessages() const; virtual int countOfAllMessages() const; + ///////////////////////////////////////// + // Members to override. */ + ///////////////////////////////////////// + + // Basic operations. + inline RootItem *parent() const { + return m_parentItem; + } + + inline void setParent(RootItem *parent_item) { + m_parentItem = parent_item; + } + + inline RootItem *child(int row) { + return m_childItems.value(row); + } + + inline int childCount() const { + return m_childItems.size(); + } + + inline void appendChild(RootItem *child) { + m_childItems.append(child); + child->setParent(this); + } + // Access to children. inline QList childItems() const { return m_childItems; diff --git a/src/gui/dialogs/formabout.cpp b/src/gui/dialogs/formabout.cpp index 8cce70b07..0df95c066 100755 --- a/src/gui/dialogs/formabout.cpp +++ b/src/gui/dialogs/formabout.cpp @@ -126,7 +126,7 @@ void FormAbout::loadLicenseAndInformation() { m_ui->m_txtInfo->setText(tr("%5 is a (very) tiny feed reader." "

    This software is distributed under the terms of GNU General Public License, version 3." "

    Contacts:" - "
    • %1 ~email
    • " + "
      • %1 ~e-mail
      • " "
      • %2 ~website
      " "You can obtain source code for %5 from its website." "


      Copyright (C) 2011-%3 %4").arg(APP_EMAIL, diff --git a/src/gui/dialogs/formsettings.cpp b/src/gui/dialogs/formsettings.cpp index d79214f26..f47297874 100755 --- a/src/gui/dialogs/formsettings.cpp +++ b/src/gui/dialogs/formsettings.cpp @@ -84,7 +84,7 @@ FormSettings::FormSettings(QWidget *parent) : QDialog(parent), m_ui(new Ui::Form << /*: Skin list name column. */ tr("Name") << /*: Version column of skin list. */ tr("Version") << tr("Author") - << tr("Email")); + << tr("E-mail")); #if QT_VERSION >= 0x050000 // Setup languages. diff --git a/src/gui/dialogs/formsettings.ui b/src/gui/dialogs/formsettings.ui index c55ccd4d6..adb74b6f1 100755 --- a/src/gui/dialogs/formsettings.ui +++ b/src/gui/dialogs/formsettings.ui @@ -88,7 +88,7 @@ - 3 + 0 diff --git a/src/services/abstract/feed.cpp b/src/services/abstract/feed.cpp index c7a030a5f..a07cc8a7a 100755 --- a/src/services/abstract/feed.cpp +++ b/src/services/abstract/feed.cpp @@ -29,12 +29,3 @@ Feed::Feed(RootItem *parent) : RootItem(parent) { Feed::~Feed() { } - -int Feed::childCount() const { - // Because feed has no children. - return 0; -} - -void Feed::appendChild(RootItem *child) { - Q_UNUSED(child) -} diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index 992f3174d..d7b82f187 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -50,12 +50,6 @@ class Feed : public RootItem { explicit Feed(RootItem *parent = NULL); virtual ~Feed(); - // Returns 0, feeds have no children. - int childCount() const; - - // Appending of childs to feed is not allowed. - void appendChild(RootItem *child); - // Performs synchronous update and returns number of newly updated messages. virtual int update() = 0; diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 6a91d8315..2c274ccca 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -38,7 +38,6 @@ #include #include #include -#include #include #include @@ -47,6 +46,7 @@ StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_mo : ServiceRoot(feeds_model, parent), m_recycleBin(new StandardRecycleBin(this)), m_actionExportFeeds(NULL), m_actionImportFeeds(NULL), m_serviceMenu(QList()), m_addItemMenu(QList()), m_feedContextMenu(QList()), m_actionFeedFetchMetadata(NULL) { + setTitle(qApp->system()->getUsername() + QL1S("@") + QL1S(APP_LOW_NAME)); setIcon(StandardServiceEntryPoint().icon()); setDescription(tr("This is obligatory service account for standard RSS/RDF/ATOM feeds.")); @@ -65,9 +65,9 @@ StandardServiceRoot::~StandardServiceRoot() { void StandardServiceRoot::start() { if (qApp->isFirstRun()) { - if (MessageBox::show(qApp->mainForm(), QMessageBox::Question, QObject::tr("Load initial feeds"), - QObject::tr("You started %1 for the first time, now you can load initial set of feeds.").arg(APP_NAME), - QObject::tr("Do you want to load initial set of feeds?"), + if (MessageBox::show(qApp->mainForm(), QMessageBox::Question, QObject::tr("Load initial set of feeds"), + tr("You started %1 for the first time, now you can load initial set of feeds.").arg(APP_NAME), + tr("Do you want to load initial set of feeds?"), QString(), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { QString target_opml_file = APP_INITIAL_FEEDS_PATH + QDir::separator() + FEED_INITIAL_OPML_PATTERN; QString current_locale = qApp->localization()->loadedLanguage(); @@ -98,7 +98,7 @@ void StandardServiceRoot::start() { } void StandardServiceRoot::stop() { - + qDebug("Stopping StandardServiceRoot instance."); } bool StandardServiceRoot::canBeEdited() { diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 5f02dfb0a..5cc7ab55b 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -43,6 +43,7 @@ class StandardServiceRoot : public ServiceRoot { explicit StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent = NULL); virtual ~StandardServiceRoot(); + // Start/stop root. void start(); void stop(); From 6aaec164f1d8c8008b68f8155e2f8afb7df0fef4 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 17 Nov 2015 09:02:50 +0100 Subject: [PATCH 048/203] =?UTF-8?q?sHIt.=C2=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/feedsmodel.cpp | 6 +- src/core/rootitem.cpp | 50 +++++++----- src/core/rootitem.h | 93 +++++++++++----------- src/services/standard/standardrecyclebin.h | 1 - 4 files changed, 78 insertions(+), 72 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 828dac9ef..e5ec5416d 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -440,11 +440,7 @@ Feed *FeedsModel::feedForIndex(const QModelIndex &index) { } bool FeedsModel::markItemRead(RootItem *item, RootItem::ReadStatus read) { - if (item->canBeMarkedAsReadUnread(read)) { - return item->markAsReadUnread(read); - } - - return false; + return item->markAsReadUnread(read); } bool FeedsModel::markItemCleared(RootItem *item, bool clean_read_only) { diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index 6cd3d9412..4b4ef2493 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -100,22 +100,6 @@ void RootItem::setupFonts() { m_boldFont.setBold(true); } -QFont RootItem::boldFont() const { - return m_boldFont; -} - -void RootItem::setBoldFont(const QFont &bold_font) { - m_boldFont = bold_font; -} - -QFont RootItem::normalFont() const { - return m_normalFont; -} - -void RootItem::setNormalFont(const QFont &normal_font) { - m_normalFont = normal_font; -} - int RootItem::row() const { if (m_parentItem) { return m_parentItem->m_childItems.indexOf(const_cast(this)); @@ -133,7 +117,7 @@ QVariant RootItem::data(int column, int role) const { switch (role) { case Qt::EditRole: if (column == FDS_MODEL_TITLE_INDEX) { - return title(); + return m_title; } else if (column == FDS_MODEL_COUNTS_INDEX) { return countOfUnreadMessages(); @@ -143,11 +127,11 @@ QVariant RootItem::data(int column, int role) const { } case Qt::FontRole: - return countOfUnreadMessages() > 0 ? boldFont() : normalFont(); + return countOfUnreadMessages() > 0 ? m_boldFont : m_normalFont; case Qt::DisplayRole: if (column == FDS_MODEL_TITLE_INDEX) { - return title(); + return m_title; } else if (column == FDS_MODEL_COUNTS_INDEX) { int count_all = countOfAllMessages(); @@ -192,6 +176,34 @@ int RootItem::countOfAllMessages() const { return total_count; } +bool RootItem::isChildOf(RootItem *root) { + if (root == NULL) { + return false; + } + + RootItem *this_item = this; + + while (this_item->kind() != RootItemKind::Root) { + if (root->childItems().contains(this_item)) { + return true; + } + else { + this_item = this_item->parent(); + } + } + + return false; +} + +bool RootItem::isParentOf(RootItem *child) { + if (child == NULL) { + return false; + } + else { + return child->isChildOf(this); + } +} + QList RootItem::getSubTree() { QList children; QList traversable_items; diff --git a/src/core/rootitem.h b/src/core/rootitem.h index b44864276..d16f3a08a 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -74,19 +74,33 @@ class RootItem : public QObject { // NOTE: Ownership of returned actions is not switched to caller, free them when needed. virtual QList contextMenuActions(); + // Can properties of this item be edited? virtual bool canBeEdited(); + + // Performs editing of properties of this item (probably via dialog) + // and returns result status. virtual bool editViaGui(); + + // Can the item be deleted? virtual bool canBeDeleted(); + + // Performs deletion of the item, this + // method should NOT display any additional dialogs. + // Returns result status. virtual bool deleteViaGui(); + // Can this item be marked read/unread? virtual bool canBeMarkedAsReadUnread(ReadStatus status); + + // Performs all needed steps (DB update, remote server update) + // to mark this item as read/unread. virtual bool markAsReadUnread(ReadStatus status); // This method should "clean" all messages it contains. - // What "clean" means? It means delete message -> move them to recycle bin + // What "clean" means? It means delete messages -> move them to recycle bin // or eventually remove them completely if there is no recycle bin functionality. // If this method is called on "recycle bin" instance of your - // service account, it should not do anything. + // service account, it should NOT do anything. virtual bool cleanMessages(bool clear_only_read); // Updates counts of all/unread messages for this feed. @@ -104,7 +118,6 @@ class RootItem : public QObject { // Members to override. */ ///////////////////////////////////////// - // Basic operations. inline RootItem *parent() const { return m_parentItem; } @@ -131,47 +144,28 @@ class RootItem : public QObject { return m_childItems; } - inline void setChildItems(QList child_items) { - m_childItems = child_items; - } - - // Checks whether THIS object is child (direct or indirect) - // of the given root. - bool isChildOf(RootItem *root) { - if (root == NULL) { - return false; - } - - RootItem *this_item = this; - - while (this_item->kind() != RootItemKind::Root) { - if (root->childItems().contains(this_item)) { - return true; - } - else { - this_item = this_item->parent(); - } - } - - return false; - } - - // Is "this" item parent if given child? - bool isParentOf(RootItem *child) { - if (child == NULL) { - return false; - } - else { - return child->isChildOf(this); - } - } - // Removes all children from this item. // NOTE: Children are NOT freed from the memory. inline void clearChildren() { m_childItems.clear(); } + inline void setChildItems(QList child_items) { + m_childItems = child_items; + } + + // Removes particular child at given index. + // NOTE: Child is NOT freed from the memory. + bool removeChild(int index); + bool removeChild(RootItem *child); + + // Checks whether "this" object is child (direct or indirect) + // of the given root. + bool isChildOf(RootItem *root); + + // Is "this" item parent (direct or indirect) if given child? + bool isParentOf(RootItem *child); + // Returns flat list of all items from subtree where this item is a root. // Returned list includes this item too. QList getSubTree(); @@ -182,11 +176,6 @@ class RootItem : public QObject { // Returns the service root node which is direct or indirect parent of current item. ServiceRoot *getParentServiceRoot(); - // Removes particular child at given index. - // NOTE: Child is NOT freed from the memory. - bool removeChild(int index); - bool removeChild(RootItem *child); - inline RootItemKind::Kind kind() const { return m_kind; } @@ -238,11 +227,21 @@ class RootItem : public QObject { m_description = description; } - QFont normalFont() const; - void setNormalFont(const QFont &normal_font); + inline QFont normalFont() const { + return m_normalFont; + } - QFont boldFont() const; - void setBoldFont(const QFont &bold_font); + inline void setNormalFont(const QFont &normal_font) { + m_normalFont = normal_font; + } + + inline QFont boldFont() const { + return m_boldFont; + } + + inline void setBoldFont(const QFont &bold_font) { + m_boldFont = bold_font; + } // Converters Category *toCategory(); diff --git a/src/services/standard/standardrecyclebin.h b/src/services/standard/standardrecyclebin.h index 7cbbf2d59..24ec68591 100755 --- a/src/services/standard/standardrecyclebin.h +++ b/src/services/standard/standardrecyclebin.h @@ -39,7 +39,6 @@ class StandardRecycleBin : public RootItem { int countOfUnreadMessages() const; int countOfAllMessages() const; QVariant data(int column, int role) const; - bool markAsReadUnread(ReadStatus status); bool empty(); From 2649011ced89bf35268716f92eace7fcd7ac72e0 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 17 Nov 2015 18:58:56 +0100 Subject: [PATCH 049/203] Tweaked dialogs. --- src/gui/dialogs/formmain.ui | 3 +++ src/services/standard/gui/formstandardcategorydetails.ui | 4 ++-- src/services/standard/gui/formstandardfeeddetails.ui | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index d1693d88f..822e25ad4 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -350,6 +350,9 @@ + + false + No actions available diff --git a/src/services/standard/gui/formstandardcategorydetails.ui b/src/services/standard/gui/formstandardcategorydetails.ui index 67bbed086..101ac40e6 100755 --- a/src/services/standard/gui/formstandardcategorydetails.ui +++ b/src/services/standard/gui/formstandardcategorydetails.ui @@ -6,8 +6,8 @@ 0 0 - 346 - 180 + 397 + 205 diff --git a/src/services/standard/gui/formstandardfeeddetails.ui b/src/services/standard/gui/formstandardfeeddetails.ui index fa1511ab4..dc1ed970a 100755 --- a/src/services/standard/gui/formstandardfeeddetails.ui +++ b/src/services/standard/gui/formstandardfeeddetails.ui @@ -6,8 +6,8 @@ 0 0 - 492 - 400 + 517 + 442 From 1633150e673635e5d5d44a6dd80f88cce582dc6a Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 17 Nov 2015 19:06:05 +0100 Subject: [PATCH 050/203] Warning for null strings. --- src/core/parsingfactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/parsingfactory.cpp b/src/core/parsingfactory.cpp index 017d372d9..0cdf85104 100755 --- a/src/core/parsingfactory.cpp +++ b/src/core/parsingfactory.cpp @@ -99,7 +99,7 @@ QList ParsingFactory::parseAsATOM10(const QString &data) { new_message.m_created = current_time; } - // TODO: There is a difference between "" and QString() in terms of NULL SQL values! + // WARNING: There is a difference between "" and QString() in terms of NULL SQL values! // This is because of difference in QString::isNull() and QString::isEmpty(), the "" is not null // while QString() is. if (new_message.m_author.isNull()) { From ebea3e00295308493a9ba08f2fb1a268ffa39e71 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 19 Nov 2015 13:21:38 +0100 Subject: [PATCH 051/203] VERY initial and f*cking buggy implementation of some messages-realted operations - right now, there is added ability to display messages according to selection. --- CMakeLists.txt | 1 - src/core/feedsselection.cpp | 73 ------------------- src/core/feedsselection.h | 50 ------------- src/core/messagesmodel.cpp | 53 +++++++++----- src/core/messagesmodel.h | 8 +- src/gui/feedmessageviewer.cpp | 9 +-- src/gui/feedsview.cpp | 17 +++-- src/gui/feedsview.h | 10 +-- src/gui/messagesview.cpp | 4 +- src/gui/messagesview.h | 3 +- src/services/abstract/serviceroot.h | 10 +++ src/services/standard/standardserviceroot.cpp | 22 ++++++ src/services/standard/standardserviceroot.h | 3 + 13 files changed, 92 insertions(+), 171 deletions(-) delete mode 100755 src/core/feedsselection.cpp delete mode 100755 src/core/feedsselection.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9af5020df..ccf63113f 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -412,7 +412,6 @@ set(APP_SOURCES src/core/rootitem.cpp src/core/parsingfactory.cpp src/core/feeddownloader.cpp - src/core/feedsselection.cpp src/core/message.cpp # ABSTRACT service sources. diff --git a/src/core/feedsselection.cpp b/src/core/feedsselection.cpp deleted file mode 100755 index c21d6e0ac..000000000 --- a/src/core/feedsselection.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// This file is part of RSS Guard. -// -// Copyright (C) 2011-2015 by Martin Rotter -// -// RSS Guard is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// RSS Guard is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with RSS Guard. If not, see . - -#include "core/feedsselection.h" - -#include "core/rootitem.h" -#include "services/standard/standardcategory.h" -#include "services/standard/standardfeed.h" -#include "definitions/definitions.h" - - -FeedsSelection::FeedsSelection(RootItem *root_of_selection) : m_selectedItem(root_of_selection) { -} - -FeedsSelection::FeedsSelection(const FeedsSelection &other) { - m_selectedItem = other.selectedItem(); -} - -FeedsSelection::~FeedsSelection() { -} - -FeedsSelection::SelectionMode FeedsSelection::mode() { - if (m_selectedItem == NULL) { - return FeedsSelection::NoMode; - } - - switch (m_selectedItem->kind()) { - case RootItemKind::Bin: - return FeedsSelection::MessagesFromRecycleBin; - - case RootItemKind::Category: - case RootItemKind::Feed: - return FeedsSelection::MessagesFromFeeds; - - default: - return FeedsSelection::NoMode; - } -} - -RootItem *FeedsSelection::selectedItem() const { - return m_selectedItem; -} - -QString FeedsSelection::generateListOfIds() { - if (m_selectedItem != NULL && - (m_selectedItem->kind() == RootItemKind::Feed || m_selectedItem->kind() == RootItemKind::Category)) { - QList children = m_selectedItem->getSubTreeFeeds(); - QStringList stringy_ids; - - foreach (Feed *child, children) { - stringy_ids.append(QString::number(child->id())); - } - - return stringy_ids.join(QSL(", ")); - } - else { - return QString(); - } -} diff --git a/src/core/feedsselection.h b/src/core/feedsselection.h deleted file mode 100755 index 1295bdffa..000000000 --- a/src/core/feedsselection.h +++ /dev/null @@ -1,50 +0,0 @@ -// This file is part of RSS Guard. -// -// Copyright (C) 2011-2015 by Martin Rotter -// -// RSS Guard is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// RSS Guard is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with RSS Guard. If not, see . - -#ifndef FEEDSSELECTION_H -#define FEEDSSELECTION_H - -#include -#include - - -class RootItem; -class StandardFeed; - -class FeedsSelection { - public: - enum SelectionMode { - NoMode, - MessagesFromFeeds, - MessagesFromRecycleBin - }; - - explicit FeedsSelection(RootItem *root_of_selection = NULL); - FeedsSelection(const FeedsSelection &other); - virtual ~FeedsSelection(); - - SelectionMode mode(); - RootItem *selectedItem() const; - QString generateListOfIds(); - - private: - RootItem *m_selectedItem; -}; - -Q_DECLARE_METATYPE(FeedsSelection::SelectionMode) - -#endif // FEEDSSELECTION_H diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 49014e078..4064fb8cf 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -22,6 +22,8 @@ #include "miscellaneous/textfactory.h" #include "miscellaneous/databasefactory.h" #include "miscellaneous/iconfactory.h" +#include "gui/dialogs/formmain.h" +#include "services/abstract/serviceroot.h" #include #include @@ -42,7 +44,7 @@ MessagesModel::MessagesModel(QObject *parent) // via model, but via DIRECT SQL calls are used to do persistent messages. setEditStrategy(QSqlTableModel::OnManualSubmit); setTable(QSL("Messages")); - loadMessages(FeedsSelection()); + loadMessages(NULL); } MessagesModel::~MessagesModel() { @@ -69,17 +71,21 @@ void MessagesModel::setupFonts() { m_boldFont.setBold(true); } -void MessagesModel::loadMessages(const FeedsSelection &selection) { - m_currentSelection = selection; +void MessagesModel::loadMessages(RootItem *item) { + m_selectedItem = item; - if (m_currentSelection.mode() == FeedsSelection::MessagesFromRecycleBin) { - setFilter(QSL("is_deleted = 1 AND is_pdeleted = 0")); + if (item == NULL) { + setFilter("true != true"); } else { - QString assembled_ids = m_currentSelection.generateListOfIds(); - - setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0")).arg(assembled_ids)); - qDebug("Loading messages from feeds: %s.", qPrintable(assembled_ids)); + if (!item->getParentServiceRoot()->loadMessagesForItem(item, this)) { + qWarning("Loading of messages from item '%s' failed.", qPrintable(item->title())); + qApp->showGuiMessage(tr("Loading of messages from item '%s' failed.").arg(item->title()), + tr("Loading of messages failed, maybe messages could not be downloaded."), + QSystemTrayIcon::Critical, + qApp->mainForm(), + true); + } } fetchAllData(); @@ -276,7 +282,10 @@ bool MessagesModel::setMessageRead(int row_index, int read) { // If commit succeeded, then emit changes, so that view // can reflect. emit dataChanged(index(row_index, 0), index(row_index, columnCount() - 1)); - emit messageCountsChanged(m_currentSelection.mode(), false, false); + emit messageCountsChanged(); + + // TODO: counts changed + //emit messageCountsChanged(m_selectedItem.mode(), false, false); return true; } else { @@ -374,7 +383,9 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int QString sql_delete_query; - if (m_currentSelection.mode() == FeedsSelection::MessagesFromFeeds) { + // TODO: todo + /* + if (m_selectedItem.mode() == FeedsSelection::MessagesFromFeeds) { sql_delete_query = QString(QSL("UPDATE Messages SET is_deleted = %2 WHERE id IN (%1);")).arg(message_ids.join(QSL(", ")), QString::number(deleted)); } @@ -382,11 +393,14 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int sql_delete_query = QString(QSL("UPDATE Messages SET is_pdeleted = %2 WHERE id IN (%1);")).arg(message_ids.join(QSL(", ")), QString::number(deleted)); } + */ if (query_read_msg.exec(sql_delete_query)) { fetchAllData(); + emit messageCountsChanged(); - emit messageCountsChanged(m_currentSelection.mode(), true, false); + // TODO: counts changed + //emit messageCountsChanged(m_selectedItem.mode(), true, false); return true; } else { @@ -411,7 +425,10 @@ bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootIt read == RootItem::Read ? QSL("1") : QSL("0")))) { fetchAllData(); - emit messageCountsChanged(m_currentSelection.mode(), false, false); + emit messageCountsChanged(); + + // TODO: counts changed + //emit messageCountsChanged(m_selectedItem.mode(), false, false); return true; } else { @@ -420,11 +437,6 @@ bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootIt } bool MessagesModel::setBatchMessagesRestored(const QModelIndexList &messages) { - if (m_currentSelection.mode() == FeedsSelection::MessagesFromFeeds) { - qDebug("Cannot restore non-deleted messages."); - return false; - } - QSqlDatabase db_handle = database(); QSqlQuery query_read_msg(db_handle); QStringList message_ids; @@ -441,7 +453,10 @@ bool MessagesModel::setBatchMessagesRestored(const QModelIndexList &messages) { if (query_read_msg.exec(sql_delete_query)) { fetchAllData(); - emit messageCountsChanged(m_currentSelection.mode(), true, true); + emit messageCountsChanged(); + + // TODO: counts changed + //emit messageCountsChanged(m_selectedItem.mode(), true, true); return true; } else { diff --git a/src/core/messagesmodel.h b/src/core/messagesmodel.h index d9b747502..f966a9bb2 100755 --- a/src/core/messagesmodel.h +++ b/src/core/messagesmodel.h @@ -20,7 +20,6 @@ #include "definitions/definitions.h" -#include "core/feedsselection.h" #include "core/message.h" #include "core/rootitem.h" @@ -81,13 +80,12 @@ class MessagesModel : public QSqlTableModel { // Filters messages void highlightMessages(MessageHighlighter highlight); - public slots: // Loads messages of given feeds. - void loadMessages(const FeedsSelection &selection); + void loadMessages(RootItem *item); signals: // Emitted if some persistent change is made which affects count of "unread/all" messages. - void messageCountsChanged(FeedsSelection::SelectionMode mode, bool total_msg_count_changed, bool any_msg_restored); + void messageCountsChanged(); private slots: // To disable persistent changes submissions. @@ -106,7 +104,7 @@ class MessagesModel : public QSqlTableModel { MessageHighlighter m_messageHighlighter; QString m_customDateFormat; - FeedsSelection m_currentSelection; + RootItem *m_selectedItem; QList m_headerData; QList m_tooltipData; diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 32208b220..25bd3c04f 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -25,7 +25,6 @@ #include "miscellaneous/databasecleaner.h" #include "core/messagesproxymodel.h" #include "core/feeddownloader.h" -#include "core/feedsselection.h" #include "services/standard/standardserviceroot.h" #include "services/standard/standardfeed.h" #include "services/standard/standardfeedsimportexportmodel.h" @@ -321,16 +320,16 @@ void FeedMessageViewer::createConnections() { connect(m_messagesView, SIGNAL(currentMessagesRemoved()), this, SLOT(updateMessageButtonsAvailability())); connect(m_messagesView, SIGNAL(currentMessagesChanged(QList)), this, SLOT(updateMessageButtonsAvailability())); - connect(m_feedsView, SIGNAL(feedsSelected(FeedsSelection)), this, SLOT(updateFeedButtonsAvailability())); + connect(m_feedsView, SIGNAL(itemSelected(RootItem*)), this, SLOT(updateFeedButtonsAvailability())); connect(qApp->feedUpdateLock(), SIGNAL(locked()), this, SLOT(updateFeedButtonsAvailability())); connect(qApp->feedUpdateLock(), SIGNAL(unlocked()), this, SLOT(updateFeedButtonsAvailability())); // If user selects feeds, load their messages. - connect(m_feedsView, SIGNAL(feedsSelected(FeedsSelection)), m_messagesView, SLOT(loadFeeds(FeedsSelection))); + connect(m_feedsView, SIGNAL(itemSelected(RootItem*)), m_messagesView, SLOT(loadFeeds(RootItem*))); // If user changes status of some messages, recalculate message counts. - connect(m_messagesView->sourceModel(), SIGNAL(messageCountsChanged(FeedsSelection::SelectionMode,bool,bool)), - m_feedsView, SLOT(receiveMessageCountsChange(FeedsSelection::SelectionMode,bool,bool))); + connect(m_messagesView->sourceModel(), SIGNAL(messageCountsChanged()), + m_feedsView, SLOT(receiveMessageCountsChange())); // State of many messages is changed, then we need // to reload selections. diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 654f54014..a0f473c1d 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -189,9 +189,12 @@ void FeedsView::clearAllFeeds() { emit feedsNeedToBeReloaded(true); } -void FeedsView::receiveMessageCountsChange(FeedsSelection::SelectionMode mode, - bool total_msg_count_changed, - bool any_msg_restored) { +void FeedsView::receiveMessageCountsChange() { + + // TODO: toto vymazat, prepocitani cisel unread/all + // a upozorneni na zmenu itemu provede ten item + // zde jen nechat tu invalidaci read filteru + // If the change came from recycle bin mode, then: // a) total count of message was changed AND no message was restored - some messages // were permanently deleted from recycle bin --> we need to update counts of @@ -207,7 +210,7 @@ void FeedsView::receiveMessageCountsChange(FeedsSelection::SelectionMode mode, // total counts. // b) total count of message was not changed - some messages switched state --> we need to update // counts of just selected feeds. - if (mode == FeedsSelection::MessagesFromRecycleBin) { + /*if (mode == FeedsSelection::MessagesFromRecycleBin) { if (total_msg_count_changed) { if (any_msg_restored) { updateCountsOfAllFeeds(true); @@ -222,7 +225,7 @@ void FeedsView::receiveMessageCountsChange(FeedsSelection::SelectionMode mode, } else { updateCountsOfSelectedFeeds(total_msg_count_changed); - } + }*/ invalidateReadFeedsFilter(); } @@ -582,7 +585,7 @@ void FeedsView::selectionChanged(const QItemSelection &selected, const QItemSele m_proxyModel->setSelectedItem(selected_item); QTreeView::selectionChanged(selected, deselected); - emit feedsSelected(FeedsSelection(selected_item)); + emit itemSelected(selected_item); invalidateReadFeedsFilter(); } @@ -610,8 +613,6 @@ void FeedsView::contextMenuEvent(QContextMenuEvent *event) { initializeContextMenuFeeds(clicked_item)->exec(event->globalPos()); } else { - // TODO: volaz specificke menu polozky? zobrazovat menu pro dalsi typy - // polozek jako odpadkovy kos atp. initializeContextMenuOtherItem(clicked_item)->exec(event->globalPos()); } } diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index 0d357c6a5..13b2e6878 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -18,13 +18,11 @@ #ifndef FEEDSVIEW_H #define FEEDSVIEW_H -#include #include -#include "core/messagesmodel.h" #include "core/feedsmodel.h" -#include "core/feedsselection.h" -#include "miscellaneous/settings.h" + +#include class FeedsProxyModel; @@ -98,7 +96,7 @@ class FeedsView : public QTreeView { // Is called when counts of messages are changed externally, // typically from message view. - void receiveMessageCountsChange(FeedsSelection::SelectionMode mode, bool total_msg_count_changed, bool any_msg_restored); + void receiveMessageCountsChange(); // Reloads counts for selected feeds. void updateCountsOfSelectedFeeds(bool update_total_too); @@ -155,7 +153,7 @@ class FeedsView : public QTreeView { void feedsNeedToBeReloaded(bool mark_current_index_read); // Emitted if user selects new feeds. - void feedsSelected(const FeedsSelection &selection); + void itemSelected(RootItem *item); // Requests opening of given messages in newspaper mode. void openMessagesInNewspaperView(const QList &messages); diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index ae2cd009f..1c224b7d7 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -225,8 +225,8 @@ void MessagesView::selectionChanged(const QItemSelection &selected, const QItemS QTreeView::selectionChanged(selected, deselected); } -void MessagesView::loadFeeds(const FeedsSelection &selection) { - m_sourceModel->loadMessages(selection); +void MessagesView::loadFeeds(RootItem *item) { + m_sourceModel->loadMessages(item); int col = qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortColumnMessages)).toInt(); Qt::SortOrder ord = static_cast(qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortOrderMessages)).toInt()); diff --git a/src/gui/messagesview.h b/src/gui/messagesview.h index 2e43e0dd8..ca94e4f83 100755 --- a/src/gui/messagesview.h +++ b/src/gui/messagesview.h @@ -20,7 +20,6 @@ #include "core/messagesmodel.h" -#include "core/feedsselection.h" #include "core/rootitem.h" #include @@ -58,7 +57,7 @@ class MessagesView : public QTreeView { void reloadSelections(bool mark_current_index_read); // Loads un-deleted messages from selected feeds. - void loadFeeds(const FeedsSelection &selection); + void loadFeeds(RootItem *item); // Message manipulators. void openSelectedSourceMessagesExternally(); diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 08ecd307d..6a2cdb5ec 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -23,6 +23,7 @@ class FeedsModel; class QAction; +class QSqlTableModel; // THIS IS the root node of the service. // NOTE: The root usually contains some core functionality of the @@ -55,6 +56,15 @@ class ServiceRoot : public RootItem { virtual void start() = 0; virtual void stop() = 0; + // This method should prepare messages for given "item" (download them maybe?) + // into predefined "Messages" table + // and then use method QSqlTableModel::setFilter(....). + // NOTE: It would be more preferable if all messages are downloaded + // right when feeds are updated. + // TODO: toto možná udělat asynchronně, zobrazit + // "loading" dialog přes view a toto zavolat, nasledně signalovat + virtual bool loadMessagesForItem(RootItem *item, QSqlTableModel *model) = 0; + // Access to feed model. FeedsModel *feedsModel() const; diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 2c274ccca..976c01369 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -40,6 +40,7 @@ #include #include #include +#include StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent) @@ -518,6 +519,27 @@ QList StandardServiceRoot::serviceMenu() { return m_serviceMenu; } +bool StandardServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *model) { + if (item->kind() == RootItemKind::Bin) { + model->setFilter(QSL("is_deleted = 1 AND is_pdeleted = 0")); + } + else { + QList children = item->getSubTreeFeeds(); + QStringList stringy_ids; + + foreach (Feed *child, children) { + stringy_ids.append(QString::number(child->id())); + } + + QString filter_clause = stringy_ids.join(QSL(", ")); + + model->setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0")).arg(filter_clause)); + qDebug("Loading messages from feeds: %s.", qPrintable(filter_clause)); + } + + return true; +} + void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { QHash assignments; assignments.insert(NO_PARENT_CATEGORY, this); diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 5cc7ab55b..75fbd12b2 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -57,6 +57,9 @@ class StandardServiceRoot : public ServiceRoot { // Return menu to be shown in "Services -> service" menu. QList serviceMenu(); + // Message stuff. + bool loadMessagesForItem(RootItem *item, QSqlTableModel *model); + // Returns all standard categories which are lying under given root node. // This does NOT include the root node even if the node is category. QHash categoriesForItem(RootItem *root); From dec5f18ad67ea310a328bd72dbdd5bab05e13928 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 19 Nov 2015 14:15:51 +0100 Subject: [PATCH 052/203] Added flags. --- src/core/messagesmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 4064fb8cf..7bd240bc6 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -162,7 +162,7 @@ void MessagesModel::setupHeaderData() { Qt::ItemFlags MessagesModel::flags(const QModelIndex &index) const { Q_UNUSED(index) - return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable; + return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemNeverHasChildren; } QVariant MessagesModel::data(int row, int column, int role) const { From a8316e2c2ad634d190c7870b4390493619f57ffc Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 19 Nov 2015 19:23:22 +0100 Subject: [PATCH 053/203] Some model shit. --- src/core/messagesmodel.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 7bd240bc6..60f64744c 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -162,7 +162,12 @@ void MessagesModel::setupHeaderData() { Qt::ItemFlags MessagesModel::flags(const QModelIndex &index) const { Q_UNUSED(index) +#if QT_VERSION >= 0x050000 return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemNeverHasChildren; +#else + + return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable; +#endif } QVariant MessagesModel::data(int row, int column, int role) const { @@ -305,9 +310,7 @@ bool MessagesModel::switchMessageImportance(int row_index) { int current_importance = data(target_index, Qt::EditRole).toInt(); // Rewrite "visible" data in the model. - bool working_change = current_importance == 1 ? - setData(target_index, 0) : - setData(target_index, 1); + bool working_change = current_importance == 1 ? setData(target_index, 0) : setData(target_index, 1); if (!working_change) { // If rewriting in the model failed, then cancel all actions. From fab7d1e8b1005dae4be81531a55b5cf3e72501db Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 20 Nov 2015 09:52:29 +0100 Subject: [PATCH 054/203] Draconic changes for messages, some methods added to interfaces, very experimental state now. --- src/core/feedsmodel.cpp | 19 +++- src/core/feedsmodel.h | 6 ++ src/core/feedsproxymodel.cpp | 26 ++++-- src/core/feedsproxymodel.h | 8 +- src/core/messagesmodel.cpp | 86 ++++++++++++------- src/core/messagesmodel.h | 11 +-- src/core/messagesproxymodel.h | 3 +- src/core/rootitem.h | 9 +- src/gui/feedmessageviewer.cpp | 8 +- src/gui/feedsview.cpp | 17 ++-- src/gui/feedsview.h | 2 - src/gui/messagesview.cpp | 6 +- src/gui/messagesview.h | 1 - src/miscellaneous/application.cpp | 3 +- src/services/abstract/serviceroot.cpp | 4 + src/services/abstract/serviceroot.h | 44 ++++++++++ src/services/standard/standardfeed.cpp | 2 +- src/services/standard/standardserviceroot.cpp | 37 ++++++++ src/services/standard/standardserviceroot.h | 6 ++ src/services/tt-rss/ttrssserviceroot.cpp | 1 - src/services/tt-rss/ttrssserviceroot.h | 16 ++++ 21 files changed, 231 insertions(+), 84 deletions(-) mode change 100644 => 100755 src/core/messagesproxymodel.h diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index e5ec5416d..28410b974 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -395,6 +395,11 @@ void FeedsModel::reloadChangedItem(RootItem *item) { reloadChangedLayout(QModelIndexList() << index_item); } +void FeedsModel::onItemDataChanged(RootItem *item) { + reloadChangedItem(item); + notifyWithCounts(); +} + QStringList FeedsModel::textualFeedIds(const QList &feeds) { QStringList stringy_ids; stringy_ids.reserve(feeds.size()); @@ -411,6 +416,17 @@ void FeedsModel::reloadWholeLayout() { emit layoutChanged(); } +bool FeedsModel::addServiceAccount(ServiceRoot *root) { + m_rootItem->appendChild(root); + + // Connect. + connect(root, SIGNAL(readFeedsFilterInvalidationRequested()), this, SIGNAL(readFeedsFilterInvalidationRequested())); + connect(root, SIGNAL(dataChanged(RootItem*)), this, SLOT(onItemDataChanged(RootItem*))); + + root->start(); + return true; +} + void FeedsModel::loadActivatedServiceAccounts() { // Iterate all globally available feed "service plugins". foreach (ServiceEntryPoint *entry_point, qApp->feedServices()) { @@ -418,8 +434,7 @@ void FeedsModel::loadActivatedServiceAccounts() { QList roots = entry_point->initializeSubtree(this); foreach (ServiceRoot *root, roots) { - m_rootItem->appendChild(root); - root->start(); + addServiceAccount(root); } } } diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 48d612b39..8e6adc4ee 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -130,6 +130,8 @@ class FeedsModel : public QAbstractItemModel { // Does necessary job before quitting this component. void quit(); + bool addServiceAccount(ServiceRoot *root); + public slots: // Feeds operations. bool markItemRead(RootItem *item, RootItem::ReadStatus read); @@ -154,10 +156,14 @@ class FeedsModel : public QAbstractItemModel { } private slots: + void onItemDataChanged(RootItem *item); + // Is executed when next auto-update round could be done. void executeNextAutoUpdate(); signals: + void readFeedsFilterInvalidationRequested(); + // Emitted when model requests update of some feeds. void feedsUpdateRequested(const QList feeds); diff --git a/src/core/feedsproxymodel.cpp b/src/core/feedsproxymodel.cpp index d2b6fbd9f..a2dd06225 100755 --- a/src/core/feedsproxymodel.cpp +++ b/src/core/feedsproxymodel.cpp @@ -24,6 +24,8 @@ #include "services/standard/standardcategory.h" #include "services/standard/standardfeed.h" +#include + FeedsProxyModel::FeedsProxyModel(QObject *parent) : QSortFilterProxyModel(parent), m_selectedItem(NULL), m_showUnreadOnly(false) { @@ -37,6 +39,8 @@ FeedsProxyModel::FeedsProxyModel(QObject *parent) setFilterRole(Qt::EditRole); setDynamicSortFilter(false); setSourceModel(m_sourceModel); + + connect(m_sourceModel, SIGNAL(readFeedsFilterInvalidationRequested()), this, SLOT(invalidateReadFeedsFilter())); } FeedsProxyModel::~FeedsProxyModel() { @@ -45,18 +49,18 @@ FeedsProxyModel::~FeedsProxyModel() { QModelIndexList FeedsProxyModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const { QModelIndexList result; - uint matchType = flags & 0x0F; + uint match_type = flags & 0x0F; Qt::CaseSensitivity cs = Qt::CaseInsensitive; bool recurse = flags & Qt::MatchRecursive; bool wrap = flags & Qt::MatchWrap; - bool allHits = (hits == -1); + bool all_hits = (hits == -1); QString entered_text; QModelIndex p = parent(start); int from = start.row(); int to = rowCount(p); for (int i = 0; (wrap && i < 2) || (!wrap && i < 1); ++i) { - for (int r = from; (r < to) && (allHits || result.count() < hits); ++r) { + for (int r = from; (r < to) && (all_hits || result.count() < hits); ++r) { QModelIndex idx = index(r, start.column(), p); if (!idx.isValid()) { @@ -64,10 +68,10 @@ QModelIndexList FeedsProxyModel::match(const QModelIndex &start, int role, const } QModelIndex mapped_idx = mapToSource(idx); - QVariant item_value = m_sourceModel->data(m_sourceModel->index(mapped_idx.row(), FDS_MODEL_TITLE_INDEX, mapped_idx.parent()), role); + QVariant item_value = m_sourceModel->itemForIndex(mapped_idx)->title(); // QVariant based matching. - if (matchType == Qt::MatchExactly) { + if (match_type == Qt::MatchExactly) { if (value == item_value) { result.append(idx); } @@ -80,7 +84,7 @@ QModelIndexList FeedsProxyModel::match(const QModelIndex &start, int role, const QString item_text = item_value.toString(); - switch (matchType) { + switch (match_type) { case Qt::MatchRegExp: if (QRegExp(entered_text, cs).exactMatch(item_text)) { result.append(idx); @@ -121,7 +125,7 @@ QModelIndexList FeedsProxyModel::match(const QModelIndex &start, int role, const } if (recurse && hasChildren(idx)) { - result += match(index(0, idx.column(), idx), role, (entered_text.isEmpty() ? value : entered_text), (allHits ? -1 : hits - result.count()), flags); + result += match(index(0, idx.column(), idx), role, (entered_text.isEmpty() ? value : entered_text), (all_hits ? -1 : hits - result.count()), flags); } } @@ -218,6 +222,14 @@ bool FeedsProxyModel::showUnreadOnly() const { return m_showUnreadOnly; } +void FeedsProxyModel::invalidateReadFeedsFilter(bool set_new_value, bool show_unread_only) { + if (set_new_value) { + setShowUnreadOnly(show_unread_only); + } + + QTimer::singleShot(0, this, SLOT(invalidateFilter())); +} + void FeedsProxyModel::setShowUnreadOnly(bool show_unread_only) { m_showUnreadOnly = show_unread_only; qApp->settings()->setValue(GROUP(Feeds), Feeds::ShowOnlyUnreadFeeds, show_unread_only); diff --git a/src/core/feedsproxymodel.h b/src/core/feedsproxymodel.h index aa000b94b..b8c1a6fef 100755 --- a/src/core/feedsproxymodel.h +++ b/src/core/feedsproxymodel.h @@ -38,6 +38,8 @@ class FeedsProxyModel : public QSortFilterProxyModel { return m_sourceModel; } + // Returns index list of items which "match" given value. + // Used for finding items according to entered title text. QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const; // Maps list of indexes. @@ -50,14 +52,16 @@ class FeedsProxyModel : public QSortFilterProxyModel { void setSelectedItem(RootItem *selected_item); public slots: + void invalidateReadFeedsFilter(bool set_new_value = false, bool show_unread_only = false); + + private slots: void invalidateFilter(); - protected: + private: // Compares two rows of data. bool lessThan(const QModelIndex &left, const QModelIndex &right) const; bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; - private: // Source model pointer. FeedsModel *m_sourceModel; diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 60f64744c..1462aaea6 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -240,13 +240,20 @@ QVariant MessagesModel::data(const QModelIndex &idx, int role) const { } } -bool MessagesModel::setMessageRead(int row_index, int read) { +bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) { if (data(row_index, MSG_DB_READ_INDEX, Qt::EditRole).toInt() == read) { // Read status is the same is the one currently set. // In that case, no extra work is needed. return true; } + int message_id = messageId(row_index); + + if (!m_selectedItem->getParentServiceRoot()->onBeforeSetMessagesRead(m_selectedItem, QList() << message_id, read)) { + // Cannot change read status of the item. Abort. + return false; + } + QSqlDatabase db_handle = database(); if (!db_handle.transaction()) { @@ -265,7 +272,6 @@ bool MessagesModel::setMessageRead(int row_index, int read) { return false; } - int message_id; QSqlQuery query_read_msg(db_handle); query_read_msg.setForwardOnly(true); @@ -276,22 +282,15 @@ bool MessagesModel::setMessageRead(int row_index, int read) { return false; } - // Rewrite the actual data in the database itself. - message_id = messageId(row_index); query_read_msg.bindValue(QSL(":id"), message_id); query_read_msg.bindValue(QSL(":read"), read); query_read_msg.exec(); // Commit changes. if (db_handle.commit()) { - // If commit succeeded, then emit changes, so that view - // can reflect. + // If commit succeeded, then emit changes, so that view can reflect. emit dataChanged(index(row_index, 0), index(row_index, columnCount() - 1)); - emit messageCountsChanged(); - - // TODO: counts changed - //emit messageCountsChanged(m_selectedItem.mode(), false, false); - return true; + return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, QList() << message_id, read); } else { return db_handle.rollback();; @@ -299,6 +298,16 @@ bool MessagesModel::setMessageRead(int row_index, int read) { } bool MessagesModel::switchMessageImportance(int row_index) { + QModelIndex target_index = index(row_index, MSG_DB_IMPORTANT_INDEX); + RootItem::Importance current_importance = (RootItem::Importance) data(target_index, Qt::EditRole).toInt(); + int message_id = messageId(row_index); + + if (!m_selectedItem->getParentServiceRoot()->onBeforeSwitchMessageImportance(m_selectedItem, + message_id, + current_importance)) { + return false; + } + QSqlDatabase db_handle = database(); if (!db_handle.transaction()) { @@ -306,11 +315,10 @@ bool MessagesModel::switchMessageImportance(int row_index) { return false; } - QModelIndex target_index = index(row_index, MSG_DB_IMPORTANT_INDEX); - int current_importance = data(target_index, Qt::EditRole).toInt(); - // Rewrite "visible" data in the model. - bool working_change = current_importance == 1 ? setData(target_index, 0) : setData(target_index, 1); + bool working_change = current_importance == RootItem::Important ? + setData(target_index, RootItem::NotImportant) : + setData(target_index, RootItem::Important); if (!working_change) { // If rewriting in the model failed, then cancel all actions. @@ -320,7 +328,6 @@ bool MessagesModel::switchMessageImportance(int row_index) { return false; } - int message_id; QSqlQuery query_importance_msg(db_handle); query_importance_msg.setForwardOnly(true); @@ -331,7 +338,6 @@ bool MessagesModel::switchMessageImportance(int row_index) { return false; } - message_id = messageId(row_index); query_importance_msg.bindValue(QSL(":id"), message_id); query_importance_msg.bindValue(QSL(":important"), current_importance == 1 ? 0 : 1); query_importance_msg.exec(); @@ -341,7 +347,8 @@ bool MessagesModel::switchMessageImportance(int row_index) { // If commit succeeded, then emit changes, so that view // can reflect. emit dataChanged(index(row_index, 0), index(row_index, columnCount() - 1)); - return true; + return m_selectedItem->getParentServiceRoot()->onAfterSwitchMessageImportance(m_selectedItem, message_id, + current_importance); } else { return db_handle.rollback(); @@ -352,12 +359,16 @@ bool MessagesModel::switchBatchMessageImportance(const QModelIndexList &messages QSqlDatabase db_handle = database(); QSqlQuery query_read_msg(db_handle); QStringList message_ids; + QList message_ids_num; query_read_msg.setForwardOnly(true); // Obtain IDs of all desired messages. foreach (const QModelIndex &message, messages) { - message_ids.append(QString::number(messageId(message.row()))); + int message_id = messageId(message.row()); + + message_ids_num.append(message_id); + message_ids.append(QString::number(message_id)); } if (query_read_msg.exec(QString(QSL("UPDATE Messages SET is_important = NOT is_important WHERE id IN (%1);")) @@ -376,12 +387,16 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int QSqlDatabase db_handle = database(); QSqlQuery query_read_msg(db_handle); QStringList message_ids; + QList message_ids_num; query_read_msg.setForwardOnly(true); // Obtain IDs of all desired messages. foreach (const QModelIndex &message, messages) { - message_ids.append(QString::number(messageId(message.row()))); + int message_id = messageId(message.row()); + + message_ids_num.append(message_id); + message_ids.append(QString::number(message_id)); } QString sql_delete_query; @@ -400,7 +415,9 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int if (query_read_msg.exec(sql_delete_query)) { fetchAllData(); - emit messageCountsChanged(); + + + //emit messageCountsChanged(); // TODO: counts changed //emit messageCountsChanged(m_selectedItem.mode(), true, false); @@ -412,27 +429,32 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int } bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootItem::ReadStatus read) { - QSqlDatabase db_handle = database(); - QSqlQuery query_read_msg(db_handle); QStringList message_ids; - - query_read_msg.setForwardOnly(true); + QList message_ids_num; // Obtain IDs of all desired messages. foreach (const QModelIndex &message, messages) { - message_ids.append(QString::number(messageId(message.row()))); + int message_id = messageId(message.row()); + + message_ids_num.append(message_id); + message_ids.append(QString::number(message_id)); } + if (!m_selectedItem->getParentServiceRoot()->onBeforeSetMessagesRead(m_selectedItem, message_ids_num, read)) { + return false; + } + + QSqlDatabase db_handle = database(); + QSqlQuery query_read_msg(db_handle); + + query_read_msg.setForwardOnly(true); + if (query_read_msg.exec(QString(QSL("UPDATE Messages SET is_read = %2 WHERE id IN (%1);")) .arg(message_ids.join(QSL(", ")), read == RootItem::Read ? QSL("1") : QSL("0")))) { fetchAllData(); - emit messageCountsChanged(); - - // TODO: counts changed - //emit messageCountsChanged(m_selectedItem.mode(), false, false); - return true; + return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, message_ids_num, read); } else { return false; @@ -456,7 +478,7 @@ bool MessagesModel::setBatchMessagesRestored(const QModelIndexList &messages) { if (query_read_msg.exec(sql_delete_query)) { fetchAllData(); - emit messageCountsChanged(); + //emit messageCountsChanged(); // TODO: counts changed //emit messageCountsChanged(m_selectedItem.mode(), true, true); diff --git a/src/core/messagesmodel.h b/src/core/messagesmodel.h index f966a9bb2..a56c6d20c 100755 --- a/src/core/messagesmodel.h +++ b/src/core/messagesmodel.h @@ -62,7 +62,7 @@ class MessagesModel : public QSqlTableModel { // NOTE: Model is NOT reset after one of these methods are applied // but changes ARE written to the database. bool switchMessageImportance(int row_index); - bool setMessageRead(int row_index, int read); + bool setMessageRead(int row_index, RootItem::ReadStatus read); // BATCH messages manipulators. // NOTE: These methods are used for changing of attributes of @@ -83,22 +83,13 @@ class MessagesModel : public QSqlTableModel { // Loads messages of given feeds. void loadMessages(RootItem *item); - signals: - // Emitted if some persistent change is made which affects count of "unread/all" messages. - void messageCountsChanged(); - private slots: // To disable persistent changes submissions. bool submitAll(); private: - // Sets up header data. void setupHeaderData(); - - // Creates "normal" and "bold" fonts. void setupFonts(); - - // Sets up all icons which are used directly by this model. void setupIcons(); MessageHighlighter m_messageHighlighter; diff --git a/src/core/messagesproxymodel.h b/src/core/messagesproxymodel.h old mode 100644 new mode 100755 index 35d7cef64..2b81ea652 --- a/src/core/messagesproxymodel.h +++ b/src/core/messagesproxymodel.h @@ -43,11 +43,10 @@ class MessagesProxyModel : public QSortFilterProxyModel { // Fix for matching indexes with respect to specifics of the message model. QModelIndexList match(const QModelIndex &start, int role, const QVariant &entered_value, int hits, Qt::MatchFlags flags) const; - protected: + private: // Compares two rows of data. bool lessThan(const QModelIndex &left, const QModelIndex &right) const; - private: // Source model pointer. MessagesModel *m_sourceModel; }; diff --git a/src/core/rootitem.h b/src/core/rootitem.h index d16f3a08a..0f36a8d6e 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -51,8 +51,13 @@ class RootItem : public QObject { public: enum ReadStatus { - Read, - Unread + Unread = 0, + Read = 1 + }; + + enum Importance { + NotImportant = 0, + Important = 1 }; enum CleanStatus { diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 25bd3c04f..55809c6fe 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -25,6 +25,7 @@ #include "miscellaneous/databasecleaner.h" #include "core/messagesproxymodel.h" #include "core/feeddownloader.h" +#include "core/feedsproxymodel.h" #include "services/standard/standardserviceroot.h" #include "services/standard/standardfeed.h" #include "services/standard/standardfeedsimportexportmodel.h" @@ -260,10 +261,10 @@ void FeedMessageViewer::toggleShowOnlyUnreadFeeds() { QAction *origin = qobject_cast(sender()); if (origin == NULL) { - m_feedsView->invalidateReadFeedsFilter(true, false); + m_feedsView->model()->invalidateReadFeedsFilter(true, false); } else { - m_feedsView->invalidateReadFeedsFilter(true, origin->isChecked()); + m_feedsView->model()->invalidateReadFeedsFilter(true, origin->isChecked()); } } @@ -328,8 +329,7 @@ void FeedMessageViewer::createConnections() { connect(m_feedsView, SIGNAL(itemSelected(RootItem*)), m_messagesView, SLOT(loadFeeds(RootItem*))); // If user changes status of some messages, recalculate message counts. - connect(m_messagesView->sourceModel(), SIGNAL(messageCountsChanged()), - m_feedsView, SLOT(receiveMessageCountsChange())); + connect(m_messagesView->sourceModel(), SIGNAL(messageCountsChanged()), m_feedsView, SLOT(receiveMessageCountsChange())); // State of many messages is changed, then we need // to reload selections. diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index a0f473c1d..a9da540bc 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -139,14 +139,6 @@ void FeedsView::loadExpandedStates() { } } -void FeedsView::invalidateReadFeedsFilter(bool set_new_value, bool show_unread_only) { - if (set_new_value) { - m_proxyModel->setShowUnreadOnly(show_unread_only); - } - - QTimer::singleShot(0, m_proxyModel, SLOT(invalidateFilter())); -} - void FeedsView::expandCollapseCurrentItem() { if (selectionModel()->selectedRows().size() == 1) { QModelIndex index = selectionModel()->selectedRows().at(0); @@ -210,7 +202,8 @@ void FeedsView::receiveMessageCountsChange() { // total counts. // b) total count of message was not changed - some messages switched state --> we need to update // counts of just selected feeds. - /*if (mode == FeedsSelection::MessagesFromRecycleBin) { + /* + if (mode == FeedsSelection::MessagesFromRecycleBin) { if (total_msg_count_changed) { if (any_msg_restored) { updateCountsOfAllFeeds(true); @@ -227,7 +220,7 @@ void FeedsView::receiveMessageCountsChange() { updateCountsOfSelectedFeeds(total_msg_count_changed); }*/ - invalidateReadFeedsFilter(); + m_proxyModel->invalidateReadFeedsFilter(); } void FeedsView::editSelectedItem() { @@ -442,7 +435,7 @@ void FeedsView::updateCountsOfParticularFeed(Feed *feed, bool update_total_too) m_sourceModel->reloadChangedLayout(QModelIndexList() << index); } - invalidateReadFeedsFilter(); + m_proxyModel->invalidateReadFeedsFilter(); m_sourceModel->notifyWithCounts(); } @@ -586,7 +579,7 @@ void FeedsView::selectionChanged(const QItemSelection &selected, const QItemSele m_proxyModel->setSelectedItem(selected_item); QTreeView::selectionChanged(selected, deselected); emit itemSelected(selected_item); - invalidateReadFeedsFilter(); + m_proxyModel->invalidateReadFeedsFilter(); } void FeedsView::keyPressEvent(QKeyEvent *event) { diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index 13b2e6878..bcda5a42c 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -28,7 +28,6 @@ class FeedsProxyModel; class Feed; class Category; -class QTimer; class FeedsView : public QTreeView { Q_OBJECT @@ -65,7 +64,6 @@ class FeedsView : public QTreeView { void loadExpandedStates(); public slots: - void invalidateReadFeedsFilter(bool set_new_value = false, bool show_unread_only = false); void expandCollapseCurrentItem(); // Feed updating. diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index 1c224b7d7..64c83b451 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -192,10 +192,6 @@ void MessagesView::mousePressEvent(QMouseEvent *event) { } } -void MessagesView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) { - QTreeView::currentChanged(current, previous); -} - void MessagesView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { QModelIndexList selected_rows = selectionModel()->selectedRows(); QModelIndex current_index = currentIndex(); @@ -209,7 +205,7 @@ void MessagesView::selectionChanged(const QItemSelection &selected, const QItemS if (!m_batchUnreadSwitch) { // Set this message as read only if current item // wasn't changed by "mark selected messages unread" action. - m_sourceModel->setMessageRead(mapped_current_index.row(), 1); + m_sourceModel->setMessageRead(mapped_current_index.row(), RootItem::Read); } emit currentMessagesChanged(QList() << m_sourceModel->messageAt(m_proxyModel->mapToSource(selected_rows.at(0)).row())); diff --git a/src/gui/messagesview.h b/src/gui/messagesview.h index ca94e4f83..e2d854132 100755 --- a/src/gui/messagesview.h +++ b/src/gui/messagesview.h @@ -114,7 +114,6 @@ class MessagesView : public QTreeView { void contextMenuEvent(QContextMenuEvent *event); void mousePressEvent(QMouseEvent *event); void keyPressEvent(QKeyEvent *event); - void currentChanged(const QModelIndex ¤t, const QModelIndex &previous); void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); QMenu *m_contextMenu; diff --git a/src/miscellaneous/application.cpp b/src/miscellaneous/application.cpp index b47449d5b..495d06042 100755 --- a/src/miscellaneous/application.cpp +++ b/src/miscellaneous/application.cpp @@ -170,7 +170,8 @@ void Application::processExecutionMessage(const QString &message) { SystemTrayIcon *Application::trayIcon() { if (m_trayIcon == NULL) { m_trayIcon = new SystemTrayIcon(APP_ICON_PATH, APP_ICON_PLAIN_PATH, m_mainForm); - connect(m_trayIcon, SIGNAL(shown()), m_mainForm->tabWidget()->feedMessageViewer()->feedsView(), SLOT(notifyWithCounts())); + connect(m_trayIcon, SIGNAL(shown()), + m_mainForm->tabWidget()->feedMessageViewer()->feedsView()->sourceModel(), SLOT(notifyWithCounts())); } return m_trayIcon; diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index 516331c7d..31b710841 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -30,3 +30,7 @@ ServiceRoot::~ServiceRoot() { FeedsModel *ServiceRoot::feedsModel() const { return m_feedsModel; } + +void ServiceRoot::itemChanged(RootItem *item) { + emit dataChanged(item); +} diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 6a2cdb5ec..1829cffcc 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -20,6 +20,8 @@ #include "core/rootitem.h" +#include "core/message.h" + class FeedsModel; class QAction; @@ -65,9 +67,51 @@ class ServiceRoot : public RootItem { // "loading" dialog přes view a toto zavolat, nasledně signalovat virtual bool loadMessagesForItem(RootItem *item, QSqlTableModel *model) = 0; + // Called BEFORE this read status update is stored in DB, + // when false is returned, change is aborted. + // This is the place to make some other changes like updating + // some ONLINE service or something. + // + // "read" is status which is ABOUT TO BE SET. + virtual bool onBeforeSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read) = 0; + + // Called AFTER this read status update is stored in DB, + // when false is returned, change is aborted. + // Here service root should inform (via signals) + // which items are actually changed. + // + // "read" is status which is ABOUT TO BE SET. + virtual bool onAfterSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read) = 0; + + // Called BEFORE this importance switch update is stored in DB, + // when false is returned, change is aborted. + // This is the place to make some other changes like updating + // some ONLINE service or something. + // + // "important" is status which is ABOUT TO BE SET. + virtual bool onBeforeSwitchMessageImportance(RootItem *selected_item, int message_db_id, Importance important) = 0; + + // Called AFTER this importance switch update is stored in DB, + // when false is returned, change is aborted. + // Here service root should inform (via signals) + // which items are actually changed. + // + // "important" is status which is ABOUT TO BE SET. + virtual bool onAfterSwitchMessageImportance(RootItem *selected_item, int message_db_id, Importance important) = 0; + // Access to feed model. FeedsModel *feedsModel() const; + // Obvious method to wrap dataChanged(...) signal + // which can be used by items themselves or any + // other component. + void itemChanged(RootItem *item); + + signals: + // Emitted if data in any item belonging to this root are changed. + void dataChanged(RootItem *item); + void readFeedsFilterInvalidationRequested(); + private: FeedsModel *m_feedsModel; }; diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 8dbd7a42f..844bb8d67 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -215,7 +215,7 @@ void StandardFeed::fetchMetadataForItself() { // Notify the model about fact, that it needs to reload new information about // this item, particularly the icon. - serviceRoot()->feedsModel()->reloadChangedItem(this); + serviceRoot()->itemChanged(this); } else { qApp->showGuiMessage(tr("Metadata not fetched"), diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 976c01369..b84bbf54f 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -540,6 +540,43 @@ bool StandardServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *mo return true; } +bool StandardServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, QList message_db_ids, RootItem::ReadStatus read) { + Q_UNUSED(message_db_ids) + Q_UNUSED(read) + Q_UNUSED(selected_item) + + return true; +} + +bool StandardServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, QList message_db_ids, RootItem::ReadStatus read) { + Q_UNUSED(message_db_ids) + Q_UNUSED(read) + + selected_item->updateCounts(false); + + emit dataChanged(selected_item); + emit readFeedsFilterInvalidationRequested(); + return true; +} + +bool StandardServiceRoot::onBeforeSwitchMessageImportance(RootItem *selected_item, int message_db_id, + RootItem::Importance important) { + Q_UNUSED(message_db_id) + Q_UNUSED(important) + Q_UNUSED(selected_item) + + return true; +} + +bool StandardServiceRoot::onAfterSwitchMessageImportance(RootItem *selected_item, int message_db_id, + RootItem::Importance important) { + Q_UNUSED(message_db_id) + Q_UNUSED(important) + Q_UNUSED(selected_item) + + return true; +} + void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { QHash assignments; assignments.insert(NO_PARENT_CATEGORY, this); diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 75fbd12b2..52ead9463 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -60,6 +60,12 @@ class StandardServiceRoot : public ServiceRoot { // Message stuff. bool loadMessagesForItem(RootItem *item, QSqlTableModel *model); + bool onBeforeSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read); + bool onAfterSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read); + + bool onBeforeSwitchMessageImportance(RootItem *selected_item, int message_db_id, Importance important); + bool onAfterSwitchMessageImportance(RootItem *selected_item, int message_db_id, Importance important); + // Returns all standard categories which are lying under given root node. // This does NOT include the root node even if the node is category. QHash categoriesForItem(RootItem *root); diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index e5a9b51a1..8efae22ec 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -64,4 +64,3 @@ QVariant TtRssServiceRoot::data(int column, int role) const { return ServiceRoot::data(column, role); } } - diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 957517850..61749c1e3 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -36,6 +36,22 @@ class TtRssServiceRoot : public ServiceRoot { bool canBeDeleted(); bool editViaGui(); QVariant data(int column, int role) const; + + bool onBeforeSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read) { + return false; + } + + bool onAfterSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read) { + return false; + } + + bool onBeforeSwitchMessageImportance(RootItem *selected_item, int message_db_id, Importance important) { + return false; + } + + bool onAfterSwitchMessageImportance(RootItem *selected_item, int message_db_id, Importance important) { + return false; + } }; #endif // TTRSSSERVICEROOT_H From 63549108820dffc655bf34e9cca6bb91bdf29557 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 20 Nov 2015 10:33:38 +0100 Subject: [PATCH 055/203] Heavy work on messages model, switching of importance. --- src/core/messagesmodel.cpp | 78 +++++++------------ src/core/messagesmodel.h | 1 + src/gui/messagesview.cpp | 2 + src/services/abstract/serviceroot.h | 8 +- src/services/standard/standardserviceroot.cpp | 14 ++-- src/services/standard/standardserviceroot.h | 4 +- src/services/tt-rss/ttrssserviceroot.h | 4 +- 7 files changed, 45 insertions(+), 66 deletions(-) diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 1462aaea6..ca1549a87 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -106,6 +106,10 @@ int MessagesModel::messageId(int row_index) const { return data(row_index, MSG_DB_ID_INDEX, Qt::EditRole).toInt(); } +RootItem::Importance MessagesModel::messageImportance(int row_index) const { + return (RootItem::Importance) data(row_index, MSG_DB_IMPORTANT_INDEX, Qt::EditRole).toInt(); +} + void MessagesModel::updateDateFormat() { if (qApp->settings()->value(GROUP(Messages), SETTING(Messages::UseCustomDate)).toBool()) { m_customDateFormat = qApp->settings()->value(GROUP(Messages), SETTING(Messages::CustomDateFormat)).toString(); @@ -254,104 +258,75 @@ bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) { return false; } - QSqlDatabase db_handle = database(); - - if (!db_handle.transaction()) { - qWarning("Starting transaction for message read change."); - return false; - } - // Rewrite "visible" data in the model. bool working_change = setData(index(row_index, MSG_DB_READ_INDEX), read); if (!working_change) { // If rewriting in the model failed, then cancel all actions. qDebug("Setting of new data to the model failed for message read change."); - - db_handle.rollback(); return false; } - QSqlQuery query_read_msg(db_handle); + QSqlQuery query_read_msg(database()); query_read_msg.setForwardOnly(true); if (!query_read_msg.prepare(QSL("UPDATE Messages SET is_read = :read WHERE id = :id;"))) { qWarning("Query preparation failed for message read change."); - - db_handle.rollback(); return false; } query_read_msg.bindValue(QSL(":id"), message_id); - query_read_msg.bindValue(QSL(":read"), read); - query_read_msg.exec(); + query_read_msg.bindValue(QSL(":read"), (int) read); - // Commit changes. - if (db_handle.commit()) { - // If commit succeeded, then emit changes, so that view can reflect. - emit dataChanged(index(row_index, 0), index(row_index, columnCount() - 1)); + if (query_read_msg.exec()) { return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, QList() << message_id, read); } else { - return db_handle.rollback();; + return false; } } bool MessagesModel::switchMessageImportance(int row_index) { QModelIndex target_index = index(row_index, MSG_DB_IMPORTANT_INDEX); RootItem::Importance current_importance = (RootItem::Importance) data(target_index, Qt::EditRole).toInt(); + RootItem::Importance next_importance = current_importance == RootItem::Important ? + RootItem::NotImportant : RootItem::Important; int message_id = messageId(row_index); + QPair pair(message_id, next_importance); if (!m_selectedItem->getParentServiceRoot()->onBeforeSwitchMessageImportance(m_selectedItem, - message_id, - current_importance)) { - return false; - } - - QSqlDatabase db_handle = database(); - - if (!db_handle.transaction()) { - qWarning("Starting transaction for message importance switch failed."); + QList >() << pair)) { return false; } // Rewrite "visible" data in the model. - bool working_change = current_importance == RootItem::Important ? - setData(target_index, RootItem::NotImportant) : - setData(target_index, RootItem::Important); + bool working_change = setData(target_index, next_importance); if (!working_change) { // If rewriting in the model failed, then cancel all actions. qDebug("Setting of new data to the model failed for message importance change."); - - db_handle.rollback(); return false; } - QSqlQuery query_importance_msg(db_handle); + QSqlQuery query_importance_msg(database()); query_importance_msg.setForwardOnly(true); if (!query_importance_msg.prepare(QSL("UPDATE Messages SET is_important = :important WHERE id = :id;"))) { qWarning("Query preparation failed for message importance switch."); - - db_handle.rollback(); return false; } query_importance_msg.bindValue(QSL(":id"), message_id); - query_importance_msg.bindValue(QSL(":important"), current_importance == 1 ? 0 : 1); - query_importance_msg.exec(); + query_importance_msg.bindValue(QSL(":important"), (int) next_importance); + // Commit changes. - if (db_handle.commit()) { - // If commit succeeded, then emit changes, so that view - // can reflect. - emit dataChanged(index(row_index, 0), index(row_index, columnCount() - 1)); - return m_selectedItem->getParentServiceRoot()->onAfterSwitchMessageImportance(m_selectedItem, message_id, - current_importance); + if (query_importance_msg.exec()) { + return m_selectedItem->getParentServiceRoot()->onAfterSwitchMessageImportance(m_selectedItem, + QList >() << pair); } else { - return db_handle.rollback(); + return false; } } @@ -359,24 +334,27 @@ bool MessagesModel::switchBatchMessageImportance(const QModelIndexList &messages QSqlDatabase db_handle = database(); QSqlQuery query_read_msg(db_handle); QStringList message_ids; - QList message_ids_num; + QList > message_states; query_read_msg.setForwardOnly(true); // Obtain IDs of all desired messages. foreach (const QModelIndex &message, messages) { int message_id = messageId(message.row()); + RootItem::Importance message_importance = messageImportance((message.row())); - message_ids_num.append(message_id); + message_states.append(QPair(message_id, message_importance)); message_ids.append(QString::number(message_id)); } + if (!m_selectedItem->getParentServiceRoot()->onBeforeSwitchMessageImportance(m_selectedItem, message_states)) { + return false; + } + if (query_read_msg.exec(QString(QSL("UPDATE Messages SET is_important = NOT is_important WHERE id IN (%1);")) .arg(message_ids.join(QSL(", "))))) { fetchAllData(); - - //emit messageCountsChanged(false); - return true; + return m_selectedItem->getParentServiceRoot()->onAfterSwitchMessageImportance(m_selectedItem, message_states); } else { return false; diff --git a/src/core/messagesmodel.h b/src/core/messagesmodel.h index a56c6d20c..4f8f9871c 100755 --- a/src/core/messagesmodel.h +++ b/src/core/messagesmodel.h @@ -53,6 +53,7 @@ class MessagesModel : public QSqlTableModel { // Returns message at given index. Message messageAt(int row_index) const; int messageId(int row_index) const; + RootItem::Importance messageImportance(int row_index) const; void updateDateFormat(); void reloadWholeLayout(); diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index 64c83b451..39e1bcbdd 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -398,9 +398,11 @@ void MessagesView::switchSelectedMessagesImportance() { current_index = m_proxyModel->mapFromSource(m_sourceModel->index(mapped_current_index.row(), mapped_current_index.column())); + m_batchUnreadSwitch = true; setCurrentIndex(current_index); scrollTo(current_index); reselectIndexes(selected_indexes); + m_batchUnreadSwitch = false; } void MessagesView::reselectIndexes(const QModelIndexList &indexes) { diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 1829cffcc..67144f59b 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -88,16 +88,16 @@ class ServiceRoot : public RootItem { // This is the place to make some other changes like updating // some ONLINE service or something. // - // "important" is status which is ABOUT TO BE SET. - virtual bool onBeforeSwitchMessageImportance(RootItem *selected_item, int message_db_id, Importance important) = 0; + // "changes" - list of pairs - + virtual bool onBeforeSwitchMessageImportance(RootItem *selected_item, QList > changes) = 0; // Called AFTER this importance switch update is stored in DB, // when false is returned, change is aborted. // Here service root should inform (via signals) // which items are actually changed. // - // "important" is status which is ABOUT TO BE SET. - virtual bool onAfterSwitchMessageImportance(RootItem *selected_item, int message_db_id, Importance important) = 0; + // "changes" - list of pairs - + virtual bool onAfterSwitchMessageImportance(RootItem *selected_item, QList > changes) = 0; // Access to feed model. FeedsModel *feedsModel() const; diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index b84bbf54f..1219de7ca 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -559,20 +559,18 @@ bool StandardServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, QList< return true; } -bool StandardServiceRoot::onBeforeSwitchMessageImportance(RootItem *selected_item, int message_db_id, - RootItem::Importance important) { - Q_UNUSED(message_db_id) - Q_UNUSED(important) +bool StandardServiceRoot::onBeforeSwitchMessageImportance(RootItem *selected_item, + QList > changes) { Q_UNUSED(selected_item) + Q_UNUSED(changes) return true; } -bool StandardServiceRoot::onAfterSwitchMessageImportance(RootItem *selected_item, int message_db_id, - RootItem::Importance important) { - Q_UNUSED(message_db_id) - Q_UNUSED(important) +bool StandardServiceRoot::onAfterSwitchMessageImportance(RootItem *selected_item, + QList > changes) { Q_UNUSED(selected_item) + Q_UNUSED(changes) return true; } diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 52ead9463..93d25c864 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -63,8 +63,8 @@ class StandardServiceRoot : public ServiceRoot { bool onBeforeSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read); bool onAfterSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read); - bool onBeforeSwitchMessageImportance(RootItem *selected_item, int message_db_id, Importance important); - bool onAfterSwitchMessageImportance(RootItem *selected_item, int message_db_id, Importance important); + bool onBeforeSwitchMessageImportance(RootItem *selected_item, QList > changes); + bool onAfterSwitchMessageImportance(RootItem *selected_item, QList > changes); // Returns all standard categories which are lying under given root node. // This does NOT include the root node even if the node is category. diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 61749c1e3..130d519d2 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -45,11 +45,11 @@ class TtRssServiceRoot : public ServiceRoot { return false; } - bool onBeforeSwitchMessageImportance(RootItem *selected_item, int message_db_id, Importance important) { + bool onBeforeSwitchMessageImportance(RootItem *selected_item, QList > changes) { return false; } - bool onAfterSwitchMessageImportance(RootItem *selected_item, int message_db_id, Importance important) { + bool onAfterSwitchMessageImportance(RootItem *selected_item, QList > changes) { return false; } }; From 8c7079de264bd91ce30f9d0af29c501e261e62e1 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 20 Nov 2015 10:38:01 +0100 Subject: [PATCH 056/203] Finalize today work. --- src/core/messagesmodel.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index ca1549a87..2a5766b90 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -331,8 +331,7 @@ bool MessagesModel::switchMessageImportance(int row_index) { } bool MessagesModel::switchBatchMessageImportance(const QModelIndexList &messages) { - QSqlDatabase db_handle = database(); - QSqlQuery query_read_msg(db_handle); + QSqlQuery query_read_msg(database()); QStringList message_ids; QList > message_states; @@ -362,8 +361,7 @@ bool MessagesModel::switchBatchMessageImportance(const QModelIndexList &messages } bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int deleted) { - QSqlDatabase db_handle = database(); - QSqlQuery query_read_msg(db_handle); + QSqlQuery query_read_msg(database()); QStringList message_ids; QList message_ids_num; @@ -379,9 +377,7 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int QString sql_delete_query; - // TODO: todo - /* - if (m_selectedItem.mode() == FeedsSelection::MessagesFromFeeds) { + if (m_selectedItem->kind() != RootItemKind::Bin) { sql_delete_query = QString(QSL("UPDATE Messages SET is_deleted = %2 WHERE id IN (%1);")).arg(message_ids.join(QSL(", ")), QString::number(deleted)); } @@ -389,7 +385,6 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int sql_delete_query = QString(QSL("UPDATE Messages SET is_pdeleted = %2 WHERE id IN (%1);")).arg(message_ids.join(QSL(", ")), QString::number(deleted)); } - */ if (query_read_msg.exec(sql_delete_query)) { fetchAllData(); @@ -397,7 +392,7 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int //emit messageCountsChanged(); - // TODO: counts changed + // TODO: counts changed - zde pokracovat podle metod setbarchmessageread //emit messageCountsChanged(m_selectedItem.mode(), true, false); return true; } @@ -422,9 +417,7 @@ bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootIt return false; } - QSqlDatabase db_handle = database(); - QSqlQuery query_read_msg(db_handle); - + QSqlQuery query_read_msg(database()); query_read_msg.setForwardOnly(true); if (query_read_msg.exec(QString(QSL("UPDATE Messages SET is_read = %2 WHERE id IN (%1);")) From 68d3e0a53f8c210440179e665e9e1ceeadf758f2 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 20 Nov 2015 13:29:32 +0100 Subject: [PATCH 057/203] Big refactoring, marking read/unread, clearing now uses newer approach. --- src/core/feedsmodel.cpp | 15 +- src/core/feedsmodel.h | 4 +- src/core/messagesmodel.cpp | 18 ++- src/gui/feedmessageviewer.cpp | 6 +- src/gui/feedsview.cpp | 136 +----------------- src/gui/feedsview.h | 51 ++----- src/main.cpp | 3 + src/services/abstract/serviceroot.cpp | 4 +- src/services/abstract/serviceroot.h | 16 ++- src/services/standard/standardfeed.cpp | 6 +- src/services/standard/standardserviceroot.cpp | 75 +++++++--- src/services/standard/standardserviceroot.h | 3 + src/services/tt-rss/ttrssserviceroot.h | 8 ++ 13 files changed, 130 insertions(+), 215 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 28410b974..2976c032a 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -206,6 +206,12 @@ int FeedsModel::rowCount(const QModelIndex &parent) const { } } +void FeedsModel::reloadCountsOfWholeModel() { + m_rootItem->updateCounts(true); + reloadWholeLayout(); + notifyWithCounts(); +} + void FeedsModel::removeItem(const QModelIndex &index) { if (index.isValid()) { QModelIndex parent_index = index.parent(); @@ -395,8 +401,11 @@ void FeedsModel::reloadChangedItem(RootItem *item) { reloadChangedLayout(QModelIndexList() << index_item); } -void FeedsModel::onItemDataChanged(RootItem *item) { - reloadChangedItem(item); +void FeedsModel::onItemDataChanged(QList items) { + foreach (RootItem *item, items) { + reloadChangedItem(item); + } + notifyWithCounts(); } @@ -421,7 +430,7 @@ bool FeedsModel::addServiceAccount(ServiceRoot *root) { // Connect. connect(root, SIGNAL(readFeedsFilterInvalidationRequested()), this, SIGNAL(readFeedsFilterInvalidationRequested())); - connect(root, SIGNAL(dataChanged(RootItem*)), this, SLOT(onItemDataChanged(RootItem*))); + connect(root, SIGNAL(dataChanged(QList)), this, SLOT(onItemDataChanged(QList))); root->start(); return true; diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 8e6adc4ee..40542a10b 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -59,6 +59,8 @@ class FeedsModel : public QAbstractItemModel { return m_rootItem->countOfUnreadMessages(); } + void reloadCountsOfWholeModel(); + // Removes item with given index. // NOTE: Also deletes item from memory. void removeItem(const QModelIndex &index); @@ -156,7 +158,7 @@ class FeedsModel : public QAbstractItemModel { } private slots: - void onItemDataChanged(RootItem *item); + void onItemDataChanged(QList items); // Is executed when next auto-update round could be done. void executeNextAutoUpdate(); diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 2a5766b90..28c96b3ca 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -361,12 +361,9 @@ bool MessagesModel::switchBatchMessageImportance(const QModelIndexList &messages } bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int deleted) { - QSqlQuery query_read_msg(database()); QStringList message_ids; QList message_ids_num; - query_read_msg.setForwardOnly(true); - // Obtain IDs of all desired messages. foreach (const QModelIndex &message, messages) { int message_id = messageId(message.row()); @@ -375,8 +372,15 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int message_ids.append(QString::number(message_id)); } + if (!m_selectedItem->getParentServiceRoot()->onBeforeMessagesDelete(m_selectedItem, message_ids_num)) { + return false; + } + + QSqlQuery query_read_msg(database()); QString sql_delete_query; + query_read_msg.setForwardOnly(true); + if (m_selectedItem->kind() != RootItemKind::Bin) { sql_delete_query = QString(QSL("UPDATE Messages SET is_deleted = %2 WHERE id IN (%1);")).arg(message_ids.join(QSL(", ")), QString::number(deleted)); @@ -388,13 +392,7 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int if (query_read_msg.exec(sql_delete_query)) { fetchAllData(); - - - //emit messageCountsChanged(); - - // TODO: counts changed - zde pokracovat podle metod setbarchmessageread - //emit messageCountsChanged(m_selectedItem.mode(), true, false); - return true; + return m_selectedItem->getParentServiceRoot()->onAfterMessagesDelete(m_selectedItem, message_ids_num); } else { return false; diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 55809c6fe..b661e4c32 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -235,7 +235,6 @@ void FeedMessageViewer::onFeedUpdatesStarted() { void FeedMessageViewer::onFeedUpdatesProgress(Feed *feed, int current, int total) { // Some feed got updated. - m_feedsView->updateCountsOfParticularFeed(feed, true); qApp->mainForm()->statusBar()->showProgressFeeds((current * 100.0) / total, //: Text display in status bar when particular feed is updated. tr("Updated feed '%1'").arg(feed->title())); @@ -328,9 +327,6 @@ void FeedMessageViewer::createConnections() { // If user selects feeds, load their messages. connect(m_feedsView, SIGNAL(itemSelected(RootItem*)), m_messagesView, SLOT(loadFeeds(RootItem*))); - // If user changes status of some messages, recalculate message counts. - connect(m_messagesView->sourceModel(), SIGNAL(messageCountsChanged()), m_feedsView, SLOT(receiveMessageCountsChange())); - // State of many messages is changed, then we need // to reload selections. connect(m_feedsView, SIGNAL(feedsNeedToBeReloaded(bool)), m_messagesView, SLOT(reloadSelections(bool))); @@ -498,7 +494,7 @@ void FeedMessageViewer::showDbCleanupAssistant() { qApp->feedUpdateLock()->unlock(); m_messagesView->reloadSelections(false); - m_feedsView->updateCountsOfAllFeeds(true); + m_feedsView->sourceModel()->reloadCountsOfWholeModel(); } else { qApp->showGuiMessage(tr("Cannot cleanup database"), diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index a9da540bc..50ff62c75 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -169,60 +169,14 @@ void FeedsView::updateAllItemsOnStartup() { void FeedsView::clearSelectedFeeds() { m_sourceModel->markItemCleared(selectedItem(), false); - updateCountsOfSelectedFeeds(true); - emit feedsNeedToBeReloaded(true); } void FeedsView::clearAllFeeds() { m_sourceModel->markItemCleared(m_sourceModel->rootItem(), false); - updateCountsOfAllFeeds(true); - emit feedsNeedToBeReloaded(true); } -void FeedsView::receiveMessageCountsChange() { - - // TODO: toto vymazat, prepocitani cisel unread/all - // a upozorneni na zmenu itemu provede ten item - // zde jen nechat tu invalidaci read filteru - - // If the change came from recycle bin mode, then: - // a) total count of message was changed AND no message was restored - some messages - // were permanently deleted from recycle bin --> we need to update counts of - // just recycle bin, including total counts. - // b) total count of message was changed AND some message was restored - some messages - // were restored --> we need to update counts from all items and bin, including total counts. - // c) total count of message was not changed - state of some messages was switched, no - // deletings or restorings were made --> update counts of just recycle bin, excluding total counts. - // - // If the change came from feed mode, then: - // a) total count of message was changed - some messages were deleted --> we need to update - // counts of recycle bin, including total counts and update counts of selected feeds, including - // total counts. - // b) total count of message was not changed - some messages switched state --> we need to update - // counts of just selected feeds. - /* - if (mode == FeedsSelection::MessagesFromRecycleBin) { - if (total_msg_count_changed) { - if (any_msg_restored) { - updateCountsOfAllFeeds(true); - } - else { - updateCountsOfRecycleBin(true); - } - } - else { - updateCountsOfRecycleBin(false); - } - } - else { - updateCountsOfSelectedFeeds(total_msg_count_changed); - }*/ - - m_proxyModel->invalidateReadFeedsFilter(); -} - void FeedsView::editSelectedItem() { if (!qApp->feedUpdateLock()->tryLock()) { // Lock was not obtained because @@ -320,8 +274,6 @@ void FeedsView::deleteSelectedItem() { void FeedsView::markSelectedItemReadStatus(RootItem::ReadStatus read) { m_sourceModel->markItemRead(selectedItem(), read); - updateCountsOfSelectedFeeds(false); - emit feedsNeedToBeReloaded(read == 1); } @@ -335,8 +287,6 @@ void FeedsView::markSelectedItemsUnread() { void FeedsView::markAllItemsReadStatus(RootItem::ReadStatus read) { m_sourceModel->markItemRead(m_sourceModel->rootItem(), read); - updateCountsOfAllFeeds(false); - emit feedsNeedToBeReloaded(read == 1); } @@ -357,88 +307,6 @@ void FeedsView::openSelectedItemsInNewspaperMode() { } } -void FeedsView::emptyRecycleBin() { - if (MessageBox::show(qApp->mainForm(), QMessageBox::Question, tr("Permanently delete messages"), - tr("You are about to permanenty delete all messages from your recycle bin."), - tr("Do you really want to empty your recycle bin?"), - QString(), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) { - // TODO: pridat metodu cisteni standardniho kose nebo vsech kosu. - //m_sourceModel->recycleBin()->empty(); - updateCountsOfSelectedFeeds(true); - - emit feedsNeedToBeReloaded(true); - } -} - -void FeedsView::restoreRecycleBin() { - // TODO: pridat metodu cisteni standardniho kose nebo vsech kosu. - //m_sourceModel->recycleBin()->restore(); - updateCountsOfAllFeeds(true); - - emit feedsNeedToBeReloaded(true); -} - -void FeedsView::updateCountsOfSelectedFeeds(bool update_total_too) { - foreach (Feed *feed, selectedFeeds()) { - feed->updateCounts(update_total_too); - } - - QModelIndexList selected_indexes = m_proxyModel->mapListToSource(selectionModel()->selectedRows()); - - if (update_total_too) { - // Number of items in recycle bin has changed. - - // TODO: pridat metodu cisteni standardniho kose nebo vsech kosu. - //m_sourceModel->recycleBin()->updateCounts(true); - - // We need to refresh data for recycle bin too. - - // TODO: pridat metodu cisteni standardniho kose nebo vsech kosu. - //selected_indexes.append(m_sourceModel->indexForItem(m_sourceModel->recycleBin())); - } - - // Make sure that selected view reloads changed indexes. - m_sourceModel->reloadChangedLayout(selected_indexes); - m_sourceModel->notifyWithCounts(); -} - -void FeedsView::updateCountsOfRecycleBin(bool update_total_too) { - - // TODO: pridat metodu cisteni standardniho kose nebo vsech kosu. - //m_sourceModel->recycleBin()->updateCounts(update_total_too); - //m_sourceModel->reloadChangedLayout(QModelIndexList() << m_sourceModel->indexForItem(m_sourceModel->recycleBin())); - m_sourceModel->notifyWithCounts(); -} - -void FeedsView::updateCountsOfAllFeeds(bool update_total_too) { - foreach (Feed *feed, allFeeds()) { - feed->updateCounts(update_total_too); - } - - if (update_total_too) { - // Number of items in recycle bin has changed. - - // TODO: pridat metodu cisteni standardniho kose nebo vsech kosu. - //m_sourceModel->recycleBin()->updateCounts(true); - } - - // Make sure that all views reloads its data. - m_sourceModel->reloadWholeLayout(); - m_sourceModel->notifyWithCounts(); -} - -void FeedsView::updateCountsOfParticularFeed(Feed *feed, bool update_total_too) { - QModelIndex index = m_sourceModel->indexForItem(feed); - - if (index.isValid()) { - feed->updateCounts(update_total_too); - m_sourceModel->reloadChangedLayout(QModelIndexList() << index); - } - - m_proxyModel->invalidateReadFeedsFilter(); - m_sourceModel->notifyWithCounts(); -} - void FeedsView::selectNextItem() { QModelIndex index_next = moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier); @@ -457,6 +325,10 @@ void FeedsView::selectPreviousItem() { } } +void FeedsView::switchVisibility() { + setVisible(!isVisible()); +} + QMenu *FeedsView::initializeContextMenuCategories(RootItem *clicked_item) { if (m_contextMenuCategories == NULL) { m_contextMenuCategories = new QMenu(tr("Context menu for categories"), this); diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index bcda5a42c..316eefd3b 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -79,10 +79,6 @@ class FeedsView : public QTreeView { // Newspaper accessors. void openSelectedItemsInNewspaperMode(); - // Recycle bin operators. - void emptyRecycleBin(); - void restoreRecycleBin(); - // Feed clearers. void clearSelectedFeeds(); void clearAllFeeds(); @@ -92,30 +88,25 @@ class FeedsView : public QTreeView { void editSelectedItem(); void deleteSelectedItem(); - // Is called when counts of messages are changed externally, - // typically from message view. - void receiveMessageCountsChange(); - - // Reloads counts for selected feeds. - void updateCountsOfSelectedFeeds(bool update_total_too); - - // Reloads counts of recycle bin. - void updateCountsOfRecycleBin(bool update_total_too); - - // Reloads counts for all feeds. - void updateCountsOfAllFeeds(bool update_total_too); - - // Reloads counts for particular feed. - void updateCountsOfParticularFeed(Feed *feed, bool update_total_too); - // Selects next/previous item (feed/category) in the list. void selectNextItem(); void selectPreviousItem(); // Switches visibility of the widget. - void switchVisibility() { - setVisible(!isVisible()); - } + void switchVisibility(); + + signals: + // Emitted if user/application requested updating of some feeds. + void feedsUpdateRequested(const QList feeds); + + // Emitted if currently selected feeds needs to be reloaded. + void feedsNeedToBeReloaded(bool mark_current_index_read); + + // Emitted if user selects new feeds. + void itemSelected(RootItem *item); + + // Requests opening of given messages in newspaper mode. + void openMessagesInNewspaperView(const QList &messages); private slots: void markSelectedItemReadStatus(RootItem::ReadStatus read); @@ -143,20 +134,6 @@ class FeedsView : public QTreeView { // Show custom context menu. void contextMenuEvent(QContextMenuEvent *event); - signals: - // Emitted if user/application requested updating of some feeds. - void feedsUpdateRequested(const QList feeds); - - // Emitted if currently selected feeds needs to be reloaded. - void feedsNeedToBeReloaded(bool mark_current_index_read); - - // Emitted if user selects new feeds. - void itemSelected(RootItem *item); - - // Requests opening of given messages in newspaper mode. - void openMessagesInNewspaperView(const QList &messages); - - private: QMenu *m_contextMenuCategories; QMenu *m_contextMenuFeeds; QMenu *m_contextMenuEmptySpace; diff --git a/src/main.cpp b/src/main.cpp index 2ed89e78e..b6e79d56f 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -72,6 +72,9 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } + // Register needed metatypes. + qRegisterMetaType >("QList"); + // Add an extra path for non-system icon themes and set current icon theme // and skin. qApp->icons()->setupSearchPaths(); diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index 31b710841..7d6539ce6 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -31,6 +31,6 @@ FeedsModel *ServiceRoot::feedsModel() const { return m_feedsModel; } -void ServiceRoot::itemChanged(RootItem *item) { - emit dataChanged(item); +void ServiceRoot::itemChanged(QList items) { + emit dataChanged(items); } diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 67144f59b..99fe34acd 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -67,7 +67,7 @@ class ServiceRoot : public RootItem { // "loading" dialog přes view a toto zavolat, nasledně signalovat virtual bool loadMessagesForItem(RootItem *item, QSqlTableModel *model) = 0; - // Called BEFORE this read status update is stored in DB, + // Called BEFORE this read status update (triggered by user in message list) is stored in DB, // when false is returned, change is aborted. // This is the place to make some other changes like updating // some ONLINE service or something. @@ -75,7 +75,7 @@ class ServiceRoot : public RootItem { // "read" is status which is ABOUT TO BE SET. virtual bool onBeforeSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read) = 0; - // Called AFTER this read status update is stored in DB, + // Called AFTER this read status update (triggered by user in message list) is stored in DB, // when false is returned, change is aborted. // Here service root should inform (via signals) // which items are actually changed. @@ -99,17 +99,25 @@ class ServiceRoot : public RootItem { // "changes" - list of pairs - virtual bool onAfterSwitchMessageImportance(RootItem *selected_item, QList > changes) = 0; + // Called BEFORE the list of messages is about to be deleted + // by the user from message list. + virtual bool onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids) = 0; + + // Called AFTER the list of messages is about to be deleted + // by the user from message list. + virtual bool onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids) = 0; + // Access to feed model. FeedsModel *feedsModel() const; // Obvious method to wrap dataChanged(...) signal // which can be used by items themselves or any // other component. - void itemChanged(RootItem *item); + void itemChanged(QList items); signals: // Emitted if data in any item belonging to this root are changed. - void dataChanged(RootItem *item); + void dataChanged(QList items); void readFeedsFilterInvalidationRequested(); private: diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 844bb8d67..801d9e09f 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -215,7 +215,7 @@ void StandardFeed::fetchMetadataForItself() { // Notify the model about fact, that it needs to reload new information about // this item, particularly the icon. - serviceRoot()->itemChanged(this); + serviceRoot()->itemChanged(QList() << this); } else { qApp->showGuiMessage(tr("Metadata not fetched"), @@ -731,6 +731,10 @@ int StandardFeed::updateMessages(const QList &messages) { qDebug("Transaction commit for message downloader failed."); } + else { + updateCounts(true); + serviceRoot()->itemChanged(QList() << this); + } return updated_messages; } diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 1219de7ca..4269baa6c 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -157,6 +157,15 @@ bool StandardServiceRoot::markFeedsReadUnread(QList items, ReadStatus rea // Commit changes. if (db_handle.commit()) { + // Messages are cleared, now inform model about need to reload data. + QList itemss; + + foreach (Feed *feed, items) { + feed->updateCounts(true); + itemss.append(feed); + } + + emit dataChanged(itemss); return true; } else { @@ -191,6 +200,9 @@ bool StandardServiceRoot::markRecycleBinReadUnread(RootItem::ReadStatus read) { // Commit changes. if (db_handle.commit()) { + m_recycleBin->updateCounts(true); + + emit dataChanged(QList() << m_recycleBin); return true; } else { @@ -200,12 +212,6 @@ bool StandardServiceRoot::markRecycleBinReadUnread(RootItem::ReadStatus read) { bool StandardServiceRoot::cleanFeeds(QList items, bool clean_read_only) { QSqlDatabase db_handle = qApp->database()->connection(QSL("StandardServiceRoot"), DatabaseFactory::FromSettings); - - if (!db_handle.transaction()) { - qWarning("Starting transaction for feeds clearing."); - return false; - } - QSqlQuery query_delete_msg(db_handle); query_delete_msg.setForwardOnly(true); @@ -213,8 +219,6 @@ bool StandardServiceRoot::cleanFeeds(QList items, bool clean_read_only) { if (!query_delete_msg.prepare(QString("UPDATE Messages SET is_deleted = :deleted " "WHERE feed IN (%1) AND is_deleted = 0 AND is_read = 1;").arg(textualFeedIds(items).join(QSL(", "))))) { qWarning("Query preparation failed for feeds clearing."); - - db_handle.rollback(); return false; } } @@ -222,8 +226,6 @@ bool StandardServiceRoot::cleanFeeds(QList items, bool clean_read_only) { if (!query_delete_msg.prepare(QString("UPDATE Messages SET is_deleted = :deleted " "WHERE feed IN (%1) AND is_deleted = 0;").arg(textualFeedIds(items).join(QSL(", "))))) { qWarning("Query preparation failed for feeds clearing."); - - db_handle.rollback(); return false; } } @@ -232,15 +234,22 @@ bool StandardServiceRoot::cleanFeeds(QList items, bool clean_read_only) { if (!query_delete_msg.exec()) { qDebug("Query execution for feeds clearing failed."); - db_handle.rollback(); - } - - // Commit changes. - if (db_handle.commit()) { - return true; + return false; } else { - return db_handle.rollback(); + // Messages are cleared, now inform model about need to reload data. + QList itemss; + + foreach (Feed *feed, items) { + feed->updateCounts(true); + itemss.append(feed); + } + + m_recycleBin->updateCounts(true); + itemss.append(m_recycleBin); + + emit dataChanged(itemss); + return true; } } @@ -533,7 +542,7 @@ bool StandardServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *mo QString filter_clause = stringy_ids.join(QSL(", ")); - model->setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0")).arg(filter_clause)); + model->setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0")).arg(filter_clause)); qDebug("Loading messages from feeds: %s.", qPrintable(filter_clause)); } @@ -554,7 +563,7 @@ bool StandardServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, QList< selected_item->updateCounts(false); - emit dataChanged(selected_item); + emit dataChanged(QList() << selected_item); emit readFeedsFilterInvalidationRequested(); return true; } @@ -575,8 +584,34 @@ bool StandardServiceRoot::onAfterSwitchMessageImportance(RootItem *selected_item return true; } +bool StandardServiceRoot::onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids) { + Q_UNUSED(selected_item) + Q_UNUSED(message_db_ids) + + return true; +} + +bool StandardServiceRoot::onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids) { + Q_UNUSED(message_db_ids) + + // User deleted some messages he selected in message list. + selected_item->updateCounts(true); + + if (selected_item->kind() == RootItemKind::Bin) { + emit dataChanged(QList() << m_recycleBin); + } + else { + m_recycleBin->updateCounts(true); + emit dataChanged(QList() << selected_item << m_recycleBin); + } + + + emit readFeedsFilterInvalidationRequested(); + return true; +} + void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { - QHash assignments; + QHash assignments; assignments.insert(NO_PARENT_CATEGORY, this); // Add top-level categories. diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 93d25c864..c25abad7a 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -66,6 +66,9 @@ class StandardServiceRoot : public ServiceRoot { bool onBeforeSwitchMessageImportance(RootItem *selected_item, QList > changes); bool onAfterSwitchMessageImportance(RootItem *selected_item, QList > changes); + bool onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids); + bool onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids); + // Returns all standard categories which are lying under given root node. // This does NOT include the root node even if the node is category. QHash categoriesForItem(RootItem *root); diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 130d519d2..7fc16f69a 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -52,6 +52,14 @@ class TtRssServiceRoot : public ServiceRoot { bool onAfterSwitchMessageImportance(RootItem *selected_item, QList > changes) { return false; } + + bool onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids) { + return false; + } + + bool onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids) { + return false; + } }; #endif // TTRSSSERVICEROOT_H From 80decea8c159e2af21c554ce947c9943bc7a6bdc Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sat, 21 Nov 2015 20:43:13 +0100 Subject: [PATCH 058/203] Fix Qt 4 build. --- src/services/abstract/serviceroot.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 99fe34acd..174a7e490 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -22,6 +22,8 @@ #include "core/message.h" +#include + class FeedsModel; class QAction; From 490d0209cbda1f79b81e9686d05c551a3893f9e7 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 22 Nov 2015 11:24:19 +0100 Subject: [PATCH 059/203] Some optimization. --- src/miscellaneous/iofactory.cpp | 2 +- src/miscellaneous/iofactory.h | 2 +- .../standard/gui/formstandardimportexport.cpp | 24 ++++++------------- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/miscellaneous/iofactory.cpp b/src/miscellaneous/iofactory.cpp index a10565eea..b9e952d03 100755 --- a/src/miscellaneous/iofactory.cpp +++ b/src/miscellaneous/iofactory.cpp @@ -92,7 +92,7 @@ QByteArray IOFactory::readTextFile(const QString &file_path) { } } -void IOFactory::writeTextFile(const QString &file_path, const QByteArray &data) { +void IOFactory::writeTextFile(const QString &file_path, const QByteArray &data, const QString &encoding) { QFile input_file(file_path); QTextStream stream(&input_file); diff --git a/src/miscellaneous/iofactory.h b/src/miscellaneous/iofactory.h index 3331b5b06..c80c6539b 100755 --- a/src/miscellaneous/iofactory.h +++ b/src/miscellaneous/iofactory.h @@ -52,7 +52,7 @@ class IOFactory { // Throws exception when no such file exists. static QByteArray readTextFile(const QString &file_path); - static void writeTextFile(const QString &file_path, const QByteArray &data); + static void writeTextFile(const QString &file_path, const QByteArray &data, const QString &encoding = "UTF-8"); // Copies file, overwrites destination. static bool copyFile(const QString &source, const QString &destination); diff --git a/src/services/standard/gui/formstandardimportexport.cpp b/src/services/standard/gui/formstandardimportexport.cpp index d8e4cf418..9c10ac444 100755 --- a/src/services/standard/gui/formstandardimportexport.cpp +++ b/src/services/standard/gui/formstandardimportexport.cpp @@ -24,6 +24,8 @@ #include "gui/feedmessageviewer.h" #include "gui/feedsview.h" #include "gui/dialogs/formmain.h" +#include "exceptions/ioexception.h" + #include #include @@ -208,23 +210,13 @@ void FormStandardImportExport::exportFeeds() { bool result_export = m_model->exportToOMPL20(result_data); if (result_export) { - // Save exported data. - QFile output_file(m_ui->m_lblSelectFile->label()->text()); + try { + IOFactory::writeTextFile(m_ui->m_lblSelectFile->label()->text(), result_data); - if (output_file.open(QIODevice::Unbuffered | QIODevice::Truncate | QIODevice::WriteOnly)) { - QTextStream stream(&output_file); - - stream.setCodec("UTF-8"); - stream << QString::fromUtf8(result_data); - output_file.flush(); - output_file.close(); - - m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, tr("Feeds were exported successfully."), - tr("Feeds were exported successfully.")); + m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, tr("Feeds were exported successfully."), tr("Feeds were exported successfully.")); } - else { - m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, tr("Cannot write into destination file."), - tr("Cannot write into destination file.")); + catch (IOException &ex) { + m_ui->m_lblResult->setStatus(WidgetWithStatus::Error, tr("Cannot write into destination file."), ex.message()); } } else { @@ -241,8 +233,6 @@ void FormStandardImportExport::importFeeds() { QString output_message; if (m_serviceRoot->mergeImportExportModel(m_model, output_message)) { - // TODO: Hate this global access, what about signal? - qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->expandAll(); m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, output_message, output_message); } else { From 8eb34100a4c3e4647605bf14c31060dca7486388 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 22 Nov 2015 12:15:15 +0100 Subject: [PATCH 060/203] Fix OS2 bug. --- src/core/feeddownloader.cpp | 1 + src/gui/notifications/notification.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/feeddownloader.cpp b/src/core/feeddownloader.cpp index 505c947e6..3bdce23f0 100755 --- a/src/core/feeddownloader.cpp +++ b/src/core/feeddownloader.cpp @@ -22,6 +22,7 @@ #include #include +#include FeedDownloader::FeedDownloader(QObject *parent) : QObject(parent) { diff --git a/src/gui/notifications/notification.cpp b/src/gui/notifications/notification.cpp index 28128d088..78b522aef 100755 --- a/src/gui/notifications/notification.cpp +++ b/src/gui/notifications/notification.cpp @@ -98,7 +98,6 @@ void Notification::notify(const QString &text, const QString &title, const QIcon argument_list << hints; // hints argument_list << (int)-1; // timeout in ms - // TODO: obrazky https://dev.visucore.com/bitcoin/doxygen/notificator_8cpp_source.html QDBusMessage response = m_dBusInterface->callWithArgumentList(QDBus::AutoDetect, "Notify", argument_list); if (response.arguments().size() == 1) { From b7f6666e627bf9e1a0181e280255d36952053bb5 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 22 Nov 2015 18:33:35 +0100 Subject: [PATCH 061/203] Work on messages/recycle bin handling. --- CMakeLists.txt | 2 + src/core/rootitem.h | 2 +- src/services/abstract/recyclebin.cpp | 43 ++++++++++++++++++++ src/services/abstract/recyclebin.h | 37 +++++++++++++++++ src/services/standard/standardrecyclebin.cpp | 25 +----------- src/services/standard/standardrecyclebin.h | 15 +++---- 6 files changed, 90 insertions(+), 34 deletions(-) create mode 100644 src/services/abstract/recyclebin.cpp create mode 100644 src/services/abstract/recyclebin.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ccf63113f..2778f9960 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -419,6 +419,7 @@ set(APP_SOURCES src/services/abstract/feed.cpp src/services/abstract/category.cpp src/services/abstract/serviceroot.cpp + src/services/abstract/recyclebin.cpp # STANDARD feed service sources. src/services/standard/gui/formstandardcategorydetails.cpp @@ -535,6 +536,7 @@ set(APP_HEADERS src/services/abstract/feed.h src/services/abstract/category.h src/services/abstract/serviceroot.h + src/services/abstract/recyclebin.h # STANDARD service headers. src/services/standard/standardfeedsimportexportmodel.h diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 0f36a8d6e..ef47662f5 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -32,7 +32,7 @@ namespace RootItemKind { // Describes the kind of the item. enum Kind { Root = 1, - Bin = 2, + Bin = 2, Feed = 4, Category = 8, ServiceRoot = 16 diff --git a/src/services/abstract/recyclebin.cpp b/src/services/abstract/recyclebin.cpp new file mode 100644 index 000000000..042c5c989 --- /dev/null +++ b/src/services/abstract/recyclebin.cpp @@ -0,0 +1,43 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#include "services/abstract/recyclebin.h" + +#include "miscellaneous/application.h" +#include "miscellaneous/iconfactory.h" + + +RecycleBin::RecycleBin(RootItem *parent_item) : RootItem(parent_item) { + setKind(RootItemKind::Bin); + setIcon(qApp->icons()->fromTheme(QSL("folder-recycle-bin"))); + setTitle(tr("Recycle bin")); + setDescription(tr("Recycle bin contains all deleted messages from all feeds.")); + setCreationDate(QDateTime::currentDateTime()); +} + +RecycleBin::~RecycleBin() { +} + +QVariant RecycleBin::data(int column, int role) const { + switch (role) { + case Qt::ToolTipRole: + return tr("Recycle bin\n%1").arg(tr("%n deleted message(s).", 0, countOfAllMessages())); + + default: + return RootItem::data(column, role); + } +} diff --git a/src/services/abstract/recyclebin.h b/src/services/abstract/recyclebin.h new file mode 100644 index 000000000..ef347b010 --- /dev/null +++ b/src/services/abstract/recyclebin.h @@ -0,0 +1,37 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#ifndef RECYCLEBIN_H +#define RECYCLEBIN_H + +#include "core/rootitem.h" + + +class RecycleBin : public RootItem { + Q_OBJECT + + public: + explicit RecycleBin(RootItem *parent_item = NULL); + virtual ~RecycleBin(); + + QVariant data(int column, int role) const; + + virtual bool empty() = 0; + virtual bool restore() = 0; +}; + +#endif // RECYCLEBIN_H diff --git a/src/services/standard/standardrecyclebin.cpp b/src/services/standard/standardrecyclebin.cpp index 61a8a8c52..c82b90e8a 100755 --- a/src/services/standard/standardrecyclebin.cpp +++ b/src/services/standard/standardrecyclebin.cpp @@ -25,13 +25,8 @@ StandardRecycleBin::StandardRecycleBin(RootItem *parent) - : RootItem(parent) { - setKind(RootItemKind::Bin); - setIcon(qApp->icons()->fromTheme(QSL("folder-recycle-bin"))); + : RecycleBin(parent) { setId(ID_RECYCLE_BIN); - setTitle(tr("Recycle bin")); - setDescription(tr("Recycle bin contains all deleted messages from all feeds.")); - setCreationDate(QDateTime::currentDateTime()); updateCounts(true); } @@ -43,14 +38,6 @@ StandardServiceRoot *StandardRecycleBin::serviceRoot() { return static_cast(getParentServiceRoot()); } -int StandardRecycleBin::childCount() const { - return 0; -} - -void StandardRecycleBin::appendChild(RootItem *child) { - Q_UNUSED(child) -} - int StandardRecycleBin::countOfUnreadMessages() const { return m_unreadCount; } @@ -59,16 +46,6 @@ int StandardRecycleBin::countOfAllMessages() const { return m_totalCount; } -QVariant StandardRecycleBin::data(int column, int role) const { - switch (role) { - case Qt::ToolTipRole: - return tr("Recycle bin\n%1").arg(tr("%n deleted message(s).", 0, countOfAllMessages())); - - default: - return RootItem::data(column, role); - } -} - bool StandardRecycleBin::markAsReadUnread(RootItem::ReadStatus status) { return serviceRoot()->markRecycleBinReadUnread(status); } diff --git a/src/services/standard/standardrecyclebin.h b/src/services/standard/standardrecyclebin.h index 24ec68591..fb3794e4b 100755 --- a/src/services/standard/standardrecyclebin.h +++ b/src/services/standard/standardrecyclebin.h @@ -15,17 +15,17 @@ // You should have received a copy of the GNU General Public License // along with RSS Guard. If not, see . -#ifndef RECYCLEBIN_H -#define RECYCLEBIN_H +#ifndef STANDARDRECYCLEBIN_H +#define STANDARDRECYCLEBIN_H -#include "core/rootitem.h" +#include "services/abstract/recyclebin.h" #include class StandardServiceRoot; -class StandardRecycleBin : public RootItem { +class StandardRecycleBin : public RecycleBin { Q_OBJECT public: @@ -34,12 +34,9 @@ class StandardRecycleBin : public RootItem { StandardServiceRoot *serviceRoot(); - int childCount() const; - void appendChild(RootItem *child); int countOfUnreadMessages() const; int countOfAllMessages() const; - QVariant data(int column, int role) const; - bool markAsReadUnread(ReadStatus status); + bool markAsReadUnread(RootItem::ReadStatus status); bool empty(); bool restore(); @@ -52,4 +49,4 @@ class StandardRecycleBin : public RootItem { int m_unreadCount; }; -#endif // RECYCLEBIN_H +#endif // STANDARDRECYCLEBIN_H From 54cf90baa36f0e7edd5454a0660985398c04bf27 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 22 Nov 2015 19:29:31 +0100 Subject: [PATCH 062/203] Save work. --- src/services/abstract/recyclebin.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/services/abstract/recyclebin.h b/src/services/abstract/recyclebin.h index ef347b010..da81745f6 100644 --- a/src/services/abstract/recyclebin.h +++ b/src/services/abstract/recyclebin.h @@ -30,7 +30,12 @@ class RecycleBin : public RootItem { QVariant data(int column, int role) const; + // Empties the bin - removes all messages from it (does not remove + // them from DB, just permanently hide them, so that they are not + // re-downloaded). virtual bool empty() = 0; + + // Performs complete restoration of all messages contained in the bin virtual bool restore() = 0; }; From adae003ed5b7c9579a5d9b2bd3204df805cf18a5 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 23 Nov 2015 10:55:44 +0100 Subject: [PATCH 063/203] =?UTF-8?q?Work=20on=20restoring.=CB=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/feedsmodel.cpp | 2 +- src/core/messagesmodel.cpp | 23 +++++++++++-------- src/services/abstract/serviceroot.h | 12 +++++++++- src/services/standard/standardserviceroot.cpp | 15 ++++++++++++ src/services/standard/standardserviceroot.h | 9 ++++++++ src/services/tt-rss/ttrssserviceroot.h | 8 +++++++ 6 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 2976c032a..9b103efb7 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -318,7 +318,7 @@ QList FeedsModel::feedsForScheduledUpdate(bool auto_update_now) { QList FeedsModel::messagesForFeeds(const QList &feeds) { QList messages; - foreach (const Feed *feed, feeds) { + foreach (Feed *feed, feeds) { messages.append(feed->undeletedMessages()); } diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 28c96b3ca..03f9a3ec3 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -431,27 +431,30 @@ bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootIt } bool MessagesModel::setBatchMessagesRestored(const QModelIndexList &messages) { - QSqlDatabase db_handle = database(); - QSqlQuery query_read_msg(db_handle); QStringList message_ids; - - query_read_msg.setForwardOnly(true); + QList message_ids_num; // Obtain IDs of all desired messages. foreach (const QModelIndex &message, messages) { - message_ids.append(QString::number(messageId(message.row()))); + int msg_id = messageId(message.row()); + + message_ids_num.append(msg_id); + message_ids.append(QString::number(msg_id)); } + if (!m_selectedItem->getParentServiceRoot()->onBeforeMessagesRestoredFromBin(m_selectedItem, message_ids_num)) { + return false; + } + + QSqlQuery query_read_msg(database()); QString sql_delete_query = QString(QSL("UPDATE Messages SET is_deleted = 0 WHERE id IN (%1);")).arg(message_ids.join(QSL(", "))); + query_read_msg.setForwardOnly(true); + if (query_read_msg.exec(sql_delete_query)) { fetchAllData(); - //emit messageCountsChanged(); - - // TODO: counts changed - //emit messageCountsChanged(m_selectedItem.mode(), true, true); - return true; + return m_selectedItem->getParentServiceRoot()->onAfterMessagesRestoredFromBin(m_selectedItem, message_ids_num); } else { return false; diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 174a7e490..ed3e7e78a 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -105,10 +105,20 @@ class ServiceRoot : public RootItem { // by the user from message list. virtual bool onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids) = 0; - // Called AFTER the list of messages is about to be deleted + // Called AFTER the list of messages was deleted // by the user from message list. virtual bool onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids) = 0; + // Called BEFORE the list of messages is about to be restored from recycle bin + // by the user from message list. + // Selected item is naturally recycle bin. + virtual bool onBeforeMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) = 0; + + // Called AFTER the list of messages was restored from recycle bin + // by the user from message list. + // Selected item is naturally recycle bin. + virtual bool onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) = 0; + // Access to feed model. FeedsModel *feedsModel() const; diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 4269baa6c..286b19376 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -610,6 +610,21 @@ bool StandardServiceRoot::onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids) { + return true; +} + +bool StandardServiceRoot::onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) { + // TODO: ok, nejake zpravy obnoveny z koše, ale nevíme přesně + // do jakých původně kanálů, obnovíme všecko. + Q_UNUSED(selected_item) + Q_UNUSED(message_db_ids) + + emit dataChanged(getSubTree()); + emit readFeedsFilterInvalidationRequested(); + return true; +} + void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { QHash assignments; assignments.insert(NO_PARENT_CATEGORY, this); diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index c25abad7a..387793790 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -22,6 +22,7 @@ #include #include +#include class StandardRecycleBin; @@ -69,6 +70,9 @@ class StandardServiceRoot : public ServiceRoot { bool onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids); bool onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids); + bool onBeforeMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids); + bool onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids); + // Returns all standard categories which are lying under given root node. // This does NOT include the root node even if the node is category. QHash categoriesForItem(RootItem *root); @@ -92,6 +96,9 @@ class StandardServiceRoot : public ServiceRoot { bool markRecycleBinReadUnread(ReadStatus read); bool cleanFeeds(QList items, bool clean_read_only); + // DB connection to be used by child items - feeds/categories. + QSqlDatabase dbConnection() const; + public slots: void addNewCategory(); void addNewFeed(); @@ -121,6 +128,8 @@ class StandardServiceRoot : public ServiceRoot { QList m_feedContextMenu; QAction *m_actionFeedFetchMetadata; + + QSqlDatabase m_database; }; #endif // STANDARDSERVICEROOT_H diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 7fc16f69a..617d9a6da 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -60,6 +60,14 @@ class TtRssServiceRoot : public ServiceRoot { bool onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids) { return false; } + + bool onBeforeMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) { + return false; + } + + bool onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) { + return false; + } }; #endif // TTRSSSERVICEROOT_H From 46eba512479767b54781f96c427ef4d6a7ff67a4 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 23 Nov 2015 13:13:03 +0100 Subject: [PATCH 064/203] Refactoring regarding reloading of displayed messages and some little cleanups. --- src/core/feedsmodel.cpp | 18 ++++++++++++++++-- src/core/feedsmodel.h | 7 ++++--- src/definitions/definitions.h.in | 1 + src/gui/feedmessageviewer.cpp | 13 +------------ src/gui/feedmessageviewer.h | 3 --- src/gui/feedsview.cpp | 4 ---- src/gui/feedsview.h | 3 --- src/services/abstract/serviceroot.cpp | 4 ++++ src/services/abstract/serviceroot.h | 6 +++--- src/services/standard/standardserviceroot.cpp | 9 ++++++--- 10 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 9b103efb7..665a61e86 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -401,9 +401,22 @@ void FeedsModel::reloadChangedItem(RootItem *item) { reloadChangedLayout(QModelIndexList() << index_item); } +void FeedsModel::notifyWithCounts() { + if (SystemTrayIcon::isSystemTrayActivated()) { + qApp->trayIcon()->setNumber(countOfUnreadMessages(), hasAnyFeedNewMessages()); + } +} + void FeedsModel::onItemDataChanged(QList items) { - foreach (RootItem *item, items) { - reloadChangedItem(item); + if (items.size() > RELOAD_MODEL_BORDER_NUM) { + qDebug("There is request to reload feed model for more than %d items, reloading model fully.", RELOAD_MODEL_BORDER_NUM); + } + else { + qDebug("There is request to reload feed model, reloading the %d items individually.", items.size()); + + foreach (RootItem *item, items) { + reloadChangedItem(item); + } } notifyWithCounts(); @@ -431,6 +444,7 @@ bool FeedsModel::addServiceAccount(ServiceRoot *root) { // Connect. connect(root, SIGNAL(readFeedsFilterInvalidationRequested()), this, SIGNAL(readFeedsFilterInvalidationRequested())); connect(root, SIGNAL(dataChanged(QList)), this, SLOT(onItemDataChanged(QList))); + connect(root, SIGNAL(reloadMessageListRequested(bool)), this, SIGNAL(reloadMessageListRequested(bool))); root->start(); return true; diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 40542a10b..d50b8f733 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -153,9 +153,7 @@ class FeedsModel : public QAbstractItemModel { // Notifies other components about messages // counts. - inline void notifyWithCounts() { - emit messageCountsChanged(countOfUnreadMessages(), countOfAllMessages(), hasAnyFeedNewMessages()); - } + void notifyWithCounts(); private slots: void onItemDataChanged(QList items); @@ -172,6 +170,9 @@ class FeedsModel : public QAbstractItemModel { // Emitted if counts of messages are changed. void messageCountsChanged(int unread_messages, int total_messages, bool any_feed_has_unread_messages); + // Emitted when there is a need of reloading of displayed messages. + void reloadMessageListRequested(bool mark_selected_messages_read); + private: // Returns converted ids of given feeds // which are suitable as IN clause for SQL queries. diff --git a/src/definitions/definitions.h.in b/src/definitions/definitions.h.in index 1a44da62a..ece3459c9 100755 --- a/src/definitions/definitions.h.in +++ b/src/definitions/definitions.h.in @@ -86,6 +86,7 @@ #define GOOGLE_SEARCH_URL "https://www.google.com/search?q=%1&ie=utf-8&oe=utf-8" #define GOOGLE_SUGGEST_URL "http://suggestqueries.google.com/complete/search?output=toolbar&hl=en&q=%1" #define ENCRYPTION_FILE_NAME "key.private" +#define RELOAD_MODEL_BORDER_NUM 10 #define FEED_INITIAL_OPML_PATTERN "feeds-%1.opml" diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index b661e4c32..11999efa6 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -220,14 +220,6 @@ void FeedMessageViewer::setListHeadersEnabled(bool enable) { m_messagesView->header()->setVisible(enable); } -void FeedMessageViewer::updateTrayIconStatus(int unread_messages, int total_messages, bool any_unread_messages) { - Q_UNUSED(total_messages) - - if (SystemTrayIcon::isSystemTrayActivated()) { - qApp->trayIcon()->setNumber(unread_messages, any_unread_messages); - } -} - void FeedMessageViewer::onFeedUpdatesStarted() { //: Text display in status bar when feed update is started. qApp->mainForm()->statusBar()->showProgressFeeds(0, tr("Feed update started")); @@ -329,10 +321,7 @@ void FeedMessageViewer::createConnections() { // State of many messages is changed, then we need // to reload selections. - connect(m_feedsView, SIGNAL(feedsNeedToBeReloaded(bool)), m_messagesView, SLOT(reloadSelections(bool))); - - // If counts of unread/all messages change, update the tray icon. - connect(m_feedsView->sourceModel(), SIGNAL(messageCountsChanged(int,int,bool)), this, SLOT(updateTrayIconStatus(int,int,bool))); + connect(m_feedsView->sourceModel(), SIGNAL(reloadMessageListRequested(bool)), m_messagesView, SLOT(reloadSelections(bool))); // Message openers. connect(m_messagesView, SIGNAL(openLinkMiniBrowser(QString)), m_messagesBrowser, SLOT(navigateToUrl(QString))); diff --git a/src/gui/feedmessageviewer.h b/src/gui/feedmessageviewer.h index a448bdd88..cd4d5c00d 100755 --- a/src/gui/feedmessageviewer.h +++ b/src/gui/feedmessageviewer.h @@ -99,9 +99,6 @@ class FeedMessageViewer : public TabContent { void updateFeeds(QList feeds); private slots: - // Updates counts of messages for example in tray icon. - void updateTrayIconStatus(int unread_messages, int total_messages, bool any_unread_messages); - // Reacts on feed updates. void onFeedUpdatesStarted(); void onFeedUpdatesProgress(Feed *feed, int current, int total); diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 50ff62c75..a465b9bd5 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -169,12 +169,10 @@ void FeedsView::updateAllItemsOnStartup() { void FeedsView::clearSelectedFeeds() { m_sourceModel->markItemCleared(selectedItem(), false); - emit feedsNeedToBeReloaded(true); } void FeedsView::clearAllFeeds() { m_sourceModel->markItemCleared(m_sourceModel->rootItem(), false); - emit feedsNeedToBeReloaded(true); } void FeedsView::editSelectedItem() { @@ -274,7 +272,6 @@ void FeedsView::deleteSelectedItem() { void FeedsView::markSelectedItemReadStatus(RootItem::ReadStatus read) { m_sourceModel->markItemRead(selectedItem(), read); - emit feedsNeedToBeReloaded(read == 1); } void FeedsView::markSelectedItemsRead() { @@ -287,7 +284,6 @@ void FeedsView::markSelectedItemsUnread() { void FeedsView::markAllItemsReadStatus(RootItem::ReadStatus read) { m_sourceModel->markItemRead(m_sourceModel->rootItem(), read); - emit feedsNeedToBeReloaded(read == 1); } void FeedsView::markAllItemsRead() { diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index 316eefd3b..926e0195c 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -99,9 +99,6 @@ class FeedsView : public QTreeView { // Emitted if user/application requested updating of some feeds. void feedsUpdateRequested(const QList feeds); - // Emitted if currently selected feeds needs to be reloaded. - void feedsNeedToBeReloaded(bool mark_current_index_read); - // Emitted if user selects new feeds. void itemSelected(RootItem *item); diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index 7d6539ce6..874f620bd 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -34,3 +34,7 @@ FeedsModel *ServiceRoot::feedsModel() const { void ServiceRoot::itemChanged(QList items) { emit dataChanged(items); } + +void ServiceRoot::requestReloadMessageList(bool mark_selected_messages_read) { + emit reloadMessageListRequested(mark_selected_messages_read); +} diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index ed3e7e78a..875de009d 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -122,15 +122,15 @@ class ServiceRoot : public RootItem { // Access to feed model. FeedsModel *feedsModel() const; - // Obvious method to wrap dataChanged(...) signal - // which can be used by items themselves or any - // other component. + // Obvious methods to wrap signals. void itemChanged(QList items); + void requestReloadMessageList(bool mark_selected_messages_read); signals: // Emitted if data in any item belonging to this root are changed. void dataChanged(QList items); void readFeedsFilterInvalidationRequested(); + void reloadMessageListRequested(bool mark_selected_messages_read); private: FeedsModel *m_feedsModel; diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 286b19376..48c04cf9e 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -165,7 +165,8 @@ bool StandardServiceRoot::markFeedsReadUnread(QList items, ReadStatus rea itemss.append(feed); } - emit dataChanged(itemss); + itemChanged(itemss); + requestReloadMessageList(read == RootItem::Read); return true; } else { @@ -202,7 +203,8 @@ bool StandardServiceRoot::markRecycleBinReadUnread(RootItem::ReadStatus read) { if (db_handle.commit()) { m_recycleBin->updateCounts(true); - emit dataChanged(QList() << m_recycleBin); + itemChanged(QList() << m_recycleBin); + requestReloadMessageList(read == RootItem::Read); return true; } else { @@ -248,7 +250,8 @@ bool StandardServiceRoot::cleanFeeds(QList items, bool clean_read_only) { m_recycleBin->updateCounts(true); itemss.append(m_recycleBin); - emit dataChanged(itemss); + itemChanged(itemss); + requestReloadMessageList(true); return true; } } From ef20ea977452268086e0d605ce98777762ff4480 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 23 Nov 2015 14:23:51 +0100 Subject: [PATCH 065/203] Update feed logic moved to model, cleared. --- src/core/feedsmodel.cpp | 90 ++++++++++++++++- src/core/feedsmodel.h | 18 ++++ src/definitions/definitions.h.in | 2 +- src/gui/feedmessageviewer.cpp | 165 +++++++++---------------------- src/gui/feedmessageviewer.h | 15 +-- src/gui/feedsview.cpp | 16 +-- src/gui/feedsview.h | 5 - 7 files changed, 159 insertions(+), 152 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 665a61e86..09a5b10e6 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -27,7 +27,11 @@ #include "miscellaneous/iconfactory.h" #include "miscellaneous/mutex.h" #include "gui/messagebox.h" +#include "gui/statusbar.h" +#include "gui/dialogs/formmain.h" +#include "core/feeddownloader.h" +#include #include #include #include @@ -40,7 +44,7 @@ FeedsModel::FeedsModel(QObject *parent) - : QAbstractItemModel(parent), m_autoUpdateTimer(new QTimer(this)) { + : QAbstractItemModel(parent), m_autoUpdateTimer(new QTimer(this)), m_feedDownloaderThread(NULL), m_feedDownloader(NULL) { setObjectName(QSL("FeedsModel")); // Create root item. @@ -64,6 +68,11 @@ FeedsModel::FeedsModel(QObject *parent) loadActivatedServiceAccounts(); updateAutoUpdateStatus(); + + if (qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::FeedsUpdateOnStartup)).toBool()) { + qDebug("Requesting update for all feeds on application startup."); + QTimer::singleShot(STARTUP_UPDATE_DELAY, this, SLOT(updateAllItems())); + } } FeedsModel::~FeedsModel() { @@ -77,6 +86,85 @@ void FeedsModel::quit() { if (m_autoUpdateTimer->isActive()) { m_autoUpdateTimer->stop(); } + + // Close worker threads. + if (m_feedDownloaderThread != NULL && m_feedDownloaderThread->isRunning()) { + qDebug("Quitting feed downloader thread."); + m_feedDownloaderThread->quit(); + + if (!m_feedDownloaderThread->wait(CLOSE_LOCK_TIMEOUT)) { + qCritical("Feed downloader thread is running despite it was told to quit. Terminating it."); + m_feedDownloaderThread->terminate(); + } + } + + // Close workers. + if (m_feedDownloader != NULL) { + qDebug("Feed downloader exists. Deleting it from memory."); + m_feedDownloader->deleteLater(); + } + + if (qApp->settings()->value(GROUP(Messages), SETTING(Messages::ClearReadOnExit)).toBool()) { + markItemCleared(m_rootItem, true); + } +} + +void FeedsModel::updateFeeds(const QList &feeds) { + if (!qApp->feedUpdateLock()->tryLock()) { + qApp->showGuiMessage(tr("Cannot update all items"), + tr("You cannot update all items because another another critical operation is ongoing."), + QSystemTrayIcon::Warning, qApp->mainForm(), true); + return; + } + + if (m_feedDownloader == NULL) { + m_feedDownloader = new FeedDownloader(); + m_feedDownloaderThread = new QThread(); + + // Downloader setup. + qRegisterMetaType >("QList"); + m_feedDownloader->moveToThread(m_feedDownloaderThread); + + connect(this, SIGNAL(feedsUpdateRequested(QList)), m_feedDownloader, SLOT(updateFeeds(QList))); + connect(m_feedDownloaderThread, SIGNAL(finished()), m_feedDownloaderThread, SLOT(deleteLater())); + connect(m_feedDownloader, SIGNAL(finished(FeedDownloadResults)), this, SLOT(onFeedUpdatesFinished(FeedDownloadResults))); + connect(m_feedDownloader, SIGNAL(started()), this, SLOT(onFeedUpdatesStarted())); + connect(m_feedDownloader, SIGNAL(progress(Feed*,int,int)), this, SLOT(onFeedUpdatesProgress(Feed*,int,int))); + + // Connections are made, start the feed downloader thread. + m_feedDownloaderThread->start(); + } + + emit feedsUpdateRequested(feeds); +} + +void FeedsModel::onFeedUpdatesStarted() { + //: Text display in status bar when feed update is started. + qApp->mainForm()->statusBar()->showProgressFeeds(0, tr("Feed update started")); +} + +void FeedsModel::onFeedUpdatesProgress(Feed *feed, int current, int total) { + // Some feed got updated. + qApp->mainForm()->statusBar()->showProgressFeeds((current * 100.0) / total, + //: Text display in status bar when particular feed is updated. + tr("Updated feed '%1'").arg(feed->title())); +} + +void FeedsModel::onFeedUpdatesFinished(FeedDownloadResults results) { + qApp->feedUpdateLock()->unlock(); + qApp->mainForm()->statusBar()->clearProgressFeeds(); + + if (!results.m_updatedFeeds.isEmpty()) { + // Now, inform about results via GUI message/notification. + qApp->showGuiMessage(tr("New messages downloaded"), results.getOverview(10), QSystemTrayIcon::NoIcon, + 0, false, qApp->icons()->fromTheme(QSL("item-update-all"))); + } + + emit feedsUpdateFinished(); +} + +void FeedsModel::updateAllFeeds() { + updateFeeds(m_rootItem->getSubTreeFeeds()); } void FeedsModel::executeNextAutoUpdate() { diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index d50b8f733..412aa7b36 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -22,6 +22,7 @@ #include "core/message.h" #include "core/rootitem.h" +#include "core/feeddownloader.h" class Category; @@ -132,6 +133,13 @@ class FeedsModel : public QAbstractItemModel { // Does necessary job before quitting this component. void quit(); + // Schedules given feeds for update. + void updateFeeds(const QList &feeds); + + // Schedules all feeds from all accounts for update. + void updateAllFeeds(); + + // Adds given service root account. bool addServiceAccount(ServiceRoot *root); public slots: @@ -161,7 +169,14 @@ class FeedsModel : public QAbstractItemModel { // Is executed when next auto-update round could be done. void executeNextAutoUpdate(); + // Reacts on feed updates. + void onFeedUpdatesStarted(); + void onFeedUpdatesProgress(Feed *feed, int current, int total); + void onFeedUpdatesFinished(FeedDownloadResults results); + signals: + void feedsUpdateFinished(); + void readFeedsFilterInvalidationRequested(); // Emitted when model requests update of some feeds. @@ -191,6 +206,9 @@ class FeedsModel : public QAbstractItemModel { bool m_globalAutoUpdateEnabled; int m_globalAutoUpdateInitialInterval; int m_globalAutoUpdateRemainingInterval; + + QThread *m_feedDownloaderThread; + FeedDownloader *m_feedDownloader; }; #endif // FEEDSMODEL_H diff --git a/src/definitions/definitions.h.in b/src/definitions/definitions.h.in index ece3459c9..a4712f8e4 100755 --- a/src/definitions/definitions.h.in +++ b/src/definitions/definitions.h.in @@ -68,7 +68,7 @@ #define INTERNAL_URL_BLANK "about:blank" #define DEFAULT_AUTO_UPDATE_INTERVAL 15 #define AUTO_UPDATE_INTERVAL 60000 -#define STARTUP_UPDATE_DELAY 15000 +#define STARTUP_UPDATE_DELAY 30000 #define TIMEZONE_OFFSET_LIMIT 6 #define CHANGE_EVENT_DELAY 250 #define FLAG_ICON_SUBFOLDER "flags" diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 11999efa6..f956974ed 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -65,17 +65,12 @@ FeedMessageViewer::FeedMessageViewer(QWidget *parent) m_messagesView(new MessagesView(this)), m_feedsView(new FeedsView(this)), m_messagesBrowser(new WebBrowser(this)), - m_feedDownloaderThread(NULL), m_dbCleanerThread(NULL), - m_feedDownloader(NULL), m_dbCleaner(NULL) { initialize(); initializeViews(); loadMessageViewerFonts(); createConnections(); - - // Now, update all feeds if user has set it. - m_feedsView->updateAllItemsOnStartup(); } FeedMessageViewer::~FeedMessageViewer() { @@ -86,38 +81,38 @@ DatabaseCleaner *FeedMessageViewer::databaseCleaner() { if (m_dbCleaner == NULL) { m_dbCleaner = new DatabaseCleaner(); m_dbCleanerThread = new QThread(); - + // Downloader setup. qRegisterMetaType("CleanerOrders"); m_dbCleaner->moveToThread(m_dbCleanerThread); connect(m_dbCleanerThread, SIGNAL(finished()), m_dbCleanerThread, SLOT(deleteLater())); - + // Connections are made, start the feed downloader thread. m_dbCleanerThread->start(); } - + return m_dbCleaner; } void FeedMessageViewer::saveSize() { Settings *settings = qApp->settings(); - + m_feedsView->saveExpandedStates(); - + // Store offsets of splitters. settings->setValue(GROUP(GUI), GUI::SplitterFeeds, QString(m_feedSplitter->saveState().toBase64())); settings->setValue(GROUP(GUI), GUI::SplitterMessages, QString(m_messageSplitter->saveState().toBase64())); - + // States of splitters are stored, let's store // widths of columns. int width_column_author = m_messagesView->columnWidth(MSG_DB_AUTHOR_INDEX); int width_column_date = m_messagesView->columnWidth(MSG_DB_DCREATED_INDEX); - + if (width_column_author != 0 && width_column_date != 0) { settings->setValue(GROUP(GUI), KEY_MESSAGES_VIEW + QString::number(MSG_DB_AUTHOR_INDEX), width_column_author); settings->setValue(GROUP(GUI), KEY_MESSAGES_VIEW + QString::number(MSG_DB_DCREATED_INDEX), width_column_date); } - + // Store "visibility" of toolbars and list headers. settings->setValue(GROUP(GUI), GUI::ToolbarsVisible, m_toolBarsEnabled); settings->setValue(GROUP(GUI), GUI::ListHeadersVisible, m_listHeadersEnabled); @@ -126,13 +121,13 @@ void FeedMessageViewer::saveSize() { void FeedMessageViewer::loadSize() { Settings *settings = qApp->settings(); int default_msg_section_size = m_messagesView->header()->defaultSectionSize(); - + m_feedsView->loadExpandedStates(); - + // Restore offsets of splitters. m_feedSplitter->restoreState(QByteArray::fromBase64(settings->value(GROUP(GUI), SETTING(GUI::SplitterFeeds)).toString().toLocal8Bit())); m_messageSplitter->restoreState(QByteArray::fromBase64(settings->value(GROUP(GUI), SETTING(GUI::SplitterMessages)).toString().toLocal8Bit())); - + // Splitters are restored, now, restore widths of columns. m_messagesView->setColumnWidth(MSG_DB_AUTHOR_INDEX, settings->value(GROUP(GUI), KEY_MESSAGES_VIEW + QString::number(MSG_DB_AUTHOR_INDEX), @@ -145,7 +140,7 @@ void FeedMessageViewer::loadSize() { void FeedMessageViewer::loadMessageViewerFonts() { Settings *settings = qApp->settings(); QWebSettings *view_settings = m_messagesBrowser->view()->settings(); - + view_settings->setFontFamily(QWebSettings::StandardFont, settings->value(GROUP(Messages), SETTING(Messages::PreviewerFontStandard)).toString()); } @@ -153,42 +148,21 @@ void FeedMessageViewer::loadMessageViewerFonts() { void FeedMessageViewer::quit() { // Quit the feeds model (stops auto-update timer etc.). m_feedsView->sourceModel()->quit(); - - // Close worker threads. - if (m_feedDownloaderThread != NULL && m_feedDownloaderThread->isRunning()) { - qDebug("Quitting feed downloader thread."); - m_feedDownloaderThread->quit(); - - if (!m_feedDownloaderThread->wait(CLOSE_LOCK_TIMEOUT)) { - qCritical("Feed downloader thread is running despite it was told to quit. Terminating it."); - m_feedDownloaderThread->terminate(); - } - } - + if (m_dbCleanerThread != NULL && m_dbCleanerThread->isRunning()) { qDebug("Quitting database cleaner thread."); m_dbCleanerThread->quit(); - + if (!m_dbCleanerThread->wait(CLOSE_LOCK_TIMEOUT)) { qCritical("Database cleaner thread is running despite it was told to quit. Terminating it."); m_dbCleanerThread->terminate(); } } - - // Close workers. - if (m_feedDownloader != NULL) { - qDebug("Feed downloader exists. Deleting it from memory."); - m_feedDownloader->deleteLater(); - } - + if (m_dbCleaner != NULL) { qDebug("Database cleaner exists. Deleting it from memory."); m_dbCleaner->deleteLater(); } - - if (qApp->settings()->value(GROUP(Messages), SETTING(Messages::ClearReadOnExit)).toBool()) { - m_feedsView->clearAllReadMessages(); - } } bool FeedMessageViewer::areToolBarsEnabled() const { @@ -220,37 +194,13 @@ void FeedMessageViewer::setListHeadersEnabled(bool enable) { m_messagesView->header()->setVisible(enable); } -void FeedMessageViewer::onFeedUpdatesStarted() { - //: Text display in status bar when feed update is started. - qApp->mainForm()->statusBar()->showProgressFeeds(0, tr("Feed update started")); -} - -void FeedMessageViewer::onFeedUpdatesProgress(Feed *feed, int current, int total) { - // Some feed got updated. - qApp->mainForm()->statusBar()->showProgressFeeds((current * 100.0) / total, - //: Text display in status bar when particular feed is updated. - tr("Updated feed '%1'").arg(feed->title())); -} - -void FeedMessageViewer::onFeedUpdatesFinished(FeedDownloadResults results) { - qApp->feedUpdateLock()->unlock(); - qApp->mainForm()->statusBar()->clearProgressFeeds(); - m_messagesView->reloadSelections(true); - - if (!results.m_updatedFeeds.isEmpty()) { - // Now, inform about results via GUI message/notification. - qApp->showGuiMessage(tr("New messages downloaded"), results.getOverview(10), QSystemTrayIcon::NoIcon, - 0, false, qApp->icons()->fromTheme(QSL("item-update-all"))); - } -} - void FeedMessageViewer::switchFeedComponentVisibility() { m_feedsWidget->setVisible(!m_feedsWidget->isVisible()); } void FeedMessageViewer::toggleShowOnlyUnreadFeeds() { QAction *origin = qobject_cast(sender()); - + if (origin == NULL) { m_feedsView->model()->invalidateReadFeedsFilter(true, false); } @@ -263,7 +213,7 @@ void FeedMessageViewer::updateMessageButtonsAvailability() { bool one_message_selected = m_messagesView->selectionModel()->selectedRows().size() == 1; bool atleast_one_message_selected = !m_messagesView->selectionModel()->selectedRows().isEmpty(); FormMain *form_main = qApp->mainForm(); - + form_main->m_ui->m_actionDeleteSelectedMessages->setEnabled(atleast_one_message_selected); form_main->m_ui->m_actionMarkSelectedMessagesAsRead->setEnabled(atleast_one_message_selected); form_main->m_ui->m_actionMarkSelectedMessagesAsUnread->setEnabled(atleast_one_message_selected); @@ -282,7 +232,7 @@ void FeedMessageViewer::updateFeedButtonsAvailability() { bool category_selected = anything_selected && selected_item->kind() == RootItemKind::Category; bool service_selected = anything_selected && selected_item->kind() == RootItemKind::ServiceRoot; FormMain *form_main = qApp->mainForm(); - + form_main->m_ui->m_actionServiceEdit->setEnabled(!critical_action_running && service_selected); form_main->m_ui->m_actionServiceDelete->setEnabled(!critical_action_running && service_selected); form_main->m_ui->m_actionBackupDatabaseSettings->setEnabled(!critical_action_running); @@ -301,27 +251,28 @@ void FeedMessageViewer::updateFeedButtonsAvailability() { void FeedMessageViewer::createConnections() { FormMain *form_main = qApp->mainForm(); - + // Filtering & searching. connect(m_toolBarMessages, SIGNAL(messageSearchPatternChanged(QString)), m_messagesView, SLOT(searchMessages(QString))); connect(m_toolBarMessages, SIGNAL(messageFilterChanged(MessagesModel::MessageHighlighter)), m_messagesView, SLOT(filterMessages(MessagesModel::MessageHighlighter))); - + // Message changers. connect(m_messagesView, SIGNAL(currentMessagesRemoved()), m_messagesBrowser, SLOT(clear())); connect(m_messagesView, SIGNAL(currentMessagesChanged(QList)), m_messagesBrowser, SLOT(navigateToMessages(QList))); connect(m_messagesView, SIGNAL(currentMessagesRemoved()), this, SLOT(updateMessageButtonsAvailability())); connect(m_messagesView, SIGNAL(currentMessagesChanged(QList)), this, SLOT(updateMessageButtonsAvailability())); - + connect(m_feedsView, SIGNAL(itemSelected(RootItem*)), this, SLOT(updateFeedButtonsAvailability())); connect(qApp->feedUpdateLock(), SIGNAL(locked()), this, SLOT(updateFeedButtonsAvailability())); connect(qApp->feedUpdateLock(), SIGNAL(unlocked()), this, SLOT(updateFeedButtonsAvailability())); - + // If user selects feeds, load their messages. connect(m_feedsView, SIGNAL(itemSelected(RootItem*)), m_messagesView, SLOT(loadFeeds(RootItem*))); - + // State of many messages is changed, then we need // to reload selections. connect(m_feedsView->sourceModel(), SIGNAL(reloadMessageListRequested(bool)), m_messagesView, SLOT(reloadSelections(bool))); + connect(m_feedsView->sourceModel(), SIGNAL(feedsUpdateFinished()), this, SLOT(onFeedsUpdateFinished())); // Message openers. connect(m_messagesView, SIGNAL(openLinkMiniBrowser(QString)), m_messagesBrowser, SLOT(navigateToUrl(QString))); @@ -331,10 +282,11 @@ void FeedMessageViewer::createConnections() { form_main->m_ui->m_tabWidget, SLOT(addLinkedBrowser(QString))); connect(m_feedsView, SIGNAL(openMessagesInNewspaperView(QList)), form_main->m_ui->m_tabWidget, SLOT(addBrowserWithMessages(QList))); - + // Downloader connections. - connect(m_feedsView, SIGNAL(feedsUpdateRequested(QList)), this, SLOT(updateFeeds(QList))); - + // TODO: přesunout všechny negui věci asi k modelům, tohle je + // hlavně GUI třída, takže přesunout aktualizace feedů do modelu + // Toolbar forwardings. connect(form_main->m_ui->m_actionCleanupDatabase, SIGNAL(triggered()), this, SLOT(showDbCleanupAssistant())); @@ -402,15 +354,15 @@ void FeedMessageViewer::initialize() { m_toolBarFeeds->setMovable(false); m_toolBarFeeds->setAllowedAreas(Qt::TopToolBarArea); m_toolBarFeeds->loadChangeableActions(); - + m_toolBarMessages->setFloatable(false); m_toolBarMessages->setMovable(false); m_toolBarMessages->setAllowedAreas(Qt::TopToolBarArea); m_toolBarMessages->loadChangeableActions(); - + // Finish web/message browser setup. m_messagesBrowser->setNavigationBarVisible(false); - + // Now refresh visual setup. refreshVisualProperties(); } @@ -420,12 +372,12 @@ void FeedMessageViewer::initializeViews() { m_messagesWidget = new QWidget(this); m_feedSplitter = new QSplitter(Qt::Horizontal, this); m_messageSplitter = new QSplitter(Qt::Vertical, this); - + // Instantiate needed components. QVBoxLayout *central_layout = new QVBoxLayout(this); QVBoxLayout *feed_layout = new QVBoxLayout(m_feedsWidget); QVBoxLayout *message_layout = new QVBoxLayout(m_messagesWidget); - + // Set layout properties. central_layout->setMargin(0); central_layout->setSpacing(0); @@ -433,11 +385,11 @@ void FeedMessageViewer::initializeViews() { feed_layout->setSpacing(0); message_layout->setMargin(0); message_layout->setSpacing(0); - + // Set views. m_feedsView->setFrameStyle(QFrame::NoFrame); m_messagesView->setFrameStyle(QFrame::NoFrame); - + // Setup message splitter. m_messageSplitter->setObjectName(QSL("MessageSplitter")); m_messageSplitter->setHandleWidth(1); @@ -445,30 +397,30 @@ void FeedMessageViewer::initializeViews() { m_messageSplitter->setChildrenCollapsible(false); m_messageSplitter->addWidget(m_messagesView); m_messageSplitter->addWidget(m_messagesBrowser); - + // Assemble message-related components to single widget. message_layout->addWidget(m_toolBarMessages); message_layout->addWidget(m_messageSplitter); - + // Assemble feed-related components to another widget. feed_layout->addWidget(m_toolBarFeeds); feed_layout->addWidget(m_feedsView); - + // Assembler everything together. m_feedSplitter->setHandleWidth(1); m_feedSplitter->setOpaqueResize(false); m_feedSplitter->setChildrenCollapsible(false); m_feedSplitter->addWidget(m_feedsWidget); m_feedSplitter->addWidget(m_messagesWidget); - + // Add toolbar and main feeds/messages widget to main layout. central_layout->addWidget(m_feedSplitter); - + setTabOrder(m_feedsView, m_messagesView); setTabOrder(m_messagesView, m_toolBarFeeds); setTabOrder(m_toolBarFeeds, m_toolBarMessages); setTabOrder(m_toolBarMessages, m_messagesBrowser); - + updateMessageButtonsAvailability(); updateFeedButtonsAvailability(); } @@ -478,10 +430,10 @@ void FeedMessageViewer::showDbCleanupAssistant() { QPointer form_pointer = new FormDatabaseCleanup(this); form_pointer.data()->setCleaner(databaseCleaner()); form_pointer.data()->exec(); - + delete form_pointer.data(); qApp->feedUpdateLock()->unlock(); - + m_messagesView->reloadSelections(false); m_feedsView->sourceModel()->reloadCountsOfWholeModel(); } @@ -495,36 +447,11 @@ void FeedMessageViewer::showDbCleanupAssistant() { void FeedMessageViewer::refreshVisualProperties() { Qt::ToolButtonStyle button_style = static_cast(qApp->settings()->value(GROUP(GUI), SETTING(GUI::ToolbarStyle)).toInt()); - + m_toolBarFeeds->setToolButtonStyle(button_style); m_toolBarMessages->setToolButtonStyle(button_style); } -void FeedMessageViewer::updateFeeds(QList feeds) { - if (!qApp->feedUpdateLock()->tryLock()) { - qApp->showGuiMessage(tr("Cannot update all items"), - tr("You cannot update all items because another another critical operation is ongoing."), - QSystemTrayIcon::Warning, qApp->mainForm(), true); - return; - } - - if (m_feedDownloader == NULL) { - m_feedDownloader = new FeedDownloader(); - m_feedDownloaderThread = new QThread(); - - // Downloader setup. - qRegisterMetaType >("QList"); - m_feedDownloader->moveToThread(m_feedDownloaderThread); - - connect(this, SIGNAL(feedsUpdateRequested(QList)), m_feedDownloader, SLOT(updateFeeds(QList))); - connect(m_feedDownloaderThread, SIGNAL(finished()), m_feedDownloaderThread, SLOT(deleteLater())); - connect(m_feedDownloader, SIGNAL(finished(FeedDownloadResults)), this, SLOT(onFeedUpdatesFinished(FeedDownloadResults))); - connect(m_feedDownloader, SIGNAL(started()), this, SLOT(onFeedUpdatesStarted())); - connect(m_feedDownloader, SIGNAL(progress(Feed*,int,int)), this, SLOT(onFeedUpdatesProgress(Feed*,int,int))); - - // Connections are made, start the feed downloader thread. - m_feedDownloaderThread->start(); - } - - emit feedsUpdateRequested(feeds); +void FeedMessageViewer::onFeedsUpdateFinished() { + m_messagesView->reloadSelections(true); } diff --git a/src/gui/feedmessageviewer.h b/src/gui/feedmessageviewer.h index cd4d5c00d..5d81e6ebb 100755 --- a/src/gui/feedmessageviewer.h +++ b/src/gui/feedmessageviewer.h @@ -96,18 +96,15 @@ class FeedMessageViewer : public TabContent { // Reloads some changeable visual settings. void refreshVisualProperties(); - void updateFeeds(QList feeds); - private slots: - // Reacts on feed updates. - void onFeedUpdatesStarted(); - void onFeedUpdatesProgress(Feed *feed, int current, int total); - void onFeedUpdatesFinished(FeedDownloadResults results); + // Called when feed update finishes. + void onFeedsUpdateFinished(); // Switches visibility of feed list and related // toolbar. void switchFeedComponentVisibility(); + // Toggles displayed feeds. void toggleShowOnlyUnreadFeeds(); void updateMessageButtonsAvailability(); @@ -123,10 +120,6 @@ class FeedMessageViewer : public TabContent { // Sets up connections. void createConnections(); - signals: - // Emitted if user/application requested updating of some feeds. - void feedsUpdateRequested(const QList feeds); - private: bool m_toolBarsEnabled; bool m_listHeadersEnabled; @@ -142,9 +135,7 @@ class FeedMessageViewer : public TabContent { QWidget *m_messagesWidget; WebBrowser *m_messagesBrowser; - QThread *m_feedDownloaderThread; QThread *m_dbCleanerThread; - FeedDownloader *m_feedDownloader; DatabaseCleaner *m_dbCleaner; }; diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index a465b9bd5..2ff36f599 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -54,7 +54,6 @@ FeedsView::FeedsView(QWidget *parent) m_sourceModel = m_proxyModel->sourceModel(); // Connections. - connect(m_sourceModel, SIGNAL(feedsUpdateRequested(QList)), this, SIGNAL(feedsUpdateRequested(QList))); connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder))); setModel(m_proxyModel); @@ -153,18 +152,11 @@ void FeedsView::expandCollapseCurrentItem() { } void FeedsView::updateAllItems() { - emit feedsUpdateRequested(allFeeds()); + m_sourceModel->updateAllFeeds(); } void FeedsView::updateSelectedItems() { - emit feedsUpdateRequested(selectedFeeds()); -} - -void FeedsView::updateAllItemsOnStartup() { - if (qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::FeedsUpdateOnStartup)).toBool()) { - qDebug("Requesting update for all feeds on application startup."); - QTimer::singleShot(STARTUP_UPDATE_DELAY, this, SLOT(updateAllItems())); - } + m_sourceModel->updateFeeds(selectedFeeds()); } void FeedsView::clearSelectedFeeds() { @@ -290,10 +282,6 @@ void FeedsView::markAllItemsRead() { markAllItemsReadStatus(RootItem::Read); } -void FeedsView::clearAllReadMessages() { - m_sourceModel->markItemCleared(m_sourceModel->rootItem(), true); -} - void FeedsView::openSelectedItemsInNewspaperMode() { QList messages = m_sourceModel->messagesForFeeds(selectedFeeds()); diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index 926e0195c..0f85374d4 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -68,7 +68,6 @@ class FeedsView : public QTreeView { // Feed updating. void updateAllItems(); - void updateAllItemsOnStartup(); void updateSelectedItems(); // Feed read/unread manipulators. @@ -82,7 +81,6 @@ class FeedsView : public QTreeView { // Feed clearers. void clearSelectedFeeds(); void clearAllFeeds(); - void clearAllReadMessages(); // Base manipulators. void editSelectedItem(); @@ -96,9 +94,6 @@ class FeedsView : public QTreeView { void switchVisibility(); signals: - // Emitted if user/application requested updating of some feeds. - void feedsUpdateRequested(const QList feeds); - // Emitted if user selects new feeds. void itemSelected(RootItem *item); From 7ea94ef42f4095262788f3060e7d6788b07ce7a4 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 23 Nov 2015 19:10:16 +0100 Subject: [PATCH 066/203] Refactored DB cleaner. --- src/core/feedsmodel.cpp | 38 +++++++++++++++++++++++++++++++++- src/core/feedsmodel.h | 7 ++++++- src/gui/feedmessageviewer.cpp | 39 +++-------------------------------- src/gui/feedmessageviewer.h | 6 ------ src/gui/messagesview.cpp | 5 +---- 5 files changed, 47 insertions(+), 48 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 09a5b10e6..95bdf6dd5 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -24,6 +24,7 @@ #include "services/standard/standardserviceroot.h" #include "miscellaneous/textfactory.h" #include "miscellaneous/databasefactory.h" +#include "miscellaneous/databasecleaner.h" #include "miscellaneous/iconfactory.h" #include "miscellaneous/mutex.h" #include "gui/messagebox.h" @@ -44,7 +45,9 @@ FeedsModel::FeedsModel(QObject *parent) - : QAbstractItemModel(parent), m_autoUpdateTimer(new QTimer(this)), m_feedDownloaderThread(NULL), m_feedDownloader(NULL) { + : QAbstractItemModel(parent), m_autoUpdateTimer(new QTimer(this)), + m_feedDownloaderThread(NULL), m_feedDownloader(NULL), + m_dbCleanerThread(NULL), m_dbCleaner(NULL) { setObjectName(QSL("FeedsModel")); // Create root item. @@ -98,12 +101,27 @@ void FeedsModel::quit() { } } + if (m_dbCleanerThread != NULL && m_dbCleanerThread->isRunning()) { + qDebug("Quitting database cleaner thread."); + m_dbCleanerThread->quit(); + + if (!m_dbCleanerThread->wait(CLOSE_LOCK_TIMEOUT)) { + qCritical("Database cleaner thread is running despite it was told to quit. Terminating it."); + m_dbCleanerThread->terminate(); + } + } + // Close workers. if (m_feedDownloader != NULL) { qDebug("Feed downloader exists. Deleting it from memory."); m_feedDownloader->deleteLater(); } + if (m_dbCleaner != NULL) { + qDebug("Database cleaner exists. Deleting it from memory."); + m_dbCleaner->deleteLater(); + } + if (qApp->settings()->value(GROUP(Messages), SETTING(Messages::ClearReadOnExit)).toBool()) { markItemCleared(m_rootItem, true); } @@ -167,6 +185,24 @@ void FeedsModel::updateAllFeeds() { updateFeeds(m_rootItem->getSubTreeFeeds()); } + +DatabaseCleaner *FeedsModel::databaseCleaner() { + if (m_dbCleaner == NULL) { + m_dbCleaner = new DatabaseCleaner(); + m_dbCleanerThread = new QThread(); + + // Downloader setup. + qRegisterMetaType("CleanerOrders"); + m_dbCleaner->moveToThread(m_dbCleanerThread); + connect(m_dbCleanerThread, SIGNAL(finished()), m_dbCleanerThread, SLOT(deleteLater())); + + // Connections are made, start the feed downloader thread. + m_dbCleanerThread->start(); + } + + return m_dbCleaner; +} + void FeedsModel::executeNextAutoUpdate() { if (!qApp->feedUpdateLock()->tryLock()) { qDebug("Delaying scheduled feed auto-updates for one minute due to another running update."); diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 412aa7b36..75ec450c7 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -24,7 +24,7 @@ #include "core/rootitem.h" #include "core/feeddownloader.h" - +class DatabaseCleaner; class Category; class Feed; class ServiceRoot; @@ -139,6 +139,8 @@ class FeedsModel : public QAbstractItemModel { // Schedules all feeds from all accounts for update. void updateAllFeeds(); + DatabaseCleaner *databaseCleaner(); + // Adds given service root account. bool addServiceAccount(ServiceRoot *root); @@ -209,6 +211,9 @@ class FeedsModel : public QAbstractItemModel { QThread *m_feedDownloaderThread; FeedDownloader *m_feedDownloader; + + QThread *m_dbCleanerThread; + DatabaseCleaner *m_dbCleaner; }; #endif // FEEDSMODEL_H diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index f956974ed..1ac26e82e 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -64,9 +64,7 @@ FeedMessageViewer::FeedMessageViewer(QWidget *parent) m_toolBarMessages(new MessagesToolBar(tr("Toolbar for messages"), this)), m_messagesView(new MessagesView(this)), m_feedsView(new FeedsView(this)), - m_messagesBrowser(new WebBrowser(this)), - m_dbCleanerThread(NULL), - m_dbCleaner(NULL) { + m_messagesBrowser(new WebBrowser(this)) { initialize(); initializeViews(); loadMessageViewerFonts(); @@ -77,23 +75,6 @@ FeedMessageViewer::~FeedMessageViewer() { qDebug("Destroying FeedMessageViewer instance."); } -DatabaseCleaner *FeedMessageViewer::databaseCleaner() { - if (m_dbCleaner == NULL) { - m_dbCleaner = new DatabaseCleaner(); - m_dbCleanerThread = new QThread(); - - // Downloader setup. - qRegisterMetaType("CleanerOrders"); - m_dbCleaner->moveToThread(m_dbCleanerThread); - connect(m_dbCleanerThread, SIGNAL(finished()), m_dbCleanerThread, SLOT(deleteLater())); - - // Connections are made, start the feed downloader thread. - m_dbCleanerThread->start(); - } - - return m_dbCleaner; -} - void FeedMessageViewer::saveSize() { Settings *settings = qApp->settings(); @@ -148,21 +129,7 @@ void FeedMessageViewer::loadMessageViewerFonts() { void FeedMessageViewer::quit() { // Quit the feeds model (stops auto-update timer etc.). m_feedsView->sourceModel()->quit(); - - if (m_dbCleanerThread != NULL && m_dbCleanerThread->isRunning()) { - qDebug("Quitting database cleaner thread."); - m_dbCleanerThread->quit(); - - if (!m_dbCleanerThread->wait(CLOSE_LOCK_TIMEOUT)) { - qCritical("Database cleaner thread is running despite it was told to quit. Terminating it."); - m_dbCleanerThread->terminate(); - } - } - - if (m_dbCleaner != NULL) { - qDebug("Database cleaner exists. Deleting it from memory."); - m_dbCleaner->deleteLater(); - } + } bool FeedMessageViewer::areToolBarsEnabled() const { @@ -428,7 +395,7 @@ void FeedMessageViewer::initializeViews() { void FeedMessageViewer::showDbCleanupAssistant() { if (qApp->feedUpdateLock()->tryLock()) { QPointer form_pointer = new FormDatabaseCleanup(this); - form_pointer.data()->setCleaner(databaseCleaner()); + form_pointer.data()->setCleaner(m_feedsView->sourceModel()->databaseCleaner()); form_pointer.data()->exec(); delete form_pointer.data(); diff --git a/src/gui/feedmessageviewer.h b/src/gui/feedmessageviewer.h index 5d81e6ebb..83b07baa1 100755 --- a/src/gui/feedmessageviewer.h +++ b/src/gui/feedmessageviewer.h @@ -29,7 +29,6 @@ class MessagesView; class MessagesToolBar; class FeedsToolBar; class FeedsView; -class DatabaseCleaner; class StandardFeed; class QToolBar; class QSplitter; @@ -65,8 +64,6 @@ class FeedMessageViewer : public TabContent { return m_toolBarFeeds; } - DatabaseCleaner *databaseCleaner(); - // Loads/saves sizes and states of ALL // underlying widgets, this contains primarily // splitters, toolbar and views. @@ -134,9 +131,6 @@ class FeedMessageViewer : public TabContent { QWidget *m_feedsWidget; QWidget *m_messagesWidget; WebBrowser *m_messagesBrowser; - - QThread *m_dbCleanerThread; - DatabaseCleaner *m_dbCleaner; }; #endif // FEEDMESSAGEVIEWER_H diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index 39e1bcbdd..d60d38938 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -349,9 +349,6 @@ void MessagesView::setSelectedMessagesReadStatus(RootItem::ReadStatus read) { m_batchUnreadSwitch = false; } - -// TODO: restore messages je uplně stejně jako tahle fce -// akorat se vola jina metoda na source modelu. void MessagesView::deleteSelectedMessages() { QModelIndex current_index = selectionModel()->currentIndex(); @@ -409,7 +406,7 @@ void MessagesView::reselectIndexes(const QModelIndexList &indexes) { QItemSelection selection; foreach (const QModelIndex &index, indexes) { - // TODO: THIS IS very slow. Try to select 4000 messages and hit "mark as read" button. + // FIXME: THIS IS very slow. Try to select 4000 messages and hit "mark as read" button. selection.merge(QItemSelection(index, index), QItemSelectionModel::Select); } From 6abe99ed54bacebd7f742713636a4682664055d8 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 23 Nov 2015 19:31:03 +0100 Subject: [PATCH 067/203] Restoring of individual messages added. --- src/core/messagesmodel.cpp | 14 ++++-- src/core/messagesmodel.h | 4 +- src/gui/dialogs/formmain.cpp | 1 + src/gui/dialogs/formmain.ui | 5 ++ src/gui/feedmessageviewer.cpp | 2 + src/gui/messagesview.cpp | 46 ++++++++++++++++--- src/gui/messagesview.h | 1 + src/services/standard/standardserviceroot.cpp | 2 + 8 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 03f9a3ec3..61169c562 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -71,6 +71,8 @@ void MessagesModel::setupFonts() { m_boldFont.setBold(true); } + + void MessagesModel::loadMessages(RootItem *item) { m_selectedItem = item; @@ -110,6 +112,10 @@ RootItem::Importance MessagesModel::messageImportance(int row_index) const { return (RootItem::Importance) data(row_index, MSG_DB_IMPORTANT_INDEX, Qt::EditRole).toInt(); } +RootItem *MessagesModel::loadedItem() const { + return m_selectedItem; +} + void MessagesModel::updateDateFormat() { if (qApp->settings()->value(GROUP(Messages), SETTING(Messages::UseCustomDate)).toBool()) { m_customDateFormat = qApp->settings()->value(GROUP(Messages), SETTING(Messages::CustomDateFormat)).toString(); @@ -360,7 +366,7 @@ bool MessagesModel::switchBatchMessageImportance(const QModelIndexList &messages } } -bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int deleted) { +bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages) { QStringList message_ids; QList message_ids_num; @@ -382,12 +388,10 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int query_read_msg.setForwardOnly(true); if (m_selectedItem->kind() != RootItemKind::Bin) { - sql_delete_query = QString(QSL("UPDATE Messages SET is_deleted = %2 WHERE id IN (%1);")).arg(message_ids.join(QSL(", ")), - QString::number(deleted)); + sql_delete_query = QString(QSL("UPDATE Messages SET is_deleted = 1 WHERE id IN (%1);")).arg(message_ids.join(QSL(", "))); } else { - sql_delete_query = QString(QSL("UPDATE Messages SET is_pdeleted = %2 WHERE id IN (%1);")).arg(message_ids.join(QSL(", ")), - QString::number(deleted)); + sql_delete_query = QString(QSL("UPDATE Messages SET is_pdeleted = 1 WHERE id IN (%1);")).arg(message_ids.join(QSL(", "))); } if (query_read_msg.exec(sql_delete_query)) { diff --git a/src/core/messagesmodel.h b/src/core/messagesmodel.h index 4f8f9871c..872d92afa 100755 --- a/src/core/messagesmodel.h +++ b/src/core/messagesmodel.h @@ -55,6 +55,8 @@ class MessagesModel : public QSqlTableModel { int messageId(int row_index) const; RootItem::Importance messageImportance(int row_index) const; + RootItem *loadedItem() const; + void updateDateFormat(); void reloadWholeLayout(); @@ -71,7 +73,7 @@ class MessagesModel : public QSqlTableModel { // NOTE: Model is reset after one of these methods is applied and // changes ARE written to the database. bool switchBatchMessageImportance(const QModelIndexList &messages); - bool setBatchMessagesDeleted(const QModelIndexList &messages, int deleted); + bool setBatchMessagesDeleted(const QModelIndexList &messages); bool setBatchMessagesRead(const QModelIndexList &messages, RootItem::ReadStatus read); bool setBatchMessagesRestored(const QModelIndexList &messages); diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index f4c0bb91f..c433d3532 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -323,6 +323,7 @@ void FormMain::setupIcons() { m_ui->m_actionSelectPreviousMessage->setIcon(icon_theme_factory->fromTheme(QSL("go-up"))); m_ui->m_actionShowOnlyUnreadItems->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-unread"))); m_ui->m_actionExpandCollapseItem->setIcon(icon_theme_factory->fromTheme(QSL("expand-collapse"))); + m_ui->m_actionRestoreSelectedMessages->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-restore-one"))); // Setup icons for underlying components: opened web browsers... foreach (WebBrowser *browser, WebBrowser::runningWebBrowsers()) { diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index 822e25ad4..606060f19 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -643,6 +643,11 @@ &Edit selected service account + + + &Restore selected messages + + diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 1ac26e82e..897081281 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -313,6 +313,8 @@ void FeedMessageViewer::createConnections() { this, SLOT(switchMessageSplitterOrientation())); connect(form_main->m_ui->m_actionShowOnlyUnreadItems, SIGNAL(toggled(bool)), this, SLOT(toggleShowOnlyUnreadFeeds())); + connect(form_main->m_ui->m_actionRestoreSelectedMessages, SIGNAL(triggered()), + m_messagesView, SLOT(restoreSelectedMessages())); } void FeedMessageViewer::initialize() { diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index d60d38938..5458c6b76 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -140,16 +140,18 @@ void MessagesView::contextMenuEvent(QContextMenuEvent *event) { return; } - if (m_contextMenu == NULL) { - // Context menu is not initialized, initialize. - initializeContextMenu(); - } + // Context menu is not initialized, initialize. + initializeContextMenu(); m_contextMenu->exec(event->globalPos()); } void MessagesView::initializeContextMenu() { - m_contextMenu = new QMenu(tr("Context menu for messages"), this); + if (m_contextMenu == NULL) { + m_contextMenu = new QMenu(tr("Context menu for messages"), this); + } + + m_contextMenu->clear(); m_contextMenu->addActions(QList() << qApp->mainForm()->m_ui->m_actionSendMessageViaEmail << qApp->mainForm()->m_ui->m_actionOpenSelectedSourceArticlesExternally << @@ -159,6 +161,10 @@ void MessagesView::initializeContextMenu() { qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsUnread << qApp->mainForm()->m_ui->m_actionSwitchImportanceOfSelectedMessages << qApp->mainForm()->m_ui->m_actionDeleteSelectedMessages); + + if (m_sourceModel->loadedItem() != NULL && m_sourceModel->loadedItem()->kind() == RootItemKind::Bin) { + m_contextMenu->addAction(qApp->mainForm()->m_ui->m_actionRestoreSelectedMessages); + } } void MessagesView::mousePressEvent(QMouseEvent *event) { @@ -359,7 +365,35 @@ void MessagesView::deleteSelectedMessages() { QModelIndexList selected_indexes = selectionModel()->selectedRows(); QModelIndexList mapped_indexes = m_proxyModel->mapListToSource(selected_indexes); - m_sourceModel->setBatchMessagesDeleted(mapped_indexes, 1); + m_sourceModel->setBatchMessagesDeleted(mapped_indexes); + sortByColumn(header()->sortIndicatorSection(), header()->sortIndicatorOrder()); + + int row_count = m_sourceModel->rowCount(); + if (row_count > 0) { + QModelIndex last_item = current_index.row() < row_count ? + m_proxyModel->index(current_index.row(), MSG_DB_TITLE_INDEX) : + m_proxyModel->index(row_count - 1, MSG_DB_TITLE_INDEX); + + setCurrentIndex(last_item); + scrollTo(last_item); + reselectIndexes(QModelIndexList() << last_item); + } + else { + emit currentMessagesRemoved(); + } +} + +void MessagesView::restoreSelectedMessages() { + QModelIndex current_index = selectionModel()->currentIndex(); + + if (!current_index.isValid()) { + return; + } + + QModelIndexList selected_indexes = selectionModel()->selectedRows(); + QModelIndexList mapped_indexes = m_proxyModel->mapListToSource(selected_indexes); + + m_sourceModel->setBatchMessagesRestored(mapped_indexes); sortByColumn(header()->sortIndicatorSection(), header()->sortIndicatorOrder()); int row_count = m_sourceModel->rowCount(); diff --git a/src/gui/messagesview.h b/src/gui/messagesview.h index e2d854132..9c120ce71 100755 --- a/src/gui/messagesview.h +++ b/src/gui/messagesview.h @@ -72,6 +72,7 @@ class MessagesView : public QTreeView { void markSelectedMessagesUnread(); void switchSelectedMessagesImportance(); void deleteSelectedMessages(); + void restoreSelectedMessages(); void selectNextItem(); void selectPreviousItem(); diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 48c04cf9e..7d439bc40 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -623,6 +623,8 @@ bool StandardServiceRoot::onAfterMessagesRestoredFromBin(RootItem *selected_item Q_UNUSED(selected_item) Q_UNUSED(message_db_ids) + updateCounts(true); + emit dataChanged(getSubTree()); emit readFeedsFilterInvalidationRequested(); return true; From d9435bed41111a7d410da4247e60db48ee8905b4 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 24 Nov 2015 07:23:56 +0100 Subject: [PATCH 068/203] Some notification info update, lang reload. --- localization/rssguard-cs_CZ.ts | 1716 +++++++++---------- localization/rssguard-de_DE.ts | 2375 +++++++++++++------------- localization/rssguard-en_GB.ts | 1677 ++++++++++--------- localization/rssguard-en_US.ts | 2845 ++++++++++++++++---------------- localization/rssguard-fr_FR.ts | 2253 +++++++++++++------------ localization/rssguard-it_IT.ts | 2253 +++++++++++++------------ localization/rssguard-nl_NL.ts | 1742 +++++++++---------- localization/rssguard-sv_SE.ts | 1741 +++++++++---------- resources/text/CHANGELOG | 1 + src/core/feeddownloader.cpp | 8 +- 10 files changed, 8626 insertions(+), 7985 deletions(-) diff --git a/localization/rssguard-cs_CZ.ts b/localization/rssguard-cs_CZ.ts index 19e1a9560..01e69ac57 100644 --- a/localization/rssguard-cs_CZ.ts +++ b/localization/rssguard-cs_CZ.ts @@ -198,29 +198,6 @@ Berte také na paměti, že některé prostředky webových stránek jsou intern Obnovení nastavení nebylo spuštěno. Ujistěte se, že cílový adresář je zapisovatelný. - - Category - - %1 (category)%2%3 - Tooltip for standard feed. - %1 (kategorie)%2%3 - - - -This category does not contain any nested items. - -Tato kategorie neobsahuje žádné položky. - - - %n unread message(s). - Tooltip for "unread" column of feed list. - - %n nepřečtená zpráva. - %n nepřečtené zprávy. - %n nepřečtených zpráv. - - - DatabaseCleaner @@ -448,82 +425,16 @@ Klikněte sem pro otevření nadřazeného adresáře. - - Feed - - does not use auto-update - Describes feed auto-update status. - nepoužívá auto-aktualizace - - - uses global settings - Describes feed auto-update status. - používá globální nastavení - - - uses specific settings (%n minute(s) to next auto-update) - Describes feed auto-update status. - - používá specifické nastavení (%n minuta do další aktualizace) - používá specifické nastavení (%n minuty do další aktualizace) - používá specifické nastavení (%n minut do další aktualizace) - - - - %1 (%2)%3 - -Network status: %6 -Encoding: %4 -Auto-update status: %5 - Tooltip for feed. - %1 (%2)%3 - -Síťový status: %6 -Kódování: %4 -Automatický update: %5 - - - %n unread message(s). - Tooltip for "unread" column of feed list. - - %n nepřečtená zpráva. - %n nepřečtené zprávy. - %n nepřečtených zpráv. - - - - Metadata not fetched - Metadata nezískána - - - Metadata was not fetched because: %1 - Metadata nezískána, protože: %1 - - FeedMessageViewer Toolbar for messages Panel zpráv - - Feed update started - Text display in status bar when feed update is started. - Spuštěn update kanálů - - - Updated feed '%1' - Text display in status bar when particular feed is updated. - Aktualizován kanál '%1' - Toolbar for feeds Panel kanálů - - Error when loading initial feeds - Chyba při načítání úvodních kanálů - Cannot cleanup database Nelze vyčistit databázi @@ -532,18 +443,6 @@ Automatický update: %5 Cannot cleanup database, because another critical action is running. Databázi nelze v současné době vyčistit, protože běží jiná kritická akce. Zkuste to později. - - Cannot update all items - Nelze aktualizovat všechny položky - - - You cannot update all items because another another critical operation is ongoing. - Nelze aktualizovat všechny položky, protože už běží jiná kritická operace. - - - New messages downloaded - Staženy nové zprávy - FeedsImportExportModel @@ -580,18 +479,6 @@ Automatický update: %5 Name of root item of feed list which can be seen in feed add/edit dialog. Kořen - - Invalid tree data. - Chybná data stromu. - - - Import successfull, but some feeds/categories were not imported due to error. - Import byl úspěšný, ale některé kanály či kategorie nebyly importovány kvůli chybě. - - - Import was completely successfull. - Import byl zcela úspěšný. - Starting auto-update of some feeds Zahajuji auto-update některých kanálů @@ -604,6 +491,28 @@ Automatický update: %5 Budu aktualizovat %n kanálů. + + Cannot update all items + Nelze aktualizovat všechny položky + + + You cannot update all items because another another critical operation is ongoing. + Nelze aktualizovat všechny položky, protože už běží jiná kritická operace. + + + Feed update started + Text display in status bar when feed update is started. + Spuštěn update kanálů + + + Updated feed '%1' + Text display in status bar when particular feed is updated. + Aktualizován kanál '%1' + + + New messages downloaded + Staženy nové zprávy + FeedsToolBar @@ -614,14 +523,6 @@ Automatický update: %5 FeedsView - - Cannot add standard category - Nelze přidat standardní kategorii - - - Cannot add standard feed - Nelze přidat standardní kanál - Cannot edit item Nelze upravit položku @@ -630,50 +531,10 @@ Automatický update: %5 Cannot delete item Nelze smazat položku - - You are about to delete selected feed or category. - Právě se chystáte smazat vybraný kanál či kategorii. - - - Deletion of item failed. - Mazání položky selhalo. - - - Selected item was not deleted due to error. - Vybraná položka nebyla smazána kvůli chybě. - - - Do you really want to delete selected item? - Opravdu chcete vybranou položku smazat? - - - Permanently delete messages - Trvalé smazání zpráv - - - You are about to permanenty delete all messages from your recycle bin. - Chystáte se vysypat koš. - - - Do you really want to empty your recycle bin? - Opravdu chcete koš vysypat? - Context menu for empty space Kontextové menu pro prázdný prostor - - Context menu for recycle bin - Kontextové menu pro koš - - - You cannot add new standard category now because another critical operation is ongoing. - Nelze přidat novou kategorii, protože už běží jiná kritická operace. - - - You cannot add new standard feed now because another critical operation is ongoing. - Nelze přidat nový kanál, protože už běží jiná kritická operace. - Selected item cannot be edited because another critical operation is ongoing. Nelze editovat vybranou položku, protože už běží jiná kritická operace. @@ -682,14 +543,43 @@ Automatický update: %5 Selected item cannot be deleted because another critical operation is ongoing. Nelze smazat vybranou položku, protože už běží jiná kritická operace. - - Delete feed/category - Smazat kanál/kategorii - Context menu for categories Kontextové menu pro kategorie + + Selected item cannot be edited, this is not (yet?) supported. + + + + Deleting "%1" + + + + You are about to completely delete item "%1". + + + + Are you sure? + + + + Cannot delete "%1" + + + + This item cannot be deleted because something critically failed. Submit bug report. + + + + This item cannot be deleted, because it does not support it +or this functionality is not implemented yet. + + + + Context menu for other items + + FormAbout @@ -737,10 +627,6 @@ Automatický update: %5 <b>%8</b><br><b>Version:</b> %1 (build on %2 with CMake %3)<br><b>Revision:</b> %4<br><b>Build date:</b> %5<br><b>Qt:</b> %6 (compiled against %7)<br> <b>%8</b><br><b>Verze:</b> %1 (při sestavování použit OS %2 a CMake %3)<br><b>Revize:</b> %4<br><b>Datum sestavení:</b> %5<br><b>Qt:</b> %6 (při kompilaci %7)<br> - - <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~email</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> - <body>%5 je (velmi) jednoduduchá čtečka kanálů.<br><br>Tato aplikace je šířena pod podmínkami licence GNU General Public License, verze 3.<br><br>Kontakty:<ul><li><a href="mailto://%1">%1</a> ~email</li><li><a href="%2">%2</a> ~web</li></ul>Zdrojové kódy pro %5 je možné získat z jeho webu.<br><br><br>Copyright (C) 2011-%3 %4</body> - About %1 About RSS Guard dialog title. @@ -770,6 +656,10 @@ Automatický update: %5 Resources Zdroje + + <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~e-mail</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> + <body>%5 je (velmi) lehkotonážní prohlížeč kanálů.<br><br>Tento software je distribuován pod licencí GNU General Public License, verze 3.<br><br>Kontakty:<ul><li><a href="mailto://%1">%1</a> ~e-mail</li><li><a href="%2">%2</a> ~web</li></ul>Zdrojový kór pro %5 lze získat na jeho webu.<br><br><br>Copyright (C) 2011-%3 %4</body> + FormBackupDatabaseSettings @@ -846,134 +736,6 @@ Automatický update: %5 Je zvolen vhodný výstupní adresář. - - FormCategoryDetails - - Parent category - Nadřazená kategorie - - - Select parent item for your category. - Zvolte nadřazenou kategorii pro Vaši kategorii. - - - Title - Nadpis - - - Description - Popis - - - Icon - Ikona - - - Select icon for your category. - Zvolte ikonu pro Vaši kategorii. - - - Add new category - Přidat novou kategorii - - - Edit existing category - Upravit existující kategorii - - - Cannot add category - Nelze přidat kategorii - - - Category was not added due to error. - Kategorie nebyla přidána kvůli chybě. - - - Cannot edit category - Nelze upravit kategorii - - - Category was not edited due to error. - Kategorie nebyla upravena kvůli chybě. - - - Category name is ok. - Název kategorie je v pořádku. - - - Category name is too short. - Název kategorie je příliš krátký. - - - Description is empty. - Popis je prázdný. - - - Select icon file for the category - Zvolte ikonu pro Vaši kategorii - - - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - Obrázky (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - - - Select icon - Vybrat ikonu - - - Cancel - Zrušit - - - Look in: - Label to describe the folder for icon file selection dialog. - Hledat v: - - - Icon name: - Název ikony: - - - Icon type: - Typ ikony: - - - Category title - Název kategorie - - - Set title for your category. - Zvolte název pro Vaši kategorii. - - - Category description - Popis kategorie - - - Set description for your category. - Zvolte popis Vaší kategorie. - - - Icon selection - Vybrat ikonu - - - Load icon from file... - Načíst ikonu ze souboru... - - - Do not use icon - Nepoužít ikonu - - - Use default icon - Použít výchozí ikonu - - - The description is ok. - Popis je v pořádku. - - FormDatabaseCleanup @@ -1045,389 +807,6 @@ Automatický update: %5 Vymazat všechny důležité zprávy (včetně těch z koše) - - FormFeedDetails - - Parent category - Nadřazená kategorie - - - Select parent item for your feed. - Zvolte nadřazenou kategorii pro Váš kanál. - - - Type - Typ - - - Select type of the standard feed. - Zvolte typ standardního kanálu. - - - Encoding - Kódování - - - Select encoding of the standard feed. If you are unsure about the encoding, then select "UTF-8" encoding. - Zvolte kódování kanálu. Pokud si nejste jisti, tak zvolte kódování "UTF-8". - - - Auto-update - Auto-aktualizace - - - Select the auto-update strategy for this feed. Default auto-update strategy means that the feed will be update in time intervals set in application settings. - Zvolte strategii auto-aktualizací tohoto kanálu. Výchozí strategorie auto-aktualizace znamená, že kanál bude aktualizován v intervalech udaných v nastavení aplikace. - - - minutes - minut - - - Title - Nadpis - - - Description - Popis - - - URL - - - - Fetch it now - Načíst nyní - - - Icon - Ikona - - - Select icon for your feed. - Zvolte ikonu pro Váš kanál. - - - Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. - Některé kanály vyžaduje autentizaci, a to včetně kanálů pro GMail. Je podporována autentizace BASIC, NTLM-2 a DIGEST-MD5. - - - Requires authentication - Vyžaduje autentizaci - - - Username - Uživatelské jméno - - - Password - Heslo - - - Fetch metadata - Načíst metadata - - - Add new feed - Přidat nový kanál - - - Edit existing feed - Upravit existující kanál - - - Feed name is ok. - Název kanálu je v pořádku. - - - Feed name is too short. - Název kanálu je příliš krátký. - - - Description is empty. - Popis je prázdný. - - - The url is ok. - Url je v pořádku. - - - The url does not meet standard pattern. Does your url start with "http://" or "https://" prefix. - Url neobsahuje standardní schéma. Začíná Vaše url schématem "http://" nebo "https://". - - - The url is empty. - Url je prázdné. - - - Username is ok or it is not needed. - Uživatelské jméno je v pořádku nebo není třeba. - - - Username is empty. - Uživatelské jméno je prázdné. - - - Password is ok or it is not needed. - Heslo je v pořádku nebo není třeba. - - - Password is empty. - Heslo je prázdné. - - - Select icon file for the feed - Vybrat ikonu pro kanál - - - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - Obrázky (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - - - Select icon - Vybrat ikonu - - - Cancel - Zrušit - - - Look in: - Label for field with icon file name textbox for selection dialog. - Hledat v: - - - Icon name: - Název ikony: - - - Icon type: - Typ ikony: - - - Cannot add feed - Nelze přidat kanál - - - Feed was not added due to error. - Kanál nepřidán kvůli chybě. - - - Cannot edit feed - Nelze upravit kanál - - - All metadata fetched successfully. - Metadata stažena úspěšně. - - - Feed and icon metadata fetched. - Metadata a ikona staženy. - - - Result: %1. - Výsledek: %1. - - - Feed or icon metatada not fetched. - Metadata nebo ikona nestaženy. - - - Error: %1. - Chyba: %1. - - - No metadata fetched. - Žádná metadata nestažena. - - - Feed title - Název kanálu - - - Set title for your feed. - Zvolte název pro Váš kanál. - - - Feed description - Popis kanálu - - - Set description for your feed. - Zvolte popis Vašeho kanálu. - - - Full feed url including scheme - Plné url kanálu včetně schématu - - - Set url for your feed. - Zvolte url Vašeho kanálu. - - - Set username to access the feed. - Nastavte uživatelské jméno pro tento kanál. - - - Set password to access the feed. - Nastavte heslo pro tento kanál. - - - Icon selection - Vybrat ikonu - - - Load icon from file... - Načíst ikonu ze souboru... - - - Do not use icon - Nepoužít ikonu - - - Use default icon - Použít výchozí ikonu - - - No metadata fetched so far. - Metadata doposud nenačtena. - - - Auto-update using global interval - Auto-aktualizovat dle hlavního nastavení - - - Auto-update every - Auto-aktualizovat každých - - - Do not auto-update at all - Zakázat auto-aktualizace - - - The description is ok. - Popis je v pořádku. - - - Feed was not edited due to error. - Kanál nebyl upraven kvůli chybě. - - - Icon fetched successfully. - Ikona úspěšně stažena. - - - Icon metadata fetched. - Metadata ikony načtena. - - - Icon metatada not fetched. - Metadata ikony nenačtena. - - - No icon fetched. - Ikona nestažena. - - - Fetch icon from feed - Stáhnout ikonu online z kanálu - - - - FormImportExport - - &Select file - &Zvolit soubor - - - Operation results - Výsledky operací - - - No file is selected. - Nevybrán žádný soubor. - - - No operation executed yet. - Doposud neprovedena žádná operace. - - - Export feeds - Exportovat kanály - - - Destination file - Cílový soubor - - - Source feeds && categories - Zdrojové kanály && kategorie - - - Source file - Zdrojový soubor - - - Target feeds && categories - Cílové kanály && kategorie - - - Import feeds - Importovat kanály - - - OPML 2.0 files (*.opml) - soubory OPML 2.0 (*.opml) - - - Select file for feeds export - Zvolit soubor pro export kanálů - - - File is selected. - Soubor je vybrán. - - - Select file for feeds import - Zvolit soubot pro import kanálů - - - Cannot open source file. - Zdrojový soubor nelze otevřít. - - - Feeds were loaded. - Kanály načteny. - - - Error, file is not well-formed. Select another file. - Chyba, soubor nemá správný formát, zvolte jiný. - - - Error occurred. File is not well-formed. Select another file. - Chyba, soubor nemá správný formát, zvolte jiný. - - - Feeds were exported successfully. - Kanály byly úspěšně exportovány. - - - Cannot write into destination file. - Do cílového souboru nelze zapisovat. - - - Critical error occurred. - Vyskytla se kritická chyba. - - - &Check all items - &Označit vše - - - &Uncheck all items - O&dznačit vše - - FormMain @@ -1506,18 +885,6 @@ Automatický update: %5 Fee&ds && categories Kanály && ka&tegorie - - Mark all messages (without message filters) from selected feeds as read. - Označit všechny zprávy (i přes filtry zpráv) z vybraných kanálů jako přečtené. - - - Mark all messages (without message filters) from selected feeds as unread. - Označit všechny zprávy (i přes filtry zpráv) z vybraných kanálů jako nepřečtené. - - - Displays all messages from selected feeds/categories in a new "newspaper mode" tab. Note that messages are not set as read automatically. - Zobrazí všechny zprávy z vybraných kanálů/kategorií v "novinovém" náhledu. Všechny zprávy budou automaticky označeny jako přečtené. - Hides main window if it is visible and shows it if it is hidden. Skryje hlavní ikno, je-li aktuálně viditelné. Jinak jej zobrazí. @@ -1542,34 +909,6 @@ Automatický update: %5 &Delete selected messages Sma&zat vybrané zprávy - - Deletes all messages from selected feeds. - Smaže všechny zprávy z vybraných kanálů. - - - Marks all messages in all feeds read. This does not take message filters into account. - Označí všechny zprávy ve všech kanálech jako přečtené. Tato funkce nemusí brát v potaz případně filtry zpráv. - - - Deletes all messages from all feeds. - Smaže všechny zprávy ze všech kanálů. - - - Update &all feeds - Aktualizovat všechny k&anály - - - Update &selected feeds - Aktualizovat vy&brané kanály - - - &Edit selected feed/category - Up&ravit vybraný kanál/kategorii - - - &Delete selected feed/category - Smazat vybraný kaná&l/kategorii - Settings Nastavení @@ -1578,10 +917,6 @@ Automatický update: %5 Hides or displays the main menu. Skryje či zobrazí hlavní menu. - - Add &new feed/category - &Přidat novou položku - &Close all tabs except current one &Zavřít všechny taby až na ten aktivní @@ -1598,18 +933,6 @@ Automatický update: %5 Mark &selected messages as &unread Označit vybrané zprávy jako &nepřečtené - - &Mark selected feeds as read - Označit vybrané kanály jako &přečtené - - - &Mark selected feeds as unread - Označit vybrané kanály jako &nepřečtené - - - &Clean selected feeds - &Vyčistit vybrané kanály - Open selected source articles in &external browser &Otevřít vybrané zdrojové články v externím prohlížeči @@ -1622,26 +945,6 @@ Automatický update: %5 Open selected source articles in &internal browser &Otevřít vybrané zdrojové články v interním prohlížeči - - &Mark all feeds as &read - Označit všechny kanály jako &přečtené - - - View selected feeds in &newspaper mode - Zobrazit vybrané kanály v &novinovém náhledu - - - &Clean all feeds - &Vyčistit všechny kanály - - - Select &next feed/category - Vybrat &další kanál/kategorii - - - Select &previous feed/category - Vybrat &předchozí kanál/kategorii - Select &next message Vybrat &další zprávu @@ -1694,22 +997,6 @@ Automatický update: %5 Cannot open external browser. Navigate to application website manually. Externí webový prohlížeč nelze otevřít. Zkontrolujte aktualizace ručně na webu programu. - - New &feed - Nový &kanál - - - Add new feed. - Přidat nový kanál. - - - New &category - No&vá kategorie - - - Add new category. - Přidat novou kategorii. - &Toolbars &Nástrojové lišty @@ -1722,30 +1009,10 @@ Automatický update: %5 &Feed/message list headers &Hlavičky seznamů zpráv/kanálů - - &Import feeds - &Importovat kanály - - - Imports feeds you want from selected file. - Importuje kanály ze souboru. - - - &Export feeds - &Exportovat kanály - - - Exports feeds you want to selected file. - Exportuje kanály do souboru. - Close all tabs except current one. Zavřít všechny taby kromě aktivního. - - &Recycle bin - &Koš - Report a &bug (GitHub)... Nahlásit &chybu (GitHub)... @@ -1762,18 +1029,6 @@ Automatický update: %5 Display &wiki Zobrazit &wiki - - &Empty recycle bin - &Vysypat koš - - - &Restore all messages - &Obnovit všechny zprávy z koše - - - Restore &selected messages - Obnovit &vybrané zprávy z koše - &Restart &Restartovat @@ -1803,16 +1058,136 @@ Automatický update: %5 &Vyčistit databázi - Show only unread feeds/categories - Zobrazit pouze nepřečtené kanály/kategorie + Add &new item + - &Fetch feed metadata - &Získat metadata kanálu + &Services + - &Expand/collapse selected feed/category - &Expandovat/složit vybraný kanál/kategorii + Update &all items + + + + Ctrl+Shift+U + + + + Update &selected items + + + + Ctrl+U + + + + &Edit selected item + + + + &Delete selected item + + + + &Mark selected items as read + + + + Mark all messages (without message filters) from selected items as read. + + + + &Mark selected items as unread + + + + Mark all messages (without message filters) from selected items as unread. + + + + &Clean selected items + + + + Deletes all messages from selected items. + + + + &Mark all items as &read + + + + Marks all messages in all items read. This does not take message filters into account. + + + + View selected items in &newspaper mode + + + + Displays all messages from selected item in a new "newspaper mode" tab. Note that messages are not set as read automatically. + + + + &Clean all items + + + + Deletes all messages from all items. + + + + Ctrl+Shift+C + + + + Select &next item + + + + S + + + + Select &previous item + + + + A + + + + Show only unread items + + + + &Expand/collapse selected item + + + + E + + + + &Add new service account + + + + &Delete selected service account + + + + &Edit selected service account + + + + &Restore selected messages + + + + No possible actions + @@ -1963,10 +1338,6 @@ Automatický update: %5 Author Autor - - Email - - Socks5 @@ -2543,6 +1914,521 @@ File filter for external e-mail selection dialog. Fancy && modern popup notifications (This uses OS native notifications via D-Bus if available.) Moderní notifikace (Toto používá nativní notifikace přes D-Bus, jsou-li dostupné.) + + E-mail + + + + + FormStandardCategoryDetails + + Parent category + Nadřazená kategorie + + + Select parent item for your category. + Zvolte nadřazenou kategorii pro Vaši kategorii. + + + Title + Nadpis + + + Description + Popis + + + Icon + Ikona + + + Select icon for your category. + Zvolte ikonu pro Vaši kategorii. + + + Add new category + Přidat novou kategorii + + + Edit existing category + Upravit existující kategorii + + + Cannot add category + Nelze přidat kategorii + + + Category was not added due to error. + Kategorie nebyla přidána kvůli chybě. + + + Cannot edit category + Nelze upravit kategorii + + + Category was not edited due to error. + Kategorie nebyla upravena kvůli chybě. + + + Category name is ok. + Název kategorie je v pořádku. + + + Category name is too short. + Název kategorie je příliš krátký. + + + Description is empty. + Popis je prázdný. + + + The description is ok. + Popis je v pořádku. + + + Select icon file for the category + Zvolte ikonu pro Vaši kategorii + + + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + Obrázky (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + + + Select icon + Vybrat ikonu + + + Cancel + Zrušit + + + Look in: + Label to describe the folder for icon file selection dialog. + Hledat v: + + + Icon name: + Název ikony: + + + Icon type: + Typ ikony: + + + Category title + Název kategorie + + + Set title for your category. + Zvolte název pro Vaši kategorii. + + + Category description + Popis kategorie + + + Set description for your category. + Zvolte popis Vaší kategorie. + + + Icon selection + Vybrat ikonu + + + Load icon from file... + Načíst ikonu ze souboru... + + + Do not use icon + Nepoužít ikonu + + + Use default icon + Použít výchozí ikonu + + + + FormStandardFeedDetails + + Parent category + Nadřazená kategorie + + + Select parent item for your feed. + Zvolte nadřazenou kategorii pro Váš kanál. + + + Type + Typ + + + Select type of the standard feed. + Zvolte typ standardního kanálu. + + + Encoding + Kódování + + + Select encoding of the standard feed. If you are unsure about the encoding, then select "UTF-8" encoding. + Zvolte kódování kanálu. Pokud si nejste jisti, tak zvolte kódování "UTF-8". + + + Auto-update + Auto-aktualizace + + + Select the auto-update strategy for this feed. Default auto-update strategy means that the feed will be update in time intervals set in application settings. + Zvolte strategii auto-aktualizací tohoto kanálu. Výchozí strategorie auto-aktualizace znamená, že kanál bude aktualizován v intervalech udaných v nastavení aplikace. + + + minutes + minut + + + Title + Nadpis + + + Description + Popis + + + URL + + + + Fetch it now + Načíst nyní + + + Icon + Ikona + + + Select icon for your feed. + Zvolte ikonu pro Váš kanál. + + + Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. + Některé kanály vyžaduje autentizaci, a to včetně kanálů pro GMail. Je podporována autentizace BASIC, NTLM-2 a DIGEST-MD5. + + + Requires authentication + Vyžaduje autentizaci + + + Username + Uživatelské jméno + + + Password + Heslo + + + Fetch metadata + Načíst metadata + + + Add new feed + Přidat nový kanál + + + Edit existing feed + Upravit existující kanál + + + Feed name is ok. + Název kanálu je v pořádku. + + + Feed name is too short. + Název kanálu je příliš krátký. + + + Description is empty. + Popis je prázdný. + + + The description is ok. + Popis je v pořádku. + + + The url is ok. + Url je v pořádku. + + + The url does not meet standard pattern. Does your url start with "http://" or "https://" prefix. + Url neobsahuje standardní schéma. Začíná Vaše url schématem "http://" nebo "https://". + + + The url is empty. + Url je prázdné. + + + Username is ok or it is not needed. + Uživatelské jméno je v pořádku nebo není třeba. + + + Username is empty. + Uživatelské jméno je prázdné. + + + Password is ok or it is not needed. + Heslo je v pořádku nebo není třeba. + + + Password is empty. + Heslo je prázdné. + + + Select icon file for the feed + Vybrat ikonu pro kanál + + + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + Obrázky (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + + + Select icon + Vybrat ikonu + + + Cancel + Zrušit + + + Look in: + Label for field with icon file name textbox for selection dialog. + Hledat v: + + + Icon name: + Název ikony: + + + Icon type: + Typ ikony: + + + Cannot add feed + Nelze přidat kanál + + + Feed was not added due to error. + Kanál nepřidán kvůli chybě. + + + Cannot edit feed + Nelze upravit kanál + + + Feed was not edited due to error. + Kanál nebyl upraven kvůli chybě. + + + All metadata fetched successfully. + Metadata stažena úspěšně. + + + Feed and icon metadata fetched. + Metadata a ikona staženy. + + + Result: %1. + Výsledek: %1. + + + Feed or icon metatada not fetched. + Metadata nebo ikona nestaženy. + + + Error: %1. + Chyba: %1. + + + No metadata fetched. + Žádná metadata nestažena. + + + Icon fetched successfully. + Ikona úspěšně stažena. + + + Icon metadata fetched. + Metadata ikony načtena. + + + Icon metatada not fetched. + Metadata ikony nenačtena. + + + No icon fetched. + Ikona nestažena. + + + Feed title + Název kanálu + + + Set title for your feed. + Zvolte název pro Váš kanál. + + + Feed description + Popis kanálu + + + Set description for your feed. + Zvolte popis Vašeho kanálu. + + + Full feed url including scheme + Plné url kanálu včetně schématu + + + Set url for your feed. + Zvolte url Vašeho kanálu. + + + Set username to access the feed. + Nastavte uživatelské jméno pro tento kanál. + + + Set password to access the feed. + Nastavte heslo pro tento kanál. + + + Icon selection + Vybrat ikonu + + + Load icon from file... + Načíst ikonu ze souboru... + + + Do not use icon + Nepoužít ikonu + + + Use default icon + Použít výchozí ikonu + + + Fetch icon from feed + Stáhnout ikonu online z kanálu + + + No metadata fetched so far. + Metadata doposud nenačtena. + + + Auto-update using global interval + Auto-aktualizovat dle hlavního nastavení + + + Auto-update every + Auto-aktualizovat každých + + + Do not auto-update at all + Zakázat auto-aktualizace + + + + FormStandardImportExport + + &Select file + &Zvolit soubor + + + &Check all items + &Označit vše + + + &Uncheck all items + O&dznačit vše + + + Operation results + Výsledky operací + + + No file is selected. + Nevybrán žádný soubor. + + + No operation executed yet. + Doposud neprovedena žádná operace. + + + Destination file + Cílový soubor + + + Source feeds && categories + Zdrojové kanály && kategorie + + + Export feeds + Exportovat kanály + + + Source file + Zdrojový soubor + + + Target feeds && categories + Cílové kanály && kategorie + + + Import feeds + Importovat kanály + + + OPML 2.0 files (*.opml) + soubory OPML 2.0 (*.opml) + + + Select file for feeds export + Zvolit soubor pro export kanálů + + + File is selected. + Soubor je vybrán. + + + Select file for feeds import + Zvolit soubot pro import kanálů + + + Cannot open source file. + Zdrojový soubor nelze otevřít. + + + Feeds were loaded. + Kanály načteny. + + + Error, file is not well-formed. Select another file. + Chyba, soubor nemá správný formát, zvolte jiný. + + + Error occurred. File is not well-formed. Select another file. + Chyba, soubor nemá správný formát, zvolte jiný. + + + Feeds were exported successfully. + Kanály byly úspěšně exportovány. + + + Cannot write into destination file. + Do cílového souboru nelze zapisovat. + + + Critical error occurred. + Vyskytla se kritická chyba. + FormUpdate @@ -2695,7 +2581,7 @@ Přejít na web aplikace a stáhnout jej ručně. MessagesModel Id - + Read @@ -2719,7 +2605,7 @@ Přejít na web aplikace a stáhnout jej ručně. Url - + Author @@ -2789,6 +2675,14 @@ Přejít na web aplikace a stáhnout jej ručně. List of attachments. Seznam příloh. + + Loading of messages from item '%s' failed. + + + + Loading of messages failed, maybe messages could not be downloaded. + + MessagesToolBar @@ -2962,26 +2856,35 @@ Přejít na web aplikace a stáhnout jej ručně. LANG_EMAIL rotter.martinos@gmail.com - - Load initial feeds - Načíst úvodní kanály - - - Do you want to load initial set of feeds? - Chcete načíst úvodní set kanálů? - LANG_NAME Name of language, e.g. English. Čeština - - You started %1 for the first time, now you can load initial set of feeds. - Spustili jste %1 poprvé, nyní si můžete zvolit, zda chcete nahrát výchozí sadu kanálů. + + + ++ %n other feeds. + + + + + - Welcome to %1 %2. - Vítá vás %1 %2. + Welcome to %1. + +Please, check NEW stuff included in this +version by clicking this popup notification. + + + + Welcome to %1. + Vítá vás %1. + + + Load initial set of feeds + @@ -3024,6 +2927,141 @@ Přejít na web aplikace a stáhnout jej ručně. Klikněte a stiskněte novou zkratku. + + StandardCategory + + %1 (category)%2%3 + Tooltip for standard feed. + %1 (kategorie)%2%3 + + + +This category does not contain any nested items. + +Tato kategorie neobsahuje žádné položky. + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + %n nepřečtená zpráva. + %n nepřečtené zprávy. + %n nepřečtených zpráv. + + + + + StandardFeed + + Metadata not fetched + Metadata nezískána + + + Metadata was not fetched because: %1. + Metadata nezískána, protože: %1. + + + does not use auto-update + Describes feed auto-update status. + nepoužívá auto-aktualizace + + + uses global settings + Describes feed auto-update status. + používá globální nastavení + + + uses specific settings (%n minute(s) to next auto-update) + Describes feed auto-update status. + + používá specifické nastavení (%n minuta do další aktualizace) + používá specifické nastavení (%n minuty do další aktualizace) + používá specifické nastavení (%n minut do další aktualizace) + + + + %1 (%2)%3 + +Network status: %6 +Encoding: %4 +Auto-update status: %5 + Tooltip for feed. + %1 (%2)%3 + +Síťový status: %6 +Kódování: %4 +Automatický update: %5 + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + %n nepřečtená zpráva. + %n nepřečtené zprávy. + %n nepřečtených zpráv. + + + + + StandardServiceRoot + + This is obligatory service account for standard RSS/RDF/ATOM feeds. + + + + You started %1 for the first time, now you can load initial set of feeds. + Spustili jste %1 poprvé, nyní si můžete zvolit, zda chcete nahrát výchozí sadu kanálů. + + + Do you want to load initial set of feeds? + Chcete načíst úvodní set kanálů? + + + Error when loading initial feeds + Chyba při načítání úvodních kanálů + + + This is service account for standard RSS/RDF/ATOM feeds. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + %n nepřečtená zpráva. + %n nepřečtené zprávy. + %n nepřečtených zpráv. + + + + Fetch metadata + Načíst metadata + + + Import successfull, but some feeds/categories were not imported due to error. + Import byl úspěšný, ale některé kanály či kategorie nebyly importovány kvůli chybě. + + + Import was completely successfull. + Import byl zcela úspěšný. + + + Add new category + Přidat novou kategorii + + + Add new feed + Přidat nový kanál + + + Export feeds + Exportovat kanály + + + Import feeds + Importovat kanály + + StatusBar @@ -3045,6 +3083,10 @@ Přejít na web aplikace a stáhnout jej ručně. Click the bubble for more information. Klikněte na bublinu pro více informací. + + anonymous + + SystemTrayIcon @@ -3152,6 +3194,22 @@ Nepřečtené zprávy: %2 Nejdříve ukončete otevřené modální dialogy. + + TtRssServiceRoot + + This is service account TT-RSS (TinyTiny RSS) server. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + %n nepřečtená zpráva. + %n nepřečtené zprávy. + %n nepřečtených zpráv. + + + WebBrowser diff --git a/localization/rssguard-de_DE.ts b/localization/rssguard-de_DE.ts index 78ab710be..7bb8c54f1 100644 --- a/localization/rssguard-de_DE.ts +++ b/localization/rssguard-de_DE.ts @@ -1,170 +1,172 @@ - + + + AdBlockAddSubscriptionDialog Add subscription - + Another subscription - + Entered title is okay. - + Entered title is empty. - + Entered url is okay. - + Entered url is empty. - + Title - + Titel Address - + AdBlockCustomList Custom rules - + AdBlockDialog Adblock settings - + Enable Adblock - + Note that Adblock may significantly slow this application down once you activate huge subscriptions. Too many rules is not good for performance. Also, make sure you restart application after you disable Adblock if you wish to have low memory footprint. Adblock is known to use much system memory. Also note that some resources are cached by internal web browser. Thus, after changing some rules or subscriptions they will fully apply only for new application instances. Make sure you restart RSS Guard for best Adblock experience. - + Options - + Filter rules - + Use only essential part of EasyList (for performance reasons) - + Add rule - + Remove rule - + Add subscription - + Remove subscription - + Update subscriptions - + Rules writing guide - + AdBlockIcon Adblock - + Show Adblock &settings - + Disable on %1 - + Disable only on this page - + Blocked popup windows - + %1 with (%2) - + No content blocked - + Blocked some content - click to edit rule - + Adblock - up and running - + Adblock - not running - + AdBlockSubscription Cannot load subscription! - + AdBlockTreeWidget Please write your rule here - + %1 (recently updated) - + %1 (error: %2) - + Add rule - + Remove rule - + @@ -175,92 +177,74 @@ Also note that some resources are cached by internal web browser. Thus, after ch Output directory is not writable. - + Settings file not copied to output directory successfully. - + Database file not copied to output directory successfully. - + Database restoration was not initiated. Make sure that output directory is writable. - + Settings restoration was not initiated. Make sure that output directory is writable. - - - - - Category - - %1 (category)%2%3 - Tooltip for standard feed. - - - - -This category does not contain any nested items. - - - - %n unread message(s). - Tooltip for "unread" column of feed list. - + DatabaseCleaner Shrinking database file... - + Database file shrinked... - + Removing read messages... - + Read messages purged... - + Recycle bin purged... - + Removing old messages... - + Purging recycle bin... - + Old messages purged... - + DatabaseFactory MySQL server works as expected. - + No MySQL server is running in the target destination. - + Access denied. Invalid username or password used. Access to MySQL server was denied. - + Unknown error. @@ -269,15 +253,15 @@ This category does not contain any nested items. Selected database does not exist (yet). - + MySQL/MariaDB (dedicated database) - + SQLite (embedded database) - + @@ -289,14 +273,17 @@ This category does not contain any nested items. Click me to add feeds from this website. This website contains %n feed(s). - + + + + DownloadItem Ico - + Filename @@ -304,103 +291,109 @@ This website contains %n feed(s). Error opening output file: %1 - + &Try again - + &Stop - + &Open file - + Select destination for downloaded file - + Error: %1 - + Fehler: %1. {1?} Download directory couldn't be created - + Error when saving file: %1 - + %1 of %2 (%3 per second) - %4 - + %1 of %2 - download completed - + Open &directory - + Cannot open file - + Cannot open output file. Open it manually. - + Cannot open directory - + Cannot open output directory. Open it manually. - + Download finished - + - File '%1' is downloaded. + File '%1' is downloaded. Click here to open parent directory. - + URL: %1 - + Local file: %1 - + Selection of local file cancelled. - + DownloadManager Clean up - + %n minutes remaining - + + + + %n seconds remaining - + + + + bytes - + kB @@ -416,47 +409,10 @@ Click here to open parent directory. Downloading %n file(s)... - - - - - Feed - - does not use auto-update - Describes feed auto-update status. - - - - uses global settings - Describes feed auto-update status. - - - - uses specific settings (%n minute(s) to next auto-update) - Describes feed auto-update status. - - - - %1 (%2)%3 - -Network status: %6 -Encoding: %4 -Auto-update status: %5 - Tooltip for feed. - - - - %n unread message(s). - Tooltip for "unread" column of feed list. - - - - Metadata not fetched - - - - Metadata was not fetched because: %1 - + + + + @@ -465,58 +421,32 @@ Auto-update status: %5 Toolbar for messages Toolbar für Nachrichten - - Feed update started - Text display in status bar when feed update is started. - Feed update begonnen - - - Updated feed '%1' - Text display in status bar when particular feed is updated. - Upgedateter feed '%1' - Toolbar for feeds Toolbar für Feeds - - Error when loading initial feeds - - Cannot cleanup database - + Cannot cleanup database, because another critical action is running. - - - - Cannot update all items - - - - You cannot update all items because another another critical operation is ongoing. - - - - New messages downloaded - + FeedsImportExportModel (category) - + (feed) - + Category - + @@ -539,25 +469,38 @@ Auto-update status: %5 Name of root item of feed list which can be seen in feed add/edit dialog. Wurzel - - Invalid tree data. - - - - Import successfull, but some feeds/categories were not imported due to error. - - - - Import was completely successfull. - - Starting auto-update of some feeds - + I will auto-update %n feed(s). - + + + + + + + Cannot update all items + + + + You cannot update all items because another another critical operation is ongoing. + + + + Feed update started + Text display in status bar when feed update is started. + Feed update begonnen + + + Updated feed '%1' + Text display in status bar when particular feed is updated. + Upgedateter feed '%1' + + + New messages downloaded + @@ -569,14 +512,6 @@ Auto-update status: %5 FeedsView - - Cannot add standard category - Kann die Standardkategorie nicht hinzufügen - - - Cannot add standard feed - Kann den Standard-Feed nicht hinzufügen - Cannot edit item Kann das Item nicht editieren @@ -585,65 +520,54 @@ Auto-update status: %5 Cannot delete item Item kann nicht gelöscht werden - - You are about to delete selected feed or category. - - - - Deletion of item failed. - - - - Selected item was not deleted due to error. - - - - Do you really want to delete selected item? - Möchtest du dieses Item wirklich löschen? - - - Permanently delete messages - Lösche diese Nachrichten dauerhaft - - - You are about to permanenty delete all messages from your recycle bin. - - - - Do you really want to empty your recycle bin? - Möchtest du den Mülleimer wirklich leeren? - Context menu for empty space - - - - Context menu for recycle bin - - - - You cannot add new standard category now because another critical operation is ongoing. - - - - You cannot add new standard feed now because another critical operation is ongoing. - + Selected item cannot be edited because another critical operation is ongoing. - + Selected item cannot be deleted because another critical operation is ongoing. - - - - Delete feed/category - + Context menu for categories - + + + + Selected item cannot be edited, this is not (yet?) supported. + + + + Deleting "%1" + + + + You are about to completely delete item "%1". + + + + Are you sure? + + + + Cannot delete "%1" + + + + This item cannot be deleted because something critically failed. Submit bug report. + + + + This item cannot be deleted, because it does not support it +or this functionality is not implemented yet. + + + + Context menu for other items + @@ -692,45 +616,45 @@ Auto-update status: %5 <b>%8</b><br><b>Version:</b> %1 (build on %2 with CMake %3)<br><b>Revision:</b> %4<br><b>Build date:</b> %5<br><b>Qt:</b> %6 (compiled against %7)<br> <b>%8</b><br><b>Version:</b> %1 (gebildet am %2 mit CMake %3)<br><b>Revision:</b> %4<br><b>Bildungsdatum:</b> %5<br><b>Qt:</b> %6 (kompiliert unter %7)<br> - - <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~email</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> - - About %1 About RSS Guard dialog title. - + Settings type - + Settings file - + Database root path - + FULLY portable - + PARTIALLY portable - + Resources - + + + + <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~e-mail</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> + FormBackupDatabaseSettings Backup database/settings - + Backup properties @@ -750,633 +674,125 @@ Auto-update status: %5 Backup name - + Operation results - + Common name for backup files - + No operation executed yet. - + Backup was created successfully. - + Backup name cannot be empty. - + Backup name looks okay. - + Backup failed. - + Output directory - + &Select directory - + Backup was created successfully and stored in target directory. - + Select destination directory - + Good destination directory is specified. - - - - - FormCategoryDetails - - Parent category - Stammkategorie - - - Select parent item for your category. - Selektieren Sie das Stamm-Item für Ihre Kategorie - - - Title - Titel - - - Description - Beschreibung - - - Icon - Icon - - - Select icon for your category. - Selektieren Sie das Icon für Ihre Kategorie - - - Add new category - Füge neue Kategorie hinzu - - - Edit existing category - Bearbeite bestehende Kategorie - - - Cannot add category - Kategorie kann nicht hinzugefügt werden - - - Category was not added due to error. - Kategorie wurde nicht hinzugefügt aufgrund eines Fehler. - - - Cannot edit category - Kategorie kann nicht editiert werden - - - Category was not edited due to error. - Kategorie wurde nicht editiert aufgrund eines Fehler. - - - Category name is ok. - Kategoriename ist okay. - - - Category name is too short. - Kategoriename ist zu kurz. - - - Description is empty. - Beschreibung ist leer. - - - Select icon file for the category - Selektiere die Icon-Datei für die Kategorie - - - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - Bilder (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - - - Select icon - Selektiere Icon - - - Cancel - Abbrechen - - - Look in: - Label to describe the folder for icon file selection dialog. - Schauen Sie in: - - - Icon name: - Icon-Name: - - - Icon type: - Icon-Typ: - - - Category title - Kategorietitel - - - Set title for your category. - Setzen Sie den Titel für die Kategorie. - - - Category description - Kategoriebeschreibung - - - Set description for your category. - Setzen Sie die Beschreibung für die Kategorie. - - - Icon selection - Icon-Selektion - - - Load icon from file... - Lade Icon aus Datei... - - - Do not use icon - Icon nicht verwenden - - - Use default icon - Standard-Icon verwenden - - - The description is ok. - Die Beschreibung ist OK. + FormDatabaseCleanup Cleanup database - + Remove all messages older than - + day(s) - + + + + Shrink database file - + Database information - + Database file size - + Database type - + Progress - + I am ready. - + Database cleanup is running. - + Database cleanup is completed. - + Database cleanup failed. - + Cleanup settings (all checked items are completely erased from database) - + Remove all read messages (not those from recycle bin) - + Remove all messages from recycle bin - + Remove all starred messages (including those from recycle bin) - - - - - FormFeedDetails - - Parent category - Stammkategorie - - - Select parent item for your feed. - Selektieren Sie das Stamm-Item für Ihren Feed. - - - Type - Typ - - - Select type of the standard feed. - Selektiere den Typ des Standard-Feeds. - - - Encoding - Enkodierung - - - Select encoding of the standard feed. If you are unsure about the encoding, then select "UTF-8" encoding. - Selektiere die Enkodierung des Standard-Feeds. Falls Sie unsicher sind wählen einfach die "UTF-8" Enkodierung. - - - Auto-update - Auto-Update - - - Select the auto-update strategy for this feed. Default auto-update strategy means that the feed will be update in time intervals set in application settings. - - - - minutes - Minuten - - - Title - Titel - - - Description - Beschreibung - - - URL - URL - - - Fetch it now - Jetzt abrufen - - - Icon - Icon - - - Select icon for your feed. - Selektieren Sie das Icon für Ihren Feed. - - - Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. - Gewisse Feeds brauchen eine Authentifizierung, wie z.b. Gmail-Feeds. BASIC, NTLM-2 und DIGEST-MD5 Authentifizierungsmodelle werden unterstützt. - - - Requires authentication - Benötigt Authentifizierung - - - Username - Benutzername - - - Password - Passwort - - - Fetch metadata - Metadaten abrufen - - - Add new feed - - - - Edit existing feed - - - - Feed name is ok. - Feed-Name ist okay. - - - Feed name is too short. - Feed-Name ist zu kurz. - - - Description is empty. - Beschreibung ist leer. - - - The url is ok. - Die URL ist okay. - - - The url does not meet standard pattern. Does your url start with "http://" or "https://" prefix. - Die URL entspricht nicht dem Standardmuster. Beginnt Ihre URL mit "http://" oder "https://"? - - - The url is empty. - Die URL ist leer. - - - Username is ok or it is not needed. - Benutzername ist okay oder wird nicht benötigt. - - - Username is empty. - Benutzername ist leer. - - - Password is ok or it is not needed. - Passwort ist okay oder wird nicht benötigt. - - - Password is empty. - Passwort ist leer. - - - Select icon file for the feed - Selektiere die Icon-Datei für den Feed. - - - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - Bilder (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - - - Select icon - Selektiere Icon - - - Cancel - Abbrechen - - - Look in: - Label for field with icon file name textbox for selection dialog. - Schauen Sie in: - - - Icon name: - Icon-Name: - - - Icon type: - Icon-Typ: - - - Cannot add feed - Kann Feed nicht hinzufügen - - - Feed was not added due to error. - Feed wurde nicht hinzugefügt aufgrund eines Fehler. - - - Cannot edit feed - Feed kann nicht editiert werden - - - All metadata fetched successfully. - Alle Metadaten wurden erfolgreich abgerufen. - - - Feed and icon metadata fetched. - Feed- und Icon-Metadaten abgerufen. - - - Result: %1. - Resultat: %1. - - - Feed or icon metatada not fetched. - Feed- oder Icon-Metadaten nicht abgerufen. - - - Error: %1. - Fehler: %1. - - - No metadata fetched. - Keine Metadaten abgerufen. - - - Feed title - Feed-Titel - - - Set title for your feed. - Setzen Sie den Titel für Ihren Feed. - - - Feed description - Feed-Beschreibung - - - Set description for your feed. - Setzen Sie die Beschreibung für Ihren Feed. - - - Full feed url including scheme - - - - Set url for your feed. - Setze die URL für Ihren Feed. - - - Set username to access the feed. - Setzen Sie den Benutzernamen um zum Feed zu gelangen. - - - Set password to access the feed. - Setzen Sie das Passwort um zum Feed zu gelangen. - - - Icon selection - Icon-Selektion - - - Load icon from file... - Lade Icon aus Datei... - - - Do not use icon - Icon nicht verwenden - - - Use default icon - Standard-Icon verwenden - - - No metadata fetched so far. - Bisher keine Metadaten abgerufen. - - - Auto-update using global interval - Auto-Update benutzt globales Intervall - - - Auto-update every - Auto-Update alle - - - Do not auto-update at all - Kein Auto-Update ausführen - - - The description is ok. - Die Beschreibung ist OK. - - - Feed was not edited due to error. - Feed wurde nicht editiert aufgrund eines Fehler. - - - Icon fetched successfully. - - - - Icon metadata fetched. - - - - Icon metatada not fetched. - - - - No icon fetched. - - - - Fetch icon from feed - - - - - FormImportExport - - &Select file - - - - Operation results - - - - No file is selected. - Keine Datei ausgewählt - - - No operation executed yet. - - - - Export feeds - - - - Destination file - - - - Source feeds && categories - - - - Source file - - - - Target feeds && categories - - - - Import feeds - - - - OPML 2.0 files (*.opml) - - - - Select file for feeds export - - - - File is selected. - - - - Select file for feeds import - - - - Cannot open source file. - - - - Feeds were loaded. - - - - Error, file is not well-formed. Select another file. - - - - Error occurred. File is not well-formed. Select another file. - - - - Feeds were exported successfully. - - - - Cannot write into destination file. - - - - Critical error occurred. - - - - &Check all items - - - - &Uncheck all items - + @@ -1457,18 +873,6 @@ Auto-update status: %5 Fee&ds && categories Fee&ds && Kategorien - - Mark all messages (without message filters) from selected feeds as read. - Markiere alle Nachrichten (ohne Nachrichtenfilter) der selektierten Feeds als gelesen. - - - Mark all messages (without message filters) from selected feeds as unread. - Markiere alle Nachrichten (ohne Nachrichtenfilter) der selektierten Feeds als ungelesen. - - - Displays all messages from selected feeds/categories in a new "newspaper mode" tab. Note that messages are not set as read automatically. - Zeige alle Nachrichten der selektierten Feeds/Kategorien in einem neuen Zeitungsmodusreiter an. Bemerke, dass Nachrichten nicht automatisch als gelesen gesetzt werden. - Hides main window if it is visible and shows it if it is hidden. Hauptfenster verstecken falls es sichtbar was oder sichtbar falls es versteckt war. @@ -1483,43 +887,15 @@ Auto-update status: %5 &About application - + Displays extra info about this application. - + &Delete selected messages - - - - Deletes all messages from selected feeds. - - - - Marks all messages in all feeds read. This does not take message filters into account. - - - - Deletes all messages from all feeds. - - - - Update &all feeds - - - - Update &selected feeds - - - - &Edit selected feed/category - - - - &Delete selected feed/category - + Settings @@ -1527,298 +903,334 @@ Auto-update status: %5 Hides or displays the main menu. - - - - Add &new feed/category - + &Close all tabs except current one - + &Close current tab - + Mark &selected messages as &read - + Mark &selected messages as &unread - - - - &Mark selected feeds as read - - - - &Mark selected feeds as unread - - - - &Clean selected feeds - + Open selected source articles in &external browser - + Open selected messages in &internal browser - + Open selected source articles in &internal browser - - - - &Mark all feeds as &read - - - - View selected feeds in &newspaper mode - - - - &Clean all feeds - - - - Select &next feed/category - - - - Select &previous feed/category - + Select &next message - + Select &previous message - + Check for &updates - + Enable &JavaScript - + Enable external &plugins - + Auto-load &images - + Show/hide - + &Fullscreen - + &Feed list - + &Main menu - + Switch visibility of main &window - + Cannot open external browser - + Cannot open external browser. Navigate to application website manually. - - - - New &feed - - - - Add new feed. - - - - New &category - - - - Add new category. - + &Toolbars - + Switch visibility of main toolbars. - + &Feed/message list headers - - - - &Import feeds - - - - Imports feeds you want from selected file. - - - - &Export feeds - - - - Exports feeds you want to selected file. - + Close all tabs except current one. - - - - &Recycle bin - + Report a &bug (GitHub)... - + Report a bug (BitBucket)... - + &Donate via PayPal - + Display &wiki - - - - &Empty recycle bin - - - - &Restore all messages - - - - Restore &selected messages - + &Restart - + &Restore database/settings - + &Backup database/settings - + Switch message list layout orientation - + &Downloads - + Send selected message via e-mail - + &Cleanup database - + - Show only unread feeds/categories - + Add &new item + - &Fetch feed metadata - + &Services + - &Expand/collapse selected feed/category - + Update &all items + + + + Ctrl+Shift+U + + + + Update &selected items + + + + Ctrl+U + + + + &Edit selected item + + + + &Delete selected item + + + + &Mark selected items as read + + + + Mark all messages (without message filters) from selected items as read. + + + + &Mark selected items as unread + + + + Mark all messages (without message filters) from selected items as unread. + + + + &Clean selected items + + + + Deletes all messages from selected items. + + + + &Mark all items as &read + + + + Marks all messages in all items read. This does not take message filters into account. + + + + View selected items in &newspaper mode + + + + Displays all messages from selected item in a new "newspaper mode" tab. Note that messages are not set as read automatically. + + + + &Clean all items + + + + Deletes all messages from all items. + + + + Ctrl+Shift+C + + + + Select &next item + + + + S + + + + Select &previous item + + + + A + + + + Show only unread items + + + + &Expand/collapse selected item + + + + E + + + + &Add new service account + + + + &Delete selected service account + + + + &Edit selected service account + + + + &Restore selected messages + + + + No possible actions + FormRestoreDatabaseSettings Restore database/settings - + Operation results - + Restore database - + Restore settings - + Restart - + No operation executed yet. - + Restoration was initiated. Restart to proceed. - + You need to restart application for restoration process to finish. - + Source directory - + &Select directory - + Database and/or settings were not copied to restoration directory successully. - + Select source directory - + Good source directory is specified. - + @@ -1914,10 +1326,6 @@ Auto-update status: %5 Author Author - - Email - Email - Socks5 Socks5 @@ -2037,7 +1445,7 @@ Auto-update status: %5 Parameters to executable - + some keyboard shortcuts are not unique @@ -2087,7 +1495,7 @@ Disadvantages: <li>application startup and shutdown can take little longer (max. 2 seconds).</li> </ul> Authors of this application are NOT responsible for lost data. - + in-memory database switched @@ -2243,65 +1651,65 @@ Authors of this application are NOT responsible for lost data. You did not executed any connection test yet. - + Launch %1 on operating system startup - + Enable JavaScript - + Enable external plugins based on NPAPI - + Auto-load images - + <html><head/><body><p>If unchecked, then default system-wide web browser is used.</p></body></html> - + Feeds && categories - + Message count format in feed list - + Enter format for count of messages displayed next to each feed/category in feed list. Use "%all" and "%unread" strings which are placeholders for the actual count of all (or unread) messages. - + custom external browser is not set correctly - + Toolbars - + Toolbar for feeds list - + Toolbar for messages list - + Select toolbar to edit - + Some critical settings were changed and will be applied after the application gets restarted. You have to restart manually. - + Do you want to restart now? @@ -2309,70 +1717,70 @@ You have to restart manually. Check for updates on application startup - + Use custom date/time format (overrides format loaded from active localization) - + Executables (*) File filter for external browser selection dialog. ---------- File filter for external e-mail selection dialog. - + Remove all read messages from all feeds on application exit - + When new message arrives from feed and duplicate exists, then its content is updated and new message is dropped. - + Remove duplicate messages - + Downloads - + Target directory for downloaded files - + Ask for each individual downloaded file - + Target directory where all downloaded files are saved - + &Browse - + Select downloads target directory - + &Show password - + Web browser & e-mail & proxy - + Remove junk Trolltech registry key (HKCU\Software\Trolltech) when application quits (Use at your own risk!) - + Working database - + Mouse gestures work with middle mouse button. Possible gestures are: @@ -2380,101 +1788,616 @@ File filter for external e-mail selection dialog. • next web page (drag mouse right), • reload current web page (drag mouse up), • open new web browser tab (drag mouse down). - + Use custom external web browser - + External e-mail client - + Use custom external e-mail client - + E-mail client executable - + Executable file of e-mail client - + Select client - + Placeholders: • %1 - title of selected message, • %2 - body of selected message. - + Save all downloaded files to - + Select e-mail executable - + Mozilla Thunderbird - + Working database which you have full access to. - + Working database is empty. - + Working database is ok. - + Notification position - + (Tray icon is not available.) - + Bottom-left corner - + Top-left corner - + Bottom-right corner - + Top-right corner - + Internal message browser fonts - + Standard font - + Note that speed of used MySQL server and latency of used connection medium HEAVILY influences the final performance of this application. Using slow database connections leads to bad performance when browsing feeds or messages. - + Fancy && modern popup notifications (This uses OS native notifications via D-Bus if available.) - + + + + E-mail + + + + + FormStandardCategoryDetails + + Parent category + Stammkategorie + + + Select parent item for your category. + Selektieren Sie das Stamm-Item für Ihre Kategorie + + + Title + Titel + + + Description + Beschreibung + + + Icon + Icon + + + Select icon for your category. + Selektieren Sie das Icon für Ihre Kategorie + + + Add new category + Füge neue Kategorie hinzu + + + Edit existing category + Bearbeite bestehende Kategorie + + + Cannot add category + Kategorie kann nicht hinzugefügt werden + + + Category was not added due to error. + Kategorie wurde nicht hinzugefügt aufgrund eines Fehler. + + + Cannot edit category + Kategorie kann nicht editiert werden + + + Category was not edited due to error. + Kategorie wurde nicht editiert aufgrund eines Fehler. + + + Category name is ok. + Kategoriename ist okay. + + + Category name is too short. + Kategoriename ist zu kurz. + + + Description is empty. + Beschreibung ist leer. + + + The description is ok. + Die Beschreibung ist OK. + + + Select icon file for the category + Selektiere die Icon-Datei für die Kategorie + + + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + Bilder (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + + + Select icon + Selektiere Icon + + + Cancel + Abbrechen + + + Look in: + Label to describe the folder for icon file selection dialog. + Schauen Sie in: + + + Icon name: + Icon-Name: + + + Icon type: + Icon-Typ: + + + Category title + Kategorietitel + + + Set title for your category. + Setzen Sie den Titel für die Kategorie. + + + Category description + Kategoriebeschreibung + + + Set description for your category. + Setzen Sie die Beschreibung für die Kategorie. + + + Icon selection + Icon-Selektion + + + Load icon from file... + Lade Icon aus Datei... + + + Do not use icon + Icon nicht verwenden + + + Use default icon + Standard-Icon verwenden + + + + FormStandardFeedDetails + + Parent category + Stammkategorie + + + Select parent item for your feed. + Selektieren Sie das Stamm-Item für Ihren Feed. + + + Type + Typ + + + Select type of the standard feed. + Selektiere den Typ des Standard-Feeds. + + + Encoding + Enkodierung + + + Select encoding of the standard feed. If you are unsure about the encoding, then select "UTF-8" encoding. + Selektiere die Enkodierung des Standard-Feeds. Falls Sie unsicher sind wählen einfach die "UTF-8" Enkodierung. + + + Auto-update + Auto-Update + + + Select the auto-update strategy for this feed. Default auto-update strategy means that the feed will be update in time intervals set in application settings. + + + + minutes + + + + Title + Titel + + + Description + Beschreibung + + + URL + URL + + + Fetch it now + Jetzt abrufen + + + Icon + Icon + + + Select icon for your feed. + Selektieren Sie das Icon für Ihren Feed. + + + Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. + Gewisse Feeds brauchen eine Authentifizierung, wie z.b. Gmail-Feeds. BASIC, NTLM-2 und DIGEST-MD5 Authentifizierungsmodelle werden unterstützt. + + + Requires authentication + Benötigt Authentifizierung + + + Username + Benutzername + + + Password + Passwort + + + Fetch metadata + Metadaten abrufen + + + Add new feed + + + + Edit existing feed + + + + Feed name is ok. + Feed-Name ist okay. + + + Feed name is too short. + Feed-Name ist zu kurz. + + + Description is empty. + Beschreibung ist leer. + + + The description is ok. + Die Beschreibung ist OK. + + + The url is ok. + Die URL ist okay. + + + The url does not meet standard pattern. Does your url start with "http://" or "https://" prefix. + Die URL entspricht nicht dem Standardmuster. Beginnt Ihre URL mit "http://" oder "https://"? + + + The url is empty. + Die URL ist leer. + + + Username is ok or it is not needed. + Benutzername ist okay oder wird nicht benötigt. + + + Username is empty. + Benutzername ist leer. + + + Password is ok or it is not needed. + Passwort ist okay oder wird nicht benötigt. + + + Password is empty. + Passwort ist leer. + + + Select icon file for the feed + Selektiere die Icon-Datei für den Feed. + + + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + Bilder (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + + + Select icon + Selektiere Icon + + + Cancel + Abbrechen + + + Look in: + Label for field with icon file name textbox for selection dialog. + Schauen Sie in: + + + Icon name: + Icon-Name: + + + Icon type: + Icon-Typ: + + + Cannot add feed + Kann Feed nicht hinzufügen + + + Feed was not added due to error. + Feed wurde nicht hinzugefügt aufgrund eines Fehler. + + + Cannot edit feed + Feed kann nicht editiert werden + + + Feed was not edited due to error. + Feed wurde nicht editiert aufgrund eines Fehler. + + + All metadata fetched successfully. + Alle Metadaten wurden erfolgreich abgerufen. + + + Feed and icon metadata fetched. + Feed- und Icon-Metadaten abgerufen. + + + Result: %1. + Resultat: %1. + + + Feed or icon metatada not fetched. + Feed- oder Icon-Metadaten nicht abgerufen. + + + Error: %1. + Fehler: %1. + + + No metadata fetched. + Keine Metadaten abgerufen. + + + Icon fetched successfully. + + + + Icon metadata fetched. + + + + Icon metatada not fetched. + + + + No icon fetched. + + + + Feed title + Feed-Titel + + + Set title for your feed. + Setzen Sie den Titel für Ihren Feed. + + + Feed description + Feed-Beschreibung + + + Set description for your feed. + Setzen Sie die Beschreibung für Ihren Feed. + + + Full feed url including scheme + + + + Set url for your feed. + Setze die URL für Ihren Feed. + + + Set username to access the feed. + Setzen Sie den Benutzernamen um zum Feed zu gelangen. + + + Set password to access the feed. + Setzen Sie das Passwort um zum Feed zu gelangen. + + + Icon selection + Icon-Selektion + + + Load icon from file... + Lade Icon aus Datei... + + + Do not use icon + Icon nicht verwenden + + + Use default icon + Standard-Icon verwenden + + + Fetch icon from feed + + + + No metadata fetched so far. + Bisher keine Metadaten abgerufen. + + + Auto-update using global interval + Auto-Update benutzt globales Intervall + + + Auto-update every + Auto-Update alle + + + Do not auto-update at all + Kein Auto-Update ausführen + + + + FormStandardImportExport + + &Select file + + + + &Check all items + + + + &Uncheck all items + + + + Operation results + + + + No file is selected. + Keine Datei ausgewählt + + + No operation executed yet. + + + + Destination file + + + + Source feeds && categories + + + + Export feeds + + + + Source file + + + + Target feeds && categories + + + + Import feeds + + + + OPML 2.0 files (*.opml) + + + + Select file for feeds export + + + + File is selected. + + + + Select file for feeds import + + + + Cannot open source file. + + + + Feeds were loaded. + + + + Error, file is not well-formed. Select another file. + + + + Error occurred. File is not well-formed. Select another file. + + + + Feeds were exported successfully. + + + + Cannot write into destination file. + + + + Critical error occurred. + @@ -2536,87 +2459,87 @@ die aktuell installierte. Update - + Download new installation files. - + Checking for updates failed. - + Download installation file for your OS. - + Installation file is not available directly. Go to application website to obtain it manually. - + No new update available. - + Cannot update application - + Cannot navigate to installation file. Check new installation downloads manually on project website. - + Download update - + Downloaded %1% (update size is %2 kB). - + Downloading update... - + Downloaded successfully - + Package was downloaded successfully. - + Install update - + Error occured - + Error occured during downloading of the package. - + Cannot launch external updater. Update application manually. - + Go to application website - + IOFactory Cannot open file '%1' for reading. - + Cannot open file '%1' for writting. - + @@ -2710,54 +2633,62 @@ Go to application website to obtain it manually. Permanently deleted - + Is message permanently deleted from recycle bin? - + Attachments - + List of attachments. - + + + + Loading of messages from item '%s' failed. + + + + Loading of messages failed, maybe messages could not be downloaded. + MessagesToolBar Search messages - + Message search box - + Menu for highlighting messages - + No extra highlighting - + Highlight unread messages - + Highlight important messages - + Display all messages - + Message highlighter - + Toolbar spacer @@ -2788,11 +2719,11 @@ Go to application website to obtain it manually. Problem with starting external e-mail client - + External e-mail client could not be started. - + @@ -2810,22 +2741,22 @@ Go to application website to obtain it manually. connection refused Network status. - + connection timed out Network status. - + SSL handshake failed Network status. - + proxy server connection refused Network status. - + temporary failure @@ -2835,17 +2766,17 @@ Go to application website to obtain it manually. authentication failed Network status. - + proxy authentication required Network status. - + proxy server not found Network status. - + uknown content @@ -2865,15 +2796,15 @@ Go to application website to obtain it manually. no errors Network status. - + access to content was denied - + connection timed out or was cancelled - + @@ -2897,61 +2828,198 @@ Go to application website to obtain it manually. LANG_EMAIL patlecat@gmail.com - - Load initial feeds - - - - Do you want to load initial set of feeds? - - LANG_NAME Name of language, e.g. English. Deutsch - - You started %1 for the first time, now you can load initial set of feeds. - + + + ++ %n other feeds. + + + + - Welcome to %1 %2. - + Welcome to %1. + +Please, check NEW stuff included in this +version by clicking this popup notification. + + + + Welcome to %1. + + + + Load initial set of feeds + RecycleBin Recycle bin - + Recycle bin contains all deleted messages from all feeds. - + Recycle bin %1 - + %n deleted message(s). - + + + + ShortcutCatcher Reset to original shortcut. - + Clear current shortcut. - + Click and hit new shortcut. - + + + + + StandardCategory + + %1 (category)%2%3 + Tooltip for standard feed. + + + + +This category does not contain any nested items. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + + StandardFeed + + Metadata not fetched + + + + Metadata was not fetched because: %1. + + + + does not use auto-update + Describes feed auto-update status. + + + + uses global settings + Describes feed auto-update status. + + + + uses specific settings (%n minute(s) to next auto-update) + Describes feed auto-update status. + + + + + + + %1 (%2)%3 + +Network status: %6 +Encoding: %4 +Auto-update status: %5 + Tooltip for feed. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + + StandardServiceRoot + + This is obligatory service account for standard RSS/RDF/ATOM feeds. + + + + You started %1 for the first time, now you can load initial set of feeds. + + + + Do you want to load initial set of feeds? + + + + Error when loading initial feeds + + + + This is service account for standard RSS/RDF/ATOM feeds. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + Fetch metadata + Metadaten abrufen + + + Import successfull, but some feeds/categories were not imported due to error. + + + + Import was completely successfull. + + + + Add new category + Füge neue Kategorie hinzu + + + Add new feed + + + + Export feeds + + + + Import feeds + @@ -2962,18 +3030,22 @@ Go to application website to obtain it manually. Switch application between fulscreen/normal states right from this status bar icon. - + SystemFactory New version available - + Click the bubble for more information. - + + + + anonymous + @@ -2981,7 +3053,7 @@ Go to application website to obtain it manually. %1 Unread news: %2 - + @@ -3012,42 +3084,42 @@ Unread news: %2 Displays main menu. - + Main menu - + Open new web browser tab. - + Downloads - + ToolBarEditor Activated actions - + Available actions - + Insert separator - + Insert spacer - + Separator - + Toolbar spacer @@ -3055,23 +3127,23 @@ Unread news: %2 Move action up - + Move action down - + Add selected action - + Delete selected action - + Delete all actions - + @@ -3081,6 +3153,21 @@ Unread news: %2 Schliessen Sie zuerst alle modalen Fenster. + + TtRssServiceRoot + + This is service account TT-RSS (TinyTiny RSS) server. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + WebBrowser @@ -3205,91 +3292,91 @@ Unread news: %2 Copies current selection into the clipboard. - + Copy link url to clipboard. - + Copy image to clipboard. - + Copy image url to clipboard. - + Open this hyperlink in new tab. - + Open the hyperlink in this tab. - + Open this image in this tab. - + Open link in external browser - + Open the hyperlink in external browser. - + Print - + Print current web page. - + HTML web pages (*.html) - + Select destination file for web page - + Cannot save web page - + Web page cannot be saved because destination file is not writtable. - + Save target as... - + Download content from the hyperlink. - + Save page as... - + Save image to disk. - + Save image as... - + source_page - + Search "%1" via Google... - + - \ No newline at end of file + diff --git a/localization/rssguard-en_GB.ts b/localization/rssguard-en_GB.ts index a85ae6343..0bfaa0d1b 100644 --- a/localization/rssguard-en_GB.ts +++ b/localization/rssguard-en_GB.ts @@ -196,27 +196,6 @@ Also note that some resources are cached by internal web browser. Thus, after ch - - Category - - %1 (category)%2%3 - Tooltip for standard feed. - - - - -This category does not contain any nested items. - - - - %n unread message(s). - Tooltip for "unread" column of feed list. - - - - - - DatabaseCleaner @@ -436,76 +415,16 @@ Click here to open parent directory. - - Feed - - does not use auto-update - Describes feed auto-update status. - - - - uses global settings - Describes feed auto-update status. - - - - uses specific settings (%n minute(s) to next auto-update) - Describes feed auto-update status. - - - - - - - %1 (%2)%3 - -Network status: %6 -Encoding: %4 -Auto-update status: %5 - Tooltip for feed. - - - - %n unread message(s). - Tooltip for "unread" column of feed list. - - - - - - - Metadata not fetched - - - - Metadata was not fetched because: %1 - - - FeedMessageViewer Toolbar for messages - - Feed update started - Text display in status bar when feed update is started. - - - - Updated feed '%1' - Text display in status bar when particular feed is updated. - - Toolbar for feeds - - Error when loading initial feeds - - Cannot cleanup database @@ -514,18 +433,6 @@ Auto-update status: %5 Cannot cleanup database, because another critical action is running. - - Cannot update all items - - - - You cannot update all items because another another critical operation is ongoing. - - - - New messages downloaded - - FeedsImportExportModel @@ -562,18 +469,6 @@ Auto-update status: %5 Name of root item of feed list which can be seen in feed add/edit dialog. - - Invalid tree data. - - - - Import successfull, but some feeds/categories were not imported due to error. - - - - Import was completely successfull. - - Starting auto-update of some feeds @@ -585,6 +480,28 @@ Auto-update status: %5 + + Cannot update all items + + + + You cannot update all items because another another critical operation is ongoing. + + + + Feed update started + Text display in status bar when feed update is started. + + + + Updated feed '%1' + Text display in status bar when particular feed is updated. + + + + New messages downloaded + + FeedsToolBar @@ -595,14 +512,6 @@ Auto-update status: %5 FeedsView - - Cannot add standard category - - - - Cannot add standard feed - - Cannot edit item @@ -611,50 +520,10 @@ Auto-update status: %5 Cannot delete item - - You are about to delete selected feed or category. - - - - Deletion of item failed. - - - - Selected item was not deleted due to error. - - - - Do you really want to delete selected item? - - - - Permanently delete messages - - - - You are about to permanenty delete all messages from your recycle bin. - - - - Do you really want to empty your recycle bin? - - Context menu for empty space - - Context menu for recycle bin - - - - You cannot add new standard category now because another critical operation is ongoing. - - - - You cannot add new standard feed now because another critical operation is ongoing. - - Selected item cannot be edited because another critical operation is ongoing. @@ -664,11 +533,40 @@ Auto-update status: %5 - Delete feed/category + Context menu for categories - Context menu for categories + Selected item cannot be edited, this is not (yet?) supported. + + + + Deleting "%1" + + + + You are about to completely delete item "%1". + + + + Are you sure? + + + + Cannot delete "%1" + + + + This item cannot be deleted because something critically failed. Submit bug report. + + + + This item cannot be deleted, because it does not support it +or this functionality is not implemented yet. + + + + Context menu for other items @@ -718,10 +616,6 @@ Auto-update status: %5 <b>%8</b><br><b>Version:</b> %1 (build on %2 with CMake %3)<br><b>Revision:</b> %4<br><b>Build date:</b> %5<br><b>Qt:</b> %6 (compiled against %7)<br> - - <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~email</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> - - About %1 About RSS Guard dialog title. @@ -751,6 +645,10 @@ Auto-update status: %5 Resources + + <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~e-mail</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> + + FormBackupDatabaseSettings @@ -827,134 +725,6 @@ Auto-update status: %5 - - FormCategoryDetails - - Parent category - - - - Select parent item for your category. - - - - Title - - - - Description - - - - Icon - - - - Select icon for your category. - - - - Add new category - - - - Edit existing category - - - - Cannot add category - - - - Category was not added due to error. - - - - Cannot edit category - - - - Category was not edited due to error. - - - - Category name is ok. - - - - Category name is too short. - - - - Description is empty. - - - - Select icon file for the category - - - - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - - - - Select icon - - - - Cancel - - - - Look in: - Label to describe the folder for icon file selection dialog. - - - - Icon name: - - - - Icon type: - - - - Category title - - - - Set title for your category. - - - - Category description - - - - Set description for your category. - - - - Icon selection - - - - Load icon from file... - - - - Do not use icon - - - - Use default icon - - - - The description is ok. - - - FormDatabaseCleanup @@ -1025,389 +795,6 @@ Auto-update status: %5 - - FormFeedDetails - - Parent category - - - - Select parent item for your feed. - - - - Type - - - - Select type of the standard feed. - - - - Encoding - - - - Select encoding of the standard feed. If you are unsure about the encoding, then select "UTF-8" encoding. - - - - Auto-update - - - - Select the auto-update strategy for this feed. Default auto-update strategy means that the feed will be update in time intervals set in application settings. - - - - minutes - - - - Title - - - - Description - - - - URL - - - - Fetch it now - - - - Icon - - - - Select icon for your feed. - - - - Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. - - - - Requires authentication - - - - Username - - - - Password - - - - Fetch metadata - - - - Add new feed - - - - Edit existing feed - - - - Feed name is ok. - - - - Feed name is too short. - - - - Description is empty. - - - - The url is ok. - - - - The url does not meet standard pattern. Does your url start with "http://" or "https://" prefix. - - - - The url is empty. - - - - Username is ok or it is not needed. - - - - Username is empty. - - - - Password is ok or it is not needed. - - - - Password is empty. - - - - Select icon file for the feed - - - - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - - - - Select icon - - - - Cancel - - - - Look in: - Label for field with icon file name textbox for selection dialog. - - - - Icon name: - - - - Icon type: - - - - Cannot add feed - - - - Feed was not added due to error. - - - - Cannot edit feed - - - - All metadata fetched successfully. - - - - Feed and icon metadata fetched. - - - - Result: %1. - - - - Feed or icon metatada not fetched. - - - - Error: %1. - - - - No metadata fetched. - - - - Feed title - - - - Set title for your feed. - - - - Feed description - - - - Set description for your feed. - - - - Full feed url including scheme - - - - Set url for your feed. - - - - Set username to access the feed. - - - - Set password to access the feed. - - - - Icon selection - - - - Load icon from file... - - - - Do not use icon - - - - Use default icon - - - - No metadata fetched so far. - - - - Auto-update using global interval - - - - Auto-update every - - - - Do not auto-update at all - - - - The description is ok. - - - - Feed was not edited due to error. - - - - Icon fetched successfully. - - - - Icon metadata fetched. - - - - Icon metatada not fetched. - - - - No icon fetched. - - - - Fetch icon from feed - - - - - FormImportExport - - &Select file - - - - Operation results - - - - No file is selected. - - - - No operation executed yet. - - - - Export feeds - - - - Destination file - - - - Source feeds && categories - - - - Source file - - - - Target feeds && categories - - - - Import feeds - - - - OPML 2.0 files (*.opml) - - - - Select file for feeds export - - - - File is selected. - - - - Select file for feeds import - - - - Cannot open source file. - - - - Feeds were loaded. - - - - Error, file is not well-formed. Select another file. - - - - Error occurred. File is not well-formed. Select another file. - - - - Feeds were exported successfully. - - - - Cannot write into destination file. - - - - Critical error occurred. - - - - &Check all items - - - - &Uncheck all items - - - FormMain @@ -1486,18 +873,6 @@ Auto-update status: %5 Fee&ds && categories - - Mark all messages (without message filters) from selected feeds as read. - - - - Mark all messages (without message filters) from selected feeds as unread. - - - - Displays all messages from selected feeds/categories in a new "newspaper mode" tab. Note that messages are not set as read automatically. - - Hides main window if it is visible and shows it if it is hidden. @@ -1522,34 +897,6 @@ Auto-update status: %5 &Delete selected messages - - Deletes all messages from selected feeds. - - - - Marks all messages in all feeds read. This does not take message filters into account. - - - - Deletes all messages from all feeds. - - - - Update &all feeds - - - - Update &selected feeds - - - - &Edit selected feed/category - - - - &Delete selected feed/category - - Settings @@ -1558,10 +905,6 @@ Auto-update status: %5 Hides or displays the main menu. - - Add &new feed/category - - &Close all tabs except current one @@ -1578,18 +921,6 @@ Auto-update status: %5 Mark &selected messages as &unread - - &Mark selected feeds as read - - - - &Mark selected feeds as unread - - - - &Clean selected feeds - - Open selected source articles in &external browser @@ -1602,26 +933,6 @@ Auto-update status: %5 Open selected source articles in &internal browser - - &Mark all feeds as &read - - - - View selected feeds in &newspaper mode - - - - &Clean all feeds - - - - Select &next feed/category - - - - Select &previous feed/category - - Select &next message @@ -1674,22 +985,6 @@ Auto-update status: %5 Cannot open external browser. Navigate to application website manually. - - New &feed - - - - Add new feed. - - - - New &category - - - - Add new category. - - &Toolbars @@ -1702,30 +997,10 @@ Auto-update status: %5 &Feed/message list headers - - &Import feeds - - - - Imports feeds you want from selected file. - - - - &Export feeds - - - - Exports feeds you want to selected file. - - Close all tabs except current one. - - &Recycle bin - - Report a &bug (GitHub)... @@ -1742,18 +1017,6 @@ Auto-update status: %5 Display &wiki - - &Empty recycle bin - - - - &Restore all messages - - - - Restore &selected messages - - &Restart @@ -1783,15 +1046,135 @@ Auto-update status: %5 - Show only unread feeds/categories + Add &new item - &Fetch feed metadata + &Services - &Expand/collapse selected feed/category + Update &all items + + + + Ctrl+Shift+U + + + + Update &selected items + + + + Ctrl+U + + + + &Edit selected item + + + + &Delete selected item + + + + &Mark selected items as read + + + + Mark all messages (without message filters) from selected items as read. + + + + &Mark selected items as unread + + + + Mark all messages (without message filters) from selected items as unread. + + + + &Clean selected items + + + + Deletes all messages from selected items. + + + + &Mark all items as &read + + + + Marks all messages in all items read. This does not take message filters into account. + + + + View selected items in &newspaper mode + + + + Displays all messages from selected item in a new "newspaper mode" tab. Note that messages are not set as read automatically. + + + + &Clean all items + + + + Deletes all messages from all items. + + + + Ctrl+Shift+C + + + + Select &next item + + + + S + + + + Select &previous item + + + + A + + + + Show only unread items + + + + &Expand/collapse selected item + + + + E + + + + &Add new service account + + + + &Delete selected service account + + + + &Edit selected service account + + + + &Restore selected messages + + + + No possible actions @@ -1943,10 +1326,6 @@ Auto-update status: %5 Author - - Email - - Socks5 @@ -2503,6 +1882,521 @@ File filter for external e-mail selection dialog. Fancy && modern popup notifications (This uses OS native notifications via D-Bus if available.) + + E-mail + + + + + FormStandardCategoryDetails + + Parent category + + + + Select parent item for your category. + + + + Title + + + + Description + + + + Icon + + + + Select icon for your category. + + + + Add new category + + + + Edit existing category + + + + Cannot add category + + + + Category was not added due to error. + + + + Cannot edit category + + + + Category was not edited due to error. + + + + Category name is ok. + + + + Category name is too short. + + + + Description is empty. + + + + The description is ok. + + + + Select icon file for the category + + + + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + + + + Select icon + + + + Cancel + + + + Look in: + Label to describe the folder for icon file selection dialog. + + + + Icon name: + + + + Icon type: + + + + Category title + + + + Set title for your category. + + + + Category description + + + + Set description for your category. + + + + Icon selection + + + + Load icon from file... + + + + Do not use icon + + + + Use default icon + + + + + FormStandardFeedDetails + + Parent category + + + + Select parent item for your feed. + + + + Type + + + + Select type of the standard feed. + + + + Encoding + + + + Select encoding of the standard feed. If you are unsure about the encoding, then select "UTF-8" encoding. + + + + Auto-update + + + + Select the auto-update strategy for this feed. Default auto-update strategy means that the feed will be update in time intervals set in application settings. + + + + minutes + + + + Title + + + + Description + + + + URL + + + + Fetch it now + + + + Icon + + + + Select icon for your feed. + + + + Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. + + + + Requires authentication + + + + Username + + + + Password + + + + Fetch metadata + + + + Add new feed + + + + Edit existing feed + + + + Feed name is ok. + + + + Feed name is too short. + + + + Description is empty. + + + + The description is ok. + + + + The url is ok. + + + + The url does not meet standard pattern. Does your url start with "http://" or "https://" prefix. + + + + The url is empty. + + + + Username is ok or it is not needed. + + + + Username is empty. + + + + Password is ok or it is not needed. + + + + Password is empty. + + + + Select icon file for the feed + + + + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + + + + Select icon + + + + Cancel + + + + Look in: + Label for field with icon file name textbox for selection dialog. + + + + Icon name: + + + + Icon type: + + + + Cannot add feed + + + + Feed was not added due to error. + + + + Cannot edit feed + + + + Feed was not edited due to error. + + + + All metadata fetched successfully. + + + + Feed and icon metadata fetched. + + + + Result: %1. + + + + Feed or icon metatada not fetched. + + + + Error: %1. + + + + No metadata fetched. + + + + Icon fetched successfully. + + + + Icon metadata fetched. + + + + Icon metatada not fetched. + + + + No icon fetched. + + + + Feed title + + + + Set title for your feed. + + + + Feed description + + + + Set description for your feed. + + + + Full feed url including scheme + + + + Set url for your feed. + + + + Set username to access the feed. + + + + Set password to access the feed. + + + + Icon selection + + + + Load icon from file... + + + + Do not use icon + + + + Use default icon + + + + Fetch icon from feed + + + + No metadata fetched so far. + + + + Auto-update using global interval + + + + Auto-update every + + + + Do not auto-update at all + + + + + FormStandardImportExport + + &Select file + + + + &Check all items + + + + &Uncheck all items + + + + Operation results + + + + No file is selected. + + + + No operation executed yet. + + + + Destination file + + + + Source feeds && categories + + + + Export feeds + + + + Source file + + + + Target feeds && categories + + + + Import feeds + + + + OPML 2.0 files (*.opml) + + + + Select file for feeds export + + + + File is selected. + + + + Select file for feeds import + + + + Cannot open source file. + + + + Feeds were loaded. + + + + Error, file is not well-formed. Select another file. + + + + Error occurred. File is not well-formed. Select another file. + + + + Feeds were exported successfully. + + + + Cannot write into destination file. + + + + Critical error occurred. + + FormUpdate @@ -2748,6 +2642,14 @@ Go to application website to obtain it manually. List of attachments. + + Loading of messages from item '%s' failed. + + + + Loading of messages failed, maybe messages could not be downloaded. + + MessagesToolBar @@ -2921,25 +2823,33 @@ Go to application website to obtain it manually. LANG_EMAIL rotter.martinos@gmail.com - - Load initial feeds - - - - Do you want to load initial set of feeds? - - LANG_NAME Name of language, e.g. English. + + + ++ %n other feeds. + + + + + - You started %1 for the first time, now you can load initial set of feeds. + Welcome to %1. + +Please, check NEW stuff included in this +version by clicking this popup notification. - Welcome to %1 %2. + Welcome to %1. + + + + Load initial set of feeds @@ -2981,6 +2891,132 @@ Go to application website to obtain it manually. + + StandardCategory + + %1 (category)%2%3 + Tooltip for standard feed. + + + + +This category does not contain any nested items. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + + StandardFeed + + Metadata not fetched + + + + Metadata was not fetched because: %1. + + + + does not use auto-update + Describes feed auto-update status. + + + + uses global settings + Describes feed auto-update status. + + + + uses specific settings (%n minute(s) to next auto-update) + Describes feed auto-update status. + + + + + + + %1 (%2)%3 + +Network status: %6 +Encoding: %4 +Auto-update status: %5 + Tooltip for feed. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + + StandardServiceRoot + + This is obligatory service account for standard RSS/RDF/ATOM feeds. + + + + You started %1 for the first time, now you can load initial set of feeds. + + + + Do you want to load initial set of feeds? + + + + Error when loading initial feeds + + + + This is service account for standard RSS/RDF/ATOM feeds. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + Fetch metadata + + + + Import successfull, but some feeds/categories were not imported due to error. + + + + Import was completely successfull. + + + + Add new category + + + + Add new feed + + + + Export feeds + + + + Import feeds + + + StatusBar @@ -3002,6 +3038,10 @@ Go to application website to obtain it manually. Click the bubble for more information. + + anonymous + + SystemTrayIcon @@ -3108,6 +3148,21 @@ Unread news: %2 + + TtRssServiceRoot + + This is service account TT-RSS (TinyTiny RSS) server. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + WebBrowser diff --git a/localization/rssguard-en_US.ts b/localization/rssguard-en_US.ts index 4ac459cd1..4e3226e75 100644 --- a/localization/rssguard-en_US.ts +++ b/localization/rssguard-en_US.ts @@ -1,522 +1,452 @@ - + + + AdBlockAddSubscriptionDialog Add subscription - + Another subscription - + Entered title is okay. - + Entered title is empty. - + Entered url is okay. - + Entered url is empty. - + Title - + Address - + AdBlockCustomList Custom rules - + AdBlockDialog Adblock settings - + Enable Adblock - + Note that Adblock may significantly slow this application down once you activate huge subscriptions. Too many rules is not good for performance. Also, make sure you restart application after you disable Adblock if you wish to have low memory footprint. Adblock is known to use much system memory. Also note that some resources are cached by internal web browser. Thus, after changing some rules or subscriptions they will fully apply only for new application instances. Make sure you restart RSS Guard for best Adblock experience. - + Options - + Filter rules - + Use only essential part of EasyList (for performance reasons) - + Add rule - + Remove rule - + Add subscription - + Remove subscription - + Update subscriptions - + Rules writing guide - + AdBlockIcon Adblock - + Show Adblock &settings - + Disable on %1 - + Disable only on this page - + Blocked popup windows - + %1 with (%2) - + No content blocked - + Blocked some content - click to edit rule - + Adblock - up and running - + Adblock - not running - + AdBlockSubscription Cannot load subscription! - + AdBlockTreeWidget Please write your rule here - + %1 (recently updated) - + %1 (error: %2) - + Add rule - + Remove rule - + Application Application is already running. - + Output directory is not writable. - + Settings file not copied to output directory successfully. - + Database file not copied to output directory successfully. - + Database restoration was not initiated. Make sure that output directory is writable. - + Settings restoration was not initiated. Make sure that output directory is writable. - - - - - Category - - %1 (category)%2%3 - Tooltip for standard feed. - - - - -This category does not contain any nested items. - - - - %n unread message(s). - Tooltip for "unread" column of feed list. - + DatabaseCleaner Shrinking database file... - + Database file shrinked... - + Removing read messages... - + Read messages purged... - + Recycle bin purged... - + Removing old messages... - + Purging recycle bin... - + Old messages purged... - + DatabaseFactory MySQL server works as expected. - + No MySQL server is running in the target destination. - + Access denied. Invalid username or password used. Access to MySQL server was denied. - + Unknown error. Unknown MySQL error arised. - + Selected database does not exist (yet). - + MySQL/MariaDB (dedicated database) - + SQLite (embedded database) - + DiscoverFeedsButton This website does not contain any feeds. - + Click me to add feeds from this website. This website contains %n feed(s). - + + + + DownloadItem Ico - + Filename - + Error opening output file: %1 - + &Try again - + &Stop - + &Open file - + Select destination for downloaded file - + Error: %1 - + Download directory couldn't be created - + Error when saving file: %1 - + %1 of %2 (%3 per second) - %4 - + %1 of %2 - download completed - + Open &directory - + Cannot open file - + Cannot open output file. Open it manually. - + Cannot open directory - + Cannot open output directory. Open it manually. - + Download finished - + - File '%1' is downloaded. + File '%1' is downloaded. Click here to open parent directory. - + URL: %1 - + Local file: %1 - + Selection of local file cancelled. - + DownloadManager Clean up - + %n minutes remaining - + + + + %n seconds remaining - + + + + bytes - + kB - + MB - + GB - + Downloading %n file(s)... - - - - - Feed - - does not use auto-update - Describes feed auto-update status. - - - - uses global settings - Describes feed auto-update status. - - - - uses specific settings (%n minute(s) to next auto-update) - Describes feed auto-update status. - - - - %1 (%2)%3 - -Network status: %6 -Encoding: %4 -Auto-update status: %5 - Tooltip for feed. - - - - %n unread message(s). - Tooltip for "unread" column of feed list. - - - - Metadata not fetched - - - - Metadata was not fetched because: %1 - + + + + FeedMessageViewer Toolbar for messages - - - - Feed update started - Text display in status bar when feed update is started. - - - - Updated feed '%1' - Text display in status bar when particular feed is updated. - + Toolbar for feeds - - - - Error when loading initial feeds - + Cannot cleanup database - + Cannot cleanup database, because another critical action is running. - - - - Cannot update all items - - - - You cannot update all items because another another critical operation is ongoing. - - - - New messages downloaded - + FeedsImportExportModel (category) - + (feed) - + Category - + @@ -524,1301 +454,783 @@ Auto-update status: %5 Title Title text in the feed list header. - + Titles of feeds/categories. - + Counts of unread/all meesages. - + Root Name of root item of feed list which can be seen in feed add/edit dialog. - - - - Invalid tree data. - - - - Import successfull, but some feeds/categories were not imported due to error. - - - - Import was completely successfull. - + Starting auto-update of some feeds - + I will auto-update %n feed(s). - + + + + + + + Cannot update all items + + + + You cannot update all items because another another critical operation is ongoing. + + + + Feed update started + Text display in status bar when feed update is started. + + + + Updated feed '%1' + Text display in status bar when particular feed is updated. + + + + New messages downloaded + FeedsToolBar Toolbar spacer - + FeedsView - - Cannot add standard category - - - - Cannot add standard feed - - Cannot edit item - + Cannot delete item - - - - You are about to delete selected feed or category. - - - - Deletion of item failed. - - - - Selected item was not deleted due to error. - - - - Do you really want to delete selected item? - - - - Permanently delete messages - - - - You are about to permanenty delete all messages from your recycle bin. - - - - Do you really want to empty your recycle bin? - + Context menu for empty space - - - - Context menu for recycle bin - - - - You cannot add new standard category now because another critical operation is ongoing. - - - - You cannot add new standard feed now because another critical operation is ongoing. - + Selected item cannot be edited because another critical operation is ongoing. - + Selected item cannot be deleted because another critical operation is ongoing. - - - - Delete feed/category - + Context menu for categories - + + + + Selected item cannot be edited, this is not (yet?) supported. + + + + Deleting "%1" + + + + You are about to completely delete item "%1". + + + + Are you sure? + + + + Cannot delete "%1" + + + + This item cannot be deleted because something critically failed. Submit bug report. + + + + This item cannot be deleted, because it does not support it +or this functionality is not implemented yet. + + + + Context menu for other items + FormAbout Information - + Licenses - + GNU GPL License (applies to RSS Guard source code) - + GNU GPL License - + BSD License (applies to QtSingleApplication source code) - + Licenses page is available only in English language. - + Changelog - + Changelog page is available only in English language. - + License not found. - + Changelog not found. - + <b>%8</b><br><b>Version:</b> %1 (build on %2 with CMake %3)<br><b>Revision:</b> %4<br><b>Build date:</b> %5<br><b>Qt:</b> %6 (compiled against %7)<br> - - - - <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~email</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> - + About %1 About RSS Guard dialog title. - + Settings type - + Settings file - + Database root path - + FULLY portable - + PARTIALLY portable - + Resources - + + + + <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~e-mail</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> + FormBackupDatabaseSettings Backup database/settings - + Backup properties - + Items to backup - + Database - + Settings - + Backup name - + Operation results - + Common name for backup files - + No operation executed yet. - + Backup was created successfully. - + Backup name cannot be empty. - + Backup name looks okay. - + Backup failed. - + Output directory - + &Select directory - + Backup was created successfully and stored in target directory. - + Select destination directory - + Good destination directory is specified. - - - - - FormCategoryDetails - - Parent category - - - - Select parent item for your category. - - - - Title - - - - Description - - - - Icon - - - - Select icon for your category. - - - - Add new category - - - - Edit existing category - - - - Cannot add category - - - - Category was not added due to error. - - - - Cannot edit category - - - - Category was not edited due to error. - - - - Category name is ok. - - - - Category name is too short. - - - - Description is empty. - - - - Select icon file for the category - - - - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - - - - Select icon - - - - Cancel - - - - Look in: - Label to describe the folder for icon file selection dialog. - - - - Icon name: - - - - Icon type: - - - - Category title - - - - Set title for your category. - - - - Category description - - - - Set description for your category. - - - - Icon selection - - - - Load icon from file... - - - - Do not use icon - - - - Use default icon - - - - The description is ok. - + FormDatabaseCleanup Cleanup database - + Remove all messages older than - + day(s) - + + + + Shrink database file - + Database information - + Database file size - + Database type - + Progress - + I am ready. - + Database cleanup is running. - + Database cleanup is completed. - + Database cleanup failed. - + Cleanup settings (all checked items are completely erased from database) - + Remove all read messages (not those from recycle bin) - + Remove all messages from recycle bin - + Remove all starred messages (including those from recycle bin) - - - - - FormFeedDetails - - Parent category - - - - Select parent item for your feed. - - - - Type - - - - Select type of the standard feed. - - - - Encoding - - - - Select encoding of the standard feed. If you are unsure about the encoding, then select "UTF-8" encoding. - - - - Auto-update - - - - Select the auto-update strategy for this feed. Default auto-update strategy means that the feed will be update in time intervals set in application settings. - - - - minutes - - - - Title - - - - Description - - - - URL - - - - Fetch it now - - - - Icon - - - - Select icon for your feed. - - - - Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. - - - - Requires authentication - - - - Username - - - - Password - - - - Fetch metadata - - - - Add new feed - - - - Edit existing feed - - - - Feed name is ok. - - - - Feed name is too short. - - - - Description is empty. - - - - The url is ok. - - - - The url does not meet standard pattern. Does your url start with "http://" or "https://" prefix. - - - - The url is empty. - - - - Username is ok or it is not needed. - - - - Username is empty. - - - - Password is ok or it is not needed. - - - - Password is empty. - - - - Select icon file for the feed - - - - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - - - - Select icon - - - - Cancel - - - - Look in: - Label for field with icon file name textbox for selection dialog. - - - - Icon name: - - - - Icon type: - - - - Cannot add feed - - - - Feed was not added due to error. - - - - Cannot edit feed - - - - All metadata fetched successfully. - - - - Feed and icon metadata fetched. - - - - Result: %1. - - - - Feed or icon metatada not fetched. - - - - Error: %1. - - - - No metadata fetched. - - - - Feed title - - - - Set title for your feed. - - - - Feed description - - - - Set description for your feed. - - - - Full feed url including scheme - - - - Set url for your feed. - - - - Set username to access the feed. - - - - Set password to access the feed. - - - - Icon selection - - - - Load icon from file... - - - - Do not use icon - - - - Use default icon - - - - No metadata fetched so far. - - - - Auto-update using global interval - - - - Auto-update every - - - - Do not auto-update at all - - - - The description is ok. - - - - Feed was not edited due to error. - - - - Icon fetched successfully. - - - - Icon metadata fetched. - - - - Icon metatada not fetched. - - - - No icon fetched. - - - - Fetch icon from feed - - - - - FormImportExport - - &Select file - - - - Operation results - - - - No file is selected. - - - - No operation executed yet. - - - - Export feeds - - - - Destination file - - - - Source feeds && categories - - - - Source file - - - - Target feeds && categories - - - - Import feeds - - - - OPML 2.0 files (*.opml) - - - - Select file for feeds export - - - - File is selected. - - - - Select file for feeds import - - - - Cannot open source file. - - - - Feeds were loaded. - - - - Error, file is not well-formed. Select another file. - - - - Error occurred. File is not well-formed. Select another file. - - - - Feeds were exported successfully. - - - - Cannot write into destination file. - - - - Critical error occurred. - - - - &Check all items - - - - &Uncheck all items - + FormMain &File - + &Help - + &View - + &Tools - + &Quit - + &Settings - + &Current tab - + &Add tab - + &Messages - + &Web browser - + Switch &importance of selected messages - + Quit the application. - + Display settings of the application. - + Switch fullscreen mode. - + Add new web browser tab. - + Close current web browser tab. - + No actions available - + No actions are available right now. - + Fee&ds && categories - - - - Mark all messages (without message filters) from selected feeds as read. - - - - Mark all messages (without message filters) from selected feeds as unread. - - - - Displays all messages from selected feeds/categories in a new "newspaper mode" tab. Note that messages are not set as read automatically. - + Hides main window if it is visible and shows it if it is hidden. - + Hides or shows the list of feeds/categories. - + Check if new update for the application is available for download. - + &About application - + Displays extra info about this application. - + &Delete selected messages - - - - Deletes all messages from selected feeds. - - - - Marks all messages in all feeds read. This does not take message filters into account. - - - - Deletes all messages from all feeds. - - - - Update &all feeds - - - - Update &selected feeds - - - - &Edit selected feed/category - - - - &Delete selected feed/category - + Settings - + Hides or displays the main menu. - - - - Add &new feed/category - + &Close all tabs except current one - + &Close current tab - + Mark &selected messages as &read - + Mark &selected messages as &unread - - - - &Mark selected feeds as read - - - - &Mark selected feeds as unread - - - - &Clean selected feeds - + Open selected source articles in &external browser - + Open selected messages in &internal browser - + Open selected source articles in &internal browser - - - - &Mark all feeds as &read - - - - View selected feeds in &newspaper mode - - - - &Clean all feeds - - - - Select &next feed/category - - - - Select &previous feed/category - + Select &next message - + Select &previous message - + Check for &updates - + Enable &JavaScript - + Enable external &plugins - + Auto-load &images - + Show/hide - + &Fullscreen - + &Feed list - + &Main menu - + Switch visibility of main &window - + Cannot open external browser - + Cannot open external browser. Navigate to application website manually. - - - - New &feed - - - - Add new feed. - - - - New &category - - - - Add new category. - + &Toolbars - + Switch visibility of main toolbars. - + &Feed/message list headers - - - - &Import feeds - - - - Imports feeds you want from selected file. - - - - &Export feeds - - - - Exports feeds you want to selected file. - + Close all tabs except current one. - - - - &Recycle bin - + Report a &bug (GitHub)... - + Report a bug (BitBucket)... - + &Donate via PayPal - + Display &wiki - - - - &Empty recycle bin - - - - &Restore all messages - - - - Restore &selected messages - + &Restart - + &Restore database/settings - + &Backup database/settings - + Switch message list layout orientation - + &Downloads - + Send selected message via e-mail - + &Cleanup database - + - Show only unread feeds/categories - + Add &new item + - &Fetch feed metadata - + &Services + - &Expand/collapse selected feed/category - + Update &all items + + + + Ctrl+Shift+U + + + + Update &selected items + + + + Ctrl+U + + + + &Edit selected item + + + + &Delete selected item + + + + &Mark selected items as read + + + + Mark all messages (without message filters) from selected items as read. + + + + &Mark selected items as unread + + + + Mark all messages (without message filters) from selected items as unread. + + + + &Clean selected items + + + + Deletes all messages from selected items. + + + + &Mark all items as &read + + + + Marks all messages in all items read. This does not take message filters into account. + + + + View selected items in &newspaper mode + + + + Displays all messages from selected item in a new "newspaper mode" tab. Note that messages are not set as read automatically. + + + + &Clean all items + + + + Deletes all messages from all items. + + + + Ctrl+Shift+C + + + + Select &next item + + + + S + + + + Select &previous item + + + + A + + + + Show only unread items + + + + &Expand/collapse selected item + + + + E + + + + &Add new service account + + + + &Delete selected service account + + + + &Edit selected service account + + + + &Restore selected messages + + + + No possible actions + FormRestoreDatabaseSettings Restore database/settings - + Operation results - + Restore database - + Restore settings - + Restart - + No operation executed yet. - + Restoration was initiated. Restart to proceed. - + You need to restart application for restoration process to finish. - + Source directory - + &Select directory - + Database and/or settings were not copied to restoration directory successully. - + Select source directory - + Good source directory is specified. - + @@ -1826,252 +1238,248 @@ Auto-update status: %5 General General settings section. - + User interface - + Icon theme - + Settings - + Keyboard shortcuts - + Language Language settings section. - + Proxy - + Icons && skins - + Tray icon - + Start application hidden - + Type Proxy server type. - + Host - + Hostname or IP of your proxy server - + Port - + Username - + Your username for proxy server authentication - + Password - + Your password for proxy server authentication - + Display password - + Code - + Version - + Author - - - - Email - + Socks5 - + Http - + (not supported on this platform) - + Tray area && notifications - + Tabs - + Close tabs with - + Middle mouse button single-click - + Open new tabs with left mouse button double-click on tab bar - + Enable mouse gestures - + Queue new tabs (with hyperlinks) after the active tab - + no icon theme Label for disabling icon theme. - + Cannot save settings - + Name - + Icons - + Skins - + Active skin: - + Selected skin: - + Hide tab bar if just one tab is visible - + Critical settings were changed - + Feeds & messages - + Some critical settings are not set. You must fix these settings in order confirm new settings. - + Messages - + Web browser executable - + Executable parameters - + Note that "%1" (without quotation marks) is placeholder for URL of selected message. - + Select web browser executable - + Executables (*.*) - + Opera 12 or older - + Executable file of web browser - + Parameters to executable - + some keyboard shortcuts are not unique - + List of errors: %1. - + List of changes: %1. - + language changed - + icon theme changed - + skin changed - + Use sample arguments for - + Use in-memory database as the working database - + Usage of in-memory working database has several advantages and pitfalls. Make sure that you are familiar with these before you turn this feature on. Advantages: @@ -2085,292 +1493,292 @@ Disadvantages: <li>application startup and shutdown can take little longer (max. 2 seconds).</li> </ul> Authors of this application are NOT responsible for lost data. - + in-memory database switched - + Internal web browser - + External web browser - + WARNING: Note that switching to another data storage type will NOT copy existing your data from currently active data storage to newly selected one. - + Database driver - + Hostname - + Test setup - + Right mouse button double-click - + Auto-update all feeds every - + minutes - + Feed connection timeout - + Connection timeout is time interval which is reserved for downloading new messages for the feed. If this time interval elapses, then download process is aborted. - + ms - + Update all feed on application startup - + Data storage - + Hostname of your MySQL server - + Username to login with - + Password for your username - + data storage backend changed - + Hostname is empty. - + Hostname looks ok. - + Username is empty. - + Username looks ok. - + Password is empty. - + Password looks ok. - + Toolbar button style - + Hide main window when it is minimized - + No connection test triggered so far. - + Note that these settings are applied only on newly established connections. - + Select browser - + No proxy - + System proxy - + Icon only - + Text only - + Text beside icon - + Text under icon - + Follow OS style - + Keep message selection in the middle of the message list viewport - + You did not executed any connection test yet. - + Launch %1 on operating system startup - + Enable JavaScript - + Enable external plugins based on NPAPI - + Auto-load images - + <html><head/><body><p>If unchecked, then default system-wide web browser is used.</p></body></html> - + Feeds && categories - + Message count format in feed list - + Enter format for count of messages displayed next to each feed/category in feed list. Use "%all" and "%unread" strings which are placeholders for the actual count of all (or unread) messages. - + custom external browser is not set correctly - + Toolbars - + Toolbar for feeds list - + Toolbar for messages list - + Select toolbar to edit - + Some critical settings were changed and will be applied after the application gets restarted. You have to restart manually. - + Do you want to restart now? - + Check for updates on application startup - + Use custom date/time format (overrides format loaded from active localization) - + Executables (*) File filter for external browser selection dialog. ---------- File filter for external e-mail selection dialog. - + Remove all read messages from all feeds on application exit - + When new message arrives from feed and duplicate exists, then its content is updated and new message is dropped. - + Remove duplicate messages - + Downloads - + Target directory for downloaded files - + Ask for each individual downloaded file - + Target directory where all downloaded files are saved - + &Browse - + Select downloads target directory - + &Show password - + Web browser & e-mail & proxy - + Remove junk Trolltech registry key (HKCU\Software\Trolltech) when application quits (Use at your own risk!) - + Working database - + Mouse gestures work with middle mouse button. Possible gestures are: @@ -2378,416 +1786,939 @@ File filter for external e-mail selection dialog. • next web page (drag mouse right), • reload current web page (drag mouse up), • open new web browser tab (drag mouse down). - + Use custom external web browser - + External e-mail client - + Use custom external e-mail client - + E-mail client executable - + Executable file of e-mail client - + Select client - + Placeholders: • %1 - title of selected message, • %2 - body of selected message. - + Save all downloaded files to - + Select e-mail executable - + Mozilla Thunderbird - + Working database which you have full access to. - + Working database is empty. - + Working database is ok. - + Notification position - + (Tray icon is not available.) - + Bottom-left corner - + Top-left corner - + Bottom-right corner - + Top-right corner - + Internal message browser fonts - + Standard font - + Note that speed of used MySQL server and latency of used connection medium HEAVILY influences the final performance of this application. Using slow database connections leads to bad performance when browsing feeds or messages. - + Fancy && modern popup notifications (This uses OS native notifications via D-Bus if available.) - + + + + E-mail + + + + + FormStandardCategoryDetails + + Parent category + + + + Select parent item for your category. + + + + Title + + + + Description + + + + Icon + + + + Select icon for your category. + + + + Add new category + + + + Edit existing category + + + + Cannot add category + + + + Category was not added due to error. + + + + Cannot edit category + + + + Category was not edited due to error. + + + + Category name is ok. + + + + Category name is too short. + + + + Description is empty. + + + + The description is ok. + + + + Select icon file for the category + + + + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + + + + Select icon + + + + Cancel + + + + Look in: + Label to describe the folder for icon file selection dialog. + + + + Icon name: + + + + Icon type: + + + + Category title + + + + Set title for your category. + + + + Category description + + + + Set description for your category. + + + + Icon selection + + + + Load icon from file... + + + + Do not use icon + + + + Use default icon + + + + + FormStandardFeedDetails + + Parent category + + + + Select parent item for your feed. + + + + Type + + + + Select type of the standard feed. + + + + Encoding + + + + Select encoding of the standard feed. If you are unsure about the encoding, then select "UTF-8" encoding. + + + + Auto-update + + + + Select the auto-update strategy for this feed. Default auto-update strategy means that the feed will be update in time intervals set in application settings. + + + + minutes + + + + Title + + + + Description + + + + URL + + + + Fetch it now + + + + Icon + + + + Select icon for your feed. + + + + Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. + + + + Requires authentication + + + + Username + + + + Password + + + + Fetch metadata + + + + Add new feed + + + + Edit existing feed + + + + Feed name is ok. + + + + Feed name is too short. + + + + Description is empty. + + + + The description is ok. + + + + The url is ok. + + + + The url does not meet standard pattern. Does your url start with "http://" or "https://" prefix. + + + + The url is empty. + + + + Username is ok or it is not needed. + + + + Username is empty. + + + + Password is ok or it is not needed. + + + + Password is empty. + + + + Select icon file for the feed + + + + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + + + + Select icon + + + + Cancel + + + + Look in: + Label for field with icon file name textbox for selection dialog. + + + + Icon name: + + + + Icon type: + + + + Cannot add feed + + + + Feed was not added due to error. + + + + Cannot edit feed + + + + Feed was not edited due to error. + + + + All metadata fetched successfully. + + + + Feed and icon metadata fetched. + + + + Result: %1. + + + + Feed or icon metatada not fetched. + + + + Error: %1. + + + + No metadata fetched. + + + + Icon fetched successfully. + + + + Icon metadata fetched. + + + + Icon metatada not fetched. + + + + No icon fetched. + + + + Feed title + + + + Set title for your feed. + + + + Feed description + + + + Set description for your feed. + + + + Full feed url including scheme + + + + Set url for your feed. + + + + Set username to access the feed. + + + + Set password to access the feed. + + + + Icon selection + + + + Load icon from file... + + + + Do not use icon + + + + Use default icon + + + + Fetch icon from feed + + + + No metadata fetched so far. + + + + Auto-update using global interval + + + + Auto-update every + + + + Do not auto-update at all + + + + + FormStandardImportExport + + &Select file + + + + &Check all items + + + + &Uncheck all items + + + + Operation results + + + + No file is selected. + + + + No operation executed yet. + + + + Destination file + + + + Source feeds && categories + + + + Export feeds + + + + Source file + + + + Target feeds && categories + + + + Import feeds + + + + OPML 2.0 files (*.opml) + + + + Select file for feeds export + + + + File is selected. + + + + Select file for feeds import + + + + Cannot open source file. + + + + Feeds were loaded. + + + + Error, file is not well-formed. Select another file. + + + + Error occurred. File is not well-formed. Select another file. + + + + Feeds were exported successfully. + + + + Cannot write into destination file. + + + + Critical error occurred. + FormUpdate Current release - + Available release - + Changes - + Status - + unknown Unknown release. - + List with updates was not downloaded successfully. - + New release available. - + This is new version which can be downloaded and installed. - + Error: '%1'. - + No new release available. - + This release is not newer than currently installed one. - + Check for updates - + Update - + Download new installation files. - + Checking for updates failed. - + Download installation file for your OS. - + Installation file is not available directly. Go to application website to obtain it manually. - + No new update available. - + Cannot update application - + Cannot navigate to installation file. Check new installation downloads manually on project website. - + Download update - + Downloaded %1% (update size is %2 kB). - + Downloading update... - + Downloaded successfully - + Package was downloaded successfully. - + Install update - + Error occured - + Error occured during downloading of the package. - + Cannot launch external updater. Update application manually. - + Go to application website - + IOFactory Cannot open file '%1' for reading. - + Cannot open file '%1' for writting. - + LocationLineEdit Website address goes here - + MessagesModel Id - + Read - + Deleted - + Important - + Feed - + Title - + Url - + Author - + Created on - + Contents - + Id of the message. - + Is message read? - + Is message deleted? - + Is message important? - + Id of feed which this message belongs to. - + Title of the message. - + Url of the message. - + Author of the message. - + Creation date of the message. - + Contents of the message. - + Permanently deleted - + Is message permanently deleted from recycle bin? - + Attachments - + List of attachments. - + + + + Loading of messages from item '%s' failed. + + + + Loading of messages failed, maybe messages could not be downloaded. + MessagesToolBar Search messages - + Message search box - + Menu for highlighting messages - + No extra highlighting - + Highlight unread messages - + Highlight important messages - + Display all messages - + Message highlighter - + Toolbar spacer - + MessagesView Context menu for messages - + Meesage without URL - + Message '%s' does not contain URL. - + Problem with starting external web browser - + External web browser could not be started. - + Problem with starting external e-mail client - + External e-mail client could not be started. - + @@ -2795,80 +2726,80 @@ Go to application website to obtain it manually. protocol error Network status. - + host not found Network status. - + connection refused Network status. - + connection timed out Network status. - + SSL handshake failed Network status. - + proxy server connection refused Network status. - + temporary failure Network status. - + authentication failed Network status. - + proxy authentication required Network status. - + proxy server not found Network status. - + uknown content Network status. - + content not found Network status. - + unknown error Network status. - + no errors Network status. - + access to content was denied - + connection timed out or was cancelled - + @@ -2886,89 +2817,230 @@ Go to application website to obtain it manually. LANG_AUTHOR Name of translator - optional. - + LANG_EMAIL rotter.martinos@gmail.com - - Load initial feeds - - - - Do you want to load initial set of feeds? - - LANG_NAME Name of language, e.g. English. English (USA) - - You started %1 for the first time, now you can load initial set of feeds. - + + + ++ %n other feeds. + + + + - Welcome to %1 %2. - + Welcome to %1. + +Please, check NEW stuff included in this +version by clicking this popup notification. + + + + Welcome to %1. + + + + Load initial set of feeds + RecycleBin Recycle bin - + Recycle bin contains all deleted messages from all feeds. - + Recycle bin %1 - + %n deleted message(s). - + + + + ShortcutCatcher Reset to original shortcut. - + Clear current shortcut. - + Click and hit new shortcut. - + + + + + StandardCategory + + %1 (category)%2%3 + Tooltip for standard feed. + + + + +This category does not contain any nested items. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + + StandardFeed + + Metadata not fetched + + + + Metadata was not fetched because: %1. + + + + does not use auto-update + Describes feed auto-update status. + + + + uses global settings + Describes feed auto-update status. + + + + uses specific settings (%n minute(s) to next auto-update) + Describes feed auto-update status. + + + + + + + %1 (%2)%3 + +Network status: %6 +Encoding: %4 +Auto-update status: %5 + Tooltip for feed. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + + StandardServiceRoot + + This is obligatory service account for standard RSS/RDF/ATOM feeds. + + + + You started %1 for the first time, now you can load initial set of feeds. + + + + Do you want to load initial set of feeds? + + + + Error when loading initial feeds + + + + This is service account for standard RSS/RDF/ATOM feeds. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + Fetch metadata + + + + Import successfull, but some feeds/categories were not imported due to error. + + + + Import was completely successfull. + + + + Add new category + + + + Add new feed + + + + Export feeds + + + + Import feeds + StatusBar Fullscreen mode - + Switch application between fulscreen/normal states right from this status bar icon. - + SystemFactory New version available - + Click the bubble for more information. - + + + + anonymous + @@ -2976,315 +3048,330 @@ Go to application website to obtain it manually. %1 Unread news: %2 - + TabBar Close this tab. - + Close tab - + TabWidget Feeds - + Browse your feeds and messages - + Web browser Web browser default tab title. - + Displays main menu. - + Main menu - + Open new web browser tab. - + Downloads - + ToolBarEditor Activated actions - + Available actions - + Insert separator - + Insert spacer - + Separator - + Toolbar spacer - + Move action up - + Move action down - + Add selected action - + Delete selected action - + Delete all actions - + TrayIconMenu Close opened modal dialogs first. - + + + + + TtRssServiceRoot + + This is service account TT-RSS (TinyTiny RSS) server. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + WebBrowser Navigation panel - + Back - + Forward - + Reload - + Stop - + Zoom - + No title Webbrowser tab title when no title is available. - + Decrease zoom. - + Reset zoom to default. - + Increase zoom. - + Written by - + uknown author - + Newspaper view - + Go back. - + Go forward. - + Reload current web page. - + Stop web page loading. - + WebView Reload web page - + Copy link url - + Copy image - + Copy image url - + Open link in new tab - + Follow link - + Open image in new tab - + Web browser - + Image - + Hyperlink - + Reload current web page. - + Copy selection - + Copies current selection into the clipboard. - + Copy link url to clipboard. - + Copy image to clipboard. - + Copy image url to clipboard. - + Open this hyperlink in new tab. - + Open the hyperlink in this tab. - + Open this image in this tab. - + Open link in external browser - + Open the hyperlink in external browser. - + Print - + Print current web page. - + HTML web pages (*.html) - + Select destination file for web page - + Cannot save web page - + Web page cannot be saved because destination file is not writtable. - + Save target as... - + Download content from the hyperlink. - + Save page as... - + Save image to disk. - + Save image as... - + source_page - + Search "%1" via Google... - + - \ No newline at end of file + diff --git a/localization/rssguard-fr_FR.ts b/localization/rssguard-fr_FR.ts index d82cc5f24..ea5667b98 100644 --- a/localization/rssguard-fr_FR.ts +++ b/localization/rssguard-fr_FR.ts @@ -1,170 +1,172 @@ - + + + AdBlockAddSubscriptionDialog Add subscription - + Another subscription - + Entered title is okay. - + Entered title is empty. - + Entered url is okay. - + Entered url is empty. - + Title - + Titre Address - + AdBlockCustomList Custom rules - + AdBlockDialog Adblock settings - + Enable Adblock - + Note that Adblock may significantly slow this application down once you activate huge subscriptions. Too many rules is not good for performance. Also, make sure you restart application after you disable Adblock if you wish to have low memory footprint. Adblock is known to use much system memory. Also note that some resources are cached by internal web browser. Thus, after changing some rules or subscriptions they will fully apply only for new application instances. Make sure you restart RSS Guard for best Adblock experience. - + Options - + Filter rules - + Use only essential part of EasyList (for performance reasons) - + Add rule - + Remove rule - + Add subscription - + Remove subscription - + Update subscriptions - + Rules writing guide - + AdBlockIcon Adblock - + Show Adblock &settings - + Disable on %1 - + Disable only on this page - + Blocked popup windows - + %1 with (%2) - + No content blocked - + Blocked some content - click to edit rule - + Adblock - up and running - + Adblock - not running - + AdBlockSubscription Cannot load subscription! - + AdBlockTreeWidget Please write your rule here - + %1 (recently updated) - + %1 (error: %2) - + Add rule - + Remove rule - + @@ -175,76 +177,58 @@ Also note that some resources are cached by internal web browser. Thus, after ch Output directory is not writable. - + Settings file not copied to output directory successfully. - + Database file not copied to output directory successfully. - + Database restoration was not initiated. Make sure that output directory is writable. - + Settings restoration was not initiated. Make sure that output directory is writable. - - - - - Category - - %1 (category)%2%3 - Tooltip for standard feed. - - - - -This category does not contain any nested items. - - - - %n unread message(s). - Tooltip for "unread" column of feed list. - + DatabaseCleaner Shrinking database file... - + Database file shrinked... - + Removing read messages... - + Read messages purged... - + Recycle bin purged... - + Removing old messages... - + Purging recycle bin... - + Old messages purged... - + @@ -269,194 +253,166 @@ This category does not contain any nested items. Selected database does not exist (yet). - + MySQL/MariaDB (dedicated database) - + SQLite (embedded database) - + DiscoverFeedsButton This website does not contain any feeds. - + Click me to add feeds from this website. This website contains %n feed(s). - + + + + DownloadItem Ico - + Filename - + Error opening output file: %1 - + &Try again - + &Stop - + &Open file - + Select destination for downloaded file - + Error: %1 - + Erreur : %1. {1?} Download directory couldn't be created - + Error when saving file: %1 - + %1 of %2 (%3 per second) - %4 - + %1 of %2 - download completed - + Open &directory - + Cannot open file - + Cannot open output file. Open it manually. - + Cannot open directory - + Cannot open output directory. Open it manually. - + Download finished - + - File '%1' is downloaded. + File '%1' is downloaded. Click here to open parent directory. - + URL: %1 - + Local file: %1 - + Selection of local file cancelled. - + DownloadManager Clean up - + %n minutes remaining - + + + + %n seconds remaining - + + + + bytes - + kB - + MB - + GB - + Downloading %n file(s)... - - - - - Feed - - does not use auto-update - Describes feed auto-update status. - - - - uses global settings - Describes feed auto-update status. - - - - uses specific settings (%n minute(s) to next auto-update) - Describes feed auto-update status. - - - - %1 (%2)%3 - -Network status: %6 -Encoding: %4 -Auto-update status: %5 - Tooltip for feed. - - - - %n unread message(s). - Tooltip for "unread" column of feed list. - - - - Metadata not fetched - - - - Metadata was not fetched because: %1 - + + + + @@ -465,43 +421,17 @@ Auto-update status: %5 Toolbar for messages Barre d'outils pour les messages - - Feed update started - Text display in status bar when feed update is started. - Mise à jour des flux démarrée - - - Updated feed '%1' - Text display in status bar when particular feed is updated. - Flux mis à jour '%1' - Toolbar for feeds Barre d'outils pour les flux - - Error when loading initial feeds - - Cannot cleanup database - + Cannot cleanup database, because another critical action is running. - - - - Cannot update all items - - - - You cannot update all items because another another critical operation is ongoing. - - - - New messages downloaded - + @@ -516,7 +446,7 @@ Auto-update status: %5 Category - + @@ -539,44 +469,49 @@ Auto-update status: %5 Name of root item of feed list which can be seen in feed add/edit dialog. Racine - - Invalid tree data. - - - - Import successfull, but some feeds/categories were not imported due to error. - - - - Import was completely successfull. - - Starting auto-update of some feeds - + I will auto-update %n feed(s). - + + + + + + + Cannot update all items + + + + You cannot update all items because another another critical operation is ongoing. + + + + Feed update started + Text display in status bar when feed update is started. + Mise à jour des flux démarrée + + + Updated feed '%1' + Text display in status bar when particular feed is updated. + Flux mis à jour '%1' + + + New messages downloaded + FeedsToolBar Toolbar spacer - + FeedsView - - Cannot add standard category - Impossible d'ajouter une catégorie standard - - - Cannot add standard feed - Impossible d'ajouter un flux standard - Cannot edit item Impossible d'éditer l'article @@ -585,65 +520,54 @@ Auto-update status: %5 Cannot delete item Impossible de supprimer l'article - - You are about to delete selected feed or category. - - - - Deletion of item failed. - - - - Selected item was not deleted due to error. - - - - Do you really want to delete selected item? - - - - Permanently delete messages - - - - You are about to permanenty delete all messages from your recycle bin. - - - - Do you really want to empty your recycle bin? - - Context menu for empty space - - - - Context menu for recycle bin - - - - You cannot add new standard category now because another critical operation is ongoing. - - - - You cannot add new standard feed now because another critical operation is ongoing. - + Selected item cannot be edited because another critical operation is ongoing. - + Selected item cannot be deleted because another critical operation is ongoing. - - - - Delete feed/category - + Context menu for categories - + + + + Selected item cannot be edited, this is not (yet?) supported. + + + + Deleting "%1" + + + + You are about to completely delete item "%1". + + + + Are you sure? + + + + Cannot delete "%1" + + + + This item cannot be deleted because something critically failed. Submit bug report. + + + + This item cannot be deleted, because it does not support it +or this functionality is not implemented yet. + + + + Context menu for other items + @@ -692,10 +616,6 @@ Auto-update status: %5 <b>%8</b><br><b>Version:</b> %1 (build on %2 with CMake %3)<br><b>Revision:</b> %4<br><b>Build date:</b> %5<br><b>Qt:</b> %6 (compiled against %7)<br> <b>%8</b><br><b>Version :</b> %1 (construit sur %2 avec CMake %3)<br><b>Révision :</b> %4<br><b>Date de création :</b> %5<br><b>Qt:</b> %6 (compilé avec %7)<br> - - <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~email</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> - <body>%5 est un lecteur de flux (très) petit.<br><br>Ce logiciel est distribué sous les termes de la licence GNU General Public License, version 3.<br><br>Contacts : <ul><li><a href="mailto://%1">%1</a> ~email</li><li><a href="%2">%2</a> ~site internet</li></ul>Vous pouvez obtenir le code source de %5 depuis le site internet.<br><br><br>Copyright (C) 2011-%3 %4</body> - About %1 About RSS Guard dialog title. @@ -703,46 +623,50 @@ Auto-update status: %5 Settings type - + Settings file - + Database root path - + FULLY portable - + PARTIALLY portable - + Resources - + + + + <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~e-mail</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> + FormBackupDatabaseSettings Backup database/settings - + Backup properties - + Items to backup - + Database - + Settings @@ -750,633 +674,125 @@ Auto-update status: %5 Backup name - + Operation results - + Common name for backup files - + No operation executed yet. - + Backup was created successfully. - + Backup name cannot be empty. - + Backup name looks okay. - + Backup failed. - + Output directory - + &Select directory - + Backup was created successfully and stored in target directory. - + Select destination directory - + Good destination directory is specified. - - - - - FormCategoryDetails - - Parent category - Catégorie parente - - - Select parent item for your category. - Sélectionner l'article parent pour votre catégorie. - - - Title - Titre - - - Description - Description - - - Icon - Icône - - - Select icon for your category. - Sélectionner un icône pour votre catégorie - - - Add new category - Ajouter une nouvelle catégorie - - - Edit existing category - - - - Cannot add category - Impossible d'ajouter une catégorie - - - Category was not added due to error. - La catégorie n'a pas été ajoutée dû à une erreur - - - Cannot edit category - Impossible d'éditer la catégori - - - Category was not edited due to error. - La catégorie n'a pas été éditée dû à une erreur. - - - Category name is ok. - Le nom de la catégorie est correct. - - - Category name is too short. - Le nom de la catégorie est trop court. - - - Description is empty. - La description est vide. - - - Select icon file for the category - Sélectionner un icône pour la catégorie - - - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - - - Select icon - Sélectionner l'icône - - - Cancel - Annuler - - - Look in: - Label to describe the folder for icon file selection dialog. - Rechercher dans : - - - Icon name: - Nom de l'icône : - - - Icon type: - Type d'icône : - - - Category title - Titre de la catégorie - - - Set title for your category. - Définir un titre pour votre catégorie - - - Category description - Description de la catégorie - - - Set description for your category. - Définir une description pour votre catégorie. - - - Icon selection - Sélection de l'icône - - - Load icon from file... - Charger l'icône depuis un fichier... - - - Do not use icon - Ne pas utiliser les icônes - - - Use default icon - Utiliser les icônes par défaut - - - The description is ok. - + FormDatabaseCleanup Cleanup database - + Remove all messages older than - + day(s) - + + + + Shrink database file - + Database information - + Database file size - + Database type - + Progress - + I am ready. - + Database cleanup is running. - + Database cleanup is completed. - + Database cleanup failed. - + Cleanup settings (all checked items are completely erased from database) - + Remove all read messages (not those from recycle bin) - + Remove all messages from recycle bin - + Remove all starred messages (including those from recycle bin) - - - - - FormFeedDetails - - Parent category - Catégorie parente - - - Select parent item for your feed. - Sélectionner l'article parent pour votre flux. - - - Type - Type - - - Select type of the standard feed. - Sélectionner un type pour le flux standard. - - - Encoding - Encodage - - - Select encoding of the standard feed. If you are unsure about the encoding, then select "UTF-8" encoding. - Sélectionner un encodage pour le flux standard. Si vous n'êtes pas sûr à propos de l'encodage, sélectionner alors l'encodage "UTF-8". - - - Auto-update - Mise à jour automatique - - - Select the auto-update strategy for this feed. Default auto-update strategy means that the feed will be update in time intervals set in application settings. - Sélectionner la stratégie des mises à jour automatique pour ce flux. Par défaut, cette stratégie signifie que le flux sera mis à jour par intervalle de temps défini dans les paramètres de l'application. - - - minutes - minutes - - - Title - Titre - - - Description - Description - - - URL - URL - - - Fetch it now - Le chercher maintenant - - - Icon - Icône - - - Select icon for your feed. - Sélectionner un icône pour votre flux. - - - Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. - Certain flux requière une authentification, incluant les flux GMail. Les schémas d'authentification BASIC, NTLM-2 et DIGEST-MD5 sont supportés. - - - Requires authentication - Authentification requise - - - Username - Nom d'utilisateur - - - Password - Mot de passe - - - Fetch metadata - Chercher les métadonnées - - - Add new feed - Ajouter un nouveau flux - - - Edit existing feed - - - - Feed name is ok. - Le nom du flux est correct. - - - Feed name is too short. - Le nom du flux est trop court. - - - Description is empty. - La description est vide. - - - The url is ok. - L'URL est correct. - - - The url does not meet standard pattern. Does your url start with "http://" or "https://" prefix. - L'URL ne respecte pas le pattern standard. Votre URL doit commencer avec les préfixe "http://" ou "https://". - - - The url is empty. - L'URL est vide. - - - Username is ok or it is not needed. - Le nom d'utilisateur est correct ou non nécessaire. - - - Username is empty. - Le nom d'utilisateur est vide. - - - Password is ok or it is not needed. - Le mot de passe est correct ou non nécessaire. - - - Password is empty. - Le mot de passe est vide. - - - Select icon file for the feed - Sélectionner un icône pour le flux - - - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - - - Select icon - Sélectionner l'icône - - - Cancel - Annuler - - - Look in: - Label for field with icon file name textbox for selection dialog. - Rechercher dans : - - - Icon name: - Nom de l'icône : - - - Icon type: - Type d'icône : - - - Cannot add feed - Impossible d'ajouter le flux - - - Feed was not added due to error. - Le flux n'a pas été ajouté dû à une erreur. - - - Cannot edit feed - Impossible d'éditer le flux - - - All metadata fetched successfully. - Tout les méta-datas ont été extraites avec succès. - - - Feed and icon metadata fetched. - Flux et icône extraits. - - - Result: %1. - Résultat : %1. - - - Feed or icon metatada not fetched. - Flux ou icône non extrait. - - - Error: %1. - Erreur : %1. - - - No metadata fetched. - Aucune méta-donnée extraite. - - - Feed title - Titre du flux - - - Set title for your feed. - Définir un titre pour votre flux. - - - Feed description - Description du flux - - - Set description for your feed. - Définir une description pour votre flux. - - - Full feed url including scheme - URL du flux complet incluant le préfixe - - - Set url for your feed. - Définir l'URL pour votre flux. - - - Set username to access the feed. - Définir le nom d'utilisateur pour accéder au flux. - - - Set password to access the feed. - Définir le mot de passe pour accéder au flux. - - - Icon selection - Sélection de l'icône - - - Load icon from file... - Charger l'icône depuis un fichier... - - - Do not use icon - Ne pas utiliser les icônes - - - Use default icon - Utiliser les icônes par défaut - - - No metadata fetched so far. - Pas de métadonnées trouvé aussi loin. - - - Auto-update using global interval - Mise à jour automatique utilisant l'intervalle global - - - Auto-update every - Tout mettre à jour - - - Do not auto-update at all - Ne pas mettre tout à jour automatiquement - - - The description is ok. - - - - Feed was not edited due to error. - Le flux n'a pas été édité dû à une erreur. - - - Icon fetched successfully. - - - - Icon metadata fetched. - - - - Icon metatada not fetched. - - - - No icon fetched. - - - - Fetch icon from feed - - - - - FormImportExport - - &Select file - - - - Operation results - - - - No file is selected. - - - - No operation executed yet. - - - - Export feeds - - - - Destination file - - - - Source feeds && categories - - - - Source file - Fichier source - - - Target feeds && categories - - - - Import feeds - Importer des flux - - - OPML 2.0 files (*.opml) - Fichier OPML 2.0 (*.opml) - - - Select file for feeds export - - - - File is selected. - Le fichier est sélectionné - - - Select file for feeds import - - - - Cannot open source file. - - - - Feeds were loaded. - - - - Error, file is not well-formed. Select another file. - - - - Error occurred. File is not well-formed. Select another file. - - - - Feeds were exported successfully. - - - - Cannot write into destination file. - - - - Critical error occurred. - Erreur critique rencontrée - - - &Check all items - - - - &Uncheck all items - + @@ -1457,18 +873,6 @@ Auto-update status: %5 Fee&ds && categories Flux && catégories - - Mark all messages (without message filters) from selected feeds as read. - Marquer tout les messages (sans les filtres) de la sélection comme lus. - - - Mark all messages (without message filters) from selected feeds as unread. - Marquer tout les messages (sans les filtres) de la sélection comme non-lus. - - - Displays all messages from selected feeds/categories in a new "newspaper mode" tab. Note that messages are not set as read automatically. - Afficher tout les messages depuis les flux/catégories sélectionnées dans un nouvel onglet en mode "journal". Notez que les messages ne sont pas marqué lus automatiquement. - Hides main window if it is visible and shows it if it is hidden. Cacher la fenêtre principale si il est visible et la montrer si il est cacher. @@ -1493,34 +897,6 @@ Auto-update status: %5 &Delete selected messages &Supprimer les messages sélectionnés - - Deletes all messages from selected feeds. - Supprimer tout les messages des flux sélectionnés. - - - Marks all messages in all feeds read. This does not take message filters into account. - Marquer tout les messages dans tout les flux lus. Cela ne tient pas en compte les filtres de messages. - - - Deletes all messages from all feeds. - Supprimer tout les messages de tout les flux. - - - Update &all feeds - Mettre à jour &tout les flux - - - Update &selected feeds - Mettre à jour les flux &sélectionnés - - - &Edit selected feed/category - &Éditer le flux/catégorie sélectionné - - - &Delete selected feed/category - &Supprimer le flux/catégorie sélectionné - Settings Paramètres @@ -1529,10 +905,6 @@ Auto-update status: %5 Hides or displays the main menu. Cacher ou montrer le menu principal. - - Add &new feed/category - Ajout un &nouveau flux/catégorie - &Close all tabs except current one &Fermer tout les onglets sauf le courant @@ -1549,18 +921,6 @@ Auto-update status: %5 Mark &selected messages as &unread Marquer les messages &sélectionner comme &non lu - - &Mark selected feeds as read - &Marquer les flux sélectionnés comme lus - - - &Mark selected feeds as unread - &Marquer les flux sélectionnés comme non lus - - - &Clean selected feeds - &Nettoyer les flux sélectionnés - Open selected source articles in &external browser Ouvrir les sources de l'article sélectionnées dans le navigateur &externe @@ -1573,26 +933,6 @@ Auto-update status: %5 Open selected source articles in &internal browser Ouvrir les sources de l'article sélectionnées dans le navigateur &interne - - &Mark all feeds as &read - &Marquer tout les flux comme &lus - - - View selected feeds in &newspaper mode - Voir les flux sélectionnés dans le mode &journal - - - &Clean all feeds - &Nettoyer tout les flux - - - Select &next feed/category - Sélectionner le flux/catégorie &suivant - - - Select &previous feed/category - Sélection le flux/catégorie &précédent - Select &next message Sélectionner le message &suivant @@ -1635,75 +975,39 @@ Auto-update status: %5 Switch visibility of main &window - + Cannot open external browser - + Cannot open external browser. Navigate to application website manually. - - - - New &feed - Nouveau &flux - - - Add new feed. - Ajouter un nouveau flux - - - New &category - Nouvelle &catégorie - - - Add new category. - Ajouter une nouvelle catégorie + &Toolbars - + Switch visibility of main toolbars. - + &Feed/message list headers - - - - &Import feeds - - - - Imports feeds you want from selected file. - - - - &Export feeds - - - - Exports feeds you want to selected file. - + Close all tabs except current one. - - - - &Recycle bin - &Corbeille + Report a &bug (GitHub)... - + Report a bug (BitBucket)... - + &Donate via PayPal @@ -1711,19 +1015,7 @@ Auto-update status: %5 Display &wiki - - - - &Empty recycle bin - - - - &Restore all messages - - - - Restore &selected messages - + &Restart @@ -1731,94 +1023,214 @@ Auto-update status: %5 &Restore database/settings - + &Backup database/settings - + Switch message list layout orientation - + &Downloads - + Send selected message via e-mail - + &Cleanup database - + - Show only unread feeds/categories - + Add &new item + - &Fetch feed metadata - + &Services + - &Expand/collapse selected feed/category - + Update &all items + + + + Ctrl+Shift+U + + + + Update &selected items + + + + Ctrl+U + + + + &Edit selected item + + + + &Delete selected item + + + + &Mark selected items as read + + + + Mark all messages (without message filters) from selected items as read. + + + + &Mark selected items as unread + + + + Mark all messages (without message filters) from selected items as unread. + + + + &Clean selected items + + + + Deletes all messages from selected items. + + + + &Mark all items as &read + + + + Marks all messages in all items read. This does not take message filters into account. + + + + View selected items in &newspaper mode + + + + Displays all messages from selected item in a new "newspaper mode" tab. Note that messages are not set as read automatically. + + + + &Clean all items + + + + Deletes all messages from all items. + + + + Ctrl+Shift+C + + + + Select &next item + + + + S + + + + Select &previous item + + + + A + + + + Show only unread items + + + + &Expand/collapse selected item + + + + E + + + + &Add new service account + + + + &Delete selected service account + + + + &Edit selected service account + + + + &Restore selected messages + + + + No possible actions + FormRestoreDatabaseSettings Restore database/settings - + Operation results - + Restore database - + Restore settings - + Restart - + No operation executed yet. - + Restoration was initiated. Restart to proceed. - + You need to restart application for restoration process to finish. - + Source directory - + &Select directory - + Database and/or settings were not copied to restoration directory successully. - + Select source directory - + Good source directory is specified. - + @@ -1914,10 +1326,6 @@ Auto-update status: %5 Author Auteur - - Email - Email - Socks5 Socks5 @@ -2293,25 +1701,25 @@ Les auteurs de cette application NE sont PAS responsable de la perte de données Toolbars - + Toolbar for feeds list - + Toolbar for messages list - + Select toolbar to edit - + Some critical settings were changed and will be applied after the application gets restarted. You have to restart manually. - + Do you want to restart now? @@ -2319,70 +1727,70 @@ You have to restart manually. Check for updates on application startup - + Use custom date/time format (overrides format loaded from active localization) - + Executables (*) File filter for external browser selection dialog. ---------- File filter for external e-mail selection dialog. - + Remove all read messages from all feeds on application exit - + When new message arrives from feed and duplicate exists, then its content is updated and new message is dropped. - + Remove duplicate messages - + Downloads - + Target directory for downloaded files - + Ask for each individual downloaded file - + Target directory where all downloaded files are saved - + &Browse - + Select downloads target directory - + &Show password - + Web browser & e-mail & proxy - + Remove junk Trolltech registry key (HKCU\Software\Trolltech) when application quits (Use at your own risk!) - + Working database - + Mouse gestures work with middle mouse button. Possible gestures are: @@ -2390,101 +1798,616 @@ File filter for external e-mail selection dialog. • next web page (drag mouse right), • reload current web page (drag mouse up), • open new web browser tab (drag mouse down). - + Use custom external web browser - + External e-mail client - + Use custom external e-mail client - + E-mail client executable - + Executable file of e-mail client - + Select client - + Placeholders: • %1 - title of selected message, • %2 - body of selected message. - + Save all downloaded files to - + Select e-mail executable - + Mozilla Thunderbird - + Working database which you have full access to. - + Working database is empty. - + Working database is ok. - + Notification position - + (Tray icon is not available.) - + Bottom-left corner - + Top-left corner - + Bottom-right corner - + Top-right corner - + Internal message browser fonts - + Standard font - + Note that speed of used MySQL server and latency of used connection medium HEAVILY influences the final performance of this application. Using slow database connections leads to bad performance when browsing feeds or messages. - + Fancy && modern popup notifications (This uses OS native notifications via D-Bus if available.) - + + + + E-mail + + + + + FormStandardCategoryDetails + + Parent category + Catégorie parente + + + Select parent item for your category. + Sélectionner l'article parent pour votre catégorie. + + + Title + Titre + + + Description + Description + + + Icon + Icône + + + Select icon for your category. + Sélectionner un icône pour votre catégorie + + + Add new category + Ajouter une nouvelle catégorie + + + Edit existing category + + + + Cannot add category + Impossible d'ajouter une catégorie + + + Category was not added due to error. + La catégorie n'a pas été ajoutée dû à une erreur + + + Cannot edit category + Impossible d'éditer la catégori + + + Category was not edited due to error. + La catégorie n'a pas été éditée dû à une erreur. + + + Category name is ok. + Le nom de la catégorie est correct. + + + Category name is too short. + Le nom de la catégorie est trop court. + + + Description is empty. + La description est vide. + + + The description is ok. + + + + Select icon file for the category + Sélectionner un icône pour la catégorie + + + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + + + Select icon + Sélectionner l'icône + + + Cancel + Annuler + + + Look in: + Label to describe the folder for icon file selection dialog. + Rechercher dans : + + + Icon name: + Nom de l'icône : + + + Icon type: + Type d'icône : + + + Category title + Titre de la catégorie + + + Set title for your category. + Définir un titre pour votre catégorie + + + Category description + Description de la catégorie + + + Set description for your category. + Définir une description pour votre catégorie. + + + Icon selection + Sélection de l'icône + + + Load icon from file... + Charger l'icône depuis un fichier... + + + Do not use icon + Ne pas utiliser les icônes + + + Use default icon + Utiliser les icônes par défaut + + + + FormStandardFeedDetails + + Parent category + Catégorie parente + + + Select parent item for your feed. + Sélectionner l'article parent pour votre flux. + + + Type + Type + + + Select type of the standard feed. + Sélectionner un type pour le flux standard. + + + Encoding + Encodage + + + Select encoding of the standard feed. If you are unsure about the encoding, then select "UTF-8" encoding. + Sélectionner un encodage pour le flux standard. Si vous n'êtes pas sûr à propos de l'encodage, sélectionner alors l'encodage "UTF-8". + + + Auto-update + Mise à jour automatique + + + Select the auto-update strategy for this feed. Default auto-update strategy means that the feed will be update in time intervals set in application settings. + Sélectionner la stratégie des mises à jour automatique pour ce flux. Par défaut, cette stratégie signifie que le flux sera mis à jour par intervalle de temps défini dans les paramètres de l'application. + + + minutes + minutes + + + Title + Titre + + + Description + Description + + + URL + URL + + + Fetch it now + Le chercher maintenant + + + Icon + Icône + + + Select icon for your feed. + Sélectionner un icône pour votre flux. + + + Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. + Certain flux requière une authentification, incluant les flux GMail. Les schémas d'authentification BASIC, NTLM-2 et DIGEST-MD5 sont supportés. + + + Requires authentication + Authentification requise + + + Username + Nom d'utilisateur + + + Password + Mot de passe + + + Fetch metadata + Chercher les métadonnées + + + Add new feed + Ajouter un nouveau flux + + + Edit existing feed + + + + Feed name is ok. + Le nom du flux est correct. + + + Feed name is too short. + Le nom du flux est trop court. + + + Description is empty. + La description est vide. + + + The description is ok. + + + + The url is ok. + L'URL est correct. + + + The url does not meet standard pattern. Does your url start with "http://" or "https://" prefix. + L'URL ne respecte pas le pattern standard. Votre URL doit commencer avec les préfixe "http://" ou "https://". + + + The url is empty. + L'URL est vide. + + + Username is ok or it is not needed. + Le nom d'utilisateur est correct ou non nécessaire. + + + Username is empty. + Le nom d'utilisateur est vide. + + + Password is ok or it is not needed. + Le mot de passe est correct ou non nécessaire. + + + Password is empty. + Le mot de passe est vide. + + + Select icon file for the feed + Sélectionner un icône pour le flux + + + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + + + Select icon + Sélectionner l'icône + + + Cancel + Annuler + + + Look in: + Label for field with icon file name textbox for selection dialog. + Rechercher dans : + + + Icon name: + Nom de l'icône : + + + Icon type: + Type d'icône : + + + Cannot add feed + Impossible d'ajouter le flux + + + Feed was not added due to error. + Le flux n'a pas été ajouté dû à une erreur. + + + Cannot edit feed + Impossible d'éditer le flux + + + Feed was not edited due to error. + Le flux n'a pas été édité dû à une erreur. + + + All metadata fetched successfully. + Tout les méta-datas ont été extraites avec succès. + + + Feed and icon metadata fetched. + Flux et icône extraits. + + + Result: %1. + Résultat : %1. + + + Feed or icon metatada not fetched. + Flux ou icône non extrait. + + + Error: %1. + Erreur : %1. + + + No metadata fetched. + Aucune méta-donnée extraite. + + + Icon fetched successfully. + + + + Icon metadata fetched. + + + + Icon metatada not fetched. + + + + No icon fetched. + + + + Feed title + Titre du flux + + + Set title for your feed. + Définir un titre pour votre flux. + + + Feed description + Description du flux + + + Set description for your feed. + Définir une description pour votre flux. + + + Full feed url including scheme + URL du flux complet incluant le préfixe + + + Set url for your feed. + Définir l'URL pour votre flux. + + + Set username to access the feed. + Définir le nom d'utilisateur pour accéder au flux. + + + Set password to access the feed. + Définir le mot de passe pour accéder au flux. + + + Icon selection + Sélection de l'icône + + + Load icon from file... + Charger l'icône depuis un fichier... + + + Do not use icon + Ne pas utiliser les icônes + + + Use default icon + Utiliser les icônes par défaut + + + Fetch icon from feed + + + + No metadata fetched so far. + Pas de métadonnées trouvé aussi loin. + + + Auto-update using global interval + Mise à jour automatique utilisant l'intervalle global + + + Auto-update every + Tout mettre à jour + + + Do not auto-update at all + Ne pas mettre tout à jour automatiquement + + + + FormStandardImportExport + + &Select file + + + + &Check all items + + + + &Uncheck all items + + + + Operation results + + + + No file is selected. + + + + No operation executed yet. + + + + Destination file + + + + Source feeds && categories + + + + Export feeds + + + + Source file + Fichier source + + + Target feeds && categories + + + + Import feeds + Importer des flux + + + OPML 2.0 files (*.opml) + Fichier OPML 2.0 (*.opml) + + + Select file for feeds export + + + + File is selected. + Le fichier est sélectionné + + + Select file for feeds import + + + + Cannot open source file. + + + + Feeds were loaded. + + + + Error, file is not well-formed. Select another file. + + + + Error occurred. File is not well-formed. Select another file. + + + + Feeds were exported successfully. + + + + Cannot write into destination file. + + + + Critical error occurred. + Erreur critique rencontrée @@ -2580,23 +2503,23 @@ Aller sur le site de l'application pour les obtenir manuellement. Download update - + Downloaded %1% (update size is %2 kB). - + Downloading update... - + Downloaded successfully - + Package was downloaded successfully. - + Install update @@ -2608,11 +2531,11 @@ Aller sur le site de l'application pour les obtenir manuellement. Error occured during downloading of the package. - + Cannot launch external updater. Update application manually. - + Go to application website @@ -2623,11 +2546,11 @@ Aller sur le site de l'application pour les obtenir manuellement.IOFactory Cannot open file '%1' for reading. - + Cannot open file '%1' for writting. - + @@ -2721,46 +2644,54 @@ Aller sur le site de l'application pour les obtenir manuellement. Permanently deleted - + Is message permanently deleted from recycle bin? - + Attachments - + List of attachments. - + + + + Loading of messages from item '%s' failed. + + + + Loading of messages failed, maybe messages could not be downloaded. + MessagesToolBar Search messages - + Message search box - + Menu for highlighting messages - + No extra highlighting - + Highlight unread messages - + Highlight important messages - + Display all messages @@ -2768,11 +2699,11 @@ Aller sur le site de l'application pour les obtenir manuellement. Message highlighter - + Toolbar spacer - + @@ -2799,11 +2730,11 @@ Aller sur le site de l'application pour les obtenir manuellement. Problem with starting external e-mail client - + External e-mail client could not be started. - + @@ -2880,11 +2811,11 @@ Aller sur le site de l'application pour les obtenir manuellement. access to content was denied - + connection timed out or was cancelled - + @@ -2908,61 +2839,198 @@ Aller sur le site de l'application pour les obtenir manuellement.LANG_EMAIL nicolaslegall34@gmail.com - - Load initial feeds - - - - Do you want to load initial set of feeds? - - LANG_NAME Name of language, e.g. English. French - - You started %1 for the first time, now you can load initial set of feeds. - + + + ++ %n other feeds. + + + + - Welcome to %1 %2. - + Welcome to %1. + +Please, check NEW stuff included in this +version by clicking this popup notification. + + + + Welcome to %1. + + + + Load initial set of feeds + RecycleBin Recycle bin - + Recycle bin contains all deleted messages from all feeds. - + Recycle bin %1 - + %n deleted message(s). - + + + + ShortcutCatcher Reset to original shortcut. - + Clear current shortcut. - + Click and hit new shortcut. - + + + + + StandardCategory + + %1 (category)%2%3 + Tooltip for standard feed. + + + + +This category does not contain any nested items. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + + StandardFeed + + Metadata not fetched + + + + Metadata was not fetched because: %1. + + + + does not use auto-update + Describes feed auto-update status. + + + + uses global settings + Describes feed auto-update status. + + + + uses specific settings (%n minute(s) to next auto-update) + Describes feed auto-update status. + + + + + + + %1 (%2)%3 + +Network status: %6 +Encoding: %4 +Auto-update status: %5 + Tooltip for feed. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + + StandardServiceRoot + + This is obligatory service account for standard RSS/RDF/ATOM feeds. + + + + You started %1 for the first time, now you can load initial set of feeds. + + + + Do you want to load initial set of feeds? + + + + Error when loading initial feeds + + + + This is service account for standard RSS/RDF/ATOM feeds. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + Fetch metadata + Chercher les métadonnées + + + Import successfull, but some feeds/categories were not imported due to error. + + + + Import was completely successfull. + + + + Add new category + Ajouter une nouvelle catégorie + + + Add new feed + Ajouter un nouveau flux + + + Export feeds + + + + Import feeds + Importer des flux @@ -2980,11 +3048,15 @@ Aller sur le site de l'application pour les obtenir manuellement.SystemFactory New version available - + Click the bubble for more information. - + + + + anonymous + @@ -2992,7 +3064,7 @@ Aller sur le site de l'application pour les obtenir manuellement. %1 Unread news: %2 - + @@ -3023,7 +3095,7 @@ Unread news: %2 Displays main menu. - + Main menu @@ -3035,14 +3107,14 @@ Unread news: %2 Downloads - + ToolBarEditor Activated actions - + Available actions @@ -3050,39 +3122,39 @@ Unread news: %2 Insert separator - + Insert spacer - + Separator - + Toolbar spacer - + Move action up - + Move action down - + Add selected action - + Delete selected action - + Delete all actions - + @@ -3092,6 +3164,21 @@ Unread news: %2 Fermer en premier les fenêtres modales ouvertes. + + TtRssServiceRoot + + This is service account TT-RSS (TinyTiny RSS) server. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + WebBrowser @@ -3244,63 +3331,63 @@ Unread news: %2 Open link in external browser - + Open the hyperlink in external browser. - + Print - + Print current web page. - + HTML web pages (*.html) - + Select destination file for web page - + Cannot save web page - + Web page cannot be saved because destination file is not writtable. - + Save target as... - + Download content from the hyperlink. - + Save page as... - + Save image to disk. - + Save image as... - + source_page - + Search "%1" via Google... - + - \ No newline at end of file + diff --git a/localization/rssguard-it_IT.ts b/localization/rssguard-it_IT.ts index 4813b3b44..e6470cfc7 100644 --- a/localization/rssguard-it_IT.ts +++ b/localization/rssguard-it_IT.ts @@ -1,4 +1,6 @@ - + + + AdBlockAddSubscriptionDialog @@ -15,15 +17,15 @@ Entered title is empty. - + Entered url is okay. - + Entered url is empty. - + Title @@ -55,7 +57,7 @@ Note that Adblock may significantly slow this application down once you activate huge subscriptions. Too many rules is not good for performance. Also, make sure you restart application after you disable Adblock if you wish to have low memory footprint. Adblock is known to use much system memory. Also note that some resources are cached by internal web browser. Thus, after changing some rules or subscriptions they will fully apply only for new application instances. Make sure you restart RSS Guard for best Adblock experience. - + Options @@ -63,11 +65,11 @@ Also note that some resources are cached by internal web browser. Thus, after ch Filter rules - + Use only essential part of EasyList (for performance reasons) - + Add rule @@ -91,7 +93,7 @@ Also note that some resources are cached by internal web browser. Thus, after ch Rules writing guide - + @@ -102,11 +104,11 @@ Also note that some resources are cached by internal web browser. Thus, after ch Show Adblock &settings - + Disable on %1 - + Disable only on this page @@ -114,11 +116,11 @@ Also note that some resources are cached by internal web browser. Thus, after ch Blocked popup windows - + %1 with (%2) - + No content blocked @@ -126,37 +128,37 @@ Also note that some resources are cached by internal web browser. Thus, after ch Blocked some content - click to edit rule - + Adblock - up and running - + Adblock - not running - + AdBlockSubscription Cannot load subscription! - + AdBlockTreeWidget Please write your rule here - + %1 (recently updated) - + %1 (error: %2) - + Add rule @@ -175,92 +177,74 @@ Also note that some resources are cached by internal web browser. Thus, after ch Output directory is not writable. - + Settings file not copied to output directory successfully. - + Database file not copied to output directory successfully. - + Database restoration was not initiated. Make sure that output directory is writable. - + Settings restoration was not initiated. Make sure that output directory is writable. - - - - - Category - - %1 (category)%2%3 - Tooltip for standard feed. - - - - -This category does not contain any nested items. - - - - %n unread message(s). - Tooltip for "unread" column of feed list. - + DatabaseCleaner Shrinking database file... - + Database file shrinked... - + Removing read messages... - + Read messages purged... - + Recycle bin purged... - + Removing old messages... - + Purging recycle bin... - + Old messages purged... - + DatabaseFactory MySQL server works as expected. - + No MySQL server is running in the target destination. - + Access denied. Invalid username or password used. Access to MySQL server was denied. - + Unknown error. @@ -269,27 +253,30 @@ This category does not contain any nested items. Selected database does not exist (yet). - + MySQL/MariaDB (dedicated database) - + SQLite (embedded database) - + DiscoverFeedsButton This website does not contain any feeds. - + Click me to add feeds from this website. This website contains %n feed(s). - + + + + @@ -304,72 +291,72 @@ This website contains %n feed(s). Error opening output file: %1 - + &Try again - + &Stop - + &Open file - + Select destination for downloaded file - + Error: %1 - + Errore: %1. {1?} Download directory couldn't be created - + Error when saving file: %1 - + %1 of %2 (%3 per second) - %4 - + %1 of %2 - download completed - + Open &directory - + Cannot open file - + Cannot open output file. Open it manually. - + Cannot open directory - + Cannot open output directory. Open it manually. - + Download finished - + - File '%1' is downloaded. + File '%1' is downloaded. Click here to open parent directory. - + URL: %1 @@ -377,11 +364,11 @@ Click here to open parent directory. Local file: %1 - + Selection of local file cancelled. - + @@ -392,11 +379,17 @@ Click here to open parent directory. %n minutes remaining - + + + + %n seconds remaining - + + + + bytes @@ -416,47 +409,10 @@ Click here to open parent directory. Downloading %n file(s)... - - - - - Feed - - does not use auto-update - Describes feed auto-update status. - - - - uses global settings - Describes feed auto-update status. - - - - uses specific settings (%n minute(s) to next auto-update) - Describes feed auto-update status. - - - - %1 (%2)%3 - -Network status: %6 -Encoding: %4 -Auto-update status: %5 - Tooltip for feed. - - - - %n unread message(s). - Tooltip for "unread" column of feed list. - - - - Metadata not fetched - - - - Metadata was not fetched because: %1 - + + + + @@ -465,58 +421,32 @@ Auto-update status: %5 Toolbar for messages Toolbar per messaggi - - Feed update started - Text display in status bar when feed update is started. - Aggiornamento feed iniziato - - - Updated feed '%1' - Text display in status bar when particular feed is updated. - Feed '%1' aggiornato - Toolbar for feeds Toolbar per i feed - - Error when loading initial feeds - - Cannot cleanup database - + Cannot cleanup database, because another critical action is running. - - - - Cannot update all items - - - - You cannot update all items because another another critical operation is ongoing. - - - - New messages downloaded - + FeedsImportExportModel (category) - + (feed) - + Category - + @@ -539,25 +469,38 @@ Auto-update status: %5 Name of root item of feed list which can be seen in feed add/edit dialog. Root - - Invalid tree data. - - - - Import successfull, but some feeds/categories were not imported due to error. - - - - Import was completely successfull. - - Starting auto-update of some feeds - + I will auto-update %n feed(s). - + + + + + + + Cannot update all items + + + + You cannot update all items because another another critical operation is ongoing. + + + + Feed update started + Text display in status bar when feed update is started. + Aggiornamento feed iniziato + + + Updated feed '%1' + Text display in status bar when particular feed is updated. + Feed '%1' aggiornato + + + New messages downloaded + @@ -569,14 +512,6 @@ Auto-update status: %5 FeedsView - - Cannot add standard category - Impossibile aggiungere categoria standard - - - Cannot add standard feed - Impossibile aggiungere feed standard - Cannot edit item Impossibile modificare elemento @@ -585,65 +520,54 @@ Auto-update status: %5 Cannot delete item Impossibile eliminare l'elemento - - You are about to delete selected feed or category. - - - - Deletion of item failed. - - - - Selected item was not deleted due to error. - - - - Do you really want to delete selected item? - - - - Permanently delete messages - - - - You are about to permanenty delete all messages from your recycle bin. - - - - Do you really want to empty your recycle bin? - - Context menu for empty space - - - - Context menu for recycle bin - - - - You cannot add new standard category now because another critical operation is ongoing. - - - - You cannot add new standard feed now because another critical operation is ongoing. - + Selected item cannot be edited because another critical operation is ongoing. - + Selected item cannot be deleted because another critical operation is ongoing. - - - - Delete feed/category - + Context menu for categories - + + + + Selected item cannot be edited, this is not (yet?) supported. + + + + Deleting "%1" + + + + You are about to completely delete item "%1". + + + + Are you sure? + + + + Cannot delete "%1" + + + + This item cannot be deleted because something critically failed. Submit bug report. + + + + This item cannot be deleted, because it does not support it +or this functionality is not implemented yet. + + + + Context menu for other items + @@ -690,11 +614,7 @@ Auto-update status: %5 <b>%8</b><br><b>Version:</b> %1 (build on %2 with CMake %3)<br><b>Revision:</b> %4<br><b>Build date:</b> %5<br><b>Qt:</b> %6 (compiled against %7)<br> - - - - <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~email</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> - <body>%5 è un (davvero) piccolo lettore di feed.<br><br>Questo software viene distribuito sotto i termini della GNU General Public License, version 3.<br><br>Contatti:<ul><li><a href="mailto://%1">%1</a> ~email</li><li><a href="%2">%2</a> ~website</li></ul>Puoi ottonere il codice sorgente di %5 dal suo sito web.<br><br><br>Copyright (C) 2011-%3 %4</body> + About %1 @@ -703,42 +623,46 @@ Auto-update status: %5 Settings type - + Settings file - + Database root path - + FULLY portable - + PARTIALLY portable - + Resources Risorse + + <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~e-mail</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> + + FormBackupDatabaseSettings Backup database/settings - + Backup properties - + Items to backup - + Database @@ -750,218 +674,93 @@ Auto-update status: %5 Backup name - + Operation results - + Common name for backup files - + No operation executed yet. - + Backup was created successfully. - + Backup name cannot be empty. - + Backup name looks okay. - + Backup failed. - + Output directory - + &Select directory - + Backup was created successfully and stored in target directory. - + Select destination directory - + Good destination directory is specified. - - - - - FormCategoryDetails - - Parent category - - - - Select parent item for your category. - - - - Title - Titolo - - - Description - Descrizione - - - Icon - Icona - - - Select icon for your category. - Seleziona icona per la tua categoria. - - - Add new category - Aggiungi nuova categoria - - - Edit existing category - Modifica categoria esistente - - - Cannot add category - Impossibile aggiungere categria - - - Category was not added due to error. - - - - Cannot edit category - Impossibile modificare categoria - - - Category was not edited due to error. - - - - Category name is ok. - Il nome della categoria è ok. - - - Category name is too short. - Il nome della categoria è troppo corto. - - - Description is empty. - La descrizione è vuota. - - - Select icon file for the category - Seleziona icona per la categoria - - - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - Immagini (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - - - Select icon - Seleziona icona - - - Cancel - Annulla - - - Look in: - Label to describe the folder for icon file selection dialog. - - - - Icon name: - Nome icona: - - - Icon type: - Tipo icona: - - - Category title - Titolo categoria - - - Set title for your category. - Imposta titolo per la tua categoria. - - - Category description - Descrizione categoria - - - Set description for your category. - Imposta descrizione per la tua categoria. - - - Icon selection - Selezione icona - - - Load icon from file... - Carica icona dal file... - - - Do not use icon - Non usare icona - - - Use default icon - Usa icona di default - - - The description is ok. - + FormDatabaseCleanup Cleanup database - + Remove all messages older than - + day(s) - + + + + Shrink database file - + Database information - + Database file size - + Database type - + Progress - + I am ready. @@ -969,414 +768,31 @@ Auto-update status: %5 Database cleanup is running. - + Database cleanup is completed. - + Database cleanup failed. - + Cleanup settings (all checked items are completely erased from database) - + Remove all read messages (not those from recycle bin) - + Remove all messages from recycle bin - + Remove all starred messages (including those from recycle bin) - - - - - FormFeedDetails - - Parent category - - - - Select parent item for your feed. - - - - Type - Tipo - - - Select type of the standard feed. - Seleziona tipo di feed standard. - - - Encoding - - - - Select encoding of the standard feed. If you are unsure about the encoding, then select "UTF-8" encoding. - - - - Auto-update - Auto-aggiorna - - - Select the auto-update strategy for this feed. Default auto-update strategy means that the feed will be update in time intervals set in application settings. - - - - minutes - minuti - - - Title - Titolo - - - Description - Descrizione - - - URL - URL - - - Fetch it now - Recupera adesso - - - Icon - Icona - - - Select icon for your feed. - Seleziona icona per il tuo feed. - - - Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. - - - - Requires authentication - Richiede autenticazione - - - Username - Nome utente - - - Password - Password - - - Fetch metadata - Recupera metadata - - - Add new feed - Aggiungi nuovo feed - - - Edit existing feed - Modifica feed esistente - - - Feed name is ok. - Il nome feed è ok. - - - Feed name is too short. - Il nome feed è troppo corto. - - - Description is empty. - La descrizione è vuota. - - - The url is ok. - L'url è ok. - - - The url does not meet standard pattern. Does your url start with "http://" or "https://" prefix. - - - - The url is empty. - L'url è vuoto. - - - Username is ok or it is not needed. - - - - Username is empty. - Nome utente vuoto. - - - Password is ok or it is not needed. - - - - Password is empty. - La password è vuota. - - - Select icon file for the feed - Seleziona icona per il feed - - - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - Immagini (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - - - Select icon - Seleziona icona - - - Cancel - Annulla - - - Look in: - Label for field with icon file name textbox for selection dialog. - - - - Icon name: - Nome icona: - - - Icon type: - Tipo icona: - - - Cannot add feed - Impossibile aggiungere feed - - - Feed was not added due to error. - Feed non aggiunto a causa di un errore. - - - Cannot edit feed - Impossibile modificare il feed - - - All metadata fetched successfully. - Tutti i metadata recuperati con successo. - - - Feed and icon metadata fetched. - Feed e icona metadata recuperati. - - - Result: %1. - Risultato: %1. - - - Feed or icon metatada not fetched. - Feed o icona metadata recuperati. - - - Error: %1. - Errore: %1. - - - No metadata fetched. - Nessun metadata recuperato. - - - Feed title - Titolo feed - - - Set title for your feed. - Imposta titolo per il tuo feed. - - - Feed description - Descrizione feed - - - Set description for your feed. - Imposta descrizione del tuo feed. - - - Full feed url including scheme - - - - Set url for your feed. - Imposta url per il tuo feed. - - - Set username to access the feed. - Imposta nome utente per accedere al feed. - - - Set password to access the feed. - Imposta password per accedere al feed. - - - Icon selection - Selezione icona - - - Load icon from file... - Carica icona dal file... - - - Do not use icon - Non usare icona - - - Use default icon - Usa icona di default - - - No metadata fetched so far. - - - - Auto-update using global interval - - - - Auto-update every - Auto-aggiorna ogni - - - Do not auto-update at all - - - - The description is ok. - - - - Feed was not edited due to error. - Feed non modificato a coausa di un errore. - - - Icon fetched successfully. - - - - Icon metadata fetched. - - - - Icon metatada not fetched. - - - - No icon fetched. - - - - Fetch icon from feed - - - - - FormImportExport - - &Select file - - - - Operation results - - - - No file is selected. - - - - No operation executed yet. - - - - Export feeds - - - - Destination file - - - - Source feeds && categories - - - - Source file - - - - Target feeds && categories - - - - Import feeds - - - - OPML 2.0 files (*.opml) - - - - Select file for feeds export - - - - File is selected. - - - - Select file for feeds import - - - - Cannot open source file. - - - - Feeds were loaded. - - - - Error, file is not well-formed. Select another file. - - - - Error occurred. File is not well-formed. Select another file. - - - - Feeds were exported successfully. - - - - Cannot write into destination file. - - - - Critical error occurred. - - - - &Check all items - - - - &Uncheck all items - + @@ -1423,7 +839,7 @@ Auto-update status: %5 Switch &importance of selected messages - + Quit the application. @@ -1455,19 +871,7 @@ Auto-update status: %5 Fee&ds && categories - - - - Mark all messages (without message filters) from selected feeds as read. - - - - Mark all messages (without message filters) from selected feeds as unread. - - - - Displays all messages from selected feeds/categories in a new "newspaper mode" tab. Note that messages are not set as read automatically. - + Hides main window if it is visible and shows it if it is hidden. @@ -1483,7 +887,7 @@ Auto-update status: %5 &About application - + Displays extra info about this application. @@ -1493,34 +897,6 @@ Auto-update status: %5 &Delete selected messages &Elimina i messaggi selezionati - - Deletes all messages from selected feeds. - Elimina tutti i messaggi dai feed selezionati. - - - Marks all messages in all feeds read. This does not take message filters into account. - - - - Deletes all messages from all feeds. - Elimina tutti i messaggi da tutti i feed. - - - Update &all feeds - - - - Update &selected feeds - - - - &Edit selected feed/category - - - - &Delete selected feed/category - - Settings Impostazioni @@ -1529,13 +905,9 @@ Auto-update status: %5 Hides or displays the main menu. Nascondi o visualizza il menu principale. - - Add &new feed/category - - &Close all tabs except current one - + &Close current tab @@ -1543,67 +915,35 @@ Auto-update status: %5 Mark &selected messages as &read - + Mark &selected messages as &unread - - - - &Mark selected feeds as read - - - - &Mark selected feeds as unread - - - - &Clean selected feeds - + Open selected source articles in &external browser - + Open selected messages in &internal browser - + Open selected source articles in &internal browser - - - - &Mark all feeds as &read - - - - View selected feeds in &newspaper mode - - - - &Clean all feeds - - - - Select &next feed/category - - - - Select &previous feed/category - + Select &next message - + Select &previous message - + Check for &updates - + Enable &JavaScript @@ -1623,11 +963,11 @@ Auto-update status: %5 &Fullscreen - + &Feed list - + &Main menu @@ -1635,7 +975,7 @@ Auto-update status: %5 Switch visibility of main &window - + Cannot open external browser @@ -1643,23 +983,7 @@ Auto-update status: %5 Cannot open external browser. Navigate to application website manually. - - - - New &feed - Nuovo &feed - - - Add new feed. - Aggiungi nuovo feed. - - - New &category - Nuova &categoria - - - Add new category. - Aggiungi nuova categoria. + &Toolbars @@ -1671,154 +995,242 @@ Auto-update status: %5 &Feed/message list headers - - - - &Import feeds - - - - Imports feeds you want from selected file. - - - - &Export feeds - - - - Exports feeds you want to selected file. - + Close all tabs except current one. - - - - &Recycle bin - + Report a &bug (GitHub)... - + Report a bug (BitBucket)... - + &Donate via PayPal - + Display &wiki - - - - &Empty recycle bin - - - - &Restore all messages - - - - Restore &selected messages - + &Restart - + &Restore database/settings - + &Backup database/settings - + Switch message list layout orientation - + &Downloads - + Send selected message via e-mail - + &Cleanup database - + - Show only unread feeds/categories - + Add &new item + - &Fetch feed metadata - + &Services + - &Expand/collapse selected feed/category - + Update &all items + + + + Ctrl+Shift+U + + + + Update &selected items + + + + Ctrl+U + + + + &Edit selected item + + + + &Delete selected item + + + + &Mark selected items as read + + + + Mark all messages (without message filters) from selected items as read. + + + + &Mark selected items as unread + + + + Mark all messages (without message filters) from selected items as unread. + + + + &Clean selected items + + + + Deletes all messages from selected items. + + + + &Mark all items as &read + + + + Marks all messages in all items read. This does not take message filters into account. + + + + View selected items in &newspaper mode + + + + Displays all messages from selected item in a new "newspaper mode" tab. Note that messages are not set as read automatically. + + + + &Clean all items + + + + Deletes all messages from all items. + + + + Ctrl+Shift+C + + + + Select &next item + + + + S + + + + Select &previous item + + + + A + + + + Show only unread items + + + + &Expand/collapse selected item + + + + E + + + + &Add new service account + + + + &Delete selected service account + + + + &Edit selected service account + + + + &Restore selected messages + + + + No possible actions + FormRestoreDatabaseSettings Restore database/settings - + Operation results - + Restore database - + Restore settings - + Restart - + No operation executed yet. - + Restoration was initiated. Restart to proceed. - + You need to restart application for restoration process to finish. - + Source directory - + &Select directory - + Database and/or settings were not copied to restoration directory successully. - + Select source directory - + Good source directory is specified. - + @@ -1914,10 +1326,6 @@ Auto-update status: %5 Author Autore - - Email - Email - Socks5 Socks5 @@ -1932,7 +1340,7 @@ Auto-update status: %5 Tray area && notifications - + Tabs @@ -1944,11 +1352,11 @@ Auto-update status: %5 Middle mouse button single-click - + Open new tabs with left mouse button double-click on tab bar - + Enable mouse gestures @@ -1956,7 +1364,7 @@ Auto-update status: %5 Queue new tabs (with hyperlinks) after the active tab - + no icon theme @@ -2001,7 +1409,7 @@ Auto-update status: %5 Some critical settings are not set. You must fix these settings in order confirm new settings. - + Messages @@ -2017,7 +1425,7 @@ Auto-update status: %5 Note that "%1" (without quotation marks) is placeholder for URL of selected message. - + Select web browser executable @@ -2073,7 +1481,7 @@ Auto-update status: %5 Use in-memory database as the working database - + Usage of in-memory working database has several advantages and pitfalls. Make sure that you are familiar with these before you turn this feature on. Advantages: @@ -2087,11 +1495,11 @@ Disadvantages: <li>application startup and shutdown can take little longer (max. 2 seconds).</li> </ul> Authors of this application are NOT responsible for lost data. - + in-memory database switched - + Internal web browser @@ -2103,7 +1511,7 @@ Authors of this application are NOT responsible for lost data. WARNING: Note that switching to another data storage type will NOT copy existing your data from currently active data storage to newly selected one. - + Database driver @@ -2115,11 +1523,11 @@ Authors of this application are NOT responsible for lost data. Test setup - + Right mouse button double-click - + Auto-update all feeds every @@ -2135,7 +1543,7 @@ Authors of this application are NOT responsible for lost data. Connection timeout is time interval which is reserved for downloading new messages for the feed. If this time interval elapses, then download process is aborted. - + ms @@ -2163,7 +1571,7 @@ Authors of this application are NOT responsible for lost data. data storage backend changed - + Hostname is empty. @@ -2199,7 +1607,7 @@ Authors of this application are NOT responsible for lost data. No connection test triggered so far. - + Note that these settings are applied only on newly established connections. @@ -2239,11 +1647,11 @@ Authors of this application are NOT responsible for lost data. Keep message selection in the middle of the message list viewport - + You did not executed any connection test yet. - + Launch %1 on operating system startup @@ -2263,7 +1671,7 @@ Authors of this application are NOT responsible for lost data. <html><head/><body><p>If unchecked, then default system-wide web browser is used.</p></body></html> - + Feeds && categories @@ -2275,7 +1683,7 @@ Authors of this application are NOT responsible for lost data. Enter format for count of messages displayed next to each feed/category in feed list. Use "%all" and "%unread" strings which are placeholders for the actual count of all (or unread) messages. - + custom external browser is not set correctly @@ -2301,7 +1709,7 @@ Authors of this application are NOT responsible for lost data. Some critical settings were changed and will be applied after the application gets restarted. You have to restart manually. - + Do you want to restart now? @@ -2309,70 +1717,70 @@ You have to restart manually. Check for updates on application startup - + Use custom date/time format (overrides format loaded from active localization) - + Executables (*) File filter for external browser selection dialog. ---------- File filter for external e-mail selection dialog. - + Remove all read messages from all feeds on application exit - + When new message arrives from feed and duplicate exists, then its content is updated and new message is dropped. - + Remove duplicate messages - + Downloads - + Target directory for downloaded files - + Ask for each individual downloaded file - + Target directory where all downloaded files are saved - + &Browse - + Select downloads target directory - + &Show password - + Web browser & e-mail & proxy - + Remove junk Trolltech registry key (HKCU\Software\Trolltech) when application quits (Use at your own risk!) - + Working database - + Mouse gestures work with middle mouse button. Possible gestures are: @@ -2380,101 +1788,616 @@ File filter for external e-mail selection dialog. • next web page (drag mouse right), • reload current web page (drag mouse up), • open new web browser tab (drag mouse down). - + Use custom external web browser - + External e-mail client - + Use custom external e-mail client - + E-mail client executable - + Executable file of e-mail client - + Select client - + Placeholders: • %1 - title of selected message, • %2 - body of selected message. - + Save all downloaded files to - + Select e-mail executable - + Mozilla Thunderbird - + Working database which you have full access to. - + Working database is empty. - + Working database is ok. - + Notification position - + (Tray icon is not available.) - + Bottom-left corner - + Top-left corner - + Bottom-right corner - + Top-right corner - + Internal message browser fonts - + Standard font - + Note that speed of used MySQL server and latency of used connection medium HEAVILY influences the final performance of this application. Using slow database connections leads to bad performance when browsing feeds or messages. - + Fancy && modern popup notifications (This uses OS native notifications via D-Bus if available.) - + + + + E-mail + + + + + FormStandardCategoryDetails + + Parent category + + + + Select parent item for your category. + + + + Title + Titolo + + + Description + Descrizione + + + Icon + Icona + + + Select icon for your category. + Seleziona icona per la tua categoria. + + + Add new category + Aggiungi nuova categoria + + + Edit existing category + Modifica categoria esistente + + + Cannot add category + Impossibile aggiungere categria + + + Category was not added due to error. + + + + Cannot edit category + Impossibile modificare categoria + + + Category was not edited due to error. + + + + Category name is ok. + Il nome della categoria è ok. + + + Category name is too short. + Il nome della categoria è troppo corto. + + + Description is empty. + La descrizione è vuota. + + + The description is ok. + + + + Select icon file for the category + Seleziona icona per la categoria + + + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + Immagini (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + + + Select icon + Seleziona icona + + + Cancel + Annulla + + + Look in: + Label to describe the folder for icon file selection dialog. + + + + Icon name: + Nome icona: + + + Icon type: + Tipo icona: + + + Category title + Titolo categoria + + + Set title for your category. + Imposta titolo per la tua categoria. + + + Category description + Descrizione categoria + + + Set description for your category. + Imposta descrizione per la tua categoria. + + + Icon selection + Selezione icona + + + Load icon from file... + Carica icona dal file... + + + Do not use icon + Non usare icona + + + Use default icon + Usa icona di default + + + + FormStandardFeedDetails + + Parent category + + + + Select parent item for your feed. + + + + Type + Tipo + + + Select type of the standard feed. + Seleziona tipo di feed standard. + + + Encoding + + + + Select encoding of the standard feed. If you are unsure about the encoding, then select "UTF-8" encoding. + + + + Auto-update + Auto-aggiorna + + + Select the auto-update strategy for this feed. Default auto-update strategy means that the feed will be update in time intervals set in application settings. + + + + minutes + minuti + + + Title + Titolo + + + Description + Descrizione + + + URL + URL + + + Fetch it now + Recupera adesso + + + Icon + Icona + + + Select icon for your feed. + Seleziona icona per il tuo feed. + + + Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. + + + + Requires authentication + Richiede autenticazione + + + Username + Nome utente + + + Password + Password + + + Fetch metadata + Recupera metadata + + + Add new feed + Aggiungi nuovo feed + + + Edit existing feed + Modifica feed esistente + + + Feed name is ok. + Il nome feed è ok. + + + Feed name is too short. + Il nome feed è troppo corto. + + + Description is empty. + La descrizione è vuota. + + + The description is ok. + + + + The url is ok. + L'url è ok. + + + The url does not meet standard pattern. Does your url start with "http://" or "https://" prefix. + + + + The url is empty. + L'url è vuoto. + + + Username is ok or it is not needed. + + + + Username is empty. + Nome utente vuoto. + + + Password is ok or it is not needed. + + + + Password is empty. + La password è vuota. + + + Select icon file for the feed + Seleziona icona per il feed + + + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + Immagini (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + + + Select icon + Seleziona icona + + + Cancel + Annulla + + + Look in: + Label for field with icon file name textbox for selection dialog. + + + + Icon name: + Nome icona: + + + Icon type: + Tipo icona: + + + Cannot add feed + Impossibile aggiungere feed + + + Feed was not added due to error. + Feed non aggiunto a causa di un errore. + + + Cannot edit feed + Impossibile modificare il feed + + + Feed was not edited due to error. + Feed non modificato a coausa di un errore. + + + All metadata fetched successfully. + Tutti i metadata recuperati con successo. + + + Feed and icon metadata fetched. + Feed e icona metadata recuperati. + + + Result: %1. + Risultato: %1. + + + Feed or icon metatada not fetched. + Feed o icona metadata recuperati. + + + Error: %1. + Errore: %1. + + + No metadata fetched. + Nessun metadata recuperato. + + + Icon fetched successfully. + + + + Icon metadata fetched. + + + + Icon metatada not fetched. + + + + No icon fetched. + + + + Feed title + Titolo feed + + + Set title for your feed. + Imposta titolo per il tuo feed. + + + Feed description + Descrizione feed + + + Set description for your feed. + Imposta descrizione del tuo feed. + + + Full feed url including scheme + + + + Set url for your feed. + Imposta url per il tuo feed. + + + Set username to access the feed. + Imposta nome utente per accedere al feed. + + + Set password to access the feed. + Imposta password per accedere al feed. + + + Icon selection + Selezione icona + + + Load icon from file... + Carica icona dal file... + + + Do not use icon + Non usare icona + + + Use default icon + Usa icona di default + + + Fetch icon from feed + + + + No metadata fetched so far. + + + + Auto-update using global interval + + + + Auto-update every + Auto-aggiorna ogni + + + Do not auto-update at all + + + + + FormStandardImportExport + + &Select file + + + + &Check all items + + + + &Uncheck all items + + + + Operation results + + + + No file is selected. + + + + No operation executed yet. + + + + Destination file + + + + Source feeds && categories + + + + Export feeds + + + + Source file + + + + Target feeds && categories + + + + Import feeds + + + + OPML 2.0 files (*.opml) + + + + Select file for feeds export + + + + File is selected. + + + + Select file for feeds import + + + + Cannot open source file. + + + + Feeds were loaded. + + + + Error, file is not well-formed. Select another file. + + + + Error occurred. File is not well-formed. Select another file. + + + + Feeds were exported successfully. + + + + Cannot write into destination file. + + + + Critical error occurred. + @@ -2553,7 +2476,7 @@ correntemente installato. Installation file is not available directly. Go to application website to obtain it manually. - + No new update available. @@ -2565,7 +2488,7 @@ Go to application website to obtain it manually. Cannot navigate to installation file. Check new installation downloads manually on project website. - + Download update @@ -2573,7 +2496,7 @@ Go to application website to obtain it manually. Downloaded %1% (update size is %2 kB). - + Downloading update... @@ -2593,30 +2516,30 @@ Go to application website to obtain it manually. Error occured - + Error occured during downloading of the package. - + Cannot launch external updater. Update application manually. - + Go to application website - + IOFactory Cannot open file '%1' for reading. - + Cannot open file '%1' for writting. - + @@ -2710,19 +2633,27 @@ Go to application website to obtain it manually. Permanently deleted - + Is message permanently deleted from recycle bin? - + Attachments - + List of attachments. - + + + + Loading of messages from item '%s' failed. + + + + Loading of messages failed, maybe messages could not be downloaded. + @@ -2737,19 +2668,19 @@ Go to application website to obtain it manually. Menu for highlighting messages - + No extra highlighting - + Highlight unread messages - + Highlight important messages - + Display all messages @@ -2757,7 +2688,7 @@ Go to application website to obtain it manually. Message highlighter - + Toolbar spacer @@ -2788,11 +2719,11 @@ Go to application website to obtain it manually. Problem with starting external e-mail client - + External e-mail client could not be started. - + @@ -2865,15 +2796,15 @@ Go to application website to obtain it manually. no errors Network status. - + access to content was denied - + connection timed out or was cancelled - + @@ -2897,46 +2828,57 @@ Go to application website to obtain it manually. LANG_EMAIL rotter.martinos@gmail.com - - Load initial feeds - - - - Do you want to load initial set of feeds? - - LANG_NAME Name of language, e.g. English. Italiano - - You started %1 for the first time, now you can load initial set of feeds. - + + + ++ %n other feeds. + + + + - Welcome to %1 %2. - + Welcome to %1. + +Please, check NEW stuff included in this +version by clicking this popup notification. + + + + Welcome to %1. + + + + Load initial set of feeds + RecycleBin Recycle bin - + Recycle bin contains all deleted messages from all feeds. - + Recycle bin %1 - + %n deleted message(s). - + + + + @@ -2951,7 +2893,133 @@ Go to application website to obtain it manually. Click and hit new shortcut. - + + + + + StandardCategory + + %1 (category)%2%3 + Tooltip for standard feed. + + + + +This category does not contain any nested items. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + + StandardFeed + + Metadata not fetched + + + + Metadata was not fetched because: %1. + + + + does not use auto-update + Describes feed auto-update status. + + + + uses global settings + Describes feed auto-update status. + + + + uses specific settings (%n minute(s) to next auto-update) + Describes feed auto-update status. + + + + + + + %1 (%2)%3 + +Network status: %6 +Encoding: %4 +Auto-update status: %5 + Tooltip for feed. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + + StandardServiceRoot + + This is obligatory service account for standard RSS/RDF/ATOM feeds. + + + + You started %1 for the first time, now you can load initial set of feeds. + + + + Do you want to load initial set of feeds? + + + + Error when loading initial feeds + + + + This is service account for standard RSS/RDF/ATOM feeds. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + Fetch metadata + Recupera metadata + + + Import successfull, but some feeds/categories were not imported due to error. + + + + Import was completely successfull. + + + + Add new category + Aggiungi nuova categoria + + + Add new feed + Aggiungi nuovo feed + + + Export feeds + + + + Import feeds + @@ -2962,18 +3030,22 @@ Go to application website to obtain it manually. Switch application between fulscreen/normal states right from this status bar icon. - + SystemFactory New version available - + Click the bubble for more information. - + + + + anonymous + @@ -2981,7 +3053,7 @@ Go to application website to obtain it manually. %1 Unread news: %2 - + @@ -3020,11 +3092,11 @@ Unread news: %2 Open new web browser tab. - + Downloads - + @@ -3055,30 +3127,45 @@ Unread news: %2 Move action up - + Move action down - + Add selected action - + Delete selected action - + Delete all actions - + TrayIconMenu Close opened modal dialogs first. - + + + + + TtRssServiceRoot + + This is service account TT-RSS (TinyTiny RSS) server. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + @@ -3205,19 +3292,19 @@ Unread news: %2 Copies current selection into the clipboard. - + Copy link url to clipboard. - + Copy image to clipboard. - + Copy image url to clipboard. - + Open this hyperlink in new tab. @@ -3233,63 +3320,63 @@ Unread news: %2 Open link in external browser - + Open the hyperlink in external browser. - + Print - + Print current web page. - + HTML web pages (*.html) - + Select destination file for web page - + Cannot save web page - + Web page cannot be saved because destination file is not writtable. - + Save target as... - + Download content from the hyperlink. - + Save page as... - + Save image to disk. - + Save image as... - + source_page - + Search "%1" via Google... - + - \ No newline at end of file + diff --git a/localization/rssguard-nl_NL.ts b/localization/rssguard-nl_NL.ts index f17dcba60..3eb26b7e7 100644 --- a/localization/rssguard-nl_NL.ts +++ b/localization/rssguard-nl_NL.ts @@ -1,4 +1,6 @@ - + + + AdBlockAddSubscriptionDialog @@ -196,25 +198,6 @@ Merk ook op dat sommige hulpbronnen worden gecached door de interne web browser. Herstel van de instellingen werd niet gestart. Zorg ervoor dat de uitvoermap beschrijfbaar is. - - Category - - %1 (category)%2%3 - Tooltip for standard feed. - %1 (categorie)%2%3 - - - -This category does not contain any nested items. - -Deze categorie bevat geen nested items. - - - %n unread message(s). - Tooltip for "unread" column of feed list. - %n ongelezen bericht%n ongelezen berichten. - - DatabaseCleaner @@ -293,9 +276,12 @@ Gelezen berichten gewist... Click me to add feeds from this website. This website contains %n feed(s). - Klik hier om feeds van deze website toe tevoegen -Deze website bevat % n feed.Klik hier om feeds van deze website toe tevoegen -Deze website bevat % n feed(s). + + Klik hier om feeds van deze website toe tevoegen +Deze website bevat % n feed. + Klik hier om feeds van deze website toe tevoegen +Deze website bevat % n feed(s). + @@ -373,7 +359,7 @@ Deze website bevat % n feed(s). Download klaar - File '%1' is downloaded. + File '%1' is downloaded. Click here to open parent directory. Bestand '%1' is klaar Klik hier om map te openen. @@ -399,11 +385,17 @@ Klik hier om map te openen. %n minutes remaining - %n resterende minuut%n resterende minuten + + %n resterende minuut + %n resterende minuten + %n seconds remaining - %n resterende seconde%n resterende seconden + + %n resterende seconde + %n resterende seconden + bytes @@ -423,51 +415,10 @@ Klik hier om map te openen. Downloading %n file(s)... - Dowloading %1 bestand...Downloading %n bestanden... - - - - Feed - - does not use auto-update - Describes feed auto-update status. - automatisch bijwerken niet gebruiken - - - uses global settings - Describes feed auto-update status. - gebruik algemene instellingen - - - uses specific settings (%n minute(s) to next auto-update) - Describes feed auto-update status. - gebruik specifieke instellingen (%n minuut voor volgende automatische update)gebruik specifieke instellingen (%n minuten voor volgende automatische update) - - - %1 (%2)%3 - -Network status: %6 -Encoding: %4 -Auto-update status: %5 - Tooltip for feed. - %1 (%2)%3 - -Netwerk status: %6 -Coderen: %4 -Auto-update status: 55 - - - %n unread message(s). - Tooltip for "unread" column of feed list. - %n ongelezen bericht.%n ongelezen berichten. - - - Metadata not fetched - Metadata niet opgehaald - - - Metadata was not fetched because: %1 - Metadate niet opgehaald omdat: %1 + + Dowloading %1 bestand... + Downloading %n bestanden... + @@ -476,24 +427,10 @@ Auto-update status: 55 Toolbar for messages Werkbalk voor berichten - - Feed update started - Text display in status bar when feed update is started. - Bijwerken feed is gestart - - - Updated feed '%1' - Text display in status bar when particular feed is updated. - Feed bijwerken '%1' - Toolbar for feeds Werkbalk voor feeds - - Error when loading initial feeds - Fout bij het laden van de eerste feeds - Cannot cleanup database Kan database niet opschonen @@ -502,18 +439,6 @@ Auto-update status: 55 Cannot cleanup database, because another critical action is running. Je kunt database niet opschonenen omdat een andere kritische operatie gaande is. - - Cannot update all items - Kan alle items niet bijwerken - - - You cannot update all items because another another critical operation is ongoing. - U kunt niet alle items updaten omdat er een andere bewerking plaats vind. - - - New messages downloaded - Nieuw bericht gedownload - FeedsImportExportModel @@ -550,25 +475,38 @@ Auto-update status: 55 Name of root item of feed list which can be seen in feed add/edit dialog. Root - - Invalid tree data. - Ongeldige structuur gegevens - - - Import successfull, but some feeds/categories were not imported due to error. - Importeren succesvol, maar sommige feeds / categorieën waren niet goed geïmporteerd door fouten. - - - Import was completely successfull. - Importeren is helemaal geslaagd. - Starting auto-update of some feeds Begint met auto-update van sommige feeds I will auto-update %n feed(s). - Auto-update van %n feedAuto-update van %n feed(s) + + Auto-update van %n feed + Auto-update van %n feed(s) + + + + Cannot update all items + Kan alle items niet bijwerken + + + You cannot update all items because another another critical operation is ongoing. + U kunt niet alle items updaten omdat er een andere bewerking plaats vind. + + + Feed update started + Text display in status bar when feed update is started. + Bijwerken feed is gestart + + + Updated feed '%1' + Text display in status bar when particular feed is updated. + Feed bijwerken '%1' + + + New messages downloaded + Nieuw bericht gedownload @@ -580,14 +518,6 @@ Auto-update status: 55 FeedsView - - Cannot add standard category - Kan geen standaard categorie toevoegen - - - Cannot add standard feed - Kan geen standaard feed toevoegen - Cannot edit item Kan item niet bewerken @@ -596,50 +526,10 @@ Auto-update status: 55 Cannot delete item Kan item niet verwijderen - - You are about to delete selected feed or category. - Je gaat geselecteerde feed of categorie verwijderen. - - - Deletion of item failed. - Verwijdering van Item is mislukt. - - - Selected item was not deleted due to error. - Geselecteerde item is niet verwijderd door een fout. - - - Do you really want to delete selected item? - Wil je het geselecteerde item echt verwijderen? - - - Permanently delete messages - Definitief berichten verwijderen - - - You are about to permanenty delete all messages from your recycle bin. - Je gaat definitief alle berichten uit de prullenbak verwijderen. - - - Do you really want to empty your recycle bin? - Wil je de prullenbak echt legen? - Context menu for empty space Contextmenu voor lege regels - - Context menu for recycle bin - Contextmenu voor prullenbak - - - You cannot add new standard category now because another critical operation is ongoing. - U kunt geen nieuwe standaard categorie toevoegen omdat een andere kritieke operatie aan de gang is. - - - You cannot add new standard feed now because another critical operation is ongoing. - U kunt geen nieuwe standaard feed toevoegen omdat een andere kritieke operatie aan de gang is. - Selected item cannot be edited because another critical operation is ongoing. Geselecteerde item kunt u niet bewerken omdat een andere kritieke operatie aan de gang is. @@ -648,14 +538,43 @@ Auto-update status: 55 Selected item cannot be deleted because another critical operation is ongoing. Geselecteerde item kunt u niet verwijderen omdat een andere kritieke operatie aan de gang is. - - Delete feed/category - Verwijder feed/categorie - Context menu for categories Contextmenu voor categorieën + + Selected item cannot be edited, this is not (yet?) supported. + + + + Deleting "%1" + + + + You are about to completely delete item "%1". + + + + Are you sure? + + + + Cannot delete "%1" + + + + This item cannot be deleted because something critically failed. Submit bug report. + + + + This item cannot be deleted, because it does not support it +or this functionality is not implemented yet. + + + + Context menu for other items + + FormAbout @@ -703,10 +622,6 @@ Auto-update status: 55 <b>%8</b><br><b>Version:</b> %1 (build on %2 with CMake %3)<br><b>Revision:</b> %4<br><b>Build date:</b> %5<br><b>Qt:</b> %6 (compiled against %7)<br> <b>%8</b><br><b>Versie:</b> %1 (Gecompileerd onder %2 en Cmake %3)<br><b> Revisie:</b> %4<br><b>Gecompileerd op:</b> %5<br><b>QT versie:</b> %6 (Gecompileerd met %7)<br> - - <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~email</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> - <body>%5 is een (zeer) makelijk te gebruiken feed lezer<br><br>Dit programma is beschikbaar onder te termen van de GNU General Public License versie 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~email</li><li><a href="%2">%2</a> ~website</li></ul>U kunt de broncode voor %5 downloaden van de website..<br><br><br>Auteursrecht (C) 2011-%3 %4</body> - About %1 About RSS Guard dialog title. @@ -736,6 +651,10 @@ Auto-update status: 55 Resources Hulpbronnen + + <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~e-mail</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> + + FormBackupDatabaseSettings @@ -812,134 +731,6 @@ Auto-update status: 55 Juiste bestemmingsmap is opgegeven - - FormCategoryDetails - - Parent category - Oudere categorie - - - Select parent item for your category. - Kies hoofd item voor je categorie. - - - Title - Titel - - - Description - Omschrijving - - - Icon - Pictogram - - - Select icon for your category. - Selecteer pictogram voor je categorie. - - - Add new category - Voeg nieuwe categorie toe - - - Edit existing category - Bewerk bestaande categorie - - - Cannot add category - Kan geen categorie toevoegen - - - Category was not added due to error. - Door een fout is de categorie niet toegevoegd. - - - Cannot edit category - Kan categorie niet bewerken - - - Category was not edited due to error. - Door een fout is de categorie niet bewerkt. - - - Category name is ok. - Categorie naam is ok. - - - Category name is too short. - Categorie naam is te kort. - - - Description is empty. - Omschrijving is leeg. - - - Select icon file for the category - Kies pictogram bestand voor de categorie - - - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - Afbeeldingen (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - - - Select icon - Selecteer pictogram - - - Cancel - Annuleer - - - Look in: - Label to describe the folder for icon file selection dialog. - Kijk in: - - - Icon name: - Pictogram naam: - - - Icon type: - Type pictogram: - - - Category title - Titel categorie - - - Set title for your category. - Stel titel in voor je categorie. - - - Category description - Categorie omschrijving - - - Set description for your category. - Stel omschrijving in voor je categorie. - - - Icon selection - Pictogram selectie - - - Load icon from file... - Laad pictogram uit een bestand... - - - Do not use icon - Gebruik geen pictogram - - - Use default icon - Gebruik standaard pictogram - - - The description is ok. - Omschrijving is ok. - - FormDatabaseCleanup @@ -952,7 +743,10 @@ Auto-update status: 55 day(s) - dagdagen + + dag + dagen + Shrink database file @@ -1007,389 +801,6 @@ Auto-update status: 55 Verwijder alle berichten met ster(niet die van de prullenbak) - - FormFeedDetails - - Parent category - Oudere categorie - - - Select parent item for your feed. - Kies hoofd item voor je feed. - - - Type - Type - - - Select type of the standard feed. - Selecteer type van de standaard feed. - - - Encoding - Coderen - - - Select encoding of the standard feed. If you are unsure about the encoding, then select "UTF-8" encoding. - Kies codering van de standaard feed. Als je niet zeker bent van de codering, selecteer dan "UTF-8" codering. - - - Auto-update - Automatische-update - - - Select the auto-update strategy for this feed. Default auto-update strategy means that the feed will be update in time intervals set in application settings. - Selekteer de automatische bijwerk strategie voor deze feed.Standaard automatische bijwerken strategie betekent dat de feed zal worden bijgewerkt in tijd tussenpauzes ingesteld in RSSguard instelling. - - - minutes - minuten - - - Title - Titel - - - Description - Omschrijving - - - URL - URL - - - Fetch it now - Nu ophalen - - - Icon - Pictogram - - - Select icon for your feed. - Selecteer pictogram voor je feed. - - - Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. - Sommige feeds vereisen verificatie,inclusief GMail feeds, BASIC, NTLM-2 en DIGEST-MD5 verificaties schema's worden ondersteund. - - - Requires authentication - Vereist verificatie - - - Username - Gebruikersnaam - - - Password - Paswoord - - - Fetch metadata - Ophalen van metadata - - - Add new feed - Voeg nieuw feed toe - - - Edit existing feed - Bewerk bestaande feed - - - Feed name is ok. - Feed naam is ok. - - - Feed name is too short. - Feed naam is te kort. - - - Description is empty. - Omschrijving is leeg. - - - The url is ok. - De url is ok. - - - The url does not meet standard pattern. Does your url start with "http://" or "https://" prefix. - De URL voldoet niet aan het standaard patroon. Start je url met "http://" of "https://" prefix. - - - The url is empty. - De url is leeg. - - - Username is ok or it is not needed. - Gebruikersnaam is ok of het is niet nodig. - - - Username is empty. - Gebruikersnaam is leeg. - - - Password is ok or it is not needed. - Paswoord is ok of het is niet nodig. - - - Password is empty. - Paswoord is leeg. - - - Select icon file for the feed - Selecteer pictogram bestand voor je feed - - - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - Afbeeldingen (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - - - Select icon - Selecteer pictogram - - - Cancel - Annuleer - - - Look in: - Label for field with icon file name textbox for selection dialog. - Kijk in: - - - Icon name: - Pictogram naam: - - - Icon type: - Type pictogram: - - - Cannot add feed - Kan geen feed toevoegen - - - Feed was not added due to error. - Door een fout is de feed niet toegevoegd. - - - Cannot edit feed - Kan feed niet bewerken - - - All metadata fetched successfully. - Alle metadata is succesvol opgehaald. - - - Feed and icon metadata fetched. - Metadata opgehaald voor feed en pictogram. - - - Result: %1. - Resultaat: %1. - - - Feed or icon metatada not fetched. - Metadata voor feed en pictogram niet opgehaald. - - - Error: %1. - Fout: %1. - - - No metadata fetched. - Geen metadata opgehaald. - - - Feed title - Feed naam - - - Set title for your feed. - Stel titel in voor je feed. - - - Feed description - Feed omschrijving - - - Set description for your feed. - Stel omschrijving voor feed in. - - - Full feed url including scheme - Volledige feed url inclusief schema - - - Set url for your feed. - Stel url in voor je feed. - - - Set username to access the feed. - Stel gebruikersnaam in voor toegang tot feed. - - - Set password to access the feed. - Stel paswoord in voor toegang tot feed. - - - Icon selection - Pictogram selectie - - - Load icon from file... - Laad pictogram uit een bestand... - - - Do not use icon - Gebruik geen pictogram - - - Use default icon - Gebruik standaard pictogram - - - No metadata fetched so far. - Nog geen metadata opgehaald. - - - Auto-update using global interval - Automatisch bijwerken met behulp van globale interval - - - Auto-update every - Automatisch bijwerken elke - - - Do not auto-update at all - Niet automatisch bijwerken - - - The description is ok. - Omschrijving is ok. - - - Feed was not edited due to error. - Door een fout is de feed niet bewerkt. - - - Icon fetched successfully. - Pictogram met succes opgehaald. - - - Icon metadata fetched. - Metadata pictogram opgehaald. - - - Icon metatada not fetched. - Metadata pictogram niet opgehaald. - - - No icon fetched. - Geen pictogram opgehaald. - - - Fetch icon from feed - Pictogram opgehaald van feed - - - - FormImportExport - - &Select file - &Selecteer bestand - - - Operation results - Resultaten - - - No file is selected. - Geen bestand geselecteerd. - - - No operation executed yet. - Nog geen handeling uitgevoerd. - - - Export feeds - Exporteer feeds - - - Destination file - Doelbestand - - - Source feeds && categories - Source Feeds && categorieën - - - Source file - Source bestand - - - Target feeds && categories - Doelgroep feeds && categorieën - - - Import feeds - Importeer feeds. - - - OPML 2.0 files (*.opml) - OPML 2.0 bestanden (*.opml) - - - Select file for feeds export - Selecteer bestand voor feed export - - - File is selected. - Bestand is geselecteerd. - - - Select file for feeds import - Selecteer bestand voor feed import - - - Cannot open source file. - Kan source bestand niet openen. - - - Feeds were loaded. - Feeds zijn geladen. - - - Error, file is not well-formed. Select another file. - Fout, het bestand is niet goed gevormd. Selecteer een ander bestand. - - - Error occurred. File is not well-formed. Select another file. - Fout opgetreden. Bestand is niet goed gevormd. Selecteer een ander bestand. - - - Feeds were exported successfully. - Feeds zijn met succes geëxporteerd. - - - Cannot write into destination file. - Kan niet schrijven naar doelbestand. - - - Critical error occurred. - Kritieke fout opgetreden. - - - &Check all items - &Controleer alle items - - - &Uncheck all items - &Vinkje bij alle items - - FormMain @@ -1468,18 +879,6 @@ Auto-update status: 55 Fee&ds && categories Fee&ds && categorieën - - Mark all messages (without message filters) from selected feeds as read. - Markeer alle berichten (zonder berichten filters) van geselecteerde feeds als gelezen. - - - Mark all messages (without message filters) from selected feeds as unread. - Markeer alle berichten (zonder berichten filters) van geselecteerde feeds als ongelezen. - - - Displays all messages from selected feeds/categories in a new "newspaper mode" tab. Note that messages are not set as read automatically. - Toon alle berichten van geselecteerde feeds/categorieën in een nieuwe "Krantweergave modus" tabblad. Onthoud dat de berichten niet zijn ingesteld als automatisch gelezen. - Hides main window if it is visible and shows it if it is hidden. Verberg hoofdvenster als het zichtbaar is en toon het als het verborgen is. @@ -1504,34 +903,6 @@ Auto-update status: 55 &Delete selected messages Verwij&der geselecteerde berichten - - Deletes all messages from selected feeds. - Verwijder alle berichten van geselecteerde feeds. - - - Marks all messages in all feeds read. This does not take message filters into account. - Markeer alle berichten van alle feeds als gelezen. Dit is niet van toepassing op berichten filters in account. - - - Deletes all messages from all feeds. - Verwijder alle berichten van alle feeds. - - - Update &all feeds - &Alle feeds bijwerken - - - Update &selected feeds - Update ge&selecteerde feeds - - - &Edit selected feed/category - B&ewerk geselecteerde feed/categorie - - - &Delete selected feed/category - Verwij&der geselecteerde feed/categorie - Settings Instellingen @@ -1540,10 +911,6 @@ Auto-update status: 55 Hides or displays the main menu. Verberg of toon het hoofdmenu. - - Add &new feed/category - Voeg &nieuwe feeds/categorieën toe - &Close all tabs except current one &Sluit alle tabbladen behalve deze @@ -1560,18 +927,6 @@ Auto-update status: 55 Mark &selected messages as &unread Markeer ge&selecteerde berichten als &ongelezen - - &Mark selected feeds as read - &Markeer geselecteerde feeds als gelezen - - - &Mark selected feeds as unread - &Markeer geselecteerde bericht als ongelezen - - - &Clean selected feeds - &Wis geselecteerde feeds - Open selected source articles in &external browser Open geselecteerde bron artikelen met &externe webbrowser @@ -1584,26 +939,6 @@ Auto-update status: 55 Open selected source articles in &internal browser Open geselecteerde bron artikelen met &ingebouwde webbrowser - - &Mark all feeds as &read - &Markeer alle feeds als &gelezen - - - View selected feeds in &newspaper mode - Bekijk de geselecteerde items in de kra&ntweergave modus - - - &Clean all feeds - Alle feeds ops&chonen - - - Select &next feed/category - Selecteer volge&nde feeds/categorieën - - - Select &previous feed/category - Selecteer &vorige feeds/categorieën - Select &next message Selecteer volge&nd bericht @@ -1656,22 +991,6 @@ Auto-update status: 55 Cannot open external browser. Navigate to application website manually. Kan externe webbrowser niet starten, Navigeer handmatig naar RSSguard website. - - New &feed - Nieuw &feed - - - Add new feed. - Voeg nieuw feed toe. - - - New &category - Nieuw &categorie - - - Add new category. - Voeg nieuwe categorie toe. - &Toolbars &Werkbalk @@ -1684,31 +1003,10 @@ Auto-update status: 55 &Feed/message list headers &Feed/bericht kopteksten - - &Import feeds - &Importeer feeds - - - Imports feeds you want from selected file. - Importeer feeds die je wilt van het geselecteerde bestand. - - - &Export feeds - &Exporteer feeds - - - Exports feeds you want to selected file. - -Exporteer feeds die je wilt van het geselecteerde bestand. - Close all tabs except current one. Sluit alle tabbladen behalve deze. - - &Recycle bin - &Prullenbak - Report a &bug (GitHub)... Rapporteer een &bug (Github)... @@ -1725,18 +1023,6 @@ Exporteer feeds die je wilt van het geselecteerde bestand. Display &wiki Toon &wiki - - &Empty recycle bin - &Prullenbak legen - - - &Restore all messages - &Herstel alle berichten - - - Restore &selected messages - Herstel &geselecteerde berichten - &Restart &Herstart @@ -1766,16 +1052,136 @@ Exporteer feeds die je wilt van het geselecteerde bestand. &database opschonen - Show only unread feeds/categories - Toon alleen de ongelezen feeds/categorieën + Add &new item + - &Fetch feed metadata - &Ophalen van de feed metadata + &Services + - &Expand/collapse selected feed/category - &Uitklappen/Inklappen van geselcteerde feed/categorie + Update &all items + + + + Ctrl+Shift+U + + + + Update &selected items + + + + Ctrl+U + + + + &Edit selected item + + + + &Delete selected item + + + + &Mark selected items as read + + + + Mark all messages (without message filters) from selected items as read. + + + + &Mark selected items as unread + + + + Mark all messages (without message filters) from selected items as unread. + + + + &Clean selected items + + + + Deletes all messages from selected items. + + + + &Mark all items as &read + + + + Marks all messages in all items read. This does not take message filters into account. + + + + View selected items in &newspaper mode + + + + Displays all messages from selected item in a new "newspaper mode" tab. Note that messages are not set as read automatically. + + + + &Clean all items + + + + Deletes all messages from all items. + + + + Ctrl+Shift+C + + + + Select &next item + + + + S + + + + Select &previous item + + + + A + + + + Show only unread items + + + + &Expand/collapse selected item + + + + E + + + + &Add new service account + + + + &Delete selected service account + + + + &Edit selected service account + + + + &Restore selected messages + + + + No possible actions + @@ -1926,10 +1332,6 @@ Exporteer feeds die je wilt van het geselecteerde bestand. Author Auteur - - Email - Email - Socks5 Socks5 @@ -2514,6 +1916,521 @@ Open nieuw webbrowser pagina(sleep muis omlaag). Fancy && modern popup notifications (This uses OS native notifications via D-Bus if available.) Fancy && moderne popup meldingen (Dit gebruikt OS natieve meldingen via D-Bus indien beschikbaar.) + + E-mail + + + + + FormStandardCategoryDetails + + Parent category + Oudere categorie + + + Select parent item for your category. + Kies hoofd item voor je categorie. + + + Title + Titel + + + Description + Omschrijving + + + Icon + Pictogram + + + Select icon for your category. + Selecteer pictogram voor je categorie. + + + Add new category + Voeg nieuwe categorie toe + + + Edit existing category + Bewerk bestaande categorie + + + Cannot add category + Kan geen categorie toevoegen + + + Category was not added due to error. + Door een fout is de categorie niet toegevoegd. + + + Cannot edit category + Kan categorie niet bewerken + + + Category was not edited due to error. + Door een fout is de categorie niet bewerkt. + + + Category name is ok. + Categorie naam is ok. + + + Category name is too short. + Categorie naam is te kort. + + + Description is empty. + Omschrijving is leeg. + + + The description is ok. + Omschrijving is ok. + + + Select icon file for the category + Kies pictogram bestand voor de categorie + + + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + Afbeeldingen (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + + + Select icon + Selecteer pictogram + + + Cancel + Annuleer + + + Look in: + Label to describe the folder for icon file selection dialog. + Kijk in: + + + Icon name: + Pictogram naam: + + + Icon type: + Type pictogram: + + + Category title + Titel categorie + + + Set title for your category. + Stel titel in voor je categorie. + + + Category description + Categorie omschrijving + + + Set description for your category. + Stel omschrijving in voor je categorie. + + + Icon selection + Pictogram selectie + + + Load icon from file... + Laad pictogram uit een bestand... + + + Do not use icon + Gebruik geen pictogram + + + Use default icon + Gebruik standaard pictogram + + + + FormStandardFeedDetails + + Parent category + Oudere categorie + + + Select parent item for your feed. + Kies hoofd item voor je feed. + + + Type + Type + + + Select type of the standard feed. + Selecteer type van de standaard feed. + + + Encoding + Coderen + + + Select encoding of the standard feed. If you are unsure about the encoding, then select "UTF-8" encoding. + Kies codering van de standaard feed. Als je niet zeker bent van de codering, selecteer dan "UTF-8" codering. + + + Auto-update + Automatische-update + + + Select the auto-update strategy for this feed. Default auto-update strategy means that the feed will be update in time intervals set in application settings. + Selekteer de automatische bijwerk strategie voor deze feed.Standaard automatische bijwerken strategie betekent dat de feed zal worden bijgewerkt in tijd tussenpauzes ingesteld in RSSguard instelling. + + + minutes + minuten + + + Title + Titel + + + Description + Omschrijving + + + URL + URL + + + Fetch it now + Nu ophalen + + + Icon + Pictogram + + + Select icon for your feed. + Selecteer pictogram voor je feed. + + + Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. + Sommige feeds vereisen verificatie,inclusief GMail feeds, BASIC, NTLM-2 en DIGEST-MD5 verificaties schema's worden ondersteund. + + + Requires authentication + Vereist verificatie + + + Username + Gebruikersnaam + + + Password + Paswoord + + + Fetch metadata + Ophalen van metadata + + + Add new feed + Voeg nieuw feed toe + + + Edit existing feed + Bewerk bestaande feed + + + Feed name is ok. + Feed naam is ok. + + + Feed name is too short. + Feed naam is te kort. + + + Description is empty. + Omschrijving is leeg. + + + The description is ok. + Omschrijving is ok. + + + The url is ok. + De url is ok. + + + The url does not meet standard pattern. Does your url start with "http://" or "https://" prefix. + De URL voldoet niet aan het standaard patroon. Start je url met "http://" of "https://" prefix. + + + The url is empty. + De url is leeg. + + + Username is ok or it is not needed. + Gebruikersnaam is ok of het is niet nodig. + + + Username is empty. + Gebruikersnaam is leeg. + + + Password is ok or it is not needed. + Paswoord is ok of het is niet nodig. + + + Password is empty. + Paswoord is leeg. + + + Select icon file for the feed + Selecteer pictogram bestand voor je feed + + + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + Afbeeldingen (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + + + Select icon + Selecteer pictogram + + + Cancel + Annuleer + + + Look in: + Label for field with icon file name textbox for selection dialog. + Kijk in: + + + Icon name: + Pictogram naam: + + + Icon type: + Type pictogram: + + + Cannot add feed + Kan geen feed toevoegen + + + Feed was not added due to error. + Door een fout is de feed niet toegevoegd. + + + Cannot edit feed + Kan feed niet bewerken + + + Feed was not edited due to error. + Door een fout is de feed niet bewerkt. + + + All metadata fetched successfully. + Alle metadata is succesvol opgehaald. + + + Feed and icon metadata fetched. + Metadata opgehaald voor feed en pictogram. + + + Result: %1. + Resultaat: %1. + + + Feed or icon metatada not fetched. + Metadata voor feed en pictogram niet opgehaald. + + + Error: %1. + Fout: %1. + + + No metadata fetched. + Geen metadata opgehaald. + + + Icon fetched successfully. + Pictogram met succes opgehaald. + + + Icon metadata fetched. + Metadata pictogram opgehaald. + + + Icon metatada not fetched. + Metadata pictogram niet opgehaald. + + + No icon fetched. + Geen pictogram opgehaald. + + + Feed title + Feed naam + + + Set title for your feed. + Stel titel in voor je feed. + + + Feed description + Feed omschrijving + + + Set description for your feed. + Stel omschrijving voor feed in. + + + Full feed url including scheme + Volledige feed url inclusief schema + + + Set url for your feed. + Stel url in voor je feed. + + + Set username to access the feed. + Stel gebruikersnaam in voor toegang tot feed. + + + Set password to access the feed. + Stel paswoord in voor toegang tot feed. + + + Icon selection + Pictogram selectie + + + Load icon from file... + Laad pictogram uit een bestand... + + + Do not use icon + Gebruik geen pictogram + + + Use default icon + Gebruik standaard pictogram + + + Fetch icon from feed + Pictogram opgehaald van feed + + + No metadata fetched so far. + Nog geen metadata opgehaald. + + + Auto-update using global interval + Automatisch bijwerken met behulp van globale interval + + + Auto-update every + Automatisch bijwerken elke + + + Do not auto-update at all + Niet automatisch bijwerken + + + + FormStandardImportExport + + &Select file + &Selecteer bestand + + + &Check all items + &Controleer alle items + + + &Uncheck all items + &Vinkje bij alle items + + + Operation results + Resultaten + + + No file is selected. + Geen bestand geselecteerd. + + + No operation executed yet. + Nog geen handeling uitgevoerd. + + + Destination file + Doelbestand + + + Source feeds && categories + Source Feeds && categorieën + + + Export feeds + Exporteer feeds + + + Source file + Source bestand + + + Target feeds && categories + Doelgroep feeds && categorieën + + + Import feeds + Importeer feeds. + + + OPML 2.0 files (*.opml) + OPML 2.0 bestanden (*.opml) + + + Select file for feeds export + Selecteer bestand voor feed export + + + File is selected. + Bestand is geselecteerd. + + + Select file for feeds import + Selecteer bestand voor feed import + + + Cannot open source file. + Kan source bestand niet openen. + + + Feeds were loaded. + Feeds zijn geladen. + + + Error, file is not well-formed. Select another file. + Fout, het bestand is niet goed gevormd. Selecteer een ander bestand. + + + Error occurred. File is not well-formed. Select another file. + Fout opgetreden. Bestand is niet goed gevormd. Selecteer een ander bestand. + + + Feeds were exported successfully. + Feeds zijn met succes geëxporteerd. + + + Cannot write into destination file. + Kan niet schrijven naar doelbestand. + + + Critical error occurred. + Kritieke fout opgetreden. + FormUpdate @@ -2763,6 +2680,14 @@ Ga naar RRSguard website en download het handmatig. List of attachments. Bijlagen lijst. + + Loading of messages from item '%s' failed. + + + + Loading of messages failed, maybe messages could not be downloaded. + + MessagesToolBar @@ -2936,26 +2861,34 @@ Ga naar RRSguard website en download het handmatig. LANG_EMAIL elbert.pol@gmail.com - - Load initial feeds - Laad eerste feeds - - - Do you want to load initial set of feeds? - Wil je de eerste set van feeds laden? - LANG_NAME Name of language, e.g. English. Nederlands - - You started %1 for the first time, now you can load initial set of feeds. - Je startte %1 voor de eerste keer, nu kun je de eerste set van de feeds laden + + + ++ %n other feeds. + + + + - Welcome to %1 %2. - Welkom bij %1 %2. + Welcome to %1. + +Please, check NEW stuff included in this +version by clicking this popup notification. + + + + Welcome to %1. + Welkom bij %1 %2. {1.?} + + + Load initial set of feeds + @@ -2976,7 +2909,10 @@ Ga naar RRSguard website en download het handmatig. %n deleted message(s). - %n verwijderde bericht(en).%n verwijderde bericht(en). + + %n verwijderde bericht(en). + %n verwijderde bericht(en). + @@ -2994,6 +2930,137 @@ Ga naar RRSguard website en download het handmatig. Klik en raak nieuwe sneltoets. + + StandardCategory + + %1 (category)%2%3 + Tooltip for standard feed. + %1 (categorie)%2%3 + + + +This category does not contain any nested items. + +Deze categorie bevat geen nested items. + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + + StandardFeed + + Metadata not fetched + Metadata niet opgehaald + + + Metadata was not fetched because: %1. + Metadate niet opgehaald omdat: %1. + + + does not use auto-update + Describes feed auto-update status. + automatisch bijwerken niet gebruiken + + + uses global settings + Describes feed auto-update status. + gebruik algemene instellingen + + + uses specific settings (%n minute(s) to next auto-update) + Describes feed auto-update status. + + gebruik specifieke instellingen (%n minuut voor volgende automatische update) + gebruik specifieke instellingen (%n minuten voor volgende automatische update) + + + + %1 (%2)%3 + +Network status: %6 +Encoding: %4 +Auto-update status: %5 + Tooltip for feed. + %1 (%2)%3 + +Netwerk status: %6 +Coderen: %4 +Auto-update status: 55 + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + + StandardServiceRoot + + This is obligatory service account for standard RSS/RDF/ATOM feeds. + + + + You started %1 for the first time, now you can load initial set of feeds. + Je startte %1 voor de eerste keer, nu kun je de eerste set van de feeds laden + + + Do you want to load initial set of feeds? + Wil je de eerste set van feeds laden? + + + Error when loading initial feeds + Fout bij het laden van de eerste feeds + + + This is service account for standard RSS/RDF/ATOM feeds. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + + Fetch metadata + Ophalen van metadata + + + Import successfull, but some feeds/categories were not imported due to error. + Importeren succesvol, maar sommige feeds / categorieën waren niet goed geïmporteerd door fouten. + + + Import was completely successfull. + Importeren is helemaal geslaagd. + + + Add new category + Voeg nieuwe categorie toe + + + Add new feed + Voeg nieuw feed toe + + + Export feeds + Exporteer feeds + + + Import feeds + Importeer feeds. + + StatusBar @@ -3015,6 +3082,10 @@ Ga naar RRSguard website en download het handmatig. Click the bubble for more information. Klik op luchtbel voor meer informatie. + + anonymous + + SystemTrayIcon @@ -3123,6 +3194,21 @@ Ongelezen nieuws: %2 Sluit geopende modaal vensters eerst. + + TtRssServiceRoot + + This is service account TT-RSS (TinyTiny RSS) server. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + + + + + WebBrowser @@ -3334,4 +3420,4 @@ Ongelezen nieuws: %2 Zoek "%1" met google... - \ No newline at end of file + diff --git a/localization/rssguard-sv_SE.ts b/localization/rssguard-sv_SE.ts index 26e1cc170..d8a9d5c06 100644 --- a/localization/rssguard-sv_SE.ts +++ b/localization/rssguard-sv_SE.ts @@ -1,4 +1,6 @@ - + + + AdBlockAddSubscriptionDialog @@ -196,25 +198,6 @@ Notera också att vissa resurser cachelagras av den interna webbläsaren. Om du Inställningsåterställning startades inte. Tillse att utdatamappen är skrivbar. - - Category - - %1 (category)%2%3 - Tooltip for standard feed. - %1 (kategori)%2%3 - - - -This category does not contain any nested items. - -Denna kategori innehåller inga objekt. - - - %n unread message(s). - Tooltip for "unread" column of feed list. - %n oläst meddelande.%n olästa meddelanden. - - DatabaseCleaner @@ -292,9 +275,12 @@ Denna kategori innehåller inga objekt. Click me to add feeds from this website. This website contains %n feed(s). - Klicka för att lägga till flöden från webbsidan. -Denna webbsida innehåller %1 flöde.Klicka för att lägga till flöden från webbsidan. -Denna webbsida innehåller %1 flöden. + + Klicka för att lägga till flöden från webbsidan. +Denna webbsida innehåller %1 flöde. + Klicka för att lägga till flöden från webbsidan. +Denna webbsida innehåller %1 flöden. + @@ -372,7 +358,7 @@ Denna webbsida innehåller %1 flöden. Nedladdning slutförd - File '%1' is downloaded. + File '%1' is downloaded. Click here to open parent directory. Filen '%1' är nedlladdad. Klicka här för att öppna målmappen. @@ -398,11 +384,17 @@ Klicka här för att öppna målmappen. %n minutes remaining - %n minut kvar%n minuter kvar + + %n minut kvar + %n minuter kvar + %n seconds remaining - %n sekund kvar%n sekunder kvar + + %n sekund kvar + %n sekunder kvar + bytes @@ -422,51 +414,10 @@ Klicka här för att öppna målmappen. Downloading %n file(s)... - Laddar ner %n fil...Laddar ner %n filer... - - - - Feed - - does not use auto-update - Describes feed auto-update status. - uppdateras inte automatiskt - - - uses global settings - Describes feed auto-update status. - Globala inställningar - - - uses specific settings (%n minute(s) to next auto-update) - Describes feed auto-update status. - Anpassade inställningar. (%n minut till nästa auto-uppdatering)Anpassade inställningar. (%n minuter till nästa auto-uppdatering) - - - %1 (%2)%3 - -Network status: %6 -Encoding: %4 -Auto-update status: %5 - Tooltip for feed. - %1 (%2)%3 - -Nätverksstatus: %6 -Kodning: %4 -Uppdateringsstatus: %5 - - - %n unread message(s). - Tooltip for "unread" column of feed list. - %n oläst meddelande.%n olästa meddelanden. - - - Metadata not fetched - Metadata hämtades inte - - - Metadata was not fetched because: %1 - Metadata hämtades inte på grund av: %1 + + Laddar ner %n fil... + Laddar ner %n filer... + @@ -475,24 +426,10 @@ Uppdateringsstatus: %5 Toolbar for messages Verktygsfält för meddelanden - - Feed update started - Text display in status bar when feed update is started. - Flödesuppdatering startad - - - Updated feed '%1' - Text display in status bar when particular feed is updated. - Uppdaterade flödet '%1' - Toolbar for feeds Verktygsfält för flöden - - Error when loading initial feeds - Fel vid inläsning av flöden - Cannot cleanup database Kan inte rensa databasen @@ -501,18 +438,6 @@ Uppdateringsstatus: %5 Cannot cleanup database, because another critical action is running. Kan inte rensa databasen, eftersom en annan kritisk åtgärd pågår. - - Cannot update all items - Kan inte uppdatera alla objekt - - - You cannot update all items because another another critical operation is ongoing. - Du kan inte uppdatera alla objekt, eftersom en annan kritisk åtgärd pågår. - - - New messages downloaded - Nya meddelanden nedladdade - FeedsImportExportModel @@ -549,25 +474,38 @@ Uppdateringsstatus: %5 Name of root item of feed list which can be seen in feed add/edit dialog. Root - - Invalid tree data. - Ogiltig träddata. - - - Import successfull, but some feeds/categories were not imported due to error. - Importen slutfördes, men vissa flöden/kategorier importerades inte på grund av något fel. - - - Import was completely successfull. - Importen slutfördes korrekt. - Starting auto-update of some feeds Uppdaterar flöden automatiskt I will auto-update %n feed(s). - Jag uppdaterar %n flöde automatisktJag uppdaterar %n flöden automatiskt + + Jag uppdaterar %n flöde automatiskt + Jag uppdaterar %n flöden automatiskt + + + + Cannot update all items + Kan inte uppdatera alla objekt + + + You cannot update all items because another another critical operation is ongoing. + Du kan inte uppdatera alla objekt, eftersom en annan kritisk åtgärd pågår. + + + Feed update started + Text display in status bar when feed update is started. + Flödesuppdatering startad + + + Updated feed '%1' + Text display in status bar when particular feed is updated. + Uppdaterade flödet '%1' + + + New messages downloaded + Nya meddelanden nedladdade @@ -579,14 +517,6 @@ Uppdateringsstatus: %5 FeedsView - - Cannot add standard category - Kan inte lägga till kategori - - - Cannot add standard feed - Kan inte lägga till flöde - Cannot edit item Kan inte redigera objektet @@ -595,50 +525,10 @@ Uppdateringsstatus: %5 Cannot delete item Kan inte bort objektet - - You are about to delete selected feed or category. - Du är på väg att ta bort markerat flöde eller kategori. - - - Deletion of item failed. - Borttagningen misslyckades. - - - Selected item was not deleted due to error. - Objektet togs inte bort, på grund av ett fel. - - - Do you really want to delete selected item? - Vill du verkligen ta bort markerat objekt? - - - Permanently delete messages - Ta bort meddelanden permanent - - - You are about to permanenty delete all messages from your recycle bin. - Du är på väg att permanent ta bort alla meddelanden från papperskorgen. - - - Do you really want to empty your recycle bin? - Vill du verkligen tömma papperskorgen? - Context menu for empty space Kontextmeny för tomt utrymme - - Context menu for recycle bin - Kontextmeny för papperskorgen - - - You cannot add new standard category now because another critical operation is ongoing. - Du kan inte lägga till ny standardkategori nu, eftersom en annan kritisk åtgärd pågår. - - - You cannot add new standard feed now because another critical operation is ongoing. - Du kan inte lägga till nytt standardflöde nu, eftersom en annan kritisk åtgärd pågår. - Selected item cannot be edited because another critical operation is ongoing. Markerat objekt kan inte redigeras, eftersom en annan kritisk åtgärd pågår. @@ -647,14 +537,43 @@ Uppdateringsstatus: %5 Selected item cannot be deleted because another critical operation is ongoing. Markerat objekt kan inte tas bort, eftersom en annan kritisk åtgärd pågår. - - Delete feed/category - Ta bort flöde/kategori - Context menu for categories Kontextmeny för kategorier + + Selected item cannot be edited, this is not (yet?) supported. + + + + Deleting "%1" + + + + You are about to completely delete item "%1". + + + + Are you sure? + + + + Cannot delete "%1" + + + + This item cannot be deleted because something critically failed. Submit bug report. + + + + This item cannot be deleted, because it does not support it +or this functionality is not implemented yet. + + + + Context menu for other items + + FormAbout @@ -702,10 +621,6 @@ Uppdateringsstatus: %5 <b>%8</b><br><b>Version:</b> %1 (build on %2 with CMake %3)<br><b>Revision:</b> %4<br><b>Build date:</b> %5<br><b>Qt:</b> %6 (compiled against %7)<br> <b>%8</b><br><b>Version:</b> %1 (byggd på %2 med CMake %3)<br><b>Revision:</b> %4<br><b>Byggdatum:</b> %5<br><b>Qt:</b> %6 (kompilerad mot %7)<br> - - <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~email</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> - <body>%5 är en (mycket) lätt flödesläsare.<br><br>Mjukvaran distribueras under villkoren för GNU General Public Licens, version 3.<br><br>Kontakt:<ul><li><a href="mailto://%1">%1</a> ~e-post</li><li><a href="%2">%2</a> ~webbsida</li></ul>Du kan hämmta källkoden för %5 från webbsidan.<br><br><br>Copyright (C) 2011-%3 %4</body> - About %1 About RSS Guard dialog title. @@ -735,6 +650,10 @@ Uppdateringsstatus: %5 Resources Resurser + + <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~e-mail</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> + + FormBackupDatabaseSettings @@ -811,134 +730,6 @@ Uppdateringsstatus: %5 Målmappen är godkänd. - - FormCategoryDetails - - Parent category - Överordnad kategori - - - Select parent item for your category. - Välj överordnad mapp för kategorin. - - - Title - Namn - - - Description - Beskrivning - - - Icon - Ikon - - - Select icon for your category. - Välj ikon för kategorin. - - - Add new category - Lägg till ny kategori - - - Edit existing category - Redigera befintlig kategori - - - Cannot add category - Kan inte lägga till kategori - - - Category was not added due to error. - Kategorin lades inte till, på grund av något fel. - - - Cannot edit category - Kan inte redigera kategorin - - - Category was not edited due to error. - Kategorin kan inte redigeras, på grund av något fel. - - - Category name is ok. - Kategorinamnet är ok. - - - Category name is too short. - Kategorinamnet är för kort. - - - Description is empty. - Beskrivning saknas. - - - Select icon file for the category - Välj ikonfil för kategorin - - - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - Bilder (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - - - Select icon - Välj ikon - - - Cancel - Avbryt - - - Look in: - Label to describe the folder for icon file selection dialog. - Sök i: - - - Icon name: - Ikonnamn: - - - Icon type: - Ikontyp: - - - Category title - Kategorinamn - - - Set title for your category. - Ange namnet på din kategori. - - - Category description - Kategoribeskrivning - - - Set description for your category. - Beskriv din kategori. - - - Icon selection - Ikonval - - - Load icon from file... - Hämta ikon från fil... - - - Do not use icon - Använd ingen ikon - - - Use default icon - Använd standardikon - - - The description is ok. - Beskrivningen är ok. - - FormDatabaseCleanup @@ -951,7 +742,10 @@ Uppdateringsstatus: %5 day(s) - dagdagar + + dag + dagar + Shrink database file @@ -1006,389 +800,6 @@ Uppdateringsstatus: %5 Ta bort alla stjärnmärkta meddelanden (inklusive dem i papperskorgen) - - FormFeedDetails - - Parent category - Överordnad kategori - - - Select parent item for your feed. - Välj överordnad mapp för flödet. - - - Type - Typ - - - Select type of the standard feed. - Välj flödestyp. - - - Encoding - Kodning - - - Select encoding of the standard feed. If you are unsure about the encoding, then select "UTF-8" encoding. - Välj flödeskodning. Välj "UTF-8" om du är osäker på kodningen. - - - Auto-update - Auto-uppdatering - - - Select the auto-update strategy for this feed. Default auto-update strategy means that the feed will be update in time intervals set in application settings. - Välj uppdateringsstrategi för flödet. Global auto-uppdatering, innebär att flödet kommer att uppdateras med tidsintervall angivna i programinställningarna. - - - minutes - minuter - - - Title - Namn - - - Description - Beskrivning - - - URL - URL - - - Fetch it now - Hämta nu - - - Icon - Ikon - - - Select icon for your feed. - Välj ikon för flödet. - - - Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. - Vissa flöden kräver autentisering, inklusive Gmail-flöden. BASIC, NTLM-2 och DIGEST-MD5 autentisering stöds. - - - Requires authentication - Kräver autentisering - - - Username - Användarnamn - - - Password - Lösenord - - - Fetch metadata - Hämta metadata - - - Add new feed - Lägg till nytt flöde - - - Edit existing feed - Redigera befintligt flöde - - - Feed name is ok. - Flödesnamnet är ok. - - - Feed name is too short. - Flödesnamnet är för kort. - - - Description is empty. - Beskrivning saknas. - - - The url is ok. - Webbadressen är ok. - - - The url does not meet standard pattern. Does your url start with "http://" or "https://" prefix. - Webbadressen liknar inte standardmönstret. Börjar din URL med prefixet "http://" eller "https://"?. - - - The url is empty. - URL saknas. - - - Username is ok or it is not needed. - Användarnamnet är ok, eller behövs inte. - - - Username is empty. - Användarnamn saknas. - - - Password is ok or it is not needed. - Lösenordet är ok, eller behövs inte. - - - Password is empty. - Lösenord saknas. - - - Select icon file for the feed - Välj ikonfil för flödet - - - Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - bilder (*.bmp *.jpg *.jpeg *.png *.svg *.tga) - - - Select icon - Välj ikon - - - Cancel - Avbryt - - - Look in: - Label for field with icon file name textbox for selection dialog. - Sök i: - - - Icon name: - Ikonnamn: - - - Icon type: - Ikontyp: - - - Cannot add feed - Kan inte lägga till flöde - - - Feed was not added due to error. - Flödet lades inte till, på grund av något fel. - - - Cannot edit feed - Kan inte redigera flödet - - - All metadata fetched successfully. - All metadata hämtades korrekt. - - - Feed and icon metadata fetched. - Flödes- och ikonmetadata hämtad. - - - Result: %1. - Resultat: %1. - - - Feed or icon metatada not fetched. - Flödes- eller ikonmetadata hämtades inte. - - - Error: %1. - Fel: %1. - - - No metadata fetched. - Ingen metadata hämtades. - - - Feed title - Flödesnamn - - - Set title for your feed. - Ange flödets namn. - - - Feed description - Flödesbeskrivning - - - Set description for your feed. - Beskriv flödet. - - - Full feed url including scheme - Flödets fullständiga webbadress (URL) - - - Set url for your feed. - Ange flödets URL. - - - Set username to access the feed. - Ange användarnamn för att få åtkomst till flödet. - - - Set password to access the feed. - Ange lösenord för att få åtkomst till flödet. - - - Icon selection - Ikonval - - - Load icon from file... - Hämta ikon från fil... - - - Do not use icon - Använd ingen ikon - - - Use default icon - Använd standardikon - - - No metadata fetched so far. - Ingen metadata hämtad. - - - Auto-update using global interval - Global auto-uppdatering - - - Auto-update every - Auto-uppdatera varje - - - Do not auto-update at all - Ingen auto-uppdatering - - - The description is ok. - Beskrivningen är ok. - - - Feed was not edited due to error. - Flödet redigerades inte, på grund av något fel. - - - Icon fetched successfully. - Ikon hämtades. - - - Icon metadata fetched. - Ikonmetadata hämtad. - - - Icon metatada not fetched. - Ikonmetadata hämtades inte. - - - No icon fetched. - Ikon hämtades inte. - - - Fetch icon from feed - Hämta ikon från flödet - - - - FormImportExport - - &Select file - &Välj fil - - - Operation results - Åtgärdsresultat - - - No file is selected. - Ingen fil har valts. - - - No operation executed yet. - Ingen åtgärd slutförd än. - - - Export feeds - Exportera flöden - - - Destination file - Målfil - - - Source feeds && categories - Källflöden && -kategorier - - - Source file - Källfil - - - Target feeds && categories - Målflöden && -kategorier - - - Import feeds - Importera flöden - - - OPML 2.0 files (*.opml) - OPML 2.0-filer (*.opml) - - - Select file for feeds export - Välj fil för flödesexport - - - File is selected. - Fil är vald. - - - Select file for feeds import - Välj fil för flödesimport - - - Cannot open source file. - Kan inte öppna källfil. - - - Feeds were loaded. - Flöden lästes in. - - - Error, file is not well-formed. Select another file. - Fel! Filen är inte rätt formaterad. Välj en annan fil. - - - Error occurred. File is not well-formed. Select another file. - Ett fel uppstod. Filen är felformaterad. Välj en annan fil. - - - Feeds were exported successfully. - Flöden exporterades korrekt. - - - Cannot write into destination file. - Kan inte skriva till målfilen. - - - Critical error occurred. - Ett allvarligt fel uppstod. - - - &Check all items - &Markera alla - - - &Uncheck all items - &Avmarkera alla - - FormMain @@ -1467,18 +878,6 @@ Uppdateringsstatus: %5 Fee&ds && categories &Flöden && kategorier - - Mark all messages (without message filters) from selected feeds as read. - Markera alla meddelanden från valda flöden, som lästa. - - - Mark all messages (without message filters) from selected feeds as unread. - Markera alla meddelanden från valda flöden, som olästa. - - - Displays all messages from selected feeds/categories in a new "newspaper mode" tab. Note that messages are not set as read automatically. - Visa alla meddelanden från markerade flöden/kategorier i en ny flik, som "tidningsvy". Notera att meddelandena inte automatiskt markeras som lästa. - Hides main window if it is visible and shows it if it is hidden. Dölj programfönstret om det är synligt, och visa det om det är dolt. @@ -1503,34 +902,6 @@ Uppdateringsstatus: %5 &Delete selected messages &Ta bort markerade meddelanden - - Deletes all messages from selected feeds. - Ta bort alla meddelanden från markerade flöden. - - - Marks all messages in all feeds read. This does not take message filters into account. - Markera alla meddelanden i samtliga flöden som lästa. Detta åsidosätter eventuella meddelandefilter. - - - Deletes all messages from all feeds. - Ta bort alla meddelanden från samtliga flöden. - - - Update &all feeds - Uppdatera &alla flöden - - - Update &selected feeds - Uppdatera &markerade flöden - - - &Edit selected feed/category - &Redigera markerat flöde/kategori - - - &Delete selected feed/category - &Ta bort markerat flöde/kategori - Settings Inställningar @@ -1539,10 +910,6 @@ Uppdateringsstatus: %5 Hides or displays the main menu. Dölj/Visa huvudmenyn. - - Add &new feed/category - Lägg till &nytt flöde/kategori - &Close all tabs except current one &Stäng alla flikar utom den aktuella @@ -1559,18 +926,6 @@ Uppdateringsstatus: %5 Mark &selected messages as &unread Märk markerade &meddelanden som &olästa - - &Mark selected feeds as read - &Märk markerade meddelanden som lästa - - - &Mark selected feeds as unread - &Märk markerade meddelanden som olästa - - - &Clean selected feeds - &Rensa markerade flöden - Open selected source articles in &external browser Öppna markerade källartiklar i &extern webbläsare @@ -1583,26 +938,6 @@ Uppdateringsstatus: %5 Open selected source articles in &internal browser Öppna markerade källartiklar i &intern webbläsare - - &Mark all feeds as &read - &Markera samtliga flöden som &lästa - - - View selected feeds in &newspaper mode - Visa markerade flöden som &tidningsvy - - - &Clean all feeds - &Rensa alla flöden - - - Select &next feed/category - Gå till &nästa flöde/kategori - - - Select &previous feed/category - Gå till &föregående flöde/kategori - Select &next message Gå till &nästa meddelande @@ -1655,22 +990,6 @@ Uppdateringsstatus: %5 Cannot open external browser. Navigate to application website manually. Kan inte öppna extern webbläsare. Navigera manuellt till programmets webbsida. - - New &feed - Nytt &flöde - - - Add new feed. - Lägg till nytt flöde. - - - New &category - Ny &kategori - - - Add new category. - Lägg till ny kategori. - &Toolbars &Verktygsfält @@ -1683,30 +1002,10 @@ Uppdateringsstatus: %5 &Feed/message list headers &Kolumnrubriker - - &Import feeds - &Importera flöden - - - Imports feeds you want from selected file. - Importera flöden från fil. - - - &Export feeds - &Exportera flöden - - - Exports feeds you want to selected file. - Exportera flöden till fil. - Close all tabs except current one. Stäng alla flikar utom aktuell. - - &Recycle bin - &Papperskorgen - Report a &bug (GitHub)... Rapportera ett &fel (GitHub)... @@ -1723,18 +1022,6 @@ Uppdateringsstatus: %5 Display &wiki Visa &wiki - - &Empty recycle bin - &Töm papperskorgen - - - &Restore all messages - &Återställ alla meddelanden - - - Restore &selected messages - Återställ &markerade meddelanden - &Restart &Starta om @@ -1764,16 +1051,136 @@ Uppdateringsstatus: %5 &Rensa databasen - Show only unread feeds/categories - Visa endast olästa flöden/kategorier + Add &new item + - &Fetch feed metadata - &Hämta flödesmetadata + &Services + - &Expand/collapse selected feed/category - &Expandera/Komprimera markerat flöde/kategori + Update &all items + + + + Ctrl+Shift+U + + + + Update &selected items + + + + Ctrl+U + + + + &Edit selected item + + + + &Delete selected item + + + + &Mark selected items as read + + + + Mark all messages (without message filters) from selected items as read. + + + + &Mark selected items as unread + + + + Mark all messages (without message filters) from selected items as unread. + + + + &Clean selected items + + + + Deletes all messages from selected items. + + + + &Mark all items as &read + + + + Marks all messages in all items read. This does not take message filters into account. + + + + View selected items in &newspaper mode + + + + Displays all messages from selected item in a new "newspaper mode" tab. Note that messages are not set as read automatically. + + + + &Clean all items + + + + Deletes all messages from all items. + + + + Ctrl+Shift+C + + + + Select &next item + + + + S + + + + Select &previous item + + + + A + + + + Show only unread items + + + + &Expand/collapse selected item + + + + E + + + + &Add new service account + + + + &Delete selected service account + + + + &Edit selected service account + + + + &Restore selected messages + + + + No possible actions + @@ -1924,10 +1331,6 @@ Uppdateringsstatus: %5 Author Översättare - - Email - E-post - Socks5 Socks5 @@ -2505,6 +1908,521 @@ File filter for external e-mail selection dialog. Fancy && modern popup notifications (This uses OS native notifications via D-Bus if available.) Tjusiga && moderna popup-aviseringar (Använder systemets integrerade aviseringar via D-Bus, om tillgängligt.) + + E-mail + + + + + FormStandardCategoryDetails + + Parent category + Överordnad kategori + + + Select parent item for your category. + Välj överordnad mapp för kategorin. + + + Title + + + + Description + Beskrivning + + + Icon + Ikon + + + Select icon for your category. + Välj ikon för kategorin. + + + Add new category + Lägg till ny kategori + + + Edit existing category + Redigera befintlig kategori + + + Cannot add category + Kan inte lägga till kategori + + + Category was not added due to error. + Kategorin lades inte till, på grund av något fel. + + + Cannot edit category + Kan inte redigera kategorin + + + Category was not edited due to error. + Kategorin kan inte redigeras, på grund av något fel. + + + Category name is ok. + Kategorinamnet är ok. + + + Category name is too short. + Kategorinamnet är för kort. + + + Description is empty. + Beskrivning saknas. + + + The description is ok. + Beskrivningen är ok. + + + Select icon file for the category + Välj ikonfil för kategorin + + + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + + + + Select icon + Välj ikon + + + Cancel + Avbryt + + + Look in: + Label to describe the folder for icon file selection dialog. + Sök i: + + + Icon name: + Ikonnamn: + + + Icon type: + Ikontyp: + + + Category title + Kategorinamn + + + Set title for your category. + Ange namnet på din kategori. + + + Category description + Kategoribeskrivning + + + Set description for your category. + Beskriv din kategori. + + + Icon selection + Ikonval + + + Load icon from file... + Hämta ikon från fil... + + + Do not use icon + Använd ingen ikon + + + Use default icon + Använd standardikon + + + + FormStandardFeedDetails + + Parent category + Överordnad kategori + + + Select parent item for your feed. + Välj överordnad mapp för flödet. + + + Type + Typ + + + Select type of the standard feed. + Välj flödestyp. + + + Encoding + Kodning + + + Select encoding of the standard feed. If you are unsure about the encoding, then select "UTF-8" encoding. + Välj flödeskodning. Välj "UTF-8" om du är osäker på kodningen. + + + Auto-update + Auto-uppdatering + + + Select the auto-update strategy for this feed. Default auto-update strategy means that the feed will be update in time intervals set in application settings. + Välj uppdateringsstrategi för flödet. Global auto-uppdatering, innebär att flödet kommer att uppdateras med tidsintervall angivna i programinställningarna. + + + minutes + minuter + + + Title + + + + Description + Beskrivning + + + URL + URL + + + Fetch it now + Hämta nu + + + Icon + Ikon + + + Select icon for your feed. + Välj ikon för flödet. + + + Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. + Vissa flöden kräver autentisering, inklusive Gmail-flöden. BASIC, NTLM-2 och DIGEST-MD5 autentisering stöds. + + + Requires authentication + Kräver autentisering + + + Username + Användarnamn + + + Password + Lösenord + + + Fetch metadata + Hämta metadata + + + Add new feed + Lägg till nytt flöde + + + Edit existing feed + Redigera befintligt flöde + + + Feed name is ok. + Flödesnamnet är ok. + + + Feed name is too short. + Flödesnamnet är för kort. + + + Description is empty. + Beskrivning saknas. + + + The description is ok. + Beskrivningen är ok. + + + The url is ok. + Webbadressen är ok. + + + The url does not meet standard pattern. Does your url start with "http://" or "https://" prefix. + Webbadressen liknar inte standardmönstret. Börjar din URL med prefixet "http://" eller "https://"?. + + + The url is empty. + URL saknas. + + + Username is ok or it is not needed. + Användarnamnet är ok, eller behövs inte. + + + Username is empty. + Användarnamn saknas. + + + Password is ok or it is not needed. + Lösenordet är ok, eller behövs inte. + + + Password is empty. + Lösenord saknas. + + + Select icon file for the feed + Välj ikonfil för flödet + + + Images (*.bmp *.jpg *.jpeg *.png *.svg *.tga) + + + + Select icon + Välj ikon + + + Cancel + Avbryt + + + Look in: + Label for field with icon file name textbox for selection dialog. + Sök i: + + + Icon name: + Ikonnamn: + + + Icon type: + Ikontyp: + + + Cannot add feed + Kan inte lägga till flöde + + + Feed was not added due to error. + Flödet lades inte till, på grund av något fel. + + + Cannot edit feed + Kan inte redigera flödet + + + Feed was not edited due to error. + Flödet redigerades inte, på grund av något fel. + + + All metadata fetched successfully. + All metadata hämtades korrekt. + + + Feed and icon metadata fetched. + Flödes- och ikonmetadata hämtad. + + + Result: %1. + Resultat: %1. + + + Feed or icon metatada not fetched. + Flödes- eller ikonmetadata hämtades inte. + + + Error: %1. + Fel: %1. + + + No metadata fetched. + Ingen metadata hämtades. + + + Icon fetched successfully. + Ikon hämtades. + + + Icon metadata fetched. + Ikonmetadata hämtad. + + + Icon metatada not fetched. + Ikonmetadata hämtades inte. + + + No icon fetched. + Ikon hämtades inte. + + + Feed title + Flödesnamn + + + Set title for your feed. + Ange flödets namn. + + + Feed description + Flödesbeskrivning + + + Set description for your feed. + Beskriv flödet. + + + Full feed url including scheme + Flödets fullständiga webbadress (URL) + + + Set url for your feed. + Ange flödets URL. + + + Set username to access the feed. + Ange användarnamn för att få åtkomst till flödet. + + + Set password to access the feed. + Ange lösenord för att få åtkomst till flödet. + + + Icon selection + Ikonval + + + Load icon from file... + Hämta ikon från fil... + + + Do not use icon + Använd ingen ikon + + + Use default icon + Använd standardikon + + + Fetch icon from feed + Hämta ikon från flödet + + + No metadata fetched so far. + Ingen metadata hämtad. + + + Auto-update using global interval + Global auto-uppdatering + + + Auto-update every + Auto-uppdatera varje + + + Do not auto-update at all + Ingen auto-uppdatering + + + + FormStandardImportExport + + &Select file + &Välj fil + + + &Check all items + &Markera alla + + + &Uncheck all items + &Avmarkera alla + + + Operation results + Åtgärdsresultat + + + No file is selected. + Ingen fil har valts. + + + No operation executed yet. + Ingen åtgärd slutförd än. + + + Destination file + Målfil + + + Source feeds && categories + Källflöden && -kategorier + + + Export feeds + Exportera flöden + + + Source file + Källfil + + + Target feeds && categories + Målflöden && -kategorier + + + Import feeds + Importera flöden + + + OPML 2.0 files (*.opml) + OPML 2.0-filer (*.opml) + + + Select file for feeds export + Välj fil för flödesexport + + + File is selected. + Fil är vald. + + + Select file for feeds import + Välj fil för flödesimport + + + Cannot open source file. + Kan inte öppna källfil. + + + Feeds were loaded. + Flöden lästes in. + + + Error, file is not well-formed. Select another file. + Fel! Filen är inte rätt formaterad. Välj en annan fil. + + + Error occurred. File is not well-formed. Select another file. + Ett fel uppstod. Filen är felformaterad. Välj en annan fil. + + + Feeds were exported successfully. + Flöden exporterades korrekt. + + + Cannot write into destination file. + Kan inte skriva till målfilen. + + + Critical error occurred. + Ett allvarligt fel uppstod. + FormUpdate @@ -2753,6 +2671,14 @@ Gå till programmets hemsida för att hämta den manuellt. List of attachments. Lista över bilagor. + + Loading of messages from item '%s' failed. + + + + Loading of messages failed, maybe messages could not be downloaded. + + MessagesToolBar @@ -2926,26 +2852,34 @@ Gå till programmets hemsida för att hämta den manuellt. LANG_EMAIL eson57@gmail.com - - Load initial feeds - Läs in flöden - - - Do you want to load initial set of feeds? - Vill du läsa in flödesuppsättningen? - LANG_NAME Name of language, e.g. English. Swedish - - You started %1 for the first time, now you can load initial set of feeds. - Du har startat %1 för första gången. Nu kan du läsa in inledande flödesuppsättning. + + + ++ %n other feeds. + + + + - Welcome to %1 %2. - Välkommen till %1 %2. + Welcome to %1. + +Please, check NEW stuff included in this +version by clicking this popup notification. + + + + Welcome to %1. + Välkommen till %1 %2. {1.?} + + + Load initial set of feeds + @@ -2966,7 +2900,10 @@ Gå till programmets hemsida för att hämta den manuellt. %n deleted message(s). - %n borttaget meddelande.%n borttagna meddelanden. + + %n borttaget meddelande. + %n borttagna meddelanden. + @@ -2984,6 +2921,137 @@ Gå till programmets hemsida för att hämta den manuellt. Klicka och välj ny snabbtangent. + + StandardCategory + + %1 (category)%2%3 + Tooltip for standard feed. + %1 (kategori)%2%3 + + + +This category does not contain any nested items. + +Denna kategori innehåller inga objekt. + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + %n oläst meddelande. + %n olästa meddelanden. + + + + + StandardFeed + + Metadata not fetched + Metadata hämtades inte + + + Metadata was not fetched because: %1. + Metadata hämtades inte på grund av: %1. + + + does not use auto-update + Describes feed auto-update status. + uppdateras inte automatiskt + + + uses global settings + Describes feed auto-update status. + Globala inställningar + + + uses specific settings (%n minute(s) to next auto-update) + Describes feed auto-update status. + + Anpassade inställningar. (%n minut till nästa auto-uppdatering) + Anpassade inställningar. (%n minuter till nästa auto-uppdatering) + + + + %1 (%2)%3 + +Network status: %6 +Encoding: %4 +Auto-update status: %5 + Tooltip for feed. + %1 (%2)%3 + +Nätverksstatus: %6 +Kodning: %4 +Uppdateringsstatus: %5 + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + %n oläst meddelande. + %n olästa meddelanden. + + + + + StandardServiceRoot + + This is obligatory service account for standard RSS/RDF/ATOM feeds. + + + + You started %1 for the first time, now you can load initial set of feeds. + Du har startat %1 för första gången. Nu kan du läsa in inledande flödesuppsättning. + + + Do you want to load initial set of feeds? + Vill du läsa in flödesuppsättningen? + + + Error when loading initial feeds + Fel vid inläsning av flöden + + + This is service account for standard RSS/RDF/ATOM feeds. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + %n oläst meddelande. + %n olästa meddelanden. + + + + Fetch metadata + Hämta metadata + + + Import successfull, but some feeds/categories were not imported due to error. + Importen slutfördes, men vissa flöden/kategorier importerades inte på grund av något fel. + + + Import was completely successfull. + Importen slutfördes korrekt. + + + Add new category + Lägg till ny kategori + + + Add new feed + Lägg till nytt flöde + + + Export feeds + Exportera flöden + + + Import feeds + Importera flöden + + StatusBar @@ -3005,6 +3073,10 @@ Gå till programmets hemsida för att hämta den manuellt. Click the bubble for more information. Klicka på detta meddelande för mer information. + + anonymous + + SystemTrayIcon @@ -3112,6 +3184,21 @@ Olästa nyheter: %2 Stäng öppna dialogrutor först. + + TtRssServiceRoot + + This is service account TT-RSS (TinyTiny RSS) server. + + + + %n unread message(s). + Tooltip for "unread" column of feed list. + + %n oläst meddelande. + %n olästa meddelanden. + + + WebBrowser @@ -3323,4 +3410,4 @@ Olästa nyheter: %2 Sök "%1" via Google... - \ No newline at end of file + diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 02bb88db0..8e4c08001 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -21,6 +21,7 @@ Fixed:
        +
      • Better info in popup notification when many feeds are updated.
      • Fixed obtaining of contents in RSS 2.0 feed entries. (bug #130)
      • Improved popup informing about changes in newly installed version.
      • Icons in notification popups are now smaller (22 x 22 pixels).
      • diff --git a/src/core/feeddownloader.cpp b/src/core/feeddownloader.cpp index 3bdce23f0..7f7b996a9 100755 --- a/src/core/feeddownloader.cpp +++ b/src/core/feeddownloader.cpp @@ -72,5 +72,11 @@ QString FeedDownloadResults::getOverview(int how_many_feeds) { result.append(m_updatedFeeds.at(i).first + QSL(": ") + QString::number(m_updatedFeeds.at(i).second)); } - return result.join(QSL("\n")); + QString res_str = result.join(QSL("\n")); + + if (m_updatedFeeds.size() > how_many_feeds) { + res_str += QObject::tr("\n\n+ %n other feeds.", 0, m_updatedFeeds.size() - how_many_feeds); + } + + return res_str; } From bd6c5390b49899fc00aa25fd784145f5342529b7 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 24 Nov 2015 09:13:43 +0100 Subject: [PATCH 069/203] Added global recycle bin menu and ability to empty/restore individiual bins or all of them. --- src/core/feeddownloader.cpp | 1 - src/core/feedsmodel.cpp | 30 +++++ src/core/feedsmodel.h | 3 + src/gui/dialogs/formmain.cpp | 56 +++++++- src/gui/dialogs/formmain.h | 1 + src/gui/dialogs/formmain.ui | 124 +++++++++++++++++- src/gui/feedmessageviewer.cpp | 11 +- src/services/abstract/recyclebin.h | 1 + src/services/abstract/serviceroot.cpp | 4 + src/services/abstract/serviceroot.h | 4 + src/services/standard/standardcategory.cpp | 6 +- src/services/standard/standardfeed.cpp | 12 +- src/services/standard/standardrecyclebin.cpp | 52 +------- src/services/standard/standardserviceroot.cpp | 92 ++++++++++--- src/services/standard/standardserviceroot.h | 8 +- 15 files changed, 313 insertions(+), 92 deletions(-) mode change 100644 => 100755 src/services/abstract/recyclebin.h diff --git a/src/core/feeddownloader.cpp b/src/core/feeddownloader.cpp index 7f7b996a9..22d331a31 100755 --- a/src/core/feeddownloader.cpp +++ b/src/core/feeddownloader.cpp @@ -67,7 +67,6 @@ QString FeedDownloadResults::getOverview(int how_many_feeds) { QStringList result; - // TODO: Maybe enhance the formatting of this output. for (int i = 0, number_items_output = qMin(how_many_feeds, m_updatedFeeds.size()); i < number_items_output; i++) { result.append(m_updatedFeeds.at(i).first + QSL(": ") + QString::number(m_updatedFeeds.at(i).second)); } diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 95bdf6dd5..b40319a00 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -21,6 +21,7 @@ #include "services/abstract/feed.h" #include "services/abstract/category.h" #include "services/abstract/serviceroot.h" +#include "services/abstract/recyclebin.h" #include "services/standard/standardserviceroot.h" #include "miscellaneous/textfactory.h" #include "miscellaneous/databasefactory.h" @@ -534,6 +535,7 @@ void FeedsModel::notifyWithCounts() { void FeedsModel::onItemDataChanged(QList items) { if (items.size() > RELOAD_MODEL_BORDER_NUM) { qDebug("There is request to reload feed model for more than %d items, reloading model fully.", RELOAD_MODEL_BORDER_NUM); + reloadWholeLayout(); } else { qDebug("There is request to reload feed model, reloading the %d items individually.", items.size()); @@ -574,6 +576,34 @@ bool FeedsModel::addServiceAccount(ServiceRoot *root) { return true; } +bool FeedsModel::restoreAllBins() { + bool result = true; + + foreach (ServiceRoot *root, serviceRoots()) { + RecycleBin *bin_of_root = root->recycleBin(); + + if (bin_of_root != NULL) { + result &= bin_of_root->restore(); + } + } + + return result; +} + +bool FeedsModel::emptyAllBins() { + bool result = true; + + foreach (ServiceRoot *root, serviceRoots()) { + RecycleBin *bin_of_root = root->recycleBin(); + + if (bin_of_root != NULL) { + result &= bin_of_root->empty(); + } + } + + return result; +} + void FeedsModel::loadActivatedServiceAccounts() { // Iterate all globally available feed "service plugins". foreach (ServiceEntryPoint *entry_point, qApp->feedServices()) { diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 75ec450c7..14728559e 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -145,6 +145,9 @@ class FeedsModel : public QAbstractItemModel { bool addServiceAccount(ServiceRoot *root); public slots: + bool restoreAllBins(); + bool emptyAllBins(); + // Feeds operations. bool markItemRead(RootItem *item, RootItem::ReadStatus read); bool markItemCleared(RootItem *item, bool clean_read_only); diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index c433d3532..765bcaaf2 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -40,6 +40,7 @@ #include "gui/dialogs/formrestoredatabasesettings.h" #include "gui/notifications/notification.h" #include "services/abstract/serviceroot.h" +#include "services/abstract/recyclebin.h" #include "services/standard/gui/formstandardimportexport.h" #include @@ -185,8 +186,8 @@ void FormMain::updateAddItemMenu() { if (root_actions.isEmpty()) { QAction *no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")), - tr("No possible actions"), - m_ui->m_menuAddItem); + tr("No possible actions"), + m_ui->m_menuAddItem); no_action->setEnabled(false); root_menu->addAction(no_action); } @@ -210,8 +211,8 @@ void FormMain::updateServicesMenu() { if (root_actions.isEmpty()) { QAction *no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")), - tr("No possible actions"), - m_ui->m_menuServices); + tr("No possible actions"), + m_ui->m_menuServices); no_action->setEnabled(false); root_menu->addAction(no_action); } @@ -231,6 +232,49 @@ void FormMain::updateServicesMenu() { m_ui->m_menuServices->addAction(m_ui->m_actionServiceDelete); } +void FormMain::updateRecycleBinMenu() { + m_ui->m_menuRecycleBin->clear(); + + foreach (ServiceRoot *activated_root, tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->serviceRoots()) { + QMenu *root_menu = new QMenu(activated_root->title(), m_ui->m_menuServices); + root_menu->setIcon(activated_root->icon()); + root_menu->setToolTip(activated_root->description()); + + RecycleBin *bin = activated_root->recycleBin(); + + if (bin == NULL) { + QAction *no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")), + tr("No recycle bin"), + m_ui->m_menuRecycleBin); + no_action->setEnabled(false); + root_menu->addAction(no_action); + } + else { + QAction *restore_action = new QAction(qApp->icons()->fromTheme(QSL("recycle-bin-restore-all")), + tr("Restore recycle bin"), + m_ui->m_menuRecycleBin); + QAction *empty_action = new QAction(qApp->icons()->fromTheme(QSL("recycle-bin-empty")), + tr("Empty recycle bin"), + m_ui->m_menuRecycleBin); + + connect(restore_action, SIGNAL(triggered()), bin, SLOT(restore())); + connect(empty_action, SIGNAL(triggered()), bin, SLOT(empty())); + + root_menu->addAction(restore_action); + root_menu->addAction(empty_action); + } + + m_ui->m_menuRecycleBin->addMenu(root_menu); + } + + if (!m_ui->m_menuRecycleBin->isEmpty()) { + m_ui->m_menuRecycleBin->addSeparator(); + } + + m_ui->m_menuRecycleBin->addAction(m_ui->m_actionRestoreAllRecycleBins); + m_ui->m_menuRecycleBin->addAction(m_ui->m_actionEmptyAllRecycleBins); +} + void FormMain::switchVisibility(bool force_hide) { if (force_hide || isVisible()) { if (SystemTrayIcon::isSystemTrayActivated()) { @@ -324,6 +368,9 @@ void FormMain::setupIcons() { m_ui->m_actionShowOnlyUnreadItems->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-unread"))); m_ui->m_actionExpandCollapseItem->setIcon(icon_theme_factory->fromTheme(QSL("expand-collapse"))); m_ui->m_actionRestoreSelectedMessages->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-restore-one"))); + m_ui->m_actionRestoreAllRecycleBins->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-restore-all"))); + m_ui->m_actionEmptyAllRecycleBins->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-empty"))); + // Setup icons for underlying components: opened web browsers... foreach (WebBrowser *browser, WebBrowser::runningWebBrowsers()) { @@ -396,6 +443,7 @@ void FormMain::createConnections() { connect(m_ui->m_menuAddItem, SIGNAL(aboutToShow()), this, SLOT(updateAddItemMenu())); connect(m_ui->m_menuServices, SIGNAL(aboutToShow()), this, SLOT(updateServicesMenu())); + connect(m_ui->m_menuRecycleBin, SIGNAL(aboutToShow()), this, SLOT(updateRecycleBinMenu())); // Menu "File" connections. connect(m_ui->m_actionBackupDatabaseSettings, SIGNAL(triggered()), this, SLOT(backupDatabaseSettings())); diff --git a/src/gui/dialogs/formmain.h b/src/gui/dialogs/formmain.h index c71b5d82c..8060e136e 100755 --- a/src/gui/dialogs/formmain.h +++ b/src/gui/dialogs/formmain.h @@ -79,6 +79,7 @@ class FormMain : public QMainWindow { private slots: void updateAddItemMenu(); void updateServicesMenu(); + void updateRecycleBinMenu(); // Loads web browser menu if user selects to change tabs. void loadWebBrowserMenu(int index); diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index 606060f19..085eb8677 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -169,6 +169,7 @@ + @@ -178,11 +179,19 @@ + + + &Recycle bin + + + + + @@ -219,6 +228,9 @@ Displays extra info about this application. + + + QAction::AboutRole @@ -255,6 +267,9 @@ Close all tabs except current one. + + + @@ -263,13 +278,16 @@ Close current web browser tab. + + + Update &all items - Ctrl+Shift+U + Ctrl+Shift+U @@ -277,33 +295,48 @@ Update &selected items - Ctrl+U + Ctrl+U &Edit selected item + + + &Delete selected item + + + Mark &selected messages as &read + + + Mark &selected messages as &unread + + + Switch &importance of selected messages + + + @@ -312,6 +345,9 @@ Mark all messages (without message filters) from selected items as read. + + + @@ -320,11 +356,17 @@ Mark all messages (without message filters) from selected items as unread. + + + &Delete selected messages + + + @@ -333,21 +375,33 @@ Deletes all messages from selected items. + + + Open selected source articles in &external browser + + + Open selected messages in &internal browser + + + Open selected source articles in &internal browser + + + @@ -370,6 +424,9 @@ Marks all messages in all items read. This does not take message filters into account. + + + @@ -378,6 +435,9 @@ Displays all messages from selected item in a new "newspaper mode" tab. Note that messages are not set as read automatically. + + + @@ -389,6 +449,9 @@ Hides main window if it is visible and shows it if it is hidden. + + + @@ -412,7 +475,7 @@ Deletes all messages from all items. - Ctrl+Shift+C + Ctrl+Shift+C @@ -420,7 +483,7 @@ Select &next item - S + S @@ -428,7 +491,7 @@ Select &previous item - A + A @@ -454,6 +517,9 @@ Check if new update for the application is available for download. + + + @@ -556,26 +622,41 @@ &Donate via PayPal + + + Display &wiki + + + &Restart + + + &Restore database/settings + + + &Backup database/settings + + + @@ -589,11 +670,17 @@ &Downloads + + + Send selected message via e-mail + + + @@ -619,13 +706,16 @@ &Expand/collapse selected item - E + E &Add new service account + + + @@ -634,6 +724,9 @@ &Delete selected service account + + + @@ -642,11 +735,30 @@ &Edit selected service account + + + &Restore selected messages + + + + + + + &Restore all recycle bins + + + + + + + + &Empty all recycle bins + diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 897081281..270cfb782 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -179,9 +179,11 @@ void FeedMessageViewer::toggleShowOnlyUnreadFeeds() { void FeedMessageViewer::updateMessageButtonsAvailability() { bool one_message_selected = m_messagesView->selectionModel()->selectedRows().size() == 1; bool atleast_one_message_selected = !m_messagesView->selectionModel()->selectedRows().isEmpty(); + bool bin_loaded = m_messagesView->sourceModel()->loadedItem() != NULL && m_messagesView->sourceModel()->loadedItem()->kind() == RootItemKind::Bin; FormMain *form_main = qApp->mainForm(); form_main->m_ui->m_actionDeleteSelectedMessages->setEnabled(atleast_one_message_selected); + form_main->m_ui->m_actionRestoreSelectedMessages->setEnabled(atleast_one_message_selected && bin_loaded); form_main->m_ui->m_actionMarkSelectedMessagesAsRead->setEnabled(atleast_one_message_selected); form_main->m_ui->m_actionMarkSelectedMessagesAsUnread->setEnabled(atleast_one_message_selected); form_main->m_ui->m_actionOpenSelectedMessagesInternally->setEnabled(atleast_one_message_selected); @@ -214,6 +216,7 @@ void FeedMessageViewer::updateFeedButtonsAvailability() { form_main->m_ui->m_actionViewSelectedItemsNewspaperMode->setEnabled(feed_selected || category_selected || service_selected); form_main->m_ui->m_actionExpandCollapseItem->setEnabled(feed_selected || category_selected || service_selected); form_main->m_ui->m_menuAddItem->setEnabled(!critical_action_running); + form_main->m_ui->m_menuRecycleBin->setEnabled(!critical_action_running); } void FeedMessageViewer::createConnections() { @@ -250,10 +253,6 @@ void FeedMessageViewer::createConnections() { connect(m_feedsView, SIGNAL(openMessagesInNewspaperView(QList)), form_main->m_ui->m_tabWidget, SLOT(addBrowserWithMessages(QList))); - // Downloader connections. - // TODO: přesunout všechny negui věci asi k modelům, tohle je - // hlavně GUI třída, takže přesunout aktualizace feedů do modelu - // Toolbar forwardings. connect(form_main->m_ui->m_actionCleanupDatabase, SIGNAL(triggered()), this, SLOT(showDbCleanupAssistant())); @@ -315,6 +314,10 @@ void FeedMessageViewer::createConnections() { this, SLOT(toggleShowOnlyUnreadFeeds())); connect(form_main->m_ui->m_actionRestoreSelectedMessages, SIGNAL(triggered()), m_messagesView, SLOT(restoreSelectedMessages())); + connect(form_main->m_ui->m_actionRestoreAllRecycleBins, SIGNAL(triggered()), + m_feedsView->sourceModel(), SLOT(restoreAllBins())); + connect(form_main->m_ui->m_actionEmptyAllRecycleBins, SIGNAL(triggered()), + m_feedsView->sourceModel(), SLOT(emptyAllBins())); } void FeedMessageViewer::initialize() { diff --git a/src/services/abstract/recyclebin.h b/src/services/abstract/recyclebin.h old mode 100644 new mode 100755 index da81745f6..36ee0d696 --- a/src/services/abstract/recyclebin.h +++ b/src/services/abstract/recyclebin.h @@ -30,6 +30,7 @@ class RecycleBin : public RootItem { QVariant data(int column, int role) const; + public slots: // Empties the bin - removes all messages from it (does not remove // them from DB, just permanently hide them, so that they are not // re-downloaded). diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index 874f620bd..9a68e01d7 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -38,3 +38,7 @@ void ServiceRoot::itemChanged(QList items) { void ServiceRoot::requestReloadMessageList(bool mark_selected_messages_read) { emit reloadMessageListRequested(mark_selected_messages_read); } + +void ServiceRoot::requestFeedReadFilterReload() { + emit readFeedsFilterInvalidationRequested(); +} diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 875de009d..1e05f29d8 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -26,6 +26,7 @@ class FeedsModel; +class RecycleBin; class QAction; class QSqlTableModel; @@ -52,6 +53,8 @@ class ServiceRoot : public RootItem { // NOTE: Caller does NOT take ownership of created menu! virtual QList serviceMenu() = 0; + virtual RecycleBin *recycleBin() = 0; + // Start/stop services. // Start method is called when feed model gets initialized OR after user adds new service. // @@ -125,6 +128,7 @@ class ServiceRoot : public RootItem { // Obvious methods to wrap signals. void itemChanged(QList items); void requestReloadMessageList(bool mark_selected_messages_read); + void requestFeedReadFilterReload(); signals: // Emitted if data in any item belonging to this root are changed. diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index 3f125e9bc..83075bc30 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -125,7 +125,7 @@ bool StandardCategory::removeItself() { if (children_removed) { // Children are removed, remove this standard category too. - QSqlDatabase database = qApp->database()->connection(QSL("Category"), DatabaseFactory::FromSettings); + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query_remove(database); // Remove this category from database. @@ -142,7 +142,7 @@ bool StandardCategory::removeItself() { bool StandardCategory::addItself(RootItem *parent) { // Now, add category to persistent storage. - QSqlDatabase database = qApp->database()->connection(QSL("Category"), DatabaseFactory::FromSettings); + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query_add(database); query_add.setForwardOnly(true); @@ -179,7 +179,7 @@ bool StandardCategory::addItself(RootItem *parent) { } bool StandardCategory::editItself(StandardCategory *new_category_data) { - QSqlDatabase database = qApp->database()->connection(QSL("Category"), DatabaseFactory::FromSettings); + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query_update_category(database); StandardCategory *original_category = this; RootItem *new_parent = new_category_data->parent(); diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 801d9e09f..bafdfecee 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -129,7 +129,7 @@ bool StandardFeed::cleanMessages(bool clean_read_only) { QList StandardFeed::undeletedMessages() const { QList messages; - QSqlDatabase database = qApp->database()->connection("StandardFeed", DatabaseFactory::FromSettings); + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query_read_msg(database); query_read_msg.setForwardOnly(true); query_read_msg.prepare("SELECT title, url, author, date_created, contents " @@ -174,7 +174,7 @@ QString StandardFeed::typeToString(StandardFeed::Type type) { } void StandardFeed::updateCounts(bool including_total_count) { - QSqlDatabase database = qApp->database()->connection(QSL("Feed"), DatabaseFactory::FromSettings); + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query_all(database); query_all.setForwardOnly(true); @@ -483,7 +483,7 @@ int StandardFeed::update() { } bool StandardFeed::removeItself() { - QSqlDatabase database = qApp->database()->connection(QSL("Feed"), DatabaseFactory::FromSettings); + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query_remove(database); query_remove.setForwardOnly(true); @@ -505,7 +505,7 @@ bool StandardFeed::removeItself() { bool StandardFeed::addItself(RootItem *parent) { // Now, add feed to persistent storage. - QSqlDatabase database = qApp->database()->connection(QSL("Feed"), DatabaseFactory::FromSettings); + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query_add_feed(database); query_add_feed.setForwardOnly(true); @@ -555,7 +555,7 @@ bool StandardFeed::addItself(RootItem *parent) { } bool StandardFeed::editItself(StandardFeed *new_feed_data) { - QSqlDatabase database = qApp->database()->connection(QSL("Feed"), DatabaseFactory::FromSettings); + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query_update_feed(database); StandardFeed *original_feed = this; RootItem *new_parent = new_feed_data->parent(); @@ -611,7 +611,7 @@ bool StandardFeed::editItself(StandardFeed *new_feed_data) { int StandardFeed::updateMessages(const QList &messages) { int feed_id = id(); int updated_messages = 0; - QSqlDatabase database = qApp->database()->connection(QSL("Feed"), DatabaseFactory::FromSettings); + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); bool remove_duplicates = qApp->settings()->value(GROUP(Messages), SETTING(Messages::RemoveDuplicates)).toBool(); // Prepare queries. diff --git a/src/services/standard/standardrecyclebin.cpp b/src/services/standard/standardrecyclebin.cpp index c82b90e8a..6086a80b7 100755 --- a/src/services/standard/standardrecyclebin.cpp +++ b/src/services/standard/standardrecyclebin.cpp @@ -51,61 +51,15 @@ bool StandardRecycleBin::markAsReadUnread(RootItem::ReadStatus status) { } bool StandardRecycleBin::empty() { - QSqlDatabase db_handle = qApp->database()->connection(QSL("RecycleBin"), DatabaseFactory::FromSettings); - - if (!db_handle.transaction()) { - qWarning("Starting transaction for recycle bin emptying."); - return false; - } - - QSqlQuery query_empty_bin(db_handle); - query_empty_bin.setForwardOnly(true); - - if (!query_empty_bin.exec(QSL("UPDATE Messages SET is_pdeleted = 1 WHERE is_deleted = 1;"))) { - qWarning("Query execution failed for recycle bin emptying."); - - db_handle.rollback(); - return false; - } - - // Commit changes. - if (db_handle.commit()) { - return true; - } - else { - return db_handle.rollback(); - } + return serviceRoot()->emptyBin(); } bool StandardRecycleBin::restore() { - QSqlDatabase db_handle = qApp->database()->connection(QSL("RecycleBin"), DatabaseFactory::FromSettings); - - if (!db_handle.transaction()) { - qWarning("Starting transaction for recycle bin restoring."); - return false; - } - - QSqlQuery query_empty_bin(db_handle); - query_empty_bin.setForwardOnly(true); - - if (!query_empty_bin.exec(QSL("UPDATE Messages SET is_deleted = 0 WHERE is_deleted = 1 AND is_pdeleted = 0;"))) { - qWarning("Query execution failed for recycle bin restoring."); - - db_handle.rollback(); - return false; - } - - // Commit changes. - if (db_handle.commit()) { - return true; - } - else { - return db_handle.rollback(); - } + return serviceRoot()->restoreBin(); } void StandardRecycleBin::updateCounts(bool update_total_count) { - QSqlDatabase database = qApp->database()->connection(QSL("RecycleBin"), DatabaseFactory::FromSettings); + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query_all(database); query_all.setForwardOnly(true); diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 7d439bc40..14796d5b1 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -129,8 +129,12 @@ QVariant StandardServiceRoot::data(int column, int role) const { } } +RecycleBin *StandardServiceRoot::recycleBin() { + return m_recycleBin; +} + bool StandardServiceRoot::markFeedsReadUnread(QList items, ReadStatus read) { - QSqlDatabase db_handle = qApp->database()->connection(QSL("StandardServiceRoot"), DatabaseFactory::FromSettings); + QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); if (!db_handle.transaction()) { qWarning("Starting transaction for feeds read change."); @@ -175,7 +179,7 @@ bool StandardServiceRoot::markFeedsReadUnread(QList items, ReadStatus rea } bool StandardServiceRoot::markRecycleBinReadUnread(RootItem::ReadStatus read) { - QSqlDatabase db_handle = qApp->database()->connection(QSL("StandardServiceRoot"), DatabaseFactory::FromSettings); + QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); if (!db_handle.transaction()) { qWarning("Starting transaction for recycle bin read change."); @@ -213,7 +217,7 @@ bool StandardServiceRoot::markRecycleBinReadUnread(RootItem::ReadStatus read) { } bool StandardServiceRoot::cleanFeeds(QList items, bool clean_read_only) { - QSqlDatabase db_handle = qApp->database()->connection(QSL("StandardServiceRoot"), DatabaseFactory::FromSettings); + QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query_delete_msg(db_handle); query_delete_msg.setForwardOnly(true); @@ -256,8 +260,69 @@ bool StandardServiceRoot::cleanFeeds(QList items, bool clean_read_only) { } } +bool StandardServiceRoot::restoreBin() { + QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + + if (!db_handle.transaction()) { + qWarning("Starting transaction for recycle bin restoring."); + return false; + } + + QSqlQuery query_empty_bin(db_handle); + query_empty_bin.setForwardOnly(true); + + if (!query_empty_bin.exec(QSL("UPDATE Messages SET is_deleted = 0 WHERE is_deleted = 1 AND is_pdeleted = 0;"))) { + qWarning("Query execution failed for recycle bin restoring."); + + db_handle.rollback(); + return false; + } + + // Commit changes. + if (db_handle.commit()) { + updateCounts(true); + itemChanged(getSubTree()); + requestReloadMessageList(true); + requestFeedReadFilterReload(); + return true; + } + else { + return db_handle.rollback(); + } +} + +bool StandardServiceRoot::emptyBin() { + QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + + if (!db_handle.transaction()) { + qWarning("Starting transaction for recycle bin emptying."); + return false; + } + + QSqlQuery query_empty_bin(db_handle); + query_empty_bin.setForwardOnly(true); + + if (!query_empty_bin.exec(QSL("UPDATE Messages SET is_pdeleted = 1 WHERE is_deleted = 1;"))) { + qWarning("Query execution failed for recycle bin emptying."); + + db_handle.rollback(); + return false; + } + + // Commit changes. + if (db_handle.commit()) { + m_recycleBin->updateCounts(true); + itemChanged(QList() << m_recycleBin); + requestReloadMessageList(true); + return true; + } + else { + return db_handle.rollback(); + } +} + void StandardServiceRoot::loadFromDatabase(){ - QSqlDatabase database = qApp->database()->connection("StandardServiceRoot", DatabaseFactory::FromSettings); + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); CategoryAssignment categories; FeedAssignment feeds; @@ -380,10 +445,6 @@ void StandardServiceRoot::assembleFeeds(FeedAssignment feeds) { } } -StandardRecycleBin *StandardServiceRoot::recycleBin() const { - return m_recycleBin; -} - bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, QString &output_message) { QStack original_parents; original_parents.push(this); QStack new_parents; new_parents.push(model->rootItem()); @@ -566,8 +627,8 @@ bool StandardServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, QList< selected_item->updateCounts(false); - emit dataChanged(QList() << selected_item); - emit readFeedsFilterInvalidationRequested(); + itemChanged(QList() << selected_item); + requestFeedReadFilterReload(); return true; } @@ -601,15 +662,15 @@ bool StandardServiceRoot::onAfterMessagesDelete(RootItem *selected_item, QListupdateCounts(true); if (selected_item->kind() == RootItemKind::Bin) { - emit dataChanged(QList() << m_recycleBin); + itemChanged(QList() << m_recycleBin); } else { m_recycleBin->updateCounts(true); - emit dataChanged(QList() << selected_item << m_recycleBin); + itemChanged(QList() << selected_item << m_recycleBin); } - emit readFeedsFilterInvalidationRequested(); + requestFeedReadFilterReload(); return true; } @@ -624,9 +685,8 @@ bool StandardServiceRoot::onAfterMessagesRestoredFromBin(RootItem *selected_item Q_UNUSED(message_db_ids) updateCounts(true); - - emit dataChanged(getSubTree()); - emit readFeedsFilterInvalidationRequested(); + itemChanged(getSubTree()); + requestFeedReadFilterReload(); return true; } diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 387793790..668e5b6a4 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -52,6 +52,8 @@ class StandardServiceRoot : public ServiceRoot { bool canBeDeleted(); QVariant data(int column, int role) const; + RecycleBin *recycleBin(); + // Return "add feed" and "add category" items. QList addItemMenu(); @@ -84,9 +86,6 @@ class StandardServiceRoot : public ServiceRoot { // Returns context specific menu actions for given feed. QList getContextMenuForFeed(StandardFeed *feed); - // Access to standard recycle bin. - StandardRecycleBin *recycleBin() const; - // Takes structure residing under given root item and adds feeds/categories from // it to active structure. // NOTE: This is used for import/export of the model. @@ -96,6 +95,9 @@ class StandardServiceRoot : public ServiceRoot { bool markRecycleBinReadUnread(ReadStatus read); bool cleanFeeds(QList items, bool clean_read_only); + bool restoreBin(); + bool emptyBin(); + // DB connection to be used by child items - feeds/categories. QSqlDatabase dbConnection() const; From cfabf56e44d9b6d80f16dcc5bb4ce4c6721a3e34 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 24 Nov 2015 10:52:53 +0100 Subject: [PATCH 070/203] Some more changes to entry points. --- src/core/feedsmodel.cpp | 2 +- src/core/feedsmodel.h | 4 ++-- src/network-web/webbrowser.cpp | 14 +++++++++++++- src/services/abstract/serviceentrypoint.h | 15 --------------- .../standard/standardserviceentrypoint.cpp | 12 ------------ src/services/standard/standardserviceentrypoint.h | 3 --- src/services/tt-rss/ttrssserviceentrypoint.cpp | 12 ------------ src/services/tt-rss/ttrssserviceentrypoint.h | 3 --- 8 files changed, 16 insertions(+), 49 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index b40319a00..b5916b72d 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -390,7 +390,7 @@ QList FeedsModel::serviceRoots() { } StandardServiceRoot *FeedsModel::standardServiceRoot() { - foreach (RootItem *root, m_rootItem->childItems()) { + foreach (RootItem *root, serviceRoots()) { StandardServiceRoot *std_service_root; if ((std_service_root = dynamic_cast(root)) != NULL) { diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 14728559e..c1cfff0ca 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -39,6 +39,8 @@ class FeedsModel : public QAbstractItemModel { explicit FeedsModel(QObject *parent = 0); virtual ~FeedsModel(); + DatabaseCleaner *databaseCleaner(); + // Model implementation. inline QVariant data(const QModelIndex &index, int role) const { // Return data according to item. @@ -139,8 +141,6 @@ class FeedsModel : public QAbstractItemModel { // Schedules all feeds from all accounts for update. void updateAllFeeds(); - DatabaseCleaner *databaseCleaner(); - // Adds given service root account. bool addServiceAccount(ServiceRoot *root); diff --git a/src/network-web/webbrowser.cpp b/src/network-web/webbrowser.cpp index 7a41612f2..9bd5ea1a2 100755 --- a/src/network-web/webbrowser.cpp +++ b/src/network-web/webbrowser.cpp @@ -215,7 +215,19 @@ void WebBrowser::onIconChanged() { void WebBrowser::addFeedFromWebsite(const QString &feed_link) { qApp->clipboard()->setText(feed_link); - qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->standardServiceRoot()->addNewFeed(); + + StandardServiceRoot *service = qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->standardServiceRoot(); + + if (service != NULL) { + service->addNewFeed(); + } + else { + qApp->showGuiMessage(tr("Cannot add feed"), + tr("You cannot add this feed to %1 because standard RSS/ATOM account is not enabled. Enable it first.").arg(APP_NAME), + QSystemTrayIcon::Warning, + qApp->mainForm(), + true); + } } void WebBrowser::onTitleChanged(const QString &new_title) { diff --git a/src/services/abstract/serviceentrypoint.h b/src/services/abstract/serviceentrypoint.h index ecfc75334..06f1bd83c 100755 --- a/src/services/abstract/serviceentrypoint.h +++ b/src/services/abstract/serviceentrypoint.h @@ -39,26 +39,11 @@ class ServiceEntryPoint { // to the global feed model. virtual QList initializeSubtree(FeedsModel *main_model) = 0; - // Must this service account be activated by default? - // NOTE: This is true particularly for "standard" service - // which operates with normal RSS/ATOM feeds. - virtual bool isDefaultService() = 0; - // Can this service account be added just once? // NOTE: This is true particularly for "standard" service // which operates with normal RSS/ATOM feeds. virtual bool isSingleInstanceService() = 0; - // Can this service account be added by user via GUI? - // NOTE: This is true particularly for "standard" service - // which operates with normal RSS/ATOM feeds. - virtual bool canBeAdded() = 0; - - // Can this service account by deleted by user via GUI? - // NOTE: This is false particularly for "standard" service - // which operates with normal RSS/ATOM feeds. - virtual bool canBeDeleted() = 0; - // Can properties of this service account be edited by user via GUI? virtual bool canBeEdited() = 0; diff --git a/src/services/standard/standardserviceentrypoint.cpp b/src/services/standard/standardserviceentrypoint.cpp index 3156a927c..e42076b30 100755 --- a/src/services/standard/standardserviceentrypoint.cpp +++ b/src/services/standard/standardserviceentrypoint.cpp @@ -29,22 +29,10 @@ StandardServiceEntryPoint::StandardServiceEntryPoint() { StandardServiceEntryPoint::~StandardServiceEntryPoint() { } -bool StandardServiceEntryPoint::isDefaultService() { - return true; -} - bool StandardServiceEntryPoint::isSingleInstanceService() { return true; } -bool StandardServiceEntryPoint::canBeAdded() { - return false; -} - -bool StandardServiceEntryPoint::canBeDeleted() { - return false; -} - bool StandardServiceEntryPoint::canBeEdited() { return false; } diff --git a/src/services/standard/standardserviceentrypoint.h b/src/services/standard/standardserviceentrypoint.h index 1bf1e1654..0a719413f 100755 --- a/src/services/standard/standardserviceentrypoint.h +++ b/src/services/standard/standardserviceentrypoint.h @@ -26,10 +26,7 @@ class StandardServiceEntryPoint : public ServiceEntryPoint { explicit StandardServiceEntryPoint(); virtual ~StandardServiceEntryPoint(); - bool isDefaultService(); bool isSingleInstanceService(); - bool canBeAdded(); - bool canBeDeleted(); bool canBeEdited(); QString name(); QString description(); diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp index c37c17f2a..da2b7d854 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.cpp +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -29,22 +29,10 @@ TtRssServiceEntryPoint::~TtRssServiceEntryPoint() { } -bool TtRssServiceEntryPoint::isDefaultService() { - return false; -} - bool TtRssServiceEntryPoint::isSingleInstanceService() { return false; } -bool TtRssServiceEntryPoint::canBeAdded() { - return true; -} - -bool TtRssServiceEntryPoint::canBeDeleted() { - return true; -} - bool TtRssServiceEntryPoint::canBeEdited() { return true; } diff --git a/src/services/tt-rss/ttrssserviceentrypoint.h b/src/services/tt-rss/ttrssserviceentrypoint.h index 6447cc567..6d04cf4d0 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.h +++ b/src/services/tt-rss/ttrssserviceentrypoint.h @@ -27,10 +27,7 @@ class TtRssServiceEntryPoint : public ServiceEntryPoint { explicit TtRssServiceEntryPoint(); virtual ~TtRssServiceEntryPoint(); - bool isDefaultService(); bool isSingleInstanceService(); - bool canBeAdded(); - bool canBeDeleted(); bool canBeEdited(); QString name(); QString description(); From 4e657da0881ab539059f4990e3852c3f462d1101 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 24 Nov 2015 19:46:12 +0100 Subject: [PATCH 071/203] Remove unused code. --- src/services/standard/standardserviceroot.cpp | 4 +--- src/services/standard/standardserviceroot.h | 6 ------ 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 14796d5b1..c7dad91ed 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -43,7 +43,7 @@ #include -StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent) +StandardServiceRoot::'StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent) : ServiceRoot(feeds_model, parent), m_recycleBin(new StandardRecycleBin(this)), m_actionExportFeeds(NULL), m_actionImportFeeds(NULL), m_serviceMenu(QList()), m_addItemMenu(QList()), m_feedContextMenu(QList()), m_actionFeedFetchMetadata(NULL) { @@ -679,8 +679,6 @@ bool StandardServiceRoot::onBeforeMessagesRestoredFromBin(RootItem *selected_ite } bool StandardServiceRoot::onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) { - // TODO: ok, nejake zpravy obnoveny z koše, ale nevíme přesně - // do jakých původně kanálů, obnovíme všecko. Q_UNUSED(selected_item) Q_UNUSED(message_db_ids) diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 668e5b6a4..bede330c3 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -22,7 +22,6 @@ #include #include -#include class StandardRecycleBin; @@ -98,9 +97,6 @@ class StandardServiceRoot : public ServiceRoot { bool restoreBin(); bool emptyBin(); - // DB connection to be used by child items - feeds/categories. - QSqlDatabase dbConnection() const; - public slots: void addNewCategory(); void addNewFeed(); @@ -130,8 +126,6 @@ class StandardServiceRoot : public ServiceRoot { QList m_feedContextMenu; QAction *m_actionFeedFetchMetadata; - - QSqlDatabase m_database; }; #endif // STANDARDSERVICEROOT_H From 8a6075610fc8b376a3a30ba80142b2731715024a Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 24 Nov 2015 19:47:12 +0100 Subject: [PATCH 072/203] Fix. --- src/services/standard/standardserviceroot.cpp | 2 +- src/services/standard/standardserviceroot.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index c7dad91ed..490344873 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -43,7 +43,7 @@ #include -StandardServiceRoot::'StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent) +StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent) : ServiceRoot(feeds_model, parent), m_recycleBin(new StandardRecycleBin(this)), m_actionExportFeeds(NULL), m_actionImportFeeds(NULL), m_serviceMenu(QList()), m_addItemMenu(QList()), m_feedContextMenu(QList()), m_actionFeedFetchMetadata(NULL) { diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index bede330c3..0197ef8f7 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -44,7 +44,7 @@ class StandardServiceRoot : public ServiceRoot { virtual ~StandardServiceRoot(); // Start/stop root. - void start(); + void aaaaaaaastart(); void stop(); bool canBeEdited(); From 85a7f104cf0a657b39274d4af2180fc794751960 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 24 Nov 2015 19:47:41 +0100 Subject: [PATCH 073/203] Fix. --- src/services/standard/standardserviceroot.cpp | 1 + src/services/standard/standardserviceroot.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 490344873..18b065af5 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -54,6 +54,7 @@ StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_mo setCreationDate(QDateTime::currentDateTime()); if (load_from_db) { + loadFromDatabase(); } } diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 0197ef8f7..bede330c3 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -44,7 +44,7 @@ class StandardServiceRoot : public ServiceRoot { virtual ~StandardServiceRoot(); // Start/stop root. - void aaaaaaaastart(); + void start(); void stop(); bool canBeEdited(); From 8ae9c97248115102014ef78e36e84f7bb37a2c66 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 25 Nov 2015 08:36:58 +0100 Subject: [PATCH 074/203] Cleaned service menu, now service menus use context menus only. --- src/core/feedsmodel.cpp | 22 ++++++++++--- src/core/feedsmodel.h | 1 + .../dynamicshortcutswidget.cpp | 2 +- src/gui/dialogs/formmain.cpp | 25 ++++++--------- src/gui/dialogs/formmain.h | 1 - src/gui/dialogs/formmain.ui | 32 +------------------ src/gui/feedmessageviewer.cpp | 2 -- src/gui/feedsview.cpp | 9 ------ src/gui/systemtrayicon.cpp | 2 +- src/gui/tabwidget.cpp | 1 - .../webbrowsernetworkaccessmanager.cpp | 2 +- src/services/abstract/serviceroot.h | 1 + src/services/standard/standardcategory.cpp | 11 +++++-- src/services/standard/standardfeed.cpp | 8 ++++- src/services/standard/standardserviceroot.cpp | 6 ++-- src/services/standard/standardserviceroot.h | 2 ++ 16 files changed, 56 insertions(+), 71 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index b5916b72d..502e5fb17 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -339,17 +339,31 @@ void FeedsModel::reloadCountsOfWholeModel() { void FeedsModel::removeItem(const QModelIndex &index) { if (index.isValid()) { - QModelIndex parent_index = index.parent(); RootItem *deleting_item = itemForIndex(index); + QModelIndex parent_index = index.parent(); RootItem *parent_item = deleting_item->parent(); - // Item was persistently removed. - // Remove it from the model. beginRemoveRows(parent_index, index.row(), index.row()); parent_item->removeChild(deleting_item); endRemoveRows(); - delete deleting_item; + deleting_item->deleteLater(); + notifyWithCounts(); + } +} + +void FeedsModel::removeItem(RootItem *deleting_item) { + if (deleting_item != NULL) { + QModelIndex index = indexForItem(deleting_item); + QModelIndex parent_index = index.parent(); + RootItem *parent_item = deleting_item->parent(); + + beginRemoveRows(parent_index, index.row(), index.row()); + parent_item->removeChild(deleting_item); + endRemoveRows(); + + deleting_item->deleteLater(); + notifyWithCounts(); } } diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index c1cfff0ca..08b205d96 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -67,6 +67,7 @@ class FeedsModel : public QAbstractItemModel { // Removes item with given index. // NOTE: Also deletes item from memory. void removeItem(const QModelIndex &index); + void removeItem(RootItem *deleting_item); // Checks if new parent node is different from one used by original node. // If it is, then it reassigns original_node to new parent. diff --git a/src/dynamic-shortcuts/dynamicshortcutswidget.cpp b/src/dynamic-shortcuts/dynamicshortcutswidget.cpp index 12ad5fac8..73356fa42 100755 --- a/src/dynamic-shortcuts/dynamicshortcutswidget.cpp +++ b/src/dynamic-shortcuts/dynamicshortcutswidget.cpp @@ -71,7 +71,7 @@ void DynamicShortcutsWidget::populate(QList actions) { int row_id = 0; - // TODO: Maybe separate actions into "categories". Each category will start with label. + // FIXME: Maybe separate actions into "categories". Each category will start with label. // I will assign each QAaction a property called "category" with some enum value. // Like: // File, FeedsCategories, Messages, Tools, WebBrowser, Help diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index 765bcaaf2..349794e44 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -129,6 +129,7 @@ QList FormMain::allActions() { actions << m_ui->m_actionUpdateSelectedItems; actions << m_ui->m_actionEditSelectedItem; actions << m_ui->m_actionDeleteSelectedItem; + actions << m_ui->m_actionServiceAdd; actions << m_ui->m_actionViewSelectedItemsNewspaperMode; actions << m_ui->m_actionSelectNextItem; actions << m_ui->m_actionSelectPreviousItem; @@ -197,12 +198,15 @@ void FormMain::updateAddItemMenu() { m_ui->m_menuAddItem->addMenu(root_menu); } -} -void FormMain::updateServicesMenu() { - m_ui->m_menuServices->clear(); + if (m_ui->m_menuAddItem->actions().size() > 0) { + m_ui->m_menuAddItem->addSeparator(); + } - foreach (ServiceRoot *activated_root, tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->serviceRoots()) { + m_ui->m_menuAddItem->addAction(m_ui->m_actionServiceAdd); + + /* + * foreach (ServiceRoot *activated_root, tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->serviceRoots()) { QMenu *root_menu = new QMenu(activated_root->title(), m_ui->m_menuServices); root_menu->setIcon(activated_root->icon()); root_menu->setToolTip(activated_root->description()); @@ -221,22 +225,14 @@ void FormMain::updateServicesMenu() { } m_ui->m_menuServices->addMenu(root_menu); - } - - if (!m_ui->m_menuServices->isEmpty()) { - m_ui->m_menuServices->addSeparator(); - } - - m_ui->m_menuServices->addAction(m_ui->m_actionServiceAdd); - m_ui->m_menuServices->addAction(m_ui->m_actionServiceEdit); - m_ui->m_menuServices->addAction(m_ui->m_actionServiceDelete); + }*/ } void FormMain::updateRecycleBinMenu() { m_ui->m_menuRecycleBin->clear(); foreach (ServiceRoot *activated_root, tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->serviceRoots()) { - QMenu *root_menu = new QMenu(activated_root->title(), m_ui->m_menuServices); + QMenu *root_menu = new QMenu(activated_root->title(), m_ui->m_menuRecycleBin); root_menu->setIcon(activated_root->icon()); root_menu->setToolTip(activated_root->description()); @@ -442,7 +438,6 @@ void FormMain::createConnections() { connect(m_ui->m_actionFullscreen, SIGNAL(toggled(bool)), m_statusBar->fullscreenSwitcher(), SLOT(setChecked(bool))); connect(m_ui->m_menuAddItem, SIGNAL(aboutToShow()), this, SLOT(updateAddItemMenu())); - connect(m_ui->m_menuServices, SIGNAL(aboutToShow()), this, SLOT(updateServicesMenu())); connect(m_ui->m_menuRecycleBin, SIGNAL(aboutToShow()), this, SLOT(updateRecycleBinMenu())); // Menu "File" connections. diff --git a/src/gui/dialogs/formmain.h b/src/gui/dialogs/formmain.h index 8060e136e..bf17615d3 100755 --- a/src/gui/dialogs/formmain.h +++ b/src/gui/dialogs/formmain.h @@ -78,7 +78,6 @@ class FormMain : public QMainWindow { private slots: void updateAddItemMenu(); - void updateServicesMenu(); void updateRecycleBinMenu(); // Loads web browser menu if user selects to change tabs. diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index 085eb8677..8a15ea446 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -131,6 +131,7 @@ Add &new item + @@ -171,14 +172,6 @@ - - - &Services - - - - - &Recycle bin @@ -188,7 +181,6 @@ - @@ -717,28 +709,6 @@ - - - false - - - &Delete selected service account - - - - - - - - false - - - &Edit selected service account - - - - - &Restore selected messages diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 270cfb782..cbe2d9fac 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -202,8 +202,6 @@ void FeedMessageViewer::updateFeedButtonsAvailability() { bool service_selected = anything_selected && selected_item->kind() == RootItemKind::ServiceRoot; FormMain *form_main = qApp->mainForm(); - form_main->m_ui->m_actionServiceEdit->setEnabled(!critical_action_running && service_selected); - form_main->m_ui->m_actionServiceDelete->setEnabled(!critical_action_running && service_selected); form_main->m_ui->m_actionBackupDatabaseSettings->setEnabled(!critical_action_running); form_main->m_ui->m_actionCleanupDatabase->setEnabled(!critical_action_running); form_main->m_ui->m_actionClearSelectedItems->setEnabled(feed_selected || category_selected || service_selected); diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 2ff36f599..e2fc28122 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -239,15 +239,6 @@ void FeedsView::deleteSelectedItem() { qApp->mainForm(), true); } - else { - // Item is gone, cleared from database. We can clear it from model now. - // NOTE: Cleared from memory here too. - // TODO: možná toto přesunout taky to metody deleteViaGui - // a delete selected_item jen volat tady, editViaGui taky obstará všechno, - // ale tam je to zas komplexnější. - m_sourceModel->removeItem(m_proxyModel->mapToSource(current_index)); - m_sourceModel->notifyWithCounts(); - } } else { qApp->showGuiMessage(tr("Cannot delete \"%1\"").arg(selected_item->title()), diff --git a/src/gui/systemtrayicon.cpp b/src/gui/systemtrayicon.cpp index 63bfc9ea9..514f061c4 100755 --- a/src/gui/systemtrayicon.cpp +++ b/src/gui/systemtrayicon.cpp @@ -124,7 +124,7 @@ void SystemTrayIcon::setNumber(int number, bool any_new_message) { QPixmap background(m_plainPixmap); QPainter tray_painter; - // TODO: Here draw different background instead of different color of number. + // FIXME: Here draw different background instead of different color of number. tray_painter.begin(&background); tray_painter.setPen(any_new_message ? Qt::blue : Qt::black); tray_painter.setRenderHint(QPainter::SmoothPixmapTransform, true); diff --git a/src/gui/tabwidget.cpp b/src/gui/tabwidget.cpp index 0c82fd4b0..2c0831e54 100755 --- a/src/gui/tabwidget.cpp +++ b/src/gui/tabwidget.cpp @@ -69,7 +69,6 @@ void TabWidget::openMainMenu() { m_menuMain = new QMenu(tr("Main menu"), this); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuFile); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuView); - m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuServices); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuFeeds); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuMessages); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuWebBrowser); diff --git a/src/network-web/webbrowsernetworkaccessmanager.cpp b/src/network-web/webbrowsernetworkaccessmanager.cpp index 0adf4ff1a..b8e433c24 100755 --- a/src/network-web/webbrowsernetworkaccessmanager.cpp +++ b/src/network-web/webbrowsernetworkaccessmanager.cpp @@ -39,7 +39,7 @@ WebBrowserNetworkAccessManager::~WebBrowserNetworkAccessManager() { void WebBrowserNetworkAccessManager::onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator) { Q_UNUSED(authenticator); - // TODO: Support authentication for web pages. + // FIXME: Support authentication for web pages. qDebug("URL '%s' requested authentication but username/password is not available.", qPrintable(reply->url().toString())); } diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 1e05f29d8..34d30bd61 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -53,6 +53,7 @@ class ServiceRoot : public RootItem { // NOTE: Caller does NOT take ownership of created menu! virtual QList serviceMenu() = 0; + // Access to recycle bin of this account if there is any. virtual RecycleBin *recycleBin() = 0; // Start/stop services. diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index 83075bc30..2ef830d2a 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -99,7 +99,13 @@ bool StandardCategory::editViaGui() { } bool StandardCategory::deleteViaGui() { - return removeItself(); + if (removeItself()) { + serviceRoot()->feedsModel()->removeItem(this); + return true; + } + else { + return false; + } } bool StandardCategory::markAsReadUnread(ReadStatus status) { @@ -113,7 +119,8 @@ bool StandardCategory::cleanMessages(bool clean_read_only) { bool StandardCategory::removeItself() { bool children_removed = true; - // Remove all child items (feeds, categories.) + // Remove all child items (feeds and categories) + // from the database. foreach (RootItem *child, childItems()) { if (child->kind() == RootItemKind::Category) { children_removed &= static_cast(child)->removeItself(); diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index bafdfecee..066562f3d 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -115,7 +115,13 @@ bool StandardFeed::editViaGui() { } bool StandardFeed::deleteViaGui() { - return removeItself(); + if (removeItself()) { + serviceRoot()->feedsModel()->removeItem(this); + return true; + } + else { + return false; + } } bool StandardFeed::markAsReadUnread(ReadStatus status) { diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 18b065af5..236a4b0ab 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -88,8 +88,6 @@ void StandardServiceRoot::start() { try { model.importAsOPML20(IOFactory::readTextFile(file_to_load)); model.checkAllItems(); - - // TODO: Expand all items here? mergeImportExportModel(&model, output_msg); } catch (ApplicationException &ex) { @@ -593,6 +591,10 @@ QList StandardServiceRoot::serviceMenu() { return m_serviceMenu; } +QList StandardServiceRoot::contextMenuActions() { + return serviceMenu(); +} + bool StandardServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *model) { if (item->kind() == RootItemKind::Bin) { model->setFilter(QSL("is_deleted = 1 AND is_pdeleted = 0")); diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index bede330c3..aa65fc15c 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -59,6 +59,8 @@ class StandardServiceRoot : public ServiceRoot { // Return menu to be shown in "Services -> service" menu. QList serviceMenu(); + QList contextMenuActions(); + // Message stuff. bool loadMessagesForItem(RootItem *item, QSqlTableModel *model); From b685f1fc86e860c3c353cf5a47c88ae5ee5bac1e Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 25 Nov 2015 09:37:40 +0100 Subject: [PATCH 075/203] Empty initial drag/drop support. --- src/core/feedsmodel.cpp | 116 ++++++++++++++++++ src/core/feedsmodel.h | 14 +++ src/core/feedsproxymodel.cpp | 4 +- src/core/rootitem.cpp | 4 + src/core/rootitem.h | 4 +- src/gui/feedsview.cpp | 1 + src/services/standard/standardcategory.cpp | 4 + src/services/standard/standardcategory.h | 1 + src/services/standard/standardfeed.cpp | 4 + src/services/standard/standardfeed.h | 1 + src/services/standard/standardserviceroot.cpp | 4 + src/services/standard/standardserviceroot.h | 1 + 12 files changed, 155 insertions(+), 3 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 502e5fb17..4e478513f 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -204,6 +204,122 @@ DatabaseCleaner *FeedsModel::databaseCleaner() { return m_dbCleaner; } +QMimeData *FeedsModel::mimeData(const QModelIndexList &indexes) const { + QMimeData *mime_data = new QMimeData(); + QByteArray encoded_data; + QDataStream stream(&encoded_data, QIODevice::WriteOnly); + + foreach (const QModelIndex &index, indexes) { + if (index.column() != 0) { + continue; + } + + RootItem *item_for_index = itemForIndex(index); + + if (item_for_index->kind() != RootItemKind::Root) { + stream << (quintptr) item_for_index; + } + } + + mime_data->setData(MIME_TYPE_ITEM_POINTER, encoded_data); + return mime_data; +} + +QStringList FeedsModel::mimeTypes() const { + return QStringList() << MIME_TYPE_ITEM_POINTER; +} + +bool FeedsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { + Q_UNUSED(row) + Q_UNUSED(column) + + if (action == Qt::IgnoreAction) { + return true; + } + else if (action != Qt::MoveAction) { + return false; + } + + QByteArray dragged_items_data = data->data(MIME_TYPE_ITEM_POINTER); + + if (dragged_items_data.isEmpty()) { + return false; + } + else { + QDataStream stream(&dragged_items_data, QIODevice::ReadOnly); + + while (!stream.atEnd()) { + quintptr pointer_to_item; + stream >> pointer_to_item; + + // We have item we want to drag, we also determine the target item. + RootItem *dragged_item = (RootItem*) pointer_to_item; + RootItem *target_item = itemForIndex(parent); + ServiceRoot *dragged_item_root = dragged_item->getParentServiceRoot(); + ServiceRoot *target_item_root = target_item->getParentServiceRoot(); + + if (dragged_item == target_item || dragged_item->parent() == target_item) { + qDebug("Dragged item is equal to target item or its parent is equal to target item. Cancelling drag-drop action."); + return false; + } + + if (dragged_item_root != target_item_root) { + // Transferring of items between different accounts is not possible. + qApp->showGuiMessage(tr("Cannot perform drag \& drop operation."), + tr("You can't transfer dragged item into different account, this is not supported."), + QSystemTrayIcon::Warning, + qApp->mainForm(), + true); + + qDebug("Dragged item cannot be dragged into different account. Cancelling drag-drop action."); + return false; + } + + /* + if (dragged_item->kind() == RootItem::Feeed) { + qDebug("Drag-drop action for feed '%s' detected, editing the feed.", qPrintable(dragged_item->title())); + + Feed *actual_feed = dragged_item->toFeed(); + Feed *feed_new = new Feed(*actual_feed); + + feed_new->setParent(target_item); + editFeed(actual_feed, feed_new); + + emit requireItemValidationAfterDragDrop(indexForItem(actual_feed)); + } + else if (dragged_item->kind() == RootItem::Cattegory) { + qDebug("Drag-drop action for category '%s' detected, editing the feed.", qPrintable(dragged_item->title())); + + Category *actual_category = dragged_item->toCategory(); + Category *category_new = new Category(*actual_category); + + category_new->clearChildren(); + category_new->setParent(target_item); + editCategory(actual_category, category_new); + + emit requireItemValidationAfterDragDrop(indexForItem(actual_category)); + } + */ + } + + return true; + } + + return false; +} + +Qt::DropActions FeedsModel::supportedDropActions() const { + return Qt::MoveAction; +} + +Qt::ItemFlags FeedsModel::flags(const QModelIndex &index) const { + Qt::ItemFlags base_flags = QAbstractItemModel::flags(index); + RootItem *item_for_index = itemForIndex(index); + Qt::ItemFlags additional_flags = item_for_index->additionalFlags(); + + return base_flags | additional_flags; +} + void FeedsModel::executeNextAutoUpdate() { if (!qApp->feedUpdateLock()->tryLock()) { qDebug("Delaying scheduled feed auto-updates for one minute due to another running update."); diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 08b205d96..9a1ffb40c 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -47,6 +47,13 @@ class FeedsModel : public QAbstractItemModel { return itemForIndex(index)->data(index.column(), role); } + // Drag & drop. + QMimeData *mimeData(const QModelIndexList &indexes) const; + QStringList mimeTypes() const; + bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); + Qt::DropActions supportedDropActions() const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; QModelIndex index(int row, int column, const QModelIndex &parent) const; QModelIndex parent(const QModelIndex &child) const; @@ -181,8 +188,11 @@ class FeedsModel : public QAbstractItemModel { void onFeedUpdatesFinished(FeedDownloadResults results); signals: + // Update of feeds is finished. void feedsUpdateFinished(); + // Counts of unread messages are changed in some feeds, + // notify view about this shit. void readFeedsFilterInvalidationRequested(); // Emitted when model requests update of some feeds. @@ -194,6 +204,10 @@ class FeedsModel : public QAbstractItemModel { // Emitted when there is a need of reloading of displayed messages. void reloadMessageListRequested(bool mark_selected_messages_read); + // There was some drag/drop operation, notify view about this. + // NOTE: View will probably expand dropped index. + void requireItemValidationAfterDragDrop(const QModelIndex &source_index); + private: // Returns converted ids of given feeds // which are suitable as IN clause for SQL queries. diff --git a/src/core/feedsproxymodel.cpp b/src/core/feedsproxymodel.cpp index a2dd06225..ba83fb4f6 100755 --- a/src/core/feedsproxymodel.cpp +++ b/src/core/feedsproxymodel.cpp @@ -206,7 +206,9 @@ bool FeedsProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source return true; } else { - return item->countOfUnreadMessages() > 0; + // NOTE: If item has < 0 of unread message it may mean, that the count + // of unread messages is not (yet) known, display that item too. + return item->countOfUnreadMessages() != 0; } } diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index 4b4ef2493..42738133f 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -166,6 +166,10 @@ QVariant RootItem::data(int column, int role) const { } } +Qt::ItemFlags RootItem::additionalFlags() const { + return Qt::NoItemFlags; +} + int RootItem::countOfAllMessages() const { int total_count = 0; diff --git a/src/core/rootitem.h b/src/core/rootitem.h index ef47662f5..1b0b6646e 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -74,8 +74,7 @@ class RootItem : public QObject { ///////////////////////////////////////// // Returns list of specific actions which can be done with the item. - // Do not include general actions here like actions: - // Mark as read, Update, ... + // Do not include general actions here like actions: Mark as read, Update, ... // NOTE: Ownership of returned actions is not switched to caller, free them when needed. virtual QList contextMenuActions(); @@ -113,6 +112,7 @@ class RootItem : public QObject { virtual int row() const; virtual QVariant data(int column, int role) const; + virtual Qt::ItemFlags additionalFlags() const; // Each item offers "counts" of messages. // Returns counts of messages of all child items summed up. diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index e2fc28122..f750ff432 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -54,6 +54,7 @@ FeedsView::FeedsView(QWidget *parent) m_sourceModel = m_proxyModel->sourceModel(); // Connections. + connect(m_sourceModel, SIGNAL(requireItemValidationAfterDragDrop(QModelIndex)), this, SLOT(validateItemAfterDragDrop(QModelIndex))); connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder))); setModel(m_proxyModel); diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index 2ef830d2a..578016dd5 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -90,6 +90,10 @@ QVariant StandardCategory::data(int column, int role) const { } } +Qt::ItemFlags StandardCategory::additionalFlags() const { + return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; +} + bool StandardCategory::editViaGui() { QPointer form_pointer = new FormStandardCategoryDetails(serviceRoot(), qApp->mainForm()); diff --git a/src/services/standard/standardcategory.h b/src/services/standard/standardcategory.h index d318ec99f..38a8d513f 100755 --- a/src/services/standard/standardcategory.h +++ b/src/services/standard/standardcategory.h @@ -44,6 +44,7 @@ class StandardCategory : public Category { // Returns the actual data representation of standard category. QVariant data(int column, int role) const; + Qt::ItemFlags additionalFlags() const; bool canBeEdited() { return true; diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 066562f3d..8902b6fe6 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -436,6 +436,10 @@ QVariant StandardFeed::data(int column, int role) const { } } +Qt::ItemFlags StandardFeed::additionalFlags() const { + return Qt::ItemIsDragEnabled; +} + int StandardFeed::update() { QByteArray feed_contents; int download_timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index 24577662b..f97714ba8 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -81,6 +81,7 @@ class StandardFeed : public Feed { // Obtains data related to this feed. QVariant data(int column, int role) const; + Qt::ItemFlags additionalFlags() const; // Perform fetching of new messages. Returns number of newly updated messages. int update(); diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 236a4b0ab..94a6e6ba0 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -128,6 +128,10 @@ QVariant StandardServiceRoot::data(int column, int role) const { } } +Qt::ItemFlags StandardServiceRoot::additionalFlags() const { + return Qt::ItemIsDropEnabled; +} + RecycleBin *StandardServiceRoot::recycleBin() { return m_recycleBin; } diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index aa65fc15c..dd1572ff6 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -50,6 +50,7 @@ class StandardServiceRoot : public ServiceRoot { bool canBeEdited(); bool canBeDeleted(); QVariant data(int column, int role) const; + Qt::ItemFlags additionalFlags() const; RecycleBin *recycleBin(); From 81cc30878b392551847f25a364b88b021f613ee7 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 25 Nov 2015 10:25:36 +0100 Subject: [PATCH 076/203] Added drag&drop support for feeds/categories. --- src/core/feedsmodel.cpp | 30 ++++------------------ src/core/rootitem.cpp | 4 +++ src/core/rootitem.h | 1 + src/services/standard/standardcategory.cpp | 16 ++++++++++++ src/services/standard/standardcategory.h | 1 + src/services/standard/standardfeed.cpp | 15 +++++++++++ src/services/standard/standardfeed.h | 1 + 7 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 4e478513f..2f2cc28ae 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -265,7 +265,7 @@ bool FeedsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int if (dragged_item_root != target_item_root) { // Transferring of items between different accounts is not possible. - qApp->showGuiMessage(tr("Cannot perform drag \& drop operation."), + qApp->showGuiMessage(tr("Cannot perform drag & drop operation."), tr("You can't transfer dragged item into different account, this is not supported."), QSystemTrayIcon::Warning, qApp->mainForm(), @@ -275,31 +275,11 @@ bool FeedsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int return false; } - /* - if (dragged_item->kind() == RootItem::Feeed) { - qDebug("Drag-drop action for feed '%s' detected, editing the feed.", qPrintable(dragged_item->title())); - - Feed *actual_feed = dragged_item->toFeed(); - Feed *feed_new = new Feed(*actual_feed); - - feed_new->setParent(target_item); - editFeed(actual_feed, feed_new); - - emit requireItemValidationAfterDragDrop(indexForItem(actual_feed)); + if (dragged_item->performDragDropChange(target_item)) { + // Drag & drop is supported by the dragged item and was + // completed on data level and in item hierarchy. + emit requireItemValidationAfterDragDrop(indexForItem(dragged_item)); } - else if (dragged_item->kind() == RootItem::Cattegory) { - qDebug("Drag-drop action for category '%s' detected, editing the feed.", qPrintable(dragged_item->title())); - - Category *actual_category = dragged_item->toCategory(); - Category *category_new = new Category(*actual_category); - - category_new->clearChildren(); - category_new->setParent(target_item); - editCategory(actual_category, category_new); - - emit requireItemValidationAfterDragDrop(indexForItem(actual_category)); - } - */ } return true; diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index 42738133f..d2c78a5e3 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -170,6 +170,10 @@ Qt::ItemFlags RootItem::additionalFlags() const { return Qt::NoItemFlags; } +bool RootItem::performDragDropChange(RootItem *target_item) { + return false; +} + int RootItem::countOfAllMessages() const { int total_count = 0; diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 1b0b6646e..ed6dbc370 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -113,6 +113,7 @@ class RootItem : public QObject { virtual int row() const; virtual QVariant data(int column, int role) const; virtual Qt::ItemFlags additionalFlags() const; + virtual bool performDragDropChange(RootItem *target_item); // Each item offers "counts" of messages. // Returns counts of messages of all child items summed up. diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index 578016dd5..ceca4f418 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -94,6 +94,22 @@ Qt::ItemFlags StandardCategory::additionalFlags() const { return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } +bool StandardCategory::performDragDropChange(RootItem *target_item) { + StandardCategory *category_new = new StandardCategory(*this); + category_new->clearChildren(); + category_new->setParent(target_item); + + if (editItself(category_new)) { + serviceRoot()->feedsModel()->reassignNodeToNewParent(this, target_item); + delete category_new; + return true; + } + else { + delete category_new; + return false; + } +} + bool StandardCategory::editViaGui() { QPointer form_pointer = new FormStandardCategoryDetails(serviceRoot(), qApp->mainForm()); diff --git a/src/services/standard/standardcategory.h b/src/services/standard/standardcategory.h index 38a8d513f..36ac62f9a 100755 --- a/src/services/standard/standardcategory.h +++ b/src/services/standard/standardcategory.h @@ -45,6 +45,7 @@ class StandardCategory : public Category { // Returns the actual data representation of standard category. QVariant data(int column, int role) const; Qt::ItemFlags additionalFlags() const; + bool performDragDropChange(RootItem *target_item); bool canBeEdited() { return true; diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 8902b6fe6..36e2ad098 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -440,6 +440,21 @@ Qt::ItemFlags StandardFeed::additionalFlags() const { return Qt::ItemIsDragEnabled; } +bool StandardFeed::performDragDropChange(RootItem *target_item) { + StandardFeed *feed_new = new StandardFeed(*this); + feed_new->setParent(target_item); + + if (editItself(feed_new)) { + serviceRoot()->feedsModel()->reassignNodeToNewParent(this, target_item); + delete feed_new; + return true; + } + else { + delete feed_new; + return false; + } +} + int StandardFeed::update() { QByteArray feed_contents; int download_timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index f97714ba8..4e5f234fc 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -82,6 +82,7 @@ class StandardFeed : public Feed { // Obtains data related to this feed. QVariant data(int column, int role) const; Qt::ItemFlags additionalFlags() const; + bool performDragDropChange(RootItem *target_item); // Perform fetching of new messages. Returns number of newly updated messages. int update(); From 3cb27e0cf87d09c19b39c4bdcf1d7a5ea1978f1a Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 25 Nov 2015 10:31:02 +0100 Subject: [PATCH 077/203] Updated changelog. --- resources/text/CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 8e4c08001..2ff1c8bb9 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -16,7 +16,7 @@ Added:
          -
        • Brand new "service plugin system" - HIGHLY EXPERIMENTAL and REWRITTEN from scratch. Some UI features (for example drag-drop) are temporarily unavailable. Expect bugs and misunderstandings now! Major parts of RSS Guard were completely rewritten.
        • +
        • Brand new "service plugin system" - HIGHLY EXPERIMENTAL and REWRITTEN from scratch. Expect bugs and misunderstandings now! Major parts of RSS Guard were completely rewritten.
        Fixed: From 51f6edd33a9d0be2885c419c372ce23ff5edaa24 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 25 Nov 2015 10:51:42 +0100 Subject: [PATCH 078/203] Fixed #128. --- resources/text/CHANGELOG | 1 + src/gui/dialogs/formsettings.cpp | 2 + src/gui/dialogs/formsettings.h | 3 +- src/gui/dialogs/formsettings.ui | 55 ++++++++++++++++++++------ src/gui/notifications/notification.cpp | 6 ++- src/gui/notifications/notification.h | 3 +- src/miscellaneous/application.cpp | 26 +++++++----- src/miscellaneous/settings.cpp | 3 ++ src/miscellaneous/settings.h | 3 ++ 9 files changed, 76 insertions(+), 26 deletions(-) mode change 100644 => 100755 src/gui/dialogs/formsettings.h mode change 100644 => 100755 src/gui/notifications/notification.h diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 2ff1c8bb9..376e1bb66 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -21,6 +21,7 @@ Fixed:
          +
        • Added ability to completely disable notifications (bug #128).
        • Better info in popup notification when many feeds are updated.
        • Fixed obtaining of contents in RSS 2.0 feed entries. (bug #130)
        • Improved popup informing about changes in newly installed version.
        • diff --git a/src/gui/dialogs/formsettings.cpp b/src/gui/dialogs/formsettings.cpp index f47297874..181bd0c45 100755 --- a/src/gui/dialogs/formsettings.cpp +++ b/src/gui/dialogs/formsettings.cpp @@ -732,6 +732,7 @@ void FormSettings::loadInterface() { m_ui->m_cmbNotificationPosition->addItem(tr("Bottom-right corner"), Qt::BottomRightCorner); m_ui->m_cmbNotificationPosition->addItem(tr("Top-right corner"), Qt::TopRightCorner); m_ui->m_cmbNotificationPosition->setCurrentIndex(m_ui->m_cmbNotificationPosition->findData(static_cast(settings->value(GROUP(GUI), SETTING(GUI::FancyNotificationsPosition)).toInt()))); + m_ui->m_grpBaseNotifications->setChecked(settings->value(GROUP(GUI), SETTING(GUI::EnableNotifications)).toBool()); // Load settings of icon theme. QString current_theme = qApp->icons()->currentIconTheme(); @@ -834,6 +835,7 @@ void FormSettings::saveInterface() { // Save notifications. settings->setValue(GROUP(GUI), GUI::UseFancyNotifications, m_ui->m_grpNotifications->isChecked()); + settings->setValue(GROUP(GUI), GUI::EnableNotifications, m_ui->m_grpBaseNotifications->isChecked()); settings->setValue(GROUP(GUI), GUI::FancyNotificationsPosition, static_cast(m_ui->m_cmbNotificationPosition->itemData(m_ui->m_cmbNotificationPosition->currentIndex()).toInt())); // Save selected icon theme. diff --git a/src/gui/dialogs/formsettings.h b/src/gui/dialogs/formsettings.h old mode 100644 new mode 100755 index 810dd3cbe..cdaa14663 --- a/src/gui/dialogs/formsettings.h +++ b/src/gui/dialogs/formsettings.h @@ -48,10 +48,9 @@ class FormSettings : public QDialog { protected: // Does check of controls before dialog can be submitted. bool doSaveCheck(); - bool eventFilter(QObject *obj, QEvent *e); - protected slots: + private slots: // Displays "restart" dialog if some critical settings changed. void promptForRestart(); diff --git a/src/gui/dialogs/formsettings.ui b/src/gui/dialogs/formsettings.ui index adb74b6f1..b92abf5bc 100755 --- a/src/gui/dialogs/formsettings.ui +++ b/src/gui/dialogs/formsettings.ui @@ -88,7 +88,7 @@ - 0 + 3 @@ -463,7 +463,7 @@ Authors of this application are NOT responsible for lost data. QTabWidget::North - 0 + 1 @@ -636,24 +636,39 @@ Authors of this application are NOT responsible for lost data. - + - Fancy && modern popup notifications (This uses OS native notifications via D-Bus if available.) + Enable notifications + + + false true - - - - - Notification position + + + + + Fancy && modern popup notifications (This uses OS native notifications via D-Bus if available.) + + true + + + + + + Notification position + + + + + + + - - - @@ -1765,5 +1780,21 @@ Authors of this application are NOT responsible for lost data. + + m_grpBaseNotifications + toggled(bool) + m_grpNotifications + setEnabled(bool) + + + 624 + 82 + + + 624 + 89 + + + diff --git a/src/gui/notifications/notification.cpp b/src/gui/notifications/notification.cpp index 78b522aef..510acf9c5 100755 --- a/src/gui/notifications/notification.cpp +++ b/src/gui/notifications/notification.cpp @@ -66,10 +66,14 @@ Notification::~Notification() { qDebug("Destroying Notification instance."); } -bool Notification::areNotificationsActivated() { +bool Notification::areFancyNotificationsEnabled() { return qApp->settings()->value(GROUP(GUI), SETTING(GUI::UseFancyNotifications)).toBool(); } +bool Notification::areNotificationsEnabled() { + return qApp->settings()->value(GROUP(GUI), SETTING(GUI::EnableNotifications)).toBool(); +} + void Notification::notify(const QString &text, const QString &title, const QIcon &icon, QObject *invokation_target, const char *invokation_slot) { cancel(); diff --git a/src/gui/notifications/notification.h b/src/gui/notifications/notification.h old mode 100644 new mode 100755 index 13b11bec5..dceb7bcc4 --- a/src/gui/notifications/notification.h +++ b/src/gui/notifications/notification.h @@ -35,7 +35,8 @@ class Notification : public QWidget { explicit Notification(); virtual ~Notification(); - static bool areNotificationsActivated(); + static bool areFancyNotificationsEnabled(); + static bool areNotificationsEnabled(); public slots: // Main methods for using the netofication. diff --git a/src/miscellaneous/application.cpp b/src/miscellaneous/application.cpp index 495d06042..0ff6edeae 100755 --- a/src/miscellaneous/application.cpp +++ b/src/miscellaneous/application.cpp @@ -198,19 +198,25 @@ void Application::showGuiMessage(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon message_type, QWidget *parent, bool show_at_least_msgbox, const QIcon &custom_icon, QObject *invokation_target, const char *invokation_slot) { - if (Notification::areNotificationsActivated()) { - // Show OSD instead if tray icon bubble, depending on settings. - if (custom_icon.isNull()) { - notification()->notify(message, title, message_type, invokation_target, invokation_slot); + if (Notification::areNotificationsEnabled()) { + if (Notification::areFancyNotificationsEnabled()) { + // Show OSD instead if tray icon bubble, depending on settings. + if (custom_icon.isNull()) { + notification()->notify(message, title, message_type, invokation_target, invokation_slot); + } + else { + notification()->notify(message, title, custom_icon, invokation_target, invokation_slot); + } + + return; } - else { - notification()->notify(message, title, custom_icon, invokation_target, invokation_slot); + else if (SystemTrayIcon::isSystemTrayActivated()) { + trayIcon()->showMessage(title, message, message_type, TRAY_ICON_BUBBLE_TIMEOUT, invokation_target, invokation_slot); + return; } } - else if (SystemTrayIcon::isSystemTrayActivated()) { - trayIcon()->showMessage(title, message, message_type, TRAY_ICON_BUBBLE_TIMEOUT, invokation_target, invokation_slot); - } - else if (show_at_least_msgbox) { + + if (show_at_least_msgbox) { // Tray icon or OSD is not available, display simple text box. MessageBox::show(parent, (QMessageBox::Icon) message_type, title, message); } diff --git a/src/miscellaneous/settings.cpp b/src/miscellaneous/settings.cpp index 56c8cbac1..bc040936e 100755 --- a/src/miscellaneous/settings.cpp +++ b/src/miscellaneous/settings.cpp @@ -111,6 +111,9 @@ DVALUE(bool) GUI::HideMainWindowWhenMinimizedDef = false; DKEY GUI::UseTrayIcon = "use_tray_icon"; DVALUE(bool) GUI::UseTrayIconDef = true; +DKEY GUI::EnableNotifications = "enable_notifications"; +DVALUE(bool) GUI::EnableNotificationsDef = true; + DKEY GUI::UseFancyNotifications = "use_fancy_notifications"; DVALUE(bool) GUI::UseFancyNotificationsDef = true; diff --git a/src/miscellaneous/settings.h b/src/miscellaneous/settings.h index c254e7cee..b3a977520 100755 --- a/src/miscellaneous/settings.h +++ b/src/miscellaneous/settings.h @@ -126,6 +126,9 @@ namespace GUI { KEY UseTrayIcon; VALUE(bool) UseTrayIconDef; + KEY EnableNotifications; + VALUE(bool) EnableNotificationsDef; + KEY UseFancyNotifications; VALUE(bool) UseFancyNotificationsDef; From 45f417ceeadd86d5506072ff4e98263b11e60176 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 25 Nov 2015 11:58:35 +0100 Subject: [PATCH 079/203] Some preps for #112. --- src/gui/messagesview.cpp | 31 +++++++++++++++++++++++++++++++ src/gui/messagesview.h | 1 + 2 files changed, 32 insertions(+) diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index 5458c6b76..c52d68104 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -467,6 +467,37 @@ void MessagesView::selectPreviousItem() { } } +void MessagesView::selectNextUnreadItem() { + // FIXME: Use this to solve #112. + + QModelIndexList selected_rows = selectionModel()->selectedRows(); + int active_row; + + if (!selected_rows.isEmpty()) { + // Okay, something is selected, start from it. + active_row = selected_rows.at(0).row(); + } + else { + active_row = 0; + } + + while (++active_row < m_proxyModel->rowCount()) { + // Get info if the message is read or not. + QModelIndex proxy_index = m_proxyModel->index(active_row, 0); + + bool is_read = m_sourceModel->data(m_proxyModel->mapToSource(proxy_index).row(), + MSG_DB_READ_INDEX, Qt::EditRole).toInt() == 1; + + if (!is_read) { + // We found unread message, mark it. + setCurrentIndex(proxy_index); + selectionModel()->select(proxy_index, QItemSelectionModel::Select | QItemSelectionModel::Rows); + setFocus(); + break; + } + } +} + void MessagesView::searchMessages(const QString &pattern) { m_proxyModel->setFilterRegExp(pattern); diff --git a/src/gui/messagesview.h b/src/gui/messagesview.h index 9c120ce71..2d4b6b107 100755 --- a/src/gui/messagesview.h +++ b/src/gui/messagesview.h @@ -76,6 +76,7 @@ class MessagesView : public QTreeView { void selectNextItem(); void selectPreviousItem(); + void selectNextUnreadItem(); // Searchs the visible message according to given pattern. void searchMessages(const QString &pattern); From 3e040377b6d94d37dbcba1b03cd3cfc9ad5fac5c Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 29 Nov 2015 09:22:17 +0100 Subject: [PATCH 080/203] Some refactoring + #112. --- resources/text/CHANGELOG | 3 ++- src/core/messagesproxymodel.cpp | 32 ++++++++++++++++++++++++++++++++ src/core/messagesproxymodel.h | 4 ++++ src/gui/dialogs/formmain.cpp | 2 ++ src/gui/dialogs/formmain.ui | 16 ++++++++++++++-- src/gui/feedmessageviewer.cpp | 2 ++ src/gui/feedsview.cpp | 10 ---------- src/gui/feedsview.h | 2 -- src/gui/messagesview.cpp | 19 ++++++------------- 9 files changed, 62 insertions(+), 28 deletions(-) diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 376e1bb66..f523affbc 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -17,11 +17,12 @@ Added:
          • Brand new "service plugin system" - HIGHLY EXPERIMENTAL and REWRITTEN from scratch. Expect bugs and misunderstandings now! Major parts of RSS Guard were completely rewritten.
          • +
          • Added ability to completely disable notifications (bug #128).
          • +
          • Added ability to go to next unread message. (partially bug #112)
          Fixed:
            -
          • Added ability to completely disable notifications (bug #128).
          • Better info in popup notification when many feeds are updated.
          • Fixed obtaining of contents in RSS 2.0 feed entries. (bug #130)
          • Improved popup informing about changes in newly installed version.
          • diff --git a/src/core/messagesproxymodel.cpp b/src/core/messagesproxymodel.cpp index 4fc5f9ece..992cc49fe 100755 --- a/src/core/messagesproxymodel.cpp +++ b/src/core/messagesproxymodel.cpp @@ -38,6 +38,38 @@ MessagesProxyModel::~MessagesProxyModel() { qDebug("Destroying MessagesProxyModel instance."); } +QModelIndex MessagesProxyModel::getNextPreviousUnreadItemIndex(int default_row) { + bool started_from_zero = default_row == 0; + QModelIndex next_index = getNextUnreadItemIndex(default_row, rowCount() - 1); + + // There is no next message, check previous. + if (!next_index.isValid() && !started_from_zero) { + next_index = getNextUnreadItemIndex(0, default_row - 1); + } + + return next_index; +} + +QModelIndex MessagesProxyModel::getNextUnreadItemIndex(int default_row, int max_row) { + while (default_row <= max_row) { + // Get info if the message is read or not. + QModelIndex proxy_index = index(default_row, 0); + + bool is_read = m_sourceModel->data(mapToSource(proxy_index).row(), + MSG_DB_READ_INDEX, Qt::EditRole).toInt() == 1; + + if (!is_read) { + // We found unread message, mark it. + return proxy_index; + } + else { + default_row++; + } + } + + return QModelIndex(); +} + bool MessagesProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { if (left.column() == MSG_DB_TITLE_INDEX && right.column() == MSG_DB_TITLE_INDEX) { return QString::localeAwareCompare(m_sourceModel->data(left).toString(), diff --git a/src/core/messagesproxymodel.h b/src/core/messagesproxymodel.h index 2b81ea652..1bb2faaa1 100755 --- a/src/core/messagesproxymodel.h +++ b/src/core/messagesproxymodel.h @@ -36,6 +36,8 @@ class MessagesProxyModel : public QSortFilterProxyModel { return m_sourceModel; } + QModelIndex getNextPreviousUnreadItemIndex(int default_row); + // Maps list of indexes. QModelIndexList mapListToSource(const QModelIndexList &indexes); QModelIndexList mapListFromSource(const QModelIndexList &indexes, bool deep = false); @@ -44,6 +46,8 @@ class MessagesProxyModel : public QSortFilterProxyModel { QModelIndexList match(const QModelIndex &start, int role, const QVariant &entered_value, int hits, Qt::MatchFlags flags) const; private: + QModelIndex getNextUnreadItemIndex(int default_row, int max_row); + // Compares two rows of data. bool lessThan(const QModelIndex &left, const QModelIndex &right) const; diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index 349794e44..226f0c638 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -135,6 +135,7 @@ QList FormMain::allActions() { actions << m_ui->m_actionSelectPreviousItem; actions << m_ui->m_actionSelectNextMessage; actions << m_ui->m_actionSelectPreviousMessage; + actions << m_ui->m_actionSelectNextUnreadMessage; actions << m_ui->m_actionExpandCollapseItem; return actions; @@ -361,6 +362,7 @@ void FormMain::setupIcons() { m_ui->m_actionSelectPreviousItem->setIcon(icon_theme_factory->fromTheme(QSL("go-up"))); m_ui->m_actionSelectNextMessage->setIcon(icon_theme_factory->fromTheme(QSL("go-down"))); m_ui->m_actionSelectPreviousMessage->setIcon(icon_theme_factory->fromTheme(QSL("go-up"))); + m_ui->m_actionSelectNextUnreadMessage->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-unread"))); m_ui->m_actionShowOnlyUnreadItems->setIcon(icon_theme_factory->fromTheme(QSL("mail-mark-unread"))); m_ui->m_actionExpandCollapseItem->setIcon(icon_theme_factory->fromTheme(QSL("expand-collapse"))); m_ui->m_actionRestoreSelectedMessages->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-restore-one"))); diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index 8a15ea446..fe4f645ce 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -125,7 +125,7 @@ - Fee&ds && categories + Feeds && categories && accounts @@ -165,6 +165,7 @@ + @@ -174,7 +175,7 @@ - &Recycle bin + &Recycle bin(s) @@ -729,6 +730,17 @@ &Empty all recycle bins + + + + + + + Select next &unread message + + + + diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index cbe2d9fac..69a978993 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -304,6 +304,8 @@ void FeedMessageViewer::createConnections() { SIGNAL(triggered()), m_feedsView, SLOT(selectPreviousItem())); connect(form_main->m_ui->m_actionSelectNextMessage, SIGNAL(triggered()), m_messagesView, SLOT(selectNextItem())); + connect(form_main->m_ui->m_actionSelectNextUnreadMessage, + SIGNAL(triggered()), m_messagesView, SLOT(selectNextUnreadItem())); connect(form_main->m_ui->m_actionSelectPreviousMessage, SIGNAL(triggered()), m_messagesView, SLOT(selectPreviousItem())); connect(form_main->m_ui->m_actionSwitchMessageListOrientation, SIGNAL(triggered()), diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index f750ff432..8c67483d8 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -98,16 +98,6 @@ RootItem *FeedsView::selectedItem() const { } } -Category *FeedsView::selectedCategory() const { - QModelIndex current_mapped = m_proxyModel->mapToSource(currentIndex()); - return m_sourceModel->categoryForIndex(current_mapped); -} - -Feed *FeedsView::selectedFeed() const { - QModelIndex current_mapped = m_proxyModel->mapToSource(currentIndex()); - return m_sourceModel->feedForIndex(current_mapped); -} - void FeedsView::saveExpandedStates() { Settings *settings = qApp->settings(); QList expandable_items; diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index 0f85374d4..05f9f8a31 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -56,8 +56,6 @@ class FeedsView : public QTreeView { // Returns pointers to selected feed/category if they are really // selected. RootItem *selectedItem() const; - Category *selectedCategory() const; - Feed *selectedFeed() const; // Saves/loads expand states of all nodes (feeds/categories) of the list to/from settings. void saveExpandedStates(); diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index c52d68104..95b493ef8 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -481,20 +481,13 @@ void MessagesView::selectNextUnreadItem() { active_row = 0; } - while (++active_row < m_proxyModel->rowCount()) { - // Get info if the message is read or not. - QModelIndex proxy_index = m_proxyModel->index(active_row, 0); + QModelIndex next_unread = m_proxyModel->getNextPreviousUnreadItemIndex(active_row); - bool is_read = m_sourceModel->data(m_proxyModel->mapToSource(proxy_index).row(), - MSG_DB_READ_INDEX, Qt::EditRole).toInt() == 1; - - if (!is_read) { - // We found unread message, mark it. - setCurrentIndex(proxy_index); - selectionModel()->select(proxy_index, QItemSelectionModel::Select | QItemSelectionModel::Rows); - setFocus(); - break; - } + if (next_unread.isValid()) { + // We found unread message, mark it. + setCurrentIndex(next_unread); + selectionModel()->select(next_unread, QItemSelectionModel::Select | QItemSelectionModel::Rows); + setFocus(); } } From c9953e10d08c7285da6eba60f9187db9e1bf34cc Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 29 Nov 2015 14:30:26 +0100 Subject: [PATCH 081/203] Added initial schema 4 updates. --- resources/misc/db_init_mysql.sql | 2 ++ resources/misc/db_init_sqlite.sql | 2 ++ resources/misc/db_update_mysql_3_4.sql | 1 + resources/misc/db_update_sqlite_3_4.sql | 1 + src/definitions/definitions.h.in | 2 +- 5 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 resources/misc/db_update_mysql_3_4.sql create mode 100644 resources/misc/db_update_sqlite_3_4.sql diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index fda045d7c..8e7b1e8d6 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -14,6 +14,8 @@ CREATE TABLE IF NOT EXISTS Information ( -- ! INSERT INTO Information VALUES (1, 'schema_version', '3'); -- ! +INSERT INTO Information VALUES (1, 'standard_account_enabled', 1); +-- ! DROP TABLE IF EXISTS Categories; -- ! CREATE TABLE IF NOT EXISTS Categories ( diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index d02ba1a99..103e48a3a 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -8,6 +8,8 @@ CREATE TABLE IF NOT EXISTS Information ( -- ! INSERT INTO Information VALUES (1, 'schema_version', '3'); -- ! +INSERT INTO Information VALUES (1, 'standard_account_enabled', 1); +-- ! DROP TABLE IF EXISTS Categories; -- ! CREATE TABLE IF NOT EXISTS Categories ( diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql new file mode 100644 index 000000000..b2a62febd --- /dev/null +++ b/resources/misc/db_update_mysql_3_4.sql @@ -0,0 +1 @@ +INSERT INTO Information VALUES (1, 'standard_account_enabled', 1); \ No newline at end of file diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql new file mode 100644 index 000000000..b2a62febd --- /dev/null +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -0,0 +1 @@ +INSERT INTO Information VALUES (1, 'standard_account_enabled', 1); \ No newline at end of file diff --git a/src/definitions/definitions.h.in b/src/definitions/definitions.h.in index a4712f8e4..c2249bbed 100755 --- a/src/definitions/definitions.h.in +++ b/src/definitions/definitions.h.in @@ -117,7 +117,7 @@ #define APP_DB_SQLITE_FILE "database.db" // Keep this in sync with schema versions declared in SQL initialization code. -#define APP_DB_SCHEMA_VERSION "3" +#define APP_DB_SCHEMA_VERSION "4" #define APP_DB_UPDATE_FILE_PATTERN "db_update_%1_%2_%3.sql" #define APP_DB_COMMENT_SPLIT "-- !\n" #define APP_DB_WEB_PATH "data/database/web" From 165fb68eff59917fbb8eac3afe43685685c45367 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 29 Nov 2015 14:33:53 +0100 Subject: [PATCH 082/203] Added initial schema 4 updates - fix. --- resources/misc/db_init_mysql.sql | 2 +- resources/misc/db_init_sqlite.sql | 2 +- resources/misc/db_update_mysql_3_4.sql | 2 +- resources/misc/db_update_sqlite_3_4.sql | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index 8e7b1e8d6..4f4ec7dc1 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -14,7 +14,7 @@ CREATE TABLE IF NOT EXISTS Information ( -- ! INSERT INTO Information VALUES (1, 'schema_version', '3'); -- ! -INSERT INTO Information VALUES (1, 'standard_account_enabled', 1); +INSERT INTO Information (inf_key, inf_value) VALUES ('standard_account_enabled', 1); -- ! DROP TABLE IF EXISTS Categories; -- ! diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index 103e48a3a..99e4b1363 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -8,7 +8,7 @@ CREATE TABLE IF NOT EXISTS Information ( -- ! INSERT INTO Information VALUES (1, 'schema_version', '3'); -- ! -INSERT INTO Information VALUES (1, 'standard_account_enabled', 1); +INSERT INTO Information (inf_key, inf_value) VALUES ('standard_account_enabled', 1); -- ! DROP TABLE IF EXISTS Categories; -- ! diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index b2a62febd..02b7e6fa6 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -1 +1 @@ -INSERT INTO Information VALUES (1, 'standard_account_enabled', 1); \ No newline at end of file +INSERT INTO Information (inf_key, inf_value) VALUES ('standard_account_enabled', 1); \ No newline at end of file diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql index b2a62febd..02b7e6fa6 100644 --- a/resources/misc/db_update_sqlite_3_4.sql +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -1 +1 @@ -INSERT INTO Information VALUES (1, 'standard_account_enabled', 1); \ No newline at end of file +INSERT INTO Information (inf_key, inf_value) VALUES ('standard_account_enabled', 1); \ No newline at end of file From e0c9b95d7eae4cc39cde161b4c28e504b73557e1 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 29 Nov 2015 14:35:10 +0100 Subject: [PATCH 083/203] Update schema value. --- resources/misc/db_update_mysql_3_4.sql | 4 +++- resources/misc/db_update_sqlite_3_4.sql | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index 02b7e6fa6..57a4a30bc 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -1 +1,3 @@ -INSERT INTO Information (inf_key, inf_value) VALUES ('standard_account_enabled', 1); \ No newline at end of file +INSERT INTO Information (inf_key, inf_value) VALUES ('standard_account_enabled', 1); +-- ! +UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql index 02b7e6fa6..57a4a30bc 100644 --- a/resources/misc/db_update_sqlite_3_4.sql +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -1 +1,3 @@ -INSERT INTO Information (inf_key, inf_value) VALUES ('standard_account_enabled', 1); \ No newline at end of file +INSERT INTO Information (inf_key, inf_value) VALUES ('standard_account_enabled', 1); +-- ! +UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file From fa51e52bb25a73c4c4647729ce0fb523ecb6572f Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 29 Nov 2015 14:52:33 +0100 Subject: [PATCH 084/203] Added some files. --- CMakeLists.txt | 3 +- src/gui/dialogs/formaddaccount.cpp | 41 ++++++++++++++++++ src/gui/dialogs/formaddaccount.h | 41 ++++++++++++++++++ src/gui/dialogs/formaddaccount.ui | 68 ++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 src/gui/dialogs/formaddaccount.cpp create mode 100644 src/gui/dialogs/formaddaccount.h create mode 100644 src/gui/dialogs/formaddaccount.ui diff --git a/CMakeLists.txt b/CMakeLists.txt index 2778f9960..c43ae11d6 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -351,6 +351,7 @@ set(APP_SOURCES src/gui/dialogs/formdatabasecleanup.cpp src/gui/dialogs/formbackupdatabasesettings.cpp src/gui/dialogs/formrestoredatabasesettings.cpp + src/gui/dialogs/formaddaccount.cpp src/gui/notifications/notification.cpp src/gui/systemtrayicon.cpp src/gui/baselineedit.cpp @@ -481,6 +482,7 @@ set(APP_HEADERS src/gui/dialogs/formrestoredatabasesettings.h src/gui/dialogs/formdatabasecleanup.h src/gui/dialogs/formupdate.h + src/gui/dialogs/formaddaccount.h src/gui/notifications/notification.h src/gui/systemtrayicon.h src/gui/baselineedit.h @@ -582,7 +584,6 @@ set(APP_FORMS src/gui/dialogs/formbackupdatabasesettings.ui src/gui/dialogs/formrestoredatabasesettings.ui src/gui/dialogs/formdatabasecleanup.ui - src/gui/toolbareditor.ui # STANDARD service forms. diff --git a/src/gui/dialogs/formaddaccount.cpp b/src/gui/dialogs/formaddaccount.cpp new file mode 100644 index 000000000..4719204ab --- /dev/null +++ b/src/gui/dialogs/formaddaccount.cpp @@ -0,0 +1,41 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#include "gui/dialogs/formaddaccount.h" + +#include "miscellaneous/application.h" + +#if defined(Q_OS_OS2) +#include "gui/messagebox.h" +#endif + + +FormAddAccount::FormAddAccount(QWidget *parent) : QDialog(parent), m_ui(new Ui::FormAddAccount) { + m_ui->setupUi(this); + + // Set flags and attributes. + setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint); + setWindowIcon(qApp->icons()->fromTheme(QSL("application-about"))); + +#if defined(Q_OS_OS2) + MessageBox::iconify(m_ui->m_buttonBox); +#endif +} + +FormAddAccount::~FormAddAccount() { + delete m_ui; +} diff --git a/src/gui/dialogs/formaddaccount.h b/src/gui/dialogs/formaddaccount.h new file mode 100644 index 000000000..13719a406 --- /dev/null +++ b/src/gui/dialogs/formaddaccount.h @@ -0,0 +1,41 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#ifndef FORMADDACCOUNT_H +#define FORMADDACCOUNT_H + +#include + +#include "ui_formaddaccount.h" + + +namespace Ui { + class FormAddAccount; +} + +class FormAddAccount : public QDialog { + Q_OBJECT + + public: + explicit FormAddAccount(QWidget *parent = 0); + virtual ~FormAddAccount(); + + private: + Ui::FormAddAccount *m_ui; +}; + +#endif // FORMADDACCOUNT_H diff --git a/src/gui/dialogs/formaddaccount.ui b/src/gui/dialogs/formaddaccount.ui new file mode 100644 index 000000000..9b5bf3ce5 --- /dev/null +++ b/src/gui/dialogs/formaddaccount.ui @@ -0,0 +1,68 @@ + + + FormAddAccount + + + + 0 + 0 + 400 + 300 + + + + Add new account + + + + + 30 + 240 + 341 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + buttonBox + accepted() + FormAddAccount + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + FormAddAccount + reject() + + + 316 + 260 + + + 286 + 274 + + + + + From fb55703e5b7c52949b1425f7fd8fcde1b36743a9 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 29 Nov 2015 14:58:07 +0100 Subject: [PATCH 085/203] Add icons. --- src/gui/dialogs/formaddaccount.cpp | 3 ++- src/gui/dialogs/formmain.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/dialogs/formaddaccount.cpp b/src/gui/dialogs/formaddaccount.cpp index 4719204ab..507da4378 100644 --- a/src/gui/dialogs/formaddaccount.cpp +++ b/src/gui/dialogs/formaddaccount.cpp @@ -18,6 +18,7 @@ #include "gui/dialogs/formaddaccount.h" #include "miscellaneous/application.h" +#include "miscellaneous/iconfactory.h" #if defined(Q_OS_OS2) #include "gui/messagebox.h" @@ -29,7 +30,7 @@ FormAddAccount::FormAddAccount(QWidget *parent) : QDialog(parent), m_ui(new Ui:: // Set flags and attributes. setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint); - setWindowIcon(qApp->icons()->fromTheme(QSL("application-about"))); + setWindowIcon(qApp->icons()->fromTheme(QSL("item-new"))); #if defined(Q_OS_OS2) MessageBox::iconify(m_ui->m_buttonBox); diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index 226f0c638..47643dab2 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -368,7 +368,7 @@ void FormMain::setupIcons() { m_ui->m_actionRestoreSelectedMessages->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-restore-one"))); m_ui->m_actionRestoreAllRecycleBins->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-restore-all"))); m_ui->m_actionEmptyAllRecycleBins->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-empty"))); - + m_ui->m_actionServiceAdd->setIcon(icon_theme_factory->fromTheme(QSL("item-add"))); // Setup icons for underlying components: opened web browsers... foreach (WebBrowser *browser, WebBrowser::runningWebBrowsers()) { From f7b818cae30b0930f95be6432feecfc7601adb9f Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 29 Nov 2015 18:50:28 +0100 Subject: [PATCH 086/203] Added UI file. --- CMakeLists.txt | 1 + src/gui/dialogs/formmain.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c43ae11d6..816219b93 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -584,6 +584,7 @@ set(APP_FORMS src/gui/dialogs/formbackupdatabasesettings.ui src/gui/dialogs/formrestoredatabasesettings.ui src/gui/dialogs/formdatabasecleanup.ui + src/gui/dialogs/formaddaccount.ui src/gui/toolbareditor.ui # STANDARD service forms. diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index 47643dab2..b49904f00 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -368,7 +368,7 @@ void FormMain::setupIcons() { m_ui->m_actionRestoreSelectedMessages->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-restore-one"))); m_ui->m_actionRestoreAllRecycleBins->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-restore-all"))); m_ui->m_actionEmptyAllRecycleBins->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-empty"))); - m_ui->m_actionServiceAdd->setIcon(icon_theme_factory->fromTheme(QSL("item-add"))); + m_ui->m_actionServiceAdd->setIcon(icon_theme_factory->fromTheme(QSL("item-new"))); // Setup icons for underlying components: opened web browsers... foreach (WebBrowser *browser, WebBrowser::runningWebBrowsers()) { From 1178787bc11557863925c707169f5ebc4134a955 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 29 Nov 2015 20:27:52 +0100 Subject: [PATCH 087/203] Last edits today. --- src/services/standard/standardserviceroot.cpp | 32 ++++++++++++++++++- src/services/standard/standardserviceroot.h | 2 ++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 94a6e6ba0..1af194217 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -106,7 +106,37 @@ bool StandardServiceRoot::canBeEdited() { } bool StandardServiceRoot::canBeDeleted() { - return false; + return true; +} + +bool StandardServiceRoot::deleteViaGui() { + QSqlDatabase connection = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + + // Remove all messages. + if (!QSqlQuery(connection).exec(QSL("DELETE FROM Messages;"))) { + return false; + } + + // Remove all feeds. + if (!QSqlQuery(connection).exec(QSL("DELETE FROM Feeds;"))) { + return false; + } + + // Remove all categories. + if (!QSqlQuery(connection).exec(QSL("DELETE FROM Categories;"))) { + return false; + } + + // Switch "existence" flag. + bool data_removed = QSqlQuery(connection).exec(QSL("UPDATE Information SET inf_value = 0 WHERE inf_key = 'standard_account_enabled';")); + + // TODO: pokračovat + + if (data_removed) { + feedsModel()->removeItem(this); + } + + return data_removed; } QVariant StandardServiceRoot::data(int column, int role) const { diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index dd1572ff6..2cf81b1ba 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -49,6 +49,8 @@ class StandardServiceRoot : public ServiceRoot { bool canBeEdited(); bool canBeDeleted(); + bool deleteViaGui(); + QVariant data(int column, int role) const; Qt::ItemFlags additionalFlags() const; From 2dc6e51e4b97e03d1b1457528d029d21a0383400 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 30 Nov 2015 06:23:06 +0100 Subject: [PATCH 088/203] OS/2 fix. --- src/gui/dialogs/formaddaccount.ui | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) mode change 100644 => 100755 src/gui/dialogs/formaddaccount.ui diff --git a/src/gui/dialogs/formaddaccount.ui b/src/gui/dialogs/formaddaccount.ui old mode 100644 new mode 100755 index 9b5bf3ce5..46afe126a --- a/src/gui/dialogs/formaddaccount.ui +++ b/src/gui/dialogs/formaddaccount.ui @@ -13,7 +13,7 @@ Add new account - + 30 @@ -33,7 +33,7 @@ - buttonBox + m_buttonBox accepted() FormAddAccount accept() @@ -49,7 +49,7 @@ - buttonBox + m_buttonBox rejected() FormAddAccount reject() From 3812e41d7bc24fa5c8330ac9045142f7a6c4a160 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 30 Nov 2015 07:10:58 +0100 Subject: [PATCH 089/203] Fix displaying of unread root when loading app. --- src/core/feedsproxymodel.cpp | 2 +- src/gui/dialogs/formaddaccount.cpp | 5 ++- src/gui/dialogs/formaddaccount.h | 7 ++- src/gui/dialogs/formaddaccount.ui | 69 ++++++++++++++++-------------- src/gui/dialogs/formmain.cpp | 10 +++++ src/gui/dialogs/formmain.h | 1 + src/gui/messagesview.cpp | 4 +- 7 files changed, 60 insertions(+), 38 deletions(-) mode change 100644 => 100755 src/gui/dialogs/formaddaccount.cpp mode change 100644 => 100755 src/gui/dialogs/formaddaccount.h diff --git a/src/core/feedsproxymodel.cpp b/src/core/feedsproxymodel.cpp index ba83fb4f6..445bd71c3 100755 --- a/src/core/feedsproxymodel.cpp +++ b/src/core/feedsproxymodel.cpp @@ -197,7 +197,7 @@ bool FeedsProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source RootItem *item = m_sourceModel->itemForIndex(idx); - if (item->kind() == RootItemKind::Bin) { + if (item->kind() == RootItemKind::Bin || item->kind() == RootItemKind::ServiceRoot) { // Recycle bin is always displayed. return true; } diff --git a/src/gui/dialogs/formaddaccount.cpp b/src/gui/dialogs/formaddaccount.cpp old mode 100644 new mode 100755 index 507da4378..243425d71 --- a/src/gui/dialogs/formaddaccount.cpp +++ b/src/gui/dialogs/formaddaccount.cpp @@ -19,13 +19,16 @@ #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" +#include "core/feedsmodel.h" + #if defined(Q_OS_OS2) #include "gui/messagebox.h" #endif -FormAddAccount::FormAddAccount(QWidget *parent) : QDialog(parent), m_ui(new Ui::FormAddAccount) { +FormAddAccount::FormAddAccount(const QList &entry_points, FeedsModel *model, QWidget *parent) + : QDialog(parent), m_ui(new Ui::FormAddAccount), m_model(model), m_entryPoints(entry_points) { m_ui->setupUi(this); // Set flags and attributes. diff --git a/src/gui/dialogs/formaddaccount.h b/src/gui/dialogs/formaddaccount.h old mode 100644 new mode 100755 index 13719a406..2aaee06dd --- a/src/gui/dialogs/formaddaccount.h +++ b/src/gui/dialogs/formaddaccount.h @@ -27,15 +27,20 @@ namespace Ui { class FormAddAccount; } +class ServiceEntryPoint; +class FeedsModel; + class FormAddAccount : public QDialog { Q_OBJECT public: - explicit FormAddAccount(QWidget *parent = 0); + explicit FormAddAccount(const QList &entry_points, FeedsModel *model, QWidget *parent = 0); virtual ~FormAddAccount(); private: Ui::FormAddAccount *m_ui; + FeedsModel *m_model; + QList m_entryPoints; }; #endif // FORMADDACCOUNT_H diff --git a/src/gui/dialogs/formaddaccount.ui b/src/gui/dialogs/formaddaccount.ui index 46afe126a..266532bd8 100755 --- a/src/gui/dialogs/formaddaccount.ui +++ b/src/gui/dialogs/formaddaccount.ui @@ -6,48 +6,51 @@ 0 0 - 400 + 558 300 Add new account - - - - 30 - 240 - 341 - 32 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - + + + + + + 0 + 1 + + + + + + + + + 0 + 1 + + + + Details + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + - - m_buttonBox - accepted() - FormAddAccount - accept() - - - 248 - 254 - - - 157 - 274 - - - m_buttonBox rejected() diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index b49904f00..278a791c8 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -38,6 +38,7 @@ #include "gui/dialogs/formupdate.h" #include "gui/dialogs/formbackupdatabasesettings.h" #include "gui/dialogs/formrestoredatabasesettings.h" +#include "gui/dialogs/formaddaccount.h" #include "gui/notifications/notification.h" #include "services/abstract/serviceroot.h" #include "services/abstract/recyclebin.h" @@ -447,6 +448,7 @@ void FormMain::createConnections() { connect(m_ui->m_actionRestoreDatabaseSettings, SIGNAL(triggered()), this, SLOT(restoreDatabaseSettings())); connect(m_ui->m_actionRestart, SIGNAL(triggered()), qApp, SLOT(restart())); connect(m_ui->m_actionQuit, SIGNAL(triggered()), qApp, SLOT(quit())); + connect(m_ui->m_actionServiceAdd, SIGNAL(triggered()), this, SLOT(showAddAccountDialog())); // Menu "View" connections. connect(m_ui->m_actionFullscreen, SIGNAL(toggled(bool)), this, SLOT(switchFullscreenMode())); @@ -551,6 +553,14 @@ void FormMain::showWiki() { } } +void FormMain::showAddAccountDialog() { + QPointer form_update = new FormAddAccount(qApp->feedServices(), + tabWidget()->feedMessageViewer()->feedsView()->sourceModel(), + this); + form_update.data()->exec(); + delete form_update.data(); +} + void FormMain::reportABugOnGitHub() { if (!WebFactory::instance()->openUrlInExternalBrowser(APP_URL_ISSUES_NEW_GITHUB)) { qApp->showGuiMessage(tr("Cannot open external browser"), diff --git a/src/gui/dialogs/formmain.h b/src/gui/dialogs/formmain.h index bf17615d3..1320a832f 100755 --- a/src/gui/dialogs/formmain.h +++ b/src/gui/dialogs/formmain.h @@ -90,6 +90,7 @@ class FormMain : public QMainWindow { void showAbout(); void showUpdates(); void showWiki(); + void showAddAccountDialog(); void reportABugOnGitHub(); void reportABugOnBitBucket(); void donate(); diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index 95b493ef8..93ab54a92 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -481,12 +481,12 @@ void MessagesView::selectNextUnreadItem() { active_row = 0; } - QModelIndex next_unread = m_proxyModel->getNextPreviousUnreadItemIndex(active_row); + QModelIndex next_unread = moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier); if (next_unread.isValid()) { // We found unread message, mark it. setCurrentIndex(next_unread); - selectionModel()->select(next_unread, QItemSelectionModel::Select | QItemSelectionModel::Rows); + selectionModel()->select(next_unread, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); setFocus(); } } From b9e2f19beef9f67d48daa82860741657b4a0e038 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 30 Nov 2015 07:13:29 +0100 Subject: [PATCH 090/203] Fix bug in select-next-unread-message feature. --- src/core/messagesproxymodel.cpp | 3 +-- src/gui/messagesview.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/messagesproxymodel.cpp b/src/core/messagesproxymodel.cpp index 992cc49fe..9be27cfaa 100755 --- a/src/core/messagesproxymodel.cpp +++ b/src/core/messagesproxymodel.cpp @@ -53,8 +53,7 @@ QModelIndex MessagesProxyModel::getNextPreviousUnreadItemIndex(int default_row) QModelIndex MessagesProxyModel::getNextUnreadItemIndex(int default_row, int max_row) { while (default_row <= max_row) { // Get info if the message is read or not. - QModelIndex proxy_index = index(default_row, 0); - + QModelIndex proxy_index = index(default_row, MSG_DB_READ_INDEX); bool is_read = m_sourceModel->data(mapToSource(proxy_index).row(), MSG_DB_READ_INDEX, Qt::EditRole).toInt() == 1; diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index 93ab54a92..17aad6651 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -481,7 +481,7 @@ void MessagesView::selectNextUnreadItem() { active_row = 0; } - QModelIndex next_unread = moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier); + QModelIndex next_unread = m_proxyModel->getNextPreviousUnreadItemIndex(active_row); if (next_unread.isValid()) { // We found unread message, mark it. From 01e595d7cd2229af754a4a9ff018b7e15c94e2ef Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 30 Nov 2015 07:47:09 +0100 Subject: [PATCH 091/203] Added TT-RSS icons. --- .../icons/mini-kfaenza/application-ttrss.png | Bin 0 -> 6140 bytes .../icons/numix/application-ttrss.png | Bin 0 -> 6140 bytes src/gui/dialogs/formaddaccount.cpp | 20 ++++++++++++++++++ src/gui/dialogs/formaddaccount.h | 5 +++++ 4 files changed, 25 insertions(+) create mode 100755 resources/graphics/icons/mini-kfaenza/application-ttrss.png create mode 100755 resources/graphics/icons/numix/application-ttrss.png diff --git a/resources/graphics/icons/mini-kfaenza/application-ttrss.png b/resources/graphics/icons/mini-kfaenza/application-ttrss.png new file mode 100755 index 0000000000000000000000000000000000000000..15c2ac4d4eb07b7edac4785ad5bb4e41a2edfa1a GIT binary patch literal 6140 zcmVtP)vaY^+x_f%2HCN9)qd9tXfu)gT zLV&dkh~-*q5oiq#u)NqCLe`>nY=jU-uwV%rjKP4-YK>*D1PCL9P76sR%}AO{bD!OF z^f}WFg-T zvOugLUdfeGKI@(D9~8GVQ0zT<)EhdpZ+zd&`-&$I9xCqc2_= zL`0#m5P^se{0{n3x}7!kfcT#0XGgTojv7+R0*F{~1Z*`#S{F5t;+4+w4cD=<02r8D zHtUTH94Z{$w{7&5Up|{Vx@$-N@UDK*z6s@0#0)XU1Q-$=1c3;|A;9PmWh%lFF`|ju z_GqGRWxS@PD>rg>duFKn84Atpk|`hnL8VApAf*B$1OyO>TNEJ(3VG2KuC!&P?4|`> z(fP}|>VNw~|HZh4(cJzWFJyK+^OND{AAKT!e1ETKUB0vxJiHhL%Ult}jwKsosfJD` z)wJ13HExb3>efV@^fFdflGwu0mydl6m%s@Q z5V2L8Saa3Q=}p((+;-dN$Hw=)^7!CSzxTt@ozFk%5B2$>u<3}CUgo5m*2ZgFx5VN# z8zW9?nH_cN0fOiI@LU%n8b*t8bHhW0?D_41iN3vPYt0Vz6UwLvTrE5(L{K6y5rH_| z6P?Q#JuV<+)uc9F|IwNa*L`&SiU0HZ@S}gT&575ojwNbWS&>)^5kqT@lIvnTUxb&* z2@~nM+7w!wYkBD0sA0>tirMpr#rS7Hgtt4|ShK(pWQr9~xL>vMK@g!(8C3P(N-2Oq z#)$S@Q+V#@WS)3zQ$zdeO>VJ>T%iazlLHg!M8c7l#yVPd*-Bouyn|LOU1+W8?7*)5 z$8g6z-;{=iIC3L>uL5vG%rKW&0Wy8HtA($u{6r9?>H}1D4l_YS$(bI&wvAiNn}(Vs zEn2&TS1wyfYnNZ9mM>|?g0^NjvB;#S`2Iis650rh(I{jFw+Bxqmp%&2B>W_^r&(8i zvhW0e6(pAd4fLYm8@_ziLjJ+m{wvbS__X^OBQRnr>fOEXxWr;nD&;dH#qr@im%{%6 zfM*we8W2tq9uxc1gb#hyjz9)_fy^jMT5#3Il}IP!@O%xe4YUq8lZb$sz|2sJ(LXed z6Q_EO<2cBT4IVJs>#5T8rB^@zGy*bOMEhEd_Mx>eM*9eSP$seHsltZ`St*!PCm^m1 z+qTfPzB3S(2ucOQGEXR3Le8}JU^hla$6;F*@?!(90w{$bE0^8{SP?}XknbvXk|1Uk z(Eh*+javkKA7ZqK5e;Ud;15-l7w(Af!JIk?&lof|)M3r?MIa(D&;3xZzi|X2U=fY{ z*uaiZtJOd>6K=^{Qh*p^03f&Td%QBt|cy0(#G~o@(f{bT?fwL%TVDsYnXsAm;L?(sR$>{_`1lYOnm_(fz z6*I%<@}qs*!mLYQVk#T}jLwc`a|d?p0)YI%SEoN@EDpP|wcc5{d}U(w6<5@D-Ec#+ zwc{#gt4;tRfJ6jv9O&+2z<36p0A1@lD`2M-&ER!`V)_P$apF`zq72csO-L-eyxl!@ zGz(^hsT4TSIf*f@@8&aaUp;`Brm>!Y4MU8cmX$5N_SUDIn&ul}e9g>C%2?pKVC^H5 zE8vF@d>+?qUIlFo)C@kLwSiKMXI|WePu=wZ(n$x#j)E-PH{+Qx5UBdD+8Bs2+KM>V zxt`rW>N~RSvu`F(ux45c5iN5hZGmQ(6#&?gcvA%Sm69Dpp;%(i^CwPahNlgh8fvj- zc}K`F=SK7Aw(Y_Bkt_g$?_~ud7L?U6)x{I>7+6^#BIHJTkG_pOAfUDtBaj&zrPMn zGy)?+Gl3fc*!KDX8P65TlyZgq*ue7>PW;xHpukMK6oHw8jEF?Ugp@>(ZtA!xNZ&>7 z`}}R_Ts(hna{ABf)9Ez6z|#_YtUgDiLX0 z)GAt+NU5UEj%MA#GesCP)h~pV9ZjU0x8@54EbeIK%NERo)~1>(m16_=Lb0#R2*c9j zOuEwAfEDApZF?{)^xlKrGUhuiE|Lx&Vy}HrQjuZoTxcI(=bs@)_ zR{Bx|luEF#z8<_`%cT6DA~E3lm(TnVN=NYiG`h=t)IU4zSCd*%;$)e3d-wmr5-Sg z@YTG8odhC{Z4;k{RzzA`z+)L0w*rHU&v?0Xoy!5<9QIzh4I~>#^8An?S)n$LHQBFZJ+qUH^_>xTqveqKmkD) zfRzFfV2p;*K8*1pFo8jot3N!^L$GW}HUk;#L&*T0i{_)gHU%?B7*rg@^*0WlFplF; zA#=XhSgLP)&r63+{`sA^t7M!_n0?ArOOlZM2p}M3iaDKJw(g4h_ulp&Ax0CidQ%D@ zB2W8%)+?2AMgUIMD3z|UIFYs}5@i@cP#S}&b``QM=>D@nb`+if8$$n|4Ufv9?s!ix zPM;l=SS*IzX#Z~GyFF}0?7>IA^-lwjJ@hpzU1J&F)2R4=84s$ygV;^t7G>T?|M)(Y zu1`oAU@pEQ6oilQy)V9S;MU8Ri_w-!q-&g|>lVd2mUqS%t=tk{yn3@Uf9Yb5z%m6F z#&b2XB8V^)L7xulf02ld&1;v<*?=!|mYr`L$9S%Ycru0jXy0}KMvNv9tM0FU_U^=r zja!}eB^z}qZvf_C-K)kFCIFJ*7Imz3;ev+ue&Y7QAARi`q*#fb8xW^O0aM78il+|u zg}bNohj;F)m~65plG?a+Q_YqeZ)w>2{`bY&+LlPkz!dTtzF~9f1bIf#(2&OJ3*`Uh z!>{c*EJ`V*-IB?V_P-LA=Y*I^=Q7^Oul&I$SA63auR_29Yzmc2fE8<~&{QUr^3r(o zC+{47{O`W+XU^x!ZU5O6pk_oSW&()8M8t~2;s=Ra^ou=*&Wvq){K@lA|Ks#j&%4CwF}bkZicJ zhLmNMdQbG(_48us4cA_)3t2qTdh0X-<{vT{dH2x!W>y5&sbqK zMi2}-7}35K9h8B?&M}ixmOFSR*Z&U>{O!JvcWvqU&X+$^IC1ba#xvrH$i_8GD)qma z{XaNSc)Orz*b{V>F2Q?Dy`yuh`$y!;u(^7&DXbGQpS0lyXvk z)2)BN@st%@gWd!Wm?dzF(MGiPK}4i1r3>S7<}dI5tATHP;ae&iCuY){)?LW|C*psh z=n@$p(G6ENQY31^m@8!jB_{Sq2J?Ln{m*+S>X2w(rU@^Tu|P^iaXOZ-ORj&%br6xc zc)^=b+(ksRufw)EJ1X`L*YnU&m!?YmpTqnCVEgXFP)f01%ImuK-@bMJC+@jj#F%ou z5dcIRA4EL#D@C#7V*im-h*}Jju4NOkrTw2TdCSqs_Vx0lq+6uP62_?D)4_}#As8V_aSB3Af{Nd@k)T8 zl+v5Z@gH;h|AC{Ykjoc?L5!vrsCbgS(J@oM^#i|`T-~))j0p;WLBwQImaVg+?zx}; z-M2ZOf@p1~3typ#5F!!nN&4z{e*ml?v#bbTKzM~fXsuFpc6`OACFw2KUmjnvsY9h| z$@pFoVkBADcBSWesH;t3Rp-L6#yB?#+kf;_z!H@LH@5`t6bx2H+J5)*e-ce+nR})W-Mt0TG%- z`0}@bF-UH{{>IS#F2VwsS&Y_AANs@F7T@{c57>2K#`AtS9!p_EU&QysWR;1;;;p{2 zp^ZjEU79YoLv!tw>+ruGc?Qf0;OT#c|H|_KE1+0lvv+U%OKi=TNu-sb3IR& zb(q=y%FJ%QE&&_(qFRB#KtXKNQe{=whI!1)YDGdX0=_F?SwX^ae= z$8g@IY{}KeFL?loSInPx3z-9<4=H!x)Nrx;;42)70Y;nZIc}*2Lx9BdU^ld^up3)j zgP1xQ2c}qn5JXJN$Nu;W5hofo`MgicvZgw4xeO*EKqN}AZ4d;b+5DUgu$l-F5$^wQ zx8q&cZo;!K?Z)7_Q5Xo)i8z)mYC|gFsQbV5Fi2Tc$PT_CMxPEymtxVr$-MsD)5&$$ zyxSii6H-)d_7lWNKro(BiF6{mpmU|$*WHI;Y*kNJ05OR%I?{SsZF=K%?-AFVOd+QT zANHt0@dOZ0!shcheRd!mf#HiJlfVtvT#g&AxqRAhPra}cW0^dfn&QZf^zH!Q1H@rs zBl&}`?J&Lv5LDUcWU}yOUSPnAxhgSm@)~g%58=fD}uxR&Ru~&PUpU`PtLk< z!^iZ8Kl3F#^}vMnI%WJ%9Jle9qYGHgoQc9WUw^pIgz`+}`-=?n7q#&I7V|VJod%)%TTO9u)lojTG@2%-_m z48lvLzyppYl6K?#w12K|n24x+nl%}e7$O?|58eO8x-DC8wwTJ&(j?)llMrK!C{`WtVOv#9d0TGLUsxUxA`x-=+N+ogf{?C27aAfxYhz3r+_Sp4_y0)8YT9$q| zQPXlwI#sh!DLYE62q1{jFohhz3}J#O3nmhQNhDCJt%o!=gIea3)!2&Iy!Mnz)TRIw zr#A`xVU*L~3ffM2u`M7+Mno9ePfu-CO>d5h(Zovi|KQ#)6Dw}N?XEA{5yiSt0*o&r zFc8CFi#Uv!GJ|L}wVJLt<90m$S=dY{OR^gaO~9dXi^DLb~nc2dm**mhl0 zL-R*IcaMfd5l;Y#BsiV|$CIF_1Gem763O>SJkNsBu}M9tu-Q=TIXG?#IgKFNXqhf~ zFx_gjVeJcm=*5i5K}2g9qk8}P3tt-F^TM;OzkBChsnuQATFF!$87MH|jhr9KY=7z( z{SSThE7?6S?w`_{CIr<@5s{2r$m~TSv$v2L1OUVwE4}QuwJX|_+Y-H+rGj{;Pm!v`vV<#D@*>v4Ih{y`x9imCpWrD_$5J`5|uU^o( z%tVbp{8p*jRC4Xr@2H-Om>dc#XEZmk^UG(_ZztZjE zhwy_jL9U9L=GPfSn0i}Me9tP)vaY^+x_f%2HCN9)qd9tXfu)gT zLV&dkh~-*q5oiq#u)NqCLe`>nY=jU-uwV%rjKP4-YK>*D1PCL9P76sR%}AO{bD!OF z^f}WFg-T zvOugLUdfeGKI@(D9~8GVQ0zT<)EhdpZ+zd&`-&$I9xCqc2_= zL`0#m5P^se{0{n3x}7!kfcT#0XGgTojv7+R0*F{~1Z*`#S{F5t;+4+w4cD=<02r8D zHtUTH94Z{$w{7&5Up|{Vx@$-N@UDK*z6s@0#0)XU1Q-$=1c3;|A;9PmWh%lFF`|ju z_GqGRWxS@PD>rg>duFKn84Atpk|`hnL8VApAf*B$1OyO>TNEJ(3VG2KuC!&P?4|`> z(fP}|>VNw~|HZh4(cJzWFJyK+^OND{AAKT!e1ETKUB0vxJiHhL%Ult}jwKsosfJD` z)wJ13HExb3>efV@^fFdflGwu0mydl6m%s@Q z5V2L8Saa3Q=}p((+;-dN$Hw=)^7!CSzxTt@ozFk%5B2$>u<3}CUgo5m*2ZgFx5VN# z8zW9?nH_cN0fOiI@LU%n8b*t8bHhW0?D_41iN3vPYt0Vz6UwLvTrE5(L{K6y5rH_| z6P?Q#JuV<+)uc9F|IwNa*L`&SiU0HZ@S}gT&575ojwNbWS&>)^5kqT@lIvnTUxb&* z2@~nM+7w!wYkBD0sA0>tirMpr#rS7Hgtt4|ShK(pWQr9~xL>vMK@g!(8C3P(N-2Oq z#)$S@Q+V#@WS)3zQ$zdeO>VJ>T%iazlLHg!M8c7l#yVPd*-Bouyn|LOU1+W8?7*)5 z$8g6z-;{=iIC3L>uL5vG%rKW&0Wy8HtA($u{6r9?>H}1D4l_YS$(bI&wvAiNn}(Vs zEn2&TS1wyfYnNZ9mM>|?g0^NjvB;#S`2Iis650rh(I{jFw+Bxqmp%&2B>W_^r&(8i zvhW0e6(pAd4fLYm8@_ziLjJ+m{wvbS__X^OBQRnr>fOEXxWr;nD&;dH#qr@im%{%6 zfM*we8W2tq9uxc1gb#hyjz9)_fy^jMT5#3Il}IP!@O%xe4YUq8lZb$sz|2sJ(LXed z6Q_EO<2cBT4IVJs>#5T8rB^@zGy*bOMEhEd_Mx>eM*9eSP$seHsltZ`St*!PCm^m1 z+qTfPzB3S(2ucOQGEXR3Le8}JU^hla$6;F*@?!(90w{$bE0^8{SP?}XknbvXk|1Uk z(Eh*+javkKA7ZqK5e;Ud;15-l7w(Af!JIk?&lof|)M3r?MIa(D&;3xZzi|X2U=fY{ z*uaiZtJOd>6K=^{Qh*p^03f&Td%QBt|cy0(#G~o@(f{bT?fwL%TVDsYnXsAm;L?(sR$>{_`1lYOnm_(fz z6*I%<@}qs*!mLYQVk#T}jLwc`a|d?p0)YI%SEoN@EDpP|wcc5{d}U(w6<5@D-Ec#+ zwc{#gt4;tRfJ6jv9O&+2z<36p0A1@lD`2M-&ER!`V)_P$apF`zq72csO-L-eyxl!@ zGz(^hsT4TSIf*f@@8&aaUp;`Brm>!Y4MU8cmX$5N_SUDIn&ul}e9g>C%2?pKVC^H5 zE8vF@d>+?qUIlFo)C@kLwSiKMXI|WePu=wZ(n$x#j)E-PH{+Qx5UBdD+8Bs2+KM>V zxt`rW>N~RSvu`F(ux45c5iN5hZGmQ(6#&?gcvA%Sm69Dpp;%(i^CwPahNlgh8fvj- zc}K`F=SK7Aw(Y_Bkt_g$?_~ud7L?U6)x{I>7+6^#BIHJTkG_pOAfUDtBaj&zrPMn zGy)?+Gl3fc*!KDX8P65TlyZgq*ue7>PW;xHpukMK6oHw8jEF?Ugp@>(ZtA!xNZ&>7 z`}}R_Ts(hna{ABf)9Ez6z|#_YtUgDiLX0 z)GAt+NU5UEj%MA#GesCP)h~pV9ZjU0x8@54EbeIK%NERo)~1>(m16_=Lb0#R2*c9j zOuEwAfEDApZF?{)^xlKrGUhuiE|Lx&Vy}HrQjuZoTxcI(=bs@)_ zR{Bx|luEF#z8<_`%cT6DA~E3lm(TnVN=NYiG`h=t)IU4zSCd*%;$)e3d-wmr5-Sg z@YTG8odhC{Z4;k{RzzA`z+)L0w*rHU&v?0Xoy!5<9QIzh4I~>#^8An?S)n$LHQBFZJ+qUH^_>xTqveqKmkD) zfRzFfV2p;*K8*1pFo8jot3N!^L$GW}HUk;#L&*T0i{_)gHU%?B7*rg@^*0WlFplF; zA#=XhSgLP)&r63+{`sA^t7M!_n0?ArOOlZM2p}M3iaDKJw(g4h_ulp&Ax0CidQ%D@ zB2W8%)+?2AMgUIMD3z|UIFYs}5@i@cP#S}&b``QM=>D@nb`+if8$$n|4Ufv9?s!ix zPM;l=SS*IzX#Z~GyFF}0?7>IA^-lwjJ@hpzU1J&F)2R4=84s$ygV;^t7G>T?|M)(Y zu1`oAU@pEQ6oilQy)V9S;MU8Ri_w-!q-&g|>lVd2mUqS%t=tk{yn3@Uf9Yb5z%m6F z#&b2XB8V^)L7xulf02ld&1;v<*?=!|mYr`L$9S%Ycru0jXy0}KMvNv9tM0FU_U^=r zja!}eB^z}qZvf_C-K)kFCIFJ*7Imz3;ev+ue&Y7QAARi`q*#fb8xW^O0aM78il+|u zg}bNohj;F)m~65plG?a+Q_YqeZ)w>2{`bY&+LlPkz!dTtzF~9f1bIf#(2&OJ3*`Uh z!>{c*EJ`V*-IB?V_P-LA=Y*I^=Q7^Oul&I$SA63auR_29Yzmc2fE8<~&{QUr^3r(o zC+{47{O`W+XU^x!ZU5O6pk_oSW&()8M8t~2;s=Ra^ou=*&Wvq){K@lA|Ks#j&%4CwF}bkZicJ zhLmNMdQbG(_48us4cA_)3t2qTdh0X-<{vT{dH2x!W>y5&sbqK zMi2}-7}35K9h8B?&M}ixmOFSR*Z&U>{O!JvcWvqU&X+$^IC1ba#xvrH$i_8GD)qma z{XaNSc)Orz*b{V>F2Q?Dy`yuh`$y!;u(^7&DXbGQpS0lyXvk z)2)BN@st%@gWd!Wm?dzF(MGiPK}4i1r3>S7<}dI5tATHP;ae&iCuY){)?LW|C*psh z=n@$p(G6ENQY31^m@8!jB_{Sq2J?Ln{m*+S>X2w(rU@^Tu|P^iaXOZ-ORj&%br6xc zc)^=b+(ksRufw)EJ1X`L*YnU&m!?YmpTqnCVEgXFP)f01%ImuK-@bMJC+@jj#F%ou z5dcIRA4EL#D@C#7V*im-h*}Jju4NOkrTw2TdCSqs_Vx0lq+6uP62_?D)4_}#As8V_aSB3Af{Nd@k)T8 zl+v5Z@gH;h|AC{Ykjoc?L5!vrsCbgS(J@oM^#i|`T-~))j0p;WLBwQImaVg+?zx}; z-M2ZOf@p1~3typ#5F!!nN&4z{e*ml?v#bbTKzM~fXsuFpc6`OACFw2KUmjnvsY9h| z$@pFoVkBADcBSWesH;t3Rp-L6#yB?#+kf;_z!H@LH@5`t6bx2H+J5)*e-ce+nR})W-Mt0TG%- z`0}@bF-UH{{>IS#F2VwsS&Y_AANs@F7T@{c57>2K#`AtS9!p_EU&QysWR;1;;;p{2 zp^ZjEU79YoLv!tw>+ruGc?Qf0;OT#c|H|_KE1+0lvv+U%OKi=TNu-sb3IR& zb(q=y%FJ%QE&&_(qFRB#KtXKNQe{=whI!1)YDGdX0=_F?SwX^ae= z$8g@IY{}KeFL?loSInPx3z-9<4=H!x)Nrx;;42)70Y;nZIc}*2Lx9BdU^ld^up3)j zgP1xQ2c}qn5JXJN$Nu;W5hofo`MgicvZgw4xeO*EKqN}AZ4d;b+5DUgu$l-F5$^wQ zx8q&cZo;!K?Z)7_Q5Xo)i8z)mYC|gFsQbV5Fi2Tc$PT_CMxPEymtxVr$-MsD)5&$$ zyxSii6H-)d_7lWNKro(BiF6{mpmU|$*WHI;Y*kNJ05OR%I?{SsZF=K%?-AFVOd+QT zANHt0@dOZ0!shcheRd!mf#HiJlfVtvT#g&AxqRAhPra}cW0^dfn&QZf^zH!Q1H@rs zBl&}`?J&Lv5LDUcWU}yOUSPnAxhgSm@)~g%58=fD}uxR&Ru~&PUpU`PtLk< z!^iZ8Kl3F#^}vMnI%WJ%9Jle9qYGHgoQc9WUw^pIgz`+}`-=?n7q#&I7V|VJod%)%TTO9u)lojTG@2%-_m z48lvLzyppYl6K?#w12K|n24x+nl%}e7$O?|58eO8x-DC8wwTJ&(j?)llMrK!C{`WtVOv#9d0TGLUsxUxA`x-=+N+ogf{?C27aAfxYhz3r+_Sp4_y0)8YT9$q| zQPXlwI#sh!DLYE62q1{jFohhz3}J#O3nmhQNhDCJt%o!=gIea3)!2&Iy!Mnz)TRIw zr#A`xVU*L~3ffM2u`M7+Mno9ePfu-CO>d5h(Zovi|KQ#)6Dw}N?XEA{5yiSt0*o&r zFc8CFi#Uv!GJ|L}wVJLt<90m$S=dY{OR^gaO~9dXi^DLb~nc2dm**mhl0 zL-R*IcaMfd5l;Y#BsiV|$CIF_1Gem763O>SJkNsBu}M9tu-Q=TIXG?#IgKFNXqhf~ zFx_gjVeJcm=*5i5K}2g9qk8}P3tt-F^TM;OzkBChsnuQATFF!$87MH|jhr9KY=7z( z{SSThE7?6S?w`_{CIr<@5s{2r$m~TSv$v2L1OUVwE4}QuwJX|_+Y-H+rGj{;Pm!v`vV<#D@*>v4Ih{y`x9imCpWrD_$5J`5|uU^o( z%tVbp{8p*jRC4Xr@2H-Om>dc#XEZmk^UG(_ZztZjE zhwy_jL9U9L=GPfSn0i}Me9 &entry_points, Fe #if defined(Q_OS_OS2) MessageBox::iconify(m_ui->m_buttonBox); #endif + + connect(m_ui->m_listEntryPoints, SIGNAL(itemSelectionChanged()), this, SLOT(displayActiveEntryPointDetails())); + loadEntryPoints(); } FormAddAccount::~FormAddAccount() { delete m_ui; } + +void FormAddAccount::displayActiveEntryPointDetails() { + QList selected_items = m_ui->m_listEntryPoints->selectedItems(); + + if (!selected_items.isEmpty()) { + ServiceEntryPoint *point = static_cast(selected_items.at(0)->data(Qt::UserRole).value()); + } +} + +void FormAddAccount::loadEntryPoints() { + foreach (ServiceEntryPoint *entry_point, m_entryPoints) { + QListWidgetItem *item = new QListWidgetItem(entry_point->icon(), entry_point->name(), m_ui->m_listEntryPoints); + + item->setData(Qt::UserRole, QVariant::fromValue((void*) entry_point)); + + } +} diff --git a/src/gui/dialogs/formaddaccount.h b/src/gui/dialogs/formaddaccount.h index 2aaee06dd..a5c29998d 100755 --- a/src/gui/dialogs/formaddaccount.h +++ b/src/gui/dialogs/formaddaccount.h @@ -37,7 +37,12 @@ class FormAddAccount : public QDialog { explicit FormAddAccount(const QList &entry_points, FeedsModel *model, QWidget *parent = 0); virtual ~FormAddAccount(); + private slots: + void displayActiveEntryPointDetails(); + private: + void loadEntryPoints(); + Ui::FormAddAccount *m_ui; FeedsModel *m_model; QList m_entryPoints; From 84fed7c4cef9315976cf260df80da5a5230185af Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 30 Nov 2015 10:50:37 +0100 Subject: [PATCH 092/203] Work on add account dialog. --- src/core/feedsmodel.cpp | 10 +++ src/core/feedsmodel.h | 4 ++ src/definitions/definitions.h.in | 3 + src/gui/dialogs/formaddaccount.cpp | 14 +++- src/gui/dialogs/formaddaccount.ui | 68 ++++++++++++++++++- src/services/abstract/serviceentrypoint.h | 7 +- src/services/abstract/serviceroot.h | 2 + .../standard/standardserviceentrypoint.cpp | 10 +-- .../standard/standardserviceentrypoint.h | 2 +- src/services/standard/standardserviceroot.cpp | 4 ++ src/services/standard/standardserviceroot.h | 2 + .../tt-rss/ttrssserviceentrypoint.cpp | 17 ++--- src/services/tt-rss/ttrssserviceentrypoint.h | 2 +- src/services/tt-rss/ttrssserviceroot.cpp | 4 ++ src/services/tt-rss/ttrssserviceroot.h | 2 + 15 files changed, 129 insertions(+), 22 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 2f2cc28ae..9249df650 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -499,6 +499,16 @@ QList FeedsModel::serviceRoots() { return roots; } +bool FeedsModel::containsServiceRootFromEntryPoint(ServiceEntryPoint *point) { + foreach (RootItem *root, serviceRoots()) { + if (root->toServiceRoot()->code() == point->code()) { + return true; + } + } + + return false; +} + StandardServiceRoot *FeedsModel::standardServiceRoot() { foreach (RootItem *root, serviceRoots()) { StandardServiceRoot *std_service_root; diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 9a1ffb40c..d99ce010f 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -28,6 +28,7 @@ class DatabaseCleaner; class Category; class Feed; class ServiceRoot; +class ServiceEntryPoint; class StandardServiceRoot; class QTimer; @@ -85,6 +86,9 @@ class FeedsModel : public QAbstractItemModel { // the model root item. QList serviceRoots(); + // Determines if there is any account activated from given entry point. + bool containsServiceRootFromEntryPoint(ServiceEntryPoint *point); + // Direct and the only global accessor to standard service root. // NOTE: Standard service root is always activated. StandardServiceRoot *standardServiceRoot(); diff --git a/src/definitions/definitions.h.in b/src/definitions/definitions.h.in index c2249bbed..f084a00d9 100755 --- a/src/definitions/definitions.h.in +++ b/src/definitions/definitions.h.in @@ -38,6 +38,9 @@ #define APP_USERAGENT QString("@APP_NAME@/@APP_VERSION@ (@APP_URL@) on @CMAKE_SYSTEM@") #define APP_DONATE_URL "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=XMWPLPK893VH4" +#define SERVICE_CODE_STD_RSS "std-rss" +#define SERVICE_CODE_TT_RSS "tt-rss" + #define ENCLOSURES_OUTER_SEPARATOR '#' #define ECNLOSURES_INNER_SEPARATOR '&' #define URI_SCHEME_FEED "feed://" diff --git a/src/gui/dialogs/formaddaccount.cpp b/src/gui/dialogs/formaddaccount.cpp index e72c44400..1feefac7f 100755 --- a/src/gui/dialogs/formaddaccount.cpp +++ b/src/gui/dialogs/formaddaccount.cpp @@ -20,7 +20,7 @@ #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" #include "core/feedsmodel.h" - +#include "services/standard/standardserviceentrypoint.h" #if defined(Q_OS_OS2) #include "gui/messagebox.h" @@ -52,14 +52,24 @@ void FormAddAccount::displayActiveEntryPointDetails() { if (!selected_items.isEmpty()) { ServiceEntryPoint *point = static_cast(selected_items.at(0)->data(Qt::UserRole).value()); + + m_ui->m_txtAuthor->setText(point->author()); + m_ui->m_txtDescription->setText(point->description()); + m_ui->m_txtName->setText(point->name()); + m_ui->m_txtVersion->setText(point->version()); } } void FormAddAccount::loadEntryPoints() { foreach (ServiceEntryPoint *entry_point, m_entryPoints) { QListWidgetItem *item = new QListWidgetItem(entry_point->icon(), entry_point->name(), m_ui->m_listEntryPoints); - item->setData(Qt::UserRole, QVariant::fromValue((void*) entry_point)); + if (entry_point->isSingleInstanceService() && m_model->containsServiceRootFromEntryPoint(entry_point)) { + // Oops, this item cannot be added, it is single instance and is already added. + item->setFlags(Qt::NoItemFlags); + } } + + m_ui->m_listEntryPoints->setCurrentRow(m_entryPoints.size() - 1); } diff --git a/src/gui/dialogs/formaddaccount.ui b/src/gui/dialogs/formaddaccount.ui index 266532bd8..67026a6b3 100755 --- a/src/gui/dialogs/formaddaccount.ui +++ b/src/gui/dialogs/formaddaccount.ui @@ -6,8 +6,8 @@ 0 0 - 558 - 300 + 610 + 271 @@ -35,6 +35,70 @@ Details + + + + + Name + + + + + + + true + + + + + + + Version + + + + + + + true + + + + + + + Author + + + + + + + true + + + + + + + Description + + + + + + + + 0 + 1 + + + + true + + + + diff --git a/src/services/abstract/serviceentrypoint.h b/src/services/abstract/serviceentrypoint.h index 06f1bd83c..1429ceb90 100755 --- a/src/services/abstract/serviceentrypoint.h +++ b/src/services/abstract/serviceentrypoint.h @@ -44,12 +44,13 @@ class ServiceEntryPoint { // which operates with normal RSS/ATOM feeds. virtual bool isSingleInstanceService() = 0; - // Can properties of this service account be edited by user via GUI? - virtual bool canBeEdited() = 0; - // Human readable service name, for example "TT-RSS". virtual QString name() = 0; + // Some arbitrary string. + // NOTE: Keep in sync with ServiceRoot::code(). + virtual QString code() = 0; + // Human readable service description, for example "Services which offers TT-RSS integration.". virtual QString description() = 0; diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 34d30bd61..d335020de 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -64,6 +64,8 @@ class ServiceRoot : public RootItem { virtual void start() = 0; virtual void stop() = 0; + virtual QString code() = 0; + // This method should prepare messages for given "item" (download them maybe?) // into predefined "Messages" table // and then use method QSqlTableModel::setFilter(....). diff --git a/src/services/standard/standardserviceentrypoint.cpp b/src/services/standard/standardserviceentrypoint.cpp index e42076b30..b71298520 100755 --- a/src/services/standard/standardserviceentrypoint.cpp +++ b/src/services/standard/standardserviceentrypoint.cpp @@ -33,12 +33,8 @@ bool StandardServiceEntryPoint::isSingleInstanceService() { return true; } -bool StandardServiceEntryPoint::canBeEdited() { - return false; -} - QString StandardServiceEntryPoint::name() { - return QSL("Standard (RSS/RDF/ATOM)"); + return QSL("Standard online feeds (RSS/RDF/ATOM)"); } QString StandardServiceEntryPoint::description() { @@ -57,6 +53,10 @@ QIcon StandardServiceEntryPoint::icon() { return QIcon(APP_ICON_PATH); } +QString StandardServiceEntryPoint::code() { + return SERVICE_CODE_STD_RSS; +} + QList StandardServiceEntryPoint::initializeSubtree(FeedsModel *main_model) { StandardServiceRoot *root = new StandardServiceRoot(true, main_model); QList roots; diff --git a/src/services/standard/standardserviceentrypoint.h b/src/services/standard/standardserviceentrypoint.h index 0a719413f..088ff7294 100755 --- a/src/services/standard/standardserviceentrypoint.h +++ b/src/services/standard/standardserviceentrypoint.h @@ -27,12 +27,12 @@ class StandardServiceEntryPoint : public ServiceEntryPoint { virtual ~StandardServiceEntryPoint(); bool isSingleInstanceService(); - bool canBeEdited(); QString name(); QString description(); QString version(); QString author(); QIcon icon(); + QString code(); QList initializeSubtree(FeedsModel *main_model); }; diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 1af194217..3c6d63bb5 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -101,6 +101,10 @@ void StandardServiceRoot::stop() { qDebug("Stopping StandardServiceRoot instance."); } +QString StandardServiceRoot::code() { + return SERVICE_CODE_STD_RSS; +} + bool StandardServiceRoot::canBeEdited() { return false; } diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 2cf81b1ba..18945401b 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -47,6 +47,8 @@ class StandardServiceRoot : public ServiceRoot { void start(); void stop(); + QString code(); + bool canBeEdited(); bool canBeDeleted(); bool deleteViaGui(); diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp index da2b7d854..28d1c2920 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.cpp +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -19,6 +19,7 @@ #include "definitions/definitions.h" #include "miscellaneous/application.h" +#include "miscellaneous/iconfactory.h" TtRssServiceEntryPoint::TtRssServiceEntryPoint(){ @@ -33,20 +34,16 @@ bool TtRssServiceEntryPoint::isSingleInstanceService() { return false; } -bool TtRssServiceEntryPoint::canBeEdited() { - return true; -} - QString TtRssServiceEntryPoint::name() { - return QSL("TT-RSS (TinyTiny RSS)"); + return QSL("Tiny Tiny RSS"); } QString TtRssServiceEntryPoint::description() { - return QSL("This service offers integration with TinyTiny RSS."); + return QSL("This service offers integration with Tiny Tiny RSS.\n\nTiny Tiny RSS is an open source web-based news feed (RSS/Atom) reader and aggregator, designed to allow you to read news from any location, while feeling as close to a real desktop application as possible."); } QString TtRssServiceEntryPoint::version() { - return QSL("0.0.1"); + return QSL("0.0.2"); } QString TtRssServiceEntryPoint::author() { @@ -54,7 +51,11 @@ QString TtRssServiceEntryPoint::author() { } QIcon TtRssServiceEntryPoint::icon() { - return QIcon(APP_ICON_PATH); + return qApp->icons()->fromTheme(QSL("application-ttrss")); +} + +QString TtRssServiceEntryPoint::code() { + return SERVICE_CODE_TT_RSS; } QList TtRssServiceEntryPoint::initializeSubtree(FeedsModel *main_model) { diff --git a/src/services/tt-rss/ttrssserviceentrypoint.h b/src/services/tt-rss/ttrssserviceentrypoint.h index 6d04cf4d0..478f9c801 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.h +++ b/src/services/tt-rss/ttrssserviceentrypoint.h @@ -28,12 +28,12 @@ class TtRssServiceEntryPoint : public ServiceEntryPoint { virtual ~TtRssServiceEntryPoint(); bool isSingleInstanceService(); - bool canBeEdited(); QString name(); QString description(); QString version(); QString author(); QIcon icon(); + QString code(); QList initializeSubtree(FeedsModel *main_model); }; diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 8efae22ec..2654f6524 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -33,6 +33,10 @@ TtRssServiceRoot::TtRssServiceRoot(FeedsModel *feeds_model, RootItem *parent) : TtRssServiceRoot::~TtRssServiceRoot() { } +QString TtRssServiceRoot::code() { + return SERVICE_CODE_TT_RSS; +} + bool TtRssServiceRoot::editViaGui() { return false; } diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 617d9a6da..68d0e4f3a 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -32,6 +32,8 @@ class TtRssServiceRoot : public ServiceRoot { explicit TtRssServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL); virtual ~TtRssServiceRoot(); + QString code(); + bool canBeEdited(); bool canBeDeleted(); bool editViaGui(); From 51e9d80fbc0563129f67c6fc76887c66eb5ce2c6 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 30 Nov 2015 11:13:00 +0100 Subject: [PATCH 093/203] Experimental adding/removing of standard account. --- src/core/feedsmodel.cpp | 3 ++ src/gui/dialogs/formaddaccount.cpp | 35 ++++++++++++++----- src/gui/dialogs/formaddaccount.h | 2 ++ src/services/abstract/serviceentrypoint.h | 7 ++++ .../standard/standardserviceentrypoint.cpp | 27 ++++++++++++-- .../standard/standardserviceentrypoint.h | 1 + .../tt-rss/ttrssserviceentrypoint.cpp | 4 +++ src/services/tt-rss/ttrssserviceentrypoint.h | 1 + 8 files changed, 69 insertions(+), 11 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 9249df650..66652ed54 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -687,6 +687,9 @@ void FeedsModel::reloadWholeLayout() { bool FeedsModel::addServiceAccount(ServiceRoot *root) { m_rootItem->appendChild(root); + // Item add, reload da shit. + reloadWholeLayout(); + // Connect. connect(root, SIGNAL(readFeedsFilterInvalidationRequested()), this, SIGNAL(readFeedsFilterInvalidationRequested())); connect(root, SIGNAL(dataChanged(QList)), this, SLOT(onItemDataChanged(QList))); diff --git a/src/gui/dialogs/formaddaccount.cpp b/src/gui/dialogs/formaddaccount.cpp index 1feefac7f..4d86eaf14 100755 --- a/src/gui/dialogs/formaddaccount.cpp +++ b/src/gui/dialogs/formaddaccount.cpp @@ -39,6 +39,7 @@ FormAddAccount::FormAddAccount(const QList &entry_points, Fe MessageBox::iconify(m_ui->m_buttonBox); #endif + connect(m_ui->m_buttonBox, SIGNAL(accepted()), this, SLOT(addSelectedAccount())); connect(m_ui->m_listEntryPoints, SIGNAL(itemSelectionChanged()), this, SLOT(displayActiveEntryPointDetails())); loadEntryPoints(); } @@ -47,27 +48,43 @@ FormAddAccount::~FormAddAccount() { delete m_ui; } -void FormAddAccount::displayActiveEntryPointDetails() { - QList selected_items = m_ui->m_listEntryPoints->selectedItems(); +void FormAddAccount::addSelectedAccount() { + accept(); - if (!selected_items.isEmpty()) { - ServiceEntryPoint *point = static_cast(selected_items.at(0)->data(Qt::UserRole).value()); + ServiceEntryPoint *point = selectedEntryPoint(); + ServiceRoot *new_root = point->createNewRoot(m_model); - m_ui->m_txtAuthor->setText(point->author()); - m_ui->m_txtDescription->setText(point->description()); - m_ui->m_txtName->setText(point->name()); - m_ui->m_txtVersion->setText(point->version()); + if (new_root != NULL) { + m_model->addServiceAccount(new_root); } + else { + qApp->showGuiMessage(tr("Cannot add account"), + tr("Some critical error occurred, report this to developers."), + QSystemTrayIcon::Critical, parentWidget(), true); + } +} + +void FormAddAccount::displayActiveEntryPointDetails() { + ServiceEntryPoint *point = selectedEntryPoint(); + + m_ui->m_txtAuthor->setText(point->author()); + m_ui->m_txtDescription->setText(point->description()); + m_ui->m_txtName->setText(point->name()); + m_ui->m_txtVersion->setText(point->version()); +} + +ServiceEntryPoint *FormAddAccount::selectedEntryPoint() { + return m_entryPoints.at(m_ui->m_listEntryPoints->currentRow()); } void FormAddAccount::loadEntryPoints() { foreach (ServiceEntryPoint *entry_point, m_entryPoints) { QListWidgetItem *item = new QListWidgetItem(entry_point->icon(), entry_point->name(), m_ui->m_listEntryPoints); - item->setData(Qt::UserRole, QVariant::fromValue((void*) entry_point)); if (entry_point->isSingleInstanceService() && m_model->containsServiceRootFromEntryPoint(entry_point)) { // Oops, this item cannot be added, it is single instance and is already added. item->setFlags(Qt::NoItemFlags); + item->setToolTip(tr("This account can be added only once.")); } } diff --git a/src/gui/dialogs/formaddaccount.h b/src/gui/dialogs/formaddaccount.h index a5c29998d..bacf59892 100755 --- a/src/gui/dialogs/formaddaccount.h +++ b/src/gui/dialogs/formaddaccount.h @@ -38,9 +38,11 @@ class FormAddAccount : public QDialog { virtual ~FormAddAccount(); private slots: + void addSelectedAccount(); void displayActiveEntryPointDetails(); private: + ServiceEntryPoint *selectedEntryPoint(); void loadEntryPoints(); Ui::FormAddAccount *m_ui; diff --git a/src/services/abstract/serviceentrypoint.h b/src/services/abstract/serviceentrypoint.h index 1429ceb90..4602666a8 100755 --- a/src/services/abstract/serviceentrypoint.h +++ b/src/services/abstract/serviceentrypoint.h @@ -33,6 +33,13 @@ class ServiceEntryPoint { explicit ServiceEntryPoint(); virtual ~ServiceEntryPoint(); + // Creates new service root item, which is ready to be added + // into the model. This method can for example display + // some kind of first-time configuration dialog inside itself + // before returning the root item. + // Returns NULL if initialization of new root cannot be done. + virtual ServiceRoot *createNewRoot(FeedsModel *main_model) = 0; + // Performs initialization of all service accounts created using this entry // point from persistent DB. // Returns list of root nodes which will be afterwards added diff --git a/src/services/standard/standardserviceentrypoint.cpp b/src/services/standard/standardserviceentrypoint.cpp index b71298520..1f9f11e82 100755 --- a/src/services/standard/standardserviceentrypoint.cpp +++ b/src/services/standard/standardserviceentrypoint.cpp @@ -22,6 +22,8 @@ #include "miscellaneous/application.h" #include "services/standard/standardserviceroot.h" +#include + StandardServiceEntryPoint::StandardServiceEntryPoint() { } @@ -57,10 +59,31 @@ QString StandardServiceEntryPoint::code() { return SERVICE_CODE_STD_RSS; } +ServiceRoot *StandardServiceEntryPoint::createNewRoot(FeedsModel *main_model) { + // Switch DB. + QSqlDatabase database = qApp->database()->connection(QSL("StandardServiceEntryPoint"), DatabaseFactory::FromSettings); + QSqlQuery query(database); + + if (query.exec(QSL("UPDATE Information SET inf_value = 1 WHERE inf_key = 'standard_account_enabled';"))) { + return new StandardServiceRoot(true, main_model); + } + else { + return NULL; + } +} + QList StandardServiceEntryPoint::initializeSubtree(FeedsModel *main_model) { - StandardServiceRoot *root = new StandardServiceRoot(true, main_model); + // Check DB if standard account is enabled. + QSqlDatabase database = qApp->database()->connection(QSL("StandardServiceEntryPoint"), DatabaseFactory::FromSettings); + QSqlQuery query(database); QList roots; - roots.append(root); + if (query.exec(QSL("SELECT inf_value FROM Information WHERE inf_key = 'standard_account_enabled';"))) { + if (query.next() && query.value(0).toInt() == 1) { + StandardServiceRoot *root = new StandardServiceRoot(true, main_model); + roots.append(root); + } + } + return roots; } diff --git a/src/services/standard/standardserviceentrypoint.h b/src/services/standard/standardserviceentrypoint.h index 088ff7294..8e4904cb4 100755 --- a/src/services/standard/standardserviceentrypoint.h +++ b/src/services/standard/standardserviceentrypoint.h @@ -34,6 +34,7 @@ class StandardServiceEntryPoint : public ServiceEntryPoint { QIcon icon(); QString code(); + ServiceRoot *createNewRoot(FeedsModel *main_model); QList initializeSubtree(FeedsModel *main_model); }; diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp index 28d1c2920..6d5a24c03 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.cpp +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -58,6 +58,10 @@ QString TtRssServiceEntryPoint::code() { return SERVICE_CODE_TT_RSS; } +ServiceRoot *TtRssServiceEntryPoint::createNewRoot(FeedsModel *main_model) { + return NULL; +} + QList TtRssServiceEntryPoint::initializeSubtree(FeedsModel *main_model) { return QList(); } diff --git a/src/services/tt-rss/ttrssserviceentrypoint.h b/src/services/tt-rss/ttrssserviceentrypoint.h index 478f9c801..17e9a7635 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.h +++ b/src/services/tt-rss/ttrssserviceentrypoint.h @@ -35,6 +35,7 @@ class TtRssServiceEntryPoint : public ServiceEntryPoint { QIcon icon(); QString code(); + ServiceRoot *createNewRoot(FeedsModel *main_model); QList initializeSubtree(FeedsModel *main_model); }; From bf3d97dd2c3232ceb283a824ccfc4db3be980712 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 30 Nov 2015 12:53:04 +0100 Subject: [PATCH 094/203] Reloaded langs + removed direct access to model from items - better encapsulation. --- localization/rssguard-cs_CZ.ts | 131 +++++++++++------ localization/rssguard-de_DE.ts | 133 ++++++++++++------ localization/rssguard-en_GB.ts | 131 +++++++++++------ localization/rssguard-en_US.ts | 131 +++++++++++------ localization/rssguard-fr_FR.ts | 131 +++++++++++------ localization/rssguard-it_IT.ts | 131 +++++++++++------ localization/rssguard-nl_NL.ts | 131 +++++++++++------ localization/rssguard-sv_SE.ts | 131 +++++++++++------ src/core/feedsmodel.cpp | 11 +- src/core/feedsmodel.h | 11 +- src/gui/dialogs/formaddaccount.cpp | 2 +- src/services/abstract/serviceentrypoint.h | 4 +- src/services/abstract/serviceroot.cpp | 14 +- src/services/abstract/serviceroot.h | 12 +- .../gui/formstandardcategorydetails.cpp | 4 +- .../standard/gui/formstandardfeeddetails.cpp | 4 +- src/services/standard/standardcategory.cpp | 4 +- src/services/standard/standardfeed.cpp | 4 +- .../standardfeedsimportexportmodel.cpp | 2 +- .../standard/standardserviceentrypoint.cpp | 8 +- .../standard/standardserviceentrypoint.h | 4 +- src/services/standard/standardserviceroot.cpp | 13 +- src/services/standard/standardserviceroot.h | 2 +- .../tt-rss/ttrssserviceentrypoint.cpp | 4 +- src/services/tt-rss/ttrssserviceentrypoint.h | 4 +- src/services/tt-rss/ttrssserviceroot.cpp | 2 +- src/services/tt-rss/ttrssserviceroot.h | 2 +- 27 files changed, 787 insertions(+), 374 deletions(-) diff --git a/localization/rssguard-cs_CZ.ts b/localization/rssguard-cs_CZ.ts index 01e69ac57..c599b7864 100644 --- a/localization/rssguard-cs_CZ.ts +++ b/localization/rssguard-cs_CZ.ts @@ -513,6 +513,14 @@ Klikněte sem pro otevření nadřazeného adresáře. New messages downloaded Staženy nové zprávy + + Cannot perform drag & drop operation. + + + + You can't transfer dragged item into different account, this is not supported. + + FeedsToolBar @@ -661,6 +669,45 @@ or this functionality is not implemented yet. <body>%5 je (velmi) lehkotonážní prohlížeč kanálů.<br><br>Tento software je distribuován pod licencí GNU General Public License, verze 3.<br><br>Kontakty:<ul><li><a href="mailto://%1">%1</a> ~e-mail</li><li><a href="%2">%2</a> ~web</li></ul>Zdrojový kór pro %5 lze získat na jeho webu.<br><br><br>Copyright (C) 2011-%3 %4</body> + + FormAddAccount + + Add new account + + + + Details + + + + Name + Název + + + Version + Verze + + + Author + Autor + + + Description + Popis + + + Cannot add account + + + + Some critical error occurred, report this to developers. + + + + This account can be added only once. + + + FormBackupDatabaseSettings @@ -881,10 +928,6 @@ or this functionality is not implemented yet. No actions are available right now. Žádná akce není právě dostupná. - - Fee&ds && categories - Kanály && ka&tegorie - Hides main window if it is visible and shows it if it is hidden. Skryje hlavní ikno, je-li aktuálně viditelné. Jinak jej zobrazí. @@ -1061,26 +1104,14 @@ or this functionality is not implemented yet. Add &new item - - &Services - - Update &all items - - Ctrl+Shift+U - - Update &selected items - - Ctrl+U - - &Edit selected item @@ -1137,26 +1168,14 @@ or this functionality is not implemented yet. Deletes all messages from all items. - - Ctrl+Shift+C - - Select &next item - - S - - Select &previous item - - A - - Show only unread items @@ -1165,22 +1184,10 @@ or this functionality is not implemented yet. &Expand/collapse selected item - - E - - &Add new service account - - &Delete selected service account - - - - &Edit selected service account - - &Restore selected messages @@ -1189,6 +1196,38 @@ or this functionality is not implemented yet. No possible actions + + Feeds && categories && accounts + + + + &Recycle bin(s) + + + + &Restore all recycle bins + + + + &Empty all recycle bins + + + + Select next &unread message + + + + No recycle bin + + + + Restore recycle bin + + + + Empty recycle bin + + FormRestoreDatabaseSettings @@ -1918,6 +1957,10 @@ File filter for external e-mail selection dialog. E-mail + + Enable notifications + + FormStandardCategoryDetails @@ -3281,6 +3324,14 @@ Nepřečtené zprávy: %2 Stop web page loading. Zastavit načítání aktuální webové stránky. + + Cannot add feed + Nelze přidat kanál + + + You cannot add this feed to %1 because standard RSS/ATOM account is not enabled. Enable it first. + + WebView diff --git a/localization/rssguard-de_DE.ts b/localization/rssguard-de_DE.ts index 7bb8c54f1..b6048b99d 100644 --- a/localization/rssguard-de_DE.ts +++ b/localization/rssguard-de_DE.ts @@ -502,6 +502,14 @@ Click here to open parent directory. New messages downloaded + + Cannot perform drag & drop operation. + + + + You can't transfer dragged item into different account, this is not supported. + + FeedsToolBar @@ -650,6 +658,45 @@ or this functionality is not implemented yet. + + FormAddAccount + + Add new account + + + + Details + + + + Name + Name + + + Version + Version + + + Author + Author + + + Description + Beschreibung + + + Cannot add account + + + + Some critical error occurred, report this to developers. + + + + This account can be added only once. + + + FormBackupDatabaseSettings @@ -869,10 +916,6 @@ or this functionality is not implemented yet. No actions are available right now. Keine Funktionen verfügbar. - - Fee&ds && categories - Fee&ds && Kategorien - Hides main window if it is visible and shows it if it is hidden. Hauptfenster verstecken falls es sichtbar was oder sichtbar falls es versteckt war. @@ -1049,26 +1092,14 @@ or this functionality is not implemented yet. Add &new item - - &Services - - Update &all items - - Ctrl+Shift+U - - Update &selected items - - Ctrl+U - - &Edit selected item @@ -1125,26 +1156,14 @@ or this functionality is not implemented yet. Deletes all messages from all items. - - Ctrl+Shift+C - - Select &next item - - S - - Select &previous item - - A - - Show only unread items @@ -1153,22 +1172,10 @@ or this functionality is not implemented yet. &Expand/collapse selected item - - E - - &Add new service account - - &Delete selected service account - - - - &Edit selected service account - - &Restore selected messages @@ -1177,6 +1184,38 @@ or this functionality is not implemented yet. No possible actions + + Feeds && categories && accounts + + + + &Recycle bin(s) + + + + &Restore all recycle bins + + + + &Empty all recycle bins + + + + Select next &unread message + + + + No recycle bin + + + + Restore recycle bin + + + + Empty recycle bin + + FormRestoreDatabaseSettings @@ -1888,6 +1927,10 @@ File filter for external e-mail selection dialog. E-mail + + Enable notifications + + FormStandardCategoryDetails @@ -2053,7 +2096,7 @@ File filter for external e-mail selection dialog. minutes - + Minuten Title @@ -3239,6 +3282,14 @@ Unread news: %2 Stop web page loading. Stoppe das laden der Webseite. + + Cannot add feed + Kann Feed nicht hinzufügen + + + You cannot add this feed to %1 because standard RSS/ATOM account is not enabled. Enable it first. + + WebView diff --git a/localization/rssguard-en_GB.ts b/localization/rssguard-en_GB.ts index 0bfaa0d1b..ec621f51b 100644 --- a/localization/rssguard-en_GB.ts +++ b/localization/rssguard-en_GB.ts @@ -502,6 +502,14 @@ Click here to open parent directory. New messages downloaded + + Cannot perform drag & drop operation. + + + + You can't transfer dragged item into different account, this is not supported. + + FeedsToolBar @@ -650,6 +658,45 @@ or this functionality is not implemented yet. + + FormAddAccount + + Add new account + + + + Details + + + + Name + + + + Version + + + + Author + + + + Description + + + + Cannot add account + + + + Some critical error occurred, report this to developers. + + + + This account can be added only once. + + + FormBackupDatabaseSettings @@ -869,10 +916,6 @@ or this functionality is not implemented yet. No actions are available right now. - - Fee&ds && categories - - Hides main window if it is visible and shows it if it is hidden. @@ -1049,26 +1092,14 @@ or this functionality is not implemented yet. Add &new item - - &Services - - Update &all items - - Ctrl+Shift+U - - Update &selected items - - Ctrl+U - - &Edit selected item @@ -1125,26 +1156,14 @@ or this functionality is not implemented yet. Deletes all messages from all items. - - Ctrl+Shift+C - - Select &next item - - S - - Select &previous item - - A - - Show only unread items @@ -1153,22 +1172,10 @@ or this functionality is not implemented yet. &Expand/collapse selected item - - E - - &Add new service account - - &Delete selected service account - - - - &Edit selected service account - - &Restore selected messages @@ -1177,6 +1184,38 @@ or this functionality is not implemented yet. No possible actions + + Feeds && categories && accounts + + + + &Recycle bin(s) + + + + &Restore all recycle bins + + + + &Empty all recycle bins + + + + Select next &unread message + + + + No recycle bin + + + + Restore recycle bin + + + + Empty recycle bin + + FormRestoreDatabaseSettings @@ -1886,6 +1925,10 @@ File filter for external e-mail selection dialog. E-mail + + Enable notifications + + FormStandardCategoryDetails @@ -3234,6 +3277,14 @@ Unread news: %2 Stop web page loading. + + Cannot add feed + + + + You cannot add this feed to %1 because standard RSS/ATOM account is not enabled. Enable it first. + + WebView diff --git a/localization/rssguard-en_US.ts b/localization/rssguard-en_US.ts index 4e3226e75..c5bec6629 100644 --- a/localization/rssguard-en_US.ts +++ b/localization/rssguard-en_US.ts @@ -502,6 +502,14 @@ Click here to open parent directory. New messages downloaded + + Cannot perform drag & drop operation. + + + + You can't transfer dragged item into different account, this is not supported. + + FeedsToolBar @@ -650,6 +658,45 @@ or this functionality is not implemented yet. + + FormAddAccount + + Add new account + + + + Details + + + + Name + + + + Version + + + + Author + + + + Description + + + + Cannot add account + + + + Some critical error occurred, report this to developers. + + + + This account can be added only once. + + + FormBackupDatabaseSettings @@ -869,10 +916,6 @@ or this functionality is not implemented yet. No actions are available right now. - - Fee&ds && categories - - Hides main window if it is visible and shows it if it is hidden. @@ -1049,26 +1092,14 @@ or this functionality is not implemented yet. Add &new item - - &Services - - Update &all items - - Ctrl+Shift+U - - Update &selected items - - Ctrl+U - - &Edit selected item @@ -1125,26 +1156,14 @@ or this functionality is not implemented yet. Deletes all messages from all items. - - Ctrl+Shift+C - - Select &next item - - S - - Select &previous item - - A - - Show only unread items @@ -1153,22 +1172,10 @@ or this functionality is not implemented yet. &Expand/collapse selected item - - E - - &Add new service account - - &Delete selected service account - - - - &Edit selected service account - - &Restore selected messages @@ -1177,6 +1184,38 @@ or this functionality is not implemented yet. No possible actions + + Feeds && categories && accounts + + + + &Recycle bin(s) + + + + &Restore all recycle bins + + + + &Empty all recycle bins + + + + Select next &unread message + + + + No recycle bin + + + + Restore recycle bin + + + + Empty recycle bin + + FormRestoreDatabaseSettings @@ -1886,6 +1925,10 @@ File filter for external e-mail selection dialog. E-mail + + Enable notifications + + FormStandardCategoryDetails @@ -3234,6 +3277,14 @@ Unread news: %2 Stop web page loading. + + Cannot add feed + + + + You cannot add this feed to %1 because standard RSS/ATOM account is not enabled. Enable it first. + + WebView diff --git a/localization/rssguard-fr_FR.ts b/localization/rssguard-fr_FR.ts index ea5667b98..bf084b1aa 100644 --- a/localization/rssguard-fr_FR.ts +++ b/localization/rssguard-fr_FR.ts @@ -502,6 +502,14 @@ Click here to open parent directory. New messages downloaded + + Cannot perform drag & drop operation. + + + + You can't transfer dragged item into different account, this is not supported. + + FeedsToolBar @@ -650,6 +658,45 @@ or this functionality is not implemented yet. + + FormAddAccount + + Add new account + + + + Details + + + + Name + Nom + + + Version + Version + + + Author + Auteur + + + Description + Description + + + Cannot add account + + + + Some critical error occurred, report this to developers. + + + + This account can be added only once. + + + FormBackupDatabaseSettings @@ -869,10 +916,6 @@ or this functionality is not implemented yet. No actions are available right now. Aucune actions disponibles pour le moment. - - Fee&ds && categories - Flux && catégories - Hides main window if it is visible and shows it if it is hidden. Cacher la fenêtre principale si il est visible et la montrer si il est cacher. @@ -1049,26 +1092,14 @@ or this functionality is not implemented yet. Add &new item - - &Services - - Update &all items - - Ctrl+Shift+U - - Update &selected items - - Ctrl+U - - &Edit selected item @@ -1125,26 +1156,14 @@ or this functionality is not implemented yet. Deletes all messages from all items. - - Ctrl+Shift+C - - Select &next item - - S - - Select &previous item - - A - - Show only unread items @@ -1153,22 +1172,10 @@ or this functionality is not implemented yet. &Expand/collapse selected item - - E - - &Add new service account - - &Delete selected service account - - - - &Edit selected service account - - &Restore selected messages @@ -1177,6 +1184,38 @@ or this functionality is not implemented yet. No possible actions + + Feeds && categories && accounts + + + + &Recycle bin(s) + + + + &Restore all recycle bins + + + + &Empty all recycle bins + + + + Select next &unread message + + + + No recycle bin + + + + Restore recycle bin + + + + Empty recycle bin + + FormRestoreDatabaseSettings @@ -1898,6 +1937,10 @@ File filter for external e-mail selection dialog. E-mail + + Enable notifications + + FormStandardCategoryDetails @@ -3250,6 +3293,14 @@ Unread news: %2 Stop web page loading. Arrêter le chargement de la page + + Cannot add feed + Impossible d'ajouter le flux + + + You cannot add this feed to %1 because standard RSS/ATOM account is not enabled. Enable it first. + + WebView diff --git a/localization/rssguard-it_IT.ts b/localization/rssguard-it_IT.ts index e6470cfc7..6e51a123f 100644 --- a/localization/rssguard-it_IT.ts +++ b/localization/rssguard-it_IT.ts @@ -502,6 +502,14 @@ Click here to open parent directory. New messages downloaded + + Cannot perform drag & drop operation. + + + + You can't transfer dragged item into different account, this is not supported. + + FeedsToolBar @@ -650,6 +658,45 @@ or this functionality is not implemented yet. + + FormAddAccount + + Add new account + + + + Details + + + + Name + Nome + + + Version + Versione + + + Author + Autore + + + Description + Descrizione + + + Cannot add account + + + + Some critical error occurred, report this to developers. + + + + This account can be added only once. + + + FormBackupDatabaseSettings @@ -869,10 +916,6 @@ or this functionality is not implemented yet. No actions are available right now. Non è disponibile nessuna azione adesso. - - Fee&ds && categories - - Hides main window if it is visible and shows it if it is hidden. Nasconde la finestra principale se è visibile e la mostra se è nascosta. @@ -1049,26 +1092,14 @@ or this functionality is not implemented yet. Add &new item - - &Services - - Update &all items - - Ctrl+Shift+U - - Update &selected items - - Ctrl+U - - &Edit selected item @@ -1125,26 +1156,14 @@ or this functionality is not implemented yet. Deletes all messages from all items. - - Ctrl+Shift+C - - Select &next item - - S - - Select &previous item - - A - - Show only unread items @@ -1153,22 +1172,10 @@ or this functionality is not implemented yet. &Expand/collapse selected item - - E - - &Add new service account - - &Delete selected service account - - - - &Edit selected service account - - &Restore selected messages @@ -1177,6 +1184,38 @@ or this functionality is not implemented yet. No possible actions + + Feeds && categories && accounts + + + + &Recycle bin(s) + + + + &Restore all recycle bins + + + + &Empty all recycle bins + + + + Select next &unread message + + + + No recycle bin + + + + Restore recycle bin + + + + Empty recycle bin + + FormRestoreDatabaseSettings @@ -1888,6 +1927,10 @@ File filter for external e-mail selection dialog. E-mail + + Enable notifications + + FormStandardCategoryDetails @@ -3239,6 +3282,14 @@ Unread news: %2 Stop web page loading. Ferma caricamento pagina web. + + Cannot add feed + Impossibile aggiungere feed + + + You cannot add this feed to %1 because standard RSS/ATOM account is not enabled. Enable it first. + + WebView diff --git a/localization/rssguard-nl_NL.ts b/localization/rssguard-nl_NL.ts index 3eb26b7e7..668f3e1e0 100644 --- a/localization/rssguard-nl_NL.ts +++ b/localization/rssguard-nl_NL.ts @@ -508,6 +508,14 @@ Klik hier om map te openen. New messages downloaded Nieuw bericht gedownload + + Cannot perform drag & drop operation. + + + + You can't transfer dragged item into different account, this is not supported. + + FeedsToolBar @@ -656,6 +664,45 @@ or this functionality is not implemented yet. + + FormAddAccount + + Add new account + + + + Details + + + + Name + Naam + + + Version + Versie + + + Author + Auteur + + + Description + Omschrijving + + + Cannot add account + + + + Some critical error occurred, report this to developers. + + + + This account can be added only once. + + + FormBackupDatabaseSettings @@ -875,10 +922,6 @@ or this functionality is not implemented yet. No actions are available right now. Er zijn geen acties beschikbaar op dit moment. - - Fee&ds && categories - Fee&ds && categorieën - Hides main window if it is visible and shows it if it is hidden. Verberg hoofdvenster als het zichtbaar is en toon het als het verborgen is. @@ -1055,26 +1098,14 @@ or this functionality is not implemented yet. Add &new item - - &Services - - Update &all items - - Ctrl+Shift+U - - Update &selected items - - Ctrl+U - - &Edit selected item @@ -1131,26 +1162,14 @@ or this functionality is not implemented yet. Deletes all messages from all items. - - Ctrl+Shift+C - - Select &next item - - S - - Select &previous item - - A - - Show only unread items @@ -1159,22 +1178,10 @@ or this functionality is not implemented yet. &Expand/collapse selected item - - E - - &Add new service account - - &Delete selected service account - - - - &Edit selected service account - - &Restore selected messages @@ -1183,6 +1190,38 @@ or this functionality is not implemented yet. No possible actions + + Feeds && categories && accounts + + + + &Recycle bin(s) + + + + &Restore all recycle bins + + + + &Empty all recycle bins + + + + Select next &unread message + + + + No recycle bin + + + + Restore recycle bin + + + + Empty recycle bin + + FormRestoreDatabaseSettings @@ -1920,6 +1959,10 @@ Open nieuw webbrowser pagina(sleep muis omlaag). E-mail + + Enable notifications + + FormStandardCategoryDetails @@ -3280,6 +3323,14 @@ Ongelezen nieuws: %2 Stop web page loading. Stop het laden van pagina. + + Cannot add feed + Kan geen feed toevoegen + + + You cannot add this feed to %1 because standard RSS/ATOM account is not enabled. Enable it first. + + WebView diff --git a/localization/rssguard-sv_SE.ts b/localization/rssguard-sv_SE.ts index d8a9d5c06..340d6b031 100644 --- a/localization/rssguard-sv_SE.ts +++ b/localization/rssguard-sv_SE.ts @@ -507,6 +507,14 @@ Klicka här för att öppna målmappen. New messages downloaded Nya meddelanden nedladdade + + Cannot perform drag & drop operation. + + + + You can't transfer dragged item into different account, this is not supported. + + FeedsToolBar @@ -655,6 +663,45 @@ or this functionality is not implemented yet. + + FormAddAccount + + Add new account + + + + Details + + + + Name + Namn + + + Version + Version + + + Author + + + + Description + Beskrivning + + + Cannot add account + + + + Some critical error occurred, report this to developers. + + + + This account can be added only once. + + + FormBackupDatabaseSettings @@ -874,10 +921,6 @@ or this functionality is not implemented yet. No actions are available right now. Inga åtgärder tillgängliga just nu. - - Fee&ds && categories - &Flöden && kategorier - Hides main window if it is visible and shows it if it is hidden. Dölj programfönstret om det är synligt, och visa det om det är dolt. @@ -1054,26 +1097,14 @@ or this functionality is not implemented yet. Add &new item - - &Services - - Update &all items - - Ctrl+Shift+U - - Update &selected items - - Ctrl+U - - &Edit selected item @@ -1130,26 +1161,14 @@ or this functionality is not implemented yet. Deletes all messages from all items. - - Ctrl+Shift+C - - Select &next item - - S - - Select &previous item - - A - - Show only unread items @@ -1158,22 +1177,10 @@ or this functionality is not implemented yet. &Expand/collapse selected item - - E - - &Add new service account - - &Delete selected service account - - - - &Edit selected service account - - &Restore selected messages @@ -1182,6 +1189,38 @@ or this functionality is not implemented yet. No possible actions + + Feeds && categories && accounts + + + + &Recycle bin(s) + + + + &Restore all recycle bins + + + + &Empty all recycle bins + + + + Select next &unread message + + + + No recycle bin + + + + Restore recycle bin + + + + Empty recycle bin + + FormRestoreDatabaseSettings @@ -1912,6 +1951,10 @@ File filter for external e-mail selection dialog. E-mail + + Enable notifications + + FormStandardCategoryDetails @@ -3270,6 +3313,14 @@ Olästa nyheter: %2 Stop web page loading. Stoppa inläsning av webbsidan. + + Cannot add feed + Kan inte lägga till flöde + + + You cannot add this feed to %1 because standard RSS/ATOM account is not enabled. Enable it first. + + WebView diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 66652ed54..c92dd72ae 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -685,12 +685,15 @@ void FeedsModel::reloadWholeLayout() { } bool FeedsModel::addServiceAccount(ServiceRoot *root) { - m_rootItem->appendChild(root); + int new_row_index = m_rootItem->childCount(); - // Item add, reload da shit. - reloadWholeLayout(); + beginInsertRows(indexForItem(m_rootItem), new_row_index, new_row_index); + m_rootItem->appendChild(root); + endInsertRows(); // Connect. + connect(root, SIGNAL(itemRemovalRequested(RootItem*)), this, SLOT(removeItem(RootItem*))); + connect(root, SIGNAL(itemReassignmentRequested(RootItem*,RootItem*)), this, SLOT(reassignNodeToNewParent(RootItem*,RootItem*))); connect(root, SIGNAL(readFeedsFilterInvalidationRequested()), this, SIGNAL(readFeedsFilterInvalidationRequested())); connect(root, SIGNAL(dataChanged(QList)), this, SLOT(onItemDataChanged(QList))); connect(root, SIGNAL(reloadMessageListRequested(bool)), this, SIGNAL(reloadMessageListRequested(bool))); @@ -731,7 +734,7 @@ void FeedsModel::loadActivatedServiceAccounts() { // Iterate all globally available feed "service plugins". foreach (ServiceEntryPoint *entry_point, qApp->feedServices()) { // Load all stored root nodes from the entry point and add those to the model. - QList roots = entry_point->initializeSubtree(this); + QList roots = entry_point->initializeSubtree(); foreach (ServiceRoot *root, roots) { addServiceAccount(root); diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index d99ce010f..83df548e5 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -75,11 +75,6 @@ class FeedsModel : public QAbstractItemModel { // Removes item with given index. // NOTE: Also deletes item from memory. void removeItem(const QModelIndex &index); - void removeItem(RootItem *deleting_item); - - // Checks if new parent node is different from one used by original node. - // If it is, then it reassigns original_node to new parent. - void reassignNodeToNewParent(RootItem *original_node, RootItem *new_parent); // Returns all activated service roots. // NOTE: Service root nodes are lying directly UNDER @@ -157,6 +152,12 @@ class FeedsModel : public QAbstractItemModel { bool addServiceAccount(ServiceRoot *root); public slots: + // Checks if new parent node is different from one used by original node. + // If it is, then it reassigns original_node to new parent. + void reassignNodeToNewParent(RootItem *original_node, RootItem *new_parent); + + void removeItem(RootItem *deleting_item); + bool restoreAllBins(); bool emptyAllBins(); diff --git a/src/gui/dialogs/formaddaccount.cpp b/src/gui/dialogs/formaddaccount.cpp index 4d86eaf14..38d7d2e68 100755 --- a/src/gui/dialogs/formaddaccount.cpp +++ b/src/gui/dialogs/formaddaccount.cpp @@ -52,7 +52,7 @@ void FormAddAccount::addSelectedAccount() { accept(); ServiceEntryPoint *point = selectedEntryPoint(); - ServiceRoot *new_root = point->createNewRoot(m_model); + ServiceRoot *new_root = point->createNewRoot(); if (new_root != NULL) { m_model->addServiceAccount(new_root); diff --git a/src/services/abstract/serviceentrypoint.h b/src/services/abstract/serviceentrypoint.h index 4602666a8..1cefafa83 100755 --- a/src/services/abstract/serviceentrypoint.h +++ b/src/services/abstract/serviceentrypoint.h @@ -38,13 +38,13 @@ class ServiceEntryPoint { // some kind of first-time configuration dialog inside itself // before returning the root item. // Returns NULL if initialization of new root cannot be done. - virtual ServiceRoot *createNewRoot(FeedsModel *main_model) = 0; + virtual ServiceRoot *createNewRoot() = 0; // Performs initialization of all service accounts created using this entry // point from persistent DB. // Returns list of root nodes which will be afterwards added // to the global feed model. - virtual QList initializeSubtree(FeedsModel *main_model) = 0; + virtual QList initializeSubtree() = 0; // Can this service account be added just once? // NOTE: This is true particularly for "standard" service diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index 9a68e01d7..61c002824 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -20,17 +20,13 @@ #include "core/feedsmodel.h" -ServiceRoot::ServiceRoot(FeedsModel *feeds_model, RootItem *parent) : RootItem(parent), m_feedsModel(feeds_model) { +ServiceRoot::ServiceRoot(RootItem *parent) : RootItem(parent) { setKind(RootItemKind::ServiceRoot); } ServiceRoot::~ServiceRoot() { } -FeedsModel *ServiceRoot::feedsModel() const { - return m_feedsModel; -} - void ServiceRoot::itemChanged(QList items) { emit dataChanged(items); } @@ -42,3 +38,11 @@ void ServiceRoot::requestReloadMessageList(bool mark_selected_messages_read) { void ServiceRoot::requestFeedReadFilterReload() { emit readFeedsFilterInvalidationRequested(); } + +void ServiceRoot::requestItemReassignment(RootItem *item, RootItem *new_parent) { + emit itemReassignmentRequested(item, new_parent); +} + +void ServiceRoot::requestItemRemoval(RootItem *item) { + emit itemRemovalRequested(item); +} diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index d335020de..954df1a19 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -37,7 +37,7 @@ class ServiceRoot : public RootItem { Q_OBJECT public: - explicit ServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL); + explicit ServiceRoot(RootItem *parent = NULL); virtual ~ServiceRoot(); // Returns list of specific actions for "Add new item" main window menu. @@ -125,22 +125,22 @@ class ServiceRoot : public RootItem { // Selected item is naturally recycle bin. virtual bool onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) = 0; - // Access to feed model. - FeedsModel *feedsModel() const; - // Obvious methods to wrap signals. void itemChanged(QList items); void requestReloadMessageList(bool mark_selected_messages_read); void requestFeedReadFilterReload(); + void requestItemReassignment(RootItem *item, RootItem *new_parent); + void requestItemRemoval(RootItem *item); + signals: // Emitted if data in any item belonging to this root are changed. void dataChanged(QList items); void readFeedsFilterInvalidationRequested(); void reloadMessageListRequested(bool mark_selected_messages_read); - private: - FeedsModel *m_feedsModel; + void itemReassignmentRequested(RootItem *item, RootItem *new_parent); + void itemRemovalRequested(RootItem *item); }; #endif // SERVICEROOT_H diff --git a/src/services/standard/gui/formstandardcategorydetails.cpp b/src/services/standard/gui/formstandardcategorydetails.cpp index 5c78d9958..86c6521a3 100755 --- a/src/services/standard/gui/formstandardcategorydetails.cpp +++ b/src/services/standard/gui/formstandardcategorydetails.cpp @@ -122,7 +122,7 @@ void FormStandardCategoryDetails::apply() { if (m_editableCategory == NULL) { // Add the category. if (new_category->addItself(parent)) { - m_serviceRoot->feedsModel()->reassignNodeToNewParent(new_category, parent); + m_serviceRoot->requestItemReassignment(new_category, parent); accept(); } else { @@ -139,7 +139,7 @@ void FormStandardCategoryDetails::apply() { bool edited = m_editableCategory->editItself(new_category); if (edited) { - m_serviceRoot->feedsModel()->reassignNodeToNewParent(m_editableCategory, new_category->parent()); + m_serviceRoot->requestItemReassignment(m_editableCategory, new_category->parent()); accept(); } else { diff --git a/src/services/standard/gui/formstandardfeeddetails.cpp b/src/services/standard/gui/formstandardfeeddetails.cpp index c6ccde65b..fa7dd493a 100755 --- a/src/services/standard/gui/formstandardfeeddetails.cpp +++ b/src/services/standard/gui/formstandardfeeddetails.cpp @@ -241,7 +241,7 @@ void FormStandardFeedDetails::apply() { if (m_editableFeed == NULL) { // Add the feed. if (new_feed->addItself(parent)) { - m_serviceRoot->feedsModel()->reassignNodeToNewParent(new_feed, parent); + m_serviceRoot->requestItemReassignment(new_feed, parent); accept(); } else { @@ -258,7 +258,7 @@ void FormStandardFeedDetails::apply() { bool edited = m_editableFeed->editItself(new_feed); if (edited) { - m_serviceRoot->feedsModel()->reassignNodeToNewParent(m_editableFeed, new_feed->parent()); + m_serviceRoot->requestItemReassignment(m_editableFeed, new_feed->parent()); accept(); } else { diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index ceca4f418..dc7a940b3 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -100,7 +100,7 @@ bool StandardCategory::performDragDropChange(RootItem *target_item) { category_new->setParent(target_item); if (editItself(category_new)) { - serviceRoot()->feedsModel()->reassignNodeToNewParent(this, target_item); + serviceRoot()->requestItemReassignment(this, target_item); delete category_new; return true; } @@ -120,7 +120,7 @@ bool StandardCategory::editViaGui() { bool StandardCategory::deleteViaGui() { if (removeItself()) { - serviceRoot()->feedsModel()->removeItem(this); + serviceRoot()->requestItemRemoval(this); return true; } else { diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 36e2ad098..91125f8c3 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -116,7 +116,7 @@ bool StandardFeed::editViaGui() { bool StandardFeed::deleteViaGui() { if (removeItself()) { - serviceRoot()->feedsModel()->removeItem(this); + serviceRoot()->requestItemRemoval(this); return true; } else { @@ -445,7 +445,7 @@ bool StandardFeed::performDragDropChange(RootItem *target_item) { feed_new->setParent(target_item); if (editItself(feed_new)) { - serviceRoot()->feedsModel()->reassignNodeToNewParent(this, target_item); + serviceRoot()->requestItemReassignment(this, target_item); delete feed_new; return true; } diff --git a/src/services/standard/standardfeedsimportexportmodel.cpp b/src/services/standard/standardfeedsimportexportmodel.cpp index 837ebc3f6..fd74f1ed8 100755 --- a/src/services/standard/standardfeedsimportexportmodel.cpp +++ b/src/services/standard/standardfeedsimportexportmodel.cpp @@ -167,7 +167,7 @@ bool FeedsImportExportModel::importAsOPML20(const QByteArray &data) { return false; } - StandardServiceRoot *root_item = new StandardServiceRoot(false, NULL, NULL); + StandardServiceRoot *root_item = new StandardServiceRoot(false); QStack model_items; model_items.push(root_item); QStack elements_to_process; elements_to_process.push(opml_document.documentElement().elementsByTagName(QSL("body")).at(0).toElement()); diff --git a/src/services/standard/standardserviceentrypoint.cpp b/src/services/standard/standardserviceentrypoint.cpp index 1f9f11e82..97fa542d1 100755 --- a/src/services/standard/standardserviceentrypoint.cpp +++ b/src/services/standard/standardserviceentrypoint.cpp @@ -59,20 +59,20 @@ QString StandardServiceEntryPoint::code() { return SERVICE_CODE_STD_RSS; } -ServiceRoot *StandardServiceEntryPoint::createNewRoot(FeedsModel *main_model) { +ServiceRoot *StandardServiceEntryPoint::createNewRoot() { // Switch DB. QSqlDatabase database = qApp->database()->connection(QSL("StandardServiceEntryPoint"), DatabaseFactory::FromSettings); QSqlQuery query(database); if (query.exec(QSL("UPDATE Information SET inf_value = 1 WHERE inf_key = 'standard_account_enabled';"))) { - return new StandardServiceRoot(true, main_model); + return new StandardServiceRoot(true); } else { return NULL; } } -QList StandardServiceEntryPoint::initializeSubtree(FeedsModel *main_model) { +QList StandardServiceEntryPoint::initializeSubtree() { // Check DB if standard account is enabled. QSqlDatabase database = qApp->database()->connection(QSL("StandardServiceEntryPoint"), DatabaseFactory::FromSettings); QSqlQuery query(database); @@ -80,7 +80,7 @@ QList StandardServiceEntryPoint::initializeSubtree(FeedsModel *mai if (query.exec(QSL("SELECT inf_value FROM Information WHERE inf_key = 'standard_account_enabled';"))) { if (query.next() && query.value(0).toInt() == 1) { - StandardServiceRoot *root = new StandardServiceRoot(true, main_model); + StandardServiceRoot *root = new StandardServiceRoot(true); roots.append(root); } } diff --git a/src/services/standard/standardserviceentrypoint.h b/src/services/standard/standardserviceentrypoint.h index 8e4904cb4..b99de25a8 100755 --- a/src/services/standard/standardserviceentrypoint.h +++ b/src/services/standard/standardserviceentrypoint.h @@ -34,8 +34,8 @@ class StandardServiceEntryPoint : public ServiceEntryPoint { QIcon icon(); QString code(); - ServiceRoot *createNewRoot(FeedsModel *main_model); - QList initializeSubtree(FeedsModel *main_model); + ServiceRoot *createNewRoot(); + QList initializeSubtree(); }; #endif // STANDARDSERVICEENTRYPOINT_H diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 3c6d63bb5..58ebfc167 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -43,8 +43,8 @@ #include -StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent) - : ServiceRoot(feeds_model, parent), m_recycleBin(new StandardRecycleBin(this)), +StandardServiceRoot::StandardServiceRoot(bool load_from_db, RootItem *parent) + : ServiceRoot(parent), m_recycleBin(new StandardRecycleBin(this)), m_actionExportFeeds(NULL), m_actionImportFeeds(NULL), m_serviceMenu(QList()), m_addItemMenu(QList()), m_feedContextMenu(QList()), m_actionFeedFetchMetadata(NULL) { @@ -54,7 +54,6 @@ StandardServiceRoot::StandardServiceRoot(bool load_from_db, FeedsModel *feeds_mo setCreationDate(QDateTime::currentDateTime()); if (load_from_db) { - loadFromDatabase(); } } @@ -134,10 +133,8 @@ bool StandardServiceRoot::deleteViaGui() { // Switch "existence" flag. bool data_removed = QSqlQuery(connection).exec(QSL("UPDATE Information SET inf_value = 0 WHERE inf_key = 'standard_account_enabled';")); - // TODO: pokračovat - if (data_removed) { - feedsModel()->removeItem(this); + requestItemRemoval(this); } return data_removed; @@ -508,7 +505,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, new_category->clearChildren(); if (new_category->addItself(target_parent)) { - feedsModel()->reassignNodeToNewParent(new_category, target_parent); + requestItemReassignment(new_category, target_parent); // Process all children of this category. original_parents.push(new_category); @@ -542,7 +539,7 @@ bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, // Append this feed and end this iteration. if (new_feed->addItself(target_parent)) { - feedsModel()->reassignNodeToNewParent(new_feed, target_parent); + requestItemReassignment(new_feed, target_parent); } else { delete new_feed; diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 18945401b..0d0903118 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -40,7 +40,7 @@ class StandardServiceRoot : public ServiceRoot { Q_OBJECT public: - explicit StandardServiceRoot(bool load_from_db, FeedsModel *feeds_model, RootItem *parent = NULL); + explicit StandardServiceRoot(bool load_from_db, RootItem *parent = NULL); virtual ~StandardServiceRoot(); // Start/stop root. diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp index 6d5a24c03..e497d30d3 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.cpp +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -58,10 +58,10 @@ QString TtRssServiceEntryPoint::code() { return SERVICE_CODE_TT_RSS; } -ServiceRoot *TtRssServiceEntryPoint::createNewRoot(FeedsModel *main_model) { +ServiceRoot *TtRssServiceEntryPoint::createNewRoot() { return NULL; } -QList TtRssServiceEntryPoint::initializeSubtree(FeedsModel *main_model) { +QList TtRssServiceEntryPoint::initializeSubtree() { return QList(); } diff --git a/src/services/tt-rss/ttrssserviceentrypoint.h b/src/services/tt-rss/ttrssserviceentrypoint.h index 17e9a7635..dcd99616b 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.h +++ b/src/services/tt-rss/ttrssserviceentrypoint.h @@ -35,8 +35,8 @@ class TtRssServiceEntryPoint : public ServiceEntryPoint { QIcon icon(); QString code(); - ServiceRoot *createNewRoot(FeedsModel *main_model); - QList initializeSubtree(FeedsModel *main_model); + ServiceRoot *createNewRoot(); + QList initializeSubtree(); }; #endif // TTRSSSERVICEENTRYPOINT_H diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 2654f6524..0c231832f 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -23,7 +23,7 @@ #include "core/feedsmodel.h" -TtRssServiceRoot::TtRssServiceRoot(FeedsModel *feeds_model, RootItem *parent) : ServiceRoot(feeds_model, parent) { +TtRssServiceRoot::TtRssServiceRoot(RootItem *parent) : ServiceRoot(parent) { // TODO: nadpis se bude měnit podle nastavení uživatelského // jména a serveru tohoto ttrss učtu setTitle(qApp->system()->getUsername() + "@ttrss"); diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 68d0e4f3a..f4f805292 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -29,7 +29,7 @@ class TtRssServiceRoot : public ServiceRoot { Q_OBJECT public: - explicit TtRssServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL); + explicit TtRssServiceRoot(RootItem *parent = NULL); virtual ~TtRssServiceRoot(); QString code(); From f4347810b6359ee47780a389191dd55e61b546a4 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 30 Nov 2015 13:03:28 +0100 Subject: [PATCH 095/203] Another lang update. --- localization/rssguard-cs_CZ.ts | 78 +++++++++++++++++++--------------- localization/rssguard-de_DE.ts | 4 +- localization/rssguard-en_GB.ts | 4 +- localization/rssguard-en_US.ts | 4 +- localization/rssguard-fr_FR.ts | 4 +- localization/rssguard-it_IT.ts | 4 +- localization/rssguard-nl_NL.ts | 4 +- localization/rssguard-sv_SE.ts | 4 +- src/core/feedsmodel.cpp | 2 +- 9 files changed, 59 insertions(+), 49 deletions(-) diff --git a/localization/rssguard-cs_CZ.ts b/localization/rssguard-cs_CZ.ts index c599b7864..00f5ef0f2 100644 --- a/localization/rssguard-cs_CZ.ts +++ b/localization/rssguard-cs_CZ.ts @@ -514,12 +514,12 @@ Klikněte sem pro otevření nadřazeného adresáře. Staženy nové zprávy - Cannot perform drag & drop operation. - + You can't transfer dragged item into different account, this is not supported. + Tažené položky nelze přesouvat mezi účty, toto není podporováno. - You can't transfer dragged item into different account, this is not supported. - + Cannot perform drag & drop operation + Operaci drag & drop nelze vykonat @@ -557,36 +557,37 @@ Klikněte sem pro otevření nadřazeného adresáře. Selected item cannot be edited, this is not (yet?) supported. - + Vybraná položka nemůže být upravena, toto není podporováno. Deleting "%1" - + Maži "%1" You are about to completely delete item "%1". - + Chystáte se zcela vymazat položku "%1". Are you sure? - + Jste si jistý? Cannot delete "%1" - + Nelze smazat "%1" This item cannot be deleted because something critically failed. Submit bug report. - + Tuto položku nelze smazat, protože se něco kriticky porouchalo, nahlašte tuto chybu. This item cannot be deleted, because it does not support it or this functionality is not implemented yet. - + Tuto položku nelze smazat, protože to nepodporuje +nebo tato funkcionality dosud není implementována. Context menu for other items - + Kontextové menu pro ostatní položky @@ -673,39 +674,39 @@ or this functionality is not implemented yet. FormAddAccount Add new account - + Přidat nový účet Details - + Detaily Name - Název + Název Version - Verze + Verze Author - Autor + Autor Description - Popis + Popis Cannot add account - + Účet nelze přidat Some critical error occurred, report this to developers. - + Vyskytla se kritická chyba, nahlaště problém vývojářům. This account can be added only once. - + Tento účet může být přidán pouze jednou. @@ -1959,7 +1960,7 @@ File filter for external e-mail selection dialog. Enable notifications - + Povolit notifikace @@ -2720,7 +2721,7 @@ Přejít na web aplikace a stáhnout jej ručně. Loading of messages from item '%s' failed. - + Načítání zpráv z položky '%s' selhalo. Loading of messages failed, maybe messages could not be downloaded. @@ -2908,10 +2909,16 @@ Přejít na web aplikace a stáhnout jej ručně. + %n other feeds. - - - - + + + ++ %n další kanál. + + ++ %n dalších kanálů. + + ++ %n kanály. @@ -2919,7 +2926,10 @@ Přejít na web aplikace a stáhnout jej ručně. Please, check NEW stuff included in this version by clicking this popup notification. - + Vítá Vás %1. + +Prosím, zkontrolujte novinky +klknutím na tuto notifikaci. Welcome to %1. @@ -2927,7 +2937,7 @@ version by clicking this popup notification. Load initial set of feeds - + Načíst úvodní sadu kanálů @@ -3049,7 +3059,7 @@ Automatický update: %5 StandardServiceRoot This is obligatory service account for standard RSS/RDF/ATOM feeds. - + Toto je účet pro standardní RSS/RDS/ATOM kanály. You started %1 for the first time, now you can load initial set of feeds. @@ -3065,7 +3075,7 @@ Automatický update: %5 This is service account for standard RSS/RDF/ATOM feeds. - + Toto je účet pro standardní RSS/RDS/ATOM kanály. %n unread message(s). @@ -3128,7 +3138,7 @@ Automatický update: %5 anonymous - + anonym @@ -3326,11 +3336,11 @@ Nepřečtené zprávy: %2 Cannot add feed - Nelze přidat kanál + Nelze přidat kanál You cannot add this feed to %1 because standard RSS/ATOM account is not enabled. Enable it first. - + Tento kanál neumí %1 přidat, protože standardní RSS/ATOM účet není aktivován. Je třeba jej aktivovat. diff --git a/localization/rssguard-de_DE.ts b/localization/rssguard-de_DE.ts index b6048b99d..15aa182c5 100644 --- a/localization/rssguard-de_DE.ts +++ b/localization/rssguard-de_DE.ts @@ -503,11 +503,11 @@ Click here to open parent directory. - Cannot perform drag & drop operation. + You can't transfer dragged item into different account, this is not supported. - You can't transfer dragged item into different account, this is not supported. + Cannot perform drag & drop operation diff --git a/localization/rssguard-en_GB.ts b/localization/rssguard-en_GB.ts index ec621f51b..e2ca47af6 100644 --- a/localization/rssguard-en_GB.ts +++ b/localization/rssguard-en_GB.ts @@ -503,11 +503,11 @@ Click here to open parent directory. - Cannot perform drag & drop operation. + You can't transfer dragged item into different account, this is not supported. - You can't transfer dragged item into different account, this is not supported. + Cannot perform drag & drop operation diff --git a/localization/rssguard-en_US.ts b/localization/rssguard-en_US.ts index c5bec6629..807e83f9a 100644 --- a/localization/rssguard-en_US.ts +++ b/localization/rssguard-en_US.ts @@ -503,11 +503,11 @@ Click here to open parent directory. - Cannot perform drag & drop operation. + You can't transfer dragged item into different account, this is not supported. - You can't transfer dragged item into different account, this is not supported. + Cannot perform drag & drop operation diff --git a/localization/rssguard-fr_FR.ts b/localization/rssguard-fr_FR.ts index bf084b1aa..9d64d2a36 100644 --- a/localization/rssguard-fr_FR.ts +++ b/localization/rssguard-fr_FR.ts @@ -503,11 +503,11 @@ Click here to open parent directory. - Cannot perform drag & drop operation. + You can't transfer dragged item into different account, this is not supported. - You can't transfer dragged item into different account, this is not supported. + Cannot perform drag & drop operation diff --git a/localization/rssguard-it_IT.ts b/localization/rssguard-it_IT.ts index 6e51a123f..00592534c 100644 --- a/localization/rssguard-it_IT.ts +++ b/localization/rssguard-it_IT.ts @@ -503,11 +503,11 @@ Click here to open parent directory. - Cannot perform drag & drop operation. + You can't transfer dragged item into different account, this is not supported. - You can't transfer dragged item into different account, this is not supported. + Cannot perform drag & drop operation diff --git a/localization/rssguard-nl_NL.ts b/localization/rssguard-nl_NL.ts index 668f3e1e0..cdb0018d3 100644 --- a/localization/rssguard-nl_NL.ts +++ b/localization/rssguard-nl_NL.ts @@ -509,11 +509,11 @@ Klik hier om map te openen. Nieuw bericht gedownload - Cannot perform drag & drop operation. + You can't transfer dragged item into different account, this is not supported. - You can't transfer dragged item into different account, this is not supported. + Cannot perform drag & drop operation diff --git a/localization/rssguard-sv_SE.ts b/localization/rssguard-sv_SE.ts index 340d6b031..0eff502bb 100644 --- a/localization/rssguard-sv_SE.ts +++ b/localization/rssguard-sv_SE.ts @@ -508,11 +508,11 @@ Klicka här för att öppna målmappen. Nya meddelanden nedladdade - Cannot perform drag & drop operation. + You can't transfer dragged item into different account, this is not supported. - You can't transfer dragged item into different account, this is not supported. + Cannot perform drag & drop operation diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index c92dd72ae..ce322eb5e 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -265,7 +265,7 @@ bool FeedsModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int if (dragged_item_root != target_item_root) { // Transferring of items between different accounts is not possible. - qApp->showGuiMessage(tr("Cannot perform drag & drop operation."), + qApp->showGuiMessage(tr("Cannot perform drag & drop operation"), tr("You can't transfer dragged item into different account, this is not supported."), QSystemTrayIcon::Warning, qApp->mainForm(), From 9c18b30e2419f4513f80fa70ae0bdb3497fc7b87 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 1 Dec 2015 06:29:00 +0100 Subject: [PATCH 096/203] New localization from Elbert, reload. --- localization/rssguard-cs_CZ.ts | 68 ++++----- localization/rssguard-nl_NL.ts | 246 +++++++++++++++++---------------- 2 files changed, 160 insertions(+), 154 deletions(-) diff --git a/localization/rssguard-cs_CZ.ts b/localization/rssguard-cs_CZ.ts index 00f5ef0f2..a089881e9 100644 --- a/localization/rssguard-cs_CZ.ts +++ b/localization/rssguard-cs_CZ.ts @@ -1103,131 +1103,131 @@ nebo tato funkcionality dosud není implementována. Add &new item - + Přidat &novou položku Update &all items - + Aktualizovat &všechny položky Update &selected items - + Aktualizovat &vybrané položky &Edit selected item - + &Upravit vybranou položku &Delete selected item - + Smazat &vybranou položku &Mark selected items as read - + Označit vybrané položky jako &přečtené Mark all messages (without message filters) from selected items as read. - + Označí všechny zprávy (vyjma zprávových filtrů) z vybraných položek jako přečtené. &Mark selected items as unread - + Označit vybrané položky jako &nepřečtené Mark all messages (without message filters) from selected items as unread. - + Označí všechny zprávy (vyjma zprávových filtrů) z vybraných položek jako nepřečtené. &Clean selected items - + &Vyčistit vybrané položky Deletes all messages from selected items. - + Smaže všechny zprávy z vybraných položek (umístí je do koše). &Mark all items as &read - + Označit všechno jako &přečtené Marks all messages in all items read. This does not take message filters into account. - + Označí zcela všechny zprávy (vyjma odpadkových košů) jako přečtené. View selected items in &newspaper mode - + Zobrazit vybrané položky v &novinovém náhledu Displays all messages from selected item in a new "newspaper mode" tab. Note that messages are not set as read automatically. - + Zobrazí všechny zprávy ze vybraných položek v "novinovém náhledu". Zprávy jsou automaticky označeny jako přečtené. &Clean all items - + &Vyčistit všechny položky Deletes all messages from all items. - + Smaže zprávy ze všech položek (vyjma odpadkových košů). Select &next item - + Vybrat &další položku Select &previous item - + Vybrat &předchozí položku Show only unread items - + Zobrazit pouze položky s nepřečtenými zprávami &Expand/collapse selected item - + &Rozbalit/sbalit položku &Add new service account - + &Přidat nový účet &Restore selected messages - + &Obnovit vybrané zprávy No possible actions - + Žádná možná akce Feeds && categories && accounts - + Kanály && zprávy && účty &Recycle bin(s) - + &Odpadkové koše &Restore all recycle bins - + &Obnovit všechn ze všech odp. košů &Empty all recycle bins - + &Vyprázdnit všechny odp. koše Select next &unread message - + Vybrat další &nepřečtenou zprávu No recycle bin - + Žádný odpadkový koš Restore recycle bin - + Obnovit odp. koš Empty recycle bin - + Vyprázdnit odp. koš @@ -2721,11 +2721,11 @@ Přejít na web aplikace a stáhnout jej ručně. Loading of messages from item '%s' failed. - Načítání zpráv z položky '%s' selhalo. + Načítání zpráv z položky '%s' selhalo. Loading of messages failed, maybe messages could not be downloaded. - + Načítání zpráv selhalo, možná zprávy nemohly být staženy. diff --git a/localization/rssguard-nl_NL.ts b/localization/rssguard-nl_NL.ts index cdb0018d3..94cb3b1c1 100644 --- a/localization/rssguard-nl_NL.ts +++ b/localization/rssguard-nl_NL.ts @@ -33,7 +33,7 @@ Address - Adres: + Adres @@ -183,11 +183,11 @@ Merk ook op dat sommige hulpbronnen worden gecached door de interne web browser. Settings file not copied to output directory successfully. - Instellingen van bestand niet succesvol gekopieerd naar uitvoermap + Instellingen van bestand niet succesvol gekopieerd naar uitvoermap. Database file not copied to output directory successfully. - Databasebestand niet succesvol gekopieerd naar uitvoermap + Databasebestand niet succesvol gekopieerd naar uitvoermap. Database restoration was not initiated. Make sure that output directory is writable. @@ -219,7 +219,7 @@ Gelezen berichten gewist... Recycle bin purged... - Prullenbak gewist.. + Prullenbak gewist... Removing old messages... @@ -277,10 +277,10 @@ Gelezen berichten gewist... Click me to add feeds from this website. This website contains %n feed(s). - Klik hier om feeds van deze website toe tevoegen -Deze website bevat % n feed. - Klik hier om feeds van deze website toe tevoegen -Deze website bevat % n feed(s). + Klik hier om feeds van deze website toe tevoegen. +Deze website bevat %n feed. + Klik hier om feeds van deze website toe tevoegen. +Deze website bevat %n feeds. @@ -416,7 +416,7 @@ Klik hier om map te openen. Downloading %n file(s)... - Dowloading %1 bestand... + Dowloading %n bestand... Downloading %n bestanden... @@ -482,8 +482,8 @@ Klik hier om map te openen. I will auto-update %n feed(s). - Auto-update van %n feed - Auto-update van %n feed(s) + Auto-update van %n feed. + Auto-update van %n feeds. @@ -510,11 +510,11 @@ Klik hier om map te openen. You can't transfer dragged item into different account, this is not supported. - + Je kan geen gesleepte item overdragen naar een ander account, dir wordt niet ondersteunt. Cannot perform drag & drop operation - + Kan de drag & drop bewerking niet uitvoeren @@ -552,36 +552,37 @@ Klik hier om map te openen. Selected item cannot be edited, this is not (yet?) supported. - + Geselecteerde item kun je niet bewerken,dit wordt nog (niet) ondersteunt. Deleting "%1" - + Verwijder "%1" You are about to completely delete item "%1". - + Je staat op het punt om gehele item "%1" te verwijderen. Are you sure? - + Weet je het zeker? Cannot delete "%1" - + Kan "%1" niet verwijderen This item cannot be deleted because something critically failed. Submit bug report. - + Deze item kan niet worden verwijderd omdat het ergens fout ging. Meld deze bug. This item cannot be deleted, because it does not support it or this functionality is not implemented yet. - + Deze item kan niet worden verwijderd omdat het niet wordt ondersteunt +of deze functie bestaat nog niet. Context menu for other items - + Invoegen van andere items @@ -661,46 +662,46 @@ or this functionality is not implemented yet. <body>%5 is a (very) tiny feed reader.<br><br>This software is distributed under the terms of GNU General Public License, version 3.<br><br>Contacts:<ul><li><a href="mailto://%1">%1</a> ~e-mail</li><li><a href="%2">%2</a> ~website</li></ul>You can obtain source code for %5 from its website.<br><br><br>Copyright (C) 2011-%3 %4</body> - + <body>%5 is een (zeer) makelijk te gebruiken feed lezer.<br><br>Dit programma is beschikbaar onder te termen van de GNU General Public License, versie 3.<br><br>Contact:<ul><li><a href="mailto://%1">%1</a> ~e-mail</li><li><a href="%2">%2</a> ~Website</li><li>U kunt de broncode voor %5 downloaden van de website.<br><br><br>Auteursrecht (C) 2011-%3 %4</body> FormAddAccount Add new account - + Voeg nieuw account toe Details - + Gegevens Name - Naam + Naam Version - Versie + Versie Author - Auteur + Auteur Description - Omschrijving + Omschrijving Cannot add account - + Kan account niet toevoegen Some critical error occurred, report this to developers. - + Enkele kritieke fouten opgetreden, vermeld dit bij de ontwikkelaars. This account can be added only once. - + Dit account kan maar 1 maal worden toegevoegd. @@ -775,7 +776,7 @@ or this functionality is not implemented yet. Good destination directory is specified. - Juiste bestemmingsmap is opgegeven + Juiste bestemmingsmap is opgegeven. @@ -791,8 +792,8 @@ or this functionality is not implemented yet. day(s) - dag - dagen + dag + dagen @@ -817,7 +818,7 @@ or this functionality is not implemented yet. I am ready. - Ik ben klaar + Het is klaar. Database cleanup is running. @@ -1056,7 +1057,7 @@ or this functionality is not implemented yet. Report a bug (BitBucket)... - Rapporteer een &bug (Bitbucket)... + Rapporteer een bug (Bitbucket)... &Donate via PayPal @@ -1076,7 +1077,7 @@ or this functionality is not implemented yet. &Backup database/settings - Backup database/instellingen + &Backup database/instellingen Switch message list layout orientation @@ -1096,131 +1097,131 @@ or this functionality is not implemented yet. Add &new item - + Voeg &nieuw item toe Update &all items - + &Alle items bijwerken Update &selected items - + &Geselecteerde items bijwerken &Edit selected item - + &Bewerk geselecteerde item &Delete selected item - + &Verwijder geselecteerde item &Mark selected items as read - + &Markeer geselecteerde berichten als gelezen Mark all messages (without message filters) from selected items as read. - + Markeer alle berichten (zonder berichtenfilters) van geselecteerde items als gelezen. &Mark selected items as unread - + &Markeer geselecteerde item als ongelezen Mark all messages (without message filters) from selected items as unread. - + Markeer alle berichten (zonder berichtenfilters) van geselecteerde items als ongelezen. &Clean selected items - + Geselecteerde items &opschonen Deletes all messages from selected items. - + Verwijder alle berichten van geselecteerde items. &Mark all items as &read - + &Markeer alle items als &gelezen Marks all messages in all items read. This does not take message filters into account. - + Markeer alle berichten in alle items als gelezen. Dit neemt geen berichtenfilters mee in account. View selected items in &newspaper mode - + Bekijk geselecteerde items in kra&ntweergave Displays all messages from selected item in a new "newspaper mode" tab. Note that messages are not set as read automatically. - + Toon alle berichten van geselecteerde item in een nieuwe "krantweergave" tabblad.Let op dat berichten niet automatisch als gelezen zijn ingesteld. &Clean all items - + Alle items &opschonen Deletes all messages from all items. - + Verwijder alle berichten van alle items. Select &next item - + Selecteer &volgende item Select &previous item - + Selecteer &vorige item Show only unread items - + Toon alleen ongelezen items &Expand/collapse selected item - + &Uitklappen/inklappen geselecteerde item &Add new service account - + &Voeg nieuwe service account toe &Restore selected messages - + &Herstel geselecteerde berichten No possible actions - + Geen mogelijke acties Feeds && categories && accounts - + Feeds && categorieën && accounts &Recycle bin(s) - + &Prullenbak &Restore all recycle bins - + &Hestel alle prullenbakken &Empty all recycle bins - + &Leeg alle prullenbakken Select next &unread message - + Selecteer volgende &ongelezen bericht No recycle bin - + Geeen vuilnisbak Restore recycle bin - + Hestel vuilnisbak Empty recycle bin - + Leeg vuilnisbak @@ -1886,10 +1887,8 @@ Open nieuw webbrowser pagina(sleep muis omlaag). • %1 - title of selected message, • %2 - body of selected message. Plaatshouders: - -•% 1 - titel van het geselecteerde bericht, - -•% 2 - body van geselecteerde bericht. + •.%1 - titel van het geselecteerde bericht, + • %2 - body van geselecteerde bericht. Save all downloaded files to @@ -1913,7 +1912,7 @@ Open nieuw webbrowser pagina(sleep muis omlaag). Working database is ok. - Werkende database is ok + Werkende database is ok. Notification position @@ -1957,11 +1956,11 @@ Open nieuw webbrowser pagina(sleep muis omlaag). E-mail - + E-mail Enable notifications - + Meldingen aanzetten @@ -2428,7 +2427,7 @@ Open nieuw webbrowser pagina(sleep muis omlaag). Import feeds - Importeer feeds. + Importeer feeds OPML 2.0 files (*.opml) @@ -2913,9 +2912,13 @@ Ga naar RRSguard website en download het handmatig. + %n other feeds. - - - + + + ++ %n andere feed. + + ++ %n andere feeds. @@ -2923,15 +2926,18 @@ Ga naar RRSguard website en download het handmatig. Please, check NEW stuff included in this version by clicking this popup notification. - + Welkom bij %1. + +Check voor NIEUW materiaal in deze versie +door te clicken op deze popup melding. Welcome to %1. - Welkom bij %1 %2. {1.?} + Welkom bij %1. Load initial set of feeds - + Laad eerste set van de feeds @@ -2989,9 +2995,9 @@ Deze categorie bevat geen nested items. %n unread message(s). Tooltip for "unread" column of feed list. - - - + + %n ongelezen bericht. + %n ongelezen berichten. @@ -2999,26 +3005,26 @@ Deze categorie bevat geen nested items. StandardFeed Metadata not fetched - Metadata niet opgehaald + Metadata niet opgehaald Metadata was not fetched because: %1. - Metadate niet opgehaald omdat: %1. + Metadate niet opgehaald omdat: %1. does not use auto-update Describes feed auto-update status. - automatisch bijwerken niet gebruiken + automatisch bijwerken niet gebruiken uses global settings Describes feed auto-update status. - gebruik algemene instellingen + gebruik algemene instellingen uses specific settings (%n minute(s) to next auto-update) Describes feed auto-update status. - + gebruik specifieke instellingen (%n minuut voor volgende automatische update) gebruik specifieke instellingen (%n minuten voor volgende automatische update) @@ -3030,18 +3036,18 @@ Network status: %6 Encoding: %4 Auto-update status: %5 Tooltip for feed. - %1 (%2)%3 + %1 (%2)%3 Netwerk status: %6 Coderen: %4 -Auto-update status: 55 +Auto-update status: %5 %n unread message(s). Tooltip for "unread" column of feed list. - - - + + %n ongelezen bericht. + %n ongelezen berichten. @@ -3049,59 +3055,59 @@ Auto-update status: 55 StandardServiceRoot This is obligatory service account for standard RSS/RDF/ATOM feeds. - + Dit is verplichte service account voor standaard RSS/RDF/ATOM feeds. You started %1 for the first time, now you can load initial set of feeds. - Je startte %1 voor de eerste keer, nu kun je de eerste set van de feeds laden + Je start %1 voor de eerste keer, nu kun je de eerste set van de feeds laden. Do you want to load initial set of feeds? - Wil je de eerste set van feeds laden? + Wil je de eerste set van feeds laden? Error when loading initial feeds - Fout bij het laden van de eerste feeds + Fout bij het laden van de eerste feeds This is service account for standard RSS/RDF/ATOM feeds. - + Dit is verplichte service account voor standaard RSS/RDF/ATOM feeds. %n unread message(s). Tooltip for "unread" column of feed list. - - - + + %n ongelezen bericht. + %n ongelezen berichten. Fetch metadata - Ophalen van metadata + Ophalen van metadata Import successfull, but some feeds/categories were not imported due to error. - Importeren succesvol, maar sommige feeds / categorieën waren niet goed geïmporteerd door fouten. + Importeren succesvol, maar sommige feeds / categorieën waren niet goed geïmporteerd door fouten. Import was completely successfull. - Importeren is helemaal geslaagd. + Importeren is helemaal geslaagd. Add new category - Voeg nieuwe categorie toe + Voeg nieuwe categorie toe Add new feed - Voeg nieuw feed toe + Voeg nieuw feed toe Export feeds - Exporteer feeds + Exporteer feeds Import feeds - Importeer feeds. + Importeer feeds @@ -3127,7 +3133,7 @@ Auto-update status: 55 anonymous - + Anoniem @@ -3241,14 +3247,14 @@ Ongelezen nieuws: %2 TtRssServiceRoot This is service account TT-RSS (TinyTiny RSS) server. - + Dit is een service account van TT-RSS (TinyTiny RSS) server. %n unread message(s). Tooltip for "unread" column of feed list. - - - + + %n ongelezen bericht. + %n ongelezen berichten. @@ -3325,11 +3331,11 @@ Ongelezen nieuws: %2 Cannot add feed - Kan geen feed toevoegen + Kan geen feed toevoegen You cannot add this feed to %1 because standard RSS/ATOM account is not enabled. Enable it first. - + Kan geen feed toevoegen aan %1 omdat de standaard RSS/ATOM account niet aanstaat. Zit die eerst aan. @@ -3416,7 +3422,7 @@ Ongelezen nieuws: %2 Open the hyperlink in external browser. - Open de hyperlink in externe browser + Open de hyperlink in externe browser. Print @@ -3444,7 +3450,7 @@ Ongelezen nieuws: %2 Save target as... - Doel opslaan als.. + Doel opslaan als... Download content from the hyperlink. From 3271c5682703ef97613c402e5e0931d63e29bf5b Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 1 Dec 2015 06:46:58 +0100 Subject: [PATCH 097/203] Added JSON libraries to support TT-RSS. --- CMakeLists.txt | 3 + src/qt-json/json.cpp | 602 +++++++++++++++++++++++++++++++++++++++++++ src/qt-json/json.h | 134 ++++++++++ 3 files changed, 739 insertions(+) create mode 100755 src/qt-json/json.cpp create mode 100755 src/qt-json/json.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 816219b93..8d04f27b3 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -343,6 +343,9 @@ set(APP_SOURCES src/qtsingleapplication/qtsinglecoreapplication.cpp src/qtsingleapplication/qtsingleapplication.cpp + # QT-JSON sources. + src/qt-json/json.cpp + # GUI sources. src/gui/dialogs/formmain.cpp src/gui/dialogs/formsettings.cpp diff --git a/src/qt-json/json.cpp b/src/qt-json/json.cpp new file mode 100755 index 000000000..f7ed3aa2e --- /dev/null +++ b/src/qt-json/json.cpp @@ -0,0 +1,602 @@ +/** + * QtJson - A simple class for parsing JSON data into a QVariant hierarchies and vice-versa. + * Copyright (C) 2011 Eeli Reilin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file json.cpp + */ + +#include +#include "json.h" + +namespace QtJson { + static QString dateFormat, dateTimeFormat; + + static QString sanitizeString(QString str); + static QByteArray join(const QList &list, const QByteArray &sep); + static QVariant parseValue(const QString &json, int &index, bool &success); + static QVariant parseObject(const QString &json, int &index, bool &success); + static QVariant parseArray(const QString &json, int &index, bool &success); + static QVariant parseString(const QString &json, int &index, bool &success); + static QVariant parseNumber(const QString &json, int &index); + static int lastIndexOfNumber(const QString &json, int index); + static void eatWhitespace(const QString &json, int &index); + static int lookAhead(const QString &json, int index); + static int nextToken(const QString &json, int &index); + + template + QByteArray serializeMap(const T &map, bool &success) { + QByteArray str = "{ "; + QList pairs; + for (typename T::const_iterator it = map.begin(), itend = map.end(); it != itend; ++it) { + QByteArray serializedValue = serialize(it.value()); + if (serializedValue.isNull()) { + success = false; + break; + } + pairs << sanitizeString(it.key()).toUtf8() + " : " + serializedValue; + } + + str += join(pairs, ", "); + str += " }"; + return str; + } + + void insert(QVariant &v, const QString &key, const QVariant &value); + void append(QVariant &v, const QVariant &value); + + template + void cloneMap(QVariant &json, const T &map) { + for (typename T::const_iterator it = map.begin(), itend = map.end(); it != itend; ++it) { + insert(json, it.key(), (*it)); + } + } + + template + void cloneList(QVariant &json, const T &list) { + for (typename T::const_iterator it = list.begin(), itend = list.end(); it != itend; ++it) { + append(json, (*it)); + } + } + + /** + * parse + */ + QVariant parse(const QString &json) { + bool success = true; + return parse(json, success); + } + + /** + * parse + */ + QVariant parse(const QString &json, bool &success) { + success = true; + + // Return an empty QVariant if the JSON data is either null or empty + if (!json.isNull() || !json.isEmpty()) { + QString data = json; + // We'll start from index 0 + int index = 0; + + // Parse the first value + QVariant value = parseValue(data, index, success); + + // Return the parsed value + return value; + } else { + // Return the empty QVariant + return QVariant(); + } + } + + /** + * clone + */ + QVariant clone(const QVariant &data) { + QVariant v; + + if (data.type() == QVariant::Map) { + cloneMap(v, data.toMap()); + } else if (data.type() == QVariant::Hash) { + cloneMap(v, data.toHash()); + } else if (data.type() == QVariant::List) { + cloneList(v, data.toList()); + } else if (data.type() == QVariant::StringList) { + cloneList(v, data.toStringList()); + } else { + v = QVariant(data); + } + + return v; + } + + /** + * insert value (map case) + */ + void insert(QVariant &v, const QString &key, const QVariant &value) { + if (!v.canConvert()) v = QVariantMap(); + QVariantMap *p = (QVariantMap *)v.data(); + p->insert(key, clone(value)); + } + + /** + * append value (list case) + */ + void append(QVariant &v, const QVariant &value) { + if (!v.canConvert()) v = QVariantList(); + QVariantList *p = (QVariantList *)v.data(); + p->append(value); + } + + QByteArray serialize(const QVariant &data) { + bool success = true; + return serialize(data, success); + } + + QByteArray serialize(const QVariant &data, bool &success) { + QByteArray str; + success = true; + + if (!data.isValid()) { // invalid or null? + str = "null"; + } else if ((data.type() == QVariant::List) || + (data.type() == QVariant::StringList)) { // variant is a list? + QList values; + const QVariantList list = data.toList(); + Q_FOREACH(const QVariant& v, list) { + QByteArray serializedValue = serialize(v); + if (serializedValue.isNull()) { + success = false; + break; + } + values << serializedValue; + } + + str = "[ " + join( values, ", " ) + " ]"; + } else if (data.type() == QVariant::Hash) { // variant is a hash? + str = serializeMap<>(data.toHash(), success); + } else if (data.type() == QVariant::Map) { // variant is a map? + str = serializeMap<>(data.toMap(), success); + } else if ((data.type() == QVariant::String) || + (data.type() == QVariant::ByteArray)) {// a string or a byte array? + str = sanitizeString(data.toString()).toUtf8(); + } else if (data.type() == QVariant::Double) { // double? + double value = data.toDouble(&success); + if (success) { + str = QByteArray::number(value, 'g'); + if (!str.contains(".") && ! str.contains("e")) { + str += ".0"; + } + } + } else if (data.type() == QVariant::Bool) { // boolean value? + str = data.toBool() ? "true" : "false"; + } else if (data.type() == QVariant::ULongLong) { // large unsigned number? + str = QByteArray::number(data.value()); + } else if (data.canConvert()) { // any signed number? + str = QByteArray::number(data.value()); + } else if (data.canConvert()) { //TODO: this code is never executed because all smaller types can be converted to qlonglong + str = QString::number(data.value()).toUtf8(); + } else if (data.type() == QVariant::DateTime) { // datetime value? + str = sanitizeString(dateTimeFormat.isEmpty() + ? data.toDateTime().toString() + : data.toDateTime().toString(dateTimeFormat)).toUtf8(); + } else if (data.type() == QVariant::Date) { // date value? + str = sanitizeString(dateTimeFormat.isEmpty() + ? data.toDate().toString() + : data.toDate().toString(dateFormat)).toUtf8(); + } else if (data.canConvert()) { // can value be converted to string? + // this will catch QUrl, ... (all other types which can be converted to string) + str = sanitizeString(data.toString()).toUtf8(); + } else { + success = false; + } + + if (success) { + return str; + } + return QByteArray(); + } + + QString serializeStr(const QVariant &data) { + return QString::fromUtf8(serialize(data)); + } + + QString serializeStr(const QVariant &data, bool &success) { + return QString::fromUtf8(serialize(data, success)); + } + + + /** + * \enum JsonToken + */ + enum JsonToken { + JsonTokenNone = 0, + JsonTokenCurlyOpen = 1, + JsonTokenCurlyClose = 2, + JsonTokenSquaredOpen = 3, + JsonTokenSquaredClose = 4, + JsonTokenColon = 5, + JsonTokenComma = 6, + JsonTokenString = 7, + JsonTokenNumber = 8, + JsonTokenTrue = 9, + JsonTokenFalse = 10, + JsonTokenNull = 11 + }; + + static QString sanitizeString(QString str) { + str.replace(QLatin1String("\\"), QLatin1String("\\\\")); + str.replace(QLatin1String("\""), QLatin1String("\\\"")); + str.replace(QLatin1String("\b"), QLatin1String("\\b")); + str.replace(QLatin1String("\f"), QLatin1String("\\f")); + str.replace(QLatin1String("\n"), QLatin1String("\\n")); + str.replace(QLatin1String("\r"), QLatin1String("\\r")); + str.replace(QLatin1String("\t"), QLatin1String("\\t")); + return QString(QLatin1String("\"%1\"")).arg(str); + } + + static QByteArray join(const QList &list, const QByteArray &sep) { + QByteArray res; + Q_FOREACH(const QByteArray &i, list) { + if (!res.isEmpty()) { + res += sep; + } + res += i; + } + return res; + } + + /** + * parseValue + */ + static QVariant parseValue(const QString &json, int &index, bool &success) { + // Determine what kind of data we should parse by + // checking out the upcoming token + switch(lookAhead(json, index)) { + case JsonTokenString: + return parseString(json, index, success); + case JsonTokenNumber: + return parseNumber(json, index); + case JsonTokenCurlyOpen: + return parseObject(json, index, success); + case JsonTokenSquaredOpen: + return parseArray(json, index, success); + case JsonTokenTrue: + nextToken(json, index); + return QVariant(true); + case JsonTokenFalse: + nextToken(json, index); + return QVariant(false); + case JsonTokenNull: + nextToken(json, index); + return QVariant(); + case JsonTokenNone: + break; + } + + // If there were no tokens, flag the failure and return an empty QVariant + success = false; + return QVariant(); + } + + /** + * parseObject + */ + static QVariant parseObject(const QString &json, int &index, bool &success) { + QVariantMap map; + int token; + + // Get rid of the whitespace and increment index + nextToken(json, index); + + // Loop through all of the key/value pairs of the object + bool done = false; + while (!done) { + // Get the upcoming token + token = lookAhead(json, index); + + if (token == JsonTokenNone) { + success = false; + return QVariantMap(); + } else if (token == JsonTokenComma) { + nextToken(json, index); + } else if (token == JsonTokenCurlyClose) { + nextToken(json, index); + return map; + } else { + // Parse the key/value pair's name + QString name = parseString(json, index, success).toString(); + + if (!success) { + return QVariantMap(); + } + + // Get the next token + token = nextToken(json, index); + + // If the next token is not a colon, flag the failure + // return an empty QVariant + if (token != JsonTokenColon) { + success = false; + return QVariant(QVariantMap()); + } + + // Parse the key/value pair's value + QVariant value = parseValue(json, index, success); + + if (!success) { + return QVariantMap(); + } + + // Assign the value to the key in the map + map[name] = value; + } + } + + // Return the map successfully + return QVariant(map); + } + + /** + * parseArray + */ + static QVariant parseArray(const QString &json, int &index, bool &success) { + QVariantList list; + + nextToken(json, index); + + bool done = false; + while(!done) { + int token = lookAhead(json, index); + + if (token == JsonTokenNone) { + success = false; + return QVariantList(); + } else if (token == JsonTokenComma) { + nextToken(json, index); + } else if (token == JsonTokenSquaredClose) { + nextToken(json, index); + break; + } else { + QVariant value = parseValue(json, index, success); + if (!success) { + return QVariantList(); + } + list.push_back(value); + } + } + + return QVariant(list); + } + + /** + * parseString + */ + static QVariant parseString(const QString &json, int &index, bool &success) { + QString s; + QChar c; + + eatWhitespace(json, index); + + c = json[index++]; + + bool complete = false; + while(!complete) { + if (index == json.size()) { + break; + } + + c = json[index++]; + + if (c == '\"') { + complete = true; + break; + } else if (c == '\\') { + if (index == json.size()) { + break; + } + + c = json[index++]; + + if (c == '\"') { + s.append('\"'); + } else if (c == '\\') { + s.append('\\'); + } else if (c == '/') { + s.append('/'); + } else if (c == 'b') { + s.append('\b'); + } else if (c == 'f') { + s.append('\f'); + } else if (c == 'n') { + s.append('\n'); + } else if (c == 'r') { + s.append('\r'); + } else if (c == 't') { + s.append('\t'); + } else if (c == 'u') { + int remainingLength = json.size() - index; + if (remainingLength >= 4) { + QString unicodeStr = json.mid(index, 4); + + int symbol = unicodeStr.toInt(0, 16); + + s.append(QChar(symbol)); + + index += 4; + } else { + break; + } + } + } else { + s.append(c); + } + } + + if (!complete) { + success = false; + return QVariant(); + } + + return QVariant(s); + } + + /** + * parseNumber + */ + static QVariant parseNumber(const QString &json, int &index) { + eatWhitespace(json, index); + + int lastIndex = lastIndexOfNumber(json, index); + int charLength = (lastIndex - index) + 1; + QString numberStr; + + numberStr = json.mid(index, charLength); + + index = lastIndex + 1; + bool ok; + + if (numberStr.contains('.')) { + return QVariant(numberStr.toDouble(NULL)); + } else if (numberStr.startsWith('-')) { + int i = numberStr.toInt(&ok); + if (!ok) { + qlonglong ll = numberStr.toLongLong(&ok); + return ok ? ll : QVariant(numberStr); + } + return i; + } else { + uint u = numberStr.toUInt(&ok); + if (!ok) { + qulonglong ull = numberStr.toULongLong(&ok); + return ok ? ull : QVariant(numberStr); + } + return u; + } + } + + /** + * lastIndexOfNumber + */ + static int lastIndexOfNumber(const QString &json, int index) { + int lastIndex; + + for(lastIndex = index; lastIndex < json.size(); lastIndex++) { + if (QString("0123456789+-.eE").indexOf(json[lastIndex]) == -1) { + break; + } + } + + return lastIndex -1; + } + + /** + * eatWhitespace + */ + static void eatWhitespace(const QString &json, int &index) { + for(; index < json.size(); index++) { + if (QString(" \t\n\r").indexOf(json[index]) == -1) { + break; + } + } + } + + /** + * lookAhead + */ + static int lookAhead(const QString &json, int index) { + int saveIndex = index; + return nextToken(json, saveIndex); + } + + /** + * nextToken + */ + static int nextToken(const QString &json, int &index) { + eatWhitespace(json, index); + + if (index == json.size()) { + return JsonTokenNone; + } + + QChar c = json[index]; + index++; + switch(c.toLatin1()) { + case '{': return JsonTokenCurlyOpen; + case '}': return JsonTokenCurlyClose; + case '[': return JsonTokenSquaredOpen; + case ']': return JsonTokenSquaredClose; + case ',': return JsonTokenComma; + case '"': return JsonTokenString; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '-': return JsonTokenNumber; + case ':': return JsonTokenColon; + } + index--; // ^ WTF? + + int remainingLength = json.size() - index; + + // True + if (remainingLength >= 4) { + if (json[index] == 't' && json[index + 1] == 'r' && + json[index + 2] == 'u' && json[index + 3] == 'e') { + index += 4; + return JsonTokenTrue; + } + } + + // False + if (remainingLength >= 5) { + if (json[index] == 'f' && json[index + 1] == 'a' && + json[index + 2] == 'l' && json[index + 3] == 's' && + json[index + 4] == 'e') { + index += 5; + return JsonTokenFalse; + } + } + + // Null + if (remainingLength >= 4) { + if (json[index] == 'n' && json[index + 1] == 'u' && + json[index + 2] == 'l' && json[index + 3] == 'l') { + index += 4; + return JsonTokenNull; + } + } + + return JsonTokenNone; + } + + void setDateTimeFormat(const QString &format) { + dateTimeFormat = format; + } + + void setDateFormat(const QString &format) { + dateFormat = format; + } + + QString getDateTimeFormat() { + return dateTimeFormat; + } + + QString getDateFormat() { + return dateFormat; + } + +} //end namespace diff --git a/src/qt-json/json.h b/src/qt-json/json.h new file mode 100755 index 000000000..728328166 --- /dev/null +++ b/src/qt-json/json.h @@ -0,0 +1,134 @@ +/** + * QtJson - A simple class for parsing JSON data into a QVariant hierarchies and vice-versa. + * Copyright (C) 2011 Eeli Reilin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file json.h + */ + +#ifndef JSON_H +#define JSON_H + +#include +#include + + +/** + * \namespace QtJson + * \brief A JSON data parser + * + * Json parses a JSON data into a QVariant hierarchy. + */ +namespace QtJson { + typedef QVariantMap JsonObject; + typedef QVariantList JsonArray; + + /** + * Clone a JSON object (makes a deep copy) + * + * \param data The JSON object + */ + QVariant clone(const QVariant &data); + + /** + * Insert value to JSON object (QVariantMap) + * + * \param v The JSON object + * \param key The key + * \param value The value + */ + void insert(QVariant &v, const QString &key, const QVariant &value); + + /** + * Append value to JSON array (QVariantList) + * + * \param v The JSON array + * \param value The value + */ + void append(QVariant &v, const QVariant &value); + + /** + * Parse a JSON string + * + * \param json The JSON data + */ + QVariant parse(const QString &json); + + /** + * Parse a JSON string + * + * \param json The JSON data + * \param success The success of the parsing + */ + QVariant parse(const QString &json, bool &success); + + /** + * This method generates a textual JSON representation + * + * \param data The JSON data generated by the parser. + * + * \return QByteArray Textual JSON representation in UTF-8 + */ + QByteArray serialize(const QVariant &data); + + /** + * This method generates a textual JSON representation + * + * \param data The JSON data generated by the parser. + * \param success The success of the serialization + * + * \return QByteArray Textual JSON representation in UTF-8 + */ + QByteArray serialize(const QVariant &data, bool &success); + + /** + * This method generates a textual JSON representation + * + * \param data The JSON data generated by the parser. + * + * \return QString Textual JSON representation + */ + QString serializeStr(const QVariant &data); + + /** + * This method generates a textual JSON representation + * + * \param data The JSON data generated by the parser. + * \param success The success of the serialization + * + * \return QString Textual JSON representation + */ + QString serializeStr(const QVariant &data, bool &success); + + /** + * This method sets date(time) format to be used for QDateTime::toString + * If QString is empty, Qt::TextDate is used. + * + * \param format The JSON data generated by the parser. + */ + void setDateTimeFormat(const QString& format); + void setDateFormat(const QString& format); + + /** + * This method gets date(time) format to be used for QDateTime::toString + * If QString is empty, Qt::TextDate is used. + */ + QString getDateTimeFormat(); + QString getDateFormat(); +} + +#endif //JSON_H From f634857f6eff0b4150a5d90a66c87aa1580d085f Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 1 Dec 2015 07:30:26 +0100 Subject: [PATCH 098/203] Added ability to synchronous/asynchronous HTTP POST to be used by TT-RSS plugin. --- src/main.cpp | 2 +- src/network-web/downloader.cpp | 44 ++++++++++++++++++++++++++++-- src/network-web/downloader.h | 7 +++++ src/network-web/networkfactory.cpp | 20 ++++++++++++++ src/network-web/networkfactory.h | 3 ++ src/services/tt-rss/definitions.h | 36 ++++++++++++++++++++++++ 6 files changed, 108 insertions(+), 4 deletions(-) mode change 100644 => 100755 src/network-web/networkfactory.h create mode 100755 src/services/tt-rss/definitions.h diff --git a/src/main.cpp b/src/main.cpp index b6e79d56f..f78478c22 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -100,7 +100,7 @@ int main(int argc, char *argv[]) { main_window.setWindowTitle(APP_LONG_NAME); // Now is a good time to initialize dynamic keyboard shortcuts. - DynamicShortcuts::load(qApp->userActions()); + DynamicShortcuts::load(qApp->userActions()); // Display main window. if (qApp->settings()->value(GROUP(GUI), SETTING(GUI::MainWindowStartsHidden)).toBool() && SystemTrayIcon::isSystemTrayActivated()) { diff --git a/src/network-web/downloader.cpp b/src/network-web/downloader.cpp index 0851c7fa0..1c468a94b 100755 --- a/src/network-web/downloader.cpp +++ b/src/network-web/downloader.cpp @@ -24,8 +24,8 @@ Downloader::Downloader(QObject *parent) : QObject(parent), m_activeReply(NULL), m_downloadManager(new SilentNetworkAccessManager(this)), - m_timer(new QTimer(this)), m_customHeaders(QHash()), m_lastOutputData(QByteArray()), - m_lastOutputError(QNetworkReply::NoError), m_lastContentType(QVariant()) { + m_timer(new QTimer(this)), m_customHeaders(QHash()), m_inputData(QByteArray()), + m_lastOutputData(QByteArray()), m_lastOutputError(QNetworkReply::NoError), m_lastContentType(QVariant()) { m_timer->setInterval(DOWNLOAD_TIMEOUT); m_timer->setSingleShot(true); @@ -66,8 +66,33 @@ void Downloader::downloadFile(const QString &url, int timeout, bool protected_co runGetRequest(request); } +void Downloader::uploadData(const QString &url, const QByteArray &data, int timeout) { + QNetworkRequest request; + QString non_const_url = url; + + foreach (const QByteArray &header_name, m_customHeaders.keys()) { + request.setRawHeader(header_name, m_customHeaders.value(header_name)); + } + + m_inputData = data; + + // Set url for this request and fire it up. + m_timer->setInterval(timeout); + + if (non_const_url.startsWith(URI_SCHEME_FEED)) { + qDebug("Replacing URI schemes for '%s'.", qPrintable(non_const_url)); + request.setUrl(non_const_url.replace(QRegExp(QString('^') + URI_SCHEME_FEED), QString(URI_SCHEME_HTTP))); + } + else { + request.setUrl(non_const_url); + } + + runPostRequest(request, m_inputData); +} + void Downloader::finished() { QNetworkReply *reply = qobject_cast(sender()); + QNetworkAccessManager::Operation reply_operation = reply->operation(); m_timer->stop(); @@ -89,7 +114,12 @@ void Downloader::finished() { m_activeReply->deleteLater(); m_activeReply = NULL; - runGetRequest(request); + if (reply_operation == QNetworkAccessManager::GetOperation) { + runGetRequest(request); + } + else if (reply_operation == QNetworkAccessManager::PostOperation) { + runPostRequest(request, m_inputData); + } } else { // No redirection is indicated. Final file is obtained in our "reply" object. @@ -120,6 +150,14 @@ void Downloader::timeout() { } } +void Downloader::runPostRequest(const QNetworkRequest &request, const QByteArray &data) { + m_timer->start(); + m_activeReply = m_downloadManager->post(request, data); + + connect(m_activeReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(progressInternal(qint64,qint64))); + connect(m_activeReply, SIGNAL(finished()), this, SLOT(finished())); +} + void Downloader::runGetRequest(const QNetworkRequest &request) { m_timer->start(); m_activeReply = m_downloadManager->get(request); diff --git a/src/network-web/downloader.h b/src/network-web/downloader.h index 8cbdf0366..621657b64 100755 --- a/src/network-web/downloader.h +++ b/src/network-web/downloader.h @@ -49,6 +49,11 @@ class Downloader : public QObject { void downloadFile(const QString &url, int timeout = DOWNLOAD_TIMEOUT, bool protected_contents = false, const QString &username = QString(), const QString &password = QString()); + // Performs asynchronous upload of given data as HTTP POST. + // User needs to setup "Content-Encoding" header which + // matches encoding of the data. + void uploadData(const QString &url, const QByteArray &data, int timeout = DOWNLOAD_TIMEOUT); + signals: // Emitted when new progress is known. void progress(qint64 bytes_received, qint64 bytes_total); @@ -65,6 +70,7 @@ class Downloader : public QObject { void timeout(); private: + void runPostRequest(const QNetworkRequest &request, const QByteArray &data); void runGetRequest(const QNetworkRequest &request); private: @@ -72,6 +78,7 @@ class Downloader : public QObject { SilentNetworkAccessManager *m_downloadManager; QTimer *m_timer; QHash m_customHeaders; + QByteArray m_inputData; // Response data. QByteArray m_lastOutputData; diff --git a/src/network-web/networkfactory.cpp b/src/network-web/networkfactory.cpp index 4acac8bf8..d98512f8b 100755 --- a/src/network-web/networkfactory.cpp +++ b/src/network-web/networkfactory.cpp @@ -148,6 +148,26 @@ QNetworkReply::NetworkError NetworkFactory::downloadIcon(const QList &u return network_result; } +NetworkResult NetworkFactory::uploadData(const QString &url, int timeout, const QByteArray &input_data, + const QString &input_content_type, QByteArray &output) { + Downloader downloader; + QEventLoop loop; + NetworkResult result; + + downloader.appendRawHeader("Content-Type", input_content_type.toLocal8Bit()); + + // We need to quit event loop when the download finishes. + QObject::connect(&downloader, SIGNAL(completed(QNetworkReply::NetworkError)), &loop, SLOT(quit())); + + downloader.uploadData(url, input_data, timeout); + loop.exec(); + output = downloader.lastOutputData(); + result.first = downloader.lastOutputError(); + result.second = downloader.lastContentType(); + + return result; +} + NetworkResult NetworkFactory::downloadFeedFile(const QString &url, int timeout, QByteArray &output, bool protected_contents, const QString &username, const QString &password) { diff --git a/src/network-web/networkfactory.h b/src/network-web/networkfactory.h old mode 100644 new mode 100755 index 8d11e2a08..08aa13c17 --- a/src/network-web/networkfactory.h +++ b/src/network-web/networkfactory.h @@ -43,6 +43,9 @@ class NetworkFactory { // given URL belongs to. static QNetworkReply::NetworkError downloadIcon(const QList &urls, int timeout, QIcon &output); + static NetworkResult uploadData(const QString &url, int timeout, const QByteArray &input_data, + const QString &input_content_type, QByteArray &output); + static NetworkResult downloadFeedFile(const QString &url, int timeout, QByteArray &output, bool protected_contents = false, const QString &username = QString(), const QString &password = QString()); diff --git a/src/services/tt-rss/definitions.h b/src/services/tt-rss/definitions.h new file mode 100755 index 000000000..e26ce4ff7 --- /dev/null +++ b/src/services/tt-rss/definitions.h @@ -0,0 +1,36 @@ +#ifndef DEFINITIONS_H +#define DEFINITIONS_H + +// Error when user needs to login before making an operation. +#define NOT_LOGGED_IN "NOT_LOGGED_IN" + +// General return status codes. +#define API_STATUS_OK 0 +#define API_STATUS_ERR 1 +#define STATUS_OK "OK" + +// Login. +#define API_DISABLED "API_DISABLED" // API is not enabled. +#define LOGIN_ERROR "LOGIN_ERROR" // Incorrect password/username. + +// Logout. +#define LOGOUT_OK "OK" + + +/* //login + * QtJson::JsonObject obj; + obj["op"] = "login"; + obj["user"] = "admin"; + obj["password"] = "Zy69tKWF"; + + QByteArray arr; + NetworkResult res = NetworkFactory::uploadData("http://rss.rotterovi.eu/api/", + 15000, + QtJson::serialize(obj), + "application/json; charset=utf-8", + arr); + + obj = QtJson::parse(QString::fromUtf8(arr)).toMap();*/ + +#endif // DEFINITIONS_H + From e4358722a6dd1abfc14e3a94335d72f52a2d6776 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 1 Dec 2015 08:22:22 +0100 Subject: [PATCH 099/203] Added initial add/edit TT-RSS account dialog. --- CMakeLists.txt | 5 + src/gui/dialogs/formsettings.ui | 4 +- .../gui/formstandardcategorydetails.ui | 2 +- src/services/tt-rss/gui/formeditaccount.cpp | 122 +++++++++++++++++ src/services/tt-rss/gui/formeditaccount.h | 59 ++++++++ src/services/tt-rss/gui/formeditaccount.ui | 129 ++++++++++++++++++ .../tt-rss/ttrssserviceentrypoint.cpp | 11 +- 7 files changed, 328 insertions(+), 4 deletions(-) create mode 100755 src/services/tt-rss/gui/formeditaccount.cpp create mode 100755 src/services/tt-rss/gui/formeditaccount.h create mode 100755 src/services/tt-rss/gui/formeditaccount.ui diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d04f27b3..b6a65dec1 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -439,6 +439,7 @@ set(APP_SOURCES # TT-RSS feed service sources. src/services/tt-rss/ttrssserviceentrypoint.cpp src/services/tt-rss/ttrssserviceroot.cpp + src/services/tt-rss/gui/formeditaccount.cpp # NETWORK-WEB sources. src/network-web/basenetworkaccessmanager.cpp @@ -555,6 +556,7 @@ set(APP_HEADERS # TT-RSS service headers. src/services/tt-rss/ttrssserviceroot.h + src/services/tt-rss/gui/formeditaccount.h # NETWORK-WEB headers. src/network-web/webpage.h @@ -595,6 +597,9 @@ set(APP_FORMS src/services/standard/gui/formstandardfeeddetails.ui src/services/standard/gui/formstandardimportexport.ui + # TT-RSS service forms. + src/services/tt-rss/gui/formeditaccount.ui + # NETWORK forms. src/network-web/downloadmanager.ui src/network-web/downloaditem.ui diff --git a/src/gui/dialogs/formsettings.ui b/src/gui/dialogs/formsettings.ui index b92abf5bc..d4f2f5e96 100755 --- a/src/gui/dialogs/formsettings.ui +++ b/src/gui/dialogs/formsettings.ui @@ -88,7 +88,7 @@ - 3 + 1 @@ -463,7 +463,7 @@ Authors of this application are NOT responsible for lost data. QTabWidget::North - 1 + 0 diff --git a/src/services/standard/gui/formstandardcategorydetails.ui b/src/services/standard/gui/formstandardcategorydetails.ui index 101ac40e6..d68dedfe4 100755 --- a/src/services/standard/gui/formstandardcategorydetails.ui +++ b/src/services/standard/gui/formstandardcategorydetails.ui @@ -7,7 +7,7 @@ 0 0 397 - 205 + 209 diff --git a/src/services/tt-rss/gui/formeditaccount.cpp b/src/services/tt-rss/gui/formeditaccount.cpp new file mode 100755 index 000000000..5d840ffce --- /dev/null +++ b/src/services/tt-rss/gui/formeditaccount.cpp @@ -0,0 +1,122 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + + +#include "services/tt-rss/gui/formeditaccount.h" + +#include "services/tt-rss/ttrssserviceroot.h" + + +FormEditAccount::FormEditAccount(QWidget *parent) + : QDialog(parent), m_ui(new Ui::FormEditAccount), m_editableRoot(NULL) { + m_ui->setupUi(this); + m_btnOk = m_ui->m_buttonBox->button(QDialogButtonBox::Ok); + + m_ui->m_txtPassword->lineEdit()->setPlaceholderText(tr("Password for your TT-RSS account.")); + m_ui->m_txtUsername->lineEdit()->setPlaceholderText(tr("Username for your TT-RSS account.")); + m_ui->m_txtUrl->lineEdit()->setPlaceholderText(tr("URL of your TT-RSS instance WITHOUT trailing \"/api/\" string.")); + m_ui->m_lblTestResult->setStatus(WidgetWithStatus::Information, + tr("No test done yet."), + tr("Here, results of connection test are shown.")); + + connect(m_ui->m_buttonBox, SIGNAL(accepted()), this, SLOT(onClickedOk())); + connect(m_ui->m_buttonBox, SIGNAL(rejected()), this, SLOT(onClickedCancel())); + connect(m_ui->m_txtPassword->lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(onPasswordChanged())); + connect(m_ui->m_txtUsername->lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(onUsernameChanged())); + connect(m_ui->m_txtUrl->lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(onUrlChanged())); + connect(m_ui->m_txtPassword->lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(checkOkButton())); + connect(m_ui->m_txtUsername->lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(checkOkButton())); + connect(m_ui->m_txtUrl->lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(checkOkButton())); + connect(m_ui->m_btnTestSetup, SIGNAL(clicked()), this, SLOT(performTest())); + + onPasswordChanged(); + onUsernameChanged(); + onUrlChanged(); + checkOkButton(); +} + +FormEditAccount::~FormEditAccount() { + delete m_ui; +} + +TtRssServiceRoot *FormEditAccount::execForCreate() { + setWindowTitle(tr("Add new Tiny Tiny RSS account")); + exec(); + return m_editableRoot; +} + +void FormEditAccount::execForEdit(TtRssServiceRoot *existing_root) { + setWindowTitle(tr("Edit existing Tiny Tiny RSS account")); + m_editableRoot = existing_root; + exec(); +} + +void FormEditAccount::performTest() { + +} + +void FormEditAccount::onClickedOk() { + if (m_editableRoot == NULL) { + // We want to confirm newly created account. + } + else { + // We want to edit existing account. + } +} + +void FormEditAccount::onClickedCancel() { + reject(); +} + +void FormEditAccount::onUsernameChanged() { + QString username = m_ui->m_txtUsername->lineEdit()->text(); + + if (username.isEmpty()) { + m_ui->m_txtUsername->setStatus(WidgetWithStatus::Error, tr("Username cannot be empty.")); + } + else { + m_ui->m_txtUsername->setStatus(WidgetWithStatus::Ok, tr("Username is okay.")); + } +} + +void FormEditAccount::onPasswordChanged() { + QString password = m_ui->m_txtPassword->lineEdit()->text(); + + if (password.isEmpty()) { + m_ui->m_txtPassword->setStatus(WidgetWithStatus::Error, tr("Password cannot be empty.")); + } + else { + m_ui->m_txtPassword->setStatus(WidgetWithStatus::Ok, tr("Password is okay.")); + } +} + +void FormEditAccount::onUrlChanged() { + QString url = m_ui->m_txtUrl->lineEdit()->text(); + + if (url.isEmpty()) { + m_ui->m_txtUrl->setStatus(WidgetWithStatus::Error, tr("URL cannot be empty.")); + } + else { + m_ui->m_txtUrl->setStatus(WidgetWithStatus::Ok, tr("URL is okay.")); + } +} + +void FormEditAccount::checkOkButton() { + m_btnOk->setEnabled(!m_ui->m_txtUsername->lineEdit()->text().isEmpty() && + !m_ui->m_txtPassword->lineEdit()->text().isEmpty() && + !m_ui->m_txtUrl->lineEdit()->text().isEmpty()); +} diff --git a/src/services/tt-rss/gui/formeditaccount.h b/src/services/tt-rss/gui/formeditaccount.h new file mode 100755 index 000000000..6de37e3db --- /dev/null +++ b/src/services/tt-rss/gui/formeditaccount.h @@ -0,0 +1,59 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + + +#ifndef FORMEDITACCOUNT_H +#define FORMEDITACCOUNT_H + +#include + +#include "ui_formeditaccount.h" + + +namespace Ui { + class FormEditAccount; +} + +class TtRssServiceRoot; + +class FormEditAccount : public QDialog { + Q_OBJECT + + public: + explicit FormEditAccount(QWidget *parent = 0); + virtual ~FormEditAccount(); + + TtRssServiceRoot *execForCreate(); + void execForEdit(TtRssServiceRoot *existing_root); + + private slots: + void performTest(); + void onClickedOk(); + void onClickedCancel(); + + void onUsernameChanged(); + void onPasswordChanged(); + void onUrlChanged(); + void checkOkButton(); + + private: + Ui::FormEditAccount *m_ui; + TtRssServiceRoot *m_editableRoot; + QPushButton *m_btnOk; +}; + +#endif // FORMEDITACCOUNT_H diff --git a/src/services/tt-rss/gui/formeditaccount.ui b/src/services/tt-rss/gui/formeditaccount.ui new file mode 100755 index 000000000..76da5638e --- /dev/null +++ b/src/services/tt-rss/gui/formeditaccount.ui @@ -0,0 +1,129 @@ + + + FormEditAccount + + + + 0 + 0 + 400 + 235 + + + + Dialog + + + + + + + + URL + + + m_txtUrl + + + + + + + + + + &Test setup + + + + + + + Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. + + + Authentication + + + false + + + false + + + + + + Username + + + m_txtUsername + + + + + + + Password + + + m_txtPassword + + + + + + + + + + + + + + + + + 0 + 0 + + + + Qt::RightToLeft + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + LineEditWithStatus + QWidget +
            lineeditwithstatus.h
            + 1 +
            + + LabelWithStatus + QWidget +
            labelwithstatus.h
            + 1 +
            +
            + + m_btnTestSetup + + + +
            diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp index e497d30d3..3b02f255e 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.cpp +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -20,6 +20,11 @@ #include "definitions/definitions.h" #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" +#include "gui/dialogs/formmain.h" +#include "services/tt-rss/gui/formeditaccount.h" +#include "services/tt-rss/ttrssserviceroot.h" + +#include TtRssServiceEntryPoint::TtRssServiceEntryPoint(){ @@ -59,7 +64,11 @@ QString TtRssServiceEntryPoint::code() { } ServiceRoot *TtRssServiceEntryPoint::createNewRoot() { - return NULL; + QPointer form_acc = new FormEditAccount(qApp->mainForm()); + TtRssServiceRoot *new_root = form_acc.data()->execForCreate(); + delete form_acc.data(); + + return new_root; } QList TtRssServiceEntryPoint::initializeSubtree() { From 5ea57062dcb6d8d7836fcd438155f819fde850c7 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 1 Dec 2015 10:05:52 +0100 Subject: [PATCH 100/203] Work on TT-RSS network/edit edialog. --- CMakeLists.txt | 1 + src/gui/labelwithstatus.cpp | 2 + src/services/tt-rss/definitions.h | 3 + src/services/tt-rss/gui/formeditaccount.cpp | 36 ++++- src/services/tt-rss/gui/formeditaccount.h | 1 + src/services/tt-rss/gui/formeditaccount.ui | 63 ++++---- .../tt-rss/network/ttrssnetworkfactory.cpp | 142 ++++++++++++++++++ .../tt-rss/network/ttrssnetworkfactory.h | 78 ++++++++++ 8 files changed, 298 insertions(+), 28 deletions(-) mode change 100644 => 100755 src/gui/labelwithstatus.cpp create mode 100755 src/services/tt-rss/network/ttrssnetworkfactory.cpp create mode 100755 src/services/tt-rss/network/ttrssnetworkfactory.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b6a65dec1..3a49c1871 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -440,6 +440,7 @@ set(APP_SOURCES src/services/tt-rss/ttrssserviceentrypoint.cpp src/services/tt-rss/ttrssserviceroot.cpp src/services/tt-rss/gui/formeditaccount.cpp + src/services/tt-rss/network/ttrssnetworkfactory.cpp # NETWORK-WEB sources. src/network-web/basenetworkaccessmanager.cpp diff --git a/src/gui/labelwithstatus.cpp b/src/gui/labelwithstatus.cpp old mode 100644 new mode 100755 index 5f15541b3..90db3a608 --- a/src/gui/labelwithstatus.cpp +++ b/src/gui/labelwithstatus.cpp @@ -26,6 +26,8 @@ LabelWithStatus::LabelWithStatus(QWidget *parent) : WidgetWithStatus(parent) { m_wdgInput = new QLabel(this); + qobject_cast(m_wdgInput)->setWordWrap(true); + // Set correct size for the tool button. int label_height = m_wdgInput->sizeHint().height(); m_btnStatus->setFixedSize(label_height, label_height); diff --git a/src/services/tt-rss/definitions.h b/src/services/tt-rss/definitions.h index e26ce4ff7..c77b7ff11 100755 --- a/src/services/tt-rss/definitions.h +++ b/src/services/tt-rss/definitions.h @@ -1,6 +1,9 @@ #ifndef DEFINITIONS_H #define DEFINITIONS_H +#define MINIMAL_API_LEVEL 10 +#define CONTENT_TYPE "application/json; charset=utf-8" + // Error when user needs to login before making an operation. #define NOT_LOGGED_IN "NOT_LOGGED_IN" diff --git a/src/services/tt-rss/gui/formeditaccount.cpp b/src/services/tt-rss/gui/formeditaccount.cpp index 5d840ffce..d6ab35621 100755 --- a/src/services/tt-rss/gui/formeditaccount.cpp +++ b/src/services/tt-rss/gui/formeditaccount.cpp @@ -19,6 +19,8 @@ #include "services/tt-rss/gui/formeditaccount.h" #include "services/tt-rss/ttrssserviceroot.h" +#include "services/tt-rss/network/ttrssnetworkfactory.h" +#include "miscellaneous/iconfactory.h" FormEditAccount::FormEditAccount(QWidget *parent) @@ -26,13 +28,23 @@ FormEditAccount::FormEditAccount(QWidget *parent) m_ui->setupUi(this); m_btnOk = m_ui->m_buttonBox->button(QDialogButtonBox::Ok); + setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint); + setWindowIcon(qApp->icons()->fromTheme(QSL("application-ttrss"))); + m_ui->m_txtPassword->lineEdit()->setPlaceholderText(tr("Password for your TT-RSS account.")); m_ui->m_txtUsername->lineEdit()->setPlaceholderText(tr("Username for your TT-RSS account.")); - m_ui->m_txtUrl->lineEdit()->setPlaceholderText(tr("URL of your TT-RSS instance WITHOUT trailing \"/api/\" string.")); + m_ui->m_txtUrl->lineEdit()->setPlaceholderText(tr("FULL URL of your TT-RSS instance WITH trailing \"/api/\" string.")); m_ui->m_lblTestResult->setStatus(WidgetWithStatus::Information, tr("No test done yet."), tr("Here, results of connection test are shown.")); + setTabOrder(m_ui->m_txtUrl->lineEdit(), m_ui->m_txtUsername->lineEdit()); + setTabOrder(m_ui->m_txtUsername->lineEdit(), m_ui->m_txtPassword->lineEdit()); + setTabOrder(m_ui->m_txtPassword->lineEdit(), m_ui->m_checkShowPassword); + setTabOrder(m_ui->m_checkShowPassword, m_ui->m_btnTestSetup); + setTabOrder(m_ui->m_btnTestSetup, m_ui->m_buttonBox); + + connect(m_ui->m_checkShowPassword, SIGNAL(toggled(bool)), this, SLOT(displayPassword(bool))); connect(m_ui->m_buttonBox, SIGNAL(accepted()), this, SLOT(onClickedOk())); connect(m_ui->m_buttonBox, SIGNAL(rejected()), this, SLOT(onClickedCancel())); connect(m_ui->m_txtPassword->lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(onPasswordChanged())); @@ -47,6 +59,7 @@ FormEditAccount::FormEditAccount(QWidget *parent) onUsernameChanged(); onUrlChanged(); checkOkButton(); + displayPassword(false); } FormEditAccount::~FormEditAccount() { @@ -65,8 +78,27 @@ void FormEditAccount::execForEdit(TtRssServiceRoot *existing_root) { exec(); } -void FormEditAccount::performTest() { +void FormEditAccount::displayPassword(bool display) { + m_ui->m_txtPassword->lineEdit()->setEchoMode(display ? QLineEdit::Normal : QLineEdit::Password); +} +void FormEditAccount::performTest() { + TtRssNetworkFactory factory; + + factory.setUsername(m_ui->m_txtUsername->lineEdit()->text()); + factory.setPassword(m_ui->m_txtPassword->lineEdit()->text()); + factory.setUrl(m_ui->m_txtUrl->lineEdit()->text()); + + LoginResult result = factory.login(); + + if (result.first == QNetworkReply::NoError) { + + } + else { + m_ui->m_lblTestResult->setStatus(WidgetWithStatus::Error, + tr("Network error, have you entered correct Tiny Tiny RSS API endpoint?"), + tr("Network error, have you entered correct Tiny Tiny RSS API endpoint?")); + } } void FormEditAccount::onClickedOk() { diff --git a/src/services/tt-rss/gui/formeditaccount.h b/src/services/tt-rss/gui/formeditaccount.h index 6de37e3db..5e278ec6a 100755 --- a/src/services/tt-rss/gui/formeditaccount.h +++ b/src/services/tt-rss/gui/formeditaccount.h @@ -41,6 +41,7 @@ class FormEditAccount : public QDialog { void execForEdit(TtRssServiceRoot *existing_root); private slots: + void displayPassword(bool display); void performTest(); void onClickedOk(); void onClickedCancel(); diff --git a/src/services/tt-rss/gui/formeditaccount.ui b/src/services/tt-rss/gui/formeditaccount.ui index 76da5638e..c604bac7e 100755 --- a/src/services/tt-rss/gui/formeditaccount.ui +++ b/src/services/tt-rss/gui/formeditaccount.ui @@ -6,7 +6,7 @@ 0 0 - 400 + 465 235
            @@ -16,19 +16,6 @@ - - - - URL - - - m_txtUrl - - - - - - @@ -36,6 +23,19 @@ + + + + + 0 + 0 + + + + Qt::RightToLeft + + + @@ -77,21 +77,32 @@ + + + + Show password + + +
            - - - - - 0 - 0 - - - - Qt::RightToLeft - - + + + + + + URL + + + m_txtUrl + + + + + + + diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp new file mode 100755 index 000000000..8c300cc77 --- /dev/null +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -0,0 +1,142 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#include "services/tt-rss/network/ttrssnetworkfactory.h" + +#include "definitions/definitions.h" +#include "services/tt-rss/definitions.h" +#include "network-web/networkfactory.h" + + +TtRssNetworkFactory::TtRssNetworkFactory() : m_url(QString()) { +} + +TtRssNetworkFactory::~TtRssNetworkFactory() { +} + +QString TtRssNetworkFactory::url() const { + return m_url; +} + +void TtRssNetworkFactory::setUrl(const QString &url) { + m_url = url; +} + +QString TtRssNetworkFactory::username() const { + return m_username; +} + +void TtRssNetworkFactory::setUsername(const QString &username) { + m_username = username; +} + +QString TtRssNetworkFactory::password() const { + return m_password; +} + +void TtRssNetworkFactory::setPassword(const QString &password) { + m_password = password; +} + +LoginResult TtRssNetworkFactory::login() { + QtJson::JsonObject json; + json["op"] = "login"; + json["user"] = m_username; + json["password"] = m_password; + + QByteArray result; + NetworkResult res = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result); + + if (res.first != QNetworkReply::NoError) { + return LoginResult(res.first, TtRssLoginResponse()); + } + else { + return LoginResult(res.first, TtRssLoginResponse(QString::fromUtf8(result))); + } +} + +TtRssResponse::TtRssResponse(const QString &raw_content) { + m_rawContent = QtJson::parse(raw_content).toMap(); +} + +TtRssResponse::~TtRssResponse() { +} + +bool TtRssResponse::isLoaded() const { + return !m_rawContent.empty(); +} + +int TtRssResponse::seq() const { + if (!isLoaded()) { + return -1; + } + else { + return m_rawContent["seq"].toInt(); + } +} + +int TtRssResponse::status() const { + if (!isLoaded()) { + return -1; + } + else { + return m_rawContent["status"].toInt(); + } +} + + +TtRssLoginResponse::TtRssLoginResponse(const QString &raw_content) : TtRssResponse(raw_content) { +} + +TtRssLoginResponse::~TtRssLoginResponse() { +} + +int TtRssLoginResponse::apiLevel() const { + if (!isLoaded()) { + return -1; + } + else { + return m_rawContent["content"].toMap()["api_level"].toInt(); + } +} + +QString TtRssLoginResponse::sessionId() const { + if (!isLoaded()) { + return QString(); + } + else { + return m_rawContent["content"].toMap()["session_id"].toString(); + } +} + +QString TtRssLoginResponse::error() const { + if (!isLoaded()) { + return QString(); + } + else { + return m_rawContent["content"].toMap()["error"].toString(); + } +} + +bool TtRssLoginResponse::hasError() const { + if (!isLoaded()) { + return false; + } + else { + return m_rawContent["content"].toMap().contains("error"); + } +} diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.h b/src/services/tt-rss/network/ttrssnetworkfactory.h new file mode 100755 index 000000000..52f559ec5 --- /dev/null +++ b/src/services/tt-rss/network/ttrssnetworkfactory.h @@ -0,0 +1,78 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#ifndef TTRSSNETWORKFACTORY_H +#define TTRSSNETWORKFACTORY_H + +#include "qt-json/json.h" + +#include +#include +#include + + +class TtRssResponse { + public: + explicit TtRssResponse(const QString &raw_content = QString()); + virtual ~TtRssResponse(); + + bool isLoaded() const; + + int seq() const; + int status() const; + + protected: + QtJson::JsonObject m_rawContent; +}; + +class TtRssLoginResponse : public TtRssResponse { + public: + explicit TtRssLoginResponse(const QString &raw_content = QString()); + virtual ~TtRssLoginResponse(); + + int apiLevel() const; + QString sessionId() const; + QString error() const; + bool hasError() const; +}; + +typedef QPair LoginResult; + +class TtRssNetworkFactory { + public: + explicit TtRssNetworkFactory(); + virtual ~TtRssNetworkFactory(); + + QString url() const; + void setUrl(const QString &url); + + QString username() const; + void setUsername(const QString &username); + + QString password() const; + void setPassword(const QString &password); + + // Operations. + LoginResult login(); + + private: + QString m_url; + QString m_username; + QString m_password; +}; + +#endif // TTRSSNETWORKFACTORY_H From 7f8d7bbb4f9a1b160b52a7411e4c07da448869bd Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 1 Dec 2015 10:19:05 +0100 Subject: [PATCH 101/203] TT-RSS dialog edit. --- src/services/tt-rss/gui/formeditaccount.cpp | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/services/tt-rss/gui/formeditaccount.cpp b/src/services/tt-rss/gui/formeditaccount.cpp index d6ab35621..615890845 100755 --- a/src/services/tt-rss/gui/formeditaccount.cpp +++ b/src/services/tt-rss/gui/formeditaccount.cpp @@ -18,6 +18,7 @@ #include "services/tt-rss/gui/formeditaccount.h" +#include "services/tt-rss/definitions.h" #include "services/tt-rss/ttrssserviceroot.h" #include "services/tt-rss/network/ttrssnetworkfactory.h" #include "miscellaneous/iconfactory.h" @@ -92,7 +93,37 @@ void FormEditAccount::performTest() { LoginResult result = factory.login(); if (result.first == QNetworkReply::NoError) { + if (result.second.hasError()) { + QString error = result.second.error(); + if (error == API_DISABLED) { + m_ui->m_lblTestResult->setStatus(WidgetWithStatus::Error, + tr("API access on selected server is not enabled."), + tr("API access on selected server is not enabled.")); + } + else if (error == LOGIN_ERROR) { + m_ui->m_lblTestResult->setStatus(WidgetWithStatus::Error, + tr("Entered credentials are incorrect."), + tr("Entered credentials are incorrect.")); + } + else { + m_ui->m_lblTestResult->setStatus(WidgetWithStatus::Error, + tr("Other error occurred, contact developers."), + tr("Other error occurred, contact developers.")); + } + } + else if (result.second.apiLevel() < MINIMAL_API_LEVEL) { + m_ui->m_lblTestResult->setStatus(WidgetWithStatus::Error, + tr("Selected Tiny Tiny RSS server is running unsupported version of API (%1). At least API level %2 is required.").arg(QString::number(result.second.apiLevel()), + QString::number(MINIMAL_API_LEVEL)), + tr("Selected Tiny Tiny RSS server is running unsupported version of API.")); + } + else { + m_ui->m_lblTestResult->setStatus(WidgetWithStatus::Ok, + tr("Tiny Tiny RSS server is okay, running with API level %1, while at least API level %2 is required.").arg(QString::number(result.second.apiLevel()), + QString::number(MINIMAL_API_LEVEL)), + tr("Tiny Tiny RSS server is okay.")); + } } else { m_ui->m_lblTestResult->setStatus(WidgetWithStatus::Error, From 693d098e903000dc5811ce60980376ce4ea59b95 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 1 Dec 2015 14:13:23 +0100 Subject: [PATCH 102/203] Fix schema level. --- resources/misc/db_init_mysql.sql | 2 +- resources/misc/db_init_sqlite.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index 4f4ec7dc1..5591faa24 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -12,7 +12,7 @@ CREATE TABLE IF NOT EXISTS Information ( inf_value TEXT NOT NULL ); -- ! -INSERT INTO Information VALUES (1, 'schema_version', '3'); +INSERT INTO Information VALUES (1, 'schema_version', '4'); -- ! INSERT INTO Information (inf_key, inf_value) VALUES ('standard_account_enabled', 1); -- ! diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index 99e4b1363..19a75d686 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -6,7 +6,7 @@ CREATE TABLE IF NOT EXISTS Information ( inf_value TEXT NOT NULL ); -- ! -INSERT INTO Information VALUES (1, 'schema_version', '3'); +INSERT INTO Information VALUES (1, 'schema_version', '4'); -- ! INSERT INTO Information (inf_key, inf_value) VALUES ('standard_account_enabled', 1); -- ! From 8a21914e4f0c143036f2659b716fa6fefb48ba11 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 1 Dec 2015 14:24:07 +0100 Subject: [PATCH 103/203] Remove unused table and fix update DB lock, which fucked with update schema process. --- resources/misc/db_init_mysql.sql | 11 ----------- resources/misc/db_init_sqlite.sql | 11 ----------- resources/misc/db_update_mysql_3_4.sql | 2 ++ resources/misc/db_update_sqlite_3_4.sql | 2 ++ src/miscellaneous/databasefactory.cpp | 5 ++--- 5 files changed, 6 insertions(+), 25 deletions(-) diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index 5591faa24..97a908f91 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -46,17 +46,6 @@ CREATE TABLE IF NOT EXISTS Feeds ( type INTEGER NOT NULL CHECK (type >= 0) ); -- ! -DROP TABLE IF EXISTS FeedsData; --- ! -CREATE TABLE IF NOT EXISTS FeedsData ( - feed_id INTEGER NOT NULL, - feed_key VARCHAR(100) NOT NULL, - feed_value TEXT, - - PRIMARY KEY (feed_id, feed_key), - FOREIGN KEY (feed_id) REFERENCES Feeds (id) -); --- ! DROP TABLE IF EXISTS Messages; -- ! CREATE TABLE IF NOT EXISTS Messages ( diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index 19a75d686..ecf85b2a1 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -40,17 +40,6 @@ CREATE TABLE IF NOT EXISTS Feeds ( type INTEGER NOT NULL CHECK (type >= 0) ); -- ! -DROP TABLE IF EXISTS FeedsData; --- ! -CREATE TABLE IF NOT EXISTS FeedsData ( - feed_id INTEGER NOT NULL, - feed_key TEXT NOT NULL, - feed_value TEXT, - - PRIMARY KEY (feed_id, feed_key), - FOREIGN KEY (feed_id) REFERENCES Feeds (id) -); --- ! DROP TABLE IF EXISTS Messages; -- ! CREATE TABLE IF NOT EXISTS Messages ( diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index 57a4a30bc..f6e1cb49e 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -1,3 +1,5 @@ INSERT INTO Information (inf_key, inf_value) VALUES ('standard_account_enabled', 1); -- ! +DROP TABLE IF EXISTS FeedsData; +-- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql index 57a4a30bc..f6e1cb49e 100644 --- a/resources/misc/db_update_sqlite_3_4.sql +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -1,3 +1,5 @@ INSERT INTO Information (inf_key, inf_value) VALUES ('standard_account_enabled', 1); -- ! +DROP TABLE IF EXISTS FeedsData; +-- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/src/miscellaneous/databasefactory.cpp b/src/miscellaneous/databasefactory.cpp index 6e0d98ff4..93f4783de 100755 --- a/src/miscellaneous/databasefactory.cpp +++ b/src/miscellaneous/databasefactory.cpp @@ -290,12 +290,13 @@ QSqlDatabase DatabaseFactory::sqliteInitializeFileBasedDatabase(const QString &c } database.commit(); + query_db.finish(); qDebug("File-based SQLite database backend should be ready now."); } else { query_db.next(); - QString installed_db_schema = query_db.value(0).toString(); + query_db.finish(); if (!updateDatabaseSchema(database, installed_db_schema)) { qFatal("Database schema was not updated from '%s' to '%s' successully.", @@ -313,8 +314,6 @@ QSqlDatabase DatabaseFactory::sqliteInitializeFileBasedDatabase(const QString &c qPrintable(QDir::toNativeSeparators(database.databaseName()))); qDebug("File-based SQLite database has version '%s'.", qPrintable(installed_db_schema)); } - - query_db.finish(); } // Everything is initialized now. From 1791fc6480336bc4c433b26cfdcae29feebac9fc Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 2 Dec 2015 10:52:49 +0100 Subject: [PATCH 104/203] Fix OS/2 error. --- src/qt-json/json.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt-json/json.cpp b/src/qt-json/json.cpp index f7ed3aa2e..275862f27 100755 --- a/src/qt-json/json.cpp +++ b/src/qt-json/json.cpp @@ -21,6 +21,7 @@ */ #include +#include > #include "json.h" namespace QtJson { From bd44be292177fe861c7b84309290e144d6f69812 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 2 Dec 2015 12:46:17 +0100 Subject: [PATCH 105/203] Fix > --- src/qt-json/json.cpp | 2 +- src/services/abstract/serviceentrypoint.cpp | 3 --- src/services/abstract/serviceentrypoint.h | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/qt-json/json.cpp b/src/qt-json/json.cpp index 275862f27..1aa505b87 100755 --- a/src/qt-json/json.cpp +++ b/src/qt-json/json.cpp @@ -21,7 +21,7 @@ */ #include -#include > +#include #include "json.h" namespace QtJson { diff --git a/src/services/abstract/serviceentrypoint.cpp b/src/services/abstract/serviceentrypoint.cpp index a368e207c..d32c3297c 100755 --- a/src/services/abstract/serviceentrypoint.cpp +++ b/src/services/abstract/serviceentrypoint.cpp @@ -18,8 +18,5 @@ #include "services/abstract/serviceentrypoint.h" -ServiceEntryPoint::ServiceEntryPoint() { -} - ServiceEntryPoint::~ServiceEntryPoint() { } diff --git a/src/services/abstract/serviceentrypoint.h b/src/services/abstract/serviceentrypoint.h index 1cefafa83..83294add5 100755 --- a/src/services/abstract/serviceentrypoint.h +++ b/src/services/abstract/serviceentrypoint.h @@ -30,7 +30,6 @@ class FeedsModel; class ServiceEntryPoint { public: // Constructors. - explicit ServiceEntryPoint(); virtual ~ServiceEntryPoint(); // Creates new service root item, which is ready to be added From aa62b7feaa56def0f349f974e80852d2c2796c38 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 2 Dec 2015 13:32:19 +0100 Subject: [PATCH 106/203] Added new table Accounts, which now holds JUST the information about how many of accounts is there. --- resources/misc/db_init_mysql.sql | 7 ++++++- resources/misc/db_init_sqlite.sql | 7 ++++++- resources/misc/db_update_mysql_3_4.sql | 7 ++++++- resources/misc/db_update_sqlite_3_4.sql | 7 ++++++- .../standard/standardserviceentrypoint.cpp | 19 +++++++++++++++---- src/services/standard/standardserviceroot.cpp | 2 +- 6 files changed, 40 insertions(+), 9 deletions(-) diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index 97a908f91..83a36e479 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -14,7 +14,12 @@ CREATE TABLE IF NOT EXISTS Information ( -- ! INSERT INTO Information VALUES (1, 'schema_version', '4'); -- ! -INSERT INTO Information (inf_key, inf_value) VALUES ('standard_account_enabled', 1); +CREATE TABLE IF NOT EXISTS Accounts ( + id INTEGER PRIMARY KEY, + type TEXT NOT NULL +); +-- ! +INSERT INTO Accounts (type) VALUES ('std-rss'); -- ! DROP TABLE IF EXISTS Categories; -- ! diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index ecf85b2a1..2f55e3e7e 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -8,7 +8,12 @@ CREATE TABLE IF NOT EXISTS Information ( -- ! INSERT INTO Information VALUES (1, 'schema_version', '4'); -- ! -INSERT INTO Information (inf_key, inf_value) VALUES ('standard_account_enabled', 1); +CREATE TABLE IF NOT EXISTS Accounts ( + id INTEGER PRIMARY KEY, + type TEXT NOT NULL +); +-- ! +INSERT INTO Accounts (type) VALUES ('std-rss'); -- ! DROP TABLE IF EXISTS Categories; -- ! diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index f6e1cb49e..68720dbd6 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -1,4 +1,9 @@ -INSERT INTO Information (inf_key, inf_value) VALUES ('standard_account_enabled', 1); +CREATE TABLE IF NOT EXISTS Accounts ( + id INTEGER PRIMARY KEY, + type TEXT NOT NULL +); +-- ! +INSERT INTO Accounts (type) VALUES ('std-rss'); -- ! DROP TABLE IF EXISTS FeedsData; -- ! diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql index f6e1cb49e..68720dbd6 100644 --- a/resources/misc/db_update_sqlite_3_4.sql +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -1,4 +1,9 @@ -INSERT INTO Information (inf_key, inf_value) VALUES ('standard_account_enabled', 1); +CREATE TABLE IF NOT EXISTS Accounts ( + id INTEGER PRIMARY KEY, + type TEXT NOT NULL +); +-- ! +INSERT INTO Accounts (type) VALUES ('std-rss'); -- ! DROP TABLE IF EXISTS FeedsData; -- ! diff --git a/src/services/standard/standardserviceentrypoint.cpp b/src/services/standard/standardserviceentrypoint.cpp index 97fa542d1..8d979815c 100755 --- a/src/services/standard/standardserviceentrypoint.cpp +++ b/src/services/standard/standardserviceentrypoint.cpp @@ -64,8 +64,18 @@ ServiceRoot *StandardServiceEntryPoint::createNewRoot() { QSqlDatabase database = qApp->database()->connection(QSL("StandardServiceEntryPoint"), DatabaseFactory::FromSettings); QSqlQuery query(database); - if (query.exec(QSL("UPDATE Information SET inf_value = 1 WHERE inf_key = 'standard_account_enabled';"))) { - return new StandardServiceRoot(true); + // First obtain the ID, which can be assigned to this new account. + if (!query.exec("SELECT max(id) FROM Accounts;") || !query.next()) { + return NULL; + } + + int id_to_assing = query.value(0).toInt() + 1; + + if (query.exec(QString("INSERT INTO Accounts (id, type) VALUES (%1, '%2');").arg(QString::number(id_to_assing), + SERVICE_CODE_STD_RSS))) { + StandardServiceRoot *root = new StandardServiceRoot(true); + root->setId(id_to_assing); + return root; } else { return NULL; @@ -78,9 +88,10 @@ QList StandardServiceEntryPoint::initializeSubtree() { QSqlQuery query(database); QList roots; - if (query.exec(QSL("SELECT inf_value FROM Information WHERE inf_key = 'standard_account_enabled';"))) { - if (query.next() && query.value(0).toInt() == 1) { + if (query.exec(QString("SELECT id FROM Accounts WHERE type = '%1';").arg(SERVICE_CODE_STD_RSS))) { + while (query.next()) { StandardServiceRoot *root = new StandardServiceRoot(true); + root->setId(query.value(0).toInt()); roots.append(root); } } diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 58ebfc167..623178b6c 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -131,7 +131,7 @@ bool StandardServiceRoot::deleteViaGui() { } // Switch "existence" flag. - bool data_removed = QSqlQuery(connection).exec(QSL("UPDATE Information SET inf_value = 0 WHERE inf_key = 'standard_account_enabled';")); + bool data_removed = QSqlQuery(connection).exec(QString("DELETE FROM Accounts WHERE id = %1;").arg(QString::number(id()))); if (data_removed) { requestItemRemoval(this); From 94dfc7c346135ea17eb4db53ab9b3c0ec739f82e Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 2 Dec 2015 14:00:19 +0100 Subject: [PATCH 107/203] Added note. --- src/services/abstract/serviceroot.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 954df1a19..f178ad4da 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -64,6 +64,8 @@ class ServiceRoot : public RootItem { virtual void start() = 0; virtual void stop() = 0; + // Returns the UNIQUE code of the given service. + // NOTE: Keep in sync with ServiceEntryRoot::code(). virtual QString code() = 0; // This method should prepare messages for given "item" (download them maybe?) From 27d8f5b04fe19cea1425a60cafdbe18a5d09f802 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 07:42:00 +0100 Subject: [PATCH 108/203] Fixed account IDs. --- resources/text/CHANGELOG | 2 +- src/services/abstract/serviceroot.cpp | 10 +++++++- src/services/abstract/serviceroot.h | 6 +++++ .../standard/standardserviceentrypoint.cpp | 4 +-- src/services/standard/standardserviceroot.cpp | 2 +- src/services/tt-rss/definitions.h | 25 +++++-------------- .../tt-rss/network/ttrssnetworkfactory.cpp | 7 ++++-- .../tt-rss/network/ttrssnetworkfactory.h | 1 + 8 files changed, 31 insertions(+), 26 deletions(-) diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index f523affbc..578cb8af3 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -16,7 +16,7 @@ Added:
              -
            • Brand new "service plugin system" - HIGHLY EXPERIMENTAL and REWRITTEN from scratch. Expect bugs and misunderstandings now! Major parts of RSS Guard were completely rewritten.
            • +
            • Brand new "service plugin system" - HIGHLY EXPERIMENTAL and REWRITTEN from scratch. Expect bugs and misunderstandings now! Major parts of RSS Guard were completely rewritten. Note that some functionality was TEMPORARILY removed, this includes "newspaper view".
            • Added ability to completely disable notifications (bug #128).
            • Added ability to go to next unread message. (partially bug #112)
            diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index 61c002824..773475c68 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -20,7 +20,7 @@ #include "core/feedsmodel.h" -ServiceRoot::ServiceRoot(RootItem *parent) : RootItem(parent) { +ServiceRoot::ServiceRoot(RootItem *parent) : RootItem(parent), m_accountId(NO_PARENT_CATEGORY) { setKind(RootItemKind::ServiceRoot); } @@ -46,3 +46,11 @@ void ServiceRoot::requestItemReassignment(RootItem *item, RootItem *new_parent) void ServiceRoot::requestItemRemoval(RootItem *item) { emit itemRemovalRequested(item); } + +int ServiceRoot::accountId() const { + return m_accountId; +} + +void ServiceRoot::setAccountId(int account_id) { + m_accountId = account_id; +} diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index f178ad4da..8868143ee 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -135,6 +135,9 @@ class ServiceRoot : public RootItem { void requestItemReassignment(RootItem *item, RootItem *new_parent); void requestItemRemoval(RootItem *item); + int accountId() const; + void setAccountId(int account_id); + signals: // Emitted if data in any item belonging to this root are changed. void dataChanged(QList items); @@ -143,6 +146,9 @@ class ServiceRoot : public RootItem { void itemReassignmentRequested(RootItem *item, RootItem *new_parent); void itemRemovalRequested(RootItem *item); + + private: + int m_accountId; }; #endif // SERVICEROOT_H diff --git a/src/services/standard/standardserviceentrypoint.cpp b/src/services/standard/standardserviceentrypoint.cpp index 8d979815c..730255b73 100755 --- a/src/services/standard/standardserviceentrypoint.cpp +++ b/src/services/standard/standardserviceentrypoint.cpp @@ -74,7 +74,7 @@ ServiceRoot *StandardServiceEntryPoint::createNewRoot() { if (query.exec(QString("INSERT INTO Accounts (id, type) VALUES (%1, '%2');").arg(QString::number(id_to_assing), SERVICE_CODE_STD_RSS))) { StandardServiceRoot *root = new StandardServiceRoot(true); - root->setId(id_to_assing); + root->setAccountId(id_to_assing); return root; } else { @@ -91,7 +91,7 @@ QList StandardServiceEntryPoint::initializeSubtree() { if (query.exec(QString("SELECT id FROM Accounts WHERE type = '%1';").arg(SERVICE_CODE_STD_RSS))) { while (query.next()) { StandardServiceRoot *root = new StandardServiceRoot(true); - root->setId(query.value(0).toInt()); + root->setAccountId(query.value(0).toInt()); roots.append(root); } } diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 623178b6c..7752375da 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -144,7 +144,7 @@ QVariant StandardServiceRoot::data(int column, int role) const { switch (role) { case Qt::ToolTipRole: if (column == FDS_MODEL_TITLE_INDEX) { - return tr("This is service account for standard RSS/RDF/ATOM feeds."); + return tr("This is service account for standard RSS/RDF/ATOM feeds.\n\nAccount ID: %1").arg(accountId()); } else if (column == FDS_MODEL_COUNTS_INDEX) { //: Tooltip for "unread" column of feed list. diff --git a/src/services/tt-rss/definitions.h b/src/services/tt-rss/definitions.h index c77b7ff11..9a96dfed7 100755 --- a/src/services/tt-rss/definitions.h +++ b/src/services/tt-rss/definitions.h @@ -4,8 +4,12 @@ #define MINIMAL_API_LEVEL 10 #define CONTENT_TYPE "application/json; charset=utf-8" -// Error when user needs to login before making an operation. -#define NOT_LOGGED_IN "NOT_LOGGED_IN" +/// +/// Errors. +/// +#define NOT_LOGGED_IN "NOT_LOGGED_IN" // Error when user needs to login before making an operation. +#define UNKNOWN_METHOD "UNKNOWN_METHOD" // Given "op" is not recognized. +#define INCORRECT_USAGE "INCORRECT_USAGE" // Given "op" was used with bad parameters. // General return status codes. #define API_STATUS_OK 0 @@ -19,21 +23,4 @@ // Logout. #define LOGOUT_OK "OK" - -/* //login - * QtJson::JsonObject obj; - obj["op"] = "login"; - obj["user"] = "admin"; - obj["password"] = "Zy69tKWF"; - - QByteArray arr; - NetworkResult res = NetworkFactory::uploadData("http://rss.rotterovi.eu/api/", - 15000, - QtJson::serialize(obj), - "application/json; charset=utf-8", - arr); - - obj = QtJson::parse(QString::fromUtf8(arr)).toMap();*/ - #endif // DEFINITIONS_H - diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index 8c300cc77..9028613f5 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -22,7 +22,8 @@ #include "network-web/networkfactory.h" -TtRssNetworkFactory::TtRssNetworkFactory() : m_url(QString()) { +TtRssNetworkFactory::TtRssNetworkFactory() + : m_url(QString()), m_username(QString()), m_password(QString()), m_session_Id(QString()) { } TtRssNetworkFactory::~TtRssNetworkFactory() { @@ -65,7 +66,9 @@ LoginResult TtRssNetworkFactory::login() { return LoginResult(res.first, TtRssLoginResponse()); } else { - return LoginResult(res.first, TtRssLoginResponse(QString::fromUtf8(result))); + LoginResult result(res.first, TtRssLoginResponse(QString::fromUtf8(result))); + m_session_Id = result.second.sessionId(); + return result; } } diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.h b/src/services/tt-rss/network/ttrssnetworkfactory.h index 52f559ec5..c6ce09028 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.h +++ b/src/services/tt-rss/network/ttrssnetworkfactory.h @@ -73,6 +73,7 @@ class TtRssNetworkFactory { QString m_url; QString m_username; QString m_password; + QString m_session_Id; }; #endif // TTRSSNETWORKFACTORY_H From 2d54dac6facd93ff5538b789cd0977de61eebda8 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 07:48:40 +0100 Subject: [PATCH 109/203] Changelog change. --- resources/text/CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 578cb8af3..045a7e7d5 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -16,7 +16,7 @@ Added:
              -
            • Brand new "service plugin system" - HIGHLY EXPERIMENTAL and REWRITTEN from scratch. Expect bugs and misunderstandings now! Major parts of RSS Guard were completely rewritten. Note that some functionality was TEMPORARILY removed, this includes "newspaper view".
            • +
            • Brand new "service plugin system" - HIGHLY EXPERIMENTAL and REWRITTEN from scratch. Expect bugs and misunderstandings now! Major parts of RSS Guard were completely rewritten. Note that some functionality might be TEMPORARILY removed.
            • Added ability to completely disable notifications (bug #128).
            • Added ability to go to next unread message. (partially bug #112)
            From b61814db88a8e02a644d4904462ce7cc0b311d14 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 09:19:59 +0100 Subject: [PATCH 110/203] Possible to add Tiny Tiny RSS account now. --- resources/misc/db_init_mysql.sql | 8 ++ resources/misc/db_init_sqlite.sql | 9 ++ resources/misc/db_update_mysql_3_4.sql | 9 ++ resources/misc/db_update_sqlite_3_4.sql | 9 ++ src/core/messagesmodel.cpp | 1 + src/miscellaneous/databasefactory.cpp | 7 +- src/services/abstract/category.cpp | 1 - src/services/abstract/feed.h | 11 ++ src/services/abstract/recyclebin.h | 8 ++ src/services/abstract/serviceentrypoint.h | 8 ++ src/services/abstract/serviceroot.h | 9 ++ src/services/tt-rss/gui/formeditaccount.cpp | 12 +- src/services/tt-rss/ttrssserviceroot.cpp | 131 +++++++++++++++++++- src/services/tt-rss/ttrssserviceroot.h | 54 ++++---- 14 files changed, 240 insertions(+), 37 deletions(-) diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index 83a36e479..44521f763 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -21,6 +21,14 @@ CREATE TABLE IF NOT EXISTS Accounts ( -- ! INSERT INTO Accounts (type) VALUES ('std-rss'); -- ! +CREATE TABLE IF NOT EXISTS TtRssAccounts ( + id INTEGER PRIMARY KEY, + username TEXT NOT NULL, + password TEXT, + url TEXT NOT NULL, + + FOREIGN KEY (id) REFERENCES Accounts (id) +); DROP TABLE IF EXISTS Categories; -- ! CREATE TABLE IF NOT EXISTS Categories ( diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index 2f55e3e7e..88bcd1c0f 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -15,6 +15,15 @@ CREATE TABLE IF NOT EXISTS Accounts ( -- ! INSERT INTO Accounts (type) VALUES ('std-rss'); -- ! +CREATE TABLE IF NOT EXISTS TtRssAccounts ( + id INTEGER PRIMARY KEY, + username TEXT NOT NULL, + password TEXT, + url TEXT NOT NULL, + + FOREIGN KEY (id) REFERENCES Accounts (id) +); +-- ! DROP TABLE IF EXISTS Categories; -- ! CREATE TABLE IF NOT EXISTS Categories ( diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index 68720dbd6..7324a89d0 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -7,4 +7,13 @@ INSERT INTO Accounts (type) VALUES ('std-rss'); -- ! DROP TABLE IF EXISTS FeedsData; -- ! +CREATE TABLE IF NOT EXISTS TtRssAccounts ( + id INTEGER PRIMARY KEY, + username TEXT NOT NULL, + password TEXT, + url TEXT NOT NULL, + + FOREIGN KEY (id) REFERENCES Accounts (id) +); +-- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql index 68720dbd6..7324a89d0 100644 --- a/resources/misc/db_update_sqlite_3_4.sql +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -7,4 +7,13 @@ INSERT INTO Accounts (type) VALUES ('std-rss'); -- ! DROP TABLE IF EXISTS FeedsData; -- ! +CREATE TABLE IF NOT EXISTS TtRssAccounts ( + id INTEGER PRIMARY KEY, + username TEXT NOT NULL, + password TEXT, + url TEXT NOT NULL, + + FOREIGN KEY (id) REFERENCES Accounts (id) +); +-- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 61169c562..0046c73e4 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -81,6 +81,7 @@ void MessagesModel::loadMessages(RootItem *item) { } else { if (!item->getParentServiceRoot()->loadMessagesForItem(item, this)) { + setFilter("true != true"); qWarning("Loading of messages from item '%s' failed.", qPrintable(item->title())); qApp->showGuiMessage(tr("Loading of messages from item '%s' failed.").arg(item->title()), tr("Loading of messages failed, maybe messages could not be downloaded."), diff --git a/src/miscellaneous/databasefactory.cpp b/src/miscellaneous/databasefactory.cpp index 93f4783de..0fa294735 100755 --- a/src/miscellaneous/databasefactory.cpp +++ b/src/miscellaneous/databasefactory.cpp @@ -203,7 +203,9 @@ QSqlDatabase DatabaseFactory::sqliteInitializeInMemoryDatabase() { copy_contents.exec(QString("ATTACH DATABASE '%1' AS 'storage';").arg(file_database.databaseName())); // Copy all stuff. - QStringList tables; tables << QSL("Information") << QSL("Categories") << QSL("Feeds") << QSL("FeedsData") << QSL("Messages"); + // WARNING: All tables belong here. + QStringList tables; tables << QSL("Information") << QSL("Categories") << QSL("Feeds") << + QSL("FeedsData") << QSL("Messages") << QSL("Accounts") << QSL("TtRssAccounts"); foreach (const QString &table, tables) { copy_contents.exec(QString("INSERT INTO main.%1 SELECT * FROM storage.%1;").arg(table)); @@ -468,8 +470,9 @@ void DatabaseFactory::sqliteSaveMemoryDatabase() { copy_contents.exec(QString(QSL("ATTACH DATABASE '%1' AS 'storage';")).arg(file_database.databaseName())); // Copy all stuff. + // WARNING: All tables belong here. QStringList tables; tables << QSL("Categories") << QSL("Feeds") << QSL("FeedsData") << - QSL("Messages"); + QSL("Messages") << QSL("Accounts") << QSL("TtRssAccounts"); foreach (const QString &table, tables) { copy_contents.exec(QString(QSL("DELETE FROM storage.%1;")).arg(table)); diff --git a/src/services/abstract/category.cpp b/src/services/abstract/category.cpp index 667e27fa0..62829f673 100755 --- a/src/services/abstract/category.cpp +++ b/src/services/abstract/category.cpp @@ -23,4 +23,3 @@ Category::Category(RootItem *parent) : RootItem(parent) { Category::~Category() { } - diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index d7b82f187..0ab9671e5 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -50,12 +50,23 @@ class Feed : public RootItem { explicit Feed(RootItem *parent = NULL); virtual ~Feed(); + ///////////////////////////////////////// + // /* Members to override. + ///////////////////////////////////////// + // Performs synchronous update and returns number of newly updated messages. + // NOTE: This should COMPLETELY download ALL messages from online source + // into locale "Messages" table, INCLUDING contents (or excerpts) of those + // messages. virtual int update() = 0; // Get ALL undeleted messages from this feed in one single list. virtual QList undeletedMessages() const = 0; + ///////////////////////////////////////// + // Members to override. */ + ///////////////////////////////////////// + inline int autoUpdateInitialInterval() const { return m_autoUpdateInitialInterval; } diff --git a/src/services/abstract/recyclebin.h b/src/services/abstract/recyclebin.h index 36ee0d696..ba3d5241b 100755 --- a/src/services/abstract/recyclebin.h +++ b/src/services/abstract/recyclebin.h @@ -31,6 +31,10 @@ class RecycleBin : public RootItem { QVariant data(int column, int role) const; public slots: + ///////////////////////////////////////// + // /* Members to override. + ///////////////////////////////////////// + // Empties the bin - removes all messages from it (does not remove // them from DB, just permanently hide them, so that they are not // re-downloaded). @@ -38,6 +42,10 @@ class RecycleBin : public RootItem { // Performs complete restoration of all messages contained in the bin virtual bool restore() = 0; + + ///////////////////////////////////////// + // Members to override. */ + ///////////////////////////////////////// }; #endif // RECYCLEBIN_H diff --git a/src/services/abstract/serviceentrypoint.h b/src/services/abstract/serviceentrypoint.h index 83294add5..b5974f446 100755 --- a/src/services/abstract/serviceentrypoint.h +++ b/src/services/abstract/serviceentrypoint.h @@ -32,6 +32,10 @@ class ServiceEntryPoint { // Constructors. virtual ~ServiceEntryPoint(); + ///////////////////////////////////////// + // /* Members to override. + ///////////////////////////////////////// + // Creates new service root item, which is ready to be added // into the model. This method can for example display // some kind of first-time configuration dialog inside itself @@ -68,6 +72,10 @@ class ServiceEntryPoint { // Icon of the service. virtual QIcon icon() = 0; + + ///////////////////////////////////////// + // Members to override. */ + ///////////////////////////////////////// }; #endif // SERVICE_H diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 8868143ee..98e30f2da 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -40,6 +40,10 @@ class ServiceRoot : public RootItem { explicit ServiceRoot(RootItem *parent = NULL); virtual ~ServiceRoot(); + ///////////////////////////////////////// + // /* Members to override. + ///////////////////////////////////////// + // Returns list of specific actions for "Add new item" main window menu. // So typical list of returned actions could look like: // a) Add new feed @@ -127,6 +131,10 @@ class ServiceRoot : public RootItem { // Selected item is naturally recycle bin. virtual bool onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) = 0; + ///////////////////////////////////////// + // Members to override. */ + ///////////////////////////////////////// + // Obvious methods to wrap signals. void itemChanged(QList items); void requestReloadMessageList(bool mark_selected_messages_read); @@ -135,6 +143,7 @@ class ServiceRoot : public RootItem { void requestItemReassignment(RootItem *item, RootItem *new_parent); void requestItemRemoval(RootItem *item); + // Account ID corresponds with DB attribute Accounts (id). int accountId() const; void setAccountId(int account_id); diff --git a/src/services/tt-rss/gui/formeditaccount.cpp b/src/services/tt-rss/gui/formeditaccount.cpp index 615890845..7ebe6d61f 100755 --- a/src/services/tt-rss/gui/formeditaccount.cpp +++ b/src/services/tt-rss/gui/formeditaccount.cpp @@ -135,10 +135,16 @@ void FormEditAccount::performTest() { void FormEditAccount::onClickedOk() { if (m_editableRoot == NULL) { // We want to confirm newly created account. + // So save new account into DB, setup its properties. + m_editableRoot = new TtRssServiceRoot(false); } - else { - // We want to edit existing account. - } + + m_editableRoot->network()->setUrl(m_ui->m_txtUrl->lineEdit()->text()); + m_editableRoot->network()->setUsername(m_ui->m_txtUsername->lineEdit()->text()); + m_editableRoot->network()->setPassword(m_ui->m_txtPassword->lineEdit()->text()); + m_editableRoot->saveToDatabase(); + + accept(); } void FormEditAccount::onClickedCancel() { diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 0c231832f..afbd99ad2 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -20,17 +20,34 @@ #include "miscellaneous/application.h" #include "miscellaneous/settings.h" #include "services/tt-rss/ttrssserviceentrypoint.h" -#include "core/feedsmodel.h" +#include "services/tt-rss/network/ttrssnetworkfactory.h" + +#include +#include -TtRssServiceRoot::TtRssServiceRoot(RootItem *parent) : ServiceRoot(parent) { - // TODO: nadpis se bude měnit podle nastavení uživatelského - // jména a serveru tohoto ttrss učtu - setTitle(qApp->system()->getUsername() + "@ttrss"); +TtRssServiceRoot::TtRssServiceRoot(bool load_from_db, RootItem *parent) + : ServiceRoot(parent), m_network(new TtRssNetworkFactory) { setIcon(TtRssServiceEntryPoint().icon()); + setCreationDate(QDateTime::currentDateTime()); + + if (load_from_db) { + loadFromDatabase(); + } } TtRssServiceRoot::~TtRssServiceRoot() { + if (m_network != NULL) { + delete m_network; + } +} + +void TtRssServiceRoot::start() { + +} + +void TtRssServiceRoot::stop() { + } QString TtRssServiceRoot::code() { @@ -41,6 +58,10 @@ bool TtRssServiceRoot::editViaGui() { return false; } +bool TtRssServiceRoot::deleteViaGui() { + return false; +} + bool TtRssServiceRoot::canBeEdited() { return true; } @@ -68,3 +89,103 @@ QVariant TtRssServiceRoot::data(int column, int role) const { return ServiceRoot::data(column, role); } } + +QList TtRssServiceRoot::addItemMenu() { + return QList(); +} + +RecycleBin *TtRssServiceRoot::recycleBin() { + return NULL; +} + +bool TtRssServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *model) { + return false; +} + +QList TtRssServiceRoot::serviceMenu() { + return QList(); +} + +bool TtRssServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, QList message_db_ids, RootItem::ReadStatus read) { + return false; +} + +bool TtRssServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, QList message_db_ids, RootItem::ReadStatus read) { + return false; +} + +bool TtRssServiceRoot::onBeforeSwitchMessageImportance(RootItem *selected_item, QList > changes) { + return false; +} + +bool TtRssServiceRoot::onAfterSwitchMessageImportance(RootItem *selected_item, QList > changes) { + return false; +} + +bool TtRssServiceRoot::onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids) { + return false; +} + +bool TtRssServiceRoot::onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids) { + return false; +} + +bool TtRssServiceRoot::onBeforeMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) { + return false; +} + +bool TtRssServiceRoot::onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) { + return false; +} + +TtRssNetworkFactory *TtRssServiceRoot::network() const { + return m_network; +} + +void TtRssServiceRoot::saveToDatabase() { + if (accountId() != NO_PARENT_CATEGORY) { + // We are overwritting previously saved data. + // TODO: todo + + updateTitle(); + itemChanged(QList() << this); + } + else { + // We are probably saving newly added account. + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + QSqlQuery query(database); + + // First obtain the ID, which can be assigned to this new account. + if (!query.exec("SELECT max(id) FROM Accounts;") || !query.next()) { + return; + } + + int id_to_assing = query.value(0).toInt() + 1; + + bool saved = query.exec(QString("INSERT INTO Accounts (id, type) VALUES (%1, '%2');").arg(QString::number(id_to_assing), + SERVICE_CODE_TT_RSS)) && + query.exec(QString("INSERT INTO TtRssAccounts (id, username, password, url) VALUES (%1, '%2', '%3', '%4');").arg(QString::number(id_to_assing), + network()->username(), + network()->password(), + network()->url())); + + if (saved) { + setAccountId(id_to_assing); + updateTitle(); + } + } +} + +void TtRssServiceRoot::loadFromDatabase() { + // Account ID is set, load connection data from DB. +} + +void TtRssServiceRoot::updateTitle() { + QString host = QUrl(m_network->url()).host(); + + if (host.isEmpty()) { + host = m_network->url(); + } + + setTitle(m_network->username() + QL1S("@") + host); +} diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index f4f805292..5060b94f8 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -23,53 +23,55 @@ #include -class FeedsModel; +class TtRssNetworkFactory; class TtRssServiceRoot : public ServiceRoot { Q_OBJECT public: - explicit TtRssServiceRoot(RootItem *parent = NULL); + explicit TtRssServiceRoot(bool load_from_db, RootItem *parent = NULL); virtual ~TtRssServiceRoot(); + void start(); + void stop(); + QString code(); bool canBeEdited(); bool canBeDeleted(); bool editViaGui(); + bool deleteViaGui(); + QVariant data(int column, int role) const; - bool onBeforeSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read) { - return false; - } + QList addItemMenu(); + QList serviceMenu(); - bool onAfterSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read) { - return false; - } + RecycleBin *recycleBin(); - bool onBeforeSwitchMessageImportance(RootItem *selected_item, QList > changes) { - return false; - } + bool loadMessagesForItem(RootItem *item, QSqlTableModel *model); - bool onAfterSwitchMessageImportance(RootItem *selected_item, QList > changes) { - return false; - } + bool onBeforeSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read); + bool onAfterSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read); - bool onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids) { - return false; - } + bool onBeforeSwitchMessageImportance(RootItem *selected_item, QList > changes); + bool onAfterSwitchMessageImportance(RootItem *selected_item, QList > changes); - bool onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids) { - return false; - } + bool onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids); + bool onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids); - bool onBeforeMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) { - return false; - } + bool onBeforeMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids); + bool onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids); - bool onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) { - return false; - } + TtRssNetworkFactory *network() const; + + void saveToDatabase(); + void loadFromDatabase(); + + private: + void updateTitle(); + + TtRssNetworkFactory *m_network; }; #endif // TTRSSSERVICEROOT_H From 057a5da197b17f281b3ca049fd843adecf7094bc Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 10:29:25 +0100 Subject: [PATCH 111/203] Adding some attributes to tables. Rough. :( --- resources/misc/db_init_mysql.sql | 4 +++- resources/misc/db_init_sqlite.sql | 4 +++- resources/misc/db_update_mysql_3_4.sql | 4 ++++ resources/misc/db_update_sqlite_3_4.sql | 3 +++ src/core/messagesmodel.cpp | 7 +++--- src/definitions/definitions.h.in | 1 + src/gui/messagesview.cpp | 1 + src/miscellaneous/databasefactory.cpp | 6 ++--- src/services/standard/standardfeed.cpp | 24 ++++++++++++------- src/services/standard/standardrecyclebin.cpp | 5 ++-- .../standard/standardserviceentrypoint.cpp | 6 +++-- src/services/standard/standardserviceroot.cpp | 22 +++++++++-------- src/services/standard/standardserviceroot.h | 6 ++--- 13 files changed, 58 insertions(+), 35 deletions(-) diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index 44521f763..262d65e89 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -74,6 +74,8 @@ CREATE TABLE IF NOT EXISTS Messages ( contents TEXT, is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1), enclosures TEXT, + account_id INTEGER NOT NULL, - FOREIGN KEY (feed) REFERENCES Feeds (id) + FOREIGN KEY (feed) REFERENCES Feeds (id), + FOREIGN KEY (account_id) REFERENCES Accounts (id) ); \ No newline at end of file diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index 88bcd1c0f..c5d9f3fe8 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -69,6 +69,8 @@ CREATE TABLE IF NOT EXISTS Messages ( contents TEXT, is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1), enclosures TEXT, + account_id INTEGER NOT NULL, - FOREIGN KEY (feed) REFERENCES Feeds (id) + FOREIGN KEY (feed) REFERENCES Feeds (id), + FOREIGN KEY (account_id) REFERENCES Accounts (id) ); \ No newline at end of file diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index 7324a89d0..cb66ceb81 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -16,4 +16,8 @@ CREATE TABLE IF NOT EXISTS TtRssAccounts ( FOREIGN KEY (id) REFERENCES Accounts (id) ); -- ! +ALTER TABLE Messages +ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); +-- ! + UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql index 7324a89d0..41f2135e7 100644 --- a/resources/misc/db_update_sqlite_3_4.sql +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -16,4 +16,7 @@ CREATE TABLE IF NOT EXISTS TtRssAccounts ( FOREIGN KEY (id) REFERENCES Accounts (id) ); -- ! +ALTER TABLE Messages +ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); +-- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 0046c73e4..9716ec781 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -71,8 +71,6 @@ void MessagesModel::setupFonts() { m_boldFont.setBold(true); } - - void MessagesModel::loadMessages(RootItem *item) { m_selectedItem = item; @@ -159,7 +157,8 @@ void MessagesModel::setupHeaderData() { /*: Tooltip for creation date of message.*/ tr("Created on") << /*: Tooltip for contents of message.*/ tr("Contents") << /*: Tooltip for "pdeleted" column in msg list.*/ tr("Permanently deleted") << - /*: Tooltip for attachments of message.*/ tr("Attachments"); + /*: Tooltip for attachments of message.*/ tr("Attachments") << + /*: Tooltip for account ID of message.*/ tr("Account ID"); m_tooltipData << tr("Id of the message.") << tr("Is message read?") << tr("Is message deleted?") << tr("Is message important?") << @@ -167,7 +166,7 @@ void MessagesModel::setupHeaderData() { tr("Title of the message.") << tr("Url of the message.") << tr("Author of the message.") << tr("Creation date of the message.") << tr("Contents of the message.") << tr("Is message permanently deleted from recycle bin?") << - tr("List of attachments."); + tr("List of attachments.") << tr("Account ID of message."); } Qt::ItemFlags MessagesModel::flags(const QModelIndex &index) const { diff --git a/src/definitions/definitions.h.in b/src/definitions/definitions.h.in index f084a00d9..f096b4033 100755 --- a/src/definitions/definitions.h.in +++ b/src/definitions/definitions.h.in @@ -183,6 +183,7 @@ #define MSG_DB_CONTENTS_INDEX 9 #define MSG_DB_PDELETED_INDEX 10 #define MSG_DB_ENCLOSURES_INDEX 11 +#define MSG_DB_ACCOUNT_ID_INDEX 12 // Indexes of columns as they are DEFINED IN THE TABLE for CATEGORIES. #define CAT_DB_ID_INDEX 0 diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index 17aad6651..ab62393c6 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -547,6 +547,7 @@ void MessagesView::adjustColumns() { hideColumn(MSG_DB_CONTENTS_INDEX); hideColumn(MSG_DB_PDELETED_INDEX); hideColumn(MSG_DB_ENCLOSURES_INDEX); + hideColumn(MSG_DB_ACCOUNT_ID_INDEX); qDebug("Adjusting column resize modes for MessagesView."); } diff --git a/src/miscellaneous/databasefactory.cpp b/src/miscellaneous/databasefactory.cpp index 0fa294735..1656d382c 100755 --- a/src/miscellaneous/databasefactory.cpp +++ b/src/miscellaneous/databasefactory.cpp @@ -205,7 +205,7 @@ QSqlDatabase DatabaseFactory::sqliteInitializeInMemoryDatabase() { // Copy all stuff. // WARNING: All tables belong here. QStringList tables; tables << QSL("Information") << QSL("Categories") << QSL("Feeds") << - QSL("FeedsData") << QSL("Messages") << QSL("Accounts") << QSL("TtRssAccounts"); + QSL("Accounts") << QSL("TtRssAccounts") << QSL("Messages"); foreach (const QString &table, tables) { copy_contents.exec(QString("INSERT INTO main.%1 SELECT * FROM storage.%1;").arg(table)); @@ -471,8 +471,8 @@ void DatabaseFactory::sqliteSaveMemoryDatabase() { // Copy all stuff. // WARNING: All tables belong here. - QStringList tables; tables << QSL("Categories") << QSL("Feeds") << QSL("FeedsData") << - QSL("Messages") << QSL("Accounts") << QSL("TtRssAccounts"); + QStringList tables; tables << QSL("Information") << QSL("Categories") << QSL("Feeds") << + QSL("Accounts") << QSL("TtRssAccounts") << QSL("Messages"); foreach (const QString &table, tables) { copy_contents.exec(QString(QSL("DELETE FROM storage.%1;")).arg(table)); diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 91125f8c3..cfaae4e08 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -140,9 +140,12 @@ QList StandardFeed::undeletedMessages() const { query_read_msg.setForwardOnly(true); query_read_msg.prepare("SELECT title, url, author, date_created, contents " "FROM Messages " - "WHERE is_deleted = 0 AND feed = :feed;"); + "WHERE is_deleted = 0 AND feed = :feed AND account_id = :account_id;"); query_read_msg.bindValue(QSL(":feed"), id()); + query_read_msg.bindValue(QSL(":account_id"), const_cast(this)->serviceRoot()->accountId()); + + // FIXME: Fix those const functions, this is fucking ugly. if (query_read_msg.exec()) { while (query_read_msg.next()) { @@ -186,13 +189,15 @@ void StandardFeed::updateCounts(bool including_total_count) { query_all.setForwardOnly(true); if (including_total_count) { - if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE feed = %1 AND is_deleted = 0;").arg(id())) && query_all.next()) { + if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE feed = %1 AND is_deleted = 0 AND account_id = %2;").arg(QString::number(id()), + QString::number(const_cast(this)->serviceRoot()->accountId()))) && query_all.next()) { m_totalCount = query_all.value(0).toInt(); } } // Obtain count of unread messages. - if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE feed = %1 AND is_deleted = 0 AND is_read = 0;").arg(id())) && query_all.next()) { + if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE feed = %1 AND is_deleted = 0 AND is_read = 0 AND account_id = %2;").arg(QString::number(id()), + QString::number(const_cast(this)->serviceRoot()->accountId()))) && query_all.next()) { int new_unread_count = query_all.value(0).toInt(); if (status() == NewMessages && new_unread_count < m_unreadCount) { @@ -514,8 +519,9 @@ bool StandardFeed::removeItself() { query_remove.setForwardOnly(true); // Remove all messages from this standard feed. - query_remove.prepare(QSL("DELETE FROM Messages WHERE feed = :feed;")); + query_remove.prepare(QSL("DELETE FROM Messages WHERE feed = :feed AND account_id = :account_id;")); query_remove.bindValue(QSL(":feed"), id()); + query_remove.bindValue(QSL(":account_id"), const_cast(this)->serviceRoot()->accountId()); if (!query_remove.exec()) { return false; @@ -638,6 +644,7 @@ int StandardFeed::updateMessages(const QList &messages) { int updated_messages = 0; QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); bool remove_duplicates = qApp->settings()->value(GROUP(Messages), SETTING(Messages::RemoveDuplicates)).toBool(); + int account_id = serviceRoot()->accountId(); // Prepare queries. QSqlQuery query_select(database); @@ -648,13 +655,13 @@ int StandardFeed::updateMessages(const QList &messages) { // WARNING: One feed CANNOT contain two (or more) messages with same AUTHOR AND TITLE AND URL AND DATE_CREATED. query_select.setForwardOnly(true); query_select.prepare("SELECT id, feed, date_created FROM Messages " - "WHERE feed = :feed AND title = :title AND url = :url AND author = :author;"); + "WHERE feed = :feed AND title = :title AND url = :url AND author = :author AND account_id = :account_id;"); // Used to insert new messages. query_insert.setForwardOnly(true); query_insert.prepare("INSERT INTO Messages " - "(feed, title, url, author, date_created, contents, enclosures) " - "VALUES (:feed, :title, :url, :author, :date_created, :contents, :enclosures);"); + "(feed, title, url, author, date_created, contents, enclosures, account_id) " + "VALUES (:feed, :title, :url, :author, :date_created, :contents, :enclosures, :account_id);"); if (remove_duplicates) { query_update.setForwardOnly(true); @@ -685,6 +692,7 @@ int StandardFeed::updateMessages(const QList &messages) { query_select.bindValue(QSL(":title"), message.m_title); query_select.bindValue(QSL(":url"), message.m_url); query_select.bindValue(QSL(":author"), message.m_author); + query_select.bindValue(QSL(":account_id"), account_id); query_select.exec(); QList datetime_stamps; @@ -706,6 +714,7 @@ int StandardFeed::updateMessages(const QList &messages) { query_insert.bindValue(QSL(":date_created"), message.m_created.toMSecsSinceEpoch()); query_insert.bindValue(QSL(":contents"), message.m_contents); query_insert.bindValue(QSL(":enclosures"), Enclosures::encodeEnclosuresToString(message.m_enclosures)); + query_insert.bindValue(QSL(":account_id"), account_id); if (query_insert.exec() && query_insert.numRowsAffected() == 1) { setStatus(NewMessages); @@ -790,5 +799,4 @@ StandardFeed::StandardFeed(const QSqlRecord &record) : Feed(NULL) { setAutoUpdateType(static_cast(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt())); setAutoUpdateInitialInterval(record.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt()); - updateCounts(true); } diff --git a/src/services/standard/standardrecyclebin.cpp b/src/services/standard/standardrecyclebin.cpp index 6086a80b7..bd0df5175 100755 --- a/src/services/standard/standardrecyclebin.cpp +++ b/src/services/standard/standardrecyclebin.cpp @@ -27,7 +27,6 @@ StandardRecycleBin::StandardRecycleBin(RootItem *parent) : RecycleBin(parent) { setId(ID_RECYCLE_BIN); - updateCounts(true); } StandardRecycleBin::~StandardRecycleBin() { @@ -63,7 +62,7 @@ void StandardRecycleBin::updateCounts(bool update_total_count) { QSqlQuery query_all(database); query_all.setForwardOnly(true); - if (query_all.exec(QSL("SELECT count(*) FROM Messages WHERE is_read = 0 AND is_deleted = 1 AND is_pdeleted = 0;")) && query_all.next()) { + if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE is_read = 0 AND is_deleted = 1 AND is_pdeleted = 0 AND account_id = %1;").arg(serviceRoot()->accountId())) && query_all.next()) { m_unreadCount = query_all.value(0).toInt(); } else { @@ -71,7 +70,7 @@ void StandardRecycleBin::updateCounts(bool update_total_count) { } if (update_total_count) { - if (query_all.exec(QSL("SELECT count(*) FROM Messages WHERE is_deleted = 1 AND is_pdeleted = 0;")) && query_all.next()) { + if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = %1;").arg(serviceRoot()->accountId())) && query_all.next()) { m_totalCount = query_all.value(0).toInt(); } else { diff --git a/src/services/standard/standardserviceentrypoint.cpp b/src/services/standard/standardserviceentrypoint.cpp index 730255b73..ca3615619 100755 --- a/src/services/standard/standardserviceentrypoint.cpp +++ b/src/services/standard/standardserviceentrypoint.cpp @@ -73,8 +73,9 @@ ServiceRoot *StandardServiceEntryPoint::createNewRoot() { if (query.exec(QString("INSERT INTO Accounts (id, type) VALUES (%1, '%2');").arg(QString::number(id_to_assing), SERVICE_CODE_STD_RSS))) { - StandardServiceRoot *root = new StandardServiceRoot(true); + StandardServiceRoot *root = new StandardServiceRoot(); root->setAccountId(id_to_assing); + root->loadFromDatabase(); return root; } else { @@ -90,8 +91,9 @@ QList StandardServiceEntryPoint::initializeSubtree() { if (query.exec(QString("SELECT id FROM Accounts WHERE type = '%1';").arg(SERVICE_CODE_STD_RSS))) { while (query.next()) { - StandardServiceRoot *root = new StandardServiceRoot(true); + StandardServiceRoot *root = new StandardServiceRoot(); root->setAccountId(query.value(0).toInt()); + root->loadFromDatabase(); roots.append(root); } } diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 7752375da..d02680f62 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -43,7 +43,7 @@ #include -StandardServiceRoot::StandardServiceRoot(bool load_from_db, RootItem *parent) +StandardServiceRoot::StandardServiceRoot(RootItem *parent) : ServiceRoot(parent), m_recycleBin(new StandardRecycleBin(this)), m_actionExportFeeds(NULL), m_actionImportFeeds(NULL), m_serviceMenu(QList()), m_addItemMenu(QList()), m_feedContextMenu(QList()), m_actionFeedFetchMetadata(NULL) { @@ -52,10 +52,6 @@ StandardServiceRoot::StandardServiceRoot(bool load_from_db, RootItem *parent) setIcon(StandardServiceEntryPoint().icon()); setDescription(tr("This is obligatory service account for standard RSS/RDF/ATOM feeds.")); setCreationDate(QDateTime::currentDateTime()); - - if (load_from_db) { - loadFromDatabase(); - } } StandardServiceRoot::~StandardServiceRoot() { @@ -116,10 +112,12 @@ bool StandardServiceRoot::deleteViaGui() { QSqlDatabase connection = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); // Remove all messages. - if (!QSqlQuery(connection).exec(QSL("DELETE FROM Messages;"))) { + if (!QSqlQuery(connection).exec(QString("DELETE FROM Messages WHERE account_id = %1;").arg(accountId()))) { return false; } + // TODO: todo + // Remove all feeds. if (!QSqlQuery(connection).exec(QSL("DELETE FROM Feeds;"))) { return false; @@ -131,7 +129,7 @@ bool StandardServiceRoot::deleteViaGui() { } // Switch "existence" flag. - bool data_removed = QSqlQuery(connection).exec(QString("DELETE FROM Accounts WHERE id = %1;").arg(QString::number(id()))); + bool data_removed = QSqlQuery(connection).exec(QString("DELETE FROM Accounts WHERE id = %1;").arg(accountId())); if (data_removed) { requestItemRemoval(this); @@ -223,7 +221,7 @@ bool StandardServiceRoot::markRecycleBinReadUnread(RootItem::ReadStatus read) { QSqlQuery query_read_msg(db_handle); query_read_msg.setForwardOnly(true); - if (!query_read_msg.prepare("UPDATE Messages SET is_read = :read WHERE is_deleted = 1;")) { + if (!query_read_msg.prepare("UPDATE Messages SET is_read = :read WHERE is_deleted = 1 AND account_id = :account_id;")) { qWarning("Query preparation failed for recycle bin read change."); db_handle.rollback(); @@ -231,6 +229,7 @@ bool StandardServiceRoot::markRecycleBinReadUnread(RootItem::ReadStatus read) { } query_read_msg.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0); + query_read_msg.bindValue(QSL(":account_id"), accountId()); if (!query_read_msg.exec()) { qDebug("Query execution for recycle bin read change failed."); @@ -305,7 +304,7 @@ bool StandardServiceRoot::restoreBin() { QSqlQuery query_empty_bin(db_handle); query_empty_bin.setForwardOnly(true); - if (!query_empty_bin.exec(QSL("UPDATE Messages SET is_deleted = 0 WHERE is_deleted = 1 AND is_pdeleted = 0;"))) { + if (!query_empty_bin.exec(QString("UPDATE Messages SET is_deleted = 0 WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = %1;").arg(accountId()))) { qWarning("Query execution failed for recycle bin restoring."); db_handle.rollback(); @@ -336,7 +335,7 @@ bool StandardServiceRoot::emptyBin() { QSqlQuery query_empty_bin(db_handle); query_empty_bin.setForwardOnly(true); - if (!query_empty_bin.exec(QSL("UPDATE Messages SET is_pdeleted = 1 WHERE is_deleted = 1;"))) { + if (!query_empty_bin.exec(QString("UPDATE Messages SET is_pdeleted = 1 WHERE is_deleted = 1 AND account_id = %1;").arg(accountId()))) { qWarning("Query execution failed for recycle bin emptying."); db_handle.rollback(); @@ -415,6 +414,7 @@ void StandardServiceRoot::loadFromDatabase(){ // As the last item, add recycle bin, which is needed. appendChild(m_recycleBin); + m_recycleBin->updateCounts(true); } QHash StandardServiceRoot::categoriesForItem(RootItem *root) { @@ -468,10 +468,12 @@ void StandardServiceRoot::assembleFeeds(FeedAssignment feeds) { if (feed.first == NO_PARENT_CATEGORY) { // This is top-level feed, add it to the root item. appendChild(feed.second); + feed.second->updateCounts(true); } else if (categories.contains(feed.first)) { // This feed belongs to this category. categories.value(feed.first)->appendChild(feed.second); + feed.second->updateCounts(true); } else { qWarning("Feed '%s' is loose, skipping it.", qPrintable(feed.second->title())); diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 0d0903118..c03461dfc 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -40,7 +40,7 @@ class StandardServiceRoot : public ServiceRoot { Q_OBJECT public: - explicit StandardServiceRoot(bool load_from_db, RootItem *parent = NULL); + explicit StandardServiceRoot(RootItem *parent = NULL); virtual ~StandardServiceRoot(); // Start/stop root. @@ -104,6 +104,8 @@ class StandardServiceRoot : public ServiceRoot { bool restoreBin(); bool emptyBin(); + void loadFromDatabase(); + public slots: void addNewCategory(); void addNewFeed(); @@ -115,8 +117,6 @@ class StandardServiceRoot : public ServiceRoot { // which are suitable as IN clause for SQL queries. QStringList textualFeedIds(const QList &feeds); - void loadFromDatabase(); - // Takes lists of feeds/categories and assembles // them into the tree structure. void assembleCategories(CategoryAssignment categories); From d5c7e3b8f47772b17554c8c324303c8589e6f4e6 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 10:53:48 +0100 Subject: [PATCH 112/203] Reworked attributes & code for Feeds and Categories too. Now each category and feed knows which account it belongs to. --- resources/misc/db_init_mysql.sql | 14 +++++++++---- resources/misc/db_init_sqlite.sql | 14 +++++++++---- resources/misc/db_update_mysql_3_4.sql | 7 ++++++- resources/misc/db_update_sqlite_3_4.sql | 6 ++++++ src/definitions/definitions.h.in | 1 + src/services/standard/standardcategory.cpp | 18 ++++------------- src/services/standard/standardfeed.cpp | 20 ++++++------------- src/services/standard/standardserviceroot.cpp | 4 ++-- 8 files changed, 45 insertions(+), 39 deletions(-) diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index 262d65e89..6c4569a53 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -34,10 +34,13 @@ DROP TABLE IF EXISTS Categories; CREATE TABLE IF NOT EXISTS Categories ( id INTEGER AUTO_INCREMENT PRIMARY KEY, parent_id INTEGER NOT NULL, - title VARCHAR(100) NOT NULL UNIQUE CHECK (title != ''), + title VARCHAR(100) NOT NULL CHECK (title != ''), description TEXT, date_created BIGINT NOT NULL CHECK (date_created != 0), - icon BLOB + icon BLOB, + account_id INTEGER NOT NULL, + + FOREIGN KEY (account_id) REFERENCES Accounts (id) ); -- ! DROP TABLE IF EXISTS Feeds; @@ -50,13 +53,16 @@ CREATE TABLE IF NOT EXISTS Feeds ( icon BLOB, category INTEGER NOT NULL CHECK (category >= -1), encoding TEXT NOT NULL CHECK (encoding != ''), - url VARCHAR(100) NOT NULL UNIQUE CHECK (url != ''), + url VARCHAR(100) NOT NULL CHECK (url != ''), protected INTEGER(1) NOT NULL CHECK (protected >= 0 AND protected <= 1), username TEXT, password TEXT, update_type INTEGER(1) NOT NULL CHECK (update_type >= 0), update_interval INTEGER NOT NULL DEFAULT 15 CHECK (update_interval >= 5), - type INTEGER NOT NULL CHECK (type >= 0) + type INTEGER NOT NULL CHECK (type >= 0), + account_id INTEGER NOT NULL, + + FOREIGN KEY (account_id) REFERENCES Accounts (id) ); -- ! DROP TABLE IF EXISTS Messages; diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index c5d9f3fe8..e64ccbad2 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -29,10 +29,13 @@ DROP TABLE IF EXISTS Categories; CREATE TABLE IF NOT EXISTS Categories ( id INTEGER PRIMARY KEY, parent_id INTEGER NOT NULL, - title TEXT NOT NULL UNIQUE CHECK (title != ''), + title TEXT NOT NULL CHECK (title != ''), description TEXT, date_created INTEGER NOT NULL CHECK (date_created != 0), - icon BLOB + icon BLOB, + account_id INTEGER NOT NULL, + + FOREIGN KEY (account_id) REFERENCES Accounts (id) ); -- ! DROP TABLE IF EXISTS Feeds; @@ -45,13 +48,16 @@ CREATE TABLE IF NOT EXISTS Feeds ( icon BLOB, category INTEGER NOT NULL CHECK (category >= -1), encoding TEXT NOT NULL CHECK (encoding != ''), - url TEXT NOT NULL UNIQUE CHECK (url != ''), + url TEXT NOT NULL CHECK (url != ''), protected INTEGER(1) NOT NULL CHECK (protected >= 0 AND protected <= 1), username TEXT, password TEXT, update_type INTEGER(1) NOT NULL CHECK (update_type >= 0), update_interval INTEGER NOT NULL CHECK (update_interval >= 5) DEFAULT 15, - type INTEGER NOT NULL CHECK (type >= 0) + type INTEGER NOT NULL CHECK (type >= 0), + account_id INTEGER NOT NULL, + + FOREIGN KEY (account_id) REFERENCES Accounts (id) ); -- ! DROP TABLE IF EXISTS Messages; diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index cb66ceb81..1d41ef9ca 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -19,5 +19,10 @@ CREATE TABLE IF NOT EXISTS TtRssAccounts ( ALTER TABLE Messages ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); -- ! - +ALTER TABLE Feeds +ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); +-- ! +ALTER TABLE Categories +ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); +-- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql index 41f2135e7..1d41ef9ca 100644 --- a/resources/misc/db_update_sqlite_3_4.sql +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -19,4 +19,10 @@ CREATE TABLE IF NOT EXISTS TtRssAccounts ( ALTER TABLE Messages ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); -- ! +ALTER TABLE Feeds +ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); +-- ! +ALTER TABLE Categories +ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); +-- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/src/definitions/definitions.h.in b/src/definitions/definitions.h.in index f096b4033..508d718eb 100755 --- a/src/definitions/definitions.h.in +++ b/src/definitions/definitions.h.in @@ -208,6 +208,7 @@ #define FDS_DB_UPDATE_TYPE_INDEX 11 #define FDS_DB_UPDATE_INTERVAL_INDEX 12 #define FDS_DB_TYPE_INDEX 13 +#define FDS_DB_ACCOUNT_ID_INDEX 14 // Indexes of columns for feed models. #define FDS_MODEL_TITLE_INDEX 0 diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index dc7a940b3..1aabaa01f 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -174,13 +174,14 @@ bool StandardCategory::addItself(RootItem *parent) { query_add.setForwardOnly(true); query_add.prepare("INSERT INTO Categories " - "(parent_id, title, description, date_created, icon) " - "VALUES (:parent_id, :title, :description, :date_created, :icon);"); + "(parent_id, title, description, date_created, icon, account_id) " + "VALUES (:parent_id, :title, :description, :date_created, :icon, :account_id);"); query_add.bindValue(QSL(":parent_id"), parent->id()); query_add.bindValue(QSL(":title"), title()); query_add.bindValue(QSL(":description"), description()); query_add.bindValue(QSL(":date_created"), creationDate().toMSecsSinceEpoch()); query_add.bindValue(QSL(":icon"), qApp->icons()->toByteArray(icon())); + query_add.bindValue(QSL(":account_id"), parent->getParentServiceRoot()->accountId()); if (!query_add.exec()) { qDebug("Failed to add category to database: %s.", qPrintable(query_add.lastError().text())); @@ -189,18 +190,7 @@ bool StandardCategory::addItself(RootItem *parent) { return false; } - query_add.prepare(QSL("SELECT id FROM Categories WHERE title = :title;")); - query_add.bindValue(QSL(":title"), title()); - - if (query_add.exec() && query_add.next()) { - // New category was added, fetch is primary id - // from the database. - setId(query_add.value(0).toInt()); - } - else { - // Something failed. - return false; - } + setId(query_add.lastInsertId().toInt()); return true; } diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index cfaae4e08..bfc240d00 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -519,9 +519,8 @@ bool StandardFeed::removeItself() { query_remove.setForwardOnly(true); // Remove all messages from this standard feed. - query_remove.prepare(QSL("DELETE FROM Messages WHERE feed = :feed AND account_id = :account_id;")); + query_remove.prepare(QSL("DELETE FROM Messages WHERE feed = :feed;")); query_remove.bindValue(QSL(":feed"), id()); - query_remove.bindValue(QSL(":account_id"), const_cast(this)->serviceRoot()->accountId()); if (!query_remove.exec()) { return false; @@ -541,8 +540,8 @@ bool StandardFeed::addItself(RootItem *parent) { query_add_feed.setForwardOnly(true); query_add_feed.prepare("INSERT INTO Feeds " - "(title, description, date_created, icon, category, encoding, url, protected, username, password, update_type, update_interval, type) " - "VALUES (:title, :description, :date_created, :icon, :category, :encoding, :url, :protected, :username, :password, :update_type, :update_interval, :type);"); + "(title, description, date_created, icon, category, encoding, url, protected, username, password, update_type, update_interval, type, account_id) " + "VALUES (:title, :description, :date_created, :icon, :category, :encoding, :url, :protected, :username, :password, :update_type, :update_interval, :type, :account_id);"); query_add_feed.bindValue(QSL(":title"), title()); query_add_feed.bindValue(QSL(":description"), description()); query_add_feed.bindValue(QSL(":date_created"), creationDate().toMSecsSinceEpoch()); @@ -552,6 +551,7 @@ bool StandardFeed::addItself(RootItem *parent) { query_add_feed.bindValue(QSL(":url"), url()); query_add_feed.bindValue(QSL(":protected"), (int) passwordProtected()); query_add_feed.bindValue(QSL(":username"), username()); + query_add_feed.bindValue(QSL(":account_id"), parent->getParentServiceRoot()->accountId()); if (password().isEmpty()) { query_add_feed.bindValue(QSL(":password"), password()); @@ -571,16 +571,8 @@ bool StandardFeed::addItself(RootItem *parent) { return false; } - query_add_feed.prepare(QSL("SELECT id FROM Feeds WHERE url = :url;")); - query_add_feed.bindValue(QSL(":url"), url()); - if (query_add_feed.exec() && query_add_feed.next()) { - // New feed was added, fetch is primary id from the database. - setId(query_add_feed.value(0).toInt()); - } - else { - // Something failed. - return false; - } + // New feed was added, fetch is primary id from the database. + setId(query_add_feed.lastInsertId().toInt()); return true; } diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index d02680f62..9ffd1b723 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -119,12 +119,12 @@ bool StandardServiceRoot::deleteViaGui() { // TODO: todo // Remove all feeds. - if (!QSqlQuery(connection).exec(QSL("DELETE FROM Feeds;"))) { + if (!QSqlQuery(connection).exec(QSL("DELETE FROM Feeds WHERE account_id = %1;").arg(accountId()))) { return false; } // Remove all categories. - if (!QSqlQuery(connection).exec(QSL("DELETE FROM Categories;"))) { + if (!QSqlQuery(connection).exec(QSL("DELETE FROM Categories WHERE account_id = %1;").arg(accountId()))) { return false; } From 441e0e863217ce277e7254885749ceb4de002521 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 11:02:19 +0100 Subject: [PATCH 113/203] TT-RSS accounts now store its additions/edits to DB/model. --- src/services/tt-rss/gui/formeditaccount.cpp | 2 +- src/services/tt-rss/ttrssserviceroot.cpp | 23 ++++++++++++++------- src/services/tt-rss/ttrssserviceroot.h | 2 +- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/services/tt-rss/gui/formeditaccount.cpp b/src/services/tt-rss/gui/formeditaccount.cpp index 7ebe6d61f..36f543f9b 100755 --- a/src/services/tt-rss/gui/formeditaccount.cpp +++ b/src/services/tt-rss/gui/formeditaccount.cpp @@ -136,7 +136,7 @@ void FormEditAccount::onClickedOk() { if (m_editableRoot == NULL) { // We want to confirm newly created account. // So save new account into DB, setup its properties. - m_editableRoot = new TtRssServiceRoot(false); + m_editableRoot = new TtRssServiceRoot(); } m_editableRoot->network()->setUrl(m_ui->m_txtUrl->lineEdit()->text()); diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index afbd99ad2..be64c7dd3 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -26,14 +26,10 @@ #include -TtRssServiceRoot::TtRssServiceRoot(bool load_from_db, RootItem *parent) +TtRssServiceRoot::TtRssServiceRoot(RootItem *parent) : ServiceRoot(parent), m_network(new TtRssNetworkFactory) { setIcon(TtRssServiceEntryPoint().icon()); setCreationDate(QDateTime::currentDateTime()); - - if (load_from_db) { - loadFromDatabase(); - } } TtRssServiceRoot::~TtRssServiceRoot() { @@ -145,10 +141,21 @@ TtRssNetworkFactory *TtRssServiceRoot::network() const { void TtRssServiceRoot::saveToDatabase() { if (accountId() != NO_PARENT_CATEGORY) { // We are overwritting previously saved data. - // TODO: todo + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + QSqlQuery query(database); - updateTitle(); - itemChanged(QList() << this); + query.prepare("UPDATE TtRssAccounts " + "SET username = :username, password = :password, url = :url " + "WHERE id = :id;"); + query.bindValue(":username", m_network->username()); + query.bindValue(":password", m_network->password()); + query.bindValue(":url", m_network->url()); + query.bindValue(":id", accountId()); + + if (query.exec()) { + updateTitle(); + itemChanged(QList() << this); + } } else { // We are probably saving newly added account. diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 5060b94f8..b57912c79 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -29,7 +29,7 @@ class TtRssServiceRoot : public ServiceRoot { Q_OBJECT public: - explicit TtRssServiceRoot(bool load_from_db, RootItem *parent = NULL); + explicit TtRssServiceRoot(RootItem *parent = NULL); virtual ~TtRssServiceRoot(); void start(); From 4f2a3709011c4e4e887bc996ad1f1a352ffde3b8 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 11:14:14 +0100 Subject: [PATCH 114/203] Some more advancements, stored TT-RSS accounts are now correctly loaded w/o feeds/categories so far. --- src/core/messagesmodel.cpp | 2 +- .../tt-rss/ttrssserviceentrypoint.cpp | 22 ++++++++++++++++++- src/services/tt-rss/ttrssserviceroot.cpp | 2 +- src/services/tt-rss/ttrssserviceroot.h | 3 +-- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 9716ec781..a0189a798 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -81,7 +81,7 @@ void MessagesModel::loadMessages(RootItem *item) { if (!item->getParentServiceRoot()->loadMessagesForItem(item, this)) { setFilter("true != true"); qWarning("Loading of messages from item '%s' failed.", qPrintable(item->title())); - qApp->showGuiMessage(tr("Loading of messages from item '%s' failed.").arg(item->title()), + qApp->showGuiMessage(tr("Loading of messages from item '%1' failed.").arg(item->title()), tr("Loading of messages failed, maybe messages could not be downloaded."), QSystemTrayIcon::Critical, qApp->mainForm(), diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp index 3b02f255e..02c03c88a 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.cpp +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -23,8 +23,10 @@ #include "gui/dialogs/formmain.h" #include "services/tt-rss/gui/formeditaccount.h" #include "services/tt-rss/ttrssserviceroot.h" +#include "services/tt-rss/network/ttrssnetworkfactory.h" #include +#include TtRssServiceEntryPoint::TtRssServiceEntryPoint(){ @@ -72,5 +74,23 @@ ServiceRoot *TtRssServiceEntryPoint::createNewRoot() { } QList TtRssServiceEntryPoint::initializeSubtree() { - return QList(); + // Check DB if standard account is enabled. + QSqlDatabase database = qApp->database()->connection(QSL("TtRssServiceEntryPoint"), DatabaseFactory::FromSettings); + QSqlQuery query(database); + QList roots; + + if (query.exec("SELECT id, username, password, url FROM TtRssAccounts;")) { + while (query.next()) { + TtRssServiceRoot *root = new TtRssServiceRoot(); + root->setAccountId(query.value(0).toInt()); + root->network()->setUsername(query.value(1).toString()); + root->network()->setPassword(query.value(2).toString()); + root->network()->setUrl(query.value(3).toString()); + root->updateTitle(); + root->loadFromDatabase(); + roots.append(root); + } + } + + return roots; } diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index be64c7dd3..383e2fb0a 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -184,7 +184,7 @@ void TtRssServiceRoot::saveToDatabase() { } void TtRssServiceRoot::loadFromDatabase() { - // Account ID is set, load connection data from DB. + // TODO: Load feeds/categories from DB. } void TtRssServiceRoot::updateTitle() { diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index b57912c79..f6b40ea7e 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -67,10 +67,9 @@ class TtRssServiceRoot : public ServiceRoot { void saveToDatabase(); void loadFromDatabase(); - - private: void updateTitle(); + private: TtRssNetworkFactory *m_network; }; From ca2d4117fbfe0288d6f98b0c1b5818a881531a6c Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 11:57:07 +0100 Subject: [PATCH 115/203] Standard account now loads only its own feeds/cats. --- src/services/standard/standardserviceroot.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 9ffd1b723..6dfa10890 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -363,7 +363,7 @@ void StandardServiceRoot::loadFromDatabase(){ QSqlQuery query_categories(database); query_categories.setForwardOnly(true); - if (!query_categories.exec(QSL("SELECT * FROM Categories;")) || query_categories.lastError().isValid()) { + if (!query_categories.exec(QString("SELECT * FROM Categories WHERE account_id = %1;").arg(accountId())) || query_categories.lastError().isValid()) { qFatal("Query for obtaining categories failed. Error message: '%s'.", qPrintable(query_categories.lastError().text())); } @@ -380,7 +380,7 @@ void StandardServiceRoot::loadFromDatabase(){ QSqlQuery query_feeds(database); query_feeds.setForwardOnly(true); - if (!query_feeds.exec(QSL("SELECT * FROM Feeds;")) || query_feeds.lastError().isValid()) { + if (!query_feeds.exec(QSL("SELECT * FROM Feeds WHERE account_id = %1;").arg(accountId())) || query_feeds.lastError().isValid()) { qFatal("Query for obtaining feeds failed. Error message: '%s'.", qPrintable(query_feeds.lastError().text())); } From d5ccfd86695527a244cf5e164c67fa031167fb05 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 13:03:29 +0100 Subject: [PATCH 116/203] Version bumped. --- CMakeLists.txt | 4 ++-- resources/text/CHANGELOG | 2 +- src/core/rootitem.cpp | 12 ++++++++++ src/services/abstract/recyclebin.cpp | 2 +- src/services/standard/standardcategory.cpp | 6 +---- src/services/standard/standardfeed.cpp | 6 +---- src/services/standard/standardserviceroot.cpp | 6 +---- src/services/tt-rss/gui/formeditaccount.cpp | 23 +++++++++++-------- src/services/tt-rss/ttrssserviceroot.cpp | 16 ++++++++----- 9 files changed, 43 insertions(+), 34 deletions(-) mode change 100644 => 100755 src/services/abstract/recyclebin.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a49c1871..1246d12a8 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,8 +65,8 @@ project(rssguard) set(APP_NAME "RSS Guard") set(APP_LOW_NAME "rssguard") -set(APP_VERSION "2.5.3") -set(FILE_VERSION "2,5,3,0") +set(APP_VERSION "2.6.0") +set(FILE_VERSION "2,6,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 045a7e7d5..9da0d179d 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -12,7 +12,7 @@ -

            2.5.3

            +

            2.6.0

            Added:
              diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index d2c78a5e3..ff9b3ed8a 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -115,6 +115,18 @@ QVariant RootItem::data(int column, int role) const { Q_UNUSED(role) switch (role) { + case Qt::ToolTipRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return m_title; + } + else if (column == FDS_MODEL_COUNTS_INDEX) { + //: Tooltip for "unread" column of feed list. + return tr("%n unread message(s).", 0, countOfUnreadMessages()); + } + else { + return QVariant(); + } + case Qt::EditRole: if (column == FDS_MODEL_TITLE_INDEX) { return m_title; diff --git a/src/services/abstract/recyclebin.cpp b/src/services/abstract/recyclebin.cpp old mode 100644 new mode 100755 index 042c5c989..dc29f0117 --- a/src/services/abstract/recyclebin.cpp +++ b/src/services/abstract/recyclebin.cpp @@ -35,7 +35,7 @@ RecycleBin::~RecycleBin() { QVariant RecycleBin::data(int column, int role) const { switch (role) { case Qt::ToolTipRole: - return tr("Recycle bin\n%1").arg(tr("%n deleted message(s).", 0, countOfAllMessages())); + return tr("Recycle bin\n\n%1").arg(tr("%n deleted message(s).", 0, countOfAllMessages())); default: return RootItem::data(column, role); diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index 1aabaa01f..8c7add25c 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -77,12 +77,8 @@ QVariant StandardCategory::data(int column, int role) const { tr("\nThis category does not contain any nested items.") : QString()); } - else if (column == FDS_MODEL_COUNTS_INDEX) { - //: Tooltip for "unread" column of feed list. - return tr("%n unread message(s).", "", countOfUnreadMessages()); - } else { - return QVariant(); + return Category::data(column, role); } default: diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index bfc240d00..09107d65f 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -416,12 +416,8 @@ QVariant StandardFeed::data(int column, int role) const { auto_update_string, NetworkFactory::networkErrorText(m_networkError)); } - else if (column == FDS_MODEL_COUNTS_INDEX) { - //: Tooltip for "unread" column of feed list. - return tr("%n unread message(s).", 0, countOfUnreadMessages()); - } else { - return QVariant(); + return Feed::data(column, role); } case Qt::ForegroundRole: diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 6dfa10890..ec9c7d861 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -144,12 +144,8 @@ QVariant StandardServiceRoot::data(int column, int role) const { if (column == FDS_MODEL_TITLE_INDEX) { return tr("This is service account for standard RSS/RDF/ATOM feeds.\n\nAccount ID: %1").arg(accountId()); } - else if (column == FDS_MODEL_COUNTS_INDEX) { - //: Tooltip for "unread" column of feed list. - return tr("%n unread message(s).", 0, countOfUnreadMessages()); - } else { - return QVariant(); + return ServiceRoot::data(column, role); } default: diff --git a/src/services/tt-rss/gui/formeditaccount.cpp b/src/services/tt-rss/gui/formeditaccount.cpp index 36f543f9b..fbfb43375 100755 --- a/src/services/tt-rss/gui/formeditaccount.cpp +++ b/src/services/tt-rss/gui/formeditaccount.cpp @@ -32,9 +32,9 @@ FormEditAccount::FormEditAccount(QWidget *parent) setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint); setWindowIcon(qApp->icons()->fromTheme(QSL("application-ttrss"))); - m_ui->m_txtPassword->lineEdit()->setPlaceholderText(tr("Password for your TT-RSS account.")); - m_ui->m_txtUsername->lineEdit()->setPlaceholderText(tr("Username for your TT-RSS account.")); - m_ui->m_txtUrl->lineEdit()->setPlaceholderText(tr("FULL URL of your TT-RSS instance WITH trailing \"/api/\" string.")); + m_ui->m_txtPassword->lineEdit()->setPlaceholderText(tr("Password for your TT-RSS account")); + m_ui->m_txtUsername->lineEdit()->setPlaceholderText(tr("Username for your TT-RSS account")); + m_ui->m_txtUrl->lineEdit()->setPlaceholderText(tr("FULL URL of your TT-RSS instance WITH trailing \"/api/\" string")); m_ui->m_lblTestResult->setStatus(WidgetWithStatus::Information, tr("No test done yet."), tr("Here, results of connection test are shown.")); @@ -48,12 +48,12 @@ FormEditAccount::FormEditAccount(QWidget *parent) connect(m_ui->m_checkShowPassword, SIGNAL(toggled(bool)), this, SLOT(displayPassword(bool))); connect(m_ui->m_buttonBox, SIGNAL(accepted()), this, SLOT(onClickedOk())); connect(m_ui->m_buttonBox, SIGNAL(rejected()), this, SLOT(onClickedCancel())); - connect(m_ui->m_txtPassword->lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(onPasswordChanged())); - connect(m_ui->m_txtUsername->lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(onUsernameChanged())); - connect(m_ui->m_txtUrl->lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(onUrlChanged())); - connect(m_ui->m_txtPassword->lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(checkOkButton())); - connect(m_ui->m_txtUsername->lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(checkOkButton())); - connect(m_ui->m_txtUrl->lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(checkOkButton())); + connect(m_ui->m_txtPassword->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(onPasswordChanged())); + connect(m_ui->m_txtUsername->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(onUsernameChanged())); + connect(m_ui->m_txtUrl->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(onUrlChanged())); + connect(m_ui->m_txtPassword->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(checkOkButton())); + connect(m_ui->m_txtUsername->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(checkOkButton())); + connect(m_ui->m_txtUrl->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(checkOkButton())); connect(m_ui->m_btnTestSetup, SIGNAL(clicked()), this, SLOT(performTest())); onPasswordChanged(); @@ -76,6 +76,11 @@ TtRssServiceRoot *FormEditAccount::execForCreate() { void FormEditAccount::execForEdit(TtRssServiceRoot *existing_root) { setWindowTitle(tr("Edit existing Tiny Tiny RSS account")); m_editableRoot = existing_root; + + m_ui->m_txtUsername->lineEdit()->setText(existing_root->network()->username()); + m_ui->m_txtPassword->lineEdit()->setText(existing_root->network()->password()); + m_ui->m_txtUrl->lineEdit()->setText(existing_root->network()->url()); + exec(); } diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 383e2fb0a..dc419e6bf 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -19,11 +19,14 @@ #include "miscellaneous/application.h" #include "miscellaneous/settings.h" +#include "gui/dialogs/formmain.h" #include "services/tt-rss/ttrssserviceentrypoint.h" #include "services/tt-rss/network/ttrssnetworkfactory.h" +#include "services/tt-rss/gui/formeditaccount.h" #include #include +#include TtRssServiceRoot::TtRssServiceRoot(RootItem *parent) @@ -51,6 +54,9 @@ QString TtRssServiceRoot::code() { } bool TtRssServiceRoot::editViaGui() { + QPointer form_pointer = new FormEditAccount(qApp->mainForm()); + form_pointer.data()->execForEdit(this); + delete form_pointer.data(); return false; } @@ -71,14 +77,12 @@ QVariant TtRssServiceRoot::data(int column, int role) const { case Qt::ToolTipRole: // TODO: zobrazovat pokročile informace a statistiky. if (column == FDS_MODEL_TITLE_INDEX) { - return tr("This is service account TT-RSS (TinyTiny RSS) server."); - } - else if (column == FDS_MODEL_COUNTS_INDEX) { - //: Tooltip for "unread" column of feed list. - return tr("%n unread message(s).", 0, countOfUnreadMessages()); + return tr("Tiny Tiny RSS\n\nAccount ID: %3\nUsername: %1\nServer: %2").arg(m_network->username(), + m_network->url(), + QString::number(accountId())); } else { - return QVariant(); + return ServiceRoot::data(column, role); } default: From aeb7f98cbb6761784dfb5fb15a93326050500783 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 13:15:28 +0100 Subject: [PATCH 117/203] Added some example. --- src/services/tt-rss/network/ttrssnetworkfactory.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index 9028613f5..f90f7d4b9 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -53,6 +53,15 @@ void TtRssNetworkFactory::setPassword(const QString &password) { m_password = password; } +// TODO: ukazky + +/* ukazky + * prihlaseni - curl -L -d '{"op":"login","user":"admin","password":"XXX"}' http://rss.rotterovi.eu/api/ + * ziska seznam VSECH zprav - curl -L -d '{"sid":"xxx","op":"getHeadlines","feed_id":-4,"include_nested":true,"include_attachments":true,"show_content":true}' http://rss.rotterovi.eu/api/ + * seznam kategorii vcetne unread countu - curl -L -d '{"sid":"e9528741496d0d6aa5021e67ca519823","op":"getCategories","include_nested":true,"include_empty":false}' http://rss.rotterovi.eu/api/ + * */ + + LoginResult TtRssNetworkFactory::login() { QtJson::JsonObject json; json["op"] = "login"; From ff67c86517e7ee1b41828b26286c7d3f1e0f1d88 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 13:37:32 +0100 Subject: [PATCH 118/203] Added "custom_id" columns for cats/feeds/messages to hold custom ID of the items from online services. --- resources/misc/db_init_mysql.sql | 3 +++ resources/misc/db_init_sqlite.sql | 3 +++ resources/misc/db_update_mysql_3_4.sql | 9 +++++++++ resources/misc/db_update_sqlite_3_4.sql | 9 +++++++++ src/core/messagesmodel.cpp | 5 +++-- src/definitions/definitions.h.in | 4 ++++ src/gui/messagesview.cpp | 1 + 7 files changed, 32 insertions(+), 2 deletions(-) diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index 6c4569a53..91e1c5cb6 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -39,6 +39,7 @@ CREATE TABLE IF NOT EXISTS Categories ( date_created BIGINT NOT NULL CHECK (date_created != 0), icon BLOB, account_id INTEGER NOT NULL, + custom_id INTEGER, FOREIGN KEY (account_id) REFERENCES Accounts (id) ); @@ -61,6 +62,7 @@ CREATE TABLE IF NOT EXISTS Feeds ( update_interval INTEGER NOT NULL DEFAULT 15 CHECK (update_interval >= 5), type INTEGER NOT NULL CHECK (type >= 0), account_id INTEGER NOT NULL, + custom_id INTEGER, FOREIGN KEY (account_id) REFERENCES Accounts (id) ); @@ -81,6 +83,7 @@ CREATE TABLE IF NOT EXISTS Messages ( is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1), enclosures TEXT, account_id INTEGER NOT NULL, + custom_id INTEGER, FOREIGN KEY (feed) REFERENCES Feeds (id), FOREIGN KEY (account_id) REFERENCES Accounts (id) diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index e64ccbad2..05bdaacc6 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -34,6 +34,7 @@ CREATE TABLE IF NOT EXISTS Categories ( date_created INTEGER NOT NULL CHECK (date_created != 0), icon BLOB, account_id INTEGER NOT NULL, + custom_id INTEGER, FOREIGN KEY (account_id) REFERENCES Accounts (id) ); @@ -56,6 +57,7 @@ CREATE TABLE IF NOT EXISTS Feeds ( update_interval INTEGER NOT NULL CHECK (update_interval >= 5) DEFAULT 15, type INTEGER NOT NULL CHECK (type >= 0), account_id INTEGER NOT NULL, + custom_id INTEGER, FOREIGN KEY (account_id) REFERENCES Accounts (id) ); @@ -76,6 +78,7 @@ CREATE TABLE IF NOT EXISTS Messages ( is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1), enclosures TEXT, account_id INTEGER NOT NULL, + custom_id INTEGER, FOREIGN KEY (feed) REFERENCES Feeds (id), FOREIGN KEY (account_id) REFERENCES Accounts (id) diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index 1d41ef9ca..d194dacfd 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -25,4 +25,13 @@ ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); ALTER TABLE Categories ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); -- ! +ALTER TABLE Messages +ADD COLUMN custom_id INTEGER; +-- ! +ALTER TABLE Feeds +ADD COLUMN custom_id INTEGER; +-- ! +ALTER TABLE Categories +ADD COLUMN custom_id INTEGER; +-- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql index 1d41ef9ca..d194dacfd 100644 --- a/resources/misc/db_update_sqlite_3_4.sql +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -25,4 +25,13 @@ ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); ALTER TABLE Categories ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); -- ! +ALTER TABLE Messages +ADD COLUMN custom_id INTEGER; +-- ! +ALTER TABLE Feeds +ADD COLUMN custom_id INTEGER; +-- ! +ALTER TABLE Categories +ADD COLUMN custom_id INTEGER; +-- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index a0189a798..62af8ae12 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -158,7 +158,8 @@ void MessagesModel::setupHeaderData() { /*: Tooltip for contents of message.*/ tr("Contents") << /*: Tooltip for "pdeleted" column in msg list.*/ tr("Permanently deleted") << /*: Tooltip for attachments of message.*/ tr("Attachments") << - /*: Tooltip for account ID of message.*/ tr("Account ID"); + /*: Tooltip for account ID of message.*/ tr("Account ID") << + /*: Tooltip for custom ID of message.*/ tr("Custom ID"); m_tooltipData << tr("Id of the message.") << tr("Is message read?") << tr("Is message deleted?") << tr("Is message important?") << @@ -166,7 +167,7 @@ void MessagesModel::setupHeaderData() { tr("Title of the message.") << tr("Url of the message.") << tr("Author of the message.") << tr("Creation date of the message.") << tr("Contents of the message.") << tr("Is message permanently deleted from recycle bin?") << - tr("List of attachments.") << tr("Account ID of message."); + tr("List of attachments.") << tr("Account ID of the message.") << tr("Custom ID of the message"); } Qt::ItemFlags MessagesModel::flags(const QModelIndex &index) const { diff --git a/src/definitions/definitions.h.in b/src/definitions/definitions.h.in index 508d718eb..33261bb8f 100755 --- a/src/definitions/definitions.h.in +++ b/src/definitions/definitions.h.in @@ -184,6 +184,7 @@ #define MSG_DB_PDELETED_INDEX 10 #define MSG_DB_ENCLOSURES_INDEX 11 #define MSG_DB_ACCOUNT_ID_INDEX 12 +#define MSG_DB_CUSTOM_ID_INDEX 13 // Indexes of columns as they are DEFINED IN THE TABLE for CATEGORIES. #define CAT_DB_ID_INDEX 0 @@ -192,6 +193,8 @@ #define CAT_DB_DESCRIPTION_INDEX 3 #define CAT_DB_DCREATED_INDEX 4 #define CAT_DB_ICON_INDEX 5 +#define CAT_DB_ACCOUNT_ID_INDEX 6 +#define CAT_DB_CUSTOM_ID_INDEX 7 // Indexes of columns as they are DEFINED IN THE TABLE for FEEDS. #define FDS_DB_ID_INDEX 0 @@ -209,6 +212,7 @@ #define FDS_DB_UPDATE_INTERVAL_INDEX 12 #define FDS_DB_TYPE_INDEX 13 #define FDS_DB_ACCOUNT_ID_INDEX 14 +#define FDS_DB_CUSTOM_ID_INDEX 15 // Indexes of columns for feed models. #define FDS_MODEL_TITLE_INDEX 0 diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index ab62393c6..5a50c6193 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -548,6 +548,7 @@ void MessagesView::adjustColumns() { hideColumn(MSG_DB_PDELETED_INDEX); hideColumn(MSG_DB_ENCLOSURES_INDEX); hideColumn(MSG_DB_ACCOUNT_ID_INDEX); + hideColumn(MSG_DB_CUSTOM_ID_INDEX); qDebug("Adjusting column resize modes for MessagesView."); } From 10f1841b54d41b7aa70fbca39ff72c86e3d88912 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 13:42:50 +0100 Subject: [PATCH 119/203] Custom ID converted to string, added as property to Message class. --- resources/misc/db_init_mysql.sql | 6 +++--- resources/misc/db_init_sqlite.sql | 6 +++--- resources/misc/db_update_mysql_3_4.sql | 6 +++--- resources/misc/db_update_sqlite_3_4.sql | 6 +++--- src/core/message.cpp | 2 +- src/core/message.h | 1 + 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index 91e1c5cb6..f95265c81 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -39,7 +39,7 @@ CREATE TABLE IF NOT EXISTS Categories ( date_created BIGINT NOT NULL CHECK (date_created != 0), icon BLOB, account_id INTEGER NOT NULL, - custom_id INTEGER, + custom_id TEXT, FOREIGN KEY (account_id) REFERENCES Accounts (id) ); @@ -62,7 +62,7 @@ CREATE TABLE IF NOT EXISTS Feeds ( update_interval INTEGER NOT NULL DEFAULT 15 CHECK (update_interval >= 5), type INTEGER NOT NULL CHECK (type >= 0), account_id INTEGER NOT NULL, - custom_id INTEGER, + custom_id TEXT, FOREIGN KEY (account_id) REFERENCES Accounts (id) ); @@ -83,7 +83,7 @@ CREATE TABLE IF NOT EXISTS Messages ( is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1), enclosures TEXT, account_id INTEGER NOT NULL, - custom_id INTEGER, + custom_id TEXT, FOREIGN KEY (feed) REFERENCES Feeds (id), FOREIGN KEY (account_id) REFERENCES Accounts (id) diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index 05bdaacc6..5a7290abc 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -34,7 +34,7 @@ CREATE TABLE IF NOT EXISTS Categories ( date_created INTEGER NOT NULL CHECK (date_created != 0), icon BLOB, account_id INTEGER NOT NULL, - custom_id INTEGER, + custom_id TEXT, FOREIGN KEY (account_id) REFERENCES Accounts (id) ); @@ -57,7 +57,7 @@ CREATE TABLE IF NOT EXISTS Feeds ( update_interval INTEGER NOT NULL CHECK (update_interval >= 5) DEFAULT 15, type INTEGER NOT NULL CHECK (type >= 0), account_id INTEGER NOT NULL, - custom_id INTEGER, + custom_id TEXT, FOREIGN KEY (account_id) REFERENCES Accounts (id) ); @@ -78,7 +78,7 @@ CREATE TABLE IF NOT EXISTS Messages ( is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1), enclosures TEXT, account_id INTEGER NOT NULL, - custom_id INTEGER, + custom_id TEXT, FOREIGN KEY (feed) REFERENCES Feeds (id), FOREIGN KEY (account_id) REFERENCES Accounts (id) diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index d194dacfd..eb283ab1c 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -26,12 +26,12 @@ ALTER TABLE Categories ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); -- ! ALTER TABLE Messages -ADD COLUMN custom_id INTEGER; +ADD COLUMN custom_id TEXT; -- ! ALTER TABLE Feeds -ADD COLUMN custom_id INTEGER; +ADD COLUMN custom_id TEXT; -- ! ALTER TABLE Categories -ADD COLUMN custom_id INTEGER; +ADD COLUMN custom_id TEXT; -- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql index d194dacfd..eb283ab1c 100644 --- a/resources/misc/db_update_sqlite_3_4.sql +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -26,12 +26,12 @@ ALTER TABLE Categories ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); -- ! ALTER TABLE Messages -ADD COLUMN custom_id INTEGER; +ADD COLUMN custom_id TEXT; -- ! ALTER TABLE Feeds -ADD COLUMN custom_id INTEGER; +ADD COLUMN custom_id TEXT; -- ! ALTER TABLE Categories -ADD COLUMN custom_id INTEGER; +ADD COLUMN custom_id TEXT; -- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/src/core/message.cpp b/src/core/message.cpp index 59ad7a598..0338a5477 100755 --- a/src/core/message.cpp +++ b/src/core/message.cpp @@ -61,7 +61,7 @@ QString Enclosures::encodeEnclosuresToString(const QList &enclosures) } Message::Message() { - m_title = m_url = m_author = m_contents = ""; + m_title = m_url = m_author = m_contents = m_customId = ""; m_feedId = 0; m_enclosures = QList(); } diff --git a/src/core/message.h b/src/core/message.h index 01330bbab..eacad327c 100755 --- a/src/core/message.h +++ b/src/core/message.h @@ -51,6 +51,7 @@ class Message { QDateTime m_created; int m_feedId; + QList m_enclosures; // Is true if "created" date was obtained directly From 3fe08fa67d2b6049b1cb20156f14e8ebc220c0db Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 14:09:02 +0100 Subject: [PATCH 120/203] Removed Messages -> Feeds foreign key. --- resources/misc/db_init_mysql.sql | 1 - resources/misc/db_init_sqlite.sql | 1 - resources/misc/db_update_mysql_3_4.sql | 3 +++ src/core/message.h | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index f95265c81..fb10284de 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -85,6 +85,5 @@ CREATE TABLE IF NOT EXISTS Messages ( account_id INTEGER NOT NULL, custom_id TEXT, - FOREIGN KEY (feed) REFERENCES Feeds (id), FOREIGN KEY (account_id) REFERENCES Accounts (id) ); \ No newline at end of file diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index 5a7290abc..41e5945c4 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -80,6 +80,5 @@ CREATE TABLE IF NOT EXISTS Messages ( account_id INTEGER NOT NULL, custom_id TEXT, - FOREIGN KEY (feed) REFERENCES Feeds (id), FOREIGN KEY (account_id) REFERENCES Accounts (id) ); \ No newline at end of file diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index eb283ab1c..0c05416e2 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -34,4 +34,7 @@ ADD COLUMN custom_id TEXT; ALTER TABLE Categories ADD COLUMN custom_id TEXT; -- ! +ALTER TABLE Messages +DROP FOREIGN KEY feed; +-- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/src/core/message.h b/src/core/message.h index eacad327c..f0cd4ab3b 100755 --- a/src/core/message.h +++ b/src/core/message.h @@ -50,7 +50,7 @@ class Message { QString m_contents; QDateTime m_created; int m_feedId; - + QString m_customId; QList m_enclosures; From 59e77f4d79d7061da634a177a244a345b6d3afde Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 14:15:13 +0100 Subject: [PATCH 121/203] Work on sync? --- src/services/tt-rss/ttrssserviceroot.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index dc419e6bf..73c81169b 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -42,7 +42,9 @@ TtRssServiceRoot::~TtRssServiceRoot() { } void TtRssServiceRoot::start() { - + if (m_childItems.isEmpty()) { + syncIn(); + } } void TtRssServiceRoot::stop() { @@ -200,3 +202,9 @@ void TtRssServiceRoot::updateTitle() { setTitle(m_network->username() + QL1S("@") + host); } + +void TtRssServiceRoot::syncIn() { + // TODO: provede stažení kanálů/kategorií + // ze serveru, a sloučení s aktuálními + // neprovádí aktualizace kanálů ani stažení počtu nepřečtených zpráv +} From 89239fc4a2b5e338de2865bdf4e789fd23ddde36 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 14:15:33 +0100 Subject: [PATCH 122/203] Work on sync? --- src/services/tt-rss/ttrssserviceroot.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index f6b40ea7e..ee6b0d339 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -70,6 +70,8 @@ class TtRssServiceRoot : public ServiceRoot { void updateTitle(); private: + void syncIn(); + TtRssNetworkFactory *m_network; }; From faa0be20748a2bdd7f98936e3870065030de4488 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 14:21:36 +0100 Subject: [PATCH 123/203] Bump version once more. --- CMakeLists.txt | 4 ++-- resources/text/CHANGELOG | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1246d12a8..2a670a27e 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,8 +65,8 @@ project(rssguard) set(APP_NAME "RSS Guard") set(APP_LOW_NAME "rssguard") -set(APP_VERSION "2.6.0") -set(FILE_VERSION "2,6,0,0") +set(APP_VERSION "3.0.0") +set(FILE_VERSION "3,0,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 9da0d179d..8718de143 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -12,7 +12,7 @@ -

              2.6.0

              +

              3.0.0

              Added:
                From 0dfaef3a128aa6004215d0c5cae89c4da1826956 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 14:22:04 +0100 Subject: [PATCH 124/203] Fix. --- src/services/tt-rss/ttrssserviceroot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 73c81169b..8997850e4 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -42,7 +42,7 @@ TtRssServiceRoot::~TtRssServiceRoot() { } void TtRssServiceRoot::start() { - if (m_childItems.isEmpty()) { + if (childItems().isEmpty()) { syncIn(); } } From b44292311e2448a8c4df0928282152c684d1e85d Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 19:50:21 +0100 Subject: [PATCH 125/203] OS/2 fix. --- src/services/standard/standardserviceroot.cpp | 6 +++--- src/services/tt-rss/network/ttrssnetworkfactory.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index ec9c7d861..d104cbd0d 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -119,12 +119,12 @@ bool StandardServiceRoot::deleteViaGui() { // TODO: todo // Remove all feeds. - if (!QSqlQuery(connection).exec(QSL("DELETE FROM Feeds WHERE account_id = %1;").arg(accountId()))) { + if (!QSqlQuery(connection).exec(QString("DELETE FROM Feeds WHERE account_id = %1;").arg(accountId()))) { return false; } // Remove all categories. - if (!QSqlQuery(connection).exec(QSL("DELETE FROM Categories WHERE account_id = %1;").arg(accountId()))) { + if (!QSqlQuery(connection).exec(QString("DELETE FROM Categories WHERE account_id = %1;").arg(accountId()))) { return false; } @@ -376,7 +376,7 @@ void StandardServiceRoot::loadFromDatabase(){ QSqlQuery query_feeds(database); query_feeds.setForwardOnly(true); - if (!query_feeds.exec(QSL("SELECT * FROM Feeds WHERE account_id = %1;").arg(accountId())) || query_feeds.lastError().isValid()) { + if (!query_feeds.exec(QString("SELECT * FROM Feeds WHERE account_id = %1;").arg(accountId())) || query_feeds.lastError().isValid()) { qFatal("Query for obtaining feeds failed. Error message: '%s'.", qPrintable(query_feeds.lastError().text())); } diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index f90f7d4b9..86d93e765 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -68,14 +68,14 @@ LoginResult TtRssNetworkFactory::login() { json["user"] = m_username; json["password"] = m_password; - QByteArray result; - NetworkResult res = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result); + QByteArray result_raw; + NetworkResult res = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); if (res.first != QNetworkReply::NoError) { return LoginResult(res.first, TtRssLoginResponse()); } else { - LoginResult result(res.first, TtRssLoginResponse(QString::fromUtf8(result))); + LoginResult result(res.first, TtRssLoginResponse(QString::fromUtf8(result_raw))); m_session_Id = result.second.sessionId(); return result; } From cff9c84b5ae908cabfa0c4cad6febe7fd147f7c6 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 3 Dec 2015 21:04:26 +0100 Subject: [PATCH 126/203] Some work. --- src/miscellaneous/databasefactory.cpp | 4 ++-- src/services/standard/standardserviceroot.cpp | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/miscellaneous/databasefactory.cpp b/src/miscellaneous/databasefactory.cpp index 1656d382c..6a7b6da61 100755 --- a/src/miscellaneous/databasefactory.cpp +++ b/src/miscellaneous/databasefactory.cpp @@ -305,7 +305,7 @@ QSqlDatabase DatabaseFactory::sqliteInitializeFileBasedDatabase(const QString &c qPrintable(installed_db_schema), APP_DB_SCHEMA_VERSION); } - else { + else if (installed_db_schema != APP_DB_SCHEMA_VERSION) { qDebug("Database schema was updated from '%s' to '%s' successully or it is already up to date.", qPrintable(installed_db_schema), APP_DB_SCHEMA_VERSION); @@ -616,7 +616,7 @@ QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_ qPrintable(installed_db_schema), APP_DB_SCHEMA_VERSION); } - else { + else if (installed_db_schema != APP_DB_SCHEMA_VERSION) { qDebug("Database schema was updated from '%s' to '%s' successully or it is already up to date.", qPrintable(installed_db_schema), APP_DB_SCHEMA_VERSION); diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index d104cbd0d..a6c779566 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -116,8 +116,6 @@ bool StandardServiceRoot::deleteViaGui() { return false; } - // TODO: todo - // Remove all feeds. if (!QSqlQuery(connection).exec(QString("DELETE FROM Feeds WHERE account_id = %1;").arg(accountId()))) { return false; From 3d026ec9557beafe5f279180726b66d07209231b Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 6 Dec 2015 19:50:58 +0100 Subject: [PATCH 127/203] Feed column in Messages table is now TEXT. --- resources/misc/db_init_mysql.sql | 2 +- resources/misc/db_init_sqlite.sql | 2 +- resources/misc/db_update_mysql_3_4.sql | 3 +++ resources/misc/db_update_sqlite_3_4.sql | 27 +++++++++++++++++++ src/gui/labelwithstatus.cpp | 2 -- src/services/standard/standardfeed.cpp | 8 +++--- .../standardfeedsimportexportmodel.cpp | 2 +- src/services/standard/standardserviceroot.cpp | 10 ++----- 8 files changed, 39 insertions(+), 17 deletions(-) diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index fb10284de..1931751fa 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -74,7 +74,7 @@ CREATE TABLE IF NOT EXISTS Messages ( is_read INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_read >= 0 AND is_read <= 1), is_deleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_deleted >= 0 AND is_deleted <= 1), is_important INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_important >= 0 AND is_important <= 1), - feed INTEGER NOT NULL, + feed TEXT, title TEXT NOT NULL CHECK (title != ''), url TEXT NOT NULL, author TEXT NOT NULL, diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index 41e5945c4..ce8eced60 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -69,7 +69,7 @@ CREATE TABLE IF NOT EXISTS Messages ( is_read INTEGER(1) NOT NULL CHECK (is_read >= 0 AND is_read <= 1) DEFAULT (0), is_deleted INTEGER(1) NOT NULL CHECK (is_deleted >= 0 AND is_deleted <= 1) DEFAULT (0), is_important INTEGER(1) NOT NULL CHECK (is_important >= 0 AND is_important <= 1) DEFAULT (0), - feed INTEGER NOT NULL, + feed TEXT, title TEXT NOT NULL CHECK (title != ''), url TEXT NOT NULL, author TEXT NOT NULL, diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index 0c05416e2..d1526931a 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -37,4 +37,7 @@ ADD COLUMN custom_id TEXT; ALTER TABLE Messages DROP FOREIGN KEY feed; -- ! +ALTER TABLE Messages +MODIFY Feeds TEXT; +-- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql index eb283ab1c..f70192ac4 100644 --- a/resources/misc/db_update_sqlite_3_4.sql +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -34,4 +34,31 @@ ADD COLUMN custom_id TEXT; ALTER TABLE Categories ADD COLUMN custom_id TEXT; -- ! +CREATE TABLE backup_Messages AS SELECT * FROM Messages; +-- ! +DROP TABLE Messages; +-- ! +CREATE TABLE Messages ( + id INTEGER PRIMARY KEY, + is_read INTEGER(1) NOT NULL CHECK (is_read >= 0 AND is_read <= 1) DEFAULT (0), + is_deleted INTEGER(1) NOT NULL CHECK (is_deleted >= 0 AND is_deleted <= 1) DEFAULT (0), + is_important INTEGER(1) NOT NULL CHECK (is_important >= 0 AND is_important <= 1) DEFAULT (0), + feed TEXT, + title TEXT NOT NULL CHECK (title != ''), + url TEXT NOT NULL, + author TEXT NOT NULL, + date_created INTEGER NOT NULL CHECK (date_created != 0), + contents TEXT, + is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1), + enclosures TEXT, + account_id INTEGER NOT NULL, + custom_id TEXT, + + FOREIGN KEY (account_id) REFERENCES Accounts (id) +); +-- ! +INSERT INTO Messages SELECT * FROM backup_Messages; +-- ! +DROP TABLE backup_Messages; +-- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/src/gui/labelwithstatus.cpp b/src/gui/labelwithstatus.cpp index 90db3a608..5f15541b3 100755 --- a/src/gui/labelwithstatus.cpp +++ b/src/gui/labelwithstatus.cpp @@ -26,8 +26,6 @@ LabelWithStatus::LabelWithStatus(QWidget *parent) : WidgetWithStatus(parent) { m_wdgInput = new QLabel(this); - qobject_cast(m_wdgInput)->setWordWrap(true); - // Set correct size for the tool button. int label_height = m_wdgInput->sizeHint().height(); m_btnStatus->setFixedSize(label_height, label_height); diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 09107d65f..6b56fd004 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -189,15 +189,15 @@ void StandardFeed::updateCounts(bool including_total_count) { query_all.setForwardOnly(true); if (including_total_count) { - if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE feed = %1 AND is_deleted = 0 AND account_id = %2;").arg(QString::number(id()), - QString::number(const_cast(this)->serviceRoot()->accountId()))) && query_all.next()) { + if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE feed = '%1' AND is_deleted = 0 AND account_id = %2;").arg(QString::number(id()), + QString::number(const_cast(this)->serviceRoot()->accountId()))) && query_all.next()) { m_totalCount = query_all.value(0).toInt(); } } // Obtain count of unread messages. - if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE feed = %1 AND is_deleted = 0 AND is_read = 0 AND account_id = %2;").arg(QString::number(id()), - QString::number(const_cast(this)->serviceRoot()->accountId()))) && query_all.next()) { + if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE feed = '%1' AND is_deleted = 0 AND is_read = 0 AND account_id = %2;").arg(QString::number(id()), + QString::number(const_cast(this)->serviceRoot()->accountId()))) && query_all.next()) { int new_unread_count = query_all.value(0).toInt(); if (status() == NewMessages && new_unread_count < m_unreadCount) { diff --git a/src/services/standard/standardfeedsimportexportmodel.cpp b/src/services/standard/standardfeedsimportexportmodel.cpp index fd74f1ed8..7a7f1a156 100755 --- a/src/services/standard/standardfeedsimportexportmodel.cpp +++ b/src/services/standard/standardfeedsimportexportmodel.cpp @@ -167,7 +167,7 @@ bool FeedsImportExportModel::importAsOPML20(const QByteArray &data) { return false; } - StandardServiceRoot *root_item = new StandardServiceRoot(false); + StandardServiceRoot *root_item = new StandardServiceRoot(); QStack model_items; model_items.push(root_item); QStack elements_to_process; elements_to_process.push(opml_document.documentElement().elementsByTagName(QSL("body")).at(0).toElement()); diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index a6c779566..89c8af3ef 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -586,7 +586,7 @@ QStringList StandardServiceRoot::textualFeedIds(const QList &feeds) { stringy_ids.reserve(feeds.size()); foreach (Feed *feed, feeds) { - stringy_ids.append(QString::number(feed->id())); + stringy_ids.append(QString("'%1'").arg(QString::number(feed->id()))); } return stringy_ids; @@ -632,13 +632,7 @@ bool StandardServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *mo } else { QList children = item->getSubTreeFeeds(); - QStringList stringy_ids; - - foreach (Feed *child, children) { - stringy_ids.append(QString::number(child->id())); - } - - QString filter_clause = stringy_ids.join(QSL(", ")); + QString filter_clause = textualFeedIds(children).join(QSL(", ")); model->setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0")).arg(filter_clause)); qDebug("Loading messages from feeds: %s.", qPrintable(filter_clause)); From 8fbb434a56dbe3ebe6e0b91d21e4977e4c4235c3 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 6 Dec 2015 19:56:00 +0100 Subject: [PATCH 128/203] Wider add account dialog list. --- src/gui/dialogs/formaddaccount.ui | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/gui/dialogs/formaddaccount.ui b/src/gui/dialogs/formaddaccount.ui index 67026a6b3..cdb35edbe 100755 --- a/src/gui/dialogs/formaddaccount.ui +++ b/src/gui/dialogs/formaddaccount.ui @@ -6,7 +6,7 @@ 0 0 - 610 + 685 271 @@ -22,6 +22,15 @@ 1 + + + 320 + 0 + + + + QListView::Adjust + From 97866f984a377ee5d6a1a5786fe4de491517d248 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 6 Dec 2015 20:07:26 +0100 Subject: [PATCH 129/203] Added empty feed & category classes. --- CMakeLists.txt | 2 ++ src/services/tt-rss/ttrsscategory.cpp | 25 ++++++++++++++++++++++ src/services/tt-rss/ttrsscategory.h | 30 +++++++++++++++++++++++++++ src/services/tt-rss/ttrssfeed.cpp | 26 +++++++++++++++++++++++ src/services/tt-rss/ttrssfeed.h | 30 +++++++++++++++++++++++++++ 5 files changed, 113 insertions(+) create mode 100644 src/services/tt-rss/ttrsscategory.cpp create mode 100644 src/services/tt-rss/ttrsscategory.h create mode 100644 src/services/tt-rss/ttrssfeed.cpp create mode 100644 src/services/tt-rss/ttrssfeed.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a670a27e..821c6a69a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -439,6 +439,8 @@ set(APP_SOURCES # TT-RSS feed service sources. src/services/tt-rss/ttrssserviceentrypoint.cpp src/services/tt-rss/ttrssserviceroot.cpp + src/services/tt-rss/ttrssfeed.cpp + src/services/tt-rss/ttrsscategory.cpp src/services/tt-rss/gui/formeditaccount.cpp src/services/tt-rss/network/ttrssnetworkfactory.cpp diff --git a/src/services/tt-rss/ttrsscategory.cpp b/src/services/tt-rss/ttrsscategory.cpp new file mode 100644 index 000000000..4fc96230b --- /dev/null +++ b/src/services/tt-rss/ttrsscategory.cpp @@ -0,0 +1,25 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#include "ttrsscategory.h" + + +TtRssCategory::TtRssCategory(RootItem *parent) : Category(parent) { +} + +TtRssCategory::~TtRssCategory() { +} diff --git a/src/services/tt-rss/ttrsscategory.h b/src/services/tt-rss/ttrsscategory.h new file mode 100644 index 000000000..2758d2c78 --- /dev/null +++ b/src/services/tt-rss/ttrsscategory.h @@ -0,0 +1,30 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#ifndef TTRSSCATEGORY_H +#define TTRSSCATEGORY_H + +#include "services/abstract/category.h" + + +class TtRssCategory : public Category { + public: + explicit TtRssCategory(RootItem *parent = NULL); + virtual ~TtRssCategory(); +}; + +#endif // TTRSSCATEGORY_H diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp new file mode 100644 index 000000000..e12fbefc2 --- /dev/null +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -0,0 +1,26 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#include "ttrssfeed.h" + + +TtRssFeed::TtRssFeed(RootItem *parent) : Feed(parent) { +} + +TtRssFeed::~TtRssFeed() { +} + diff --git a/src/services/tt-rss/ttrssfeed.h b/src/services/tt-rss/ttrssfeed.h new file mode 100644 index 000000000..b947e805d --- /dev/null +++ b/src/services/tt-rss/ttrssfeed.h @@ -0,0 +1,30 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#ifndef TTRSSFEED_H +#define TTRSSFEED_H + +#include + + +class TtRssFeed : public Feed { + public: + explicit TtRssFeed(RootItem *parent = NULL); + virtual ~TtRssFeed(); +}; + +#endif // TTRSSFEED_H From 32a8fc81cbf9eb0d6c229f76c95e6fdbd7b90eae Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 7 Dec 2015 09:42:46 +0100 Subject: [PATCH 130/203] Work on TT-RSS network. --- .../graphics/icons/mini-kfaenza/item-sync.png | Bin 0 -> 2947 bytes resources/misc/db_init_mysql.sql | 2 +- resources/misc/db_init_sqlite.sql | 2 +- resources/misc/db_update_mysql_3_4.sql | 2 +- resources/misc/db_update_sqlite_3_4.sql | 2 +- src/core/rootitem.cpp | 2 +- src/core/rootitem.h | 2 +- src/gui/feedsview.cpp | 6 +- src/services/abstract/serviceroot.cpp | 31 +++++ src/services/abstract/serviceroot.h | 2 + src/services/standard/standardfeed.cpp | 2 +- src/services/standard/standardfeed.h | 2 +- src/services/standard/standardserviceroot.cpp | 28 +---- src/services/standard/standardserviceroot.h | 2 +- src/services/tt-rss/definitions.h | 3 + .../tt-rss/network/ttrssnetworkfactory.cpp | 114 ++++++++++++++++-- .../tt-rss/network/ttrssnetworkfactory.h | 34 +++++- src/services/tt-rss/ttrssserviceroot.cpp | 28 ++++- src/services/tt-rss/ttrssserviceroot.h | 11 +- 19 files changed, 217 insertions(+), 58 deletions(-) create mode 100755 resources/graphics/icons/mini-kfaenza/item-sync.png diff --git a/resources/graphics/icons/mini-kfaenza/item-sync.png b/resources/graphics/icons/mini-kfaenza/item-sync.png new file mode 100755 index 0000000000000000000000000000000000000000..4d025c236c9f9dddb5be992707d35677fc522267 GIT binary patch literal 2947 zcmV-}3w-p6P)%Yw2Go1_5)^aI~by5#5Z9o zI(zos|K&W)-rGGlC}IwrmHg@K+rPiH{FGf!gIZxd~Y^xFvV;fX32Qfeaz|dN& z`<+&`)(QX&s9+8hKmb6c6#PvJAOHX&`Y)}*a5obxrTqC3pq@tWW^zPCB!o~zBv?U@ z-Zky5u2xD(@Axmhs}^He0pe+Q$8!=w2&I&lN+ovc)Ty>}=guXTmX;!=Qi*D5mRkZ@1g;tLo5hDNss*F$SD-h{a-%N~Or; zXuSUV>km&% zOtdDGNnnftAp{5^ptS}e1lYC>j4{#L+UnT0t!>*5lrc?H96o$_%5`1G1JBN#JGbW4 zsZ;HgQihE*Zi2BYh;PS2h=`1_$UE=6lPQ%-EzxK+Y#DGI2X^h+mGA58Tj}oZw%4s& zSJql9DJ8#g{P=^8-tZ{9rTI8Iq>tqO&L zKN+^Sx04rMcp57Qd%jcWTj#xQp(7Q6DKn9c$`p5 zfe-@mcpSd`^2^M^!a}qWD|ta2D7IP}MMPwmFJE30i9`Z=lv3&=M~>WxL?Q(#rEF$^ zMh2mj^1;Euj8ZBZo|AJ9hGFo*!NCV9rQG+7W;9yMeGPqx5JJwLJ-bFJRb~CHTemKE zcX!WwS#`A;6)B}`WMm|L@#4h}(=-DH^M_#=FflRF`t{deKfoB{HLlb&k@=+r)(9bl zkn!>Hs9_j^rL@+N&1RQXgNMQvYGe$pb>zbjKg=W&i6EA0M>3g&;o;#;`F!3agi!za z+ESu!1qdOGF=lekquwwHAv~AM8HQm5R&rez`uh3`h{!nS!TpRe6A`IW3YAh29$IT8 zgz)#@e?NnWQOLD@j-`O(F0(HmQ@@&bZE|X zU8fO$6GD(N#tVf)YVY2?`S7(fXU?SK@pu3}kw`d?KKkfN01Pp~7+X+E`LR}43k45r zt+fzBbaZqqKJ&~obKige{n~KGZ6w8F5e^b4^9dp6d|OJDG(7j=VD-BV8XJjvJgVm25xvrDYZYm z!j4?Kb}i|%8zBUQ5U_3AwvrG+hVPeBYClOrgFJwq0#yo2DMfpG`{M51yXS1%u44+z zvY@}ef7&$7r5fwrQv9Ouv(G+TXWMoxoLe%PjMdfE70`37gc4cZ3Xs|oKq;ji$8n#0 z^2y20&dwFBbvO&d_U+sAy}i9T*L7XLA+XvkeDUJN)X2z4XDXEn<`hCeZ*TA7ZRV@0 zMyv9Gl(OytDW$S)+Zq@cn6zzM`AkFz5&ixBQ{{5Gtd!D>F-9q6-b&V%CFmKRa?XuE z{`e#H>8GD&TU%SHZ+$5xbar;GJoVI5v##rkX7yBU<83vigcd@GbUMBG^wUqz*|rU( zQVE`a{`qOnc|j>92_a-7K<&qt}B}uGAs@E#C04S7NwLbm&;avfB!@*7890bm8F!LF~%-jxUgn+ zcDAjvvlFD0(b?JA==k_J{P4pMKq-ZmmKHEg6FNIP>oRV!ScIKBcP>8i$RoLOx$NG? z`e6m?GV$%c2WTOLNG6jD-ik<%P53w8e6z8wtqpy4;+%t@S(}M%+n|&Z`}gmk-Lhp% zu2d?On=wxVX}G1VrO|o~wAQw52W@x87`uA)YBCm!aoe_o7RoK22Pq{iFE7LP?c4La zckiA>#KmH<=-dH#fF>>!yySLD_`hA(6`4#X|Hd0{Tp1f1Tl3RTKc%OprlOp4@Q2nK z9LE761PCEiHk-Acd+xcLnM`KZvaFKyv)XEr{~0?Ci@BhjSdA#9lx^F#<2dt~OeX*G z%P-Gcmeq3e=FQ0B;v!#KT8bc|jz*(09*?^ZJ@ils5sQ{(St~0m;ts7201!~Je_T~g z-|1xDgxY7Rd_I2@5%Y;ef+UkkB!p1!veH`XVzC&M*>_^~2GX#c4rj~1q)X_p@^)rH z&+{$;2U6RpsB)pd*qv@De;42e^8z&44`Aqq`&PUaXxNod`FuY2KSy+j;$aM2#aF-v zfWpa>Cub2c2$1_s5E04AlP6~Zpa2!jfeV!YVEm(xKKiGW^0xyA4y|H&tx6aZk{!yJ6* zMgUj~09yf|7XZ2d;C}n$>H|Ly0G9wDr~SGepwherfHVNCg9`Y_y}{X39H=NU0{}O* t*ZHWce-M#D#kKCofA$bs>#FZ*{{@A9SuW}WoJ9Zt002ovPDHLkV1j{ig|Ywu literal 0 HcmV?d00001 diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index 1931751fa..b3eb5e2cd 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -22,7 +22,7 @@ CREATE TABLE IF NOT EXISTS Accounts ( INSERT INTO Accounts (type) VALUES ('std-rss'); -- ! CREATE TABLE IF NOT EXISTS TtRssAccounts ( - id INTEGER PRIMARY KEY, + id INTEGER, username TEXT NOT NULL, password TEXT, url TEXT NOT NULL, diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index ce8eced60..80a091205 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -16,7 +16,7 @@ CREATE TABLE IF NOT EXISTS Accounts ( INSERT INTO Accounts (type) VALUES ('std-rss'); -- ! CREATE TABLE IF NOT EXISTS TtRssAccounts ( - id INTEGER PRIMARY KEY, + id INTEGER, username TEXT NOT NULL, password TEXT, url TEXT NOT NULL, diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index d1526931a..892d54579 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -8,7 +8,7 @@ INSERT INTO Accounts (type) VALUES ('std-rss'); DROP TABLE IF EXISTS FeedsData; -- ! CREATE TABLE IF NOT EXISTS TtRssAccounts ( - id INTEGER PRIMARY KEY, + id INTEGER, username TEXT NOT NULL, password TEXT, url TEXT NOT NULL, diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql index f70192ac4..6a6433312 100644 --- a/resources/misc/db_update_sqlite_3_4.sql +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -8,7 +8,7 @@ INSERT INTO Accounts (type) VALUES ('std-rss'); DROP TABLE IF EXISTS FeedsData; -- ! CREATE TABLE IF NOT EXISTS TtRssAccounts ( - id INTEGER PRIMARY KEY, + id INTEGER, username TEXT NOT NULL, password TEXT, url TEXT NOT NULL, diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index ff9b3ed8a..879ad8839 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -42,7 +42,7 @@ RootItem::~RootItem() { qDeleteAll(m_childItems); } -QList RootItem::contextMenuActions() { +QList RootItem::contextMenu() { return QList(); } diff --git a/src/core/rootitem.h b/src/core/rootitem.h index ed6dbc370..800bbc3cf 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -76,7 +76,7 @@ class RootItem : public QObject { // Returns list of specific actions which can be done with the item. // Do not include general actions here like actions: Mark as read, Update, ... // NOTE: Ownership of returned actions is not switched to caller, free them when needed. - virtual QList contextMenuActions(); + virtual QList contextMenu(); // Can properties of this item be edited? virtual bool canBeEdited(); diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 8c67483d8..d976b6e84 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -303,7 +303,7 @@ QMenu *FeedsView::initializeContextMenuCategories(RootItem *clicked_item) { m_contextMenuCategories->clear(); } - QList specific_actions = clicked_item->contextMenuActions(); + QList specific_actions = clicked_item->contextMenu(); m_contextMenuCategories->addActions(QList() << qApp->mainForm()->m_ui->m_actionUpdateSelectedItems << @@ -329,7 +329,7 @@ QMenu *FeedsView::initializeContextMenuFeeds(RootItem *clicked_item) { m_contextMenuFeeds->clear(); } - QList specific_actions = clicked_item->contextMenuActions(); + QList specific_actions = clicked_item->contextMenu(); m_contextMenuFeeds->addActions(QList() << qApp->mainForm()->m_ui->m_actionUpdateSelectedItems << @@ -365,7 +365,7 @@ QMenu *FeedsView::initializeContextMenuOtherItem(RootItem *clicked_item) { m_contextMenuOtherItems->clear(); } - QList specific_actions = clicked_item->contextMenuActions(); + QList specific_actions = clicked_item->contextMenu(); if (!specific_actions.isEmpty()) { m_contextMenuOtherItems->addSeparator(); diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index 773475c68..2a804ce18 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -18,6 +18,9 @@ #include "services/abstract/serviceroot.h" #include "core/feedsmodel.h" +#include "miscellaneous/application.h" + +#include ServiceRoot::ServiceRoot(RootItem *parent) : RootItem(parent), m_accountId(NO_PARENT_CATEGORY) { @@ -27,6 +30,34 @@ ServiceRoot::ServiceRoot(RootItem *parent) : RootItem(parent), m_accountId(NO_PA ServiceRoot::~ServiceRoot() { } +bool ServiceRoot::deleteViaGui() { + QSqlDatabase connection = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + + // Remove all messages. + if (!QSqlQuery(connection).exec(QString("DELETE FROM Messages WHERE account_id = %1;").arg(accountId()))) { + return false; + } + + // Remove all feeds. + if (!QSqlQuery(connection).exec(QString("DELETE FROM Feeds WHERE account_id = %1;").arg(accountId()))) { + return false; + } + + // Remove all categories. + if (!QSqlQuery(connection).exec(QString("DELETE FROM Categories WHERE account_id = %1;").arg(accountId()))) { + return false; + } + + // Switch "existence" flag. + bool data_removed = QSqlQuery(connection).exec(QString("DELETE FROM Accounts WHERE id = %1;").arg(accountId())); + + if (data_removed) { + requestItemRemoval(this); + } + + return data_removed; +} + void ServiceRoot::itemChanged(QList items) { emit dataChanged(items); } diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 98e30f2da..3dbd13475 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -44,6 +44,8 @@ class ServiceRoot : public RootItem { // /* Members to override. ///////////////////////////////////////// + bool deleteViaGui(); + // Returns list of specific actions for "Add new item" main window menu. // So typical list of returned actions could look like: // a) Add new feed diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 6b56fd004..c9a355880 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -98,7 +98,7 @@ int StandardFeed::countOfUnreadMessages() const { return m_unreadCount; } -QList StandardFeed::contextMenuActions() { +QList StandardFeed::contextMenu() { return serviceRoot()->getContextMenuForFeed(this); } diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index 4e5f234fc..de1b8db56 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -61,7 +61,7 @@ class StandardFeed : public Feed { int countOfAllMessages() const; int countOfUnreadMessages() const; - QList contextMenuActions(); + QList contextMenu(); bool canBeEdited() { return true; diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 89c8af3ef..ecebe24bf 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -109,31 +109,7 @@ bool StandardServiceRoot::canBeDeleted() { } bool StandardServiceRoot::deleteViaGui() { - QSqlDatabase connection = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); - - // Remove all messages. - if (!QSqlQuery(connection).exec(QString("DELETE FROM Messages WHERE account_id = %1;").arg(accountId()))) { - return false; - } - - // Remove all feeds. - if (!QSqlQuery(connection).exec(QString("DELETE FROM Feeds WHERE account_id = %1;").arg(accountId()))) { - return false; - } - - // Remove all categories. - if (!QSqlQuery(connection).exec(QString("DELETE FROM Categories WHERE account_id = %1;").arg(accountId()))) { - return false; - } - - // Switch "existence" flag. - bool data_removed = QSqlQuery(connection).exec(QString("DELETE FROM Accounts WHERE id = %1;").arg(accountId())); - - if (data_removed) { - requestItemRemoval(this); - } - - return data_removed; + return ServiceRoot::deleteViaGui(); } QVariant StandardServiceRoot::data(int column, int role) const { @@ -622,7 +598,7 @@ QList StandardServiceRoot::serviceMenu() { return m_serviceMenu; } -QList StandardServiceRoot::contextMenuActions() { +QList StandardServiceRoot::contextMenu() { return serviceMenu(); } diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index c03461dfc..1a54f7b02 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -64,7 +64,7 @@ class StandardServiceRoot : public ServiceRoot { // Return menu to be shown in "Services -> service" menu. QList serviceMenu(); - QList contextMenuActions(); + QList contextMenu(); // Message stuff. bool loadMessagesForItem(RootItem *item, QSqlTableModel *model); diff --git a/src/services/tt-rss/definitions.h b/src/services/tt-rss/definitions.h index 9a96dfed7..6aae31bea 100755 --- a/src/services/tt-rss/definitions.h +++ b/src/services/tt-rss/definitions.h @@ -23,4 +23,7 @@ // Logout. #define LOGOUT_OK "OK" +// Get feed tree. +#define GFT_TYPE_CATEGORY "category" + #endif // DEFINITIONS_H diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index 86d93e765..18ab3dfe9 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -18,12 +18,13 @@ #include "services/tt-rss/network/ttrssnetworkfactory.h" #include "definitions/definitions.h" +#include "core/rootitem.h" #include "services/tt-rss/definitions.h" #include "network-web/networkfactory.h" TtRssNetworkFactory::TtRssNetworkFactory() - : m_url(QString()), m_username(QString()), m_password(QString()), m_session_Id(QString()) { + : m_url(QString()), m_username(QString()), m_password(QString()), m_sessionId(QString()) { } TtRssNetworkFactory::~TtRssNetworkFactory() { @@ -63,22 +64,56 @@ void TtRssNetworkFactory::setPassword(const QString &password) { LoginResult TtRssNetworkFactory::login() { + if (!m_sessionId.isEmpty()) { + logout(); + } + QtJson::JsonObject json; json["op"] = "login"; json["user"] = m_username; json["password"] = m_password; QByteArray result_raw; - NetworkResult res = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + LoginResult result(network_reply.first, TtRssLoginResponse(QString::fromUtf8(result_raw))); - if (res.first != QNetworkReply::NoError) { - return LoginResult(res.first, TtRssLoginResponse()); + if (network_reply.first == QNetworkReply::NoError) { + m_sessionId = result.second.sessionId(); } - else { - LoginResult result(res.first, TtRssLoginResponse(QString::fromUtf8(result_raw))); - m_session_Id = result.second.sessionId(); - return result; + + return result; +} + +LogoutResult TtRssNetworkFactory::logout() { + QtJson::JsonObject json; + json["op"] = "logout"; + json["sid"] = m_sessionId; + + QByteArray result_raw; + NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + + return LogoutResult(network_reply.first, TtRssResponse(QString::fromUtf8(result_raw))); +} + +GetFeedTreeResult TtRssNetworkFactory::getFeedTree() { + QtJson::JsonObject json; + json["op"] = "getFeedTree"; + json["sid"] = m_sessionId; + json["include_empty"] = true; + + QByteArray result_raw; + NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + GetFeedTreeResult result(network_reply.first, TtRssGetFeedTreeResponse(QString::fromUtf8(result_raw))); + + if (result.second.isNotLoggedIn()) { + // We are not logged in. + login(); + + network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + result = GetFeedTreeResult(network_reply.first, TtRssGetFeedTreeResponse(QString::fromUtf8(result_raw))); } + + return result; } TtRssResponse::TtRssResponse(const QString &raw_content) { @@ -110,6 +145,10 @@ int TtRssResponse::status() const { } } +bool TtRssResponse::isNotLoggedIn() const { + return status() == API_STATUS_ERR && hasError() && error() == NOT_LOGGED_IN; +} + TtRssLoginResponse::TtRssLoginResponse(const QString &raw_content) : TtRssResponse(raw_content) { } @@ -135,7 +174,7 @@ QString TtRssLoginResponse::sessionId() const { } } -QString TtRssLoginResponse::error() const { +QString TtRssResponse::error() const { if (!isLoaded()) { return QString(); } @@ -144,7 +183,7 @@ QString TtRssLoginResponse::error() const { } } -bool TtRssLoginResponse::hasError() const { +bool TtRssResponse::hasError() const { if (!isLoaded()) { return false; } @@ -152,3 +191,58 @@ bool TtRssLoginResponse::hasError() const { return m_rawContent["content"].toMap().contains("error"); } } + + +TtRssGetFeedTreeResponse::TtRssGetFeedTreeResponse(const QString &raw_content) : TtRssResponse(raw_content) { + +} + +TtRssGetFeedTreeResponse::~TtRssGetFeedTreeResponse() { +} + +QList TtRssGetFeedTreeResponse::getTree() { + QList items; + + if (status() == API_STATUS_OK) { + // We have data, construct object tree according to data. + QList items_to_process = m_rawContent["content"].toMap()["categories"].toMap()["items"].toList(); + + processSubtree(true, items, NULL, items_to_process); + } + + return items; +} + +void TtRssGetFeedTreeResponse::processSubtree(bool is_top_level, QList &top_level_items, + RootItem *parent, const QList &items) { + foreach (QVariant item, items) { + QMap map_item = item.toMap(); + + if (map_item.contains("type") && map_item["type"].toString() == GFT_TYPE_CATEGORY) { + // TODO: pokračovat tady + + // We have category, create it, add it to "parent". + // Then process all its children. + // + // TtRssCategory *new_category = new TtRssCategory(); + // naplnit informace..... + // parent->appendChild(new_category); + // if (is_top_level) { + // top_level_items.append(new_category); + // } + // else { + // parent->appendChild(new_category); + // } + // processSubtree(false, top_level_items, new_category, map_item["items"].toList()); + } + else { + // We have feed, add it. + // TtRssFeed *new_feed = new TtRssFeed(); + // naplnit informace..... + // parent->appendChild(new_feed); + // if (is_top_level) { + // top_level_items.append(new_feed); + // } + } + } +} diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.h b/src/services/tt-rss/network/ttrssnetworkfactory.h index c6ce09028..292666b55 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.h +++ b/src/services/tt-rss/network/ttrssnetworkfactory.h @@ -25,6 +25,8 @@ #include +class RootItem; + class TtRssResponse { public: explicit TtRssResponse(const QString &raw_content = QString()); @@ -34,6 +36,9 @@ class TtRssResponse { int seq() const; int status() const; + QString error() const; + bool hasError() const; + bool isNotLoggedIn() const; protected: QtJson::JsonObject m_rawContent; @@ -46,11 +51,24 @@ class TtRssLoginResponse : public TtRssResponse { int apiLevel() const; QString sessionId() const; - QString error() const; - bool hasError() const; }; typedef QPair LoginResult; +typedef QPair LogoutResult; + +class TtRssGetFeedTreeResponse : public TtRssResponse { + public: + explicit TtRssGetFeedTreeResponse(const QString &raw_content = QString()); + virtual ~TtRssGetFeedTreeResponse(); + + QList getTree(); + + private: + void processSubtree(bool is_top_level, QList &top_level_items, + RootItem *parent, const QList &items); +}; + +typedef QPair GetFeedTreeResult; class TtRssNetworkFactory { public: @@ -67,13 +85,21 @@ class TtRssNetworkFactory { void setPassword(const QString &password); // Operations. + + // Logs user in. LoginResult login(); - private: + // Logs user out. + LogoutResult logout(); + + // Gets tree from feeds/categories obtained from the server. + GetFeedTreeResult getFeedTree(); + + private: QString m_url; QString m_username; QString m_password; - QString m_session_Id; + QString m_sessionId; }; #endif // TTRSSNETWORKFACTORY_H diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 8997850e4..8360c4655 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -30,7 +30,7 @@ TtRssServiceRoot::TtRssServiceRoot(RootItem *parent) - : ServiceRoot(parent), m_network(new TtRssNetworkFactory) { + : ServiceRoot(parent), m_network(new TtRssNetworkFactory), m_actionSyncIn(NULL), m_serviceMenu(QList()) { setIcon(TtRssServiceEntryPoint().icon()); setCreationDate(QDateTime::currentDateTime()); } @@ -63,7 +63,16 @@ bool TtRssServiceRoot::editViaGui() { } bool TtRssServiceRoot::deleteViaGui() { - return false; + QSqlDatabase connection = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + + // Remove extra entry in "Tiny Tiny RSS accounts list" and then delete + // all the categories/feeds and messages. + if (!QSqlQuery(connection).exec(QString("DELETE FROM TtRssAccounts WHERE id = %1;").arg(accountId()))) { + return false; + } + else { + return ServiceRoot::deleteViaGui(); + } } bool TtRssServiceRoot::canBeEdited() { @@ -105,7 +114,19 @@ bool TtRssServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *model } QList TtRssServiceRoot::serviceMenu() { - return QList(); + if (m_serviceMenu.isEmpty()) { + m_actionSyncIn = new QAction(qApp->icons()->fromTheme(QSL("item-sync")), tr("Sync in"), this); + + connect(m_actionSyncIn, SIGNAL(triggered()), this, SLOT(syncIn())); + + m_serviceMenu.append(m_actionSyncIn); + } + + return m_serviceMenu; +} + +QList TtRssServiceRoot::contextMenu() { + return serviceMenu(); } bool TtRssServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, QList message_db_ids, RootItem::ReadStatus read) { @@ -207,4 +228,5 @@ void TtRssServiceRoot::syncIn() { // TODO: provede stažení kanálů/kategorií // ze serveru, a sloučení s aktuálními // neprovádí aktualizace kanálů ani stažení počtu nepřečtených zpráv + m_network->getFeedTree(); } diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index ee6b0d339..00ba6446e 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -44,8 +44,9 @@ class TtRssServiceRoot : public ServiceRoot { QVariant data(int column, int role) const; - QList addItemMenu(); - QList serviceMenu(); + QList addItemMenu(); + QList serviceMenu(); + QList contextMenu(); RecycleBin *recycleBin(); @@ -69,9 +70,13 @@ class TtRssServiceRoot : public ServiceRoot { void loadFromDatabase(); void updateTitle(); - private: + private slots: void syncIn(); + private: + QAction *m_actionSyncIn; + QList m_serviceMenu; + TtRssNetworkFactory *m_network; }; From 1eaafe3eae0e9ea69008fd71ed848a696991165c Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 7 Dec 2015 10:00:50 +0100 Subject: [PATCH 131/203] Login/logout. --- src/services/tt-rss/network/ttrssnetworkfactory.cpp | 1 + src/services/tt-rss/ttrssserviceroot.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index 18ab3dfe9..c5224217d 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -108,6 +108,7 @@ GetFeedTreeResult TtRssNetworkFactory::getFeedTree() { if (result.second.isNotLoggedIn()) { // We are not logged in. login(); + json["sid"] = m_sessionId; network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); result = GetFeedTreeResult(network_reply.first, TtRssGetFeedTreeResponse(QString::fromUtf8(result_raw))); diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 8360c4655..26b21fc46 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -228,5 +228,5 @@ void TtRssServiceRoot::syncIn() { // TODO: provede stažení kanálů/kategorií // ze serveru, a sloučení s aktuálními // neprovádí aktualizace kanálů ani stažení počtu nepřečtených zpráv - m_network->getFeedTree(); + QList aa = m_network->getFeedTree().second.getTree(); } From b0cf12230a362ba53e48790db3f021269103e6fa Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 7 Dec 2015 16:58:59 +0100 Subject: [PATCH 132/203] Remove comment. --- src/services/tt-rss/ttrssserviceroot.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 26b21fc46..f24297696 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -86,7 +86,6 @@ bool TtRssServiceRoot::canBeDeleted() { QVariant TtRssServiceRoot::data(int column, int role) const { switch (role) { case Qt::ToolTipRole: - // TODO: zobrazovat pokročile informace a statistiky. if (column == FDS_MODEL_TITLE_INDEX) { return tr("Tiny Tiny RSS\n\nAccount ID: %3\nUsername: %1\nServer: %2").arg(m_network->username(), m_network->url(), From 02f3ee0f689cab684dbf6c970c4f1878407a6a11 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 7 Dec 2015 17:01:59 +0100 Subject: [PATCH 133/203] Fix warning. --- src/services/tt-rss/ttrssserviceroot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index f24297696..dd01193e7 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -30,7 +30,7 @@ TtRssServiceRoot::TtRssServiceRoot(RootItem *parent) - : ServiceRoot(parent), m_network(new TtRssNetworkFactory), m_actionSyncIn(NULL), m_serviceMenu(QList()) { + : ServiceRoot(parent), m_actionSyncIn(NULL), m_serviceMenu(QList()), m_network(new TtRssNetworkFactory) { setIcon(TtRssServiceEntryPoint().icon()); setCreationDate(QDateTime::currentDateTime()); } From 5b432772ddba73ab1e382eb474f4eb0ff79560ef Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 7 Dec 2015 19:39:54 +0100 Subject: [PATCH 134/203] Fuck it all, no mood. --- src/services/tt-rss/gui/formeditaccount.cpp | 15 ++-- .../tt-rss/network/ttrssnetworkfactory.cpp | 71 ++++++------------- .../tt-rss/network/ttrssnetworkfactory.h | 25 +++---- src/services/tt-rss/ttrssserviceroot.cpp | 5 +- 4 files changed, 41 insertions(+), 75 deletions(-) diff --git a/src/services/tt-rss/gui/formeditaccount.cpp b/src/services/tt-rss/gui/formeditaccount.cpp index fbfb43375..43068321c 100755 --- a/src/services/tt-rss/gui/formeditaccount.cpp +++ b/src/services/tt-rss/gui/formeditaccount.cpp @@ -90,16 +90,17 @@ void FormEditAccount::displayPassword(bool display) { void FormEditAccount::performTest() { TtRssNetworkFactory factory; + QNetworkReply::NetworkError err; factory.setUsername(m_ui->m_txtUsername->lineEdit()->text()); factory.setPassword(m_ui->m_txtPassword->lineEdit()->text()); factory.setUrl(m_ui->m_txtUrl->lineEdit()->text()); - LoginResult result = factory.login(); + TtRssLoginResponse result = factory.login(err); - if (result.first == QNetworkReply::NoError) { - if (result.second.hasError()) { - QString error = result.second.error(); + if (err == QNetworkReply::NoError) { + if (result.hasError()) { + QString error = result.error(); if (error == API_DISABLED) { m_ui->m_lblTestResult->setStatus(WidgetWithStatus::Error, @@ -117,15 +118,15 @@ void FormEditAccount::performTest() { tr("Other error occurred, contact developers.")); } } - else if (result.second.apiLevel() < MINIMAL_API_LEVEL) { + else if (result.apiLevel() < MINIMAL_API_LEVEL) { m_ui->m_lblTestResult->setStatus(WidgetWithStatus::Error, - tr("Selected Tiny Tiny RSS server is running unsupported version of API (%1). At least API level %2 is required.").arg(QString::number(result.second.apiLevel()), + tr("Selected Tiny Tiny RSS server is running unsupported version of API (%1). At least API level %2 is required.").arg(QString::number(result.apiLevel()), QString::number(MINIMAL_API_LEVEL)), tr("Selected Tiny Tiny RSS server is running unsupported version of API.")); } else { m_ui->m_lblTestResult->setStatus(WidgetWithStatus::Ok, - tr("Tiny Tiny RSS server is okay, running with API level %1, while at least API level %2 is required.").arg(QString::number(result.second.apiLevel()), + tr("Tiny Tiny RSS server is okay, running with API level %1, while at least API level %2 is required.").arg(QString::number(result.apiLevel()), QString::number(MINIMAL_API_LEVEL)), tr("Tiny Tiny RSS server is okay.")); } diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index c5224217d..ba5c6c0cc 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -20,8 +20,11 @@ #include "definitions/definitions.h" #include "core/rootitem.h" #include "services/tt-rss/definitions.h" +#include "services/tt-rss/ttrssfeed.h" #include "network-web/networkfactory.h" +#include + TtRssNetworkFactory::TtRssNetworkFactory() : m_url(QString()), m_username(QString()), m_password(QString()), m_sessionId(QString()) { @@ -63,9 +66,9 @@ void TtRssNetworkFactory::setPassword(const QString &password) { * */ -LoginResult TtRssNetworkFactory::login() { +TtRssLoginResponse TtRssNetworkFactory::login(QNetworkReply::NetworkError &error) { if (!m_sessionId.isEmpty()) { - logout(); + logout(error); } QtJson::JsonObject json; @@ -75,16 +78,17 @@ LoginResult TtRssNetworkFactory::login() { QByteArray result_raw; NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); - LoginResult result(network_reply.first, TtRssLoginResponse(QString::fromUtf8(result_raw))); + TtRssLoginResponse login_response(QString::fromUtf8(result_raw)); if (network_reply.first == QNetworkReply::NoError) { - m_sessionId = result.second.sessionId(); + m_sessionId = login_response.sessionId(); } - return result; + error = network_reply.first; + return login_response; } -LogoutResult TtRssNetworkFactory::logout() { +TtRssResponse TtRssNetworkFactory::logout(QNetworkReply::NetworkError &error) { QtJson::JsonObject json; json["op"] = "logout"; json["sid"] = m_sessionId; @@ -92,10 +96,11 @@ LogoutResult TtRssNetworkFactory::logout() { QByteArray result_raw; NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); - return LogoutResult(network_reply.first, TtRssResponse(QString::fromUtf8(result_raw))); + error = network_reply.first; + return TtRssResponse(QString::fromUtf8(result_raw)); } -GetFeedTreeResult TtRssNetworkFactory::getFeedTree() { +TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories(QNetworkReply::NetworkError &error) { QtJson::JsonObject json; json["op"] = "getFeedTree"; json["sid"] = m_sessionId; @@ -103,17 +108,18 @@ GetFeedTreeResult TtRssNetworkFactory::getFeedTree() { QByteArray result_raw; NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); - GetFeedTreeResult result(network_reply.first, TtRssGetFeedTreeResponse(QString::fromUtf8(result_raw))); + TtRssGetFeedsCategoriesResponse result(QString::fromUtf8(result_raw)); - if (result.second.isNotLoggedIn()) { + if (result.isNotLoggedIn()) { // We are not logged in. - login(); + login(error); json["sid"] = m_sessionId; network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); - result = GetFeedTreeResult(network_reply.first, TtRssGetFeedTreeResponse(QString::fromUtf8(result_raw))); + result = TtRssGetFeedsCategoriesResponse(QString::fromUtf8(result_raw)); } + error = network_reply.first; return result; } @@ -194,56 +200,21 @@ bool TtRssResponse::hasError() const { } -TtRssGetFeedTreeResponse::TtRssGetFeedTreeResponse(const QString &raw_content) : TtRssResponse(raw_content) { +TtRssGetFeedsCategoriesResponse::TtRssGetFeedsCategoriesResponse(const QString &raw_content) : TtRssResponse(raw_content) { } -TtRssGetFeedTreeResponse::~TtRssGetFeedTreeResponse() { +TtRssGetFeedsCategoriesResponse::~TtRssGetFeedsCategoriesResponse() { } -QList TtRssGetFeedTreeResponse::getTree() { +QList TtRssGetFeedsCategoriesResponse::feedsCategories() { QList items; if (status() == API_STATUS_OK) { // We have data, construct object tree according to data. QList items_to_process = m_rawContent["content"].toMap()["categories"].toMap()["items"].toList(); - processSubtree(true, items, NULL, items_to_process); } return items; } - -void TtRssGetFeedTreeResponse::processSubtree(bool is_top_level, QList &top_level_items, - RootItem *parent, const QList &items) { - foreach (QVariant item, items) { - QMap map_item = item.toMap(); - - if (map_item.contains("type") && map_item["type"].toString() == GFT_TYPE_CATEGORY) { - // TODO: pokračovat tady - - // We have category, create it, add it to "parent". - // Then process all its children. - // - // TtRssCategory *new_category = new TtRssCategory(); - // naplnit informace..... - // parent->appendChild(new_category); - // if (is_top_level) { - // top_level_items.append(new_category); - // } - // else { - // parent->appendChild(new_category); - // } - // processSubtree(false, top_level_items, new_category, map_item["items"].toList()); - } - else { - // We have feed, add it. - // TtRssFeed *new_feed = new TtRssFeed(); - // naplnit informace..... - // parent->appendChild(new_feed); - // if (is_top_level) { - // top_level_items.append(new_feed); - // } - } - } -} diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.h b/src/services/tt-rss/network/ttrssnetworkfactory.h index 292666b55..25cac350f 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.h +++ b/src/services/tt-rss/network/ttrssnetworkfactory.h @@ -53,23 +53,14 @@ class TtRssLoginResponse : public TtRssResponse { QString sessionId() const; }; -typedef QPair LoginResult; -typedef QPair LogoutResult; - -class TtRssGetFeedTreeResponse : public TtRssResponse { +class TtRssGetFeedsCategoriesResponse : public TtRssResponse { public: - explicit TtRssGetFeedTreeResponse(const QString &raw_content = QString()); - virtual ~TtRssGetFeedTreeResponse(); + explicit TtRssGetFeedsCategoriesResponse(const QString &raw_content = QString()); + virtual ~TtRssGetFeedsCategoriesResponse(); - QList getTree(); - - private: - void processSubtree(bool is_top_level, QList &top_level_items, - RootItem *parent, const QList &items); + QList feedsCategories(); }; -typedef QPair GetFeedTreeResult; - class TtRssNetworkFactory { public: explicit TtRssNetworkFactory(); @@ -87,13 +78,13 @@ class TtRssNetworkFactory { // Operations. // Logs user in. - LoginResult login(); + TtRssLoginResponse login(QNetworkReply::NetworkError &error); // Logs user out. - LogoutResult logout(); + TtRssResponse logout(QNetworkReply::NetworkError &error); - // Gets tree from feeds/categories obtained from the server. - GetFeedTreeResult getFeedTree(); + // Gets feeds from the server. + TtRssGetFeedsCategoriesResponse getFeedsCategories(QNetworkReply::NetworkError &error); private: QString m_url; diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index dd01193e7..8c19371a4 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -227,5 +227,8 @@ void TtRssServiceRoot::syncIn() { // TODO: provede stažení kanálů/kategorií // ze serveru, a sloučení s aktuálními // neprovádí aktualizace kanálů ani stažení počtu nepřečtených zpráv - QList aa = m_network->getFeedTree().second.getTree(); + QNetworkReply::NetworkError err; + + + TtRssGetFeedsCategoriesResponse aa = m_network->getFeedsCategories(err); } From 90d92e8aa8df61bfb26c49b1b7d15dbc7c496f0b Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 7 Dec 2015 19:40:05 +0100 Subject: [PATCH 135/203] Fuck it all, no mood. --- src/services/tt-rss/network/ttrssnetworkfactory.cpp | 5 ++++- src/services/tt-rss/ttrssserviceroot.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index ba5c6c0cc..af563c2cf 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -207,13 +207,16 @@ TtRssGetFeedsCategoriesResponse::TtRssGetFeedsCategoriesResponse(const QString & TtRssGetFeedsCategoriesResponse::~TtRssGetFeedsCategoriesResponse() { } -QList TtRssGetFeedsCategoriesResponse::feedsCategories() { +QList TtRssGetFeedsCategoriesResponse::feedsCategories() { QList items; if (status() == API_STATUS_OK) { // We have data, construct object tree according to data. QList items_to_process = m_rawContent["content"].toMap()["categories"].toMap()["items"].toList(); + while (!items_to_process.isEmpty()) { + + } } return items; diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 8c19371a4..381606e8f 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -230,5 +230,5 @@ void TtRssServiceRoot::syncIn() { QNetworkReply::NetworkError err; - TtRssGetFeedsCategoriesResponse aa = m_network->getFeedsCategories(err); + QList aa = m_network->getFeedsCategories(err).feedsCategories(); } From 746e7aae1f1b7e90b45b9cea797beb4590b1e34c Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 7 Dec 2015 20:41:16 +0100 Subject: [PATCH 136/203] Initial version of getFeedTree implementation. --- src/services/abstract/category.cpp | 1 + src/services/abstract/feed.cpp | 4 +- src/services/standard/standardcategory.cpp | 9 --- src/services/standard/standardcategory.h | 3 - src/services/standard/standardfeed.cpp | 3 - .../tt-rss/network/ttrssnetworkfactory.cpp | 62 +++++++++++++++++-- .../tt-rss/network/ttrssnetworkfactory.h | 2 +- src/services/tt-rss/ttrsscategory.cpp | 14 ++++- src/services/tt-rss/ttrsscategory.h | 6 ++ src/services/tt-rss/ttrssfeed.cpp | 21 ++++++- src/services/tt-rss/ttrssfeed.h | 11 +++- src/services/tt-rss/ttrssserviceroot.cpp | 2 +- 12 files changed, 111 insertions(+), 27 deletions(-) diff --git a/src/services/abstract/category.cpp b/src/services/abstract/category.cpp index 62829f673..097c9bc56 100755 --- a/src/services/abstract/category.cpp +++ b/src/services/abstract/category.cpp @@ -19,6 +19,7 @@ Category::Category(RootItem *parent) : RootItem(parent) { + setKind(RootItemKind::Category); } Category::~Category() { diff --git a/src/services/abstract/feed.cpp b/src/services/abstract/feed.cpp index a07cc8a7a..2faabce27 100755 --- a/src/services/abstract/feed.cpp +++ b/src/services/abstract/feed.cpp @@ -22,9 +22,11 @@ Feed::Feed(RootItem *parent) : RootItem(parent) { m_status = Normal; - m_autoUpdateType = DontAutoUpdate; + m_autoUpdateType = DefaultAutoUpdate; m_autoUpdateInitialInterval = DEFAULT_AUTO_UPDATE_INTERVAL; m_autoUpdateRemainingInterval = DEFAULT_AUTO_UPDATE_INTERVAL; + + setKind(RootItemKind::Feed); } Feed::~Feed() { diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index 8c7add25c..9cbe45021 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -37,13 +37,10 @@ StandardCategory::StandardCategory(RootItem *parent_item) : Category(parent_item) { - init(); } StandardCategory::StandardCategory(const StandardCategory &other) : Category(NULL) { - init(); - setId(other.id()); setTitle(other.title()); setDescription(other.description()); @@ -61,10 +58,6 @@ StandardServiceRoot *StandardCategory::serviceRoot() { return static_cast(getParentServiceRoot()); } -void StandardCategory::init() { - setKind(RootItemKind::Category); -} - QVariant StandardCategory::data(int column, int role) const { switch (role) { case Qt::ToolTipRole: @@ -222,8 +215,6 @@ bool StandardCategory::editItself(StandardCategory *new_category_data) { } StandardCategory::StandardCategory(const QSqlRecord &record) : Category(NULL) { - init(); - setId(record.value(CAT_DB_ID_INDEX).toInt()); setTitle(record.value(CAT_DB_TITLE_INDEX).toString()); setDescription(record.value(CAT_DB_DESCRIPTION_INDEX).toString()); diff --git a/src/services/standard/standardcategory.h b/src/services/standard/standardcategory.h index 36ac62f9a..7a90fd1f1 100755 --- a/src/services/standard/standardcategory.h +++ b/src/services/standard/standardcategory.h @@ -67,9 +67,6 @@ class StandardCategory : public Category { bool addItself(RootItem *parent); bool editItself(StandardCategory *new_category_data); - - private: - void init(); }; #endif // FEEDSMODELCLASSICCATEGORY_H diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index c9a355880..a0f4332f3 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -55,8 +55,6 @@ StandardFeed::StandardFeed(RootItem *parent_item) m_unreadCount = 0; m_encoding = QString(); m_url = QString(); - - setKind(RootItemKind::Feed); } StandardFeed::StandardFeed(const StandardFeed &other) @@ -76,7 +74,6 @@ StandardFeed::StandardFeed(const StandardFeed &other) setAutoUpdateInitialInterval(other.autoUpdateInitialInterval()); setAutoUpdateRemainingInterval(other.autoUpdateRemainingInterval()); - setKind(RootItemKind::Feed); setTitle(other.title()); setId(other.id()); setIcon(other.icon()); diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index af563c2cf..6576b9c08 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -21,6 +21,9 @@ #include "core/rootitem.h" #include "services/tt-rss/definitions.h" #include "services/tt-rss/ttrssfeed.h" +#include "services/tt-rss/ttrsscategory.h" +#include "miscellaneous/application.h" +#include "miscellaneous/iconfactory.h" #include "network-web/networkfactory.h" #include @@ -207,17 +210,68 @@ TtRssGetFeedsCategoriesResponse::TtRssGetFeedsCategoriesResponse(const QString & TtRssGetFeedsCategoriesResponse::~TtRssGetFeedsCategoriesResponse() { } -QList TtRssGetFeedsCategoriesResponse::feedsCategories() { - QList items; +RootItem *TtRssGetFeedsCategoriesResponse::feedsCategories() { + RootItem *parent = new RootItem(); if (status() == API_STATUS_OK) { // We have data, construct object tree according to data. QList items_to_process = m_rawContent["content"].toMap()["categories"].toMap()["items"].toList(); + QList > pairs; - while (!items_to_process.isEmpty()) { + foreach (QVariant item, items_to_process) { + pairs.append(QPair(parent, item)); + } + + while (!pairs.isEmpty()) { + QPair pair = pairs.takeFirst(); + RootItem *act_parent = pair.first; + QMap item = pair.second.toMap(); + + if (item.contains("type") && item["type"].toString() == GFT_TYPE_CATEGORY) { + // Add category to the parent, go through children. + int item_bare_id = item["bare_id"].toInt(); + + if (item_bare_id < 0) { + // Ignore virtual categories or feeds. + continue; + } + + if (item_bare_id == 0) { + // This is "Uncategorized" category, all its feeds belong to total parent. + if (item.contains("items")) { + foreach (QVariant child_feed, item["items"].toList()) { + pairs.append(QPair(parent, child_feed)); + } + } + } + else if (item_bare_id > 0) { + TtRssCategory *category = new TtRssCategory(); + + category->setIcon(qApp->icons()->fromTheme(QSL("folder-category"))); + category->setTitle(item["name"].toString()); + category->setCustomId(item_bare_id); + act_parent->appendChild(category); + + if (item.contains("items")) { + foreach (QVariant child, item["items"].toList()) { + pairs.append(QPair(category, child)); + } + } + } + } + else { + // We have feed. + int item_bare_id = item["bare_id"].toInt(); + TtRssFeed *feed = new TtRssFeed(); + + // TODO: stahnout a nastavit ikonu + feed->setTitle(item["name"].toString()); + feed->setCustomId(item_bare_id); + act_parent->appendChild(feed); + } } } - return items; + return parent; } diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.h b/src/services/tt-rss/network/ttrssnetworkfactory.h index 25cac350f..5bc259209 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.h +++ b/src/services/tt-rss/network/ttrssnetworkfactory.h @@ -58,7 +58,7 @@ class TtRssGetFeedsCategoriesResponse : public TtRssResponse { explicit TtRssGetFeedsCategoriesResponse(const QString &raw_content = QString()); virtual ~TtRssGetFeedsCategoriesResponse(); - QList feedsCategories(); + RootItem *feedsCategories(); }; class TtRssNetworkFactory { diff --git a/src/services/tt-rss/ttrsscategory.cpp b/src/services/tt-rss/ttrsscategory.cpp index 4fc96230b..7b485288e 100644 --- a/src/services/tt-rss/ttrsscategory.cpp +++ b/src/services/tt-rss/ttrsscategory.cpp @@ -15,11 +15,21 @@ // You should have received a copy of the GNU General Public License // along with RSS Guard. If not, see . -#include "ttrsscategory.h" +#include "services/tt-rss/ttrsscategory.h" + +#include "definitions/definitions.h" -TtRssCategory::TtRssCategory(RootItem *parent) : Category(parent) { +TtRssCategory::TtRssCategory(RootItem *parent) : Category(parent), m_customId(NO_PARENT_CATEGORY) { } TtRssCategory::~TtRssCategory() { } + +int TtRssCategory::customId() const { + return m_customId; +} + +void TtRssCategory::setCustomId(int custom_id) { + m_customId = custom_id; +} diff --git a/src/services/tt-rss/ttrsscategory.h b/src/services/tt-rss/ttrsscategory.h index 2758d2c78..fb7df9a24 100644 --- a/src/services/tt-rss/ttrsscategory.h +++ b/src/services/tt-rss/ttrsscategory.h @@ -25,6 +25,12 @@ class TtRssCategory : public Category { public: explicit TtRssCategory(RootItem *parent = NULL); virtual ~TtRssCategory(); + + int customId() const; + void setCustomId(int custom_id); + + private: + int m_customId; }; #endif // TTRSSCATEGORY_H diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index e12fbefc2..45d90dc31 100644 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -15,12 +15,29 @@ // You should have received a copy of the GNU General Public License // along with RSS Guard. If not, see . -#include "ttrssfeed.h" +#include "services/tt-rss/ttrssfeed.h" + +#include "definitions/definitions.h" -TtRssFeed::TtRssFeed(RootItem *parent) : Feed(parent) { +TtRssFeed::TtRssFeed(RootItem *parent) : Feed(parent), m_customId(NO_PARENT_CATEGORY) { } TtRssFeed::~TtRssFeed() { } +int TtRssFeed::update() { + return 0; +} + +QList TtRssFeed::undeletedMessages() const { + return QList(); +} + +int TtRssFeed::customId() const { + return m_customId; +} + +void TtRssFeed::setCustomId(int custom_id) { + m_customId = custom_id; +} diff --git a/src/services/tt-rss/ttrssfeed.h b/src/services/tt-rss/ttrssfeed.h index b947e805d..314ad880d 100644 --- a/src/services/tt-rss/ttrssfeed.h +++ b/src/services/tt-rss/ttrssfeed.h @@ -18,13 +18,22 @@ #ifndef TTRSSFEED_H #define TTRSSFEED_H -#include +#include "services/abstract/feed.h" class TtRssFeed : public Feed { public: explicit TtRssFeed(RootItem *parent = NULL); virtual ~TtRssFeed(); + + int update(); + QList undeletedMessages() const; + + int customId() const; + void setCustomId(int custom_id); + + private: + int m_customId; }; #endif // TTRSSFEED_H diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 381606e8f..48575f313 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -230,5 +230,5 @@ void TtRssServiceRoot::syncIn() { QNetworkReply::NetworkError err; - QList aa = m_network->getFeedsCategories(err).feedsCategories(); + RootItem *aa = m_network->getFeedsCategories(err).feedsCategories(); } From a9f44bdd02353c305323cd198097256adcb32195 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 7 Dec 2015 20:59:43 +0100 Subject: [PATCH 137/203] Work on syncing. --- src/services/tt-rss/gui/formeditaccount.cpp | 2 +- .../tt-rss/network/ttrssnetworkfactory.cpp | 13 +++---- .../tt-rss/network/ttrssnetworkfactory.h | 10 ++--- .../tt-rss/ttrssserviceentrypoint.cpp | 1 - src/services/tt-rss/ttrssserviceroot.cpp | 38 +++++++++++++++---- src/services/tt-rss/ttrssserviceroot.h | 7 +++- 6 files changed, 48 insertions(+), 23 deletions(-) diff --git a/src/services/tt-rss/gui/formeditaccount.cpp b/src/services/tt-rss/gui/formeditaccount.cpp index 43068321c..57fbfed10 100755 --- a/src/services/tt-rss/gui/formeditaccount.cpp +++ b/src/services/tt-rss/gui/formeditaccount.cpp @@ -148,7 +148,7 @@ void FormEditAccount::onClickedOk() { m_editableRoot->network()->setUrl(m_ui->m_txtUrl->lineEdit()->text()); m_editableRoot->network()->setUsername(m_ui->m_txtUsername->lineEdit()->text()); m_editableRoot->network()->setPassword(m_ui->m_txtPassword->lineEdit()->text()); - m_editableRoot->saveToDatabase(); + m_editableRoot->saveAccountDataToDatabase(); accept(); } diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index 6576b9c08..3c854f1bd 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -103,7 +103,7 @@ TtRssResponse TtRssNetworkFactory::logout(QNetworkReply::NetworkError &error) { return TtRssResponse(QString::fromUtf8(result_raw)); } -TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories(QNetworkReply::NetworkError &error) { +TtRssGetFeedsTreeResponse TtRssNetworkFactory::getFeedsTree(QNetworkReply::NetworkError &error) { QtJson::JsonObject json; json["op"] = "getFeedTree"; json["sid"] = m_sessionId; @@ -111,7 +111,7 @@ TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories(QNetwork QByteArray result_raw; NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); - TtRssGetFeedsCategoriesResponse result(QString::fromUtf8(result_raw)); + TtRssGetFeedsTreeResponse result(QString::fromUtf8(result_raw)); if (result.isNotLoggedIn()) { // We are not logged in. @@ -119,7 +119,7 @@ TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories(QNetwork json["sid"] = m_sessionId; network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); - result = TtRssGetFeedsCategoriesResponse(QString::fromUtf8(result_raw)); + result = TtRssGetFeedsTreeResponse(QString::fromUtf8(result_raw)); } error = network_reply.first; @@ -203,14 +203,13 @@ bool TtRssResponse::hasError() const { } -TtRssGetFeedsCategoriesResponse::TtRssGetFeedsCategoriesResponse(const QString &raw_content) : TtRssResponse(raw_content) { - +TtRssGetFeedsTreeResponse::TtRssGetFeedsTreeResponse(const QString &raw_content) : TtRssResponse(raw_content) { } -TtRssGetFeedsCategoriesResponse::~TtRssGetFeedsCategoriesResponse() { +TtRssGetFeedsTreeResponse::~TtRssGetFeedsTreeResponse() { } -RootItem *TtRssGetFeedsCategoriesResponse::feedsCategories() { +RootItem *TtRssGetFeedsTreeResponse::feedsTree() { RootItem *parent = new RootItem(); if (status() == API_STATUS_OK) { diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.h b/src/services/tt-rss/network/ttrssnetworkfactory.h index 5bc259209..6db415d73 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.h +++ b/src/services/tt-rss/network/ttrssnetworkfactory.h @@ -53,12 +53,12 @@ class TtRssLoginResponse : public TtRssResponse { QString sessionId() const; }; -class TtRssGetFeedsCategoriesResponse : public TtRssResponse { +class TtRssGetFeedsTreeResponse : public TtRssResponse { public: - explicit TtRssGetFeedsCategoriesResponse(const QString &raw_content = QString()); - virtual ~TtRssGetFeedsCategoriesResponse(); + explicit TtRssGetFeedsTreeResponse(const QString &raw_content = QString()); + virtual ~TtRssGetFeedsTreeResponse(); - RootItem *feedsCategories(); + RootItem *feedsTree(); }; class TtRssNetworkFactory { @@ -84,7 +84,7 @@ class TtRssNetworkFactory { TtRssResponse logout(QNetworkReply::NetworkError &error); // Gets feeds from the server. - TtRssGetFeedsCategoriesResponse getFeedsCategories(QNetworkReply::NetworkError &error); + TtRssGetFeedsTreeResponse getFeedsTree(QNetworkReply::NetworkError &error); private: QString m_url; diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp index 02c03c88a..6af16e2a8 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.cpp +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -87,7 +87,6 @@ QList TtRssServiceEntryPoint::initializeSubtree() { root->network()->setPassword(query.value(2).toString()); root->network()->setUrl(query.value(3).toString()); root->updateTitle(); - root->loadFromDatabase(); roots.append(root); } } diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 48575f313..7f1086a5b 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -42,6 +42,8 @@ TtRssServiceRoot::~TtRssServiceRoot() { } void TtRssServiceRoot::start() { + loadFeedTreeFromDatabase(); + if (childItems().isEmpty()) { syncIn(); } @@ -164,7 +166,7 @@ TtRssNetworkFactory *TtRssServiceRoot::network() const { return m_network; } -void TtRssServiceRoot::saveToDatabase() { +void TtRssServiceRoot::saveAccountDataToDatabase() { if (accountId() != NO_PARENT_CATEGORY) { // We are overwritting previously saved data. QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); @@ -209,10 +211,6 @@ void TtRssServiceRoot::saveToDatabase() { } } -void TtRssServiceRoot::loadFromDatabase() { - // TODO: Load feeds/categories from DB. -} - void TtRssServiceRoot::updateTitle() { QString host = QUrl(m_network->url()).host(); @@ -227,8 +225,34 @@ void TtRssServiceRoot::syncIn() { // TODO: provede stažení kanálů/kategorií // ze serveru, a sloučení s aktuálními // neprovádí aktualizace kanálů ani stažení počtu nepřečtených zpráv - QNetworkReply::NetworkError err; + QNetworkReply::NetworkError error; + RootItem *new_feeds = m_network->getFeedsTree(error).feedsTree(); + if (error == QNetworkReply::NoError) { + // We have new feeds, purge old and set new to DB. + removeOldFeedTree(); - RootItem *aa = m_network->getFeedsCategories(err).feedsCategories(); + foreach (RootItem *child, childItems()) { + requestItemRemoval(child); + } + + clearChildren(); + + // Old stuff is gone. + storeNewFeedTree(new_feeds); + loadFeedTreeFromDatabase(); + //itemChanged(QList() << this); + } +} + +void TtRssServiceRoot::removeOldFeedTree() { + // TODO: vymazat kanaly a kategorie. +} + +void TtRssServiceRoot::storeNewFeedTree(RootItem *tree_root) { + // TODO: ulozit do db. +} + +void TtRssServiceRoot::loadFeedTreeFromDatabase() { + // TODO: nacist kanaly a kategorie z db } diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 00ba6446e..f34fba2b3 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -66,14 +66,17 @@ class TtRssServiceRoot : public ServiceRoot { TtRssNetworkFactory *network() const; - void saveToDatabase(); - void loadFromDatabase(); + void saveAccountDataToDatabase(); void updateTitle(); private slots: void syncIn(); private: + void removeOldFeedTree(); + void storeNewFeedTree(RootItem *tree_root); + void loadFeedTreeFromDatabase(); + QAction *m_actionSyncIn; QList m_serviceMenu; From 683517948d84c229ba2201dfaf82aae03daabfeb Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 8 Dec 2015 09:11:55 +0100 Subject: [PATCH 138/203] Many changes, working Sync in, fixed some problems with item expanding, items now can inform model that it wants some items expanded or not. --- resources/misc/db_init_mysql.sql | 10 +- resources/misc/db_init_sqlite.sql | 10 +- resources/misc/db_update_mysql_3_4.sql | 15 +++ resources/misc/db_update_sqlite_3_4.sql | 50 ++++++++ src/core/feedsmodel.cpp | 1 + src/core/feedsmodel.h | 3 + src/gui/feedsview.cpp | 19 +++- src/gui/feedsview.h | 1 + src/services/abstract/serviceroot.cpp | 6 +- src/services/abstract/serviceroot.h | 5 +- .../standard/standardserviceentrypoint.cpp | 2 - src/services/standard/standardserviceroot.cpp | 2 + src/services/tt-rss/gui/formeditaccount.cpp | 5 +- .../tt-rss/network/ttrssnetworkfactory.cpp | 102 ++++++++++------- .../tt-rss/network/ttrssnetworkfactory.h | 5 +- .../tt-rss/ttrssserviceentrypoint.cpp | 1 - src/services/tt-rss/ttrssserviceroot.cpp | 107 +++++++++++++++++- src/services/tt-rss/ttrssserviceroot.h | 8 +- 18 files changed, 282 insertions(+), 70 deletions(-) diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index b3eb5e2cd..d1bbd370d 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -36,7 +36,7 @@ CREATE TABLE IF NOT EXISTS Categories ( parent_id INTEGER NOT NULL, title VARCHAR(100) NOT NULL CHECK (title != ''), description TEXT, - date_created BIGINT NOT NULL CHECK (date_created != 0), + date_created BIGINT, icon BLOB, account_id INTEGER NOT NULL, custom_id TEXT, @@ -50,17 +50,17 @@ CREATE TABLE IF NOT EXISTS Feeds ( id INTEGER AUTO_INCREMENT PRIMARY KEY, title TEXT NOT NULL CHECK (title != ''), description TEXT, - date_created BIGINT NOT NULL CHECK (date_created != 0), + date_created BIGINT, icon BLOB, category INTEGER NOT NULL CHECK (category >= -1), - encoding TEXT NOT NULL CHECK (encoding != ''), - url VARCHAR(100) NOT NULL CHECK (url != ''), + encoding TEXT, + url VARCHAR(100), protected INTEGER(1) NOT NULL CHECK (protected >= 0 AND protected <= 1), username TEXT, password TEXT, update_type INTEGER(1) NOT NULL CHECK (update_type >= 0), update_interval INTEGER NOT NULL DEFAULT 15 CHECK (update_interval >= 5), - type INTEGER NOT NULL CHECK (type >= 0), + type INTEGER, account_id INTEGER NOT NULL, custom_id TEXT, diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index 80a091205..a0e357296 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -31,7 +31,7 @@ CREATE TABLE IF NOT EXISTS Categories ( parent_id INTEGER NOT NULL, title TEXT NOT NULL CHECK (title != ''), description TEXT, - date_created INTEGER NOT NULL CHECK (date_created != 0), + date_created INTEGER, icon BLOB, account_id INTEGER NOT NULL, custom_id TEXT, @@ -45,17 +45,17 @@ CREATE TABLE IF NOT EXISTS Feeds ( id INTEGER PRIMARY KEY, title TEXT NOT NULL CHECK (title != ''), description TEXT, - date_created INTEGER NOT NULL CHECK (date_created != 0), + date_created INTEGER, icon BLOB, category INTEGER NOT NULL CHECK (category >= -1), - encoding TEXT NOT NULL CHECK (encoding != ''), - url TEXT NOT NULL CHECK (url != ''), + encoding TEXT, + url TEXT, protected INTEGER(1) NOT NULL CHECK (protected >= 0 AND protected <= 1), username TEXT, password TEXT, update_type INTEGER(1) NOT NULL CHECK (update_type >= 0), update_interval INTEGER NOT NULL CHECK (update_interval >= 5) DEFAULT 15, - type INTEGER NOT NULL CHECK (type >= 0), + type INTEGER, account_id INTEGER NOT NULL, custom_id TEXT, diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index 892d54579..25038fd1e 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -40,4 +40,19 @@ DROP FOREIGN KEY feed; ALTER TABLE Messages MODIFY Feeds TEXT; -- ! +ALTER TABLE Feeds +MODIFY date_created BIGINT; +-- ! +ALTER TABLE Feeds +MODIFY encoding TEXT; +-- ! +ALTER TABLE Feeds +MODIFY url VARCHAR(100); +-- ! +ALTER TABLE Feeds +MODIFY type INTEGER; +-- ! +ALTER TABLE Categories +MODIFY date_created BIGINT; +-- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql index 6a6433312..6765c6491 100644 --- a/resources/misc/db_update_sqlite_3_4.sql +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -61,4 +61,54 @@ INSERT INTO Messages SELECT * FROM backup_Messages; -- ! DROP TABLE backup_Messages; -- ! +CREATE TABLE backup_Feeds AS SELECT * FROM Feeds; +-- ! +DROP TABLE Feeds; +-- ! +CREATE TABLE Feeds ( + id INTEGER PRIMARY KEY, + title TEXT NOT NULL CHECK (title != ''), + description TEXT, + date_created INTEGER, + icon BLOB, + category INTEGER NOT NULL CHECK (category >= -1), + encoding TEXT, + url TEXT, + protected INTEGER(1) NOT NULL CHECK (protected >= 0 AND protected <= 1), + username TEXT, + password TEXT, + update_type INTEGER(1) NOT NULL CHECK (update_type >= 0), + update_interval INTEGER NOT NULL CHECK (update_interval >= 5) DEFAULT 15, + type INTEGER, + account_id INTEGER NOT NULL, + custom_id TEXT, + + FOREIGN KEY (account_id) REFERENCES Accounts (id) +); +-- ! +INSERT INTO Feeds SELECT * FROM backup_Feeds; +-- ! +DROP TABLE backup_Feeds; +-- ! +CREATE TABLE backup_Categories AS SELECT * FROM Categories; +-- ! +DROP TABLE Categories; +-- ! +CREATE TABLE Categories ( + id INTEGER PRIMARY KEY, + parent_id INTEGER NOT NULL, + title TEXT NOT NULL CHECK (title != ''), + description TEXT, + date_created INTEGER, + icon BLOB, + account_id INTEGER NOT NULL, + custom_id TEXT, + + FOREIGN KEY (account_id) REFERENCES Accounts (id) +); +-- ! +INSERT INTO Categories SELECT * FROM backup_Categories; +-- ! +DROP TABLE backup_Categories; +-- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index ce322eb5e..b6040476e 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -697,6 +697,7 @@ bool FeedsModel::addServiceAccount(ServiceRoot *root) { connect(root, SIGNAL(readFeedsFilterInvalidationRequested()), this, SIGNAL(readFeedsFilterInvalidationRequested())); connect(root, SIGNAL(dataChanged(QList)), this, SLOT(onItemDataChanged(QList))); connect(root, SIGNAL(reloadMessageListRequested(bool)), this, SIGNAL(reloadMessageListRequested(bool))); + connect(root, SIGNAL(itemExpandRequested(QList,bool)), this, SIGNAL(itemExpandRequested(QList,bool))); root->start(); return true; diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 83df548e5..1e94efc93 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -206,6 +206,9 @@ class FeedsModel : public QAbstractItemModel { // Emitted if counts of messages are changed. void messageCountsChanged(int unread_messages, int total_messages, bool any_feed_has_unread_messages); + // Emitted if any item requested that any view should expand it. + void itemExpandRequested(QList items, bool expand); + // Emitted when there is a need of reloading of displayed messages. void reloadMessageListRequested(bool mark_selected_messages_read); diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index d976b6e84..39a48d211 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -55,6 +55,7 @@ FeedsView::FeedsView(QWidget *parent) // Connections. connect(m_sourceModel, SIGNAL(requireItemValidationAfterDragDrop(QModelIndex)), this, SLOT(validateItemAfterDragDrop(QModelIndex))); + connect(m_sourceModel, SIGNAL(itemExpandRequested(QList,bool)), this, SLOT(onItemExpandRequested(QList,bool))); connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortState(int,Qt::SortOrder))); setModel(m_proxyModel); @@ -102,11 +103,11 @@ void FeedsView::saveExpandedStates() { Settings *settings = qApp->settings(); QList expandable_items; - expandable_items.append(sourceModel()->rootItem()->getSubTree(RootItemKind::Category)); + expandable_items.append(sourceModel()->rootItem()->getSubTree(RootItemKind::Category | RootItemKind::ServiceRoot)); // Iterate all categories and save their expand statuses. foreach (RootItem *item, expandable_items) { - QString setting_name = QString::number(qHash(item->title())) + QL1S("-") + QString::number(item->id()); + QString setting_name = QString::number(item->kind()) + QL1S("-") + QString::number(qHash(item->title())) + QL1S("-") + QString::number(item->id()); settings->setValue(GROUP(Categories), setting_name, @@ -122,10 +123,10 @@ void FeedsView::loadExpandedStates() { // Iterate all categories and save their expand statuses. foreach (RootItem *item, expandable_items) { - QString setting_name = QString::number(qHash(item->title())) + QL1S("-") + QString::number(item->id()); + QString setting_name = QString::number(item->kind()) + QL1S("-") + QString::number(qHash(item->title())) + QL1S("-") + QString::number(item->id()); setExpanded(model()->mapFromSource(sourceModel()->indexForItem(item)), - settings->value(GROUP(Categories), setting_name, true).toBool()); + settings->value(GROUP(Categories), setting_name, item->childCount() > 0).toBool()); } } @@ -466,3 +467,13 @@ void FeedsView::validateItemAfterDragDrop(const QModelIndex &source_index) { setCurrentIndex(mapped); } } + +void FeedsView::onItemExpandRequested(const QList &items, bool exp) { + foreach (RootItem *item, items) { + QModelIndex source_index = m_sourceModel->indexForItem(item); + QModelIndex proxy_index = m_proxyModel->mapFromSource(source_index); + + setExpanded(proxy_index, !exp); + setExpanded(proxy_index, exp); + } +} diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index 05f9f8a31..f80a9a250 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -104,6 +104,7 @@ class FeedsView : public QTreeView { void saveSortState(int column, Qt::SortOrder order); void validateItemAfterDragDrop(const QModelIndex &source_index); + void onItemExpandRequested(const QList &items, bool exp); private: // Initializes context menus. diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index 2a804ce18..cd25632b1 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -58,7 +58,7 @@ bool ServiceRoot::deleteViaGui() { return data_removed; } -void ServiceRoot::itemChanged(QList items) { +void ServiceRoot::itemChanged(const QList &items) { emit dataChanged(items); } @@ -70,6 +70,10 @@ void ServiceRoot::requestFeedReadFilterReload() { emit readFeedsFilterInvalidationRequested(); } +void ServiceRoot::requestItemExpand(const QList &items, bool expand) { + emit itemExpandRequested(items, expand); +} + void ServiceRoot::requestItemReassignment(RootItem *item, RootItem *new_parent) { emit itemReassignmentRequested(item, new_parent); } diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 3dbd13475..30498fc73 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -138,10 +138,10 @@ class ServiceRoot : public RootItem { ///////////////////////////////////////// // Obvious methods to wrap signals. - void itemChanged(QList items); + void itemChanged(const QList &items); void requestReloadMessageList(bool mark_selected_messages_read); void requestFeedReadFilterReload(); - + void requestItemExpand(const QList &items, bool expand); void requestItemReassignment(RootItem *item, RootItem *new_parent); void requestItemRemoval(RootItem *item); @@ -154,6 +154,7 @@ class ServiceRoot : public RootItem { void dataChanged(QList items); void readFeedsFilterInvalidationRequested(); void reloadMessageListRequested(bool mark_selected_messages_read); + void itemExpandRequested(QList items, bool expand); void itemReassignmentRequested(RootItem *item, RootItem *new_parent); void itemRemovalRequested(RootItem *item); diff --git a/src/services/standard/standardserviceentrypoint.cpp b/src/services/standard/standardserviceentrypoint.cpp index ca3615619..f852f6bb5 100755 --- a/src/services/standard/standardserviceentrypoint.cpp +++ b/src/services/standard/standardserviceentrypoint.cpp @@ -75,7 +75,6 @@ ServiceRoot *StandardServiceEntryPoint::createNewRoot() { SERVICE_CODE_STD_RSS))) { StandardServiceRoot *root = new StandardServiceRoot(); root->setAccountId(id_to_assing); - root->loadFromDatabase(); return root; } else { @@ -93,7 +92,6 @@ QList StandardServiceEntryPoint::initializeSubtree() { while (query.next()) { StandardServiceRoot *root = new StandardServiceRoot(); root->setAccountId(query.value(0).toInt()); - root->loadFromDatabase(); roots.append(root); } } diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index ecebe24bf..c261155f0 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -61,6 +61,8 @@ StandardServiceRoot::~StandardServiceRoot() { } void StandardServiceRoot::start() { + loadFromDatabase(); + if (qApp->isFirstRun()) { if (MessageBox::show(qApp->mainForm(), QMessageBox::Question, QObject::tr("Load initial set of feeds"), tr("You started %1 for the first time, now you can load initial set of feeds.").arg(APP_NAME), diff --git a/src/services/tt-rss/gui/formeditaccount.cpp b/src/services/tt-rss/gui/formeditaccount.cpp index 43068321c..865e2df0e 100755 --- a/src/services/tt-rss/gui/formeditaccount.cpp +++ b/src/services/tt-rss/gui/formeditaccount.cpp @@ -148,7 +148,7 @@ void FormEditAccount::onClickedOk() { m_editableRoot->network()->setUrl(m_ui->m_txtUrl->lineEdit()->text()); m_editableRoot->network()->setUsername(m_ui->m_txtUsername->lineEdit()->text()); m_editableRoot->network()->setPassword(m_ui->m_txtPassword->lineEdit()->text()); - m_editableRoot->saveToDatabase(); + m_editableRoot->saveAccountDataToDatabase(); accept(); } @@ -185,6 +185,9 @@ void FormEditAccount::onUrlChanged() { if (url.isEmpty()) { m_ui->m_txtUrl->setStatus(WidgetWithStatus::Error, tr("URL cannot be empty.")); } + else if (!url.endsWith(QL1S("api/"))) { + m_ui->m_txtUrl->setStatus(WidgetWithStatus::Error, tr("URL must end with \"api/\".")); + } else { m_ui->m_txtUrl->setStatus(WidgetWithStatus::Ok, tr("URL is okay.")); } diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index 6576b9c08..5915f545e 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -92,15 +92,22 @@ TtRssLoginResponse TtRssNetworkFactory::login(QNetworkReply::NetworkError &error } TtRssResponse TtRssNetworkFactory::logout(QNetworkReply::NetworkError &error) { - QtJson::JsonObject json; - json["op"] = "logout"; - json["sid"] = m_sessionId; + if (!m_sessionId.isEmpty()) { - QByteArray result_raw; - NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + QtJson::JsonObject json; + json["op"] = "logout"; + json["sid"] = m_sessionId; - error = network_reply.first; - return TtRssResponse(QString::fromUtf8(result_raw)); + QByteArray result_raw; + NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + + error = network_reply.first; + return TtRssResponse(QString::fromUtf8(result_raw)); + } + else { + error = QNetworkReply::NoError; + return TtRssResponse(); + } } TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories(QNetworkReply::NetworkError &error) { @@ -210,9 +217,12 @@ TtRssGetFeedsCategoriesResponse::TtRssGetFeedsCategoriesResponse(const QString & TtRssGetFeedsCategoriesResponse::~TtRssGetFeedsCategoriesResponse() { } -RootItem *TtRssGetFeedsCategoriesResponse::feedsCategories() { +RootItem *TtRssGetFeedsCategoriesResponse::feedsCategories(bool obtain_icons, QString base_address) { RootItem *parent = new RootItem(); + // Chop the "api/" from the end of the address. + base_address.chop(4); + if (status() == API_STATUS_OK) { // We have data, construct object tree according to data. QList items_to_process = m_rawContent["content"].toMap()["categories"].toMap()["items"].toList(); @@ -227,49 +237,61 @@ RootItem *TtRssGetFeedsCategoriesResponse::feedsCategories() { RootItem *act_parent = pair.first; QMap item = pair.second.toMap(); - if (item.contains("type") && item["type"].toString() == GFT_TYPE_CATEGORY) { - // Add category to the parent, go through children. - int item_bare_id = item["bare_id"].toInt(); + int item_id = item["bare_id"].toInt(); + bool is_category = item.contains("type") && item["type"].toString() == GFT_TYPE_CATEGORY; - if (item_bare_id < 0) { - // Ignore virtual categories or feeds. - continue; - } + if (item_id >= 0) { + if (is_category) { + if (item_id == 0) { + // This is "Uncategorized" category, all its feeds belong to top-level root. + if (item.contains("items")) { + foreach (QVariant child_feed, item["items"].toList()) { + pairs.append(QPair(parent, child_feed)); + } + } + } + else { + TtRssCategory *category = new TtRssCategory(); - if (item_bare_id == 0) { - // This is "Uncategorized" category, all its feeds belong to total parent. - if (item.contains("items")) { - foreach (QVariant child_feed, item["items"].toList()) { - pairs.append(QPair(parent, child_feed)); + category->setIcon(qApp->icons()->fromTheme(QSL("folder-category"))); + category->setTitle(item["name"].toString()); + category->setCustomId(item_id); + act_parent->appendChild(category); + + if (item.contains("items")) { + foreach (QVariant child, item["items"].toList()) { + pairs.append(QPair(category, child)); + } } } } - else if (item_bare_id > 0) { - TtRssCategory *category = new TtRssCategory(); + else { + // We have feed. + TtRssFeed *feed = new TtRssFeed(); - category->setIcon(qApp->icons()->fromTheme(QSL("folder-category"))); - category->setTitle(item["name"].toString()); - category->setCustomId(item_bare_id); - act_parent->appendChild(category); + if (obtain_icons) { + QString icon_path = item["icon"].type() == QVariant::String ? item["icon"].toString() : QString(); - if (item.contains("items")) { - foreach (QVariant child, item["items"].toList()) { - pairs.append(QPair(category, child)); + if (!icon_path.isEmpty()) { + // Chop the "api/" suffix out and append + QString full_icon_address = base_address + QL1C('/') + icon_path; + QByteArray icon_data; + + if (NetworkFactory::downloadFile(full_icon_address, DOWNLOAD_TIMEOUT, icon_data).first == QNetworkReply::NoError) { + // Icon downloaded, set it up. + QPixmap icon_pixmap; + icon_pixmap.loadFromData(icon_data); + feed->setIcon(QIcon(icon_pixmap)); + } } } + + // TODO: stahnout a nastavit ikonu + feed->setTitle(item["name"].toString()); + feed->setCustomId(item_id); + act_parent->appendChild(feed); } } - else { - // We have feed. - int item_bare_id = item["bare_id"].toInt(); - TtRssFeed *feed = new TtRssFeed(); - - // TODO: stahnout a nastavit ikonu - feed->setTitle(item["name"].toString()); - feed->setCustomId(item_bare_id); - act_parent->appendChild(feed); - } - } } diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.h b/src/services/tt-rss/network/ttrssnetworkfactory.h index 5bc259209..8e76f3b09 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.h +++ b/src/services/tt-rss/network/ttrssnetworkfactory.h @@ -58,7 +58,10 @@ class TtRssGetFeedsCategoriesResponse : public TtRssResponse { explicit TtRssGetFeedsCategoriesResponse(const QString &raw_content = QString()); virtual ~TtRssGetFeedsCategoriesResponse(); - RootItem *feedsCategories(); + // Returns tree of feeds/categories. + // Top-level root of the tree is not needed here. + // Returned items do not have primary IDs assigned. + RootItem *feedsCategories(bool obtain_icons, QString base_address = QString()); }; class TtRssNetworkFactory { diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp index 02c03c88a..6af16e2a8 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.cpp +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -87,7 +87,6 @@ QList TtRssServiceEntryPoint::initializeSubtree() { root->network()->setPassword(query.value(2).toString()); root->network()->setUrl(query.value(3).toString()); root->updateTitle(); - root->loadFromDatabase(); roots.append(root); } } diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 48575f313..bffdd96e0 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -21,6 +21,8 @@ #include "miscellaneous/settings.h" #include "gui/dialogs/formmain.h" #include "services/tt-rss/ttrssserviceentrypoint.h" +#include "services/tt-rss/ttrssfeed.h" +#include "services/tt-rss/ttrsscategory.h" #include "services/tt-rss/network/ttrssnetworkfactory.h" #include "services/tt-rss/gui/formeditaccount.h" @@ -42,13 +44,16 @@ TtRssServiceRoot::~TtRssServiceRoot() { } void TtRssServiceRoot::start() { - if (childItems().isEmpty()) { - syncIn(); - } + // TODO: posunout starty rootů až je okno uděláno + loadFromDatabase(); + + // TODO: pokud tady není nic načteno, tak + // syncIn } void TtRssServiceRoot::stop() { - + QNetworkReply::NetworkError error; + m_network->logout(error); } QString TtRssServiceRoot::code() { @@ -164,7 +169,7 @@ TtRssNetworkFactory *TtRssServiceRoot::network() const { return m_network; } -void TtRssServiceRoot::saveToDatabase() { +void TtRssServiceRoot::saveAccountDataToDatabase() { if (accountId() != NO_PARENT_CATEGORY) { // We are overwritting previously saved data. QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); @@ -228,7 +233,97 @@ void TtRssServiceRoot::syncIn() { // ze serveru, a sloučení s aktuálními // neprovádí aktualizace kanálů ani stažení počtu nepřečtených zpráv QNetworkReply::NetworkError err; + TtRssGetFeedsCategoriesResponse feed_cats_response = m_network->getFeedsCategories(err); + if (err == QNetworkReply::NoError) { + RootItem *new_tree = feed_cats_response.feedsCategories(true, m_network->url()); - RootItem *aa = m_network->getFeedsCategories(err).feedsCategories(); + // Purge old data from SQL and clean all model items. + removeOldFeedTree(); + cleanAllItems(); + + // Model is clean, now store new tree into DB and + // set primary IDs of the items. + storeNewFeedTree(new_tree); + + foreach (RootItem *top_level_item, new_tree->childItems()) { + appendChild(top_level_item); + } + + new_tree->clearChildren(); + new_tree->deleteLater(); + itemChanged(QList() << this); + requestFeedReadFilterReload(); + requestReloadMessageList(true); + requestItemExpand(getSubTree(), true); + } +} + +void TtRssServiceRoot::removeOldFeedTree() { + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + QSqlQuery query(database); + query.setForwardOnly(true); + + query.prepare(QSL("DELETE FROM Feeds WHERE account_id = :account_id;")); + query.bindValue(QSL(":account_id"), accountId()); + query.exec(); + + query.prepare(QSL("DELETE FROM Categories WHERE account_id = :account_id;")); + query.bindValue(QSL(":account_id"), accountId()); + query.exec(); +} + +void TtRssServiceRoot::cleanAllItems() { + foreach (RootItem *top_level_item, childItems()) { + requestItemRemoval(top_level_item); + } +} + +void TtRssServiceRoot::storeNewFeedTree(RootItem *root) { + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + QSqlQuery query_category(database); + QSqlQuery query_feed(database); + + query_category.prepare("INSERT INTO Categories (parent_id, title, account_id, custom_id) " + "VALUES (:parent_id, :title, :account_id, :custom_id);"); + query_feed.prepare("INSERT INTO Feeds (title, icon, category, protected, update_type, update_interval, account_id, custom_id) " + "VALUES (:title, :icon, :category, :protected, :update_type, :update_interval, :account_id, :custom_id);"); + + // Iterate all children. + foreach (RootItem *child, root->getSubTree()) { + if (child->kind() == RootItemKind::Category) { + query_category.bindValue(QSL(":parent_id"), child->parent()->id()); + query_category.bindValue(QSL(":title"), child->title()); + query_category.bindValue(QSL(":account_id"), accountId()); + query_category.bindValue(QSL(":custom_id"), QString::number(static_cast(child)->customId())); + + if (query_category.exec()) { + child->setId(query_category.lastInsertId().toInt()); + } + else { + // TODO: logovat + } + } + else if (child->kind() == RootItemKind::Feed) { + TtRssFeed *feed = static_cast(child); + + query_feed.bindValue(QSL(":title"), feed->title()); + query_feed.bindValue(QSL(":icon"), qApp->icons()->toByteArray(feed->icon())); + query_feed.bindValue(QSL(":category"), feed->parent()->id()); + query_feed.bindValue(QSL(":protected"), 0); + query_feed.bindValue(QSL(":update_type"), (int) feed->autoUpdateType()); + query_feed.bindValue(QSL(":update_interval"), feed->autoUpdateInitialInterval()); + query_feed.bindValue(QSL(":account_id"), accountId()); + query_feed.bindValue(QSL(":custom_id"), feed->customId()); + + if (query_feed.exec()) { + feed->setId(query_feed.lastInsertId().toInt()); + + // TODO: updatecounts; + } + else { + // TODO: logovat. + } + } + } } diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 00ba6446e..a549d1374 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -66,14 +66,18 @@ class TtRssServiceRoot : public ServiceRoot { TtRssNetworkFactory *network() const; - void saveToDatabase(); - void loadFromDatabase(); + void saveAccountDataToDatabase(); void updateTitle(); private slots: void syncIn(); private: + void removeOldFeedTree(); + void cleanAllItems(); + void storeNewFeedTree(RootItem *root); + void loadFromDatabase(); + QAction *m_actionSyncIn; QList m_serviceMenu; From 11dfe67b4a7a0bcfb9123ffa31d6edfbf5c414b1 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 8 Dec 2015 09:34:14 +0100 Subject: [PATCH 139/203] Account initial starting is now delayed after main form construction, better now. Also some more stuff. --- src/core/feedsmodel.cpp | 6 +++++- src/core/feedsmodel.h | 6 +++--- src/gui/feedmessageviewer.cpp | 2 -- src/main.cpp | 4 ++++ src/services/abstract/serviceroot.h | 4 ++-- src/services/tt-rss/ttrssserviceroot.cpp | 10 +++++++--- 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index b6040476e..6b4ee2a30 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -70,7 +70,7 @@ FeedsModel::FeedsModel(QObject *parent) connect(m_autoUpdateTimer, SIGNAL(timeout()), this, SLOT(executeNextAutoUpdate())); - loadActivatedServiceAccounts(); + //loadActivatedServiceAccounts(); updateAutoUpdateStatus(); if (qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::FeedsUpdateOnStartup)).toBool()) { @@ -82,6 +82,10 @@ FeedsModel::FeedsModel(QObject *parent) FeedsModel::~FeedsModel() { qDebug("Destroying FeedsModel instance."); + foreach (ServiceRoot *account, serviceRoots()) { + account->stop(); + } + // Delete all model items. delete m_rootItem; } diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 1e94efc93..b561aa506 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -151,6 +151,9 @@ class FeedsModel : public QAbstractItemModel { // Adds given service root account. bool addServiceAccount(ServiceRoot *root); + // Loads feed/categories from the database. + void loadActivatedServiceAccounts(); + public slots: // Checks if new parent node is different from one used by original node. // If it is, then it reassigns original_node to new parent. @@ -221,9 +224,6 @@ class FeedsModel : public QAbstractItemModel { // which are suitable as IN clause for SQL queries. QStringList textualFeedIds(const QList &feeds); - // Loads feed/categories from the database. - void loadActivatedServiceAccounts(); - RootItem *m_rootItem; QList m_headerData; QList m_tooltipData; diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 69a978993..c772e7548 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -103,8 +103,6 @@ void FeedMessageViewer::loadSize() { Settings *settings = qApp->settings(); int default_msg_section_size = m_messagesView->header()->defaultSectionSize(); - m_feedsView->loadExpandedStates(); - // Restore offsets of splitters. m_feedSplitter->restoreState(QByteArray::fromBase64(settings->value(GROUP(GUI), SETTING(GUI::SplitterFeeds)).toString().toLocal8Bit())); m_messageSplitter->restoreState(QByteArray::fromBase64(settings->value(GROUP(GUI), SETTING(GUI::SplitterMessages)).toString().toLocal8Bit())); diff --git a/src/main.cpp b/src/main.cpp index f78478c22..94736dd08 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -121,6 +121,10 @@ int main(int argc, char *argv[]) { QTimer::singleShot(STARTUP_UPDATE_DELAY, application.system(), SLOT(checkForUpdatesOnStartup())); } + // Load activated accounts. + qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->loadActivatedServiceAccounts(); + qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->loadExpandedStates(); + // Setup single-instance behavior. QObject::connect(&application, SIGNAL(messageReceived(QString)), &application, SLOT(processExecutionMessage(QString))); diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 30498fc73..ed0295daa 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -64,6 +64,8 @@ class ServiceRoot : public RootItem { // Start/stop services. // Start method is called when feed model gets initialized OR after user adds new service. + // Account should synchronously initialize its children (load them from DB is recommended + // here). // // Stop method is called just before application exits OR when // user explicitly deletes existing service instance. @@ -79,8 +81,6 @@ class ServiceRoot : public RootItem { // and then use method QSqlTableModel::setFilter(....). // NOTE: It would be more preferable if all messages are downloaded // right when feeds are updated. - // TODO: toto možná udělat asynchronně, zobrazit - // "loading" dialog přes view a toto zavolat, nasledně signalovat virtual bool loadMessagesForItem(RootItem *item, QSqlTableModel *model) = 0; // Called BEFORE this read status update (triggered by user in message list) is stored in DB, diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index bffdd96e0..0f6680779 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -20,6 +20,7 @@ #include "miscellaneous/application.h" #include "miscellaneous/settings.h" #include "gui/dialogs/formmain.h" +#include "network-web/networkfactory.h" #include "services/tt-rss/ttrssserviceentrypoint.h" #include "services/tt-rss/ttrssfeed.h" #include "services/tt-rss/ttrsscategory.h" @@ -44,16 +45,19 @@ TtRssServiceRoot::~TtRssServiceRoot() { } void TtRssServiceRoot::start() { - // TODO: posunout starty rootů až je okno uděláno loadFromDatabase(); - // TODO: pokud tady není nic načteno, tak - // syncIn + if (childCount() == 0) { + // TODO: pokud tady není nic načteno, tak + // syncIn + } } void TtRssServiceRoot::stop() { QNetworkReply::NetworkError error; m_network->logout(error); + + qDebug("Stopping Tiny Tiny RSS account, logging out with result '%d'.", (int) error); } QString TtRssServiceRoot::code() { From 04028ef6bb8bc41fb7796dc938f3ccceea6326fa Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 8 Dec 2015 09:58:05 +0100 Subject: [PATCH 140/203] Fixed expanding when importing, newer readme. --- README.md | 2 + src/gui/dialogs/formmain.cpp | 2 + .../standard/gui/formstandardimportexport.cpp | 1 + src/services/standard/standardserviceroot.cpp | 5 +- src/services/tt-rss/ttrssfeed.cpp | 46 ++++++++++++++++++- src/services/tt-rss/ttrssfeed.h | 11 +++++ src/services/tt-rss/ttrssserviceroot.cpp | 5 +- 7 files changed, 68 insertions(+), 4 deletions(-) mode change 100644 => 100755 src/services/tt-rss/ttrssfeed.cpp mode change 100644 => 100755 src/services/tt-rss/ttrssfeed.h diff --git a/README.md b/README.md index 716888781..b3cfb76d5 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,8 @@ RSS Guard is simple (yet powerful) feed reader. It is able to fetch the most kno RSS Guard is written in C++. It is pretty fast even with tons of messages loaded. The core features are: +* support for online feed synchronization via plugins, + * Tiny Tiny RSS (from RSS Guard 3.0.0). * multiplatformity, * support for all feed formats, * simplicity, diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index 278a791c8..ce207f599 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -80,6 +80,8 @@ FormMain::FormMain(QWidget *parent, Qt::WindowFlags f) setupIcons(); loadSize(); + statusBar()->setVisible(false); + // Initialize the web factory. WebFactory::instance()->loadState(); } diff --git a/src/services/standard/gui/formstandardimportexport.cpp b/src/services/standard/gui/formstandardimportexport.cpp index 9c10ac444..6e7f869cd 100755 --- a/src/services/standard/gui/formstandardimportexport.cpp +++ b/src/services/standard/gui/formstandardimportexport.cpp @@ -233,6 +233,7 @@ void FormStandardImportExport::importFeeds() { QString output_message; if (m_serviceRoot->mergeImportExportModel(m_model, output_message)) { + m_serviceRoot->requestItemExpand(m_serviceRoot->getSubTree(), true); m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, output_message, output_message); } else { diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index c261155f0..e86be599b 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -85,7 +85,10 @@ void StandardServiceRoot::start() { try { model.importAsOPML20(IOFactory::readTextFile(file_to_load)); model.checkAllItems(); - mergeImportExportModel(&model, output_msg); + + if (mergeImportExportModel(&model, output_msg)) { + requestItemExpand(getSubTree(), true); + } } catch (ApplicationException &ex) { MessageBox::show(qApp->mainForm(), QMessageBox::Critical, tr("Error when loading initial feeds"), ex.message()); diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp old mode 100644 new mode 100755 index 45d90dc31..5c8dc0810 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -18,14 +18,58 @@ #include "services/tt-rss/ttrssfeed.h" #include "definitions/definitions.h" +#include "miscellaneous/application.h" +#include "miscellaneous/databasefactory.h" +#include "services/tt-rss/ttrssserviceroot.h" + +#include -TtRssFeed::TtRssFeed(RootItem *parent) : Feed(parent), m_customId(NO_PARENT_CATEGORY) { +TtRssFeed::TtRssFeed(RootItem *parent) + : Feed(parent), m_customId(NO_PARENT_CATEGORY), m_totalCount(0), m_unreadCount(0) { } TtRssFeed::~TtRssFeed() { } +TtRssServiceRoot *TtRssFeed::serviceRoot() { + return qobject_cast(getParentServiceRoot()); +} + +void TtRssFeed::updateCounts(bool including_total_count) { + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + QSqlQuery query_all(database); + + query_all.setForwardOnly(true); + + if (including_total_count) { + if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE feed = '%1' AND is_deleted = 0 AND account_id = %2;").arg(QString::number(customId()), + QString::number(serviceRoot()->accountId()))) && query_all.next()) { + m_totalCount = query_all.value(0).toInt(); + } + } + + // Obtain count of unread messages. + if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE feed = '%1' AND is_deleted = 0 AND is_read = 0 AND account_id = %2;").arg(QString::number(customId()), + QString::number(serviceRoot()->accountId()))) && query_all.next()) { + int new_unread_count = query_all.value(0).toInt(); + + if (status() == NewMessages && new_unread_count < m_unreadCount) { + setStatus(Normal); + } + + m_unreadCount = new_unread_count; + } +} + +int TtRssFeed::countOfAllMessages() { + return m_totalCount; +} + +int TtRssFeed::countOfUnreadMessages() { + return m_unreadCount; +} + int TtRssFeed::update() { return 0; } diff --git a/src/services/tt-rss/ttrssfeed.h b/src/services/tt-rss/ttrssfeed.h old mode 100644 new mode 100755 index 314ad880d..a66335781 --- a/src/services/tt-rss/ttrssfeed.h +++ b/src/services/tt-rss/ttrssfeed.h @@ -21,11 +21,20 @@ #include "services/abstract/feed.h" +class TtRssServiceRoot; + class TtRssFeed : public Feed { public: explicit TtRssFeed(RootItem *parent = NULL); virtual ~TtRssFeed(); + TtRssServiceRoot *serviceRoot(); + + void updateCounts(bool including_total_count); + + int countOfAllMessages(); + int countOfUnreadMessages(); + int update(); QList undeletedMessages() const; @@ -34,6 +43,8 @@ class TtRssFeed : public Feed { private: int m_customId; + int m_totalCount; + int m_unreadCount; }; #endif // TTRSSFEED_H diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 0f6680779..50eeb2bd3 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -254,8 +254,11 @@ void TtRssServiceRoot::syncIn() { appendChild(top_level_item); } + updateCounts(true); + new_tree->clearChildren(); new_tree->deleteLater(); + itemChanged(QList() << this); requestFeedReadFilterReload(); requestReloadMessageList(true); @@ -322,8 +325,6 @@ void TtRssServiceRoot::storeNewFeedTree(RootItem *root) { if (query_feed.exec()) { feed->setId(query_feed.lastInsertId().toInt()); - - // TODO: updatecounts; } else { // TODO: logovat. From a66c9055fd5f1687eb3906ed3b8dfc66a2e86422 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 8 Dec 2015 09:59:51 +0100 Subject: [PATCH 141/203] README. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b3cfb76d5..6ec89a9b8 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ RSS Guard ========= Welcome to RSS Guard website. You can find here basic information. -RSS Guard is simple and easy-to-use RSS/ATOM feed aggregator developed using Qt framework. +RSS Guard is simple and easy-to-use RSS/ATOM feed aggregator developed using Qt framework which supports online feed synchronization. - - - Contacts @@ -66,7 +66,7 @@ RSS Guard is simple (yet powerful) feed reader. It is able to fetch the most kno RSS Guard is written in C++. It is pretty fast even with tons of messages loaded. The core features are: -* support for online feed synchronization via plugins, +* **support for online feed synchronization via plugins**, * Tiny Tiny RSS (from RSS Guard 3.0.0). * multiplatformity, * support for all feed formats, From cac3aee503c04744044b1cd928c3fa9887be41e4 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 8 Dec 2015 10:13:05 +0100 Subject: [PATCH 142/203] Added ability to hide status bar. --- resources/text/CHANGELOG | 1 + src/gui/dialogs/formmain.cpp | 13 ++++++------- src/gui/dialogs/formmain.h | 3 --- src/gui/dialogs/formmain.ui | 12 ++++++++++++ src/miscellaneous/settings.cpp | 3 +++ src/miscellaneous/settings.h | 3 +++ 6 files changed, 25 insertions(+), 10 deletions(-) diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 8718de143..1ad0bd8f0 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -18,6 +18,7 @@
                • Brand new "service plugin system" - HIGHLY EXPERIMENTAL and REWRITTEN from scratch. Expect bugs and misunderstandings now! Major parts of RSS Guard were completely rewritten. Note that some functionality might be TEMPORARILY removed.
                • Added ability to completely disable notifications (bug #128).
                • +
                • Added ability to hide status bar.
                • Added ability to go to next unread message. (partially bug #112)
                diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index ce207f599..94801af62 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -80,8 +80,6 @@ FormMain::FormMain(QWidget *parent, Qt::WindowFlags f) setupIcons(); loadSize(); - statusBar()->setVisible(false); - // Initialize the web factory. WebFactory::instance()->loadState(); } @@ -107,6 +105,7 @@ QList FormMain::allActions() { actions << m_ui->m_actionSwitchMainMenu; actions << m_ui->m_actionSwitchToolBars; actions << m_ui->m_actionSwitchListHeaders; + actions << m_ui->m_actionSwitchStatusBar; actions << m_ui->m_actionSwitchMessageListOrientation; // Add web browser actions @@ -174,10 +173,6 @@ void FormMain::switchFullscreenMode() { } } -void FormMain::switchMainMenu() { - m_ui->m_menuBar->setVisible(m_ui->m_actionSwitchMainMenu->isChecked()); -} - void FormMain::updateAddItemMenu() { // NOTE: Clear here deletes items from memory but only those OWNED by the menu. m_ui->m_menuAddItem->clear(); @@ -328,6 +323,7 @@ void FormMain::setupIcons() { m_ui->m_actionSwitchMainMenu->setIcon(icon_theme_factory->fromTheme(QSL("view-switch-menu"))); m_ui->m_actionSwitchToolBars->setIcon(icon_theme_factory->fromTheme(QSL("view-switch-list"))); m_ui->m_actionSwitchListHeaders->setIcon(icon_theme_factory->fromTheme(QSL("view-switch-list"))); + m_ui->m_actionSwitchStatusBar->setIcon(icon_theme_factory->fromTheme(QSL("dialog-information"))); m_ui->m_actionSwitchMessageListOrientation->setIcon(icon_theme_factory->fromTheme(QSL("view-switch-layout-direction"))); m_ui->m_menuShowHide->setIcon(icon_theme_factory->fromTheme(QSL("view-switch"))); @@ -410,6 +406,7 @@ void FormMain::loadSize() { m_ui->m_tabWidget->feedMessageViewer()->loadSize(); m_ui->m_actionSwitchToolBars->setChecked(settings->value(GROUP(GUI), SETTING(GUI::ToolbarsVisible)).toBool()); m_ui->m_actionSwitchListHeaders->setChecked(settings->value(GROUP(GUI), SETTING(GUI::ListHeadersVisible)).toBool()); + m_ui->m_actionSwitchStatusBar->setChecked(settings->value(GROUP(GUI), SETTING(GUI::StatusBarVisible)).toBool()); // Make sure that only unread feeds are shown if user has that feature set on. m_ui->m_actionShowOnlyUnreadItems->setChecked(settings->value(GROUP(Feeds), SETTING(Feeds::ShowOnlyUnreadFeeds)).toBool()); @@ -433,6 +430,7 @@ void FormMain::saveSize() { settings->setValue(GROUP(GUI), GUI::MainWindowInitialSize, size()); settings->setValue(GROUP(GUI), GUI::MainWindowStartsMaximized, is_maximized); settings->setValue(GROUP(GUI), GUI::MainWindowStartsFullscreen, is_fullscreen); + settings->setValue(GROUP(GUI), GUI::StatusBarVisible, m_ui->m_actionSwitchStatusBar->isChecked()); m_ui->m_tabWidget->feedMessageViewer()->saveSize(); } @@ -454,8 +452,9 @@ void FormMain::createConnections() { // Menu "View" connections. connect(m_ui->m_actionFullscreen, SIGNAL(toggled(bool)), this, SLOT(switchFullscreenMode())); - connect(m_ui->m_actionSwitchMainMenu, SIGNAL(toggled(bool)), this, SLOT(switchMainMenu())); + connect(m_ui->m_actionSwitchMainMenu, SIGNAL(toggled(bool)), m_ui->m_menuBar, SLOT(setVisible(bool))); connect(m_ui->m_actionSwitchMainWindow, SIGNAL(triggered()), this, SLOT(switchVisibility())); + connect(m_ui->m_actionSwitchStatusBar, SIGNAL(toggled(bool)), statusBar(), SLOT(setVisible(bool))); // Menu "Tools" connections. connect(m_ui->m_actionSettings, SIGNAL(triggered()), this, SLOT(showSettings())); diff --git a/src/gui/dialogs/formmain.h b/src/gui/dialogs/formmain.h index 1320a832f..140d9ad79 100755 --- a/src/gui/dialogs/formmain.h +++ b/src/gui/dialogs/formmain.h @@ -73,9 +73,6 @@ class FormMain : public QMainWindow { // Turns on/off fullscreen mode void switchFullscreenMode(); - // Switches visibility of main menu. - void switchMainMenu(); - private slots: void updateAddItemMenu(); void updateRecycleBinMenu(); diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index fe4f645ce..b392a808b 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -85,6 +85,7 @@ + @@ -742,6 +743,17 @@ + + + true + + + true + + + Status bar + + diff --git a/src/miscellaneous/settings.cpp b/src/miscellaneous/settings.cpp index bc040936e..bf1179f07 100755 --- a/src/miscellaneous/settings.cpp +++ b/src/miscellaneous/settings.cpp @@ -105,6 +105,9 @@ DVALUE(bool) GUI::ToolbarsVisibleDef = true; DKEY GUI::ListHeadersVisible = "enable_list_headers"; DVALUE(bool) GUI::ListHeadersVisibleDef = true; +DKEY GUI::StatusBarVisible = "enable_status_bar"; +DVALUE(bool) GUI::StatusBarVisibleDef = true; + DKEY GUI::HideMainWindowWhenMinimized = "hide_when_minimized"; DVALUE(bool) GUI::HideMainWindowWhenMinimizedDef = false; diff --git a/src/miscellaneous/settings.h b/src/miscellaneous/settings.h index b3a977520..35746dd5b 100755 --- a/src/miscellaneous/settings.h +++ b/src/miscellaneous/settings.h @@ -120,6 +120,9 @@ namespace GUI { KEY ListHeadersVisible; VALUE(bool) ListHeadersVisibleDef; + KEY StatusBarVisible; + VALUE(bool) StatusBarVisibleDef; + KEY HideMainWindowWhenMinimized; VALUE(bool) HideMainWindowWhenMinimizedDef; From c4a8497471315608e80e98b22048a25c4c06bc63 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 8 Dec 2015 10:55:03 +0100 Subject: [PATCH 143/203] Refactored assembling methods, TT-RSS is now able to load stored feeds. --- src/core/rootitem.cpp | 20 +++++++ src/core/rootitem.h | 1 + src/gui/dialogs/formmain.ui | 3 ++ src/services/abstract/serviceroot.cpp | 45 ++++++++++++++++ src/services/abstract/serviceroot.h | 9 ++++ src/services/standard/standardfeed.cpp | 3 +- src/services/standard/standardserviceroot.cpp | 54 +++---------------- src/services/standard/standardserviceroot.h | 11 ---- src/services/tt-rss/ttrsscategory.cpp | 11 ++++ src/services/tt-rss/ttrsscategory.h | 3 ++ src/services/tt-rss/ttrssfeed.cpp | 10 ++++ src/services/tt-rss/ttrssfeed.h | 3 ++ src/services/tt-rss/ttrssserviceroot.cpp | 43 +++++++++++++++ src/services/tt-rss/ttrssserviceroot.h | 2 + 14 files changed, 157 insertions(+), 61 deletions(-) mode change 100644 => 100755 src/services/tt-rss/ttrsscategory.cpp mode change 100644 => 100755 src/services/tt-rss/ttrsscategory.h diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index 879ad8839..60f7482ed 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -281,6 +281,26 @@ QList RootItem::getSubTreeCategories() { return children; } +QHash RootItem::getHashedSubTreeCategories() { + QHash children; + QList traversable_items; + + traversable_items.append(this); + + // Iterate all nested items. + while (!traversable_items.isEmpty()) { + RootItem *active_item = traversable_items.takeFirst(); + + if (active_item->kind() == RootItemKind::Category && !children.contains(active_item->id())) { + children.insert(active_item->id(), active_item->toCategory()); + } + + traversable_items.append(active_item->childItems()); + } + + return children; +} + QList RootItem::getSubTreeFeeds() { QList children; QList traversable_items; diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 800bbc3cf..9ad382c32 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -177,6 +177,7 @@ class RootItem : public QObject { QList getSubTree(); QList getSubTree(RootItemKind::Kind kind_of_item); QList getSubTreeCategories(); + QHash getHashedSubTreeCategories(); QList getSubTreeFeeds(); // Returns the service root node which is direct or indirect parent of current item. diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index b392a808b..7e9a1ef3c 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -753,6 +753,9 @@ Status bar + + + diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index cd25632b1..c3c9413a3 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -19,6 +19,7 @@ #include "core/feedsmodel.h" #include "miscellaneous/application.h" +#include "services/abstract/category.h" #include @@ -89,3 +90,47 @@ int ServiceRoot::accountId() const { void ServiceRoot::setAccountId(int account_id) { m_accountId = account_id; } + +void ServiceRoot::assembleFeeds(Assignment feeds) { + QHash categories = getHashedSubTreeCategories(); + + foreach (const AssignmentItem &feed, feeds) { + if (feed.first == NO_PARENT_CATEGORY) { + // This is top-level feed, add it to the root item. + appendChild(feed.second); + feed.second->updateCounts(true); + } + else if (categories.contains(feed.first)) { + // This feed belongs to this category. + categories.value(feed.first)->appendChild(feed.second); + feed.second->updateCounts(true); + } + else { + qWarning("Feed '%s' is loose, skipping it.", qPrintable(feed.second->title())); + } + } +} + +void ServiceRoot::assembleCategories(Assignment categories) { + QHash assignments; + assignments.insert(NO_PARENT_CATEGORY, this); + + // Add top-level categories. + while (!categories.isEmpty()) { + for (int i = 0; i < categories.size(); i++) { + if (assignments.contains(categories.at(i).first)) { + // Parent category of this category is already added. + assignments.value(categories.at(i).first)->appendChild(categories.at(i).second); + + // Now, added category can be parent for another categories, add it. + assignments.insert(categories.at(i).second->id(), categories.at(i).second); + + // Remove the category from the list, because it was + // added to the final collection. + categories.removeAt(i); + i--; + } + } + } +} + diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index ed0295daa..aca550619 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -30,6 +30,10 @@ class RecycleBin; class QAction; class QSqlTableModel; +// Car here represents ID of the item. +typedef QList > Assignment; +typedef QPair AssignmentItem; + // THIS IS the root node of the service. // NOTE: The root usually contains some core functionality of the // service like service account username/password etc. @@ -149,6 +153,11 @@ class ServiceRoot : public RootItem { int accountId() const; void setAccountId(int account_id); + protected: + // Takes lists of feeds/categories and assembles them into the tree structure. + void assembleCategories(Assignment categories); + void assembleFeeds(Assignment feeds); + signals: // Emitted if data in any item belonging to this root are changed. void dataChanged(QList items); diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index a0f4332f3..0b22d15a9 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -763,7 +763,6 @@ QNetworkReply::NetworkError StandardFeed::networkError() const { } StandardFeed::StandardFeed(const QSqlRecord &record) : Feed(NULL) { - setKind(RootItemKind::Feed); setTitle(record.value(FDS_DB_TITLE_INDEX).toString()); setId(record.value(FDS_DB_ID_INDEX).toInt()); setDescription(record.value(FDS_DB_DESCRIPTION_INDEX).toString()); @@ -782,6 +781,6 @@ StandardFeed::StandardFeed(const QSqlRecord &record) : Feed(NULL) { } - setAutoUpdateType(static_cast(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt())); + setAutoUpdateType(static_cast(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt())); setAutoUpdateInitialInterval(record.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt()); } diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index e86be599b..6a6c44884 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -331,8 +331,8 @@ bool StandardServiceRoot::emptyBin() { void StandardServiceRoot::loadFromDatabase(){ QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); - CategoryAssignment categories; - FeedAssignment feeds; + Assignment categories; + Assignment feeds; // Obtain data for categories from the database. QSqlQuery query_categories(database); @@ -344,7 +344,7 @@ void StandardServiceRoot::loadFromDatabase(){ } while (query_categories.next()) { - CategoryAssignmentItem pair; + AssignmentItem pair; pair.first = query_categories.value(CAT_DB_PARENT_ID_INDEX).toInt(); pair.second = new StandardCategory(query_categories.record()); @@ -369,10 +369,10 @@ void StandardServiceRoot::loadFromDatabase(){ case StandardFeed::Rdf: case StandardFeed::Rss0X: case StandardFeed::Rss2X: { - FeedAssignmentItem pair; + AssignmentItem pair; pair.first = query_feeds.value(FDS_DB_CATEGORY_INDEX).toInt(); pair.second = new StandardFeed(query_feeds.record()); - pair.second->setType(type); + qobject_cast(pair.second)->setType(type); feeds << pair; break; @@ -419,6 +419,7 @@ QHash StandardServiceRoot::categoriesForItem(RootItem *ro } QHash StandardServiceRoot::allCategories() { + // TODO: změnit na qlist, použít getsubtree možná return categoriesForItem(this); } @@ -436,26 +437,6 @@ QList StandardServiceRoot::getContextMenuForFeed(StandardFeed *feed) { return m_feedContextMenu; } -void StandardServiceRoot::assembleFeeds(FeedAssignment feeds) { - QHash categories = categoriesForItem(this); - - foreach (const FeedAssignmentItem &feed, feeds) { - if (feed.first == NO_PARENT_CATEGORY) { - // This is top-level feed, add it to the root item. - appendChild(feed.second); - feed.second->updateCounts(true); - } - else if (categories.contains(feed.first)) { - // This feed belongs to this category. - categories.value(feed.first)->appendChild(feed.second); - feed.second->updateCounts(true); - } - else { - qWarning("Feed '%s' is loose, skipping it.", qPrintable(feed.second->title())); - } - } -} - bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, QString &output_message) { QStack original_parents; original_parents.push(this); QStack new_parents; new_parents.push(model->rootItem()); @@ -696,26 +677,3 @@ bool StandardServiceRoot::onAfterMessagesRestoredFromBin(RootItem *selected_item requestFeedReadFilterReload(); return true; } - -void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { - QHash assignments; - assignments.insert(NO_PARENT_CATEGORY, this); - - // Add top-level categories. - while (!categories.isEmpty()) { - for (int i = 0; i < categories.size(); i++) { - if (assignments.contains(categories.at(i).first)) { - // Parent category of this category is already added. - assignments.value(categories.at(i).first)->appendChild(categories.at(i).second); - - // Now, added category can be parent for another categories, add it. - assignments.insert(categories.at(i).second->id(), categories.at(i).second); - - // Remove the category from the list, because it was - // added to the final collection. - categories.removeAt(i); - i--; - } - } - } -} diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 1a54f7b02..55552ff54 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -30,12 +30,6 @@ class StandardFeed; class FeedsImportExportModel; class QMenu; -typedef QList > CategoryAssignment; -typedef QPair CategoryAssignmentItem; - -typedef QList > FeedAssignment; -typedef QPair FeedAssignmentItem; - class StandardServiceRoot : public ServiceRoot { Q_OBJECT @@ -117,11 +111,6 @@ class StandardServiceRoot : public ServiceRoot { // which are suitable as IN clause for SQL queries. QStringList textualFeedIds(const QList &feeds); - // Takes lists of feeds/categories and assembles - // them into the tree structure. - void assembleCategories(CategoryAssignment categories); - void assembleFeeds(FeedAssignment feeds); - StandardRecycleBin *m_recycleBin; // Menus. diff --git a/src/services/tt-rss/ttrsscategory.cpp b/src/services/tt-rss/ttrsscategory.cpp old mode 100644 new mode 100755 index 7b485288e..9334a347d --- a/src/services/tt-rss/ttrsscategory.cpp +++ b/src/services/tt-rss/ttrsscategory.cpp @@ -18,11 +18,22 @@ #include "services/tt-rss/ttrsscategory.h" #include "definitions/definitions.h" +#include "miscellaneous/application.h" +#include "miscellaneous/iconfactory.h" + +#include TtRssCategory::TtRssCategory(RootItem *parent) : Category(parent), m_customId(NO_PARENT_CATEGORY) { } +TtRssCategory::TtRssCategory(const QSqlRecord &record) : Category(NULL) { + setId(record.value(CAT_DB_ID_INDEX).toInt()); + setTitle(record.value(CAT_DB_TITLE_INDEX).toString()); + setIcon(qApp->icons()->fromByteArray(record.value(CAT_DB_ICON_INDEX).toByteArray())); + setCustomId(record.value(CAT_DB_CUSTOM_ID_INDEX).toInt()); +} + TtRssCategory::~TtRssCategory() { } diff --git a/src/services/tt-rss/ttrsscategory.h b/src/services/tt-rss/ttrsscategory.h old mode 100644 new mode 100755 index fb7df9a24..c029d3435 --- a/src/services/tt-rss/ttrsscategory.h +++ b/src/services/tt-rss/ttrsscategory.h @@ -20,10 +20,13 @@ #include "services/abstract/category.h" +#include + class TtRssCategory : public Category { public: explicit TtRssCategory(RootItem *parent = NULL); + explicit TtRssCategory(const QSqlRecord &record); virtual ~TtRssCategory(); int customId() const; diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index 5c8dc0810..f45cd427f 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -20,6 +20,7 @@ #include "definitions/definitions.h" #include "miscellaneous/application.h" #include "miscellaneous/databasefactory.h" +#include "miscellaneous/iconfactory.h" #include "services/tt-rss/ttrssserviceroot.h" #include @@ -29,6 +30,15 @@ TtRssFeed::TtRssFeed(RootItem *parent) : Feed(parent), m_customId(NO_PARENT_CATEGORY), m_totalCount(0), m_unreadCount(0) { } +TtRssFeed::TtRssFeed(const QSqlRecord &record) : Feed(NULL), m_totalCount(0), m_unreadCount(0) { + setTitle(record.value(FDS_DB_TITLE_INDEX).toString()); + setId(record.value(FDS_DB_ID_INDEX).toInt()); + setIcon(qApp->icons()->fromByteArray(record.value(FDS_DB_ICON_INDEX).toByteArray())); + setAutoUpdateType(static_cast(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt())); + setAutoUpdateInitialInterval(record.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt()); + setCustomId(record.value(FDS_DB_CUSTOM_ID_INDEX).toInt()); +} + TtRssFeed::~TtRssFeed() { } diff --git a/src/services/tt-rss/ttrssfeed.h b/src/services/tt-rss/ttrssfeed.h index a66335781..a934f9743 100755 --- a/src/services/tt-rss/ttrssfeed.h +++ b/src/services/tt-rss/ttrssfeed.h @@ -20,12 +20,15 @@ #include "services/abstract/feed.h" +#include + class TtRssServiceRoot; class TtRssFeed : public Feed { public: explicit TtRssFeed(RootItem *parent = NULL); + explicit TtRssFeed(const QSqlRecord &record); virtual ~TtRssFeed(); TtRssServiceRoot *serviceRoot(); diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 50eeb2bd3..32882d7c6 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -30,6 +30,7 @@ #include #include #include +#include TtRssServiceRoot::TtRssServiceRoot(RootItem *parent) @@ -220,6 +221,48 @@ void TtRssServiceRoot::saveAccountDataToDatabase() { void TtRssServiceRoot::loadFromDatabase() { // TODO: Load feeds/categories from DB. + + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + Assignment categories; + Assignment feeds; + + // Obtain data for categories from the database. + QSqlQuery query_categories(database); + query_categories.setForwardOnly(true); + + if (!query_categories.exec(QString("SELECT * FROM Categories WHERE account_id = %1;").arg(accountId())) || query_categories.lastError().isValid()) { + qFatal("Query for obtaining categories failed. Error message: '%s'.", + qPrintable(query_categories.lastError().text())); + } + + while (query_categories.next()) { + AssignmentItem pair; + pair.first = query_categories.value(CAT_DB_PARENT_ID_INDEX).toInt(); + pair.second = new TtRssCategory(query_categories.record()); + + categories << pair; + } + + // All categories are now loaded. + QSqlQuery query_feeds(database); + query_feeds.setForwardOnly(true); + + if (!query_feeds.exec(QString("SELECT * FROM Feeds WHERE account_id = %1;").arg(accountId())) || query_feeds.lastError().isValid()) { + qFatal("Query for obtaining feeds failed. Error message: '%s'.", + qPrintable(query_feeds.lastError().text())); + } + + while (query_feeds.next()) { + AssignmentItem pair; + pair.first = query_feeds.value(FDS_DB_CATEGORY_INDEX).toInt(); + pair.second = new TtRssFeed(query_feeds.record()); + + feeds << pair; + } + + // All data are now obtained, lets create the hierarchy. + assembleCategories(categories); + assembleFeeds(feeds); } void TtRssServiceRoot::updateTitle() { diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index a549d1374..5ff7cffb6 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -23,6 +23,8 @@ #include +class TtRssCategory; +class TtRssFeed; class TtRssNetworkFactory; class TtRssServiceRoot : public ServiceRoot { From 523adcf4b7d39d93544dec3a900262658620d4b3 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 8 Dec 2015 11:00:43 +0100 Subject: [PATCH 144/203] Fixed icons. --- src/services/tt-rss/network/ttrssnetworkfactory.cpp | 1 - src/services/tt-rss/ttrsscategory.cpp | 3 ++- src/services/tt-rss/ttrssfeed.cpp | 1 + src/services/tt-rss/ttrssserviceroot.cpp | 6 +----- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index 5915f545e..5dcfb7b8b 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -253,7 +253,6 @@ RootItem *TtRssGetFeedsCategoriesResponse::feedsCategories(bool obtain_icons, QS else { TtRssCategory *category = new TtRssCategory(); - category->setIcon(qApp->icons()->fromTheme(QSL("folder-category"))); category->setTitle(item["name"].toString()); category->setCustomId(item_id); act_parent->appendChild(category); diff --git a/src/services/tt-rss/ttrsscategory.cpp b/src/services/tt-rss/ttrsscategory.cpp index 9334a347d..7dc127ea6 100755 --- a/src/services/tt-rss/ttrsscategory.cpp +++ b/src/services/tt-rss/ttrsscategory.cpp @@ -25,12 +25,13 @@ TtRssCategory::TtRssCategory(RootItem *parent) : Category(parent), m_customId(NO_PARENT_CATEGORY) { + setIcon(qApp->icons()->fromTheme(QSL("folder-category"))); } TtRssCategory::TtRssCategory(const QSqlRecord &record) : Category(NULL) { + setIcon(qApp->icons()->fromTheme(QSL("folder-category"))); setId(record.value(CAT_DB_ID_INDEX).toInt()); setTitle(record.value(CAT_DB_TITLE_INDEX).toString()); - setIcon(qApp->icons()->fromByteArray(record.value(CAT_DB_ICON_INDEX).toByteArray())); setCustomId(record.value(CAT_DB_CUSTOM_ID_INDEX).toInt()); } diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index f45cd427f..9b6916c86 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -81,6 +81,7 @@ int TtRssFeed::countOfUnreadMessages() { } int TtRssFeed::update() { + // TODO: přes getHeadlines provede stažení kompletnich zprav. return 0; } diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 32882d7c6..532610aa7 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -49,8 +49,7 @@ void TtRssServiceRoot::start() { loadFromDatabase(); if (childCount() == 0) { - // TODO: pokud tady není nic načteno, tak - // syncIn + syncIn(); } } @@ -276,9 +275,6 @@ void TtRssServiceRoot::updateTitle() { } void TtRssServiceRoot::syncIn() { - // TODO: provede stažení kanálů/kategorií - // ze serveru, a sloučení s aktuálními - // neprovádí aktualizace kanálů ani stažení počtu nepřečtených zpráv QNetworkReply::NetworkError err; TtRssGetFeedsCategoriesResponse feed_cats_response = m_network->getFeedsCategories(err); From eb1eef3a504afe4ebe185816fc5242a4d489b28a Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 8 Dec 2015 11:13:35 +0100 Subject: [PATCH 145/203] Added ability to load messages. --- src/services/tt-rss/ttrssserviceroot.cpp | 20 +++++++++++++++++++- src/services/tt-rss/ttrssserviceroot.h | 4 ++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 532610aa7..5ac50a600 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -27,6 +27,7 @@ #include "services/tt-rss/network/ttrssnetworkfactory.h" #include "services/tt-rss/gui/formeditaccount.h" +#include #include #include #include @@ -118,7 +119,13 @@ RecycleBin *TtRssServiceRoot::recycleBin() { } bool TtRssServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *model) { - return false; + QList children = item->getSubTreeFeeds(); + QString filter_clause = textualFeedIds(children).join(QSL(", ")); + + model->setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0")).arg(filter_clause)); + qDebug("Loading messages from feeds: %s.", qPrintable(filter_clause)); + + return true; } QList TtRssServiceRoot::serviceMenu() { @@ -305,6 +312,17 @@ void TtRssServiceRoot::syncIn() { } } +QStringList TtRssServiceRoot::textualFeedIds(const QList &feeds) { + QStringList stringy_ids; + stringy_ids.reserve(feeds.size()); + + foreach (Feed *feed, feeds) { + stringy_ids.append(QString("'%1'").arg(QString::number(static_cast(feed)->customId()))); + } + + return stringy_ids; +} + void TtRssServiceRoot::removeOldFeedTree() { QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query(database); diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 5ff7cffb6..56519886f 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -75,6 +75,10 @@ class TtRssServiceRoot : public ServiceRoot { void syncIn(); private: + // Returns converted ids of given feeds + // which are suitable as IN clause for SQL queries. + QStringList textualFeedIds(const QList &feeds); + void removeOldFeedTree(); void cleanAllItems(); void storeNewFeedTree(RootItem *root); From c9bb406a509cd88f0a46be20ff2f27656fdef85a Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 8 Dec 2015 12:12:39 +0100 Subject: [PATCH 146/203] Added undeletedMessages() implementation. --- src/services/standard/standardfeed.cpp | 3 ++- src/services/tt-rss/ttrssfeed.cpp | 33 +++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 0b22d15a9..c7ea6fecc 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -135,7 +135,7 @@ QList StandardFeed::undeletedMessages() const { QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query_read_msg(database); query_read_msg.setForwardOnly(true); - query_read_msg.prepare("SELECT title, url, author, date_created, contents " + query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures " "FROM Messages " "WHERE is_deleted = 0 AND feed = :feed AND account_id = :account_id;"); @@ -154,6 +154,7 @@ QList StandardFeed::undeletedMessages() const { message.m_author = query_read_msg.value(2).toString(); message.m_created = TextFactory::parseDateTime(query_read_msg.value(3).value()); message.m_contents = query_read_msg.value(4).toString(); + message.m_enclosures = Enclosures::decodeEnclosuresFromString(query_read_msg.value(5).toString()); messages.append(message); } diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index 9b6916c86..849b67ace 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -21,6 +21,7 @@ #include "miscellaneous/application.h" #include "miscellaneous/databasefactory.h" #include "miscellaneous/iconfactory.h" +#include "miscellaneous/textfactory.h" #include "services/tt-rss/ttrssserviceroot.h" #include @@ -86,7 +87,37 @@ int TtRssFeed::update() { } QList TtRssFeed::undeletedMessages() const { - return QList(); + QList messages; + int account_id = const_cast(this)->serviceRoot()->accountId(); + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + QSqlQuery query_read_msg(database); + query_read_msg.setForwardOnly(true); + query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures " + "FROM Messages " + "WHERE is_deleted = 0 AND feed = :feed AND account_id = :account_id;"); + + query_read_msg.bindValue(QSL(":feed"), id()); + query_read_msg.bindValue(QSL(":account_id"), account_id); + + // FIXME: Fix those const functions, this is fucking ugly. + + if (query_read_msg.exec()) { + while (query_read_msg.next()) { + Message message; + + message.m_feedId = account_id; + message.m_title = query_read_msg.value(0).toString(); + message.m_url = query_read_msg.value(1).toString(); + message.m_author = query_read_msg.value(2).toString(); + message.m_created = TextFactory::parseDateTime(query_read_msg.value(3).value()); + message.m_contents = query_read_msg.value(4).toString(); + message.m_enclosures = Enclosures::decodeEnclosuresFromString(query_read_msg.value(5).toString()); + + messages.append(message); + } + } + + return messages; } int TtRssFeed::customId() const { From 34e2f702190b1c58389f01e329f08bf557e43e25 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 8 Dec 2015 13:37:26 +0100 Subject: [PATCH 147/203] Working on TT-RSS messages obtaining. --- src/core/message.cpp | 4 +- src/core/message.h | 5 +- src/core/messagesmodel.cpp | 3 +- src/services/abstract/feed.h | 1 + src/services/tt-rss/definitions.h | 3 + .../tt-rss/network/ttrssnetworkfactory.cpp | 75 +++++++++++++++++++ .../tt-rss/network/ttrssnetworkfactory.h | 15 ++++ src/services/tt-rss/ttrssfeed.cpp | 36 ++++++++- src/services/tt-rss/ttrssfeed.h | 2 + 9 files changed, 137 insertions(+), 7 deletions(-) diff --git a/src/core/message.cpp b/src/core/message.cpp index 0338a5477..6c8833400 100755 --- a/src/core/message.cpp +++ b/src/core/message.cpp @@ -61,7 +61,7 @@ QString Enclosures::encodeEnclosuresToString(const QList &enclosures) } Message::Message() { - m_title = m_url = m_author = m_contents = m_customId = ""; - m_feedId = 0; + m_title = m_url = m_author = m_contents = m_feedId = m_customId = ""; m_enclosures = QList(); + m_isImportant = m_isImportant = false; } diff --git a/src/core/message.h b/src/core/message.h index f0cd4ab3b..eab142d15 100755 --- a/src/core/message.h +++ b/src/core/message.h @@ -49,9 +49,12 @@ class Message { QString m_author; QString m_contents; QDateTime m_created; - int m_feedId; + QString m_feedId; QString m_customId; + bool m_isRead; + bool m_isImportant; + QList m_enclosures; // Is true if "created" date was obtained directly diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 62af8ae12..ba0968bbe 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -139,7 +139,8 @@ Message MessagesModel::messageAt(int row_index) const { message.m_enclosures = Enclosures::decodeEnclosuresFromString(rec.value(MSG_DB_ENCLOSURES_INDEX).toString()); message.m_title = rec.value(MSG_DB_TITLE_INDEX).toString(); message.m_url = rec.value(MSG_DB_URL_INDEX).toString(); - message.m_feedId = rec.value(MSG_DB_FEED_INDEX).toInt(); + message.m_feedId = rec.value(MSG_DB_FEED_INDEX).toString(); + message.m_customId = rec.value(MSG_DB_CUSTOM_ID_INDEX).toString(); message.m_created = TextFactory::parseDateTime(rec.value(MSG_DB_DCREATED_INDEX).value()).toLocalTime(); return message; diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index 0ab9671e5..aaed9266a 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -55,6 +55,7 @@ class Feed : public RootItem { ///////////////////////////////////////// // Performs synchronous update and returns number of newly updated messages. + // NOTE: This is called from worker thread, not from main UI thread. // NOTE: This should COMPLETELY download ALL messages from online source // into locale "Messages" table, INCLUDING contents (or excerpts) of those // messages. diff --git a/src/services/tt-rss/definitions.h b/src/services/tt-rss/definitions.h index 6aae31bea..391188c76 100755 --- a/src/services/tt-rss/definitions.h +++ b/src/services/tt-rss/definitions.h @@ -11,6 +11,9 @@ #define UNKNOWN_METHOD "UNKNOWN_METHOD" // Given "op" is not recognized. #define INCORRECT_USAGE "INCORRECT_USAGE" // Given "op" was used with bad parameters. +// Limitations +#define MAX_MESSAGES 200 + // General return status codes. #define API_STATUS_OK 0 #define API_STATUS_ERR 1 diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index 5dcfb7b8b..4d5c8ec03 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -24,6 +24,7 @@ #include "services/tt-rss/ttrsscategory.h" #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" +#include "miscellaneous/textfactory.h" #include "network-web/networkfactory.h" #include @@ -133,6 +134,37 @@ TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories(QNetwork return result; } +TtRssGetHeadlinesResponse TtRssNetworkFactory::getHeadlines(int feed_id, bool force_update, int limit, int skip, + bool show_content, bool include_attachments, + bool sanitize, QNetworkReply::NetworkError &error) { + QtJson::JsonObject json; + json["op"] = "getHeadlines"; + json["sid"] = m_sessionId; + json["feed_id"] = feed_id; + json["force_update"] = force_update; + json["limit"] = limit; + json["skip"] = skip; + json["show_content"] = show_content; + json["include_attachments"] = include_attachments; + json["sanitize"] = sanitize; + + QByteArray result_raw; + NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + TtRssGetHeadlinesResponse result(QString::fromUtf8(result_raw)); + + if (result.isNotLoggedIn()) { + // We are not logged in. + login(error); + json["sid"] = m_sessionId; + + network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + result = TtRssGetHeadlinesResponse(QString::fromUtf8(result_raw)); + } + + error = network_reply.first; + return result; +} + TtRssResponse::TtRssResponse(const QString &raw_content) { m_rawContent = QtJson::parse(raw_content).toMap(); } @@ -296,3 +328,46 @@ RootItem *TtRssGetFeedsCategoriesResponse::feedsCategories(bool obtain_icons, QS return parent; } + + +TtRssGetHeadlinesResponse::TtRssGetHeadlinesResponse(const QString &raw_content) : TtRssResponse(raw_content) { +} + +TtRssGetHeadlinesResponse::~TtRssGetHeadlinesResponse() { +} + +QList TtRssGetHeadlinesResponse::messages() { + QList messages; + + foreach (QVariant item, m_rawContent["content"].toList()) { + QMap mapped = item.toMap(); + Message message; + + message.m_author = mapped["author"].toString(); + message.m_isRead = !mapped["unread"].toBool(); + message.m_isImportant = mapped["marked"].toBool(); + message.m_contents = mapped["content"].toString(); + message.m_created = TextFactory::parseDateTime(mapped["updated"].value()); + message.m_createdFromFeed = true; + message.m_customId = mapped["id"].toString(); + message.m_feedId = mapped["feed_id"].toString(); + message.m_title = mapped["title"].toString(); + message.m_url = mapped["link"].toString(); + + if (mapped.contains(QSL("attachments"))) { + // Process enclosures. + foreach (QVariant attachment, mapped["attachments"].toList()) { + QMap mapped_attachemnt = attachment.toMap(); + Enclosure enclosure; + + enclosure.m_mimeType = mapped_attachemnt["content_type"].toString(); + enclosure.m_url = mapped_attachemnt["content_url"].toString(); + message.m_enclosures.append(enclosure); + } + } + + messages.append(message); + } + + return messages; +} diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.h b/src/services/tt-rss/network/ttrssnetworkfactory.h index 8e76f3b09..8d9374f20 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.h +++ b/src/services/tt-rss/network/ttrssnetworkfactory.h @@ -20,6 +20,8 @@ #include "qt-json/json.h" +#include "core/message.h" + #include #include #include @@ -64,6 +66,14 @@ class TtRssGetFeedsCategoriesResponse : public TtRssResponse { RootItem *feedsCategories(bool obtain_icons, QString base_address = QString()); }; +class TtRssGetHeadlinesResponse : public TtRssResponse { + public: + explicit TtRssGetHeadlinesResponse(const QString &raw_content = QString()); + virtual ~TtRssGetHeadlinesResponse(); + + QList messages(); +}; + class TtRssNetworkFactory { public: explicit TtRssNetworkFactory(); @@ -89,6 +99,11 @@ class TtRssNetworkFactory { // Gets feeds from the server. TtRssGetFeedsCategoriesResponse getFeedsCategories(QNetworkReply::NetworkError &error); + // Gets headlines (messages) from the server. + TtRssGetHeadlinesResponse getHeadlines(int feed_id, bool force_update, int limit, int skip, + bool show_content, bool include_attachments, + bool sanitize, QNetworkReply::NetworkError &error); + private: QString m_url; QString m_username; diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index 849b67ace..7a8c64383 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -22,7 +22,9 @@ #include "miscellaneous/databasefactory.h" #include "miscellaneous/iconfactory.h" #include "miscellaneous/textfactory.h" +#include "services/tt-rss/definitions.h" #include "services/tt-rss/ttrssserviceroot.h" +#include "services/tt-rss/network/ttrssnetworkfactory.h" #include @@ -83,7 +85,30 @@ int TtRssFeed::countOfUnreadMessages() { int TtRssFeed::update() { // TODO: přes getHeadlines provede stažení kompletnich zprav. - return 0; + QNetworkReply::NetworkError error; + QList messages; + int newly_added_messages = 0; + int limit = MAX_MESSAGES; + int skip = 0; + + do { + TtRssGetHeadlinesResponse headlines = serviceRoot()->network()->getHeadlines(customId(), true, limit, skip, + true, true, false, error); + + if (error != QNetworkReply::NoError) { + setStatus(Feed::NetworkError); + return 0; + } + else { + QList new_messages = headlines.messages(); + + messages.append(new_messages); + skip += new_messages.size(); + } + } + while (newly_added_messages > 0); + + return updateMessages(messages); } QList TtRssFeed::undeletedMessages() const { @@ -92,7 +117,7 @@ QList TtRssFeed::undeletedMessages() const { QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query_read_msg(database); query_read_msg.setForwardOnly(true); - query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures " + query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures, custom_id " "FROM Messages " "WHERE is_deleted = 0 AND feed = :feed AND account_id = :account_id;"); @@ -105,13 +130,14 @@ QList TtRssFeed::undeletedMessages() const { while (query_read_msg.next()) { Message message; - message.m_feedId = account_id; + message.m_feedId = QString::number(account_id); message.m_title = query_read_msg.value(0).toString(); message.m_url = query_read_msg.value(1).toString(); message.m_author = query_read_msg.value(2).toString(); message.m_created = TextFactory::parseDateTime(query_read_msg.value(3).value()); message.m_contents = query_read_msg.value(4).toString(); message.m_enclosures = Enclosures::decodeEnclosuresFromString(query_read_msg.value(5).toString()); + message.m_customId = query_read_msg.value(6).toString(); messages.append(message); } @@ -127,3 +153,7 @@ int TtRssFeed::customId() const { void TtRssFeed::setCustomId(int custom_id) { m_customId = custom_id; } + +int TtRssFeed::updateMessages(const QList &messages) { + return 0; +} diff --git a/src/services/tt-rss/ttrssfeed.h b/src/services/tt-rss/ttrssfeed.h index a934f9743..92fae6ef2 100755 --- a/src/services/tt-rss/ttrssfeed.h +++ b/src/services/tt-rss/ttrssfeed.h @@ -45,6 +45,8 @@ class TtRssFeed : public Feed { void setCustomId(int custom_id); private: + int updateMessages(const QList &messages); + int m_customId; int m_totalCount; int m_unreadCount; From 44528a79d751f5df0f846f3d846f750dae926411 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 8 Dec 2015 13:44:57 +0100 Subject: [PATCH 148/203] Work on msgs gettttttttttttttttttttting. --- src/services/tt-rss/ttrssfeed.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index 7a8c64383..33c7f1bc6 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -103,7 +103,8 @@ int TtRssFeed::update() { QList new_messages = headlines.messages(); messages.append(new_messages); - skip += new_messages.size(); + newly_added_messages = new_messages.size(); + skip += newly_added_messages; } } while (newly_added_messages > 0); @@ -155,5 +156,7 @@ void TtRssFeed::setCustomId(int custom_id) { } int TtRssFeed::updateMessages(const QList &messages) { + // TODO: pokračovat tady + return 0; } From 3e1dcb4ab8f85550b086189c749efd2fc57c976f Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 8 Dec 2015 20:42:26 +0100 Subject: [PATCH 149/203] Fix loading of msgs. --- src/services/tt-rss/ttrssfeed.cpp | 1 - src/services/tt-rss/ttrssserviceroot.cpp | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index 33c7f1bc6..8d0b0541b 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -84,7 +84,6 @@ int TtRssFeed::countOfUnreadMessages() { } int TtRssFeed::update() { - // TODO: přes getHeadlines provede stažení kompletnich zprav. QNetworkReply::NetworkError error; QList messages; int newly_added_messages = 0; diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 5ac50a600..465b2d030 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -122,7 +122,8 @@ bool TtRssServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *model QList children = item->getSubTreeFeeds(); QString filter_clause = textualFeedIds(children).join(QSL(", ")); - model->setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0")).arg(filter_clause)); + model->setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = '%2'")).arg(filter_clause, + QString::number(accountId()))); qDebug("Loading messages from feeds: %s.", qPrintable(filter_clause)); return true; From d84aa21ad806914212dac365b908d5ff4b0c2847 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 9 Dec 2015 09:29:14 +0100 Subject: [PATCH 150/203] Feed updating now works. --- src/services/standard/standardfeed.cpp | 8 +- .../tt-rss/network/ttrssnetworkfactory.cpp | 5 +- src/services/tt-rss/ttrssfeed.cpp | 115 +++++++++++++++++- src/services/tt-rss/ttrssfeed.h | 4 +- src/services/tt-rss/ttrssserviceroot.cpp | 10 +- 5 files changed, 128 insertions(+), 14 deletions(-) diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index c7ea6fecc..2e33f9f57 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -651,7 +651,7 @@ int StandardFeed::updateMessages(const QList &messages) { if (remove_duplicates) { query_update.setForwardOnly(true); - query_update.prepare(QSL("UPDATE Messages SET contents = :contents enclosures = :enclosures WHERE id = :id;")); + query_update.prepare(QSL("UPDATE Messages SET contents = :contents, enclosures = :enclosures WHERE id = :id;")); } if (!database.transaction()) { @@ -703,7 +703,6 @@ int StandardFeed::updateMessages(const QList &messages) { query_insert.bindValue(QSL(":account_id"), account_id); if (query_insert.exec() && query_insert.numRowsAffected() == 1) { - setStatus(NewMessages); updated_messages++; } @@ -735,7 +734,6 @@ int StandardFeed::updateMessages(const QList &messages) { query_insert.bindValue(QSL(":enclosures"), Enclosures::encodeEnclosuresToString(message.m_enclosures)); if (query_insert.exec() && query_insert.numRowsAffected() == 1) { - setStatus(NewMessages); updated_messages++; } @@ -746,6 +744,10 @@ int StandardFeed::updateMessages(const QList &messages) { } } + if (updated_messages > 0) { + setStatus(NewMessages); + } + if (!database.commit()) { database.rollback(); diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index 4d5c8ec03..04b3f02b2 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -347,7 +347,10 @@ QList TtRssGetHeadlinesResponse::messages() { message.m_isRead = !mapped["unread"].toBool(); message.m_isImportant = mapped["marked"].toBool(); message.m_contents = mapped["content"].toString(); - message.m_created = TextFactory::parseDateTime(mapped["updated"].value()); + + // Multiply by 1000 because Tiny Tiny RSS API does not include miliseconds in Unix + // date/time number. + message.m_created = TextFactory::parseDateTime(mapped["updated"].value() * 1000); message.m_createdFromFeed = true; message.m_customId = mapped["id"].toString(); message.m_feedId = mapped["feed_id"].toString(); diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index 8d0b0541b..ef2aa4c91 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -75,11 +75,11 @@ void TtRssFeed::updateCounts(bool including_total_count) { } } -int TtRssFeed::countOfAllMessages() { +int TtRssFeed::countOfAllMessages() const { return m_totalCount; } -int TtRssFeed::countOfUnreadMessages() { +int TtRssFeed::countOfUnreadMessages() const { return m_unreadCount; } @@ -155,7 +155,114 @@ void TtRssFeed::setCustomId(int custom_id) { } int TtRssFeed::updateMessages(const QList &messages) { - // TODO: pokračovat tady + if (messages.isEmpty()) { + return 0; + } - return 0; + int feed_id = customId(); + int updated_messages = 0; + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + int account_id = serviceRoot()->accountId(); + + // Prepare queries. + QSqlQuery query_insert(database); + QSqlQuery query_select(database); + QSqlQuery query_update(database); + + query_update.setForwardOnly(true); + query_update.prepare("UPDATE Messages " + "SET title = :title, is_read = :is_read, is_important = :is_important, url = :url, author = :author, date_created = :date_created, contents = :contents, enclosures = :enclosures " + "WHERE id = :id;"); + + query_select.setForwardOnly(true); + query_select.prepare("SELECT id, date_created FROM Messages " + "WHERE account_id = :account_id AND custom_id = :custom_id;"); + + // Used to insert new messages. + query_insert.setForwardOnly(true); + query_insert.prepare("INSERT INTO Messages " + "(feed, title, is_read, is_important, url, author, date_created, contents, enclosures, custom_id, account_id) " + "VALUES (:feed, :title, :is_read, :is_important, :url, :author, :date_created, :contents, :enclosures, :custom_id, :account_id);"); + + if (!database.transaction()) { + database.rollback(); + qDebug("Transaction start for message downloader failed."); + return updated_messages; + } + + foreach (Message message, messages) { + query_select.bindValue(QSL(":account_id"), account_id); + query_select.bindValue(QSL(":custom_id"), message.m_customId); + + query_select.exec(); + + int id_existing_message = -1; + qint64 date_existing_message; + + if (query_select.next()) { + id_existing_message = query_select.value(0).toInt(); + date_existing_message = query_select.value(1).value(); + } + + query_select.finish(); + + // Now, check if this message is already in the DB. + if (id_existing_message >= 0) { + if (message.m_created.toMSecsSinceEpoch() != date_existing_message) { + // Message exists, it is changed, update it. + query_update.bindValue(QSL(":title"), message.m_title); + query_update.bindValue(QSL(":is_read"), (int) message.m_isRead); + query_update.bindValue(QSL(":is_important"), (int) message.m_isImportant); + query_update.bindValue(QSL(":url"), message.m_url); + query_update.bindValue(QSL(":author"), message.m_author); + query_update.bindValue(QSL(":date_created"), message.m_created.toMSecsSinceEpoch()); + query_update.bindValue(QSL(":contents"), message.m_contents); + query_update.bindValue(QSL(":enclosures"), Enclosures::encodeEnclosuresToString(message.m_enclosures)); + query_update.bindValue(QSL(":id"), id_existing_message); + + if (query_update.exec()) { + updated_messages++; + } + + query_update.finish(); + + qDebug("Updating message '%s' in DB.", qPrintable(message.m_title)); + } + } + else { + // Message with this URL is not fetched in this feed yet. + query_insert.bindValue(QSL(":feed"), feed_id); + query_insert.bindValue(QSL(":title"), message.m_title); + query_insert.bindValue(QSL(":is_read"), (int) message.m_isRead); + query_insert.bindValue(QSL(":is_important"), (int) message.m_isImportant); + query_insert.bindValue(QSL(":url"), message.m_url); + query_insert.bindValue(QSL(":author"), message.m_author); + query_insert.bindValue(QSL(":date_created"), message.m_created.toMSecsSinceEpoch()); + query_insert.bindValue(QSL(":contents"), message.m_contents); + query_insert.bindValue(QSL(":enclosures"), Enclosures::encodeEnclosuresToString(message.m_enclosures)); + query_insert.bindValue(QSL(":custom_id"), message.m_customId); + query_insert.bindValue(QSL(":account_id"), account_id); + + if (query_insert.exec() && query_insert.numRowsAffected() == 1) { + updated_messages++; + } + + query_insert.finish(); + + qDebug("Adding new message '%s' to DB.", qPrintable(message.m_title)); + } + } + + if (!database.commit()) { + database.rollback(); + + qDebug("Transaction commit for message downloader failed."); + } + else { + setStatus(NewMessages); + updateCounts(true); + serviceRoot()->itemChanged(QList() << this); + } + + return updated_messages; } diff --git a/src/services/tt-rss/ttrssfeed.h b/src/services/tt-rss/ttrssfeed.h index 92fae6ef2..87a2c3e9f 100755 --- a/src/services/tt-rss/ttrssfeed.h +++ b/src/services/tt-rss/ttrssfeed.h @@ -35,8 +35,8 @@ class TtRssFeed : public Feed { void updateCounts(bool including_total_count); - int countOfAllMessages(); - int countOfUnreadMessages(); + int countOfAllMessages() const; + int countOfUnreadMessages() const; int update(); QList undeletedMessages() const; diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 465b2d030..16da7dc2c 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -298,7 +298,8 @@ void TtRssServiceRoot::syncIn() { storeNewFeedTree(new_tree); foreach (RootItem *top_level_item, new_tree->childItems()) { - appendChild(top_level_item); + top_level_item->setParent(NULL); + requestItemReassignment(top_level_item, this); } updateCounts(true); @@ -306,10 +307,11 @@ void TtRssServiceRoot::syncIn() { new_tree->clearChildren(); new_tree->deleteLater(); - itemChanged(QList() << this); - requestFeedReadFilterReload(); + QList all_items = getSubTree(); + + itemChanged(all_items); requestReloadMessageList(true); - requestItemExpand(getSubTree(), true); + requestItemExpand(all_items, true); } } From bb9b251acd1328e28964d3ba5e82027f9f4bb51d Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 9 Dec 2015 10:52:34 +0100 Subject: [PATCH 151/203] Messages are now correctly update if changed in the meantime on the server. --- src/services/tt-rss/ttrssfeed.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index ef2aa4c91..51cf0ef78 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -175,7 +175,7 @@ int TtRssFeed::updateMessages(const QList &messages) { "WHERE id = :id;"); query_select.setForwardOnly(true); - query_select.prepare("SELECT id, date_created FROM Messages " + query_select.prepare("SELECT id, date_created, is_read, is_important FROM Messages " "WHERE account_id = :account_id AND custom_id = :custom_id;"); // Used to insert new messages. @@ -198,17 +198,25 @@ int TtRssFeed::updateMessages(const QList &messages) { int id_existing_message = -1; qint64 date_existing_message; + bool is_read_existing_message; + bool is_important_existing_message; if (query_select.next()) { id_existing_message = query_select.value(0).toInt(); date_existing_message = query_select.value(1).value(); + is_read_existing_message = query_select.value(2).toBool(); + is_important_existing_message = query_select.value(3).toBool(); } query_select.finish(); // Now, check if this message is already in the DB. if (id_existing_message >= 0) { - if (message.m_created.toMSecsSinceEpoch() != date_existing_message) { + // Message is already in the DB. + + if (message.m_created.toMSecsSinceEpoch() != date_existing_message || + message.m_isRead != is_read_existing_message || + message.m_isImportant != is_important_existing_message) { // Message exists, it is changed, update it. query_update.bindValue(QSL(":title"), message.m_title); query_update.bindValue(QSL(":is_read"), (int) message.m_isRead); From a502af94374bcdf4b5d7eee42cd8c9199da36dc6 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 9 Dec 2015 11:10:51 +0100 Subject: [PATCH 152/203] Old data of TT-RSS account are now purged when credentials are changed and new data are synced. --- src/services/tt-rss/gui/formeditaccount.cpp | 8 ++++++++ .../tt-rss/network/ttrssnetworkfactory.cpp | 8 +++++++- .../tt-rss/network/ttrssnetworkfactory.h | 4 ++++ src/services/tt-rss/ttrssserviceroot.cpp | 19 +++++++++++++++++-- src/services/tt-rss/ttrssserviceroot.h | 6 ++++-- 5 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/services/tt-rss/gui/formeditaccount.cpp b/src/services/tt-rss/gui/formeditaccount.cpp index 865e2df0e..67e9d3d8c 100755 --- a/src/services/tt-rss/gui/formeditaccount.cpp +++ b/src/services/tt-rss/gui/formeditaccount.cpp @@ -139,10 +139,13 @@ void FormEditAccount::performTest() { } void FormEditAccount::onClickedOk() { + bool editing_account = true; + if (m_editableRoot == NULL) { // We want to confirm newly created account. // So save new account into DB, setup its properties. m_editableRoot = new TtRssServiceRoot(); + editing_account = false; } m_editableRoot->network()->setUrl(m_ui->m_txtUrl->lineEdit()->text()); @@ -150,6 +153,11 @@ void FormEditAccount::onClickedOk() { m_editableRoot->network()->setPassword(m_ui->m_txtPassword->lineEdit()->text()); m_editableRoot->saveAccountDataToDatabase(); + if (editing_account) { + m_editableRoot->completelyRemoveAllData(); + m_editableRoot->syncIn(); + } + accept(); } diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index 04b3f02b2..a7bd5aafb 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -31,7 +31,8 @@ TtRssNetworkFactory::TtRssNetworkFactory() - : m_url(QString()), m_username(QString()), m_password(QString()), m_sessionId(QString()) { + : m_url(QString()), m_username(QString()), m_password(QString()), m_sessionId(QString()), + m_lastLoginTime(QDateTime()) { } TtRssNetworkFactory::~TtRssNetworkFactory() { @@ -61,6 +62,10 @@ void TtRssNetworkFactory::setPassword(const QString &password) { m_password = password; } +QDateTime TtRssNetworkFactory::lastLoginTime() const { + return m_lastLoginTime; +} + // TODO: ukazky /* ukazky @@ -86,6 +91,7 @@ TtRssLoginResponse TtRssNetworkFactory::login(QNetworkReply::NetworkError &error if (network_reply.first == QNetworkReply::NoError) { m_sessionId = login_response.sessionId(); + m_lastLoginTime = QDateTime::currentDateTime(); } error = network_reply.first; diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.h b/src/services/tt-rss/network/ttrssnetworkfactory.h index 8d9374f20..ca74fc11e 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.h +++ b/src/services/tt-rss/network/ttrssnetworkfactory.h @@ -88,6 +88,9 @@ class TtRssNetworkFactory { QString password() const; void setPassword(const QString &password); + // Metadata. + QDateTime lastLoginTime() const; + // Operations. // Logs user in. @@ -109,6 +112,7 @@ class TtRssNetworkFactory { QString m_username; QString m_password; QString m_sessionId; + QDateTime m_lastLoginTime; }; #endif // TTRSSNETWORKFACTORY_H diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 16da7dc2c..1314aa871 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -282,6 +282,15 @@ void TtRssServiceRoot::updateTitle() { setTitle(m_network->username() + QL1S("@") + host); } +void TtRssServiceRoot::completelyRemoveAllData() { + // Purge old data from SQL and clean all model items. + removeOldFeedTree(true); + cleanAllItems(); + updateCounts(true); + itemChanged(QList() << this); + requestReloadMessageList(true); +} + void TtRssServiceRoot::syncIn() { QNetworkReply::NetworkError err; TtRssGetFeedsCategoriesResponse feed_cats_response = m_network->getFeedsCategories(err); @@ -290,7 +299,7 @@ void TtRssServiceRoot::syncIn() { RootItem *new_tree = feed_cats_response.feedsCategories(true, m_network->url()); // Purge old data from SQL and clean all model items. - removeOldFeedTree(); + removeOldFeedTree(true); cleanAllItems(); // Model is clean, now store new tree into DB and @@ -326,7 +335,7 @@ QStringList TtRssServiceRoot::textualFeedIds(const QList &feeds) { return stringy_ids; } -void TtRssServiceRoot::removeOldFeedTree() { +void TtRssServiceRoot::removeOldFeedTree(bool including_messages) { QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query(database); query.setForwardOnly(true); @@ -338,6 +347,12 @@ void TtRssServiceRoot::removeOldFeedTree() { query.prepare(QSL("DELETE FROM Categories WHERE account_id = :account_id;")); query.bindValue(QSL(":account_id"), accountId()); query.exec(); + + if (including_messages) { + query.prepare(QSL("DELETE FROM Messages WHERE account_id = :account_id;")); + query.bindValue(QSL(":account_id"), accountId()); + query.exec(); + } } void TtRssServiceRoot::cleanAllItems() { diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 56519886f..35efa1173 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -71,7 +71,9 @@ class TtRssServiceRoot : public ServiceRoot { void saveAccountDataToDatabase(); void updateTitle(); - private slots: + void completelyRemoveAllData(); + + public slots: void syncIn(); private: @@ -79,7 +81,7 @@ class TtRssServiceRoot : public ServiceRoot { // which are suitable as IN clause for SQL queries. QStringList textualFeedIds(const QList &feeds); - void removeOldFeedTree(); + void removeOldFeedTree(bool including_messages); void cleanAllItems(); void storeNewFeedTree(RootItem *root); void loadFromDatabase(); From 3284d3a1b5cd337f3f220c53713481f1894637dc Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 9 Dec 2015 11:25:04 +0100 Subject: [PATCH 153/203] Typo. --- src/services/tt-rss/ttrssserviceroot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 1314aa871..6b50a7ad4 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -299,7 +299,7 @@ void TtRssServiceRoot::syncIn() { RootItem *new_tree = feed_cats_response.feedsCategories(true, m_network->url()); // Purge old data from SQL and clean all model items. - removeOldFeedTree(true); + removeOldFeedTree(false); cleanAllItems(); // Model is clean, now store new tree into DB and From 09b023b937a80d16cafc7b513ba81a2a278c4023 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 9 Dec 2015 12:03:34 +0100 Subject: [PATCH 154/203] Message class now includes account ID. Fixed newspaper mode for TT-RSS. --- src/core/message.cpp | 1 + src/core/message.h | 1 + src/core/messagesmodel.cpp | 1 + src/services/standard/standardfeed.cpp | 1 + src/services/tt-rss/ttrssfeed.cpp | 6 ++++-- src/services/tt-rss/ttrssserviceroot.cpp | 16 +++++++++++++++- src/services/tt-rss/ttrssserviceroot.h | 2 +- 7 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/core/message.cpp b/src/core/message.cpp index a0a6d4448..a8e5b22ce 100755 --- a/src/core/message.cpp +++ b/src/core/message.cpp @@ -63,5 +63,6 @@ QString Enclosures::encodeEnclosuresToString(const QList &enclosures) Message::Message() { m_title = m_url = m_author = m_contents = m_feedId = m_customId = ""; m_enclosures = QList(); + m_accountId = 0; m_isRead = m_isImportant = false; } diff --git a/src/core/message.h b/src/core/message.h index eab142d15..7459eb0be 100755 --- a/src/core/message.h +++ b/src/core/message.h @@ -50,6 +50,7 @@ class Message { QString m_contents; QDateTime m_created; QString m_feedId; + int m_accountId; QString m_customId; bool m_isRead; diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index ba0968bbe..cedbd2ebd 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -140,6 +140,7 @@ Message MessagesModel::messageAt(int row_index) const { message.m_title = rec.value(MSG_DB_TITLE_INDEX).toString(); message.m_url = rec.value(MSG_DB_URL_INDEX).toString(); message.m_feedId = rec.value(MSG_DB_FEED_INDEX).toString(); + message.m_accountId = rec.value(MSG_DB_ACCOUNT_ID_INDEX).toInt(); message.m_customId = rec.value(MSG_DB_CUSTOM_ID_INDEX).toString(); message.m_created = TextFactory::parseDateTime(rec.value(MSG_DB_DCREATED_INDEX).value()).toLocalTime(); diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 2e33f9f57..321884f87 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -154,6 +154,7 @@ QList StandardFeed::undeletedMessages() const { message.m_author = query_read_msg.value(2).toString(); message.m_created = TextFactory::parseDateTime(query_read_msg.value(3).value()); message.m_contents = query_read_msg.value(4).toString(); + message.m_accountId = const_cast(this)->serviceRoot()->accountId(); message.m_enclosures = Enclosures::decodeEnclosuresFromString(query_read_msg.value(5).toString()); messages.append(message); diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index 51cf0ef78..0579cf0fb 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -116,12 +116,13 @@ QList TtRssFeed::undeletedMessages() const { int account_id = const_cast(this)->serviceRoot()->accountId(); QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query_read_msg(database); + query_read_msg.setForwardOnly(true); query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures, custom_id " "FROM Messages " "WHERE is_deleted = 0 AND feed = :feed AND account_id = :account_id;"); - query_read_msg.bindValue(QSL(":feed"), id()); + query_read_msg.bindValue(QSL(":feed"), customId()); query_read_msg.bindValue(QSL(":account_id"), account_id); // FIXME: Fix those const functions, this is fucking ugly. @@ -130,13 +131,14 @@ QList TtRssFeed::undeletedMessages() const { while (query_read_msg.next()) { Message message; - message.m_feedId = QString::number(account_id); + message.m_feedId = QString::number(customId()); message.m_title = query_read_msg.value(0).toString(); message.m_url = query_read_msg.value(1).toString(); message.m_author = query_read_msg.value(2).toString(); message.m_created = TextFactory::parseDateTime(query_read_msg.value(3).value()); message.m_contents = query_read_msg.value(4).toString(); message.m_enclosures = Enclosures::decodeEnclosuresFromString(query_read_msg.value(5).toString()); + message.m_accountId = account_id; message.m_customId = query_read_msg.value(6).toString(); messages.append(message); diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 6b50a7ad4..e076a2b43 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -146,11 +146,25 @@ QList TtRssServiceRoot::contextMenu() { } bool TtRssServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, QList message_db_ids, RootItem::ReadStatus read) { + // TODO: misto čísel primarnich zprav, vracet cele objekty zprav + // tedy včetně custom ID, nemusi se tak znova tahat z DB asi?s + + // OK, update the messages status online. + + // First obtain, custom IDs of messages. + return false; } bool TtRssServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, QList message_db_ids, RootItem::ReadStatus read) { - return false; + Q_UNUSED(message_db_ids) + Q_UNUSED(read) + + selected_item->updateCounts(false); + + itemChanged(QList() << selected_item); + requestFeedReadFilterReload(); + return true; } bool TtRssServiceRoot::onBeforeSwitchMessageImportance(RootItem *selected_item, QList > changes) { diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 35efa1173..96d424b06 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -76,7 +76,7 @@ class TtRssServiceRoot : public ServiceRoot { public slots: void syncIn(); - private: + private: // Returns converted ids of given feeds // which are suitable as IN clause for SQL queries. QStringList textualFeedIds(const QList &feeds); From 97e5e70afa1b6fa8b10ff17a5de419a1cddc8169 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 9 Dec 2015 12:58:01 +0100 Subject: [PATCH 155/203] Hmmm. --- src/core/messagesmodel.cpp | 3 +-- src/gui/messagesview.cpp | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index cedbd2ebd..cd1fad544 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -426,8 +426,7 @@ bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootIt query_read_msg.setForwardOnly(true); if (query_read_msg.exec(QString(QSL("UPDATE Messages SET is_read = %2 WHERE id IN (%1);")) - .arg(message_ids.join(QSL(", ")), - read == RootItem::Read ? QSL("1") : QSL("0")))) { + .arg(message_ids.join(QSL(", ")), read == RootItem::Read ? QSL("1") : QSL("0")))) { fetchAllData(); return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, message_ids_num, read); diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index 5a50c6193..ee523bc9a 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -440,11 +440,11 @@ void MessagesView::reselectIndexes(const QModelIndexList &indexes) { QItemSelection selection; foreach (const QModelIndex &index, indexes) { - // FIXME: THIS IS very slow. Try to select 4000 messages and hit "mark as read" button. selection.merge(QItemSelection(index, index), QItemSelectionModel::Select); } - selectionModel()->select(selection, QItemSelectionModel::Select | QItemSelectionModel::Rows); + // FIXME: THIS IS very slow. Try to select 4000 messages and hit "mark as read" button. + //selectionModel()->select(selection, QItemSelectionModel::Select | QItemSelectionModel::Rows); } void MessagesView::selectNextItem() { From c33eb38e4219b2021d7c42bae184a55df76caeb9 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 9 Dec 2015 18:27:03 +0100 Subject: [PATCH 156/203] Add account on 2xclick. --- src/gui/dialogs/formaddaccount.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/dialogs/formaddaccount.cpp b/src/gui/dialogs/formaddaccount.cpp index 38d7d2e68..60fa962af 100755 --- a/src/gui/dialogs/formaddaccount.cpp +++ b/src/gui/dialogs/formaddaccount.cpp @@ -39,6 +39,7 @@ FormAddAccount::FormAddAccount(const QList &entry_points, Fe MessageBox::iconify(m_ui->m_buttonBox); #endif + connect(m_ui->m_listEntryPoints, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(addSelectedAccount())); connect(m_ui->m_buttonBox, SIGNAL(accepted()), this, SLOT(addSelectedAccount())); connect(m_ui->m_listEntryPoints, SIGNAL(itemSelectionChanged()), this, SLOT(displayActiveEntryPointDetails())); loadEntryPoints(); From 250483295da994d105b806bd12ca3b283f65f120 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 9 Dec 2015 18:36:31 +0100 Subject: [PATCH 157/203] Added empty recycle bin. --- CMakeLists.txt | 4 +++ src/services/tt-rss/ttrssrecyclebin.cpp | 35 +++++++++++++++++++++++++ src/services/tt-rss/ttrssrecyclebin.h | 35 +++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 src/services/tt-rss/ttrssrecyclebin.cpp create mode 100644 src/services/tt-rss/ttrssrecyclebin.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 821c6a69a..b3d3086de 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -441,6 +441,7 @@ set(APP_SOURCES src/services/tt-rss/ttrssserviceroot.cpp src/services/tt-rss/ttrssfeed.cpp src/services/tt-rss/ttrsscategory.cpp + src/services/tt-rss/ttrssrecyclebin.cpp src/services/tt-rss/gui/formeditaccount.cpp src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -559,6 +560,9 @@ set(APP_HEADERS # TT-RSS service headers. src/services/tt-rss/ttrssserviceroot.h + src/services/tt-rss/ttrssrecyclebin.h + src/services/tt-rss/ttrssfeed.h + src/services/tt-rss/ttrsscategory.h src/services/tt-rss/gui/formeditaccount.h # NETWORK-WEB headers. diff --git a/src/services/tt-rss/ttrssrecyclebin.cpp b/src/services/tt-rss/ttrssrecyclebin.cpp new file mode 100644 index 000000000..31d566825 --- /dev/null +++ b/src/services/tt-rss/ttrssrecyclebin.cpp @@ -0,0 +1,35 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#include "services/tt-rss/ttrssrecyclebin.h" + + +TtRssRecycleBin::TtRssRecycleBin(QObject *parent) : RecycleBin(parent) { + +} + +TtRssRecycleBin::~TtRssRecycleBin() { +} + +bool TtRssRecycleBin::empty() { + return false; +} + +bool TtRssRecycleBin::restore() { + return false; +} + diff --git a/src/services/tt-rss/ttrssrecyclebin.h b/src/services/tt-rss/ttrssrecyclebin.h new file mode 100644 index 000000000..cc24ee7f5 --- /dev/null +++ b/src/services/tt-rss/ttrssrecyclebin.h @@ -0,0 +1,35 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#ifndef TTRSSRECYCLEBIN_H +#define TTRSSRECYCLEBIN_H + +#include "services/abstract/recyclebin.h" + + +class TtRssRecycleBin : public RecycleBin { + Q_OBJECT + + public: + explicit TtRssRecycleBin(QObject *parent = 0); + virtual ~TtRssRecycleBin(); + + bool empty(); + bool restore(); +}; + +#endif // TTRSSRECYCLEBIN_H From 19fc304e69c84f6a8b5e6f5ea6691b3a3d68e035 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 9 Dec 2015 18:42:36 +0100 Subject: [PATCH 158/203] Added empty recycle bin. --- src/services/tt-rss/ttrssrecyclebin.cpp | 2 +- src/services/tt-rss/ttrssrecyclebin.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/tt-rss/ttrssrecyclebin.cpp b/src/services/tt-rss/ttrssrecyclebin.cpp index 31d566825..eca3ffb62 100644 --- a/src/services/tt-rss/ttrssrecyclebin.cpp +++ b/src/services/tt-rss/ttrssrecyclebin.cpp @@ -18,7 +18,7 @@ #include "services/tt-rss/ttrssrecyclebin.h" -TtRssRecycleBin::TtRssRecycleBin(QObject *parent) : RecycleBin(parent) { +TtRssRecycleBin::TtRssRecycleBin(RootItem *parent) : RecycleBin(parent) { } diff --git a/src/services/tt-rss/ttrssrecyclebin.h b/src/services/tt-rss/ttrssrecyclebin.h index cc24ee7f5..2bacc2954 100644 --- a/src/services/tt-rss/ttrssrecyclebin.h +++ b/src/services/tt-rss/ttrssrecyclebin.h @@ -25,7 +25,7 @@ class TtRssRecycleBin : public RecycleBin { Q_OBJECT public: - explicit TtRssRecycleBin(QObject *parent = 0); + explicit TtRssRecycleBin(RootItem *parent = 0); virtual ~TtRssRecycleBin(); bool empty(); From dca3f31f7660807124682b60411a7399c837d005 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 9 Dec 2015 18:44:37 +0100 Subject: [PATCH 159/203] Converted slot. --- src/services/standard/standardrecyclebin.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/services/standard/standardrecyclebin.h b/src/services/standard/standardrecyclebin.h index fb3794e4b..02fb09909 100755 --- a/src/services/standard/standardrecyclebin.h +++ b/src/services/standard/standardrecyclebin.h @@ -41,7 +41,6 @@ class StandardRecycleBin : public RecycleBin { bool empty(); bool restore(); - public slots: void updateCounts(bool update_total_count); private: From b7349140ee59c61bd20c1315deb6ae118e3b838f Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 9 Dec 2015 20:32:55 +0100 Subject: [PATCH 160/203] Fix message loading for standar root. --- src/services/standard/standardserviceroot.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 6a6c44884..2c8c6da62 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -590,13 +590,14 @@ QList StandardServiceRoot::contextMenu() { bool StandardServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *model) { if (item->kind() == RootItemKind::Bin) { - model->setFilter(QSL("is_deleted = 1 AND is_pdeleted = 0")); + model->setFilter(QString("is_deleted = 1 AND is_pdeleted = 0 AND account_id = %1").arg(accountId())); } else { QList children = item->getSubTreeFeeds(); QString filter_clause = textualFeedIds(children).join(QSL(", ")); - model->setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0")).arg(filter_clause)); + model->setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = %1")).arg(filter_clause, + accountId())); qDebug("Loading messages from feeds: %s.", qPrintable(filter_clause)); } From 5baa274970d0daae3bd887474ff7b3717d7a9c0e Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 9 Dec 2015 20:33:22 +0100 Subject: [PATCH 161/203] Fix message loading for standar root. --- src/services/standard/standardserviceroot.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 2c8c6da62..2ab487f4d 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -596,8 +596,8 @@ bool StandardServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *mo QList children = item->getSubTreeFeeds(); QString filter_clause = textualFeedIds(children).join(QSL(", ")); - model->setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = %1")).arg(filter_clause, - accountId())); + model->setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = %2")).arg(filter_clause, + accountId())); qDebug("Loading messages from feeds: %s.", qPrintable(filter_clause)); } From 2fb97342ee8dc64f2127bac674225375355e7a1d Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 9 Dec 2015 20:37:11 +0100 Subject: [PATCH 162/203] Fix message loading for standar root. --- src/services/standard/standardserviceroot.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 2ab487f4d..0b500bbc9 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -590,14 +590,14 @@ QList StandardServiceRoot::contextMenu() { bool StandardServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *model) { if (item->kind() == RootItemKind::Bin) { - model->setFilter(QString("is_deleted = 1 AND is_pdeleted = 0 AND account_id = %1").arg(accountId())); + model->setFilter(QString("is_deleted = 1 AND is_pdeleted = 0 AND account_id = %1").arg(QString::number(accountId()))); } else { QList children = item->getSubTreeFeeds(); QString filter_clause = textualFeedIds(children).join(QSL(", ")); model->setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = %2")).arg(filter_clause, - accountId())); + QString::number(accountId()))); qDebug("Loading messages from feeds: %s.", qPrintable(filter_clause)); } From 724e4337868abfe65791b873213974172a832689 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 10 Dec 2015 07:02:09 +0100 Subject: [PATCH 163/203] Refactored recycle bin. --- src/services/abstract/recyclebin.cpp | 73 +++++++++++++++++++ src/services/abstract/recyclebin.h | 4 +- src/services/standard/standardrecyclebin.cpp | 4 +- src/services/standard/standardserviceroot.cpp | 61 ---------------- src/services/standard/standardserviceroot.h | 3 - 5 files changed, 77 insertions(+), 68 deletions(-) diff --git a/src/services/abstract/recyclebin.cpp b/src/services/abstract/recyclebin.cpp index dc29f0117..e7528a06b 100755 --- a/src/services/abstract/recyclebin.cpp +++ b/src/services/abstract/recyclebin.cpp @@ -19,6 +19,9 @@ #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" +#include "services/abstract/serviceroot.h" + +#include RecycleBin::RecycleBin(RootItem *parent_item) : RootItem(parent_item) { @@ -41,3 +44,73 @@ QVariant RecycleBin::data(int column, int role) const { return RootItem::data(column, role); } } + +bool RecycleBin::empty() { + QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + + if (!db_handle.transaction()) { + qWarning("Starting transaction for recycle bin emptying."); + return false; + } + + ServiceRoot *parent_root = getParentServiceRoot(); + QSqlQuery query_empty_bin(db_handle); + + query_empty_bin.setForwardOnly(true); + query_empty_bin.prepare(QSL("UPDATE Messages SET is_pdeleted = 1 WHERE is_deleted = 1 AND account_id = :account_id;")); + query_empty_bin.bindValue(QSL(":account_id"), parent_root->accountId()); + + if (!query_empty_bin.exec()) { + qWarning("Query execution failed for recycle bin emptying."); + + db_handle.rollback(); + return false; + } + + // Commit changes. + if (db_handle.commit()) { + updateCounts(true); + parent_root->itemChanged(QList() << this); + parent_root->requestReloadMessageList(true); + return true; + } + else { + return db_handle.rollback(); + } +} + +bool RecycleBin::restore() { + QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + + if (!db_handle.transaction()) { + qWarning("Starting transaction for recycle bin restoring."); + return false; + } + + ServiceRoot *parent_root = getParentServiceRoot(); + QSqlQuery query_empty_bin(db_handle); + + query_empty_bin.setForwardOnly(true); + query_empty_bin.prepare("UPDATE Messages SET is_deleted = 0 " + "WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;"); + query_empty_bin.bindValue(QSL(":account_id"), parent_root->accountId()); + + if (!query_empty_bin.exec()) { + qWarning("Query execution failed for recycle bin restoring."); + + db_handle.rollback(); + return false; + } + + // Commit changes. + if (db_handle.commit()) { + parent_root->updateCounts(true); + parent_root->itemChanged(parent_root->getSubTree()); + parent_root->requestReloadMessageList(true); + parent_root->requestFeedReadFilterReload(); + return true; + } + else { + return db_handle.rollback(); + } +} diff --git a/src/services/abstract/recyclebin.h b/src/services/abstract/recyclebin.h index ba3d5241b..fa360aade 100755 --- a/src/services/abstract/recyclebin.h +++ b/src/services/abstract/recyclebin.h @@ -38,10 +38,10 @@ class RecycleBin : public RootItem { // Empties the bin - removes all messages from it (does not remove // them from DB, just permanently hide them, so that they are not // re-downloaded). - virtual bool empty() = 0; + virtual bool empty(); // Performs complete restoration of all messages contained in the bin - virtual bool restore() = 0; + virtual bool restore(); ///////////////////////////////////////// // Members to override. */ diff --git a/src/services/standard/standardrecyclebin.cpp b/src/services/standard/standardrecyclebin.cpp index bd0df5175..64781a656 100755 --- a/src/services/standard/standardrecyclebin.cpp +++ b/src/services/standard/standardrecyclebin.cpp @@ -50,11 +50,11 @@ bool StandardRecycleBin::markAsReadUnread(RootItem::ReadStatus status) { } bool StandardRecycleBin::empty() { - return serviceRoot()->emptyBin(); + return RecycleBin::empty(); } bool StandardRecycleBin::restore() { - return serviceRoot()->restoreBin(); + return RecycleBin::restore(); } void StandardRecycleBin::updateCounts(bool update_total_count) { diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 0b500bbc9..6c62e789c 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -268,67 +268,6 @@ bool StandardServiceRoot::cleanFeeds(QList items, bool clean_read_only) { } } -bool StandardServiceRoot::restoreBin() { - QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); - - if (!db_handle.transaction()) { - qWarning("Starting transaction for recycle bin restoring."); - return false; - } - - QSqlQuery query_empty_bin(db_handle); - query_empty_bin.setForwardOnly(true); - - if (!query_empty_bin.exec(QString("UPDATE Messages SET is_deleted = 0 WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = %1;").arg(accountId()))) { - qWarning("Query execution failed for recycle bin restoring."); - - db_handle.rollback(); - return false; - } - - // Commit changes. - if (db_handle.commit()) { - updateCounts(true); - itemChanged(getSubTree()); - requestReloadMessageList(true); - requestFeedReadFilterReload(); - return true; - } - else { - return db_handle.rollback(); - } -} - -bool StandardServiceRoot::emptyBin() { - QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); - - if (!db_handle.transaction()) { - qWarning("Starting transaction for recycle bin emptying."); - return false; - } - - QSqlQuery query_empty_bin(db_handle); - query_empty_bin.setForwardOnly(true); - - if (!query_empty_bin.exec(QString("UPDATE Messages SET is_pdeleted = 1 WHERE is_deleted = 1 AND account_id = %1;").arg(accountId()))) { - qWarning("Query execution failed for recycle bin emptying."); - - db_handle.rollback(); - return false; - } - - // Commit changes. - if (db_handle.commit()) { - m_recycleBin->updateCounts(true); - itemChanged(QList() << m_recycleBin); - requestReloadMessageList(true); - return true; - } - else { - return db_handle.rollback(); - } -} - void StandardServiceRoot::loadFromDatabase(){ QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); Assignment categories; diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 55552ff54..56044aadb 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -95,9 +95,6 @@ class StandardServiceRoot : public ServiceRoot { bool markRecycleBinReadUnread(ReadStatus read); bool cleanFeeds(QList items, bool clean_read_only); - bool restoreBin(); - bool emptyBin(); - void loadFromDatabase(); public slots: From 333d38cf98a731f5fa9ee472a6ffdd3073c3bc38 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 10 Dec 2015 07:31:04 +0100 Subject: [PATCH 164/203] Refactored markin read/unread in recycle bin. --- src/services/abstract/recyclebin.cpp | 82 +++++++++++++++++++ src/services/abstract/recyclebin.h | 11 +++ src/services/standard/standardrecyclebin.cpp | 32 +------- src/services/standard/standardrecyclebin.h | 8 -- src/services/standard/standardserviceroot.cpp | 39 --------- src/services/standard/standardserviceroot.h | 1 - 6 files changed, 94 insertions(+), 79 deletions(-) diff --git a/src/services/abstract/recyclebin.cpp b/src/services/abstract/recyclebin.cpp index e7528a06b..9b97fcfa2 100755 --- a/src/services/abstract/recyclebin.cpp +++ b/src/services/abstract/recyclebin.cpp @@ -35,6 +35,46 @@ RecycleBin::RecycleBin(RootItem *parent_item) : RootItem(parent_item) { RecycleBin::~RecycleBin() { } +int RecycleBin::countOfUnreadMessages() const { + return m_unreadCount; +} + +int RecycleBin::countOfAllMessages() const { + return m_totalCount; +} + +void RecycleBin::updateCounts(bool update_total_count) { + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + QSqlQuery query_all(database); + ServiceRoot *parent_root = getParentServiceRoot(); + + query_all.setForwardOnly(true); + query_all.prepare("SELECT count(*) FROM Messages " + "WHERE is_read = 0 AND is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;"); + query_all.bindValue(QSL(":account_id"), parent_root->accountId()); + + + if (query_all.exec() && query_all.next()) { + m_unreadCount = query_all.value(0).toInt(); + } + else { + m_unreadCount = 0; + } + + if (update_total_count) { + query_all.prepare("SELECT count(*) FROM Messages " + "WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;"); + query_all.bindValue(QSL(":account_id"), parent_root->accountId()); + + if (query_all.exec() && query_all.next()) { + m_totalCount = query_all.value(0).toInt(); + } + else { + m_totalCount = 0; + } + } +} + QVariant RecycleBin::data(int column, int role) const { switch (role) { case Qt::ToolTipRole: @@ -45,6 +85,48 @@ QVariant RecycleBin::data(int column, int role) const { } } +bool RecycleBin::markAsReadUnread(RootItem::ReadStatus status) { + QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + + if (!db_handle.transaction()) { + qWarning("Starting transaction for recycle bin read change."); + return false; + } + + QSqlQuery query_read_msg(db_handle); + ServiceRoot *parent_root = getParentServiceRoot(); + + query_read_msg.setForwardOnly(true); + + if (!query_read_msg.prepare("UPDATE Messages SET is_read = :read " + "WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;")) { + qWarning("Query preparation failed for recycle bin read change."); + + db_handle.rollback(); + return false; + } + + query_read_msg.bindValue(QSL(":read"), status == RootItem::Read ? 1 : 0); + query_read_msg.bindValue(QSL(":account_id"), parent_root->accountId()); + + if (!query_read_msg.exec()) { + qDebug("Query execution for recycle bin read change failed."); + db_handle.rollback(); + } + + // Commit changes. + if (db_handle.commit()) { + updateCounts(true); + + parent_root->itemChanged(QList() << this); + parent_root->requestReloadMessageList(status == RootItem::Read); + return true; + } + else { + return db_handle.rollback(); + } +} + bool RecycleBin::empty() { QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); diff --git a/src/services/abstract/recyclebin.h b/src/services/abstract/recyclebin.h index fa360aade..386601da8 100755 --- a/src/services/abstract/recyclebin.h +++ b/src/services/abstract/recyclebin.h @@ -30,6 +30,13 @@ class RecycleBin : public RootItem { QVariant data(int column, int role) const; + bool markAsReadUnread(ReadStatus status); + + int countOfUnreadMessages() const; + int countOfAllMessages() const; + + void updateCounts(bool update_total_count); + public slots: ///////////////////////////////////////// // /* Members to override. @@ -46,6 +53,10 @@ class RecycleBin : public RootItem { ///////////////////////////////////////// // Members to override. */ ///////////////////////////////////////// + + private: + int m_totalCount; + int m_unreadCount; }; #endif // RECYCLEBIN_H diff --git a/src/services/standard/standardrecyclebin.cpp b/src/services/standard/standardrecyclebin.cpp index 64781a656..dc1bbe20a 100755 --- a/src/services/standard/standardrecyclebin.cpp +++ b/src/services/standard/standardrecyclebin.cpp @@ -37,16 +37,8 @@ StandardServiceRoot *StandardRecycleBin::serviceRoot() { return static_cast(getParentServiceRoot()); } -int StandardRecycleBin::countOfUnreadMessages() const { - return m_unreadCount; -} - -int StandardRecycleBin::countOfAllMessages() const { - return m_totalCount; -} - bool StandardRecycleBin::markAsReadUnread(RootItem::ReadStatus status) { - return serviceRoot()->markRecycleBinReadUnread(status); + return RecycleBin::markAsReadUnread(status); } bool StandardRecycleBin::empty() { @@ -56,25 +48,3 @@ bool StandardRecycleBin::empty() { bool StandardRecycleBin::restore() { return RecycleBin::restore(); } - -void StandardRecycleBin::updateCounts(bool update_total_count) { - QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); - QSqlQuery query_all(database); - query_all.setForwardOnly(true); - - if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE is_read = 0 AND is_deleted = 1 AND is_pdeleted = 0 AND account_id = %1;").arg(serviceRoot()->accountId())) && query_all.next()) { - m_unreadCount = query_all.value(0).toInt(); - } - else { - m_unreadCount = 0; - } - - if (update_total_count) { - if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = %1;").arg(serviceRoot()->accountId())) && query_all.next()) { - m_totalCount = query_all.value(0).toInt(); - } - else { - m_totalCount = 0; - } - } -} diff --git a/src/services/standard/standardrecyclebin.h b/src/services/standard/standardrecyclebin.h index 02fb09909..180e5ce5b 100755 --- a/src/services/standard/standardrecyclebin.h +++ b/src/services/standard/standardrecyclebin.h @@ -34,18 +34,10 @@ class StandardRecycleBin : public RecycleBin { StandardServiceRoot *serviceRoot(); - int countOfUnreadMessages() const; - int countOfAllMessages() const; bool markAsReadUnread(RootItem::ReadStatus status); bool empty(); bool restore(); - - void updateCounts(bool update_total_count); - - private: - int m_totalCount; - int m_unreadCount; }; #endif // STANDARDRECYCLEBIN_H diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 6c62e789c..bb5d9b6e2 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -185,45 +185,6 @@ bool StandardServiceRoot::markFeedsReadUnread(QList items, ReadStatus rea } } -bool StandardServiceRoot::markRecycleBinReadUnread(RootItem::ReadStatus read) { - QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); - - if (!db_handle.transaction()) { - qWarning("Starting transaction for recycle bin read change."); - return false; - } - - QSqlQuery query_read_msg(db_handle); - query_read_msg.setForwardOnly(true); - - if (!query_read_msg.prepare("UPDATE Messages SET is_read = :read WHERE is_deleted = 1 AND account_id = :account_id;")) { - qWarning("Query preparation failed for recycle bin read change."); - - db_handle.rollback(); - return false; - } - - query_read_msg.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0); - query_read_msg.bindValue(QSL(":account_id"), accountId()); - - if (!query_read_msg.exec()) { - qDebug("Query execution for recycle bin read change failed."); - db_handle.rollback(); - } - - // Commit changes. - if (db_handle.commit()) { - m_recycleBin->updateCounts(true); - - itemChanged(QList() << m_recycleBin); - requestReloadMessageList(read == RootItem::Read); - return true; - } - else { - return db_handle.rollback(); - } -} - bool StandardServiceRoot::cleanFeeds(QList items, bool clean_read_only) { QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query_delete_msg(db_handle); diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 56044aadb..35d5e0eca 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -92,7 +92,6 @@ class StandardServiceRoot : public ServiceRoot { bool mergeImportExportModel(FeedsImportExportModel *model, QString &output_message); bool markFeedsReadUnread(QList items, ReadStatus read); - bool markRecycleBinReadUnread(ReadStatus read); bool cleanFeeds(QList items, bool clean_read_only); void loadFromDatabase(); From e66fb101e9fcb9b321c25613874627929060ea35 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 10 Dec 2015 07:34:39 +0100 Subject: [PATCH 165/203] Removed some code. --- src/services/standard/standardrecyclebin.cpp | 18 ------------------ src/services/standard/standardrecyclebin.h | 11 ----------- 2 files changed, 29 deletions(-) diff --git a/src/services/standard/standardrecyclebin.cpp b/src/services/standard/standardrecyclebin.cpp index dc1bbe20a..f99ecb06a 100755 --- a/src/services/standard/standardrecyclebin.cpp +++ b/src/services/standard/standardrecyclebin.cpp @@ -21,8 +21,6 @@ #include "miscellaneous/iconfactory.h" #include "services/standard/standardserviceroot.h" -#include - StandardRecycleBin::StandardRecycleBin(RootItem *parent) : RecycleBin(parent) { @@ -32,19 +30,3 @@ StandardRecycleBin::StandardRecycleBin(RootItem *parent) StandardRecycleBin::~StandardRecycleBin() { qDebug("Destroying RecycleBin instance."); } - -StandardServiceRoot *StandardRecycleBin::serviceRoot() { - return static_cast(getParentServiceRoot()); -} - -bool StandardRecycleBin::markAsReadUnread(RootItem::ReadStatus status) { - return RecycleBin::markAsReadUnread(status); -} - -bool StandardRecycleBin::empty() { - return RecycleBin::empty(); -} - -bool StandardRecycleBin::restore() { - return RecycleBin::restore(); -} diff --git a/src/services/standard/standardrecyclebin.h b/src/services/standard/standardrecyclebin.h index 180e5ce5b..5dbba31a4 100755 --- a/src/services/standard/standardrecyclebin.h +++ b/src/services/standard/standardrecyclebin.h @@ -20,10 +20,6 @@ #include "services/abstract/recyclebin.h" -#include - - -class StandardServiceRoot; class StandardRecycleBin : public RecycleBin { Q_OBJECT @@ -31,13 +27,6 @@ class StandardRecycleBin : public RecycleBin { public: explicit StandardRecycleBin(RootItem *parent = NULL); virtual ~StandardRecycleBin(); - - StandardServiceRoot *serviceRoot(); - - bool markAsReadUnread(RootItem::ReadStatus status); - - bool empty(); - bool restore(); }; #endif // STANDARDRECYCLEBIN_H From 0b5b75d3bd2e1852be19edb3c3aee9aaa1d8a4e8 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 10 Dec 2015 08:24:38 +0100 Subject: [PATCH 166/203] Fixed reselecting of HUGE number of messages. --- resources/text/CHANGELOG | 1 + src/definitions/definitions.h.in | 1 + src/gui/messagesview.cpp | 13 +++++++------ src/services/tt-rss/network/ttrssnetworkfactory.cpp | 2 +- src/services/tt-rss/ttrssrecyclebin.cpp | 9 --------- src/services/tt-rss/ttrssrecyclebin.h | 3 --- 6 files changed, 10 insertions(+), 19 deletions(-) mode change 100644 => 100755 src/services/tt-rss/ttrssrecyclebin.cpp mode change 100644 => 100755 src/services/tt-rss/ttrssrecyclebin.h diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 1ad0bd8f0..b602cd783 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -24,6 +24,7 @@ Fixed:
                  +
                • Solved problem when user selects HUGE number of individual messages and marks them read/unread. Reselecting them after change may cause RSS Guard to hang.
                • Better info in popup notification when many feeds are updated.
                • Fixed obtaining of contents in RSS 2.0 feed entries. (bug #130)
                • Improved popup informing about changes in newly installed version.
                • diff --git a/src/definitions/definitions.h.in b/src/definitions/definitions.h.in index 33261bb8f..6cf56098b 100755 --- a/src/definitions/definitions.h.in +++ b/src/definitions/definitions.h.in @@ -53,6 +53,7 @@ #define URL_REGEXP "^(http|https|feed|ftp):\\/\\/[\\w\\-_]+(\\.[\\w\\-_]+)+([\\w\\-\\.,@?^=%&:/~\\+#]*[\\w\\-\\@?^=%&/~\\+#])?$" #define USER_AGENT_HTTP_HEADER "User-Agent" #define TEXT_TITLE_LIMIT 30 +#define RESELECT_MESSAGE_THRESSHOLD 500 #define MAX_ZOOM_FACTOR 10.0 #define ICON_SIZE_SETTINGS 16 #define NO_PARENT_CATEGORY -1 diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index ee523bc9a..e6522062c 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -437,14 +437,15 @@ void MessagesView::switchSelectedMessagesImportance() { } void MessagesView::reselectIndexes(const QModelIndexList &indexes) { - QItemSelection selection; + if (indexes.size() < RESELECT_MESSAGE_THRESSHOLD) { + QItemSelection selection; - foreach (const QModelIndex &index, indexes) { - selection.merge(QItemSelection(index, index), QItemSelectionModel::Select); + foreach (const QModelIndex &index, indexes) { + selection.merge(QItemSelection(index, index), QItemSelectionModel::Select); + } + + selectionModel()->select(selection, QItemSelectionModel::Select | QItemSelectionModel::Rows); } - - // FIXME: THIS IS very slow. Try to select 4000 messages and hit "mark as read" button. - //selectionModel()->select(selection, QItemSelectionModel::Select | QItemSelectionModel::Rows); } void MessagesView::selectNextItem() { diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index a7bd5aafb..bfc02ab33 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -121,7 +121,7 @@ TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories(QNetwork QtJson::JsonObject json; json["op"] = "getFeedTree"; json["sid"] = m_sessionId; - json["include_empty"] = true; + json["include_empty"] = false; QByteArray result_raw; NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); diff --git a/src/services/tt-rss/ttrssrecyclebin.cpp b/src/services/tt-rss/ttrssrecyclebin.cpp old mode 100644 new mode 100755 index eca3ffb62..80b477a7d --- a/src/services/tt-rss/ttrssrecyclebin.cpp +++ b/src/services/tt-rss/ttrssrecyclebin.cpp @@ -24,12 +24,3 @@ TtRssRecycleBin::TtRssRecycleBin(RootItem *parent) : RecycleBin(parent) { TtRssRecycleBin::~TtRssRecycleBin() { } - -bool TtRssRecycleBin::empty() { - return false; -} - -bool TtRssRecycleBin::restore() { - return false; -} - diff --git a/src/services/tt-rss/ttrssrecyclebin.h b/src/services/tt-rss/ttrssrecyclebin.h old mode 100644 new mode 100755 index 2bacc2954..b235863aa --- a/src/services/tt-rss/ttrssrecyclebin.h +++ b/src/services/tt-rss/ttrssrecyclebin.h @@ -27,9 +27,6 @@ class TtRssRecycleBin : public RecycleBin { public: explicit TtRssRecycleBin(RootItem *parent = 0); virtual ~TtRssRecycleBin(); - - bool empty(); - bool restore(); }; #endif // TTRSSRECYCLEBIN_H From c8d4819270c9083f5a24df4b8c146d59bba6ae54 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 10 Dec 2015 11:30:10 +0100 Subject: [PATCH 167/203] Experimental ability to update read/unread status of messages. --- src/core/message.cpp | 2 +- src/core/message.h | 1 + src/core/messagesmodel.cpp | 21 +++--- src/gui/feedmessageviewer.cpp | 2 +- src/gui/messagesview.cpp | 2 +- src/gui/messagesview.h | 2 +- src/services/abstract/serviceroot.h | 4 +- src/services/standard/standardfeed.cpp | 3 +- src/services/standard/standardserviceroot.cpp | 8 +-- src/services/standard/standardserviceroot.h | 4 +- .../tt-rss/network/ttrssnetworkfactory.cpp | 67 ++++++++++++++++++- .../tt-rss/network/ttrssnetworkfactory.h | 34 +++++++++- src/services/tt-rss/ttrssfeed.cpp | 3 +- src/services/tt-rss/ttrssserviceroot.cpp | 35 +++++++--- src/services/tt-rss/ttrssserviceroot.h | 6 +- 15 files changed, 154 insertions(+), 40 deletions(-) diff --git a/src/core/message.cpp b/src/core/message.cpp index a8e5b22ce..e47791322 100755 --- a/src/core/message.cpp +++ b/src/core/message.cpp @@ -63,6 +63,6 @@ QString Enclosures::encodeEnclosuresToString(const QList &enclosures) Message::Message() { m_title = m_url = m_author = m_contents = m_feedId = m_customId = ""; m_enclosures = QList(); - m_accountId = 0; + m_accountId = m_id = 0; m_isRead = m_isImportant = false; } diff --git a/src/core/message.h b/src/core/message.h index 7459eb0be..a9f9769fb 100755 --- a/src/core/message.h +++ b/src/core/message.h @@ -51,6 +51,7 @@ class Message { QDateTime m_created; QString m_feedId; int m_accountId; + int m_id; QString m_customId; bool m_isRead; diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index cd1fad544..05a22d9eb 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -141,6 +141,7 @@ Message MessagesModel::messageAt(int row_index) const { message.m_url = rec.value(MSG_DB_URL_INDEX).toString(); message.m_feedId = rec.value(MSG_DB_FEED_INDEX).toString(); message.m_accountId = rec.value(MSG_DB_ACCOUNT_ID_INDEX).toInt(); + message.m_id = rec.value(MSG_DB_ID_INDEX).toInt(); message.m_customId = rec.value(MSG_DB_CUSTOM_ID_INDEX).toString(); message.m_created = TextFactory::parseDateTime(rec.value(MSG_DB_DCREATED_INDEX).value()).toLocalTime(); @@ -260,9 +261,9 @@ bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) { return true; } - int message_id = messageId(row_index); + Message message = messageAt(row_index); - if (!m_selectedItem->getParentServiceRoot()->onBeforeSetMessagesRead(m_selectedItem, QList() << message_id, read)) { + if (!m_selectedItem->getParentServiceRoot()->onBeforeSetMessagesRead(m_selectedItem, QList() << message, read)) { // Cannot change read status of the item. Abort. return false; } @@ -284,11 +285,11 @@ bool MessagesModel::setMessageRead(int row_index, RootItem::ReadStatus read) { return false; } - query_read_msg.bindValue(QSL(":id"), message_id); + query_read_msg.bindValue(QSL(":id"), message.m_id); query_read_msg.bindValue(QSL(":read"), (int) read); if (query_read_msg.exec()) { - return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, QList() << message_id, read); + return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, QList() << message, read); } else { return false; @@ -408,17 +409,17 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages) { bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootItem::ReadStatus read) { QStringList message_ids; - QList message_ids_num; + QList msgs; // Obtain IDs of all desired messages. foreach (const QModelIndex &message, messages) { - int message_id = messageId(message.row()); + Message msg = messageAt(message.row()); - message_ids_num.append(message_id); - message_ids.append(QString::number(message_id)); + msgs.append(msg); + message_ids.append(QString::number(msg.m_id)); } - if (!m_selectedItem->getParentServiceRoot()->onBeforeSetMessagesRead(m_selectedItem, message_ids_num, read)) { + if (!m_selectedItem->getParentServiceRoot()->onBeforeSetMessagesRead(m_selectedItem, msgs, read)) { return false; } @@ -429,7 +430,7 @@ bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootIt .arg(message_ids.join(QSL(", ")), read == RootItem::Read ? QSL("1") : QSL("0")))) { fetchAllData(); - return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, message_ids_num, read); + return m_selectedItem->getParentServiceRoot()->onAfterSetMessagesRead(m_selectedItem, msgs, read); } else { return false; diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index c772e7548..75f2e75c1 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -233,7 +233,7 @@ void FeedMessageViewer::createConnections() { connect(qApp->feedUpdateLock(), SIGNAL(unlocked()), this, SLOT(updateFeedButtonsAvailability())); // If user selects feeds, load their messages. - connect(m_feedsView, SIGNAL(itemSelected(RootItem*)), m_messagesView, SLOT(loadFeeds(RootItem*))); + connect(m_feedsView, SIGNAL(itemSelected(RootItem*)), m_messagesView, SLOT(loadItem(RootItem*))); // State of many messages is changed, then we need // to reload selections. diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index e6522062c..0d8ecbf97 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -227,7 +227,7 @@ void MessagesView::selectionChanged(const QItemSelection &selected, const QItemS QTreeView::selectionChanged(selected, deselected); } -void MessagesView::loadFeeds(RootItem *item) { +void MessagesView::loadItem(RootItem *item) { m_sourceModel->loadMessages(item); int col = qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortColumnMessages)).toInt(); diff --git a/src/gui/messagesview.h b/src/gui/messagesview.h index 2d4b6b107..27ea31bf3 100755 --- a/src/gui/messagesview.h +++ b/src/gui/messagesview.h @@ -57,7 +57,7 @@ class MessagesView : public QTreeView { void reloadSelections(bool mark_current_index_read); // Loads un-deleted messages from selected feeds. - void loadFeeds(RootItem *item); + void loadItem(RootItem *item); // Message manipulators. void openSelectedSourceMessagesExternally(); diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index aca550619..5c3212c04 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -93,7 +93,7 @@ class ServiceRoot : public RootItem { // some ONLINE service or something. // // "read" is status which is ABOUT TO BE SET. - virtual bool onBeforeSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read) = 0; + virtual bool onBeforeSetMessagesRead(RootItem *selected_item, const QList &messages, ReadStatus read) = 0; // Called AFTER this read status update (triggered by user in message list) is stored in DB, // when false is returned, change is aborted. @@ -101,7 +101,7 @@ class ServiceRoot : public RootItem { // which items are actually changed. // // "read" is status which is ABOUT TO BE SET. - virtual bool onAfterSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read) = 0; + virtual bool onAfterSetMessagesRead(RootItem *selected_item, const QList &messages, ReadStatus read) = 0; // Called BEFORE this importance switch update is stored in DB, // when false is returned, change is aborted. diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 321884f87..0eeb522b0 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -135,7 +135,7 @@ QList StandardFeed::undeletedMessages() const { QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query_read_msg(database); query_read_msg.setForwardOnly(true); - query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures " + query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures, id " "FROM Messages " "WHERE is_deleted = 0 AND feed = :feed AND account_id = :account_id;"); @@ -156,6 +156,7 @@ QList StandardFeed::undeletedMessages() const { message.m_contents = query_read_msg.value(4).toString(); message.m_accountId = const_cast(this)->serviceRoot()->accountId(); message.m_enclosures = Enclosures::decodeEnclosuresFromString(query_read_msg.value(5).toString()); + message.m_id = query_read_msg.value(6).toInt(); messages.append(message); } diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index bb5d9b6e2..985f93c62 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -504,16 +504,16 @@ bool StandardServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *mo return true; } -bool StandardServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, QList message_db_ids, RootItem::ReadStatus read) { - Q_UNUSED(message_db_ids) +bool StandardServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, const QList &messages, RootItem::ReadStatus read) { + Q_UNUSED(messages) Q_UNUSED(read) Q_UNUSED(selected_item) return true; } -bool StandardServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, QList message_db_ids, RootItem::ReadStatus read) { - Q_UNUSED(message_db_ids) +bool StandardServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, const QList &messages, RootItem::ReadStatus read) { + Q_UNUSED(messages) Q_UNUSED(read) selected_item->updateCounts(false); diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 35d5e0eca..ca782b283 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -63,8 +63,8 @@ class StandardServiceRoot : public ServiceRoot { // Message stuff. bool loadMessagesForItem(RootItem *item, QSqlTableModel *model); - bool onBeforeSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read); - bool onAfterSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read); + bool onBeforeSetMessagesRead(RootItem *selected_item, const QList &messages, ReadStatus read); + bool onAfterSetMessagesRead(RootItem *selected_item, const QList &messages, ReadStatus read); bool onBeforeSwitchMessageImportance(RootItem *selected_item, QList > changes); bool onAfterSwitchMessageImportance(RootItem *selected_item, QList > changes); diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index bfc02ab33..f6cb1159d 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -171,6 +171,44 @@ TtRssGetHeadlinesResponse TtRssNetworkFactory::getHeadlines(int feed_id, bool fo return result; } +TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QList &ids, + UpdateArticle::OperatingField field, + UpdateArticle::Mode mode, + QNetworkReply::NetworkError &error) { + QtJson::JsonObject json; + json["op"] = "updateArticle"; + json["sid"] = m_sessionId; + json["article_ids"] = encodeArticleIds(ids); + json["mode"] = (int) mode; + json["field"] = (int) field; + + QByteArray result_raw; + NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + TtRssUpdateArticleResponse result(QString::fromUtf8(result_raw)); + + if (result.isNotLoggedIn()) { + // We are not logged in. + login(error); + json["sid"] = m_sessionId; + + network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + result = TtRssUpdateArticleResponse(QString::fromUtf8(result_raw)); + } + + error = network_reply.first; + return result; +} + +QString TtRssNetworkFactory::encodeArticleIds(const QList &ids) { + QStringList strings; + + foreach (int id, ids) { + strings.append(QString::number(id)); + } + + return strings.join(QL1C(',')); +} + TtRssResponse::TtRssResponse(const QString &raw_content) { m_rawContent = QtJson::parse(raw_content).toMap(); } @@ -255,7 +293,7 @@ TtRssGetFeedsCategoriesResponse::TtRssGetFeedsCategoriesResponse(const QString & TtRssGetFeedsCategoriesResponse::~TtRssGetFeedsCategoriesResponse() { } -RootItem *TtRssGetFeedsCategoriesResponse::feedsCategories(bool obtain_icons, QString base_address) { +RootItem *TtRssGetFeedsCategoriesResponse::feedsCategories(bool obtain_icons, QString base_address) const { RootItem *parent = new RootItem(); // Chop the "api/" from the end of the address. @@ -342,7 +380,7 @@ TtRssGetHeadlinesResponse::TtRssGetHeadlinesResponse(const QString &raw_content) TtRssGetHeadlinesResponse::~TtRssGetHeadlinesResponse() { } -QList TtRssGetHeadlinesResponse::messages() { +QList TtRssGetHeadlinesResponse::messages() const { QList messages; foreach (QVariant item, m_rawContent["content"].toList()) { @@ -380,3 +418,28 @@ QList TtRssGetHeadlinesResponse::messages() { return messages; } + + +TtRssUpdateArticleResponse::TtRssUpdateArticleResponse(const QString &raw_content) : TtRssResponse(raw_content) { +} + +TtRssUpdateArticleResponse::~TtRssUpdateArticleResponse() { +} + +QString TtRssUpdateArticleResponse::updateStatus() const { + if (m_rawContent.contains(QSL("content"))) { + return m_rawContent["content"].toMap()["status"].toString(); + } + else { + return QString(); + } +} + +int TtRssUpdateArticleResponse::articlesUpdated() const { + if (m_rawContent.contains(QSL("content"))) { + return m_rawContent["content"].toMap()["updated"].toInt(); + } + else { + return 0; + } +} diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.h b/src/services/tt-rss/network/ttrssnetworkfactory.h index ca74fc11e..b7bf159fa 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.h +++ b/src/services/tt-rss/network/ttrssnetworkfactory.h @@ -63,7 +63,7 @@ class TtRssGetFeedsCategoriesResponse : public TtRssResponse { // Returns tree of feeds/categories. // Top-level root of the tree is not needed here. // Returned items do not have primary IDs assigned. - RootItem *feedsCategories(bool obtain_icons, QString base_address = QString()); + RootItem *feedsCategories(bool obtain_icons, QString base_address = QString()) const; }; class TtRssGetHeadlinesResponse : public TtRssResponse { @@ -71,9 +71,32 @@ class TtRssGetHeadlinesResponse : public TtRssResponse { explicit TtRssGetHeadlinesResponse(const QString &raw_content = QString()); virtual ~TtRssGetHeadlinesResponse(); - QList messages(); + QList messages() const; }; +class TtRssUpdateArticleResponse : public TtRssResponse { + public: + explicit TtRssUpdateArticleResponse(const QString &raw_content = QString()); + virtual ~TtRssUpdateArticleResponse(); + + QString updateStatus() const; + int articlesUpdated() const; +}; + +namespace UpdateArticle { + enum Mode { + SetToFalse = 0, + SetToTrue = 1, + Togggle = 2 + }; + + enum OperatingField { + Starred = 0, + Published = 1, + Unread = 2 + }; +} + class TtRssNetworkFactory { public: explicit TtRssNetworkFactory(); @@ -107,7 +130,12 @@ class TtRssNetworkFactory { bool show_content, bool include_attachments, bool sanitize, QNetworkReply::NetworkError &error); - private: + TtRssUpdateArticleResponse updateArticles(const QList &ids, UpdateArticle::OperatingField field, + UpdateArticle::Mode mode, QNetworkReply::NetworkError &error); + + private: + QString encodeArticleIds(const QList &ids); + QString m_url; QString m_username; QString m_password; diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index 0579cf0fb..2dd8ccc48 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -118,7 +118,7 @@ QList TtRssFeed::undeletedMessages() const { QSqlQuery query_read_msg(database); query_read_msg.setForwardOnly(true); - query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures, custom_id " + query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures, custom_id, id " "FROM Messages " "WHERE is_deleted = 0 AND feed = :feed AND account_id = :account_id;"); @@ -140,6 +140,7 @@ QList TtRssFeed::undeletedMessages() const { message.m_enclosures = Enclosures::decodeEnclosuresFromString(query_read_msg.value(5).toString()); message.m_accountId = account_id; message.m_customId = query_read_msg.value(6).toString(); + message.m_id = query_read_msg.value(7).toInt(); messages.append(message); } diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index e076a2b43..02a842b0c 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -24,6 +24,7 @@ #include "services/tt-rss/ttrssserviceentrypoint.h" #include "services/tt-rss/ttrssfeed.h" #include "services/tt-rss/ttrsscategory.h" +#include "services/tt-rss/definitions.h" #include "services/tt-rss/network/ttrssnetworkfactory.h" #include "services/tt-rss/gui/formeditaccount.h" @@ -145,19 +146,25 @@ QList TtRssServiceRoot::contextMenu() { return serviceMenu(); } -bool TtRssServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, QList message_db_ids, RootItem::ReadStatus read) { - // TODO: misto čísel primarnich zprav, vracet cele objekty zprav - // tedy včetně custom ID, nemusi se tak znova tahat z DB asi?s +bool TtRssServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, const QList &messages, RootItem::ReadStatus read) { + Q_UNUSED(selected_item) - // OK, update the messages status online. + QNetworkReply::NetworkError error; + TtRssUpdateArticleResponse response = m_network->updateArticles(customIDsOfMessages(messages), + UpdateArticle::Unread, + read == RootItem::Unread ? UpdateArticle::SetToTrue : UpdateArticle::SetToFalse, + error); - // First obtain, custom IDs of messages. - - return false; + if (error == QNetworkReply::NoError && response.updateStatus() == STATUS_OK && response.articlesUpdated() == messages.size()) { + return true; + } + else { + return false; + } } -bool TtRssServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, QList message_db_ids, RootItem::ReadStatus read) { - Q_UNUSED(message_db_ids) +bool TtRssServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, const QList &messages, RootItem::ReadStatus read) { + Q_UNUSED(messages) Q_UNUSED(read) selected_item->updateCounts(false); @@ -338,6 +345,16 @@ void TtRssServiceRoot::syncIn() { } } +QList TtRssServiceRoot::customIDsOfMessages(const QList &messages) { + QList list; + + foreach (const Message &message, messages) { + list.append(message.m_customId.toInt()); + } + + return list; +} + QStringList TtRssServiceRoot::textualFeedIds(const QList &feeds) { QStringList stringy_ids; stringy_ids.reserve(feeds.size()); diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 96d424b06..4d4b896e3 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -54,8 +54,8 @@ class TtRssServiceRoot : public ServiceRoot { bool loadMessagesForItem(RootItem *item, QSqlTableModel *model); - bool onBeforeSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read); - bool onAfterSetMessagesRead(RootItem *selected_item, QList message_db_ids, ReadStatus read); + bool onBeforeSetMessagesRead(RootItem *selected_item, const QList &messages, ReadStatus read); + bool onAfterSetMessagesRead(RootItem *selected_item, const QList &messages, ReadStatus read); bool onBeforeSwitchMessageImportance(RootItem *selected_item, QList > changes); bool onAfterSwitchMessageImportance(RootItem *selected_item, QList > changes); @@ -77,6 +77,8 @@ class TtRssServiceRoot : public ServiceRoot { void syncIn(); private: + QList customIDsOfMessages(const QList &messages); + // Returns converted ids of given feeds // which are suitable as IN clause for SQL queries. QStringList textualFeedIds(const QList &feeds); From 7bfbdca4e9597ff00ccbc087c91c2442ada086d7 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 10 Dec 2015 12:57:01 +0100 Subject: [PATCH 168/203] Added initial starred status switching. --- src/core/messagesmodel.cpp | 18 ++++---- src/services/abstract/serviceroot.h | 4 +- src/services/standard/standardserviceroot.cpp | 4 +- src/services/standard/standardserviceroot.h | 4 +- .../tt-rss/network/ttrssnetworkfactory.cpp | 14 +----- .../tt-rss/network/ttrssnetworkfactory.h | 4 +- src/services/tt-rss/ttrssserviceroot.cpp | 44 ++++++++++++++++--- src/services/tt-rss/ttrssserviceroot.h | 9 ++-- 8 files changed, 60 insertions(+), 41 deletions(-) diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 05a22d9eb..874324a86 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -301,11 +301,11 @@ bool MessagesModel::switchMessageImportance(int row_index) { RootItem::Importance current_importance = (RootItem::Importance) data(target_index, Qt::EditRole).toInt(); RootItem::Importance next_importance = current_importance == RootItem::Important ? RootItem::NotImportant : RootItem::Important; - int message_id = messageId(row_index); - QPair pair(message_id, next_importance); + Message message = messageAt(row_index); + QPair pair(message, next_importance); if (!m_selectedItem->getParentServiceRoot()->onBeforeSwitchMessageImportance(m_selectedItem, - QList >() << pair)) { + QList >() << pair)) { return false; } @@ -326,14 +326,14 @@ bool MessagesModel::switchMessageImportance(int row_index) { return false; } - query_importance_msg.bindValue(QSL(":id"), message_id); + query_importance_msg.bindValue(QSL(":id"), message.m_id); query_importance_msg.bindValue(QSL(":important"), (int) next_importance); // Commit changes. if (query_importance_msg.exec()) { return m_selectedItem->getParentServiceRoot()->onAfterSwitchMessageImportance(m_selectedItem, - QList >() << pair); + QList >() << pair); } else { return false; @@ -343,17 +343,17 @@ bool MessagesModel::switchMessageImportance(int row_index) { bool MessagesModel::switchBatchMessageImportance(const QModelIndexList &messages) { QSqlQuery query_read_msg(database()); QStringList message_ids; - QList > message_states; + QList > message_states; query_read_msg.setForwardOnly(true); // Obtain IDs of all desired messages. foreach (const QModelIndex &message, messages) { - int message_id = messageId(message.row()); + Message msg = messageAt(message.row()); RootItem::Importance message_importance = messageImportance((message.row())); - message_states.append(QPair(message_id, message_importance)); - message_ids.append(QString::number(message_id)); + message_states.append(QPair(msg, message_importance)); + message_ids.append(QString::number(msg.m_id)); } if (!m_selectedItem->getParentServiceRoot()->onBeforeSwitchMessageImportance(m_selectedItem, message_states)) { diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 5c3212c04..e67dacf7d 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -109,7 +109,7 @@ class ServiceRoot : public RootItem { // some ONLINE service or something. // // "changes" - list of pairs - - virtual bool onBeforeSwitchMessageImportance(RootItem *selected_item, QList > changes) = 0; + virtual bool onBeforeSwitchMessageImportance(RootItem *selected_item, const QList > &changes) = 0; // Called AFTER this importance switch update is stored in DB, // when false is returned, change is aborted. @@ -117,7 +117,7 @@ class ServiceRoot : public RootItem { // which items are actually changed. // // "changes" - list of pairs - - virtual bool onAfterSwitchMessageImportance(RootItem *selected_item, QList > changes) = 0; + virtual bool onAfterSwitchMessageImportance(RootItem *selected_item, const QList > &changes) = 0; // Called BEFORE the list of messages is about to be deleted // by the user from message list. diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 985f93c62..d706f3551 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -524,7 +524,7 @@ bool StandardServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, const } bool StandardServiceRoot::onBeforeSwitchMessageImportance(RootItem *selected_item, - QList > changes) { + const QList > &changes) { Q_UNUSED(selected_item) Q_UNUSED(changes) @@ -532,7 +532,7 @@ bool StandardServiceRoot::onBeforeSwitchMessageImportance(RootItem *selected_ite } bool StandardServiceRoot::onAfterSwitchMessageImportance(RootItem *selected_item, - QList > changes) { + const QList > &changes) { Q_UNUSED(selected_item) Q_UNUSED(changes) diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index ca782b283..4f2b5efdb 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -66,8 +66,8 @@ class StandardServiceRoot : public ServiceRoot { bool onBeforeSetMessagesRead(RootItem *selected_item, const QList &messages, ReadStatus read); bool onAfterSetMessagesRead(RootItem *selected_item, const QList &messages, ReadStatus read); - bool onBeforeSwitchMessageImportance(RootItem *selected_item, QList > changes); - bool onAfterSwitchMessageImportance(RootItem *selected_item, QList > changes); + bool onBeforeSwitchMessageImportance(RootItem *selected_item, const QList > &changes); + bool onAfterSwitchMessageImportance(RootItem *selected_item, const QList > &changes); bool onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids); bool onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids); diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index f6cb1159d..a41073a0d 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -171,14 +171,14 @@ TtRssGetHeadlinesResponse TtRssNetworkFactory::getHeadlines(int feed_id, bool fo return result; } -TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QList &ids, +TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QStringList &ids, UpdateArticle::OperatingField field, UpdateArticle::Mode mode, QNetworkReply::NetworkError &error) { QtJson::JsonObject json; json["op"] = "updateArticle"; json["sid"] = m_sessionId; - json["article_ids"] = encodeArticleIds(ids); + json["article_ids"] = ids.join(QL1C(',')); json["mode"] = (int) mode; json["field"] = (int) field; @@ -199,16 +199,6 @@ TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QList return result; } -QString TtRssNetworkFactory::encodeArticleIds(const QList &ids) { - QStringList strings; - - foreach (int id, ids) { - strings.append(QString::number(id)); - } - - return strings.join(QL1C(',')); -} - TtRssResponse::TtRssResponse(const QString &raw_content) { m_rawContent = QtJson::parse(raw_content).toMap(); } diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.h b/src/services/tt-rss/network/ttrssnetworkfactory.h index b7bf159fa..8c80f5eb6 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.h +++ b/src/services/tt-rss/network/ttrssnetworkfactory.h @@ -130,12 +130,10 @@ class TtRssNetworkFactory { bool show_content, bool include_attachments, bool sanitize, QNetworkReply::NetworkError &error); - TtRssUpdateArticleResponse updateArticles(const QList &ids, UpdateArticle::OperatingField field, + TtRssUpdateArticleResponse updateArticles(const QStringList &ids, UpdateArticle::OperatingField field, UpdateArticle::Mode mode, QNetworkReply::NetworkError &error); private: - QString encodeArticleIds(const QList &ids); - QString m_url; QString m_username; QString m_password; diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 02a842b0c..8dbceeb0f 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -174,12 +174,32 @@ bool TtRssServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, const QLi return true; } -bool TtRssServiceRoot::onBeforeSwitchMessageImportance(RootItem *selected_item, QList > changes) { - return false; +bool TtRssServiceRoot::onBeforeSwitchMessageImportance(RootItem *selected_item, const QList > &changes) { + Q_UNUSED(selected_item) + + QNetworkReply::NetworkError error; + + // NOTE: We just toggle it here, because we know, that there is only + // toggling of starred status supported by RSS Guard right now and + // Tiny Tiny RSS API allows it, which is greate. + TtRssUpdateArticleResponse response = m_network->updateArticles(customIDsOfMessages(changes), + UpdateArticle::Starred, + UpdateArticle::Togggle, + error); + + if (error == QNetworkReply::NoError && response.updateStatus() == STATUS_OK && response.articlesUpdated() == changes.size()) { + return true; + } + else { + return false; + } } -bool TtRssServiceRoot::onAfterSwitchMessageImportance(RootItem *selected_item, QList > changes) { - return false; +bool TtRssServiceRoot::onAfterSwitchMessageImportance(RootItem *selected_item, const QList > &changes) { + Q_UNUSED(selected_item) + Q_UNUSED(changes) + + return true; } bool TtRssServiceRoot::onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids) { @@ -345,11 +365,21 @@ void TtRssServiceRoot::syncIn() { } } -QList TtRssServiceRoot::customIDsOfMessages(const QList &messages) { - QList list; +QStringList TtRssServiceRoot::customIDsOfMessages(const QList > &changes) { + QStringList list; + + for (int i = 0; i < changes.size(); i++) { + list.append(changes.at(i).first.m_customId); + } + + return list; +} + +QStringList TtRssServiceRoot::customIDsOfMessages(const QList &messages) { + QStringList list; foreach (const Message &message, messages) { - list.append(message.m_customId.toInt()); + list.append(message.m_customId); } return list; diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 4d4b896e3..eacd42e34 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -57,8 +57,8 @@ class TtRssServiceRoot : public ServiceRoot { bool onBeforeSetMessagesRead(RootItem *selected_item, const QList &messages, ReadStatus read); bool onAfterSetMessagesRead(RootItem *selected_item, const QList &messages, ReadStatus read); - bool onBeforeSwitchMessageImportance(RootItem *selected_item, QList > changes); - bool onAfterSwitchMessageImportance(RootItem *selected_item, QList > changes); + bool onBeforeSwitchMessageImportance(RootItem *selected_item, const QList > &changes); + bool onAfterSwitchMessageImportance(RootItem *selected_item, const QList > &changes); bool onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids); bool onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids); @@ -76,8 +76,9 @@ class TtRssServiceRoot : public ServiceRoot { public slots: void syncIn(); - private: - QList customIDsOfMessages(const QList &messages); + private: + QStringList customIDsOfMessages(const QList > &changes); + QStringList customIDsOfMessages(const QList &messages); // Returns converted ids of given feeds // which are suitable as IN clause for SQL queries. From 68a93552233ae1727da07a058e266cf047977415 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 10 Dec 2015 13:40:45 +0100 Subject: [PATCH 169/203] Refactored some stuff with messages deleting. --- src/core/messagesmodel.cpp | 12 ++++++------ src/services/abstract/serviceroot.h | 4 ++-- src/services/standard/standardserviceroot.cpp | 8 ++++---- src/services/standard/standardserviceroot.h | 4 ++-- src/services/tt-rss/ttrssserviceroot.cpp | 4 ++-- src/services/tt-rss/ttrssserviceroot.h | 4 ++-- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 874324a86..b55fcdfce 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -372,17 +372,17 @@ bool MessagesModel::switchBatchMessageImportance(const QModelIndexList &messages bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages) { QStringList message_ids; - QList message_ids_num; + QList msgs; // Obtain IDs of all desired messages. foreach (const QModelIndex &message, messages) { - int message_id = messageId(message.row()); + Message msg = messageAt(message.row()); - message_ids_num.append(message_id); - message_ids.append(QString::number(message_id)); + msgs.append(msg); + message_ids.append(QString::number(msg.m_id)); } - if (!m_selectedItem->getParentServiceRoot()->onBeforeMessagesDelete(m_selectedItem, message_ids_num)) { + if (!m_selectedItem->getParentServiceRoot()->onBeforeMessagesDelete(m_selectedItem, msgs)) { return false; } @@ -400,7 +400,7 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages) { if (query_read_msg.exec(sql_delete_query)) { fetchAllData(); - return m_selectedItem->getParentServiceRoot()->onAfterMessagesDelete(m_selectedItem, message_ids_num); + return m_selectedItem->getParentServiceRoot()->onAfterMessagesDelete(m_selectedItem, msgs); } else { return false; diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index e67dacf7d..b3ce5906d 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -121,11 +121,11 @@ class ServiceRoot : public RootItem { // Called BEFORE the list of messages is about to be deleted // by the user from message list. - virtual bool onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids) = 0; + virtual bool onBeforeMessagesDelete(RootItem *selected_item, const QList &messages) = 0; // Called AFTER the list of messages was deleted // by the user from message list. - virtual bool onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids) = 0; + virtual bool onAfterMessagesDelete(RootItem *selected_item, const QList &messages) = 0; // Called BEFORE the list of messages is about to be restored from recycle bin // by the user from message list. diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index d706f3551..ae0363239 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -539,15 +539,15 @@ bool StandardServiceRoot::onAfterSwitchMessageImportance(RootItem *selected_item return true; } -bool StandardServiceRoot::onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids) { +bool StandardServiceRoot::onBeforeMessagesDelete(RootItem *selected_item, const QList &messages) { Q_UNUSED(selected_item) - Q_UNUSED(message_db_ids) + Q_UNUSED(messages) return true; } -bool StandardServiceRoot::onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids) { - Q_UNUSED(message_db_ids) +bool StandardServiceRoot::onAfterMessagesDelete(RootItem *selected_item, const QList &messages) { + Q_UNUSED(messages) // User deleted some messages he selected in message list. selected_item->updateCounts(true); diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 4f2b5efdb..3ea582ba8 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -69,8 +69,8 @@ class StandardServiceRoot : public ServiceRoot { bool onBeforeSwitchMessageImportance(RootItem *selected_item, const QList > &changes); bool onAfterSwitchMessageImportance(RootItem *selected_item, const QList > &changes); - bool onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids); - bool onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids); + bool onBeforeMessagesDelete(RootItem *selected_item, const QList &messages); + bool onAfterMessagesDelete(RootItem *selected_item, const QList &messages); bool onBeforeMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids); bool onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids); diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 8dbceeb0f..ebf0d4241 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -202,11 +202,11 @@ bool TtRssServiceRoot::onAfterSwitchMessageImportance(RootItem *selected_item, c return true; } -bool TtRssServiceRoot::onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids) { +bool TtRssServiceRoot::onBeforeMessagesDelete(RootItem *selected_item, const QList &messages) { return false; } -bool TtRssServiceRoot::onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids) { +bool TtRssServiceRoot::onAfterMessagesDelete(RootItem *selected_item, const QList &messages) { return false; } diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index eacd42e34..61a560a66 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -60,8 +60,8 @@ class TtRssServiceRoot : public ServiceRoot { bool onBeforeSwitchMessageImportance(RootItem *selected_item, const QList > &changes); bool onAfterSwitchMessageImportance(RootItem *selected_item, const QList > &changes); - bool onBeforeMessagesDelete(RootItem *selected_item, QList message_db_ids); - bool onAfterMessagesDelete(RootItem *selected_item, QList message_db_ids); + bool onBeforeMessagesDelete(RootItem *selected_item, const QList &messages); + bool onAfterMessagesDelete(RootItem *selected_item, const QList &messages); bool onBeforeMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids); bool onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids); From c6576ea799b47a6ba78e2ec6d51aa2d98f836520 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 10 Dec 2015 13:46:26 +0100 Subject: [PATCH 170/203] Refactored restoring of messages. --- src/core/messagesmodel.cpp | 12 ++++++------ src/services/abstract/serviceroot.h | 4 ++-- src/services/standard/standardserviceroot.cpp | 6 +++--- src/services/standard/standardserviceroot.h | 4 ++-- src/services/tt-rss/ttrssserviceroot.cpp | 4 ++-- src/services/tt-rss/ttrssserviceroot.h | 4 ++-- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index b55fcdfce..8663f5466 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -439,17 +439,17 @@ bool MessagesModel::setBatchMessagesRead(const QModelIndexList &messages, RootIt bool MessagesModel::setBatchMessagesRestored(const QModelIndexList &messages) { QStringList message_ids; - QList message_ids_num; + QList msgs; // Obtain IDs of all desired messages. foreach (const QModelIndex &message, messages) { - int msg_id = messageId(message.row()); + Message msg = messageAt(message.row()); - message_ids_num.append(msg_id); - message_ids.append(QString::number(msg_id)); + msgs.append(msg); + message_ids.append(QString::number(msg.m_id)); } - if (!m_selectedItem->getParentServiceRoot()->onBeforeMessagesRestoredFromBin(m_selectedItem, message_ids_num)) { + if (!m_selectedItem->getParentServiceRoot()->onBeforeMessagesRestoredFromBin(m_selectedItem, msgs)) { return false; } @@ -461,7 +461,7 @@ bool MessagesModel::setBatchMessagesRestored(const QModelIndexList &messages) { if (query_read_msg.exec(sql_delete_query)) { fetchAllData(); - return m_selectedItem->getParentServiceRoot()->onAfterMessagesRestoredFromBin(m_selectedItem, message_ids_num); + return m_selectedItem->getParentServiceRoot()->onAfterMessagesRestoredFromBin(m_selectedItem, msgs); } else { return false; diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index b3ce5906d..33a839daa 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -130,12 +130,12 @@ class ServiceRoot : public RootItem { // Called BEFORE the list of messages is about to be restored from recycle bin // by the user from message list. // Selected item is naturally recycle bin. - virtual bool onBeforeMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) = 0; + virtual bool onBeforeMessagesRestoredFromBin(RootItem *selected_item, const QList &messages) = 0; // Called AFTER the list of messages was restored from recycle bin // by the user from message list. // Selected item is naturally recycle bin. - virtual bool onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) = 0; + virtual bool onAfterMessagesRestoredFromBin(RootItem *selected_item, const QList &messages) = 0; ///////////////////////////////////////// // Members to override. */ diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index ae0363239..75c403fbf 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -565,13 +565,13 @@ bool StandardServiceRoot::onAfterMessagesDelete(RootItem *selected_item, const Q return true; } -bool StandardServiceRoot::onBeforeMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) { +bool StandardServiceRoot::onBeforeMessagesRestoredFromBin(RootItem *selected_item, const QList &messages) { return true; } -bool StandardServiceRoot::onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) { +bool StandardServiceRoot::onAfterMessagesRestoredFromBin(RootItem *selected_item, const QList &messages) { Q_UNUSED(selected_item) - Q_UNUSED(message_db_ids) + Q_UNUSED(messages) updateCounts(true); itemChanged(getSubTree()); diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 3ea582ba8..31cc877e1 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -72,8 +72,8 @@ class StandardServiceRoot : public ServiceRoot { bool onBeforeMessagesDelete(RootItem *selected_item, const QList &messages); bool onAfterMessagesDelete(RootItem *selected_item, const QList &messages); - bool onBeforeMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids); - bool onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids); + bool onBeforeMessagesRestoredFromBin(RootItem *selected_item, const QList &messages); + bool onAfterMessagesRestoredFromBin(RootItem *selected_item, const QList &messages); // Returns all standard categories which are lying under given root node. // This does NOT include the root node even if the node is category. diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index ebf0d4241..76e20de3a 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -210,11 +210,11 @@ bool TtRssServiceRoot::onAfterMessagesDelete(RootItem *selected_item, const QLis return false; } -bool TtRssServiceRoot::onBeforeMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) { +bool TtRssServiceRoot::onBeforeMessagesRestoredFromBin(RootItem *selected_item, const QList &messages) { return false; } -bool TtRssServiceRoot::onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids) { +bool TtRssServiceRoot::onAfterMessagesRestoredFromBin(RootItem *selected_item, const QList &messages) { return false; } diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 61a560a66..903100cb9 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -63,8 +63,8 @@ class TtRssServiceRoot : public ServiceRoot { bool onBeforeMessagesDelete(RootItem *selected_item, const QList &messages); bool onAfterMessagesDelete(RootItem *selected_item, const QList &messages); - bool onBeforeMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids); - bool onAfterMessagesRestoredFromBin(RootItem *selected_item, QList message_db_ids); + bool onBeforeMessagesRestoredFromBin(RootItem *selected_item, const QList &messages); + bool onAfterMessagesRestoredFromBin(RootItem *selected_item, const QList &messages); TtRssNetworkFactory *network() const; From 32e137492185946d830c9a9de41439676098e71c Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 10 Dec 2015 13:57:40 +0100 Subject: [PATCH 171/203] Refactored some code. --- .../gui/formstandardcategorydetails.cpp | 2 +- .../standard/gui/formstandardfeeddetails.cpp | 5 ++- src/services/standard/standardserviceroot.cpp | 32 ++++--------------- src/services/standard/standardserviceroot.h | 6 +--- 4 files changed, 10 insertions(+), 35 deletions(-) diff --git a/src/services/standard/gui/formstandardcategorydetails.cpp b/src/services/standard/gui/formstandardcategorydetails.cpp index 86c6521a3..5dafa2c3f 100755 --- a/src/services/standard/gui/formstandardcategorydetails.cpp +++ b/src/services/standard/gui/formstandardcategorydetails.cpp @@ -76,7 +76,7 @@ void FormStandardCategoryDetails::setEditableCategory(StandardCategory *editable int FormStandardCategoryDetails::exec(StandardCategory *input_category, RootItem *parent_to_select) { // Load categories. - loadCategories(m_serviceRoot->allCategories().values(), m_serviceRoot, input_category); + loadCategories(m_serviceRoot->allCategories(), m_serviceRoot, input_category); if (input_category == NULL) { // User is adding new category. diff --git a/src/services/standard/gui/formstandardfeeddetails.cpp b/src/services/standard/gui/formstandardfeeddetails.cpp index fa7dd493a..bc720cad6 100755 --- a/src/services/standard/gui/formstandardfeeddetails.cpp +++ b/src/services/standard/gui/formstandardfeeddetails.cpp @@ -61,7 +61,7 @@ FormStandardFeedDetails::~FormStandardFeedDetails() { int FormStandardFeedDetails::exec(StandardFeed *input_feed, RootItem *parent_to_select) { // Load categories. - loadCategories(m_serviceRoot->allCategories().values(), m_serviceRoot); + loadCategories(m_serviceRoot->allCategories(), m_serviceRoot); if (input_feed == NULL) { // User is adding new category. @@ -491,8 +491,7 @@ void FormStandardFeedDetails::loadCategories(const QList cate QVariant::fromValue((void*) root_item)); foreach (StandardCategory *category, categories) { - m_ui->m_cmbParentCategory->addItem(category->data(FDS_MODEL_TITLE_INDEX, - Qt::DecorationRole).value(), + m_ui->m_cmbParentCategory->addItem(category->icon(), category->title(), QVariant::fromValue((void*) category)); } diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 75c403fbf..6f6778072 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -292,35 +292,15 @@ void StandardServiceRoot::loadFromDatabase(){ m_recycleBin->updateCounts(true); } -QHash StandardServiceRoot::categoriesForItem(RootItem *root) { - QHash categories; - QList parents; +QList StandardServiceRoot::allCategories() { + QList cats = getSubTreeCategories(); + QList std_cats; - parents.append(root->childItems()); - - while (!parents.isEmpty()) { - RootItem *item = parents.takeFirst(); - - if (item->kind() == RootItemKind::Category) { - // This item is category, add it to the output list and - // scan its children. - int category_id = item->id(); - StandardCategory *category = static_cast(item); - - if (!categories.contains(category_id)) { - categories.insert(category_id, category); - } - - parents.append(category->childItems()); - } + foreach (Category *category, cats) { + std_cats.append(qobject_cast(category)); } - return categories; -} - -QHash StandardServiceRoot::allCategories() { - // TODO: změnit na qlist, použít getsubtree možná - return categoriesForItem(this); + return std_cats; } QList StandardServiceRoot::getContextMenuForFeed(StandardFeed *feed) { diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 31cc877e1..1a7b62ab0 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -75,13 +75,9 @@ class StandardServiceRoot : public ServiceRoot { bool onBeforeMessagesRestoredFromBin(RootItem *selected_item, const QList &messages); bool onAfterMessagesRestoredFromBin(RootItem *selected_item, const QList &messages); - // Returns all standard categories which are lying under given root node. - // This does NOT include the root node even if the node is category. - QHash categoriesForItem(RootItem *root); - // Returns all categories from this root, each pair // consists of ID of parent item and pointer to category. - QHash allCategories(); + QList allCategories(); // Returns context specific menu actions for given feed. QList getContextMenuForFeed(StandardFeed *feed); From 85ca65bc39414fa03c050c5c17b1f3d5ccb2fe14 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 10 Dec 2015 20:38:39 +0100 Subject: [PATCH 172/203] Fix Qt4 build. --- CMakeLists.txt | 2 -- src/services/tt-rss/network/ttrssnetworkfactory.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b3d3086de..56623674c 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -561,8 +561,6 @@ set(APP_HEADERS # TT-RSS service headers. src/services/tt-rss/ttrssserviceroot.h src/services/tt-rss/ttrssrecyclebin.h - src/services/tt-rss/ttrssfeed.h - src/services/tt-rss/ttrsscategory.h src/services/tt-rss/gui/formeditaccount.h # NETWORK-WEB headers. diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index a41073a0d..9e35e1963 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -178,7 +178,7 @@ TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QStringList QtJson::JsonObject json; json["op"] = "updateArticle"; json["sid"] = m_sessionId; - json["article_ids"] = ids.join(QL1C(',')); + json["article_ids"] = ids.join(QSL(",")); json["mode"] = (int) mode; json["field"] = (int) field; From 43b1aaa1a4ec9afd36379aaa8e6935c2bcffd176 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 11 Dec 2015 07:21:49 +0100 Subject: [PATCH 173/203] General work, will refactore some methods probably now. --- src/core/rootitem.h | 13 ++++++------- src/gui/feedmessageviewer.cpp | 4 ++-- src/services/abstract/recyclebin.cpp | 16 ++++++++++++++-- src/services/abstract/recyclebin.h | 2 ++ src/services/abstract/serviceroot.cpp | 1 - .../tt-rss/network/ttrssnetworkfactory.cpp | 1 - src/services/tt-rss/ttrssserviceroot.cpp | 4 ---- 7 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 9ad382c32..876fe1149 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -32,7 +32,7 @@ namespace RootItemKind { // Describes the kind of the item. enum Kind { Root = 1, - Bin = 2, + Bin = 2, Feed = 4, Category = 8, ServiceRoot = 16 @@ -50,21 +50,20 @@ class RootItem : public QObject { Q_OBJECT public: + // Holds statuses for feeds/messages + // to be marked read/unread. enum ReadStatus { Unread = 0, Read = 1 }; + // Holds statuses for messages + // to be switched importance (starred). enum Importance { NotImportant = 0, Important = 1 }; - enum CleanStatus { - Clean, - Unclean - }; - // Constructors and destructors. explicit RootItem(RootItem *parent_item = NULL); virtual ~RootItem(); @@ -104,7 +103,7 @@ class RootItem : public QObject { // What "clean" means? It means delete messages -> move them to recycle bin // or eventually remove them completely if there is no recycle bin functionality. // If this method is called on "recycle bin" instance of your - // service account, it should NOT do anything. + // service account, it should "empty" the recycle bin. virtual bool cleanMessages(bool clear_only_read); // Updates counts of all/unread messages for this feed. diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 75f2e75c1..45c135a7c 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -202,7 +202,7 @@ void FeedMessageViewer::updateFeedButtonsAvailability() { form_main->m_ui->m_actionBackupDatabaseSettings->setEnabled(!critical_action_running); form_main->m_ui->m_actionCleanupDatabase->setEnabled(!critical_action_running); - form_main->m_ui->m_actionClearSelectedItems->setEnabled(feed_selected || category_selected || service_selected); + form_main->m_ui->m_actionClearSelectedItems->setEnabled(anything_selected); form_main->m_ui->m_actionDeleteSelectedItem->setEnabled(!critical_action_running && anything_selected); form_main->m_ui->m_actionEditSelectedItem->setEnabled(!critical_action_running && anything_selected); form_main->m_ui->m_actionMarkSelectedItemsAsRead->setEnabled(anything_selected); @@ -210,7 +210,7 @@ void FeedMessageViewer::updateFeedButtonsAvailability() { form_main->m_ui->m_actionUpdateAllItems->setEnabled(!critical_action_running); form_main->m_ui->m_actionUpdateSelectedItems->setEnabled(!critical_action_running && (feed_selected || category_selected || service_selected)); form_main->m_ui->m_actionViewSelectedItemsNewspaperMode->setEnabled(feed_selected || category_selected || service_selected); - form_main->m_ui->m_actionExpandCollapseItem->setEnabled(feed_selected || category_selected || service_selected); + form_main->m_ui->m_actionExpandCollapseItem->setEnabled(anything_selected); form_main->m_ui->m_menuAddItem->setEnabled(!critical_action_running); form_main->m_ui->m_menuRecycleBin->setEnabled(!critical_action_running); } diff --git a/src/services/abstract/recyclebin.cpp b/src/services/abstract/recyclebin.cpp index 9b97fcfa2..051c7f37c 100755 --- a/src/services/abstract/recyclebin.cpp +++ b/src/services/abstract/recyclebin.cpp @@ -127,7 +127,7 @@ bool RecycleBin::markAsReadUnread(RootItem::ReadStatus status) { } } -bool RecycleBin::empty() { +bool RecycleBin::cleanMessages(bool clear_only_read) { QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); if (!db_handle.transaction()) { @@ -139,7 +139,15 @@ bool RecycleBin::empty() { QSqlQuery query_empty_bin(db_handle); query_empty_bin.setForwardOnly(true); - query_empty_bin.prepare(QSL("UPDATE Messages SET is_pdeleted = 1 WHERE is_deleted = 1 AND account_id = :account_id;")); + + if (clear_only_read) { + query_empty_bin.prepare("UPDATE Messages SET is_pdeleted = 1 " + "WHERE is_read = 1 AND is_deleted = 1 AND account_id = :account_id;"); + } + else { + query_empty_bin.prepare(QSL("UPDATE Messages SET is_pdeleted = 1 WHERE is_deleted = 1 AND account_id = :account_id;")); + } + query_empty_bin.bindValue(QSL(":account_id"), parent_root->accountId()); if (!query_empty_bin.exec()) { @@ -161,6 +169,10 @@ bool RecycleBin::empty() { } } +bool RecycleBin::empty() { + return cleanMessages(false); +} + bool RecycleBin::restore() { QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); diff --git a/src/services/abstract/recyclebin.h b/src/services/abstract/recyclebin.h index 386601da8..c494aeecc 100755 --- a/src/services/abstract/recyclebin.h +++ b/src/services/abstract/recyclebin.h @@ -31,6 +31,8 @@ class RecycleBin : public RootItem { QVariant data(int column, int role) const; bool markAsReadUnread(ReadStatus status); + bool cleanMessages(bool clear_only_read); + int countOfUnreadMessages() const; int countOfAllMessages() const; diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index c3c9413a3..cc454b411 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -133,4 +133,3 @@ void ServiceRoot::assembleCategories(Assignment categories) { } } } - diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index 9e35e1963..3c0b3d263 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -351,7 +351,6 @@ RootItem *TtRssGetFeedsCategoriesResponse::feedsCategories(bool obtain_icons, QS } } - // TODO: stahnout a nastavit ikonu feed->setTitle(item["name"].toString()); feed->setCustomId(item_id); act_parent->appendChild(feed); diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 76e20de3a..0f2714c47 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -268,8 +268,6 @@ void TtRssServiceRoot::saveAccountDataToDatabase() { } void TtRssServiceRoot::loadFromDatabase() { - // TODO: Load feeds/categories from DB. - QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); Assignment categories; Assignment feeds; @@ -444,7 +442,6 @@ void TtRssServiceRoot::storeNewFeedTree(RootItem *root) { child->setId(query_category.lastInsertId().toInt()); } else { - // TODO: logovat } } else if (child->kind() == RootItemKind::Feed) { @@ -463,7 +460,6 @@ void TtRssServiceRoot::storeNewFeedTree(RootItem *root) { feed->setId(query_feed.lastInsertId().toInt()); } else { - // TODO: logovat. } } } From 46a3f9f57a480639464925ffd7d110420f8d2d34 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 11 Dec 2015 09:13:48 +0100 Subject: [PATCH 174/203] Some tiny fixes. Thinking about something. --- src/services/abstract/recyclebin.h | 1 - src/services/standard/standardserviceroot.cpp | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/services/abstract/recyclebin.h b/src/services/abstract/recyclebin.h index c494aeecc..e192e80f9 100755 --- a/src/services/abstract/recyclebin.h +++ b/src/services/abstract/recyclebin.h @@ -33,7 +33,6 @@ class RecycleBin : public RootItem { bool markAsReadUnread(ReadStatus status); bool cleanMessages(bool clear_only_read); - int countOfUnreadMessages() const; int countOfAllMessages() const; diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 6f6778072..d3315adab 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -546,6 +546,9 @@ bool StandardServiceRoot::onAfterMessagesDelete(RootItem *selected_item, const Q } bool StandardServiceRoot::onBeforeMessagesRestoredFromBin(RootItem *selected_item, const QList &messages) { + Q_UNUSED(selected_item) + Q_UNUSED(messages) + return true; } From 7e42e17046b0d5787ef6c603cf8eb5174ca953ef Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 11 Dec 2015 09:45:01 +0100 Subject: [PATCH 175/203] More efficient marking as read/unread for standard plugin. --- src/services/standard/standardserviceroot.cpp | 34 ++++++++++++++++++- src/services/standard/standardserviceroot.h | 6 +++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index d3315adab..7a51f291b 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -117,6 +117,38 @@ bool StandardServiceRoot::deleteViaGui() { return ServiceRoot::deleteViaGui(); } +bool StandardServiceRoot::markAsReadUnread(RootItem::ReadStatus status) { + QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + + if (!db_handle.transaction()) { + qWarning("Starting transaction for feeds read change."); + return false; + } + + QSqlQuery query_read_msg(db_handle); + query_read_msg.setForwardOnly(true); + query_read_msg.prepare(QSL("UPDATE Messages SET is_read = :read WHERE is_pdeleted = 0 AND account_id = :account_id;")); + + query_read_msg.bindValue(QSL(":account_id"), accountId()); + query_read_msg.bindValue(QSL(":read"), status == RootItem::Read ? 1 : 0); + + if (!query_read_msg.exec()) { + qDebug("Query execution for feeds read change failed."); + db_handle.rollback(); + } + + // Commit changes. + if (db_handle.commit()) { + updateCounts(false); + itemChanged(getSubTree()); + requestReloadMessageList(status == RootItem::Read); + return true; + } + else { + return db_handle.rollback(); + } +} + QVariant StandardServiceRoot::data(int column, int role) const { switch (role) { case Qt::ToolTipRole: @@ -172,7 +204,7 @@ bool StandardServiceRoot::markFeedsReadUnread(QList items, ReadStatus rea QList itemss; foreach (Feed *feed, items) { - feed->updateCounts(true); + feed->updateCounts(false); itemss.append(feed); } diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 1a7b62ab0..95425dc20 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -47,17 +47,21 @@ class StandardServiceRoot : public ServiceRoot { bool canBeDeleted(); bool deleteViaGui(); + bool markAsReadUnread(ReadStatus status); + QVariant data(int column, int role) const; Qt::ItemFlags additionalFlags() const; + // Access to recycle bin. RecycleBin *recycleBin(); // Return "add feed" and "add category" items. QList addItemMenu(); - // Return menu to be shown in "Services -> service" menu. + // Returns menu to be shown in "Services -> service" menu. QList serviceMenu(); + // Returns context menu. QList contextMenu(); // Message stuff. From 8708d7b3050f632653a3382bde7ddfbc6619cd5d Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 11 Dec 2015 09:58:13 +0100 Subject: [PATCH 176/203] RootItem class files moved. --- CMakeLists.txt | 4 +- src/core/feedsmodel.h | 2 +- src/core/feedsproxymodel.cpp | 2 +- src/core/feedsproxymodel.h | 3 +- src/core/messagesmodel.h | 2 +- src/core/rootitem.cpp | 373 ------------------ src/core/rootitem.h | 274 ------------- src/gui/feedsview.cpp | 2 +- src/gui/messagesview.h | 2 +- src/services/abstract/category.h | 2 +- src/services/abstract/feed.h | 2 +- src/services/abstract/recyclebin.h | 2 +- src/services/abstract/serviceroot.h | 2 +- .../gui/formstandardcategorydetails.cpp | 2 +- .../standard/gui/formstandardfeeddetails.cpp | 2 +- .../standard/standardfeedsimportexportmodel.h | 2 +- .../tt-rss/network/ttrssnetworkfactory.cpp | 2 +- 17 files changed, 16 insertions(+), 664 deletions(-) delete mode 100755 src/core/rootitem.cpp delete mode 100755 src/core/rootitem.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 56623674c..1027f8d9a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -413,12 +413,12 @@ set(APP_SOURCES src/core/messagesproxymodel.cpp src/core/feedsmodel.cpp src/core/feedsproxymodel.cpp - src/core/rootitem.cpp src/core/parsingfactory.cpp src/core/feeddownloader.cpp src/core/message.cpp # ABSTRACT service sources. + src/services/abstract/rootitem.cpp src/services/abstract/serviceentrypoint.cpp src/services/abstract/feed.cpp src/services/abstract/category.cpp @@ -540,9 +540,9 @@ set(APP_HEADERS src/core/feedsmodel.h src/core/feedsproxymodel.h src/core/feeddownloader.h - src/core/rootitem.h # ABSTRACT service headers. + src/services/abstract/rootitem.h src/services/abstract/feed.h src/services/abstract/category.h src/services/abstract/serviceroot.h diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index b561aa506..4379ce681 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -21,7 +21,7 @@ #include #include "core/message.h" -#include "core/rootitem.h" +#include "services/abstract/rootitem.h" #include "core/feeddownloader.h" class DatabaseCleaner; diff --git a/src/core/feedsproxymodel.cpp b/src/core/feedsproxymodel.cpp index 445bd71c3..ea1504d91 100755 --- a/src/core/feedsproxymodel.cpp +++ b/src/core/feedsproxymodel.cpp @@ -20,7 +20,7 @@ #include "definitions/definitions.h" #include "miscellaneous/application.h" #include "core/feedsmodel.h" -#include "core/rootitem.h" +#include "services/abstract/rootitem.h" #include "services/standard/standardcategory.h" #include "services/standard/standardfeed.h" diff --git a/src/core/feedsproxymodel.h b/src/core/feedsproxymodel.h index b8c1a6fef..9abd57770 100755 --- a/src/core/feedsproxymodel.h +++ b/src/core/feedsproxymodel.h @@ -18,12 +18,11 @@ #ifndef FEEDSPROXYMODEL_H #define FEEDSPROXYMODEL_H -#include "rootitem.h" - #include class FeedsModel; +class RootItem; class FeedsProxyModel : public QSortFilterProxyModel { Q_OBJECT diff --git a/src/core/messagesmodel.h b/src/core/messagesmodel.h index 872d92afa..9a77938c7 100755 --- a/src/core/messagesmodel.h +++ b/src/core/messagesmodel.h @@ -21,7 +21,7 @@ #include "definitions/definitions.h" #include "core/message.h" -#include "core/rootitem.h" +#include "services/abstract/rootitem.h" #include #include diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp deleted file mode 100755 index 60f7482ed..000000000 --- a/src/core/rootitem.cpp +++ /dev/null @@ -1,373 +0,0 @@ -// This file is part of RSS Guard. -// -// Copyright (C) 2011-2015 by Martin Rotter -// -// RSS Guard is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// RSS Guard is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with RSS Guard. If not, see . - -#include "core/rootitem.h" - -#include "services/abstract/serviceroot.h" -#include "services/abstract/feed.h" -#include "services/abstract/category.h" -#include "miscellaneous/application.h" - -#include - - -RootItem::RootItem(RootItem *parent_item) - : QObject(NULL), - m_kind(RootItemKind::Root), - m_id(NO_PARENT_CATEGORY), - m_title(QString()), - m_description(QString()), - m_icon(QIcon()), - m_creationDate(QDateTime()), - m_childItems(QList()), - m_parentItem(parent_item) { - setupFonts(); -} - -RootItem::~RootItem() { - qDeleteAll(m_childItems); -} - -QList RootItem::contextMenu() { - return QList(); -} - -bool RootItem::canBeEdited() { - return false; -} - -bool RootItem::editViaGui() { - return false; -} - -bool RootItem::canBeDeleted() { - return false; -} - -bool RootItem::deleteViaGui() { - return false; -} - -bool RootItem::canBeMarkedAsReadUnread(ReadStatus status) { - return true; -} - -bool RootItem::markAsReadUnread(ReadStatus status) { - bool result = true; - - foreach (RootItem *child, m_childItems) { - if (child->canBeMarkedAsReadUnread(status)) { - result &= child->markAsReadUnread(status); - } - } - - return result; -} - -bool RootItem::cleanMessages(bool clear_only_read) { - bool result = true; - - foreach (RootItem *child, m_childItems) { - result &= child->cleanMessages(clear_only_read); - } - - return result; -} - -void RootItem::updateCounts(bool including_total_count) { - foreach (RootItem *child, m_childItems) { - child->updateCounts(including_total_count); - } -} - -void RootItem::setupFonts() { - m_normalFont = Application::font("FeedsView"); - m_boldFont = m_normalFont; - m_boldFont.setBold(true); -} - -int RootItem::row() const { - if (m_parentItem) { - return m_parentItem->m_childItems.indexOf(const_cast(this)); - } - else { - // This item has no parent. Therefore, its row index is 0. - return 0; - } -} - -QVariant RootItem::data(int column, int role) const { - Q_UNUSED(column) - Q_UNUSED(role) - - switch (role) { - case Qt::ToolTipRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return m_title; - } - else if (column == FDS_MODEL_COUNTS_INDEX) { - //: Tooltip for "unread" column of feed list. - return tr("%n unread message(s).", 0, countOfUnreadMessages()); - } - else { - return QVariant(); - } - - case Qt::EditRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return m_title; - } - else if (column == FDS_MODEL_COUNTS_INDEX) { - return countOfUnreadMessages(); - } - else { - return QVariant(); - } - - case Qt::FontRole: - return countOfUnreadMessages() > 0 ? m_boldFont : m_normalFont; - - case Qt::DisplayRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return m_title; - } - else if (column == FDS_MODEL_COUNTS_INDEX) { - int count_all = countOfAllMessages(); - int count_unread = countOfUnreadMessages(); - - return qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::CountFormat)).toString() - .replace(PLACEHOLDER_UNREAD_COUNTS, count_unread < 0 ? QSL("-") : QString::number(count_unread)) - .replace(PLACEHOLDER_ALL_COUNTS, count_all < 0 ? QSL("-") : QString::number(count_all)); - } - else { - return QVariant(); - } - - case Qt::DecorationRole: - if (column == FDS_MODEL_TITLE_INDEX) { - return icon(); - } - else { - return QVariant(); - } - - case Qt::TextAlignmentRole: - if (column == FDS_MODEL_COUNTS_INDEX) { - return Qt::AlignCenter; - } - else { - return QVariant(); - } - - default: - return QVariant(); - } -} - -Qt::ItemFlags RootItem::additionalFlags() const { - return Qt::NoItemFlags; -} - -bool RootItem::performDragDropChange(RootItem *target_item) { - return false; -} - -int RootItem::countOfAllMessages() const { - int total_count = 0; - - foreach (RootItem *child_item, m_childItems) { - total_count += child_item->countOfAllMessages(); - } - - return total_count; -} - -bool RootItem::isChildOf(RootItem *root) { - if (root == NULL) { - return false; - } - - RootItem *this_item = this; - - while (this_item->kind() != RootItemKind::Root) { - if (root->childItems().contains(this_item)) { - return true; - } - else { - this_item = this_item->parent(); - } - } - - return false; -} - -bool RootItem::isParentOf(RootItem *child) { - if (child == NULL) { - return false; - } - else { - return child->isChildOf(this); - } -} - -QList RootItem::getSubTree() { - QList children; - QList traversable_items; - - traversable_items.append(this); - - // Iterate all nested items. - while (!traversable_items.isEmpty()) { - RootItem *active_item = traversable_items.takeFirst(); - - children.append(active_item); - traversable_items.append(active_item->childItems()); - } - - return children; -} - -QList RootItem::getSubTree(RootItemKind::Kind kind_of_item) { - QList children; - QList traversable_items; - - traversable_items.append(this); - - // Iterate all nested items. - while (!traversable_items.isEmpty()) { - RootItem *active_item = traversable_items.takeFirst(); - - if ((active_item->kind() & kind_of_item) > 0) { - children.append(active_item); - } - - traversable_items.append(active_item->childItems()); - } - - return children; -} - -QList RootItem::getSubTreeCategories() { - QList children; - QList traversable_items; - - traversable_items.append(this); - - // Iterate all nested items. - while (!traversable_items.isEmpty()) { - RootItem *active_item = traversable_items.takeFirst(); - - if (active_item->kind() == RootItemKind::Category) { - children.append(active_item->toCategory()); - } - - traversable_items.append(active_item->childItems()); - } - - return children; -} - -QHash RootItem::getHashedSubTreeCategories() { - QHash children; - QList traversable_items; - - traversable_items.append(this); - - // Iterate all nested items. - while (!traversable_items.isEmpty()) { - RootItem *active_item = traversable_items.takeFirst(); - - if (active_item->kind() == RootItemKind::Category && !children.contains(active_item->id())) { - children.insert(active_item->id(), active_item->toCategory()); - } - - traversable_items.append(active_item->childItems()); - } - - return children; -} - -QList RootItem::getSubTreeFeeds() { - QList children; - QList traversable_items; - - traversable_items.append(this); - - // Iterate all nested items. - while (!traversable_items.isEmpty()) { - RootItem *active_item = traversable_items.takeFirst(); - - if (active_item->kind() == RootItemKind::Feed) { - children.append(active_item->toFeed()); - } - - traversable_items.append(active_item->childItems()); - } - - return children; -} - -ServiceRoot *RootItem::getParentServiceRoot() { - RootItem *working_parent = this; - - while (working_parent->kind() != RootItemKind::Root) { - if (working_parent->kind() == RootItemKind::ServiceRoot) { - return working_parent->toServiceRoot(); - } - else { - working_parent = working_parent->parent(); - } - } - - return NULL; -} - -bool RootItem::removeChild(RootItem *child) { - return m_childItems.removeOne(child); -} - -Category *RootItem::toCategory() { - return static_cast(this); -} - -Feed *RootItem::toFeed() { - return static_cast(this); -} - -ServiceRoot *RootItem::toServiceRoot() { - return static_cast(this); -} - -int RootItem::countOfUnreadMessages() const { - int total_count = 0; - - foreach (RootItem *child_item, m_childItems) { - total_count += child_item->countOfUnreadMessages(); - } - - return total_count; -} - -bool RootItem::removeChild(int index) { - if (index >= 0 && index < m_childItems.size()) { - m_childItems.removeAt(index); - return true; - } - else { - return false; - } -} diff --git a/src/core/rootitem.h b/src/core/rootitem.h deleted file mode 100755 index 876fe1149..000000000 --- a/src/core/rootitem.h +++ /dev/null @@ -1,274 +0,0 @@ -// This file is part of RSS Guard. -// -// Copyright (C) 2011-2015 by Martin Rotter -// -// RSS Guard is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// RSS Guard is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with RSS Guard. If not, see . - -#ifndef ROOTITEM_H -#define ROOTITEM_H - -#include -#include -#include - - -class Category; -class Feed; -class ServiceRoot; -class QAction; - -namespace RootItemKind { - // Describes the kind of the item. - enum Kind { - Root = 1, - Bin = 2, - Feed = 4, - Category = 8, - ServiceRoot = 16 - }; - - inline Kind operator|(Kind a, Kind b) { - return static_cast(static_cast(a) | static_cast(b)); - } -} - -// Represents ROOT item of FeedsModel. -// NOTE: This class is derived to add functionality for -// all other non-root items of FeedsModel. -class RootItem : public QObject { - Q_OBJECT - - public: - // Holds statuses for feeds/messages - // to be marked read/unread. - enum ReadStatus { - Unread = 0, - Read = 1 - }; - - // Holds statuses for messages - // to be switched importance (starred). - enum Importance { - NotImportant = 0, - Important = 1 - }; - - // Constructors and destructors. - explicit RootItem(RootItem *parent_item = NULL); - virtual ~RootItem(); - - ///////////////////////////////////////// - // /* Members to override. - ///////////////////////////////////////// - - // Returns list of specific actions which can be done with the item. - // Do not include general actions here like actions: Mark as read, Update, ... - // NOTE: Ownership of returned actions is not switched to caller, free them when needed. - virtual QList contextMenu(); - - // Can properties of this item be edited? - virtual bool canBeEdited(); - - // Performs editing of properties of this item (probably via dialog) - // and returns result status. - virtual bool editViaGui(); - - // Can the item be deleted? - virtual bool canBeDeleted(); - - // Performs deletion of the item, this - // method should NOT display any additional dialogs. - // Returns result status. - virtual bool deleteViaGui(); - - // Can this item be marked read/unread? - virtual bool canBeMarkedAsReadUnread(ReadStatus status); - - // Performs all needed steps (DB update, remote server update) - // to mark this item as read/unread. - virtual bool markAsReadUnread(ReadStatus status); - - // This method should "clean" all messages it contains. - // What "clean" means? It means delete messages -> move them to recycle bin - // or eventually remove them completely if there is no recycle bin functionality. - // If this method is called on "recycle bin" instance of your - // service account, it should "empty" the recycle bin. - virtual bool cleanMessages(bool clear_only_read); - - // Updates counts of all/unread messages for this feed. - virtual void updateCounts(bool including_total_count); - - virtual int row() const; - virtual QVariant data(int column, int role) const; - virtual Qt::ItemFlags additionalFlags() const; - virtual bool performDragDropChange(RootItem *target_item); - - // Each item offers "counts" of messages. - // Returns counts of messages of all child items summed up. - virtual int countOfUnreadMessages() const; - virtual int countOfAllMessages() const; - - ///////////////////////////////////////// - // Members to override. */ - ///////////////////////////////////////// - - inline RootItem *parent() const { - return m_parentItem; - } - - inline void setParent(RootItem *parent_item) { - m_parentItem = parent_item; - } - - inline RootItem *child(int row) { - return m_childItems.value(row); - } - - inline int childCount() const { - return m_childItems.size(); - } - - inline void appendChild(RootItem *child) { - m_childItems.append(child); - child->setParent(this); - } - - // Access to children. - inline QList childItems() const { - return m_childItems; - } - - // Removes all children from this item. - // NOTE: Children are NOT freed from the memory. - inline void clearChildren() { - m_childItems.clear(); - } - - inline void setChildItems(QList child_items) { - m_childItems = child_items; - } - - // Removes particular child at given index. - // NOTE: Child is NOT freed from the memory. - bool removeChild(int index); - bool removeChild(RootItem *child); - - // Checks whether "this" object is child (direct or indirect) - // of the given root. - bool isChildOf(RootItem *root); - - // Is "this" item parent (direct or indirect) if given child? - bool isParentOf(RootItem *child); - - // Returns flat list of all items from subtree where this item is a root. - // Returned list includes this item too. - QList getSubTree(); - QList getSubTree(RootItemKind::Kind kind_of_item); - QList getSubTreeCategories(); - QHash getHashedSubTreeCategories(); - QList getSubTreeFeeds(); - - // Returns the service root node which is direct or indirect parent of current item. - ServiceRoot *getParentServiceRoot(); - - inline RootItemKind::Kind kind() const { - return m_kind; - } - - inline void setKind(RootItemKind::Kind kind) { - m_kind = kind; - } - - // Each item can have icon. - inline QIcon icon() const { - return m_icon; - } - - inline void setIcon(const QIcon &icon) { - m_icon = icon; - } - - // Each item has some kind of id. Usually taken from primary key attribute from DB. - inline int id() const { - return m_id; - } - - inline void setId(int id) { - m_id = id; - } - - // Each item has its title. - inline QString title() const { - return m_title; - } - - inline void setTitle(const QString &title) { - m_title = title; - } - - inline QDateTime creationDate() const { - return m_creationDate; - } - - inline void setCreationDate(const QDateTime &creation_date) { - m_creationDate = creation_date; - } - - inline QString description() const { - return m_description; - } - - inline void setDescription(const QString &description) { - m_description = description; - } - - inline QFont normalFont() const { - return m_normalFont; - } - - inline void setNormalFont(const QFont &normal_font) { - m_normalFont = normal_font; - } - - inline QFont boldFont() const { - return m_boldFont; - } - - inline void setBoldFont(const QFont &bold_font) { - m_boldFont = bold_font; - } - - // Converters - Category *toCategory(); - Feed *toFeed(); - ServiceRoot *toServiceRoot(); - - private: - void setupFonts(); - - RootItemKind::Kind m_kind; - int m_id; - QString m_title; - QString m_description; - QIcon m_icon; - QDateTime m_creationDate; - - QFont m_normalFont; - QFont m_boldFont; - - QList m_childItems; - RootItem *m_parentItem; -}; - -#endif // ROOTITEM_H diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 39a48d211..fa51aee30 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -20,7 +20,7 @@ #include "definitions/definitions.h" #include "core/feedsmodel.h" #include "core/feedsproxymodel.h" -#include "core/rootitem.h" +#include "services/abstract/rootitem.h" #include "miscellaneous/systemfactory.h" #include "miscellaneous/mutex.h" #include "gui/systemtrayicon.h" diff --git a/src/gui/messagesview.h b/src/gui/messagesview.h index 27ea31bf3..991a24d58 100755 --- a/src/gui/messagesview.h +++ b/src/gui/messagesview.h @@ -20,7 +20,7 @@ #include "core/messagesmodel.h" -#include "core/rootitem.h" +#include "services/abstract/rootitem.h" #include #include diff --git a/src/services/abstract/category.h b/src/services/abstract/category.h index 961eed509..ea339831a 100755 --- a/src/services/abstract/category.h +++ b/src/services/abstract/category.h @@ -18,7 +18,7 @@ #ifndef CATEGORY_H #define CATEGORY_H -#include "core/rootitem.h" +#include "services/abstract/rootitem.h" class Category : public RootItem { diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index aaed9266a..d17befd84 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -18,7 +18,7 @@ #ifndef FEED_H #define FEED_H -#include "core/rootitem.h" +#include "services/abstract/rootitem.h" #include "core/message.h" diff --git a/src/services/abstract/recyclebin.h b/src/services/abstract/recyclebin.h index e192e80f9..4d702d8ac 100755 --- a/src/services/abstract/recyclebin.h +++ b/src/services/abstract/recyclebin.h @@ -18,7 +18,7 @@ #ifndef RECYCLEBIN_H #define RECYCLEBIN_H -#include "core/rootitem.h" +#include "services/abstract/rootitem.h" class RecycleBin : public RootItem { diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 33a839daa..9cc47dfc4 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -18,7 +18,7 @@ #ifndef SERVICEROOT_H #define SERVICEROOT_H -#include "core/rootitem.h" +#include "services/abstract/rootitem.h" #include "core/message.h" diff --git a/src/services/standard/gui/formstandardcategorydetails.cpp b/src/services/standard/gui/formstandardcategorydetails.cpp index 5dafa2c3f..00e0664d6 100755 --- a/src/services/standard/gui/formstandardcategorydetails.cpp +++ b/src/services/standard/gui/formstandardcategorydetails.cpp @@ -18,7 +18,7 @@ #include "services/standard/gui/formstandardcategorydetails.h" #include "definitions/definitions.h" -#include "core/rootitem.h" +#include "services/abstract/rootitem.h" #include "core/feedsmodel.h" #include "miscellaneous/iconfactory.h" #include "gui/feedsview.h" diff --git a/src/services/standard/gui/formstandardfeeddetails.cpp b/src/services/standard/gui/formstandardfeeddetails.cpp index bc720cad6..84ac02b9a 100755 --- a/src/services/standard/gui/formstandardfeeddetails.cpp +++ b/src/services/standard/gui/formstandardfeeddetails.cpp @@ -19,7 +19,7 @@ #include "definitions/definitions.h" #include "core/feedsmodel.h" -#include "core/rootitem.h" +#include "services/abstract/rootitem.h" #include "services/standard/standardserviceroot.h" #include "services/standard/standardcategory.h" #include "services/standard/standardfeed.h" diff --git a/src/services/standard/standardfeedsimportexportmodel.h b/src/services/standard/standardfeedsimportexportmodel.h index e5bc8c54f..3fc5aa9c3 100755 --- a/src/services/standard/standardfeedsimportexportmodel.h +++ b/src/services/standard/standardfeedsimportexportmodel.h @@ -20,7 +20,7 @@ #include -#include "core/rootitem.h" +#include "services/abstract/rootitem.h" class FeedsImportExportModel : public QAbstractItemModel { diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index 3c0b3d263..f3d1986f9 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -18,7 +18,7 @@ #include "services/tt-rss/network/ttrssnetworkfactory.h" #include "definitions/definitions.h" -#include "core/rootitem.h" +#include "services/abstract/rootitem.h" #include "services/tt-rss/definitions.h" #include "services/tt-rss/ttrssfeed.h" #include "services/tt-rss/ttrsscategory.h" From fe9efa62024cbc4d958588de10b297b54e62d8bd Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 11 Dec 2015 09:58:55 +0100 Subject: [PATCH 177/203] Added new files. --- src/services/abstract/rootitem.cpp | 373 +++++++++++++++++++++++++++++ src/services/abstract/rootitem.h | 274 +++++++++++++++++++++ 2 files changed, 647 insertions(+) create mode 100755 src/services/abstract/rootitem.cpp create mode 100755 src/services/abstract/rootitem.h diff --git a/src/services/abstract/rootitem.cpp b/src/services/abstract/rootitem.cpp new file mode 100755 index 000000000..d9c4ca476 --- /dev/null +++ b/src/services/abstract/rootitem.cpp @@ -0,0 +1,373 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#include "services/abstract/rootitem.h" + +#include "services/abstract/serviceroot.h" +#include "services/abstract/feed.h" +#include "services/abstract/category.h" +#include "miscellaneous/application.h" + +#include + + +RootItem::RootItem(RootItem *parent_item) + : QObject(NULL), + m_kind(RootItemKind::Root), + m_id(NO_PARENT_CATEGORY), + m_title(QString()), + m_description(QString()), + m_icon(QIcon()), + m_creationDate(QDateTime()), + m_childItems(QList()), + m_parentItem(parent_item) { + setupFonts(); +} + +RootItem::~RootItem() { + qDeleteAll(m_childItems); +} + +QList RootItem::contextMenu() { + return QList(); +} + +bool RootItem::canBeEdited() { + return false; +} + +bool RootItem::editViaGui() { + return false; +} + +bool RootItem::canBeDeleted() { + return false; +} + +bool RootItem::deleteViaGui() { + return false; +} + +bool RootItem::canBeMarkedAsReadUnread(ReadStatus status) { + return true; +} + +bool RootItem::markAsReadUnread(ReadStatus status) { + bool result = true; + + foreach (RootItem *child, m_childItems) { + if (child->canBeMarkedAsReadUnread(status)) { + result &= child->markAsReadUnread(status); + } + } + + return result; +} + +bool RootItem::cleanMessages(bool clear_only_read) { + bool result = true; + + foreach (RootItem *child, m_childItems) { + result &= child->cleanMessages(clear_only_read); + } + + return result; +} + +void RootItem::updateCounts(bool including_total_count) { + foreach (RootItem *child, m_childItems) { + child->updateCounts(including_total_count); + } +} + +void RootItem::setupFonts() { + m_normalFont = Application::font("FeedsView"); + m_boldFont = m_normalFont; + m_boldFont.setBold(true); +} + +int RootItem::row() const { + if (m_parentItem) { + return m_parentItem->m_childItems.indexOf(const_cast(this)); + } + else { + // This item has no parent. Therefore, its row index is 0. + return 0; + } +} + +QVariant RootItem::data(int column, int role) const { + Q_UNUSED(column) + Q_UNUSED(role) + + switch (role) { + case Qt::ToolTipRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return m_title; + } + else if (column == FDS_MODEL_COUNTS_INDEX) { + //: Tooltip for "unread" column of feed list. + return tr("%n unread message(s).", 0, countOfUnreadMessages()); + } + else { + return QVariant(); + } + + case Qt::EditRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return m_title; + } + else if (column == FDS_MODEL_COUNTS_INDEX) { + return countOfUnreadMessages(); + } + else { + return QVariant(); + } + + case Qt::FontRole: + return countOfUnreadMessages() > 0 ? m_boldFont : m_normalFont; + + case Qt::DisplayRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return m_title; + } + else if (column == FDS_MODEL_COUNTS_INDEX) { + int count_all = countOfAllMessages(); + int count_unread = countOfUnreadMessages(); + + return qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::CountFormat)).toString() + .replace(PLACEHOLDER_UNREAD_COUNTS, count_unread < 0 ? QSL("-") : QString::number(count_unread)) + .replace(PLACEHOLDER_ALL_COUNTS, count_all < 0 ? QSL("-") : QString::number(count_all)); + } + else { + return QVariant(); + } + + case Qt::DecorationRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return icon(); + } + else { + return QVariant(); + } + + case Qt::TextAlignmentRole: + if (column == FDS_MODEL_COUNTS_INDEX) { + return Qt::AlignCenter; + } + else { + return QVariant(); + } + + default: + return QVariant(); + } +} + +Qt::ItemFlags RootItem::additionalFlags() const { + return Qt::NoItemFlags; +} + +bool RootItem::performDragDropChange(RootItem *target_item) { + return false; +} + +int RootItem::countOfAllMessages() const { + int total_count = 0; + + foreach (RootItem *child_item, m_childItems) { + total_count += child_item->countOfAllMessages(); + } + + return total_count; +} + +bool RootItem::isChildOf(RootItem *root) { + if (root == NULL) { + return false; + } + + RootItem *this_item = this; + + while (this_item->kind() != RootItemKind::Root) { + if (root->childItems().contains(this_item)) { + return true; + } + else { + this_item = this_item->parent(); + } + } + + return false; +} + +bool RootItem::isParentOf(RootItem *child) { + if (child == NULL) { + return false; + } + else { + return child->isChildOf(this); + } +} + +QList RootItem::getSubTree() { + QList children; + QList traversable_items; + + traversable_items.append(this); + + // Iterate all nested items. + while (!traversable_items.isEmpty()) { + RootItem *active_item = traversable_items.takeFirst(); + + children.append(active_item); + traversable_items.append(active_item->childItems()); + } + + return children; +} + +QList RootItem::getSubTree(RootItemKind::Kind kind_of_item) { + QList children; + QList traversable_items; + + traversable_items.append(this); + + // Iterate all nested items. + while (!traversable_items.isEmpty()) { + RootItem *active_item = traversable_items.takeFirst(); + + if ((active_item->kind() & kind_of_item) > 0) { + children.append(active_item); + } + + traversable_items.append(active_item->childItems()); + } + + return children; +} + +QList RootItem::getSubTreeCategories() { + QList children; + QList traversable_items; + + traversable_items.append(this); + + // Iterate all nested items. + while (!traversable_items.isEmpty()) { + RootItem *active_item = traversable_items.takeFirst(); + + if (active_item->kind() == RootItemKind::Category) { + children.append(active_item->toCategory()); + } + + traversable_items.append(active_item->childItems()); + } + + return children; +} + +QHash RootItem::getHashedSubTreeCategories() { + QHash children; + QList traversable_items; + + traversable_items.append(this); + + // Iterate all nested items. + while (!traversable_items.isEmpty()) { + RootItem *active_item = traversable_items.takeFirst(); + + if (active_item->kind() == RootItemKind::Category && !children.contains(active_item->id())) { + children.insert(active_item->id(), active_item->toCategory()); + } + + traversable_items.append(active_item->childItems()); + } + + return children; +} + +QList RootItem::getSubTreeFeeds() { + QList children; + QList traversable_items; + + traversable_items.append(this); + + // Iterate all nested items. + while (!traversable_items.isEmpty()) { + RootItem *active_item = traversable_items.takeFirst(); + + if (active_item->kind() == RootItemKind::Feed) { + children.append(active_item->toFeed()); + } + + traversable_items.append(active_item->childItems()); + } + + return children; +} + +ServiceRoot *RootItem::getParentServiceRoot() { + RootItem *working_parent = this; + + while (working_parent->kind() != RootItemKind::Root) { + if (working_parent->kind() == RootItemKind::ServiceRoot) { + return working_parent->toServiceRoot(); + } + else { + working_parent = working_parent->parent(); + } + } + + return NULL; +} + +bool RootItem::removeChild(RootItem *child) { + return m_childItems.removeOne(child); +} + +Category *RootItem::toCategory() { + return static_cast(this); +} + +Feed *RootItem::toFeed() { + return static_cast(this); +} + +ServiceRoot *RootItem::toServiceRoot() { + return static_cast(this); +} + +int RootItem::countOfUnreadMessages() const { + int total_count = 0; + + foreach (RootItem *child_item, m_childItems) { + total_count += child_item->countOfUnreadMessages(); + } + + return total_count; +} + +bool RootItem::removeChild(int index) { + if (index >= 0 && index < m_childItems.size()) { + m_childItems.removeAt(index); + return true; + } + else { + return false; + } +} diff --git a/src/services/abstract/rootitem.h b/src/services/abstract/rootitem.h new file mode 100755 index 000000000..876fe1149 --- /dev/null +++ b/src/services/abstract/rootitem.h @@ -0,0 +1,274 @@ +// This file is part of RSS Guard. +// +// Copyright (C) 2011-2015 by Martin Rotter +// +// RSS Guard is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RSS Guard is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RSS Guard. If not, see . + +#ifndef ROOTITEM_H +#define ROOTITEM_H + +#include +#include +#include + + +class Category; +class Feed; +class ServiceRoot; +class QAction; + +namespace RootItemKind { + // Describes the kind of the item. + enum Kind { + Root = 1, + Bin = 2, + Feed = 4, + Category = 8, + ServiceRoot = 16 + }; + + inline Kind operator|(Kind a, Kind b) { + return static_cast(static_cast(a) | static_cast(b)); + } +} + +// Represents ROOT item of FeedsModel. +// NOTE: This class is derived to add functionality for +// all other non-root items of FeedsModel. +class RootItem : public QObject { + Q_OBJECT + + public: + // Holds statuses for feeds/messages + // to be marked read/unread. + enum ReadStatus { + Unread = 0, + Read = 1 + }; + + // Holds statuses for messages + // to be switched importance (starred). + enum Importance { + NotImportant = 0, + Important = 1 + }; + + // Constructors and destructors. + explicit RootItem(RootItem *parent_item = NULL); + virtual ~RootItem(); + + ///////////////////////////////////////// + // /* Members to override. + ///////////////////////////////////////// + + // Returns list of specific actions which can be done with the item. + // Do not include general actions here like actions: Mark as read, Update, ... + // NOTE: Ownership of returned actions is not switched to caller, free them when needed. + virtual QList contextMenu(); + + // Can properties of this item be edited? + virtual bool canBeEdited(); + + // Performs editing of properties of this item (probably via dialog) + // and returns result status. + virtual bool editViaGui(); + + // Can the item be deleted? + virtual bool canBeDeleted(); + + // Performs deletion of the item, this + // method should NOT display any additional dialogs. + // Returns result status. + virtual bool deleteViaGui(); + + // Can this item be marked read/unread? + virtual bool canBeMarkedAsReadUnread(ReadStatus status); + + // Performs all needed steps (DB update, remote server update) + // to mark this item as read/unread. + virtual bool markAsReadUnread(ReadStatus status); + + // This method should "clean" all messages it contains. + // What "clean" means? It means delete messages -> move them to recycle bin + // or eventually remove them completely if there is no recycle bin functionality. + // If this method is called on "recycle bin" instance of your + // service account, it should "empty" the recycle bin. + virtual bool cleanMessages(bool clear_only_read); + + // Updates counts of all/unread messages for this feed. + virtual void updateCounts(bool including_total_count); + + virtual int row() const; + virtual QVariant data(int column, int role) const; + virtual Qt::ItemFlags additionalFlags() const; + virtual bool performDragDropChange(RootItem *target_item); + + // Each item offers "counts" of messages. + // Returns counts of messages of all child items summed up. + virtual int countOfUnreadMessages() const; + virtual int countOfAllMessages() const; + + ///////////////////////////////////////// + // Members to override. */ + ///////////////////////////////////////// + + inline RootItem *parent() const { + return m_parentItem; + } + + inline void setParent(RootItem *parent_item) { + m_parentItem = parent_item; + } + + inline RootItem *child(int row) { + return m_childItems.value(row); + } + + inline int childCount() const { + return m_childItems.size(); + } + + inline void appendChild(RootItem *child) { + m_childItems.append(child); + child->setParent(this); + } + + // Access to children. + inline QList childItems() const { + return m_childItems; + } + + // Removes all children from this item. + // NOTE: Children are NOT freed from the memory. + inline void clearChildren() { + m_childItems.clear(); + } + + inline void setChildItems(QList child_items) { + m_childItems = child_items; + } + + // Removes particular child at given index. + // NOTE: Child is NOT freed from the memory. + bool removeChild(int index); + bool removeChild(RootItem *child); + + // Checks whether "this" object is child (direct or indirect) + // of the given root. + bool isChildOf(RootItem *root); + + // Is "this" item parent (direct or indirect) if given child? + bool isParentOf(RootItem *child); + + // Returns flat list of all items from subtree where this item is a root. + // Returned list includes this item too. + QList getSubTree(); + QList getSubTree(RootItemKind::Kind kind_of_item); + QList getSubTreeCategories(); + QHash getHashedSubTreeCategories(); + QList getSubTreeFeeds(); + + // Returns the service root node which is direct or indirect parent of current item. + ServiceRoot *getParentServiceRoot(); + + inline RootItemKind::Kind kind() const { + return m_kind; + } + + inline void setKind(RootItemKind::Kind kind) { + m_kind = kind; + } + + // Each item can have icon. + inline QIcon icon() const { + return m_icon; + } + + inline void setIcon(const QIcon &icon) { + m_icon = icon; + } + + // Each item has some kind of id. Usually taken from primary key attribute from DB. + inline int id() const { + return m_id; + } + + inline void setId(int id) { + m_id = id; + } + + // Each item has its title. + inline QString title() const { + return m_title; + } + + inline void setTitle(const QString &title) { + m_title = title; + } + + inline QDateTime creationDate() const { + return m_creationDate; + } + + inline void setCreationDate(const QDateTime &creation_date) { + m_creationDate = creation_date; + } + + inline QString description() const { + return m_description; + } + + inline void setDescription(const QString &description) { + m_description = description; + } + + inline QFont normalFont() const { + return m_normalFont; + } + + inline void setNormalFont(const QFont &normal_font) { + m_normalFont = normal_font; + } + + inline QFont boldFont() const { + return m_boldFont; + } + + inline void setBoldFont(const QFont &bold_font) { + m_boldFont = bold_font; + } + + // Converters + Category *toCategory(); + Feed *toFeed(); + ServiceRoot *toServiceRoot(); + + private: + void setupFonts(); + + RootItemKind::Kind m_kind; + int m_id; + QString m_title; + QString m_description; + QIcon m_icon; + QDateTime m_creationDate; + + QFont m_normalFont; + QFont m_boldFont; + + QList m_childItems; + RootItem *m_parentItem; +}; + +#endif // ROOTITEM_H From 562ea97ffa64038f6f56a3f1f7fc0e453d9e41ed Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 11 Dec 2015 10:13:42 +0100 Subject: [PATCH 178/203] Some refactoring. --- src/core/feedsmodel.cpp | 10 ++-------- src/core/feedsmodel.h | 2 +- src/gui/feedmessageviewer.cpp | 4 ++-- src/gui/feedsview.cpp | 8 ++++---- src/gui/feedsview.h | 4 ++-- src/services/abstract/feed.h | 3 --- src/services/abstract/rootitem.cpp | 12 +++++------- src/services/abstract/rootitem.h | 9 ++++++--- 8 files changed, 22 insertions(+), 30 deletions(-) diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 6b4ee2a30..6563466d5 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -564,14 +564,8 @@ QList FeedsModel::feedsForScheduledUpdate(bool auto_update_now) { return feeds_for_update; } -QList FeedsModel::messagesForFeeds(const QList &feeds) { - QList messages; - - foreach (Feed *feed, feeds) { - messages.append(feed->undeletedMessages()); - } - - return messages; +QList FeedsModel::messagesForItem(RootItem *item) { + return item->undeletedMessages(); } int FeedsModel::columnCount(const QModelIndex &parent) const { diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 4379ce681..73c641b6c 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -98,7 +98,7 @@ class FeedsModel : public QAbstractItemModel { // Returns (undeleted) messages for given feeds. // This is usually used for displaying whole feeds // in "newspaper" mode. - QList messagesForFeeds(const QList &feeds); + QList messagesForItem(RootItem *item); // Returns list of all categories contained in the model. QList allCategories(); diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 45c135a7c..f17d806a1 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -271,11 +271,11 @@ void FeedMessageViewer::createConnections() { connect(form_main->m_ui->m_actionMarkAllItemsRead, SIGNAL(triggered()), m_feedsView, SLOT(markAllItemsRead())); connect(form_main->m_ui->m_actionMarkSelectedItemsAsRead, - SIGNAL(triggered()), m_feedsView, SLOT(markSelectedItemsRead())); + SIGNAL(triggered()), m_feedsView, SLOT(markSelectedItemRead())); connect(form_main->m_ui->m_actionExpandCollapseItem, SIGNAL(triggered()), m_feedsView, SLOT(expandCollapseCurrentItem())); connect(form_main->m_ui->m_actionMarkSelectedItemsAsUnread, - SIGNAL(triggered()), m_feedsView, SLOT(markSelectedItemsUnread())); + SIGNAL(triggered()), m_feedsView, SLOT(markSelectedItemUnread())); connect(form_main->m_ui->m_actionClearSelectedItems, SIGNAL(triggered()), m_feedsView, SLOT(clearSelectedFeeds())); connect(form_main->m_ui->m_actionClearAllItems, diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index fa51aee30..34652e5e5 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -249,11 +249,11 @@ void FeedsView::markSelectedItemReadStatus(RootItem::ReadStatus read) { m_sourceModel->markItemRead(selectedItem(), read); } -void FeedsView::markSelectedItemsRead() { +void FeedsView::markSelectedItemRead() { markSelectedItemReadStatus(RootItem::Read); } -void FeedsView::markSelectedItemsUnread() { +void FeedsView::markSelectedItemUnread() { markSelectedItemReadStatus(RootItem::Unread); } @@ -266,11 +266,11 @@ void FeedsView::markAllItemsRead() { } void FeedsView::openSelectedItemsInNewspaperMode() { - QList messages = m_sourceModel->messagesForFeeds(selectedFeeds()); + QList messages = m_sourceModel->messagesForItem(selectedItem()); if (!messages.isEmpty()) { emit openMessagesInNewspaperView(messages); - QTimer::singleShot(0, this, SLOT(markSelectedItemsRead())); + QTimer::singleShot(0, this, SLOT(markSelectedItemRead())); } } diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index f80a9a250..4932fe68c 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -69,8 +69,8 @@ class FeedsView : public QTreeView { void updateSelectedItems(); // Feed read/unread manipulators. - void markSelectedItemsRead(); - void markSelectedItemsUnread(); + void markSelectedItemRead(); + void markSelectedItemUnread(); void markAllItemsRead(); // Newspaper accessors. diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index d17befd84..459f4e6cf 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -61,9 +61,6 @@ class Feed : public RootItem { // messages. virtual int update() = 0; - // Get ALL undeleted messages from this feed in one single list. - virtual QList undeletedMessages() const = 0; - ///////////////////////////////////////// // Members to override. */ ///////////////////////////////////////// diff --git a/src/services/abstract/rootitem.cpp b/src/services/abstract/rootitem.cpp index d9c4ca476..ea9962cbb 100755 --- a/src/services/abstract/rootitem.cpp +++ b/src/services/abstract/rootitem.cpp @@ -62,22 +62,20 @@ bool RootItem::deleteViaGui() { return false; } -bool RootItem::canBeMarkedAsReadUnread(ReadStatus status) { - return true; -} - bool RootItem::markAsReadUnread(ReadStatus status) { bool result = true; foreach (RootItem *child, m_childItems) { - if (child->canBeMarkedAsReadUnread(status)) { - result &= child->markAsReadUnread(status); - } + result &= child->markAsReadUnread(status); } return result; } +QList RootItem::undeletedMessages() const { + return QList(); +} + bool RootItem::cleanMessages(bool clear_only_read) { bool result = true; diff --git a/src/services/abstract/rootitem.h b/src/services/abstract/rootitem.h index 876fe1149..54b9be830 100755 --- a/src/services/abstract/rootitem.h +++ b/src/services/abstract/rootitem.h @@ -18,6 +18,8 @@ #ifndef ROOTITEM_H #define ROOTITEM_H +#include "core/message.h" + #include #include #include @@ -92,13 +94,14 @@ class RootItem : public QObject { // Returns result status. virtual bool deleteViaGui(); - // Can this item be marked read/unread? - virtual bool canBeMarkedAsReadUnread(ReadStatus status); - // Performs all needed steps (DB update, remote server update) // to mark this item as read/unread. virtual bool markAsReadUnread(ReadStatus status); + // Get ALL undeleted messages from this item in one single list. + // This is currently used for displaying items in "newspaper mode". + virtual QList undeletedMessages() const; + // This method should "clean" all messages it contains. // What "clean" means? It means delete messages -> move them to recycle bin // or eventually remove them completely if there is no recycle bin functionality. From c40961ccba30b7c10eb7fc275967d180eebc2deb Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 11 Dec 2015 11:09:20 +0100 Subject: [PATCH 179/203] Undeleted messages refactoring. --- src/gui/feedmessageviewer.cpp | 2 +- src/services/abstract/recyclebin.cpp | 37 ++++++++++++++++++++++++ src/services/abstract/recyclebin.h | 2 ++ src/services/abstract/rootitem.cpp | 8 +++++- src/services/abstract/serviceroot.cpp | 41 +++++++++++++++++++++++++++ src/services/abstract/serviceroot.h | 2 ++ src/services/tt-rss/ttrssfeed.cpp | 2 +- 7 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index f17d806a1..2002cd3a3 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -209,7 +209,7 @@ void FeedMessageViewer::updateFeedButtonsAvailability() { form_main->m_ui->m_actionMarkSelectedItemsAsUnread->setEnabled(anything_selected); form_main->m_ui->m_actionUpdateAllItems->setEnabled(!critical_action_running); form_main->m_ui->m_actionUpdateSelectedItems->setEnabled(!critical_action_running && (feed_selected || category_selected || service_selected)); - form_main->m_ui->m_actionViewSelectedItemsNewspaperMode->setEnabled(feed_selected || category_selected || service_selected); + form_main->m_ui->m_actionViewSelectedItemsNewspaperMode->setEnabled(anything_selected); form_main->m_ui->m_actionExpandCollapseItem->setEnabled(anything_selected); form_main->m_ui->m_menuAddItem->setEnabled(!critical_action_running); form_main->m_ui->m_menuRecycleBin->setEnabled(!critical_action_running); diff --git a/src/services/abstract/recyclebin.cpp b/src/services/abstract/recyclebin.cpp index 051c7f37c..a616714bf 100755 --- a/src/services/abstract/recyclebin.cpp +++ b/src/services/abstract/recyclebin.cpp @@ -19,6 +19,7 @@ #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" +#include "miscellaneous/textfactory.h" #include "services/abstract/serviceroot.h" #include @@ -85,6 +86,42 @@ QVariant RecycleBin::data(int column, int role) const { } } +QList RecycleBin::undeletedMessages() const { + QList messages; + int account_id = const_cast(this)->getParentServiceRoot()->accountId(); + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + QSqlQuery query_read_msg(database); + + query_read_msg.setForwardOnly(true); + query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures, custom_id, id, feed " + "FROM Messages " + "WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;"); + query_read_msg.bindValue(QSL(":account_id"), account_id); + + // FIXME: Fix those const functions, this is fucking ugly. + + if (query_read_msg.exec()) { + while (query_read_msg.next()) { + Message message; + + message.m_feedId = query_read_msg.value(7).toString(); + message.m_title = query_read_msg.value(0).toString(); + message.m_url = query_read_msg.value(1).toString(); + message.m_author = query_read_msg.value(2).toString(); + message.m_created = TextFactory::parseDateTime(query_read_msg.value(3).value()); + message.m_contents = query_read_msg.value(4).toString(); + message.m_enclosures = Enclosures::decodeEnclosuresFromString(query_read_msg.value(5).toString()); + message.m_accountId = account_id; + message.m_customId = query_read_msg.value(6).toString(); + message.m_id = query_read_msg.value(7).toInt(); + + messages.append(message); + } + } + + return messages; +} + bool RecycleBin::markAsReadUnread(RootItem::ReadStatus status) { QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); diff --git a/src/services/abstract/recyclebin.h b/src/services/abstract/recyclebin.h index 4d702d8ac..a7d26278f 100755 --- a/src/services/abstract/recyclebin.h +++ b/src/services/abstract/recyclebin.h @@ -30,6 +30,8 @@ class RecycleBin : public RootItem { QVariant data(int column, int role) const; + QList undeletedMessages() const; + bool markAsReadUnread(ReadStatus status); bool cleanMessages(bool clear_only_read); diff --git a/src/services/abstract/rootitem.cpp b/src/services/abstract/rootitem.cpp index ea9962cbb..db3f6d039 100755 --- a/src/services/abstract/rootitem.cpp +++ b/src/services/abstract/rootitem.cpp @@ -73,7 +73,13 @@ bool RootItem::markAsReadUnread(ReadStatus status) { } QList RootItem::undeletedMessages() const { - return QList(); + QList messages; + + foreach (RootItem *child, m_childItems) { + messages.append(child->undeletedMessages()); + } + + return messages; } bool RootItem::cleanMessages(bool clear_only_read) { diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index cc454b411..f84b288d4 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -19,6 +19,7 @@ #include "core/feedsmodel.h" #include "miscellaneous/application.h" +#include "miscellaneous/textfactory.h" #include "services/abstract/category.h" #include @@ -59,6 +60,46 @@ bool ServiceRoot::deleteViaGui() { return data_removed; } +QList ServiceRoot::undeletedMessages() const { + QList messages; + int account_id = accountId(); + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + QSqlQuery query_read_msg(database); + + query_read_msg.setForwardOnly(true); + query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures, custom_id, id, feed " + "FROM Messages " + "WHERE is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;"); + query_read_msg.bindValue(QSL(":account_id"), account_id); + + // FIXME: Fix those const functions, this is fucking ugly. + + if (query_read_msg.exec()) { + while (query_read_msg.next()) { + Message message; + + // TODO: napsat funkci static Message Message::fromSqlRecord(const QSqlRecord &record) + // ta prostě bude brat record z SELECT * FROM Messages WHERE ....; + // a vrati ho jako objekt Message; + + message.m_feedId = query_read_msg.value(7).toString(); + message.m_title = query_read_msg.value(0).toString(); + message.m_url = query_read_msg.value(1).toString(); + message.m_author = query_read_msg.value(2).toString(); + message.m_created = TextFactory::parseDateTime(query_read_msg.value(3).value()); + message.m_contents = query_read_msg.value(4).toString(); + message.m_enclosures = Enclosures::decodeEnclosuresFromString(query_read_msg.value(5).toString()); + message.m_accountId = account_id; + message.m_customId = query_read_msg.value(6).toString(); + message.m_id = query_read_msg.value(7).toInt(); + + messages.append(message); + } + } + + return messages; +} + void ServiceRoot::itemChanged(const QList &items) { emit dataChanged(items); } diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 9cc47dfc4..aca20bf3d 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -66,6 +66,8 @@ class ServiceRoot : public RootItem { // Access to recycle bin of this account if there is any. virtual RecycleBin *recycleBin() = 0; + QList undeletedMessages() const; + // Start/stop services. // Start method is called when feed model gets initialized OR after user adds new service. // Account should synchronously initialize its children (load them from DB is recommended diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index 2dd8ccc48..075ef70bc 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -120,7 +120,7 @@ QList TtRssFeed::undeletedMessages() const { query_read_msg.setForwardOnly(true); query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures, custom_id, id " "FROM Messages " - "WHERE is_deleted = 0 AND feed = :feed AND account_id = :account_id;"); + "WHERE is_deleted = 0 AND is_pdeleted = 0 AND feed = :feed AND account_id = :account_id;"); query_read_msg.bindValue(QSL(":feed"), customId()); query_read_msg.bindValue(QSL(":account_id"), account_id); From 62e87a941a5c5730a891cdf3c87cd284f1077c7c Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 11 Dec 2015 13:04:37 +0100 Subject: [PATCH 180/203] Refactored getting Message instances from DB. --- src/core/message.cpp | 36 ++++++++++++++++++++++++++ src/core/message.h | 5 ++++ src/core/messagesmodel.cpp | 19 ++------------ src/services/abstract/recyclebin.cpp | 18 +++++-------- src/services/abstract/serviceroot.cpp | 22 +++++----------- src/services/standard/standardfeed.cpp | 17 +++++------- src/services/tt-rss/ttrssfeed.cpp | 18 +++++-------- 7 files changed, 67 insertions(+), 68 deletions(-) diff --git a/src/core/message.cpp b/src/core/message.cpp index e47791322..e74789fff 100755 --- a/src/core/message.cpp +++ b/src/core/message.cpp @@ -17,6 +17,10 @@ #include "core/message.h" +#include "miscellaneous/textfactory.h" + +#include + Enclosure::Enclosure(const QString &url, const QString &mime) : m_url(url), m_mimeType(mime) { } @@ -66,3 +70,35 @@ Message::Message() { m_accountId = m_id = 0; m_isRead = m_isImportant = false; } + +Message Message::fromSqlRecord(const QSqlRecord &record, bool *result) { + if (record.count() != MSG_DB_CUSTOM_ID_INDEX + 1) { + if (result != NULL) { + *result = false; + return Message(); + } + } + + Message message; + + message.m_id = record.value(MSG_DB_ID_INDEX).toInt(); + message.m_isRead = record.value(MSG_DB_READ_INDEX).toBool(); + //message = record.value(MSG_DB_DELETED_INDEX).toInt(); + message.m_isImportant = record.value(MSG_DB_IMPORTANT_INDEX).toBool(); + message.m_feedId = record.value(MSG_DB_FEED_INDEX).toString(); + message.m_title = record.value(MSG_DB_TITLE_INDEX).toString(); + message.m_url = record.value(MSG_DB_URL_INDEX).toString(); + message.m_author = record.value(MSG_DB_AUTHOR_INDEX).toString(); + message.m_created = TextFactory::parseDateTime(record.value(MSG_DB_DCREATED_INDEX).value()); + message.m_contents = record.value(MSG_DB_CONTENTS_INDEX).toString(); + //message = record.value(MSG_DB_PDELETED_INDEX).toInt(); + message.m_enclosures = Enclosures::decodeEnclosuresFromString(record.value(MSG_DB_ENCLOSURES_INDEX).toString()); + message.m_accountId = record.value(MSG_DB_ACCOUNT_ID_INDEX).toInt(); + message.m_customId = record.value(MSG_DB_CUSTOM_ID_INDEX).toString(); + + if (result != NULL) { + *result = true; + } + + return message; +} diff --git a/src/core/message.h b/src/core/message.h index a9f9769fb..299299230 100755 --- a/src/core/message.h +++ b/src/core/message.h @@ -22,6 +22,7 @@ #include #include +#include // Represents single enclosure. @@ -44,6 +45,10 @@ class Message { public: explicit Message(); + // Creates Message from given record, which contains + // row from query SELECT * FROM Messages WHERE ....; + static Message fromSqlRecord(const QSqlRecord &record, bool *result = NULL); + QString m_title; QString m_url; QString m_author; diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 8663f5466..baacb58ab 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -129,23 +129,8 @@ void MessagesModel::reloadWholeLayout() { emit layoutChanged(); } -Message MessagesModel::messageAt(int row_index) const { - QSqlRecord rec = record(row_index); - Message message; - - // Fill Message object with details. - message.m_author = rec.value(MSG_DB_AUTHOR_INDEX).toString(); - message.m_contents = rec.value(MSG_DB_CONTENTS_INDEX).toString(); - message.m_enclosures = Enclosures::decodeEnclosuresFromString(rec.value(MSG_DB_ENCLOSURES_INDEX).toString()); - message.m_title = rec.value(MSG_DB_TITLE_INDEX).toString(); - message.m_url = rec.value(MSG_DB_URL_INDEX).toString(); - message.m_feedId = rec.value(MSG_DB_FEED_INDEX).toString(); - message.m_accountId = rec.value(MSG_DB_ACCOUNT_ID_INDEX).toInt(); - message.m_id = rec.value(MSG_DB_ID_INDEX).toInt(); - message.m_customId = rec.value(MSG_DB_CUSTOM_ID_INDEX).toString(); - message.m_created = TextFactory::parseDateTime(rec.value(MSG_DB_DCREATED_INDEX).value()).toLocalTime(); - - return message; +Message MessagesModel::messageAt(int row_index) const { + return Message::fromSqlRecord(record(row_index)); } void MessagesModel::setupHeaderData() { diff --git a/src/services/abstract/recyclebin.cpp b/src/services/abstract/recyclebin.cpp index a616714bf..5cc27df93 100755 --- a/src/services/abstract/recyclebin.cpp +++ b/src/services/abstract/recyclebin.cpp @@ -93,7 +93,7 @@ QList RecycleBin::undeletedMessages() const { QSqlQuery query_read_msg(database); query_read_msg.setForwardOnly(true); - query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures, custom_id, id, feed " + query_read_msg.prepare("SELECT * " "FROM Messages " "WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;"); query_read_msg.bindValue(QSL(":account_id"), account_id); @@ -102,18 +102,12 @@ QList RecycleBin::undeletedMessages() const { if (query_read_msg.exec()) { while (query_read_msg.next()) { - Message message; + bool decoded; + Message message = Message::fromSqlRecord(query_read_msg.record(), &decoded); - message.m_feedId = query_read_msg.value(7).toString(); - message.m_title = query_read_msg.value(0).toString(); - message.m_url = query_read_msg.value(1).toString(); - message.m_author = query_read_msg.value(2).toString(); - message.m_created = TextFactory::parseDateTime(query_read_msg.value(3).value()); - message.m_contents = query_read_msg.value(4).toString(); - message.m_enclosures = Enclosures::decodeEnclosuresFromString(query_read_msg.value(5).toString()); - message.m_accountId = account_id; - message.m_customId = query_read_msg.value(6).toString(); - message.m_id = query_read_msg.value(7).toInt(); + if (decoded) { + messages.append(message); + } messages.append(message); } diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index f84b288d4..455b9e4f8 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -67,7 +67,7 @@ QList ServiceRoot::undeletedMessages() const { QSqlQuery query_read_msg(database); query_read_msg.setForwardOnly(true); - query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures, custom_id, id, feed " + query_read_msg.prepare("SELECT * " "FROM Messages " "WHERE is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;"); query_read_msg.bindValue(QSL(":account_id"), account_id); @@ -76,22 +76,12 @@ QList ServiceRoot::undeletedMessages() const { if (query_read_msg.exec()) { while (query_read_msg.next()) { - Message message; + bool decoded; + Message message = Message::fromSqlRecord(query_read_msg.record(), &decoded); - // TODO: napsat funkci static Message Message::fromSqlRecord(const QSqlRecord &record) - // ta prostě bude brat record z SELECT * FROM Messages WHERE ....; - // a vrati ho jako objekt Message; - - message.m_feedId = query_read_msg.value(7).toString(); - message.m_title = query_read_msg.value(0).toString(); - message.m_url = query_read_msg.value(1).toString(); - message.m_author = query_read_msg.value(2).toString(); - message.m_created = TextFactory::parseDateTime(query_read_msg.value(3).value()); - message.m_contents = query_read_msg.value(4).toString(); - message.m_enclosures = Enclosures::decodeEnclosuresFromString(query_read_msg.value(5).toString()); - message.m_accountId = account_id; - message.m_customId = query_read_msg.value(6).toString(); - message.m_id = query_read_msg.value(7).toInt(); + if (decoded) { + messages.append(message); + } messages.append(message); } diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 0eeb522b0..9057b67d9 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -135,7 +135,7 @@ QList StandardFeed::undeletedMessages() const { QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlQuery query_read_msg(database); query_read_msg.setForwardOnly(true); - query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures, id " + query_read_msg.prepare("SELECT * " "FROM Messages " "WHERE is_deleted = 0 AND feed = :feed AND account_id = :account_id;"); @@ -146,17 +146,12 @@ QList StandardFeed::undeletedMessages() const { if (query_read_msg.exec()) { while (query_read_msg.next()) { - Message message; + bool decoded; + Message message = Message::fromSqlRecord(query_read_msg.record(), &decoded); - message.m_feedId = id(); - message.m_title = query_read_msg.value(0).toString(); - message.m_url = query_read_msg.value(1).toString(); - message.m_author = query_read_msg.value(2).toString(); - message.m_created = TextFactory::parseDateTime(query_read_msg.value(3).value()); - message.m_contents = query_read_msg.value(4).toString(); - message.m_accountId = const_cast(this)->serviceRoot()->accountId(); - message.m_enclosures = Enclosures::decodeEnclosuresFromString(query_read_msg.value(5).toString()); - message.m_id = query_read_msg.value(6).toInt(); + if (decoded) { + messages.append(message); + } messages.append(message); } diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index 075ef70bc..bc1c5a3df 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -118,7 +118,7 @@ QList TtRssFeed::undeletedMessages() const { QSqlQuery query_read_msg(database); query_read_msg.setForwardOnly(true); - query_read_msg.prepare("SELECT title, url, author, date_created, contents, enclosures, custom_id, id " + query_read_msg.prepare("SELECT * " "FROM Messages " "WHERE is_deleted = 0 AND is_pdeleted = 0 AND feed = :feed AND account_id = :account_id;"); @@ -129,18 +129,12 @@ QList TtRssFeed::undeletedMessages() const { if (query_read_msg.exec()) { while (query_read_msg.next()) { - Message message; + bool decoded; + Message message = Message::fromSqlRecord(query_read_msg.record(), &decoded); - message.m_feedId = QString::number(customId()); - message.m_title = query_read_msg.value(0).toString(); - message.m_url = query_read_msg.value(1).toString(); - message.m_author = query_read_msg.value(2).toString(); - message.m_created = TextFactory::parseDateTime(query_read_msg.value(3).value()); - message.m_contents = query_read_msg.value(4).toString(); - message.m_enclosures = Enclosures::decodeEnclosuresFromString(query_read_msg.value(5).toString()); - message.m_accountId = account_id; - message.m_customId = query_read_msg.value(6).toString(); - message.m_id = query_read_msg.value(7).toInt(); + if (decoded) { + messages.append(message); + } messages.append(message); } From fbfeb9f91b0d2964005a693328d13fdcd0387476 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 11 Dec 2015 13:08:58 +0100 Subject: [PATCH 181/203] Some stuff regarding newspaper view. --- src/gui/messagesview.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/gui/messagesview.cpp b/src/gui/messagesview.cpp index 0d8ecbf97..be30c14a2 100755 --- a/src/gui/messagesview.cpp +++ b/src/gui/messagesview.cpp @@ -28,6 +28,7 @@ #include #include +#include #include @@ -257,8 +258,8 @@ void MessagesView::openSelectedSourceMessagesExternally() { } // Finally, mark opened messages as read. - if (selectionModel()->selectedRows().size() > 1) { - markSelectedMessagesRead(); + if (!selectionModel()->selectedRows().isEmpty()) { + QTimer::singleShot(0, this, SLOT(markSelectedMessagesRead())); } } @@ -278,8 +279,8 @@ void MessagesView::openSelectedSourceMessagesInternally() { } // Finally, mark opened messages as read. - if (selectionModel()->selectedRows().size() > 1) { - markSelectedMessagesRead(); + if (!selectionModel()->selectedRows().isEmpty()) { + QTimer::singleShot(0, this, SLOT(markSelectedMessagesRead())); } } @@ -301,7 +302,7 @@ void MessagesView::openSelectedMessagesInternally() { emit openMessagesInNewspaperView(messages); // Finally, mark opened messages as read. - markSelectedMessagesRead(); + QTimer::singleShot(0, this, SLOT(markSelectedMessagesRead())); } } From e4fe5a9f137d03940696a75c42b9934d8ff9605c Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 11 Dec 2015 13:56:05 +0100 Subject: [PATCH 182/203] Some changes to DB schema. --- resources/misc/db_init_mysql.sql | 4 ++-- resources/misc/db_init_sqlite.sql | 4 ++-- resources/misc/db_update_mysql_3_4.sql | 5 ++++- resources/misc/db_update_sqlite_3_4.sql | 4 ++-- src/services/standard/standardserviceentrypoint.cpp | 6 +++--- src/services/tt-rss/network/ttrssnetworkfactory.cpp | 2 +- src/services/tt-rss/ttrssfeed.cpp | 4 ++++ src/services/tt-rss/ttrssserviceentrypoint.cpp | 1 + src/services/tt-rss/ttrssserviceroot.cpp | 9 +++++---- 9 files changed, 24 insertions(+), 15 deletions(-) diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index d1bbd370d..c882d52af 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -74,10 +74,10 @@ CREATE TABLE IF NOT EXISTS Messages ( is_read INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_read >= 0 AND is_read <= 1), is_deleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_deleted >= 0 AND is_deleted <= 1), is_important INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_important >= 0 AND is_important <= 1), - feed TEXT, + feed TEXT NOT NULL, title TEXT NOT NULL CHECK (title != ''), url TEXT NOT NULL, - author TEXT NOT NULL, + author TEXT, date_created BIGINT NOT NULL CHECK (date_created != 0), contents TEXT, is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1), diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index a0e357296..01f7e09ab 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -69,10 +69,10 @@ CREATE TABLE IF NOT EXISTS Messages ( is_read INTEGER(1) NOT NULL CHECK (is_read >= 0 AND is_read <= 1) DEFAULT (0), is_deleted INTEGER(1) NOT NULL CHECK (is_deleted >= 0 AND is_deleted <= 1) DEFAULT (0), is_important INTEGER(1) NOT NULL CHECK (is_important >= 0 AND is_important <= 1) DEFAULT (0), - feed TEXT, + feed TEXT NOT NULL, title TEXT NOT NULL CHECK (title != ''), url TEXT NOT NULL, - author TEXT NOT NULL, + author TEXT, date_created INTEGER NOT NULL CHECK (date_created != 0), contents TEXT, is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1), diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index 25038fd1e..289eec2f2 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -38,7 +38,7 @@ ALTER TABLE Messages DROP FOREIGN KEY feed; -- ! ALTER TABLE Messages -MODIFY Feeds TEXT; +MODIFY feed TEXT NOT NULL; -- ! ALTER TABLE Feeds MODIFY date_created BIGINT; @@ -55,4 +55,7 @@ MODIFY type INTEGER; ALTER TABLE Categories MODIFY date_created BIGINT; -- ! +ALTER TABLE Messages +MODIFY author TEXT; +-- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql index 6765c6491..1763e54d9 100644 --- a/resources/misc/db_update_sqlite_3_4.sql +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -43,10 +43,10 @@ CREATE TABLE Messages ( is_read INTEGER(1) NOT NULL CHECK (is_read >= 0 AND is_read <= 1) DEFAULT (0), is_deleted INTEGER(1) NOT NULL CHECK (is_deleted >= 0 AND is_deleted <= 1) DEFAULT (0), is_important INTEGER(1) NOT NULL CHECK (is_important >= 0 AND is_important <= 1) DEFAULT (0), - feed TEXT, + feed TEXT NOT NULL, title TEXT NOT NULL CHECK (title != ''), url TEXT NOT NULL, - author TEXT NOT NULL, + author TEXT, date_created INTEGER NOT NULL CHECK (date_created != 0), contents TEXT, is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1), diff --git a/src/services/standard/standardserviceentrypoint.cpp b/src/services/standard/standardserviceentrypoint.cpp index f852f6bb5..74a4bfee4 100755 --- a/src/services/standard/standardserviceentrypoint.cpp +++ b/src/services/standard/standardserviceentrypoint.cpp @@ -69,12 +69,12 @@ ServiceRoot *StandardServiceEntryPoint::createNewRoot() { return NULL; } - int id_to_assing = query.value(0).toInt() + 1; + int id_to_assign = query.value(0).toInt() + 1; - if (query.exec(QString("INSERT INTO Accounts (id, type) VALUES (%1, '%2');").arg(QString::number(id_to_assing), + if (query.exec(QString("INSERT INTO Accounts (id, type) VALUES (%1, '%2');").arg(QString::number(id_to_assign), SERVICE_CODE_STD_RSS))) { StandardServiceRoot *root = new StandardServiceRoot(); - root->setAccountId(id_to_assing); + root->setAccountId(id_to_assign); return root; } else { diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index f3d1986f9..5ba9927bd 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -376,7 +376,7 @@ QList TtRssGetHeadlinesResponse::messages() const { QMap mapped = item.toMap(); Message message; - message.m_author = mapped["author"].toString(); + message.m_author = mapped["author"].toString(); message.m_isRead = !mapped["unread"].toBool(); message.m_isImportant = mapped["marked"].toBool(); message.m_contents = mapped["content"].toString(); diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index bc1c5a3df..76a4b1ea8 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -27,6 +27,7 @@ #include "services/tt-rss/network/ttrssnetworkfactory.h" #include +#include TtRssFeed::TtRssFeed(RootItem *parent) @@ -251,6 +252,9 @@ int TtRssFeed::updateMessages(const QList &messages) { if (query_insert.exec() && query_insert.numRowsAffected() == 1) { updated_messages++; } + else { + QString str = query_insert.lastError().text(); + } query_insert.finish(); diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp index 6af16e2a8..c0b2565ed 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.cpp +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -82,6 +82,7 @@ QList TtRssServiceEntryPoint::initializeSubtree() { if (query.exec("SELECT id, username, password, url FROM TtRssAccounts;")) { while (query.next()) { TtRssServiceRoot *root = new TtRssServiceRoot(); + root->setId(query.value(0).toInt()); root->setAccountId(query.value(0).toInt()); root->network()->setUsername(query.value(1).toString()); root->network()->setPassword(query.value(2).toString()); diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 0f2714c47..ea9f22036 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -251,17 +251,18 @@ void TtRssServiceRoot::saveAccountDataToDatabase() { return; } - int id_to_assing = query.value(0).toInt() + 1; + int id_to_assign = query.value(0).toInt() + 1; - bool saved = query.exec(QString("INSERT INTO Accounts (id, type) VALUES (%1, '%2');").arg(QString::number(id_to_assing), + bool saved = query.exec(QString("INSERT INTO Accounts (id, type) VALUES (%1, '%2');").arg(QString::number(id_to_assign), SERVICE_CODE_TT_RSS)) && - query.exec(QString("INSERT INTO TtRssAccounts (id, username, password, url) VALUES (%1, '%2', '%3', '%4');").arg(QString::number(id_to_assing), + query.exec(QString("INSERT INTO TtRssAccounts (id, username, password, url) VALUES (%1, '%2', '%3', '%4');").arg(QString::number(id_to_assign), network()->username(), network()->password(), network()->url())); if (saved) { - setAccountId(id_to_assing); + setId(id_to_assign); + setAccountId(id_to_assign); updateTitle(); } } From 4e289fc1f0b5c6ddee368a92bdfd87acbdbff713 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sat, 12 Dec 2015 08:40:19 +0100 Subject: [PATCH 183/203] Added Q_OBJECT to classes. --- CMakeLists.txt | 2 + src/services/tt-rss/ttrsscategory.h | 4 ++ src/services/tt-rss/ttrssfeed.h | 2 + src/services/tt-rss/ttrssserviceroot.cpp | 71 ++++++++++++++++++++++++ src/services/tt-rss/ttrssserviceroot.h | 4 +- 5 files changed, 82 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1027f8d9a..aaef3c5a2 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -561,6 +561,8 @@ set(APP_HEADERS # TT-RSS service headers. src/services/tt-rss/ttrssserviceroot.h src/services/tt-rss/ttrssrecyclebin.h + src/services/tt-rss/ttrssfeed.h + src/services/tt-rss/ttrsscategory.h src/services/tt-rss/gui/formeditaccount.h # NETWORK-WEB headers. diff --git a/src/services/tt-rss/ttrsscategory.h b/src/services/tt-rss/ttrsscategory.h index c029d3435..54e573448 100755 --- a/src/services/tt-rss/ttrsscategory.h +++ b/src/services/tt-rss/ttrsscategory.h @@ -24,11 +24,15 @@ class TtRssCategory : public Category { + Q_OBJECT + public: explicit TtRssCategory(RootItem *parent = NULL); explicit TtRssCategory(const QSqlRecord &record); virtual ~TtRssCategory(); + + int customId() const; void setCustomId(int custom_id); diff --git a/src/services/tt-rss/ttrssfeed.h b/src/services/tt-rss/ttrssfeed.h index 87a2c3e9f..ccd78d386 100755 --- a/src/services/tt-rss/ttrssfeed.h +++ b/src/services/tt-rss/ttrssfeed.h @@ -26,6 +26,8 @@ class TtRssServiceRoot; class TtRssFeed : public Feed { + Q_OBJECT + public: explicit TtRssFeed(RootItem *parent = NULL); explicit TtRssFeed(const QSqlRecord &record); diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index ea9f22036..ca6061a64 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -222,6 +222,77 @@ TtRssNetworkFactory *TtRssServiceRoot::network() const { return m_network; } +QStringList TtRssServiceRoot::customIDSOfMessagesForItem(RootItem *item) { + if (item->getParentServiceRoot() != this) { + // Not item from this account. + return QStringList(); + } + else { + QStringList list; + + switch (item->kind()) { + case RootItemKind::Category: { + foreach (RootItem *child, item->childItems()) { + list.append(customIDSOfMessagesForItem(child)); + } + + return list; + } + + case RootItemKind::ServiceRoot: { + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + QSqlQuery query(database); + + query.prepare(QSL("SELECT custom_id FROM Messages WHERE is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;")); + query.bindValue(QSL(":account_id"), accountId()); + query.exec(); + + while (query.next()) { + list.append(query.value(0).toString()); + } + + break; + } + + case RootItemKind::Bin: { + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + QSqlQuery query(database); + + query.prepare(QSL("SELECT custom_id FROM Messages WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;")); + query.bindValue(QSL(":account_id"), accountId()); + query.exec(); + + while (query.next()) { + list.append(query.value(0).toString()); + } + + break; + } + + case RootItemKind::Feed: { + QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + QSqlQuery query(database); + + query.prepare(QSL("SELECT custom_id FROM Messages WHERE is_deleted = 0 AND is_pdeleted = 0 AND feed = :feed AND account_id = :account_id;")); + query.bindValue(QSL(":account_id"), accountId()); + query.bindValue(QSL(":feed"), qobject_cast(item)->customId()); + query.exec(); + + while (query.next()) { + list.append(query.value(0).toString()); + } + + break; + } + + default: + break; + } + + return list; + } +} + void TtRssServiceRoot::saveAccountDataToDatabase() { if (accountId() != NO_PARENT_CATEGORY) { // We are overwritting previously saved data. diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 903100cb9..6f594ab7f 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -68,9 +68,11 @@ class TtRssServiceRoot : public ServiceRoot { TtRssNetworkFactory *network() const; + // Returns list of custom IDS of all DB messages in given item. + QStringList customIDSOfMessagesForItem(RootItem *item); + void saveAccountDataToDatabase(); void updateTitle(); - void completelyRemoveAllData(); public slots: From e23f517c056f3565f8c3acfad6d02c5d21768805 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sat, 12 Dec 2015 12:32:40 +0100 Subject: [PATCH 184/203] Marking TT-RSS read/unread works - only for whole acc now. --- CMakeLists.txt | 2 +- src/services/abstract/serviceroot.cpp | 32 +++++++++++++++++++ src/services/abstract/serviceroot.h | 2 ++ src/services/standard/standardserviceroot.cpp | 30 +---------------- src/services/tt-rss/ttrsscategory.h | 2 -- src/services/tt-rss/ttrssfeed.cpp | 18 +++++++++++ src/services/tt-rss/ttrssfeed.h | 2 ++ src/services/tt-rss/ttrssserviceroot.cpp | 17 ++++++++++ src/services/tt-rss/ttrssserviceroot.h | 2 ++ 9 files changed, 75 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aaef3c5a2..313bfecdb 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -560,7 +560,7 @@ set(APP_HEADERS # TT-RSS service headers. src/services/tt-rss/ttrssserviceroot.h - src/services/tt-rss/ttrssrecyclebin.h + src/services/tt-rss/ttrssrecyclebin.h; src/services/tt-rss/ttrssfeed.h src/services/tt-rss/ttrsscategory.h src/services/tt-rss/gui/formeditaccount.h diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index 455b9e4f8..d83bfa2d4 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -60,6 +60,38 @@ bool ServiceRoot::deleteViaGui() { return data_removed; } +bool ServiceRoot::markAsReadUnread(RootItem::ReadStatus status) { + QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + + if (!db_handle.transaction()) { + qWarning("Starting transaction for feeds read change."); + return false; + } + + QSqlQuery query_read_msg(db_handle); + query_read_msg.setForwardOnly(true); + query_read_msg.prepare(QSL("UPDATE Messages SET is_read = :read WHERE is_pdeleted = 0 AND account_id = :account_id;")); + + query_read_msg.bindValue(QSL(":account_id"), accountId()); + query_read_msg.bindValue(QSL(":read"), status == RootItem::Read ? 1 : 0); + + if (!query_read_msg.exec()) { + qDebug("Query execution for feeds read change failed."); + db_handle.rollback(); + } + + // Commit changes. + if (db_handle.commit()) { + updateCounts(false); + itemChanged(getSubTree()); + requestReloadMessageList(status == RootItem::Read); + return true; + } + else { + return db_handle.rollback(); + } +} + QList ServiceRoot::undeletedMessages() const { QList messages; int account_id = accountId(); diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index aca20bf3d..c4c3a0455 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -50,6 +50,8 @@ class ServiceRoot : public RootItem { bool deleteViaGui(); + bool markAsReadUnread(ReadStatus status); + // Returns list of specific actions for "Add new item" main window menu. // So typical list of returned actions could look like: // a) Add new feed diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 7a51f291b..512288582 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -118,35 +118,7 @@ bool StandardServiceRoot::deleteViaGui() { } bool StandardServiceRoot::markAsReadUnread(RootItem::ReadStatus status) { - QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); - - if (!db_handle.transaction()) { - qWarning("Starting transaction for feeds read change."); - return false; - } - - QSqlQuery query_read_msg(db_handle); - query_read_msg.setForwardOnly(true); - query_read_msg.prepare(QSL("UPDATE Messages SET is_read = :read WHERE is_pdeleted = 0 AND account_id = :account_id;")); - - query_read_msg.bindValue(QSL(":account_id"), accountId()); - query_read_msg.bindValue(QSL(":read"), status == RootItem::Read ? 1 : 0); - - if (!query_read_msg.exec()) { - qDebug("Query execution for feeds read change failed."); - db_handle.rollback(); - } - - // Commit changes. - if (db_handle.commit()) { - updateCounts(false); - itemChanged(getSubTree()); - requestReloadMessageList(status == RootItem::Read); - return true; - } - else { - return db_handle.rollback(); - } + return ServiceRoot::markAsReadUnread(status); } QVariant StandardServiceRoot::data(int column, int role) const { diff --git a/src/services/tt-rss/ttrsscategory.h b/src/services/tt-rss/ttrsscategory.h index 54e573448..d2355f8e2 100755 --- a/src/services/tt-rss/ttrsscategory.h +++ b/src/services/tt-rss/ttrsscategory.h @@ -31,8 +31,6 @@ class TtRssCategory : public Category { explicit TtRssCategory(const QSqlRecord &record); virtual ~TtRssCategory(); - - int customId() const; void setCustomId(int custom_id); diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index 76a4b1ea8..a8b228522 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -144,6 +144,24 @@ QList TtRssFeed::undeletedMessages() const { return messages; } +bool TtRssFeed::markAsReadUnread(RootItem::ReadStatus status) { + QNetworkReply::NetworkError error; + QStringList ids = serviceRoot()->customIDSOfMessagesForItem(this); + TtRssUpdateArticleResponse response = serviceRoot()->network()->updateArticles(ids, UpdateArticle::Unread, + status == RootItem::Unread ? + UpdateArticle::SetToTrue : + UpdateArticle::SetToFalse, + error); + + if (error != QNetworkReply::NoError || response.updateStatus() != STATUS_OK) { + return false; + } + else { + // TODO: todo + //return Feed::markAsReadUnread(status); + } +} + int TtRssFeed::customId() const { return m_customId; } diff --git a/src/services/tt-rss/ttrssfeed.h b/src/services/tt-rss/ttrssfeed.h index ccd78d386..c49501049 100755 --- a/src/services/tt-rss/ttrssfeed.h +++ b/src/services/tt-rss/ttrssfeed.h @@ -43,6 +43,8 @@ class TtRssFeed : public Feed { int update(); QList undeletedMessages() const; + bool markAsReadUnread(ReadStatus status); + int customId() const; void setCustomId(int custom_id); diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index ca6061a64..4ae0c6e97 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -86,6 +86,23 @@ bool TtRssServiceRoot::deleteViaGui() { } } +bool TtRssServiceRoot::markAsReadUnread(RootItem::ReadStatus status) { + QNetworkReply::NetworkError error; + QStringList ids = customIDSOfMessagesForItem(this); + TtRssUpdateArticleResponse response = m_network->updateArticles(ids, UpdateArticle::Unread, + status == RootItem::Unread ? + UpdateArticle::SetToTrue : + UpdateArticle::SetToFalse, + error); + + if (error != QNetworkReply::NoError || response.updateStatus() != STATUS_OK) { + return false; + } + else { + return ServiceRoot::markAsReadUnread(status); + } +} + bool TtRssServiceRoot::canBeEdited() { return true; } diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 6f594ab7f..6dd03a2a7 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -44,6 +44,8 @@ class TtRssServiceRoot : public ServiceRoot { bool editViaGui(); bool deleteViaGui(); + bool markAsReadUnread(ReadStatus status); + QVariant data(int column, int role) const; QList addItemMenu(); From 23b0f411d6f8dc27005bcb4ae142786e6b80d8ee Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sat, 12 Dec 2015 12:43:30 +0100 Subject: [PATCH 185/203] Marking TT-RSS read/unread works - for feed. --- src/services/standard/standardserviceroot.cpp | 4 +- src/services/tt-rss/ttrssfeed.cpp | 3 +- src/services/tt-rss/ttrssserviceroot.cpp | 48 ++++++++++++++++++- src/services/tt-rss/ttrssserviceroot.h | 2 + 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 512288582..97a974fb1 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -156,7 +156,7 @@ bool StandardServiceRoot::markFeedsReadUnread(QList items, ReadStatus rea query_read_msg.setForwardOnly(true); if (!query_read_msg.prepare(QString("UPDATE Messages SET is_read = :read " - "WHERE feed IN (%1) AND is_deleted = 0;").arg(textualFeedIds(items).join(QSL(", "))))) { + "WHERE feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0;").arg(textualFeedIds(items).join(QSL(", "))))) { qWarning("Query preparation failed for feeds read change."); db_handle.rollback(); @@ -172,7 +172,7 @@ bool StandardServiceRoot::markFeedsReadUnread(QList items, ReadStatus rea // Commit changes. if (db_handle.commit()) { - // Messages are cleared, now inform model about need to reload data. + // Messages are switched, now inform model about need to reload data. QList itemss; foreach (Feed *feed, items) { diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index a8b228522..a1e9ce144 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -157,8 +157,7 @@ bool TtRssFeed::markAsReadUnread(RootItem::ReadStatus status) { return false; } else { - // TODO: todo - //return Feed::markAsReadUnread(status); + return serviceRoot()->markFeedsReadUnread(QList() << this, status); } } diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 4ae0c6e97..099c4e8fa 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -310,6 +310,50 @@ QStringList TtRssServiceRoot::customIDSOfMessagesForItem(RootItem *item) { } } +bool TtRssServiceRoot::markFeedsReadUnread(QList items, RootItem::ReadStatus read) { + QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + + if (!db_handle.transaction()) { + qWarning("Starting transaction for feeds read change."); + return false; + } + + QSqlQuery query_read_msg(db_handle); + query_read_msg.setForwardOnly(true); + + if (!query_read_msg.prepare(QString("UPDATE Messages SET is_read = :read " + "WHERE feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0;").arg(textualFeedIds(items).join(QSL(", "))))) { + qWarning("Query preparation failed for feeds read change."); + + db_handle.rollback(); + return false; + } + + query_read_msg.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0); + + if (!query_read_msg.exec()) { + qDebug("Query execution for feeds read change failed."); + db_handle.rollback(); + } + + // Commit changes. + if (db_handle.commit()) { + QList itemss; + + foreach (Feed *feed, items) { + feed->updateCounts(false); + itemss.append(feed); + } + + itemChanged(itemss); + requestReloadMessageList(read == RootItem::Read); + return true; + } + else { + return db_handle.rollback(); + } +} + void TtRssServiceRoot::saveAccountDataToDatabase() { if (accountId() != NO_PARENT_CATEGORY) { // We are overwritting previously saved data. @@ -477,7 +521,7 @@ QStringList TtRssServiceRoot::textualFeedIds(const QList &feeds) { stringy_ids.reserve(feeds.size()); foreach (Feed *feed, feeds) { - stringy_ids.append(QString("'%1'").arg(QString::number(static_cast(feed)->customId()))); + stringy_ids.append(QString("'%1'").arg(QString::number(qobject_cast(feed)->customId()))); } return stringy_ids; @@ -525,7 +569,7 @@ void TtRssServiceRoot::storeNewFeedTree(RootItem *root) { query_category.bindValue(QSL(":parent_id"), child->parent()->id()); query_category.bindValue(QSL(":title"), child->title()); query_category.bindValue(QSL(":account_id"), accountId()); - query_category.bindValue(QSL(":custom_id"), QString::number(static_cast(child)->customId())); + query_category.bindValue(QSL(":custom_id"), QString::number(qobject_cast(child)->customId())); if (query_category.exec()) { child->setId(query_category.lastInsertId().toInt()); diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 6dd03a2a7..d1ff3ae38 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -73,6 +73,8 @@ class TtRssServiceRoot : public ServiceRoot { // Returns list of custom IDS of all DB messages in given item. QStringList customIDSOfMessagesForItem(RootItem *item); + bool markFeedsReadUnread(QList items, ReadStatus read); + void saveAccountDataToDatabase(); void updateTitle(); void completelyRemoveAllData(); From bfa177a32d50a799c45d5685a8c3d1b9903a3619 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sat, 12 Dec 2015 17:53:46 +0100 Subject: [PATCH 186/203] Can mark category. --- src/services/tt-rss/ttrsscategory.cpp | 24 ++++++++++++++++++++++++ src/services/tt-rss/ttrsscategory.h | 6 ++++++ 2 files changed, 30 insertions(+) diff --git a/src/services/tt-rss/ttrsscategory.cpp b/src/services/tt-rss/ttrsscategory.cpp index 7dc127ea6..ac5e11641 100755 --- a/src/services/tt-rss/ttrsscategory.cpp +++ b/src/services/tt-rss/ttrsscategory.cpp @@ -20,6 +20,9 @@ #include "definitions/definitions.h" #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" +#include "services/tt-rss/definitions.h" +#include "services/tt-rss/ttrssserviceroot.h" +#include "services/tt-rss/network/ttrssnetworkfactory.h" #include @@ -38,6 +41,27 @@ TtRssCategory::TtRssCategory(const QSqlRecord &record) : Category(NULL) { TtRssCategory::~TtRssCategory() { } +TtRssServiceRoot *TtRssCategory::serviceRoot() { + return qobject_cast(getParentServiceRoot()); +} + +bool TtRssCategory::markAsReadUnread(RootItem::ReadStatus status) { + QNetworkReply::NetworkError error; + QStringList ids = serviceRoot()->customIDSOfMessagesForItem(this); + TtRssUpdateArticleResponse response = serviceRoot()->network()->updateArticles(ids, UpdateArticle::Unread, + status == RootItem::Unread ? + UpdateArticle::SetToTrue : + UpdateArticle::SetToFalse, + error); + + if (error != QNetworkReply::NoError || response.updateStatus() != STATUS_OK) { + return false; + } + else { + return serviceRoot()->markFeedsReadUnread(getSubTreeFeeds(), status); + } +} + int TtRssCategory::customId() const { return m_customId; } diff --git a/src/services/tt-rss/ttrsscategory.h b/src/services/tt-rss/ttrsscategory.h index d2355f8e2..599b8751e 100755 --- a/src/services/tt-rss/ttrsscategory.h +++ b/src/services/tt-rss/ttrsscategory.h @@ -23,6 +23,8 @@ #include +class TtRssServiceRoot; + class TtRssCategory : public Category { Q_OBJECT @@ -31,6 +33,10 @@ class TtRssCategory : public Category { explicit TtRssCategory(const QSqlRecord &record); virtual ~TtRssCategory(); + TtRssServiceRoot *serviceRoot(); + + bool markAsReadUnread(ReadStatus status); + int customId() const; void setCustomId(int custom_id); From a212c44ad2ce5811778645a538c745846fe473e5 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sat, 12 Dec 2015 18:27:54 +0100 Subject: [PATCH 187/203] Added recycle bin initially to TT-RSS. --- src/services/tt-rss/ttrssserviceroot.cpp | 19 ++++++++++++++++--- src/services/tt-rss/ttrssserviceroot.h | 3 +++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 099c4e8fa..20ea46865 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -23,6 +23,7 @@ #include "network-web/networkfactory.h" #include "services/tt-rss/ttrssserviceentrypoint.h" #include "services/tt-rss/ttrssfeed.h" +#include "services/tt-rss/ttrssrecyclebin.h" #include "services/tt-rss/ttrsscategory.h" #include "services/tt-rss/definitions.h" #include "services/tt-rss/network/ttrssnetworkfactory.h" @@ -36,7 +37,7 @@ TtRssServiceRoot::TtRssServiceRoot(RootItem *parent) - : ServiceRoot(parent), m_actionSyncIn(NULL), m_serviceMenu(QList()), m_network(new TtRssNetworkFactory) { + : ServiceRoot(parent), m_recycleBin(new TtRssRecycleBin(this)), m_actionSyncIn(NULL), m_serviceMenu(QList()), m_network(new TtRssNetworkFactory) { setIcon(TtRssServiceEntryPoint().icon()); setCreationDate(QDateTime::currentDateTime()); } @@ -133,7 +134,7 @@ QList TtRssServiceRoot::addItemMenu() { } RecycleBin *TtRssServiceRoot::recycleBin() { - return NULL; + return m_recycleBin; } bool TtRssServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *model) { @@ -442,6 +443,10 @@ void TtRssServiceRoot::loadFromDatabase() { // All data are now obtained, lets create the hierarchy. assembleCategories(categories); assembleFeeds(feeds); + + // As the last item, add recycle bin, which is needed. + appendChild(m_recycleBin); + m_recycleBin->updateCounts(true); } void TtRssServiceRoot::updateTitle() { @@ -549,7 +554,9 @@ void TtRssServiceRoot::removeOldFeedTree(bool including_messages) { void TtRssServiceRoot::cleanAllItems() { foreach (RootItem *top_level_item, childItems()) { - requestItemRemoval(top_level_item); + if (top_level_item->kind() != RootItemKind::Bin) { + requestItemRemoval(top_level_item); + } } } @@ -596,4 +603,10 @@ void TtRssServiceRoot::storeNewFeedTree(RootItem *root) { } } } + + if (!childItems().contains(m_recycleBin)) { + // As the last item, add recycle bin, which is needed. + appendChild(m_recycleBin); + m_recycleBin->updateCounts(true); + } } diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index d1ff3ae38..968d27cb0 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -26,6 +26,7 @@ class TtRssCategory; class TtRssFeed; class TtRssNetworkFactory; +class TtRssRecycleBin; class TtRssServiceRoot : public ServiceRoot { Q_OBJECT @@ -95,6 +96,8 @@ class TtRssServiceRoot : public ServiceRoot { void storeNewFeedTree(RootItem *root); void loadFromDatabase(); + TtRssRecycleBin *m_recycleBin; + QAction *m_actionSyncIn; QList m_serviceMenu; From a161e57118789e836a6eebf54c01264886384bdc Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sat, 12 Dec 2015 18:30:50 +0100 Subject: [PATCH 188/203] Can delete individual msgs. --- src/services/tt-rss/ttrssserviceroot.cpp | 37 +++++++++++++++++++----- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 20ea46865..8b5f54c68 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -138,12 +138,17 @@ RecycleBin *TtRssServiceRoot::recycleBin() { } bool TtRssServiceRoot::loadMessagesForItem(RootItem *item, QSqlTableModel *model) { - QList children = item->getSubTreeFeeds(); - QString filter_clause = textualFeedIds(children).join(QSL(", ")); + if (item->kind() == RootItemKind::Bin) { + model->setFilter(QString("is_deleted = 1 AND is_pdeleted = 0 AND account_id = %1").arg(QString::number(accountId()))); + } + else { + QList children = item->getSubTreeFeeds(); + QString filter_clause = textualFeedIds(children).join(QSL(", ")); - model->setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = '%2'")).arg(filter_clause, - QString::number(accountId()))); - qDebug("Loading messages from feeds: %s.", qPrintable(filter_clause)); + model->setFilter(QString(QSL("feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0 AND account_id = '%2'")).arg(filter_clause, + QString::number(accountId()))); + qDebug("Loading messages from feeds: %s.", qPrintable(filter_clause)); + } return true; } @@ -221,11 +226,29 @@ bool TtRssServiceRoot::onAfterSwitchMessageImportance(RootItem *selected_item, c } bool TtRssServiceRoot::onBeforeMessagesDelete(RootItem *selected_item, const QList &messages) { - return false; + Q_UNUSED(selected_item) + Q_UNUSED(messages) + + return true; } bool TtRssServiceRoot::onAfterMessagesDelete(RootItem *selected_item, const QList &messages) { - return false; + Q_UNUSED(messages) + + // User deleted some messages he selected in message list. + selected_item->updateCounts(true); + + if (selected_item->kind() == RootItemKind::Bin) { + itemChanged(QList() << m_recycleBin); + } + else { + m_recycleBin->updateCounts(true); + itemChanged(QList() << selected_item << m_recycleBin); + } + + + requestFeedReadFilterReload(); + return true; } bool TtRssServiceRoot::onBeforeMessagesRestoredFromBin(RootItem *selected_item, const QList &messages) { From ffd220e4f2cab85192e1427b736fb505d66b3c05 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 13 Dec 2015 09:36:37 +0100 Subject: [PATCH 189/203] Much work, cleaning, marking... --- src/services/abstract/recyclebin.cpp | 2 +- src/services/abstract/rootitem.cpp | 13 ++++- src/services/standard/standardserviceroot.cpp | 4 +- src/services/tt-rss/ttrsscategory.cpp | 4 ++ src/services/tt-rss/ttrsscategory.h | 1 + src/services/tt-rss/ttrssfeed.cpp | 4 ++ src/services/tt-rss/ttrssfeed.h | 1 + src/services/tt-rss/ttrssrecyclebin.cpp | 25 ++++++++ src/services/tt-rss/ttrssrecyclebin.h | 6 ++ src/services/tt-rss/ttrssserviceroot.cpp | 57 ++++++++++++++++--- src/services/tt-rss/ttrssserviceroot.h | 1 + 11 files changed, 105 insertions(+), 13 deletions(-) diff --git a/src/services/abstract/recyclebin.cpp b/src/services/abstract/recyclebin.cpp index 5cc27df93..7f0ad4fc1 100755 --- a/src/services/abstract/recyclebin.cpp +++ b/src/services/abstract/recyclebin.cpp @@ -147,7 +147,7 @@ bool RecycleBin::markAsReadUnread(RootItem::ReadStatus status) { // Commit changes. if (db_handle.commit()) { - updateCounts(true); + updateCounts(false); parent_root->itemChanged(QList() << this); parent_root->requestReloadMessageList(status == RootItem::Read); diff --git a/src/services/abstract/rootitem.cpp b/src/services/abstract/rootitem.cpp index db3f6d039..f7745907b 100755 --- a/src/services/abstract/rootitem.cpp +++ b/src/services/abstract/rootitem.cpp @@ -20,6 +20,7 @@ #include "services/abstract/serviceroot.h" #include "services/abstract/feed.h" #include "services/abstract/category.h" +#include "services/abstract/recyclebin.h" #include "miscellaneous/application.h" #include @@ -84,9 +85,19 @@ QList RootItem::undeletedMessages() const { bool RootItem::cleanMessages(bool clear_only_read) { bool result = true; + RecycleBin *bin = NULL; foreach (RootItem *child, m_childItems) { - result &= child->cleanMessages(clear_only_read); + if (child->kind() == RootItemKind::Bin) { + bin = qobject_cast(child); + } + else { + result &= child->cleanMessages(clear_only_read); + } + } + + if (bin != NULL) { + result &= bin->cleanMessages(clear_only_read); } return result; diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 97a974fb1..8fa26db42 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -196,14 +196,14 @@ bool StandardServiceRoot::cleanFeeds(QList items, bool clean_read_only) { if (clean_read_only) { if (!query_delete_msg.prepare(QString("UPDATE Messages SET is_deleted = :deleted " - "WHERE feed IN (%1) AND is_deleted = 0 AND is_read = 1;").arg(textualFeedIds(items).join(QSL(", "))))) { + "WHERE feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0 AND is_read = 1;").arg(textualFeedIds(items).join(QSL(", "))))) { qWarning("Query preparation failed for feeds clearing."); return false; } } else { if (!query_delete_msg.prepare(QString("UPDATE Messages SET is_deleted = :deleted " - "WHERE feed IN (%1) AND is_deleted = 0;").arg(textualFeedIds(items).join(QSL(", "))))) { + "WHERE feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0;").arg(textualFeedIds(items).join(QSL(", "))))) { qWarning("Query preparation failed for feeds clearing."); return false; } diff --git a/src/services/tt-rss/ttrsscategory.cpp b/src/services/tt-rss/ttrsscategory.cpp index ac5e11641..5ad6de9f4 100755 --- a/src/services/tt-rss/ttrsscategory.cpp +++ b/src/services/tt-rss/ttrsscategory.cpp @@ -62,6 +62,10 @@ bool TtRssCategory::markAsReadUnread(RootItem::ReadStatus status) { } } +bool TtRssCategory::cleanMessages(bool clear_only_read) { + return serviceRoot()->cleanFeeds(getSubTreeFeeds(), clear_only_read); +} + int TtRssCategory::customId() const { return m_customId; } diff --git a/src/services/tt-rss/ttrsscategory.h b/src/services/tt-rss/ttrsscategory.h index 599b8751e..1fcd9ccf5 100755 --- a/src/services/tt-rss/ttrsscategory.h +++ b/src/services/tt-rss/ttrsscategory.h @@ -36,6 +36,7 @@ class TtRssCategory : public Category { TtRssServiceRoot *serviceRoot(); bool markAsReadUnread(ReadStatus status); + bool cleanMessages(bool clear_only_read); int customId() const; void setCustomId(int custom_id); diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index a1e9ce144..6a724c639 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -161,6 +161,10 @@ bool TtRssFeed::markAsReadUnread(RootItem::ReadStatus status) { } } +bool TtRssFeed::cleanMessages(bool clear_only_read) { + return serviceRoot()->cleanFeeds(QList() << this, clear_only_read); +} + int TtRssFeed::customId() const { return m_customId; } diff --git a/src/services/tt-rss/ttrssfeed.h b/src/services/tt-rss/ttrssfeed.h index c49501049..66c6838a6 100755 --- a/src/services/tt-rss/ttrssfeed.h +++ b/src/services/tt-rss/ttrssfeed.h @@ -44,6 +44,7 @@ class TtRssFeed : public Feed { QList undeletedMessages() const; bool markAsReadUnread(ReadStatus status); + bool cleanMessages(bool clear_only_read); int customId() const; void setCustomId(int custom_id); diff --git a/src/services/tt-rss/ttrssrecyclebin.cpp b/src/services/tt-rss/ttrssrecyclebin.cpp index 80b477a7d..9cc7c96cd 100755 --- a/src/services/tt-rss/ttrssrecyclebin.cpp +++ b/src/services/tt-rss/ttrssrecyclebin.cpp @@ -17,6 +17,10 @@ #include "services/tt-rss/ttrssrecyclebin.h" +#include "services/tt-rss/definitions.h" +#include "services/tt-rss/network/ttrssnetworkfactory.h" +#include "services/tt-rss/ttrssserviceroot.h" + TtRssRecycleBin::TtRssRecycleBin(RootItem *parent) : RecycleBin(parent) { @@ -24,3 +28,24 @@ TtRssRecycleBin::TtRssRecycleBin(RootItem *parent) : RecycleBin(parent) { TtRssRecycleBin::~TtRssRecycleBin() { } + +TtRssServiceRoot *TtRssRecycleBin::serviceRoot() { + return qobject_cast(getParentServiceRoot()); +} + +bool TtRssRecycleBin::markAsReadUnread(RootItem::ReadStatus status) { + QNetworkReply::NetworkError error; + QStringList ids = serviceRoot()->customIDSOfMessagesForItem(this); + TtRssUpdateArticleResponse response = serviceRoot()->network()->updateArticles(ids, UpdateArticle::Unread, + status == RootItem::Unread ? + UpdateArticle::SetToTrue : + UpdateArticle::SetToFalse, + error); + + if (error != QNetworkReply::NoError || response.updateStatus() != STATUS_OK) { + return false; + } + else { + return RecycleBin::markAsReadUnread(status); + } +} diff --git a/src/services/tt-rss/ttrssrecyclebin.h b/src/services/tt-rss/ttrssrecyclebin.h index b235863aa..a013aae74 100755 --- a/src/services/tt-rss/ttrssrecyclebin.h +++ b/src/services/tt-rss/ttrssrecyclebin.h @@ -21,12 +21,18 @@ #include "services/abstract/recyclebin.h" +class TtRssServiceRoot; + class TtRssRecycleBin : public RecycleBin { Q_OBJECT public: explicit TtRssRecycleBin(RootItem *parent = 0); virtual ~TtRssRecycleBin(); + + TtRssServiceRoot *serviceRoot(); + + bool markAsReadUnread(ReadStatus status); }; #endif // TTRSSRECYCLEBIN_H diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 8b5f54c68..885c3b3a4 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -43,15 +43,13 @@ TtRssServiceRoot::TtRssServiceRoot(RootItem *parent) } TtRssServiceRoot::~TtRssServiceRoot() { - if (m_network != NULL) { - delete m_network; - } + delete m_network; } void TtRssServiceRoot::start() { loadFromDatabase(); - if (childCount() == 0) { + if (childCount() == 1 && child(0)->kind() == RootItemKind::Bin) { syncIn(); } } @@ -158,7 +156,6 @@ QList TtRssServiceRoot::serviceMenu() { m_actionSyncIn = new QAction(qApp->icons()->fromTheme(QSL("item-sync")), tr("Sync in"), this); connect(m_actionSyncIn, SIGNAL(triggered()), this, SLOT(syncIn())); - m_serviceMenu.append(m_actionSyncIn); } @@ -178,7 +175,7 @@ bool TtRssServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, const QL read == RootItem::Unread ? UpdateArticle::SetToTrue : UpdateArticle::SetToFalse, error); - if (error == QNetworkReply::NoError && response.updateStatus() == STATUS_OK && response.articlesUpdated() == messages.size()) { + if (error == QNetworkReply::NoError && response.updateStatus() == STATUS_OK) { return true; } else { @@ -191,7 +188,6 @@ bool TtRssServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, const QLi Q_UNUSED(read) selected_item->updateCounts(false); - itemChanged(QList() << selected_item); requestFeedReadFilterReload(); return true; @@ -210,7 +206,7 @@ bool TtRssServiceRoot::onBeforeSwitchMessageImportance(RootItem *selected_item, UpdateArticle::Togggle, error); - if (error == QNetworkReply::NoError && response.updateStatus() == STATUS_OK && response.articlesUpdated() == changes.size()) { + if (error == QNetworkReply::NoError && response.updateStatus() == STATUS_OK) { return true; } else { @@ -246,7 +242,6 @@ bool TtRssServiceRoot::onAfterMessagesDelete(RootItem *selected_item, const QLis itemChanged(QList() << selected_item << m_recycleBin); } - requestFeedReadFilterReload(); return true; } @@ -378,6 +373,50 @@ bool TtRssServiceRoot::markFeedsReadUnread(QList items, RootItem::ReadSta } } +bool TtRssServiceRoot::cleanFeeds(QList items, bool clean_read_only) { + QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); + QSqlQuery query_delete_msg(db_handle); + query_delete_msg.setForwardOnly(true); + + if (clean_read_only) { + if (!query_delete_msg.prepare(QString("UPDATE Messages SET is_deleted = :deleted " + "WHERE feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0 AND is_read = 1;").arg(textualFeedIds(items).join(QSL(", "))))) { + qWarning("Query preparation failed for feeds clearing."); + return false; + } + } + else { + if (!query_delete_msg.prepare(QString("UPDATE Messages SET is_deleted = :deleted " + "WHERE feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0;").arg(textualFeedIds(items).join(QSL(", "))))) { + qWarning("Query preparation failed for feeds clearing."); + return false; + } + } + + query_delete_msg.bindValue(QSL(":deleted"), 1); + + if (!query_delete_msg.exec()) { + qDebug("Query execution for feeds clearing failed."); + return false; + } + else { + // Messages are cleared, now inform model about need to reload data. + QList itemss; + + foreach (Feed *feed, items) { + feed->updateCounts(true); + itemss.append(feed); + } + + m_recycleBin->updateCounts(true); + itemss.append(m_recycleBin); + + itemChanged(itemss); + requestReloadMessageList(true); + return true; + } +} + void TtRssServiceRoot::saveAccountDataToDatabase() { if (accountId() != NO_PARENT_CATEGORY) { // We are overwritting previously saved data. diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 968d27cb0..af2277e3f 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -75,6 +75,7 @@ class TtRssServiceRoot : public ServiceRoot { QStringList customIDSOfMessagesForItem(RootItem *item); bool markFeedsReadUnread(QList items, ReadStatus read); + bool cleanFeeds(QList items, bool clean_read_only); void saveAccountDataToDatabase(); void updateTitle(); From 156edc97538ebc7acac995bd15aa85267658b7d2 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 13 Dec 2015 17:59:05 +0100 Subject: [PATCH 190/203] Logout shit. --- src/services/tt-rss/gui/formeditaccount.cpp | 3 +++ .../tt-rss/network/ttrssnetworkfactory.cpp | 14 +++++--------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/services/tt-rss/gui/formeditaccount.cpp b/src/services/tt-rss/gui/formeditaccount.cpp index 67e9d3d8c..ccf0a517d 100755 --- a/src/services/tt-rss/gui/formeditaccount.cpp +++ b/src/services/tt-rss/gui/formeditaccount.cpp @@ -154,6 +154,9 @@ void FormEditAccount::onClickedOk() { m_editableRoot->saveAccountDataToDatabase(); if (editing_account) { + QNetworkReply::NetworkError error; + + m_editableRoot->network()->logout(error); m_editableRoot->completelyRemoveAllData(); m_editableRoot->syncIn(); } diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index 5ba9927bd..d7fb4c024 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -66,15 +66,6 @@ QDateTime TtRssNetworkFactory::lastLoginTime() const { return m_lastLoginTime; } -// TODO: ukazky - -/* ukazky - * prihlaseni - curl -L -d '{"op":"login","user":"admin","password":"XXX"}' http://rss.rotterovi.eu/api/ - * ziska seznam VSECH zprav - curl -L -d '{"sid":"xxx","op":"getHeadlines","feed_id":-4,"include_nested":true,"include_attachments":true,"show_content":true}' http://rss.rotterovi.eu/api/ - * seznam kategorii vcetne unread countu - curl -L -d '{"sid":"e9528741496d0d6aa5021e67ca519823","op":"getCategories","include_nested":true,"include_empty":false}' http://rss.rotterovi.eu/api/ - * */ - - TtRssLoginResponse TtRssNetworkFactory::login(QNetworkReply::NetworkError &error) { if (!m_sessionId.isEmpty()) { logout(error); @@ -109,6 +100,11 @@ TtRssResponse TtRssNetworkFactory::logout(QNetworkReply::NetworkError &error) { NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); error = network_reply.first; + + if (error == QNetworkReply::NoError) { + m_sessionId.clear(); + } + return TtRssResponse(QString::fromUtf8(result_raw)); } else { From ce7e0f657923bd2d668683c80bd0022d4790c7f4 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 13 Dec 2015 18:10:50 +0100 Subject: [PATCH 191/203] Fixed #131. --- resources/text/CHANGELOG | 1 + src/core/feedsmodel.cpp | 10 +++++----- src/core/feedsmodel.h | 6 +++--- src/main.cpp | 9 +++++---- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index b602cd783..6fede8370 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -24,6 +24,7 @@ Fixed:
                    +
                  • Fixed bug with updating feed. (bug #131)
                  • Solved problem when user selects HUGE number of individual messages and marks them read/unread. Reselecting them after change may cause RSS Guard to hang.
                  • Better info in popup notification when many feeds are updated.
                  • Fixed obtaining of contents in RSS 2.0 feed entries. (bug #130)
                  • diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 6563466d5..2a2a3164d 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -72,11 +72,6 @@ FeedsModel::FeedsModel(QObject *parent) //loadActivatedServiceAccounts(); updateAutoUpdateStatus(); - - if (qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::FeedsUpdateOnStartup)).toBool()) { - qDebug("Requesting update for all feeds on application startup."); - QTimer::singleShot(STARTUP_UPDATE_DELAY, this, SLOT(updateAllItems())); - } } FeedsModel::~FeedsModel() { @@ -739,6 +734,11 @@ void FeedsModel::loadActivatedServiceAccounts() { addServiceAccount(root); } } + + if (qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::FeedsUpdateOnStartup)).toBool()) { + qDebug("Requesting update for all feeds on application startup."); + QTimer::singleShot(STARTUP_UPDATE_DELAY, this, SLOT(updateAllFeeds())); + } } QList FeedsModel::feedsForIndex(const QModelIndex &index) { diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index 73c641b6c..6807b6709 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -145,9 +145,6 @@ class FeedsModel : public QAbstractItemModel { // Schedules given feeds for update. void updateFeeds(const QList &feeds); - // Schedules all feeds from all accounts for update. - void updateAllFeeds(); - // Adds given service root account. bool addServiceAccount(ServiceRoot *root); @@ -155,6 +152,9 @@ class FeedsModel : public QAbstractItemModel { void loadActivatedServiceAccounts(); public slots: + // Schedules all feeds from all accounts for update. + void updateAllFeeds(); + // Checks if new parent node is different from one used by original node. // If it is, then it reassigns original_node to new parent. void reassignNodeToNewParent(RootItem *original_node, RootItem *new_parent); diff --git a/src/main.cpp b/src/main.cpp index 94736dd08..eb23d82c4 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -117,10 +117,6 @@ int main(int argc, char *argv[]) { qApp->showTrayIcon(); } - if (qApp->settings()->value(GROUP(General), SETTING(General::UpdateOnStartup)).toBool()) { - QTimer::singleShot(STARTUP_UPDATE_DELAY, application.system(), SLOT(checkForUpdatesOnStartup())); - } - // Load activated accounts. qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->loadActivatedServiceAccounts(); qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->loadExpandedStates(); @@ -137,6 +133,11 @@ int main(int argc, char *argv[]) { qApp->showGuiMessage(QSL(APP_NAME), QObject::tr("Welcome to %1.").arg(APP_LONG_NAME), QSystemTrayIcon::NoIcon); } + if (qApp->settings()->value(GROUP(General), SETTING(General::UpdateOnStartup)).toBool()) { + QTimer::singleShot(STARTUP_UPDATE_DELAY, application.system(), SLOT(checkForUpdatesOnStartup())); + } + + // Enter global event loop. return Application::exec(); } From 0900d68dcaa1d32c1d5fffdc41ba0c2445edf688 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 13 Dec 2015 18:21:06 +0100 Subject: [PATCH 192/203] Refactored data getter a bit. --- src/services/abstract/feed.cpp | 19 +++++ src/services/abstract/feed.h | 4 + src/services/standard/standardfeed.cpp | 108 +++++++++++-------------- src/services/standard/standardfeed.h | 3 +- src/services/tt-rss/ttrssfeed.cpp | 8 +- 5 files changed, 80 insertions(+), 62 deletions(-) diff --git a/src/services/abstract/feed.cpp b/src/services/abstract/feed.cpp index 2faabce27..8183d158e 100755 --- a/src/services/abstract/feed.cpp +++ b/src/services/abstract/feed.cpp @@ -31,3 +31,22 @@ Feed::Feed(RootItem *parent) : RootItem(parent) { Feed::~Feed() { } + +QVariant Feed::data(int column, int role) const { + switch (role) { + case Qt::ForegroundRole: + switch (status()) { + case NewMessages: + return QColor(Qt::blue); + + case NetworkError: + return QColor(Qt::red); + + default: + return QVariant(); + } + + default: + return RootItem::data(column, role); + } +} diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index 459f4e6cf..edd1362d5 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -22,6 +22,8 @@ #include "core/message.h" +#include + // Base class for "feed" nodes. class Feed : public RootItem { @@ -61,6 +63,8 @@ class Feed : public RootItem { // messages. virtual int update() = 0; + QVariant data(int column, int role) const; + ///////////////////////////////////////// // Members to override. */ ///////////////////////////////////////// diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 9057b67d9..92c74b20c 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -160,6 +160,54 @@ QList StandardFeed::undeletedMessages() const { return messages; } +QVariant StandardFeed::data(int column, int role) const { + switch (role) { + case Qt::ToolTipRole: + if (column == FDS_MODEL_TITLE_INDEX) { + QString auto_update_string; + + switch (autoUpdateType()) { + case DontAutoUpdate: + //: Describes feed auto-update status. + auto_update_string = tr("does not use auto-update"); + break; + + case DefaultAutoUpdate: + //: Describes feed auto-update status. + auto_update_string = tr("uses global settings"); + break; + + case SpecificAutoUpdate: + default: + //: Describes feed auto-update status. + auto_update_string = tr("uses specific settings " + "(%n minute(s) to next auto-update)", + 0, + autoUpdateRemainingInterval()); + break; + } + + //: Tooltip for feed. + return tr("%1 (%2)" + "%3\n\n" + "Network status: %6\n" + "Encoding: %4\n" + "Auto-update status: %5").arg(title(), + StandardFeed::typeToString(type()), + description().isEmpty() ? QString() : QString('\n') + description(), + encoding(), + auto_update_string, + NetworkFactory::networkErrorText(m_networkError)); + } + else { + return Feed::data(column, role); + } + + default: + return Feed::data(column, role); + } +} + QString StandardFeed::typeToString(StandardFeed::Type type) { switch (type) { case Atom10: @@ -372,66 +420,6 @@ QPair StandardFeed::guessFeed(const Q return result; } -QVariant StandardFeed::data(int column, int role) const { - switch (role) { - case Qt::ToolTipRole: - if (column == FDS_MODEL_TITLE_INDEX) { - QString auto_update_string; - - switch (autoUpdateType()) { - case DontAutoUpdate: - //: Describes feed auto-update status. - auto_update_string = tr("does not use auto-update"); - break; - - case DefaultAutoUpdate: - //: Describes feed auto-update status. - auto_update_string = tr("uses global settings"); - break; - - case SpecificAutoUpdate: - default: - //: Describes feed auto-update status. - auto_update_string = tr("uses specific settings " - "(%n minute(s) to next auto-update)", - 0, - autoUpdateRemainingInterval()); - break; - } - - //: Tooltip for feed. - return tr("%1 (%2)" - "%3\n\n" - "Network status: %6\n" - "Encoding: %4\n" - "Auto-update status: %5").arg(title(), - StandardFeed::typeToString(type()), - description().isEmpty() ? QString() : QString('\n') + description(), - encoding(), - auto_update_string, - NetworkFactory::networkErrorText(m_networkError)); - } - else { - return Feed::data(column, role); - } - - case Qt::ForegroundRole: - switch (status()) { - case NewMessages: - return QColor(Qt::blue); - - case NetworkError: - return QColor(Qt::red); - - default: - return QVariant(); - } - - default: - return Feed::data(column, role); - } -} - Qt::ItemFlags StandardFeed::additionalFlags() const { return Qt::ItemIsDragEnabled; } diff --git a/src/services/standard/standardfeed.h b/src/services/standard/standardfeed.h index de1b8db56..84a414c96 100755 --- a/src/services/standard/standardfeed.h +++ b/src/services/standard/standardfeed.h @@ -79,8 +79,9 @@ class StandardFeed : public Feed { QList undeletedMessages() const; - // Obtains data related to this feed. QVariant data(int column, int role) const; + + // Obtains data related to this feed. Qt::ItemFlags additionalFlags() const; bool performDragDropChange(RootItem *target_item); diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index 6a724c639..be6bea0aa 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -289,7 +289,13 @@ int TtRssFeed::updateMessages(const QList &messages) { qDebug("Transaction commit for message downloader failed."); } else { - setStatus(NewMessages); + if (updated_messages > 0) { + setStatus(NewMessages); + } + else { + setStatus(Normal); + } + updateCounts(true); serviceRoot()->itemChanged(QList() << this); } From 662bea00eb95cf115b20d7bb01e2307e86feeff5 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 13 Dec 2015 18:21:54 +0100 Subject: [PATCH 193/203] Refactored data getter a bit. --- src/services/standard/standardfeed.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 92c74b20c..c548c7646 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -49,7 +49,7 @@ StandardFeed::StandardFeed(RootItem *parent_item) m_passwordProtected = false; m_username = QString(); m_password = QString(); - m_networkError = QNetworkReply::NoError; + m_networkError = QNetworkReply::NoError; // TODO: mozna i networkError refaktorovat do Feed předka m_type = Rss0X; m_totalCount = 0; m_unreadCount = 0; From a86ab15e2e30e93facdaccd996f4fd2848e2d209 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 14 Dec 2015 07:06:15 +0100 Subject: [PATCH 194/203] Database schema update, URLs are not not NOT NULL. --- resources/misc/db_init_mysql.sql | 2 +- resources/misc/db_init_sqlite.sql | 2 +- resources/misc/db_update_mysql_3_4.sql | 7 ++- resources/misc/db_update_sqlite_3_4.sql | 33 +++------- src/miscellaneous/databasefactory.cpp | 63 +++++++++---------- src/miscellaneous/databasefactory.h | 3 - .../tt-rss/ttrssserviceentrypoint.cpp | 2 +- 7 files changed, 48 insertions(+), 64 deletions(-) diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index c882d52af..a3fc21ca9 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -76,7 +76,7 @@ CREATE TABLE IF NOT EXISTS Messages ( is_important INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_important >= 0 AND is_important <= 1), feed TEXT NOT NULL, title TEXT NOT NULL CHECK (title != ''), - url TEXT NOT NULL, + url TEXT, author TEXT, date_created BIGINT NOT NULL CHECK (date_created != 0), contents TEXT, diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index 01f7e09ab..72bb11663 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -71,7 +71,7 @@ CREATE TABLE IF NOT EXISTS Messages ( is_important INTEGER(1) NOT NULL CHECK (is_important >= 0 AND is_important <= 1) DEFAULT (0), feed TEXT NOT NULL, title TEXT NOT NULL CHECK (title != ''), - url TEXT NOT NULL, + url TEXT, author TEXT, date_created INTEGER NOT NULL CHECK (date_created != 0), contents TEXT, diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index 289eec2f2..ae42d6970 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -1,4 +1,4 @@ -CREATE TABLE IF NOT EXISTS Accounts ( +CREATE TABLE Accounts ( id INTEGER PRIMARY KEY, type TEXT NOT NULL ); @@ -7,7 +7,7 @@ INSERT INTO Accounts (type) VALUES ('std-rss'); -- ! DROP TABLE IF EXISTS FeedsData; -- ! -CREATE TABLE IF NOT EXISTS TtRssAccounts ( +CREATE TABLE TtRssAccounts ( id INTEGER, username TEXT NOT NULL, password TEXT, @@ -58,4 +58,7 @@ MODIFY date_created BIGINT; ALTER TABLE Messages MODIFY author TEXT; -- ! +ALTER TABLE Messages +MODIFY url TEXT; +-- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql index 1763e54d9..5923577b3 100644 --- a/resources/misc/db_update_sqlite_3_4.sql +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -1,4 +1,4 @@ -CREATE TABLE IF NOT EXISTS Accounts ( +CREATE TABLE Accounts ( id INTEGER PRIMARY KEY, type TEXT NOT NULL ); @@ -7,7 +7,7 @@ INSERT INTO Accounts (type) VALUES ('std-rss'); -- ! DROP TABLE IF EXISTS FeedsData; -- ! -CREATE TABLE IF NOT EXISTS TtRssAccounts ( +CREATE TABLE TtRssAccounts ( id INTEGER, username TEXT NOT NULL, password TEXT, @@ -16,24 +16,6 @@ CREATE TABLE IF NOT EXISTS TtRssAccounts ( FOREIGN KEY (id) REFERENCES Accounts (id) ); -- ! -ALTER TABLE Messages -ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); --- ! -ALTER TABLE Feeds -ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); --- ! -ALTER TABLE Categories -ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); --- ! -ALTER TABLE Messages -ADD COLUMN custom_id TEXT; --- ! -ALTER TABLE Feeds -ADD COLUMN custom_id TEXT; --- ! -ALTER TABLE Categories -ADD COLUMN custom_id TEXT; --- ! CREATE TABLE backup_Messages AS SELECT * FROM Messages; -- ! DROP TABLE Messages; @@ -45,7 +27,7 @@ CREATE TABLE Messages ( is_important INTEGER(1) NOT NULL CHECK (is_important >= 0 AND is_important <= 1) DEFAULT (0), feed TEXT NOT NULL, title TEXT NOT NULL CHECK (title != ''), - url TEXT NOT NULL, + url TEXT, author TEXT, date_created INTEGER NOT NULL CHECK (date_created != 0), contents TEXT, @@ -57,7 +39,8 @@ CREATE TABLE Messages ( FOREIGN KEY (account_id) REFERENCES Accounts (id) ); -- ! -INSERT INTO Messages SELECT * FROM backup_Messages; +INSERT INTO Messages (id, is_read, is_deleted, is_important, feed, title, url, author, date_created, contents, is_pdeleted, enclosures, account_id) +SELECT id, is_read, is_deleted, is_important, feed, title, url, author, date_created, contents, is_pdeleted, enclosures, 1 FROM backup_Messages; -- ! DROP TABLE backup_Messages; -- ! @@ -86,7 +69,8 @@ CREATE TABLE Feeds ( FOREIGN KEY (account_id) REFERENCES Accounts (id) ); -- ! -INSERT INTO Feeds SELECT * FROM backup_Feeds; +INSERT INTO Feeds (id, title, description, date_created, icon, category, encoding, url, protected, username, password, update_type, update_type, type, account_id) +SELECT id, title, description, date_created, icon, category, encoding, url, protected, username, password, update_type, update_type, type, 1 FROM backup_Feeds; -- ! DROP TABLE backup_Feeds; -- ! @@ -107,7 +91,8 @@ CREATE TABLE Categories ( FOREIGN KEY (account_id) REFERENCES Accounts (id) ); -- ! -INSERT INTO Categories SELECT * FROM backup_Categories; +INSERT INTO Categories (id, parent_id, title, description, date_created, icon, account_id) +SELECT id, parent_id, title, description, date_created, icon, 1 FROM backup_Categories; -- ! DROP TABLE backup_Categories; -- ! diff --git a/src/miscellaneous/databasefactory.cpp b/src/miscellaneous/databasefactory.cpp index 6a7b6da61..374dcf71e 100755 --- a/src/miscellaneous/databasefactory.cpp +++ b/src/miscellaneous/databasefactory.cpp @@ -300,15 +300,17 @@ QSqlDatabase DatabaseFactory::sqliteInitializeFileBasedDatabase(const QString &c QString installed_db_schema = query_db.value(0).toString(); query_db.finish(); - if (!updateDatabaseSchema(database, installed_db_schema)) { - qFatal("Database schema was not updated from '%s' to '%s' successully.", - qPrintable(installed_db_schema), - APP_DB_SCHEMA_VERSION); - } - else if (installed_db_schema != APP_DB_SCHEMA_VERSION) { - qDebug("Database schema was updated from '%s' to '%s' successully or it is already up to date.", - qPrintable(installed_db_schema), - APP_DB_SCHEMA_VERSION); + if (installed_db_schema < APP_DB_SCHEMA_VERSION) { + if (sqliteUpdateDatabaseSchema(database, installed_db_schema)) { + qDebug("Database schema was updated from '%s' to '%s' successully or it is already up to date.", + qPrintable(installed_db_schema), + APP_DB_SCHEMA_VERSION); + } + else { + qFatal("Database schema was not updated from '%s' to '%s' successully.", + qPrintable(installed_db_schema), + APP_DB_SCHEMA_VERSION); + } } qDebug("File-based SQLite database connection '%s' to file '%s' seems to be established.", @@ -328,24 +330,18 @@ QString DatabaseFactory::sqliteDatabaseFilePath() const { return m_sqliteDatabaseFilePath + QDir::separator() + APP_DB_SQLITE_FILE; } -bool DatabaseFactory::updateDatabaseSchema(QSqlDatabase database, const QString &source_db_schema_version) { - switch (m_activeDatabaseDriver) { - case SQLITE: - case SQLITE_MEMORY: - return sqliteUpdateDatabaseSchema(database, source_db_schema_version); - - case MYSQL: - return mysqlUpdateDatabaseSchema(database, source_db_schema_version); - - default: - return false; - } -} - bool DatabaseFactory::sqliteUpdateDatabaseSchema(QSqlDatabase database, const QString &source_db_schema_version) { int working_version = QString(source_db_schema_version).remove('.').toInt(); int current_version = QString(APP_DB_SCHEMA_VERSION).remove('.').toInt(); + // Now, it would be good to create backup of SQLite DB file. + if (IOFactory::copyFile(sqliteDatabaseFilePath(), sqliteDatabaseFilePath() + ".bak")) { + qDebug("Creating backup of SQLite DB file."); + } + else { + qFatal("Creation of backup SQLite DB file failed."); + } + while (working_version != current_version) { QString update_file_name = QString(APP_MISC_PATH) + QDir::separator() + QString(APP_DB_UPDATE_FILE_PATTERN).arg(QSL("sqlite"), @@ -611,15 +607,18 @@ QSqlDatabase DatabaseFactory::mysqlInitializeDatabase(const QString &connection_ QString installed_db_schema = query_db.value(0).toString(); - if (!mysqlUpdateDatabaseSchema(database, installed_db_schema)) { - qFatal("Database schema was not updated from '%s' to '%s' successully.", - qPrintable(installed_db_schema), - APP_DB_SCHEMA_VERSION); - } - else if (installed_db_schema != APP_DB_SCHEMA_VERSION) { - qDebug("Database schema was updated from '%s' to '%s' successully or it is already up to date.", - qPrintable(installed_db_schema), - APP_DB_SCHEMA_VERSION); + if (installed_db_schema < APP_DB_SCHEMA_VERSION) { + if (mysqlUpdateDatabaseSchema(database, installed_db_schema)) { + qDebug("Database schema was updated from '%s' to '%s' successully or it is already up to date.", + qPrintable(installed_db_schema), + APP_DB_SCHEMA_VERSION); + + } + else { + qFatal("Database schema was not updated from '%s' to '%s' successully.", + qPrintable(installed_db_schema), + APP_DB_SCHEMA_VERSION); + } } } diff --git a/src/miscellaneous/databasefactory.h b/src/miscellaneous/databasefactory.h index b1f0d2b80..453d8e61f 100755 --- a/src/miscellaneous/databasefactory.h +++ b/src/miscellaneous/databasefactory.h @@ -116,9 +116,6 @@ 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. UsedDriver m_activeDatabaseDriver; diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp index c0b2565ed..29288cee7 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.cpp +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -50,7 +50,7 @@ QString TtRssServiceEntryPoint::description() { } QString TtRssServiceEntryPoint::version() { - return QSL("0.0.2"); + return APP_VERSION; } QString TtRssServiceEntryPoint::author() { From 7d130395332f78060b3460aadca5495ddc52af14 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 14 Dec 2015 07:22:34 +0100 Subject: [PATCH 195/203] Refactor MySQL update script a bit. --- resources/misc/db_update_mysql_3_4.sql | 36 +++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index ae42d6970..5324d59da 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -19,27 +19,27 @@ CREATE TABLE TtRssAccounts ( ALTER TABLE Messages ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); -- ! -ALTER TABLE Feeds -ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); --- ! -ALTER TABLE Categories -ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); --- ! ALTER TABLE Messages ADD COLUMN custom_id TEXT; -- ! -ALTER TABLE Feeds -ADD COLUMN custom_id TEXT; --- ! -ALTER TABLE Categories -ADD COLUMN custom_id TEXT; --- ! ALTER TABLE Messages DROP FOREIGN KEY feed; -- ! ALTER TABLE Messages MODIFY feed TEXT NOT NULL; -- ! +ALTER TABLE Messages +MODIFY author TEXT; +-- ! +ALTER TABLE Messages +MODIFY url TEXT; +-- ! +ALTER TABLE Feeds +ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); +-- ! +ALTER TABLE Feeds +ADD COLUMN custom_id TEXT; +-- ! ALTER TABLE Feeds MODIFY date_created BIGINT; -- ! @@ -53,12 +53,12 @@ ALTER TABLE Feeds MODIFY type INTEGER; -- ! ALTER TABLE Categories +ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); +-- ! +ALTER TABLE Categories +ADD COLUMN custom_id TEXT; +-- ! +ALTER TABLE Categories MODIFY date_created BIGINT; -- ! -ALTER TABLE Messages -MODIFY author TEXT; --- ! -ALTER TABLE Messages -MODIFY url TEXT; --- ! UPDATE Information SET inf_value = '4' WHERE inf_key = 'schema_version'; \ No newline at end of file From 7b7fe704d2914f0d336a14aaec1b7c18556cdb4f Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 14 Dec 2015 09:47:03 +0100 Subject: [PATCH 196/203] Added "Accounts" menu and some minor TT-RSS stuff. --- src/gui/dialogs/formmain.cpp | 67 ++++++++++++++---------- src/gui/dialogs/formmain.h | 1 + src/gui/dialogs/formmain.ui | 30 +++++++++-- src/gui/feedmessageviewer.cpp | 5 ++ src/services/abstract/feed.cpp | 2 +- src/services/abstract/feed.h | 2 +- src/services/standard/standardfeed.cpp | 2 +- src/services/tt-rss/ttrssfeed.cpp | 5 +- src/services/tt-rss/ttrssserviceroot.cpp | 8 +++ 9 files changed, 84 insertions(+), 38 deletions(-) diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index 94801af62..98e1b6c60 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -197,34 +197,6 @@ void FormMain::updateAddItemMenu() { m_ui->m_menuAddItem->addMenu(root_menu); } - - if (m_ui->m_menuAddItem->actions().size() > 0) { - m_ui->m_menuAddItem->addSeparator(); - } - - m_ui->m_menuAddItem->addAction(m_ui->m_actionServiceAdd); - - /* - * foreach (ServiceRoot *activated_root, tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->serviceRoots()) { - QMenu *root_menu = new QMenu(activated_root->title(), m_ui->m_menuServices); - root_menu->setIcon(activated_root->icon()); - root_menu->setToolTip(activated_root->description()); - - QList root_actions = activated_root->serviceMenu(); - - if (root_actions.isEmpty()) { - QAction *no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")), - tr("No possible actions"), - m_ui->m_menuServices); - no_action->setEnabled(false); - root_menu->addAction(no_action); - } - else { - root_menu->addActions(root_actions); - } - - m_ui->m_menuServices->addMenu(root_menu); - }*/ } void FormMain::updateRecycleBinMenu() { @@ -270,6 +242,39 @@ void FormMain::updateRecycleBinMenu() { m_ui->m_menuRecycleBin->addAction(m_ui->m_actionEmptyAllRecycleBins); } +void FormMain::updateAccountsMenu() { + m_ui->m_menuAccounts->clear(); + + foreach (ServiceRoot *activated_root, tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->serviceRoots()) { + QMenu *root_menu = new QMenu(activated_root->title(), m_ui->m_menuAccounts); + root_menu->setIcon(activated_root->icon()); + root_menu->setToolTip(activated_root->description()); + + QList root_actions = activated_root->serviceMenu(); + + if (root_actions.isEmpty()) { + QAction *no_action = new QAction(qApp->icons()->fromTheme(QSL("dialog-error")), + tr("No possible actions"), + m_ui->m_menuAccounts); + no_action->setEnabled(false); + root_menu->addAction(no_action); + } + else { + root_menu->addActions(root_actions); + } + + m_ui->m_menuAccounts->addMenu(root_menu); + } + + if (m_ui->m_menuAccounts->actions().size() > 0) { + m_ui->m_menuAccounts->addSeparator(); + } + + m_ui->m_menuAccounts->addAction(m_ui->m_actionServiceAdd); + m_ui->m_menuAccounts->addAction(m_ui->m_actionServiceEdit); + m_ui->m_menuAccounts->addAction(m_ui->m_actionServiceDelete); +} + void FormMain::switchVisibility(bool force_hide) { if (force_hide || isVisible()) { if (SystemTrayIcon::isSystemTrayActivated()) { @@ -368,6 +373,8 @@ void FormMain::setupIcons() { m_ui->m_actionRestoreAllRecycleBins->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-restore-all"))); m_ui->m_actionEmptyAllRecycleBins->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-empty"))); m_ui->m_actionServiceAdd->setIcon(icon_theme_factory->fromTheme(QSL("item-new"))); + m_ui->m_actionServiceEdit->setIcon(icon_theme_factory->fromTheme(QSL("item-edit"))); + m_ui->m_actionServiceDelete->setIcon(icon_theme_factory->fromTheme(QSL("item-remove"))); // Setup icons for underlying components: opened web browsers... foreach (WebBrowser *browser, WebBrowser::runningWebBrowsers()) { @@ -442,6 +449,10 @@ void FormMain::createConnections() { connect(m_ui->m_menuAddItem, SIGNAL(aboutToShow()), this, SLOT(updateAddItemMenu())); connect(m_ui->m_menuRecycleBin, SIGNAL(aboutToShow()), this, SLOT(updateRecycleBinMenu())); + connect(m_ui->m_menuAccounts, SIGNAL(aboutToShow()), this, SLOT(updateAccountsMenu())); + + connect(m_ui->m_actionServiceDelete, SIGNAL(triggered()), m_ui->m_actionDeleteSelectedItem, SIGNAL(triggered())); + connect(m_ui->m_actionServiceEdit, SIGNAL(triggered()), m_ui->m_actionEditSelectedItem, SIGNAL(triggered())); // Menu "File" connections. connect(m_ui->m_actionBackupDatabaseSettings, SIGNAL(triggered()), this, SLOT(backupDatabaseSettings())); diff --git a/src/gui/dialogs/formmain.h b/src/gui/dialogs/formmain.h index 140d9ad79..a5e7dac7b 100755 --- a/src/gui/dialogs/formmain.h +++ b/src/gui/dialogs/formmain.h @@ -76,6 +76,7 @@ class FormMain : public QMainWindow { private slots: void updateAddItemMenu(); void updateRecycleBinMenu(); + void updateAccountsMenu(); // Loads web browser menu if user selects to change tabs. void loadWebBrowserMenu(int index); diff --git a/src/gui/dialogs/formmain.ui b/src/gui/dialogs/formmain.ui index 7e9a1ef3c..ecbb7f392 100755 --- a/src/gui/dialogs/formmain.ui +++ b/src/gui/dialogs/formmain.ui @@ -126,13 +126,12 @@ - Feeds && categories && accounts + Feeds && categories Add &new item - @@ -181,8 +180,17 @@ + + + &Accounts + + + + + + @@ -705,7 +713,7 @@ - &Add new service account + &Add new account @@ -757,6 +765,22 @@ + + + &Edit selected account + + + + + + + + &Delete selected account + + + + + diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 2002cd3a3..f9e7be57b 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -211,7 +211,12 @@ void FeedMessageViewer::updateFeedButtonsAvailability() { form_main->m_ui->m_actionUpdateSelectedItems->setEnabled(!critical_action_running && (feed_selected || category_selected || service_selected)); form_main->m_ui->m_actionViewSelectedItemsNewspaperMode->setEnabled(anything_selected); form_main->m_ui->m_actionExpandCollapseItem->setEnabled(anything_selected); + + form_main->m_ui->m_actionServiceDelete->setEnabled(service_selected); + form_main->m_ui->m_actionServiceEdit->setEnabled(service_selected); + form_main->m_ui->m_menuAddItem->setEnabled(!critical_action_running); + form_main->m_ui->m_menuAccounts->setEnabled(!critical_action_running); form_main->m_ui->m_menuRecycleBin->setEnabled(!critical_action_running); } diff --git a/src/services/abstract/feed.cpp b/src/services/abstract/feed.cpp index 8183d158e..b838c33fb 100755 --- a/src/services/abstract/feed.cpp +++ b/src/services/abstract/feed.cpp @@ -39,7 +39,7 @@ QVariant Feed::data(int column, int role) const { case NewMessages: return QColor(Qt::blue); - case NetworkError: + case Error: return QColor(Qt::red); default: diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index edd1362d5..4b9b9a550 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -43,7 +43,7 @@ class Feed : public RootItem { enum Status { Normal = 0, NewMessages = 1, - NetworkError = 2, + Error = 2, ParsingError = 3, OtherError = 4 }; diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index c548c7646..8f202a466 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -447,7 +447,7 @@ int StandardFeed::update() { if (m_networkError != QNetworkReply::NoError) { qWarning("Error during fetching of new messages for feed '%s' (id %d).", qPrintable(url()), id()); - setStatus(NetworkError); + setStatus(Error); return 0; } else if (status() != NewMessages) { diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index be6bea0aa..f16f5a259 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -96,7 +96,7 @@ int TtRssFeed::update() { true, true, false, error); if (error != QNetworkReply::NoError) { - setStatus(Feed::NetworkError); + setStatus(Feed::Error); return 0; } else { @@ -273,9 +273,6 @@ int TtRssFeed::updateMessages(const QList &messages) { if (query_insert.exec() && query_insert.numRowsAffected() == 1) { updated_messages++; } - else { - QString str = query_insert.lastError().text(); - } query_insert.finish(); diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 885c3b3a4..8f0710883 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -531,6 +531,11 @@ void TtRssServiceRoot::completelyRemoveAllData() { } void TtRssServiceRoot::syncIn() { + QIcon original_icon = icon(); + + setIcon(qApp->icons()->fromTheme(QSL("item-sync"))); + itemChanged(QList() << this); + QNetworkReply::NetworkError err; TtRssGetFeedsCategoriesResponse feed_cats_response = m_network->getFeedsCategories(err); @@ -561,6 +566,9 @@ void TtRssServiceRoot::syncIn() { requestReloadMessageList(true); requestItemExpand(all_items, true); } + + setIcon(original_icon); + itemChanged(QList() << this); } QStringList TtRssServiceRoot::customIDsOfMessages(const QList > &changes) { From 1213c2e742d7b499d4f33471a9e3a0679b2a5828 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 14 Dec 2015 11:32:16 +0100 Subject: [PATCH 197/203] Refactores some of TT-RSS network stuff. --- src/services/tt-rss/definitions.h | 2 + src/services/tt-rss/gui/formeditaccount.cpp | 9 ++-- .../tt-rss/network/ttrssnetworkfactory.cpp | 45 ++++++++++--------- .../tt-rss/network/ttrssnetworkfactory.h | 13 +++--- src/services/tt-rss/ttrsscategory.cpp | 6 +-- src/services/tt-rss/ttrssfeed.cpp | 11 ++--- src/services/tt-rss/ttrssrecyclebin.cpp | 6 +-- src/services/tt-rss/ttrssserviceroot.cpp | 34 ++++++-------- 8 files changed, 59 insertions(+), 67 deletions(-) diff --git a/src/services/tt-rss/definitions.h b/src/services/tt-rss/definitions.h index 391188c76..ab6e91c26 100755 --- a/src/services/tt-rss/definitions.h +++ b/src/services/tt-rss/definitions.h @@ -19,6 +19,8 @@ #define API_STATUS_ERR 1 #define STATUS_OK "OK" +#define CONTENT_NOT_LOADED -1 + // Login. #define API_DISABLED "API_DISABLED" // API is not enabled. #define LOGIN_ERROR "LOGIN_ERROR" // Incorrect password/username. diff --git a/src/services/tt-rss/gui/formeditaccount.cpp b/src/services/tt-rss/gui/formeditaccount.cpp index ccf0a517d..1870d3d6a 100755 --- a/src/services/tt-rss/gui/formeditaccount.cpp +++ b/src/services/tt-rss/gui/formeditaccount.cpp @@ -90,15 +90,14 @@ void FormEditAccount::displayPassword(bool display) { void FormEditAccount::performTest() { TtRssNetworkFactory factory; - QNetworkReply::NetworkError err; factory.setUsername(m_ui->m_txtUsername->lineEdit()->text()); factory.setPassword(m_ui->m_txtPassword->lineEdit()->text()); factory.setUrl(m_ui->m_txtUrl->lineEdit()->text()); - TtRssLoginResponse result = factory.login(err); + TtRssLoginResponse result = factory.login(); - if (err == QNetworkReply::NoError) { + if (factory.lastError() == QNetworkReply::NoError) { if (result.hasError()) { QString error = result.error(); @@ -154,9 +153,7 @@ void FormEditAccount::onClickedOk() { m_editableRoot->saveAccountDataToDatabase(); if (editing_account) { - QNetworkReply::NetworkError error; - - m_editableRoot->network()->logout(error); + m_editableRoot->network()->logout(); m_editableRoot->completelyRemoveAllData(); m_editableRoot->syncIn(); } diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index d7fb4c024..b111cb8d3 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -32,7 +32,7 @@ TtRssNetworkFactory::TtRssNetworkFactory() : m_url(QString()), m_username(QString()), m_password(QString()), m_sessionId(QString()), - m_lastLoginTime(QDateTime()) { + m_lastLoginTime(QDateTime()), m_lastError(QNetworkReply::NoError) { } TtRssNetworkFactory::~TtRssNetworkFactory() { @@ -66,9 +66,13 @@ QDateTime TtRssNetworkFactory::lastLoginTime() const { return m_lastLoginTime; } -TtRssLoginResponse TtRssNetworkFactory::login(QNetworkReply::NetworkError &error) { +QNetworkReply::NetworkError TtRssNetworkFactory::lastError() const { + return m_lastError; +} + +TtRssLoginResponse TtRssNetworkFactory::login() { if (!m_sessionId.isEmpty()) { - logout(error); + logout(); } QtJson::JsonObject json; @@ -85,11 +89,11 @@ TtRssLoginResponse TtRssNetworkFactory::login(QNetworkReply::NetworkError &error m_lastLoginTime = QDateTime::currentDateTime(); } - error = network_reply.first; + m_lastError = network_reply.first; return login_response; } -TtRssResponse TtRssNetworkFactory::logout(QNetworkReply::NetworkError &error) { +TtRssResponse TtRssNetworkFactory::logout() { if (!m_sessionId.isEmpty()) { QtJson::JsonObject json; @@ -99,21 +103,21 @@ TtRssResponse TtRssNetworkFactory::logout(QNetworkReply::NetworkError &error) { QByteArray result_raw; NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); - error = network_reply.first; + m_lastError = network_reply.first; - if (error == QNetworkReply::NoError) { + if (m_lastError == QNetworkReply::NoError) { m_sessionId.clear(); } return TtRssResponse(QString::fromUtf8(result_raw)); } else { - error = QNetworkReply::NoError; + m_lastError = QNetworkReply::NoError; return TtRssResponse(); } } -TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories(QNetworkReply::NetworkError &error) { +TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories() { QtJson::JsonObject json; json["op"] = "getFeedTree"; json["sid"] = m_sessionId; @@ -125,20 +129,20 @@ TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories(QNetwork if (result.isNotLoggedIn()) { // We are not logged in. - login(error); + login(); json["sid"] = m_sessionId; network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); result = TtRssGetFeedsCategoriesResponse(QString::fromUtf8(result_raw)); } - error = network_reply.first; + m_lastError = network_reply.first; return result; } TtRssGetHeadlinesResponse TtRssNetworkFactory::getHeadlines(int feed_id, bool force_update, int limit, int skip, bool show_content, bool include_attachments, - bool sanitize, QNetworkReply::NetworkError &error) { + bool sanitize) { QtJson::JsonObject json; json["op"] = "getHeadlines"; json["sid"] = m_sessionId; @@ -156,21 +160,20 @@ TtRssGetHeadlinesResponse TtRssNetworkFactory::getHeadlines(int feed_id, bool fo if (result.isNotLoggedIn()) { // We are not logged in. - login(error); + login(); json["sid"] = m_sessionId; network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); result = TtRssGetHeadlinesResponse(QString::fromUtf8(result_raw)); } - error = network_reply.first; + m_lastError = network_reply.first; return result; } TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QStringList &ids, UpdateArticle::OperatingField field, - UpdateArticle::Mode mode, - QNetworkReply::NetworkError &error) { + UpdateArticle::Mode mode) { QtJson::JsonObject json; json["op"] = "updateArticle"; json["sid"] = m_sessionId; @@ -184,14 +187,14 @@ TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QStringList if (result.isNotLoggedIn()) { // We are not logged in. - login(error); + login(); json["sid"] = m_sessionId; network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); result = TtRssUpdateArticleResponse(QString::fromUtf8(result_raw)); } - error = network_reply.first; + m_lastError = network_reply.first; return result; } @@ -208,7 +211,7 @@ bool TtRssResponse::isLoaded() const { int TtRssResponse::seq() const { if (!isLoaded()) { - return -1; + return CONTENT_NOT_LOADED; } else { return m_rawContent["seq"].toInt(); @@ -217,7 +220,7 @@ int TtRssResponse::seq() const { int TtRssResponse::status() const { if (!isLoaded()) { - return -1; + return CONTENT_NOT_LOADED; } else { return m_rawContent["status"].toInt(); @@ -237,7 +240,7 @@ TtRssLoginResponse::~TtRssLoginResponse() { int TtRssLoginResponse::apiLevel() const { if (!isLoaded()) { - return -1; + return CONTENT_NOT_LOADED; } else { return m_rawContent["content"].toMap()["api_level"].toInt(); diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.h b/src/services/tt-rss/network/ttrssnetworkfactory.h index 8c80f5eb6..83cb2fcb1 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.h +++ b/src/services/tt-rss/network/ttrssnetworkfactory.h @@ -114,24 +114,26 @@ class TtRssNetworkFactory { // Metadata. QDateTime lastLoginTime() const; + QNetworkReply::NetworkError lastError() const; + // Operations. // Logs user in. - TtRssLoginResponse login(QNetworkReply::NetworkError &error); + TtRssLoginResponse login(); // Logs user out. - TtRssResponse logout(QNetworkReply::NetworkError &error); + TtRssResponse logout(); // Gets feeds from the server. - TtRssGetFeedsCategoriesResponse getFeedsCategories(QNetworkReply::NetworkError &error); + TtRssGetFeedsCategoriesResponse getFeedsCategories(); // Gets headlines (messages) from the server. TtRssGetHeadlinesResponse getHeadlines(int feed_id, bool force_update, int limit, int skip, bool show_content, bool include_attachments, - bool sanitize, QNetworkReply::NetworkError &error); + bool sanitize); TtRssUpdateArticleResponse updateArticles(const QStringList &ids, UpdateArticle::OperatingField field, - UpdateArticle::Mode mode, QNetworkReply::NetworkError &error); + UpdateArticle::Mode mode); private: QString m_url; @@ -139,6 +141,7 @@ class TtRssNetworkFactory { QString m_password; QString m_sessionId; QDateTime m_lastLoginTime; + QNetworkReply::NetworkError m_lastError; }; #endif // TTRSSNETWORKFACTORY_H diff --git a/src/services/tt-rss/ttrsscategory.cpp b/src/services/tt-rss/ttrsscategory.cpp index 5ad6de9f4..506181f55 100755 --- a/src/services/tt-rss/ttrsscategory.cpp +++ b/src/services/tt-rss/ttrsscategory.cpp @@ -46,15 +46,13 @@ TtRssServiceRoot *TtRssCategory::serviceRoot() { } bool TtRssCategory::markAsReadUnread(RootItem::ReadStatus status) { - QNetworkReply::NetworkError error; QStringList ids = serviceRoot()->customIDSOfMessagesForItem(this); TtRssUpdateArticleResponse response = serviceRoot()->network()->updateArticles(ids, UpdateArticle::Unread, status == RootItem::Unread ? UpdateArticle::SetToTrue : - UpdateArticle::SetToFalse, - error); + UpdateArticle::SetToFalse); - if (error != QNetworkReply::NoError || response.updateStatus() != STATUS_OK) { + if (serviceRoot()->network()->lastError() != QNetworkReply::NoError || response.updateStatus() != STATUS_OK) { return false; } else { diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index f16f5a259..214c0a3d9 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -85,7 +85,6 @@ int TtRssFeed::countOfUnreadMessages() const { } int TtRssFeed::update() { - QNetworkReply::NetworkError error; QList messages; int newly_added_messages = 0; int limit = MAX_MESSAGES; @@ -93,9 +92,9 @@ int TtRssFeed::update() { do { TtRssGetHeadlinesResponse headlines = serviceRoot()->network()->getHeadlines(customId(), true, limit, skip, - true, true, false, error); + true, true, false); - if (error != QNetworkReply::NoError) { + if (serviceRoot()->network()->lastError() != QNetworkReply::NoError) { setStatus(Feed::Error); return 0; } @@ -145,15 +144,13 @@ QList TtRssFeed::undeletedMessages() const { } bool TtRssFeed::markAsReadUnread(RootItem::ReadStatus status) { - QNetworkReply::NetworkError error; QStringList ids = serviceRoot()->customIDSOfMessagesForItem(this); TtRssUpdateArticleResponse response = serviceRoot()->network()->updateArticles(ids, UpdateArticle::Unread, status == RootItem::Unread ? UpdateArticle::SetToTrue : - UpdateArticle::SetToFalse, - error); + UpdateArticle::SetToFalse); - if (error != QNetworkReply::NoError || response.updateStatus() != STATUS_OK) { + if (serviceRoot()->network()->lastError() != QNetworkReply::NoError || response.updateStatus() != STATUS_OK) { return false; } else { diff --git a/src/services/tt-rss/ttrssrecyclebin.cpp b/src/services/tt-rss/ttrssrecyclebin.cpp index 9cc7c96cd..0b807b570 100755 --- a/src/services/tt-rss/ttrssrecyclebin.cpp +++ b/src/services/tt-rss/ttrssrecyclebin.cpp @@ -34,15 +34,13 @@ TtRssServiceRoot *TtRssRecycleBin::serviceRoot() { } bool TtRssRecycleBin::markAsReadUnread(RootItem::ReadStatus status) { - QNetworkReply::NetworkError error; QStringList ids = serviceRoot()->customIDSOfMessagesForItem(this); TtRssUpdateArticleResponse response = serviceRoot()->network()->updateArticles(ids, UpdateArticle::Unread, status == RootItem::Unread ? UpdateArticle::SetToTrue : - UpdateArticle::SetToFalse, - error); + UpdateArticle::SetToFalse); - if (error != QNetworkReply::NoError || response.updateStatus() != STATUS_OK) { + if (serviceRoot()->network()->lastError() != QNetworkReply::NoError || response.updateStatus() != STATUS_OK) { return false; } else { diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 8f0710883..e7131610b 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -55,10 +55,9 @@ void TtRssServiceRoot::start() { } void TtRssServiceRoot::stop() { - QNetworkReply::NetworkError error; - m_network->logout(error); + m_network->logout(); - qDebug("Stopping Tiny Tiny RSS account, logging out with result '%d'.", (int) error); + qDebug("Stopping Tiny Tiny RSS account, logging out with result '%d'.", (int) m_network->lastError()); } QString TtRssServiceRoot::code() { @@ -86,15 +85,13 @@ bool TtRssServiceRoot::deleteViaGui() { } bool TtRssServiceRoot::markAsReadUnread(RootItem::ReadStatus status) { - QNetworkReply::NetworkError error; QStringList ids = customIDSOfMessagesForItem(this); TtRssUpdateArticleResponse response = m_network->updateArticles(ids, UpdateArticle::Unread, status == RootItem::Unread ? UpdateArticle::SetToTrue : - UpdateArticle::SetToFalse, - error); + UpdateArticle::SetToFalse); - if (error != QNetworkReply::NoError || response.updateStatus() != STATUS_OK) { + if (m_network->lastError() != QNetworkReply::NoError || response.updateStatus() != STATUS_OK) { return false; } else { @@ -166,16 +163,17 @@ QList TtRssServiceRoot::contextMenu() { return serviceMenu(); } -bool TtRssServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, const QList &messages, RootItem::ReadStatus read) { +bool TtRssServiceRoot::onBeforeSetMessagesRead(RootItem *selected_item, const QList &messages, + RootItem::ReadStatus read) { Q_UNUSED(selected_item) - QNetworkReply::NetworkError error; TtRssUpdateArticleResponse response = m_network->updateArticles(customIDsOfMessages(messages), UpdateArticle::Unread, - read == RootItem::Unread ? UpdateArticle::SetToTrue : UpdateArticle::SetToFalse, - error); + read == RootItem::Unread ? + UpdateArticle::SetToTrue : + UpdateArticle::SetToFalse); - if (error == QNetworkReply::NoError && response.updateStatus() == STATUS_OK) { + if (m_network->lastError() == QNetworkReply::NoError && response.updateStatus() == STATUS_OK) { return true; } else { @@ -196,17 +194,14 @@ bool TtRssServiceRoot::onAfterSetMessagesRead(RootItem *selected_item, const QLi bool TtRssServiceRoot::onBeforeSwitchMessageImportance(RootItem *selected_item, const QList > &changes) { Q_UNUSED(selected_item) - QNetworkReply::NetworkError error; - // NOTE: We just toggle it here, because we know, that there is only // toggling of starred status supported by RSS Guard right now and // Tiny Tiny RSS API allows it, which is greate. TtRssUpdateArticleResponse response = m_network->updateArticles(customIDsOfMessages(changes), UpdateArticle::Starred, - UpdateArticle::Togggle, - error); + UpdateArticle::Togggle); - if (error == QNetworkReply::NoError && response.updateStatus() == STATUS_OK) { + if (m_network->lastError() == QNetworkReply::NoError && response.updateStatus() == STATUS_OK) { return true; } else { @@ -536,10 +531,9 @@ void TtRssServiceRoot::syncIn() { setIcon(qApp->icons()->fromTheme(QSL("item-sync"))); itemChanged(QList() << this); - QNetworkReply::NetworkError err; - TtRssGetFeedsCategoriesResponse feed_cats_response = m_network->getFeedsCategories(err); + TtRssGetFeedsCategoriesResponse feed_cats_response = m_network->getFeedsCategories(); - if (err == QNetworkReply::NoError) { + if (m_network->lastError() == QNetworkReply::NoError) { RootItem *new_tree = feed_cats_response.feedsCategories(true, m_network->url()); // Purge old data from SQL and clean all model items. From 480f78b1bf35b442ced8629b542e66b50204f12e Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 14 Dec 2015 13:28:40 +0100 Subject: [PATCH 198/203] Display more information in TT-RSS account root item tooltip. --- src/services/tt-rss/ttrssserviceroot.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index e7131610b..dbd9bfe4d 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -111,9 +111,14 @@ QVariant TtRssServiceRoot::data(int column, int role) const { switch (role) { case Qt::ToolTipRole: if (column == FDS_MODEL_TITLE_INDEX) { - return tr("Tiny Tiny RSS\n\nAccount ID: %3\nUsername: %1\nServer: %2").arg(m_network->username(), - m_network->url(), - QString::number(accountId())); + return tr("Tiny Tiny RSS\n\nAccount ID: %3\nUsername: %1\nServer: %2\n" + "Last error: %4\nLast login on: %5").arg(m_network->username(), + m_network->url(), + QString::number(accountId()), + NetworkFactory::networkErrorText(m_network->lastError()), + m_network->lastLoginTime().isValid() ? + m_network->lastLoginTime().toString(Qt::DefaultLocaleShortDate) : + QSL("-")); } else { return ServiceRoot::data(column, role); From 796bc43dd6a7d554b744c9f094e330e125911e54 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 14 Dec 2015 13:35:58 +0100 Subject: [PATCH 199/203] Remove comment. --- src/services/standard/standardfeed.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 8f202a466..48a8ede25 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -49,7 +49,7 @@ StandardFeed::StandardFeed(RootItem *parent_item) m_passwordProtected = false; m_username = QString(); m_password = QString(); - m_networkError = QNetworkReply::NoError; // TODO: mozna i networkError refaktorovat do Feed předka + m_networkError = QNetworkReply::NoError; m_type = Rss0X; m_totalCount = 0; m_unreadCount = 0; From 7861641612c95f84228cba045eff8ff1e50b2f77 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 15 Dec 2015 07:43:41 +0100 Subject: [PATCH 200/203] Fixed #132. --- resources/misc/db_init_mysql.sql | 3 + resources/misc/db_init_sqlite.sql | 3 + resources/misc/db_update_mysql_3_4.sql | 3 + resources/misc/db_update_sqlite_3_4.sql | 3 + resources/text/CHANGELOG | 1 + src/gui/feedsview.cpp | 6 +- src/network-web/downloader.cpp | 30 ++- src/network-web/downloader.h | 7 +- src/network-web/networkfactory.cpp | 5 +- src/network-web/networkfactory.h | 4 +- .../silentnetworkaccessmanager.cpp | 12 +- .../standard/gui/formstandardfeeddetails.ui | 2 +- src/services/tt-rss/gui/formeditaccount.cpp | 54 +++- src/services/tt-rss/gui/formeditaccount.h | 3 + src/services/tt-rss/gui/formeditaccount.ui | 241 +++++++++++------- .../tt-rss/network/ttrssnetworkfactory.cpp | 51 +++- .../tt-rss/network/ttrssnetworkfactory.h | 12 + src/services/tt-rss/ttrssfeed.cpp | 1 + .../tt-rss/ttrssserviceentrypoint.cpp | 12 +- src/services/tt-rss/ttrssserviceroot.cpp | 15 +- 20 files changed, 327 insertions(+), 141 deletions(-) mode change 100644 => 100755 src/network-web/silentnetworkaccessmanager.cpp diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index a3fc21ca9..54d6fd185 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -25,6 +25,9 @@ CREATE TABLE IF NOT EXISTS TtRssAccounts ( id INTEGER, username TEXT NOT NULL, password TEXT, + auth_protected INTEGER(1) NOT NULL CHECK (auth_protected >= 0 AND auth_protected <= 1) DEFAULT 0, + auth_username TEXT, + auth_password TEXT, url TEXT NOT NULL, FOREIGN KEY (id) REFERENCES Accounts (id) diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index 72bb11663..157fb0ffc 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -19,6 +19,9 @@ CREATE TABLE IF NOT EXISTS TtRssAccounts ( id INTEGER, username TEXT NOT NULL, password TEXT, + auth_protected INTEGER(1) NOT NULL CHECK (auth_protected >= 0 AND auth_protected <= 1) DEFAULT 0, + auth_username TEXT, + auth_password TEXT, url TEXT NOT NULL, FOREIGN KEY (id) REFERENCES Accounts (id) diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index 5324d59da..b6acbcb72 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -11,6 +11,9 @@ CREATE TABLE TtRssAccounts ( id INTEGER, username TEXT NOT NULL, password TEXT, + auth_protected INTEGER(1) NOT NULL CHECK (auth_protected >= 0 AND auth_protected <= 1) DEFAULT 0, + auth_username TEXT, + auth_password TEXT, url TEXT NOT NULL, FOREIGN KEY (id) REFERENCES Accounts (id) diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql index 5923577b3..33e985e6f 100644 --- a/resources/misc/db_update_sqlite_3_4.sql +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -11,6 +11,9 @@ CREATE TABLE TtRssAccounts ( id INTEGER, username TEXT NOT NULL, password TEXT, + auth_protected INTEGER(1) NOT NULL CHECK (auth_protected >= 0 AND auth_protected <= 1) DEFAULT 0, + auth_username TEXT, + auth_password TEXT, url TEXT NOT NULL, FOREIGN KEY (id) REFERENCES Accounts (id) diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 6fede8370..dbf432f47 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -24,6 +24,7 @@ Fixed:
                      +
                    • Tiny Tiny RSS plugin now supports HTTP authentication (Basic, NTLM, Digest). (bug #132)
                    • Fixed bug with updating feed. (bug #131)
                    • Solved problem when user selects HUGE number of individual messages and marks them read/unread. Reselecting them after change may cause RSS Guard to hang.
                    • Better info in popup notification when many feeds are updated.
                    • diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index 34652e5e5..b930714e9 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -128,6 +128,9 @@ void FeedsView::loadExpandedStates() { setExpanded(model()->mapFromSource(sourceModel()->indexForItem(item)), settings->value(GROUP(Categories), setting_name, item->childCount() > 0).toBool()); } + + sortByColumn(qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortColumnFeeds)).toInt(), + static_cast(qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortOrderFeeds)).toInt())); } void FeedsView::expandCollapseCurrentItem() { @@ -407,9 +410,6 @@ void FeedsView::setupAppearance() { setItemDelegate(new StyledItemDelegateWithoutFocus(this)); header()->setStretchLastSection(false); header()->setSortIndicatorShown(false); - - sortByColumn(qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortColumnFeeds)).toInt(), - static_cast(qApp->settings()->value(GROUP(GUI), SETTING(GUI::DefaultSortOrderFeeds)).toInt())); } void FeedsView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { diff --git a/src/network-web/downloader.cpp b/src/network-web/downloader.cpp index 1c468a94b..66e5a04ea 100755 --- a/src/network-web/downloader.cpp +++ b/src/network-web/downloader.cpp @@ -25,6 +25,7 @@ Downloader::Downloader(QObject *parent) : QObject(parent), m_activeReply(NULL), m_downloadManager(new SilentNetworkAccessManager(this)), m_timer(new QTimer(this)), m_customHeaders(QHash()), m_inputData(QByteArray()), + m_targetProtected(false), m_targetUsername(QString()), m_targetPassword(QString()), m_lastOutputData(QByteArray()), m_lastOutputError(QNetworkReply::NoError), m_lastContentType(QVariant()) { m_timer->setInterval(DOWNLOAD_TIMEOUT); @@ -37,17 +38,11 @@ Downloader::~Downloader() { m_downloadManager->deleteLater(); } -void Downloader::downloadFile(const QString &url, int timeout, bool protected_contents, const QString &username, const QString &password) { +void Downloader::downloadFile(const QString &url, int timeout, bool protected_contents, const QString &username, + const QString &password) { QNetworkRequest request; - QObject originatingObject; QString non_const_url = url; - // Set credential information as originating object. - originatingObject.setProperty("protected", protected_contents); - originatingObject.setProperty("username", username); - originatingObject.setProperty("password", password); - request.setOriginatingObject(&originatingObject); - foreach (const QByteArray &header_name, m_customHeaders.keys()) { request.setRawHeader(header_name, m_customHeaders.value(header_name)); } @@ -63,10 +58,15 @@ void Downloader::downloadFile(const QString &url, int timeout, bool protected_co request.setUrl(non_const_url); } + m_targetProtected = protected_contents; + m_targetUsername = username; + m_targetPassword = password; + runGetRequest(request); } -void Downloader::uploadData(const QString &url, const QByteArray &data, int timeout) { +void Downloader::uploadData(const QString &url, const QByteArray &data, int timeout, + bool protected_contents, const QString &username, const QString &password) { QNetworkRequest request; QString non_const_url = url; @@ -87,6 +87,10 @@ void Downloader::uploadData(const QString &url, const QByteArray &data, int time request.setUrl(non_const_url); } + m_targetProtected = protected_contents; + m_targetUsername = username; + m_targetPassword = password; + runPostRequest(request, m_inputData); } @@ -154,6 +158,10 @@ void Downloader::runPostRequest(const QNetworkRequest &request, const QByteArray m_timer->start(); m_activeReply = m_downloadManager->post(request, data); + m_activeReply->setProperty("protected", m_targetProtected); + m_activeReply->setProperty("username", m_targetUsername); + m_activeReply->setProperty("password", m_targetPassword); + connect(m_activeReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(progressInternal(qint64,qint64))); connect(m_activeReply, SIGNAL(finished()), this, SLOT(finished())); } @@ -162,6 +170,10 @@ void Downloader::runGetRequest(const QNetworkRequest &request) { m_timer->start(); m_activeReply = m_downloadManager->get(request); + m_activeReply->setProperty("protected", m_targetProtected); + m_activeReply->setProperty("username", m_targetUsername); + m_activeReply->setProperty("password", m_targetPassword); + connect(m_activeReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(progressInternal(qint64,qint64))); connect(m_activeReply, SIGNAL(finished()), this, SLOT(finished())); } diff --git a/src/network-web/downloader.h b/src/network-web/downloader.h index 621657b64..c803c27ea 100755 --- a/src/network-web/downloader.h +++ b/src/network-web/downloader.h @@ -52,7 +52,8 @@ class Downloader : public QObject { // Performs asynchronous upload of given data as HTTP POST. // User needs to setup "Content-Encoding" header which // matches encoding of the data. - void uploadData(const QString &url, const QByteArray &data, int timeout = DOWNLOAD_TIMEOUT); + void uploadData(const QString &url, const QByteArray &data, int timeout = DOWNLOAD_TIMEOUT, + bool protected_contents = false, const QString &username = QString(), const QString &password = QString()); signals: // Emitted when new progress is known. @@ -80,6 +81,10 @@ class Downloader : public QObject { QHash m_customHeaders; QByteArray m_inputData; + bool m_targetProtected; + QString m_targetUsername; + QString m_targetPassword; + // Response data. QByteArray m_lastOutputData; QNetworkReply::NetworkError m_lastOutputError; diff --git a/src/network-web/networkfactory.cpp b/src/network-web/networkfactory.cpp index d98512f8b..35d2463fc 100755 --- a/src/network-web/networkfactory.cpp +++ b/src/network-web/networkfactory.cpp @@ -149,7 +149,8 @@ QNetworkReply::NetworkError NetworkFactory::downloadIcon(const QList &u } NetworkResult NetworkFactory::uploadData(const QString &url, int timeout, const QByteArray &input_data, - const QString &input_content_type, QByteArray &output) { + const QString &input_content_type, QByteArray &output, + bool protected_contents, const QString &username, const QString &password) { Downloader downloader; QEventLoop loop; NetworkResult result; @@ -159,7 +160,7 @@ NetworkResult NetworkFactory::uploadData(const QString &url, int timeout, const // We need to quit event loop when the download finishes. QObject::connect(&downloader, SIGNAL(completed(QNetworkReply::NetworkError)), &loop, SLOT(quit())); - downloader.uploadData(url, input_data, timeout); + downloader.uploadData(url, input_data, timeout, protected_contents, username, password); loop.exec(); output = downloader.lastOutputData(); result.first = downloader.lastOutputError(); diff --git a/src/network-web/networkfactory.h b/src/network-web/networkfactory.h index 08aa13c17..d14e8d7d5 100755 --- a/src/network-web/networkfactory.h +++ b/src/network-web/networkfactory.h @@ -44,7 +44,9 @@ class NetworkFactory { static QNetworkReply::NetworkError downloadIcon(const QList &urls, int timeout, QIcon &output); static NetworkResult uploadData(const QString &url, int timeout, const QByteArray &input_data, - const QString &input_content_type, QByteArray &output); + const QString &input_content_type, QByteArray &output, + bool protected_contents = false, const QString &username = QString(), + const QString &password = QString()); static NetworkResult downloadFeedFile(const QString &url, int timeout, QByteArray &output, bool protected_contents = false, const QString &username = QString(), diff --git a/src/network-web/silentnetworkaccessmanager.cpp b/src/network-web/silentnetworkaccessmanager.cpp old mode 100644 new mode 100755 index d7acc324f..5b2e5755c --- a/src/network-web/silentnetworkaccessmanager.cpp +++ b/src/network-web/silentnetworkaccessmanager.cpp @@ -44,20 +44,20 @@ SilentNetworkAccessManager *SilentNetworkAccessManager::instance() { } void SilentNetworkAccessManager::onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator) { - QObject *originating_object = reply->request().originatingObject(); + QList keys = authenticator->options().keys(); - if (originating_object->property("protected").toBool()) { + if (reply->property("protected").toBool()) { // This feed contains authentication information, it is good. - authenticator->setUser(originating_object->property("username").toString()); - authenticator->setPassword(originating_object->property("password").toString()); + authenticator->setUser(reply->property("username").toString()); + authenticator->setPassword(reply->property("password").toString()); reply->setProperty("authentication-given", true); - qDebug("Feed '%s' requested authentication and got it.", qPrintable(reply->url().toString())); + qDebug("Item '%s' requested authentication and got it.", qPrintable(reply->url().toString())); } else { reply->setProperty("authentication-given", false); // Authentication is required but this feed does not contain it. - qWarning("Feed '%s' requested authentication but username/password is not available.", qPrintable(reply->url().toString())); + qWarning("Item '%s' requested authentication but username/password is not available.", qPrintable(reply->url().toString())); } } diff --git a/src/services/standard/gui/formstandardfeeddetails.ui b/src/services/standard/gui/formstandardfeeddetails.ui index dc1ed970a..31b13fc7d 100755 --- a/src/services/standard/gui/formstandardfeeddetails.ui +++ b/src/services/standard/gui/formstandardfeeddetails.ui @@ -238,7 +238,7 @@ Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. - Requires authentication + Requires HTTP authentication false diff --git a/src/services/tt-rss/gui/formeditaccount.cpp b/src/services/tt-rss/gui/formeditaccount.cpp index 1870d3d6a..bf12530c2 100755 --- a/src/services/tt-rss/gui/formeditaccount.cpp +++ b/src/services/tt-rss/gui/formeditaccount.cpp @@ -22,6 +22,7 @@ #include "services/tt-rss/ttrssserviceroot.h" #include "services/tt-rss/network/ttrssnetworkfactory.h" #include "miscellaneous/iconfactory.h" +#include "network-web/networkfactory.h" FormEditAccount::FormEditAccount(QWidget *parent) @@ -32,6 +33,8 @@ FormEditAccount::FormEditAccount(QWidget *parent) setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint); setWindowIcon(qApp->icons()->fromTheme(QSL("application-ttrss"))); + m_ui->m_txtHttpUsername->lineEdit()->setPlaceholderText(tr("HTTP authentication username")); + m_ui->m_txtHttpPassword->lineEdit()->setPlaceholderText(tr("HTTP authentication password")); m_ui->m_txtPassword->lineEdit()->setPlaceholderText(tr("Password for your TT-RSS account")); m_ui->m_txtUsername->lineEdit()->setPlaceholderText(tr("Username for your TT-RSS account")); m_ui->m_txtUrl->lineEdit()->setPlaceholderText(tr("FULL URL of your TT-RSS instance WITH trailing \"/api/\" string")); @@ -50,17 +53,25 @@ FormEditAccount::FormEditAccount(QWidget *parent) connect(m_ui->m_buttonBox, SIGNAL(rejected()), this, SLOT(onClickedCancel())); connect(m_ui->m_txtPassword->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(onPasswordChanged())); connect(m_ui->m_txtUsername->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(onUsernameChanged())); + connect(m_ui->m_txtHttpPassword->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(onHttpPasswordChanged())); + connect(m_ui->m_txtHttpUsername->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(onHttpUsernameChanged())); connect(m_ui->m_txtUrl->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(onUrlChanged())); connect(m_ui->m_txtPassword->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(checkOkButton())); connect(m_ui->m_txtUsername->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(checkOkButton())); connect(m_ui->m_txtUrl->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(checkOkButton())); connect(m_ui->m_btnTestSetup, SIGNAL(clicked()), this, SLOT(performTest())); + connect(m_ui->m_gbHttpAuthentication, SIGNAL(toggled(bool)), this, SLOT(onHttpPasswordChanged())); + connect(m_ui->m_gbHttpAuthentication, SIGNAL(toggled(bool)), this, SLOT(onHttpUsernameChanged())); + connect(m_ui->m_checkShowHttpPassword, SIGNAL(toggled(bool)), this, SLOT(displayHttpPassword(bool))); onPasswordChanged(); onUsernameChanged(); onUrlChanged(); + onHttpPasswordChanged(); + onHttpUsernameChanged(); checkOkButton(); displayPassword(false); + displayHttpPassword(false); } FormEditAccount::~FormEditAccount() { @@ -77,6 +88,9 @@ void FormEditAccount::execForEdit(TtRssServiceRoot *existing_root) { setWindowTitle(tr("Edit existing Tiny Tiny RSS account")); m_editableRoot = existing_root; + m_ui->m_gbHttpAuthentication->setChecked(existing_root->network()->authIsUsed()); + m_ui->m_txtHttpPassword->lineEdit()->setText(existing_root->network()->authPassword()); + m_ui->m_txtHttpUsername->lineEdit()->setText(existing_root->network()->authUsername()); m_ui->m_txtUsername->lineEdit()->setText(existing_root->network()->username()); m_ui->m_txtPassword->lineEdit()->setText(existing_root->network()->password()); m_ui->m_txtUrl->lineEdit()->setText(existing_root->network()->url()); @@ -88,12 +102,19 @@ void FormEditAccount::displayPassword(bool display) { m_ui->m_txtPassword->lineEdit()->setEchoMode(display ? QLineEdit::Normal : QLineEdit::Password); } +void FormEditAccount::displayHttpPassword(bool display) { + m_ui->m_txtHttpPassword->lineEdit()->setEchoMode(display ? QLineEdit::Normal : QLineEdit::Password); +} + void FormEditAccount::performTest() { TtRssNetworkFactory factory; factory.setUsername(m_ui->m_txtUsername->lineEdit()->text()); factory.setPassword(m_ui->m_txtPassword->lineEdit()->text()); factory.setUrl(m_ui->m_txtUrl->lineEdit()->text()); + factory.setAuthIsUsed(m_ui->m_gbHttpAuthentication->isChecked()); + factory.setAuthUsername(m_ui->m_txtHttpUsername->lineEdit()->text()); + factory.setAuthPassword(m_ui->m_txtHttpPassword->lineEdit()->text()); TtRssLoginResponse result = factory.login(); @@ -132,8 +153,8 @@ void FormEditAccount::performTest() { } else { m_ui->m_lblTestResult->setStatus(WidgetWithStatus::Error, - tr("Network error, have you entered correct Tiny Tiny RSS API endpoint?"), - tr("Network error, have you entered correct Tiny Tiny RSS API endpoint?")); + tr("Network error: '%1'.").arg(NetworkFactory::networkErrorText(factory.lastError())), + tr("Network error, have you entered correct Tiny Tiny RSS API endpoint and password?")); } } @@ -150,15 +171,18 @@ void FormEditAccount::onClickedOk() { m_editableRoot->network()->setUrl(m_ui->m_txtUrl->lineEdit()->text()); m_editableRoot->network()->setUsername(m_ui->m_txtUsername->lineEdit()->text()); m_editableRoot->network()->setPassword(m_ui->m_txtPassword->lineEdit()->text()); + m_editableRoot->network()->setAuthIsUsed(m_ui->m_gbHttpAuthentication->isChecked()); + m_editableRoot->network()->setAuthUsername(m_ui->m_txtHttpUsername->lineEdit()->text()); + m_editableRoot->network()->setAuthPassword(m_ui->m_txtHttpPassword->lineEdit()->text()); m_editableRoot->saveAccountDataToDatabase(); + accept(); + if (editing_account) { m_editableRoot->network()->logout(); m_editableRoot->completelyRemoveAllData(); m_editableRoot->syncIn(); } - - accept(); } void FormEditAccount::onClickedCancel() { @@ -187,6 +211,28 @@ void FormEditAccount::onPasswordChanged() { } } +void FormEditAccount::onHttpUsernameChanged() { + bool is_username_ok = !m_ui->m_gbHttpAuthentication->isChecked() || !m_ui->m_txtHttpUsername->lineEdit()->text().isEmpty(); + + m_ui->m_txtHttpUsername->setStatus(is_username_ok ? + LineEditWithStatus::Ok : + LineEditWithStatus::Warning, + is_username_ok ? + tr("Username is ok or it is not needed.") : + tr("Username is empty.")); +} + +void FormEditAccount::onHttpPasswordChanged() { + bool is_username_ok = !m_ui->m_gbHttpAuthentication->isChecked() || !m_ui->m_txtHttpPassword->lineEdit()->text().isEmpty(); + + m_ui->m_txtHttpPassword->setStatus(is_username_ok ? + LineEditWithStatus::Ok : + LineEditWithStatus::Warning, + is_username_ok ? + tr("Password is ok or it is not needed.") : + tr("Password is empty.")); +} + void FormEditAccount::onUrlChanged() { QString url = m_ui->m_txtUrl->lineEdit()->text(); diff --git a/src/services/tt-rss/gui/formeditaccount.h b/src/services/tt-rss/gui/formeditaccount.h index 5e278ec6a..4b9c57381 100755 --- a/src/services/tt-rss/gui/formeditaccount.h +++ b/src/services/tt-rss/gui/formeditaccount.h @@ -42,12 +42,15 @@ class FormEditAccount : public QDialog { private slots: void displayPassword(bool display); + void displayHttpPassword(bool display); void performTest(); void onClickedOk(); void onClickedCancel(); void onUsernameChanged(); void onPasswordChanged(); + void onHttpUsernameChanged(); + void onHttpPasswordChanged(); void onUrlChanged(); void checkOkButton(); diff --git a/src/services/tt-rss/gui/formeditaccount.ui b/src/services/tt-rss/gui/formeditaccount.ui index c604bac7e..adbf578f3 100755 --- a/src/services/tt-rss/gui/formeditaccount.ui +++ b/src/services/tt-rss/gui/formeditaccount.ui @@ -7,106 +7,132 @@ 0 0 465 - 235 + 304 Dialog - - - - - - - &Test setup - - - - - - - - 0 - 0 - - - - Qt::RightToLeft - - - - - - - Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. - - - Authentication - - - false - - - false - - - - - - Username - - - m_txtUsername - - - - - - - Password - - - m_txtPassword - - - - - - - - - - - - - Show password - - - - - - - - - - - - URL - - - m_txtUrl - - - - - - - - - + + + + + Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. + + + Authentication + + + false + + + false + + + + + + Username + + + m_txtUsername + + + + + + + Password + + + m_txtPassword + + + + + + + + + + + + + Show password + + + + + - + + + + Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. + + + Requires HTTP authentication + + + false + + + true + + + true + + + + + + Username + + + m_txtUsername + + + + + + + + + + Password + + + m_txtPassword + + + + + + + + + + Show password + + + + + + + + + + + 0 + 0 + + + + Qt::RightToLeft + + + + Qt::Horizontal @@ -116,6 +142,30 @@ + + + + + + URL + + + m_txtUrl + + + + + + + + + + + + &Test setup + + + @@ -132,9 +182,6 @@ 1 - - m_btnTestSetup - diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index b111cb8d3..51fccd388 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -31,7 +31,8 @@ TtRssNetworkFactory::TtRssNetworkFactory() - : m_url(QString()), m_username(QString()), m_password(QString()), m_sessionId(QString()), + : m_url(QString()), m_username(QString()), m_password(QString()), m_authIsUsed(false), + m_authUsername(QString()), m_authPassword(QString()), m_sessionId(QString()), m_lastLoginTime(QDateTime()), m_lastError(QNetworkReply::NoError) { } @@ -81,7 +82,8 @@ TtRssLoginResponse TtRssNetworkFactory::login() { json["password"] = m_password; QByteArray result_raw; - NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw, + m_authIsUsed, m_authUsername, m_authPassword); TtRssLoginResponse login_response(QString::fromUtf8(result_raw)); if (network_reply.first == QNetworkReply::NoError) { @@ -101,7 +103,8 @@ TtRssResponse TtRssNetworkFactory::logout() { json["sid"] = m_sessionId; QByteArray result_raw; - NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw, + m_authIsUsed, m_authUsername, m_authPassword); m_lastError = network_reply.first; @@ -124,7 +127,8 @@ TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories() { json["include_empty"] = false; QByteArray result_raw; - NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw, + m_authIsUsed, m_authUsername, m_authPassword); TtRssGetFeedsCategoriesResponse result(QString::fromUtf8(result_raw)); if (result.isNotLoggedIn()) { @@ -132,7 +136,8 @@ TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories() { login(); json["sid"] = m_sessionId; - network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw, + m_authIsUsed, m_authUsername, m_authPassword); result = TtRssGetFeedsCategoriesResponse(QString::fromUtf8(result_raw)); } @@ -155,7 +160,8 @@ TtRssGetHeadlinesResponse TtRssNetworkFactory::getHeadlines(int feed_id, bool fo json["sanitize"] = sanitize; QByteArray result_raw; - NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw, + m_authIsUsed, m_authUsername, m_authPassword); TtRssGetHeadlinesResponse result(QString::fromUtf8(result_raw)); if (result.isNotLoggedIn()) { @@ -163,7 +169,8 @@ TtRssGetHeadlinesResponse TtRssNetworkFactory::getHeadlines(int feed_id, bool fo login(); json["sid"] = m_sessionId; - network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw, + m_authIsUsed, m_authUsername, m_authPassword); result = TtRssGetHeadlinesResponse(QString::fromUtf8(result_raw)); } @@ -182,7 +189,8 @@ TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QStringList json["field"] = (int) field; QByteArray result_raw; - NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + NetworkResult network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw, + m_authIsUsed, m_authUsername, m_authPassword); TtRssUpdateArticleResponse result(QString::fromUtf8(result_raw)); if (result.isNotLoggedIn()) { @@ -190,13 +198,38 @@ TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QStringList login(); json["sid"] = m_sessionId; - network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw); + network_reply = NetworkFactory::uploadData(m_url, DOWNLOAD_TIMEOUT, QtJson::serialize(json), CONTENT_TYPE, result_raw, + m_authIsUsed, m_authUsername, m_authPassword); result = TtRssUpdateArticleResponse(QString::fromUtf8(result_raw)); } m_lastError = network_reply.first; return result; } +bool TtRssNetworkFactory::authIsUsed() const +{ + return m_authIsUsed; +} + +void TtRssNetworkFactory::setAuthIsUsed(bool auth_is_used) { + m_authIsUsed = auth_is_used; +} + +QString TtRssNetworkFactory::authUsername() const { + return m_authUsername; +} + +void TtRssNetworkFactory::setAuthUsername(const QString &auth_username) { + m_authUsername = auth_username; +} + +QString TtRssNetworkFactory::authPassword() const { + return m_authPassword; +} + +void TtRssNetworkFactory::setAuthPassword(const QString &auth_password) { + m_authPassword = auth_password; +} TtRssResponse::TtRssResponse(const QString &raw_content) { m_rawContent = QtJson::parse(raw_content).toMap(); diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.h b/src/services/tt-rss/network/ttrssnetworkfactory.h index 83cb2fcb1..55879056e 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.h +++ b/src/services/tt-rss/network/ttrssnetworkfactory.h @@ -111,6 +111,15 @@ class TtRssNetworkFactory { QString password() const; void setPassword(const QString &password); + bool authIsUsed() const; + void setAuthIsUsed(bool auth_is_used); + + QString authUsername() const; + void setAuthUsername(const QString &auth_username); + + QString authPassword() const; + void setAuthPassword(const QString &auth_password); + // Metadata. QDateTime lastLoginTime() const; @@ -139,6 +148,9 @@ class TtRssNetworkFactory { QString m_url; QString m_username; QString m_password; + bool m_authIsUsed; + QString m_authUsername; + QString m_authPassword; QString m_sessionId; QDateTime m_lastLoginTime; QNetworkReply::NetworkError m_lastError; diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index 214c0a3d9..f8ca2a0ca 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -96,6 +96,7 @@ int TtRssFeed::update() { if (serviceRoot()->network()->lastError() != QNetworkReply::NoError) { setStatus(Feed::Error); + serviceRoot()->itemChanged(QList() << this); return 0; } else { diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp index 29288cee7..37a8d2dc9 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.cpp +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -20,6 +20,7 @@ #include "definitions/definitions.h" #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" +#include "miscellaneous/textfactory.h" #include "gui/dialogs/formmain.h" #include "services/tt-rss/gui/formeditaccount.h" #include "services/tt-rss/ttrssserviceroot.h" @@ -79,14 +80,19 @@ QList TtRssServiceEntryPoint::initializeSubtree() { QSqlQuery query(database); QList roots; - if (query.exec("SELECT id, username, password, url FROM TtRssAccounts;")) { + if (query.exec("SELECT * FROM TtRssAccounts;")) { while (query.next()) { TtRssServiceRoot *root = new TtRssServiceRoot(); root->setId(query.value(0).toInt()); root->setAccountId(query.value(0).toInt()); root->network()->setUsername(query.value(1).toString()); - root->network()->setPassword(query.value(2).toString()); - root->network()->setUrl(query.value(3).toString()); + root->network()->setPassword(TextFactory::decrypt(query.value(2).toString())); + + root->network()->setAuthIsUsed(query.value(3).toBool()); + root->network()->setAuthUsername(query.value(4).toString()); + root->network()->setAuthPassword(TextFactory::decrypt(query.value(5).toString())); + + root->network()->setUrl(query.value(6).toString()); root->updateTitle(); roots.append(root); } diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index dbd9bfe4d..92e828b35 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -19,6 +19,7 @@ #include "miscellaneous/application.h" #include "miscellaneous/settings.h" +#include "miscellaneous/textfactory.h" #include "gui/dialogs/formmain.h" #include "network-web/networkfactory.h" #include "services/tt-rss/ttrssserviceentrypoint.h" @@ -424,12 +425,16 @@ void TtRssServiceRoot::saveAccountDataToDatabase() { QSqlQuery query(database); query.prepare("UPDATE TtRssAccounts " - "SET username = :username, password = :password, url = :url " + "SET username = :username, password = :password, url = :url, auth_protected = :auth_protected, " + "auth_username = :auth_username, auth_password = :auth_password " "WHERE id = :id;"); - query.bindValue(":username", m_network->username()); - query.bindValue(":password", m_network->password()); - query.bindValue(":url", m_network->url()); - query.bindValue(":id", accountId()); + query.bindValue(QSL(":username"), m_network->username()); + query.bindValue(QSL(":password"), TextFactory::encrypt(m_network->password())); + query.bindValue(QSL(":url"), m_network->url()); + query.bindValue(QSL(":auth_protected"), m_network->authIsUsed()); + query.bindValue(QSL(":auth_username"), m_network->authUsername()); + query.bindValue(QSL(":auth_password"), TextFactory::encrypt(m_network->authPassword())); + query.bindValue(QSL(":id"), accountId()); if (query.exec()) { updateTitle(); From 68e06a6da65798133218c08b395ebcd14e623eed Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 15 Dec 2015 07:46:56 +0100 Subject: [PATCH 201/203] Fix tab order in TT-RSS acc edit dialog. --- src/services/tt-rss/gui/formeditaccount.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/services/tt-rss/gui/formeditaccount.cpp b/src/services/tt-rss/gui/formeditaccount.cpp index bf12530c2..e0e1728b1 100755 --- a/src/services/tt-rss/gui/formeditaccount.cpp +++ b/src/services/tt-rss/gui/formeditaccount.cpp @@ -45,7 +45,12 @@ FormEditAccount::FormEditAccount(QWidget *parent) setTabOrder(m_ui->m_txtUrl->lineEdit(), m_ui->m_txtUsername->lineEdit()); setTabOrder(m_ui->m_txtUsername->lineEdit(), m_ui->m_txtPassword->lineEdit()); setTabOrder(m_ui->m_txtPassword->lineEdit(), m_ui->m_checkShowPassword); - setTabOrder(m_ui->m_checkShowPassword, m_ui->m_btnTestSetup); + setTabOrder(m_ui->m_checkShowPassword, m_ui->m_gbHttpAuthentication); + setTabOrder(m_ui->m_gbHttpAuthentication, m_ui->m_txtHttpUsername->lineEdit()); + + setTabOrder(m_ui->m_txtHttpUsername->lineEdit(), m_ui->m_txtHttpPassword->lineEdit()); + setTabOrder(m_ui->m_txtHttpPassword->lineEdit(), m_ui->m_checkShowHttpPassword); + setTabOrder(m_ui->m_checkShowHttpPassword, m_ui->m_btnTestSetup); setTabOrder(m_ui->m_btnTestSetup, m_ui->m_buttonBox); connect(m_ui->m_checkShowPassword, SIGNAL(toggled(bool)), this, SLOT(displayPassword(bool))); From bd7c37dc660b17151bf097d33b4f760c9b4bc050 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 15 Dec 2015 07:49:53 +0100 Subject: [PATCH 202/203] Readme stuff. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6ec89a9b8..5b12953bb 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ RSS Guard is written in C++. It is pretty fast even with tons of messages loaded * Qt library is the only dependency, * open-source development model and friendly author waiting for your feedback, * no ads, no hidden costs. + - - - Philosophy From e729ccb3bd3f485fd6d7460dfea3d7434cdefe8b Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 15 Dec 2015 09:13:35 +0100 Subject: [PATCH 203/203] Switchable server-side update for TT-RSS. --- resources/misc/db_init_mysql.sql | 11 ++++---- resources/misc/db_init_sqlite.sql | 9 +++--- resources/misc/db_update_mysql_3_4.sql | 7 +++-- resources/misc/db_update_sqlite_3_4.sql | 9 +++--- src/gui/dialogs/formaddaccount.cpp | 4 +-- src/services/tt-rss/gui/formeditaccount.cpp | 7 +++-- src/services/tt-rss/gui/formeditaccount.ui | 22 +++++++++++---- .../tt-rss/network/ttrssnetworkfactory.cpp | 20 +++++++++---- .../tt-rss/network/ttrssnetworkfactory.h | 7 ++++- src/services/tt-rss/ttrssfeed.cpp | 2 +- .../tt-rss/ttrssserviceentrypoint.cpp | 4 +-- src/services/tt-rss/ttrssserviceroot.cpp | 28 ++++++++++++++----- 12 files changed, 86 insertions(+), 44 deletions(-) diff --git a/resources/misc/db_init_mysql.sql b/resources/misc/db_init_mysql.sql index 54d6fd185..68e397b7c 100644 --- a/resources/misc/db_init_mysql.sql +++ b/resources/misc/db_init_mysql.sql @@ -29,6 +29,7 @@ CREATE TABLE IF NOT EXISTS TtRssAccounts ( auth_username TEXT, auth_password TEXT, url TEXT NOT NULL, + force_update INTEGER(1) NOT NULL CHECK (force_update >= 0 AND force_update <= 1) DEFAULT 0, FOREIGN KEY (id) REFERENCES Accounts (id) ); @@ -62,7 +63,7 @@ CREATE TABLE IF NOT EXISTS Feeds ( username TEXT, password TEXT, update_type INTEGER(1) NOT NULL CHECK (update_type >= 0), - update_interval INTEGER NOT NULL DEFAULT 15 CHECK (update_interval >= 5), + update_interval INTEGER NOT NULL CHECK (update_interval >= 5) DEFAULT 15, type INTEGER, account_id INTEGER NOT NULL, custom_id TEXT, @@ -74,16 +75,16 @@ DROP TABLE IF EXISTS Messages; -- ! CREATE TABLE IF NOT EXISTS Messages ( id INTEGER AUTO_INCREMENT PRIMARY KEY, - is_read INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_read >= 0 AND is_read <= 1), - is_deleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_deleted >= 0 AND is_deleted <= 1), - is_important INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_important >= 0 AND is_important <= 1), + is_read INTEGER(1) NOT NULL CHECK (is_read >= 0 AND is_read <= 1) DEFAULT 0, + is_deleted INTEGER(1) NOT NULL CHECK (is_deleted >= 0 AND is_deleted <= 1) DEFAULT 0, + is_important INTEGER(1) NOT NULL CHECK (is_important >= 0 AND is_important <= 1) DEFAULT 0 , feed TEXT NOT NULL, title TEXT NOT NULL CHECK (title != ''), url TEXT, author TEXT, date_created BIGINT NOT NULL CHECK (date_created != 0), contents TEXT, - is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1), + is_pdeleted INTEGER(1) NOT NULL CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1) DEFAULT 0 , enclosures TEXT, account_id INTEGER NOT NULL, custom_id TEXT, diff --git a/resources/misc/db_init_sqlite.sql b/resources/misc/db_init_sqlite.sql index 157fb0ffc..d4c20de99 100644 --- a/resources/misc/db_init_sqlite.sql +++ b/resources/misc/db_init_sqlite.sql @@ -23,6 +23,7 @@ CREATE TABLE IF NOT EXISTS TtRssAccounts ( auth_username TEXT, auth_password TEXT, url TEXT NOT NULL, + force_update INTEGER(1) NOT NULL CHECK (force_update >= 0 AND force_update <= 1) DEFAULT 0, FOREIGN KEY (id) REFERENCES Accounts (id) ); @@ -69,16 +70,16 @@ DROP TABLE IF EXISTS Messages; -- ! CREATE TABLE IF NOT EXISTS Messages ( id INTEGER PRIMARY KEY, - is_read INTEGER(1) NOT NULL CHECK (is_read >= 0 AND is_read <= 1) DEFAULT (0), - is_deleted INTEGER(1) NOT NULL CHECK (is_deleted >= 0 AND is_deleted <= 1) DEFAULT (0), - is_important INTEGER(1) NOT NULL CHECK (is_important >= 0 AND is_important <= 1) DEFAULT (0), + is_read INTEGER(1) NOT NULL CHECK (is_read >= 0 AND is_read <= 1) DEFAULT 0, + is_deleted INTEGER(1) NOT NULL CHECK (is_deleted >= 0 AND is_deleted <= 1) DEFAULT 0, + is_important INTEGER(1) NOT NULL CHECK (is_important >= 0 AND is_important <= 1) DEFAULT 0, feed TEXT NOT NULL, title TEXT NOT NULL CHECK (title != ''), url TEXT, author TEXT, date_created INTEGER NOT NULL CHECK (date_created != 0), contents TEXT, - is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1), + is_pdeleted INTEGER(1) NOT NULL CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1) DEFAULT 0, enclosures TEXT, account_id INTEGER NOT NULL, custom_id TEXT, diff --git a/resources/misc/db_update_mysql_3_4.sql b/resources/misc/db_update_mysql_3_4.sql index b6acbcb72..f2c27f644 100644 --- a/resources/misc/db_update_mysql_3_4.sql +++ b/resources/misc/db_update_mysql_3_4.sql @@ -15,12 +15,13 @@ CREATE TABLE TtRssAccounts ( auth_username TEXT, auth_password TEXT, url TEXT NOT NULL, + force_update INTEGER(1) NOT NULL CHECK (force_update >= 0 AND force_update <= 1) DEFAULT 0, FOREIGN KEY (id) REFERENCES Accounts (id) ); -- ! ALTER TABLE Messages -ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); +ADD COLUMN account_id INTEGER NOT NULL DEFAULT 1; -- ! ALTER TABLE Messages ADD COLUMN custom_id TEXT; @@ -38,7 +39,7 @@ ALTER TABLE Messages MODIFY url TEXT; -- ! ALTER TABLE Feeds -ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); +ADD COLUMN account_id INTEGER NOT NULL DEFAULT 1; -- ! ALTER TABLE Feeds ADD COLUMN custom_id TEXT; @@ -56,7 +57,7 @@ ALTER TABLE Feeds MODIFY type INTEGER; -- ! ALTER TABLE Categories -ADD COLUMN account_id INTEGER NOT NULL DEFAULT (1); +ADD COLUMN account_id INTEGER NOT NULL DEFAULT 1; -- ! ALTER TABLE Categories ADD COLUMN custom_id TEXT; diff --git a/resources/misc/db_update_sqlite_3_4.sql b/resources/misc/db_update_sqlite_3_4.sql index 33e985e6f..7366f1b5e 100644 --- a/resources/misc/db_update_sqlite_3_4.sql +++ b/resources/misc/db_update_sqlite_3_4.sql @@ -15,6 +15,7 @@ CREATE TABLE TtRssAccounts ( auth_username TEXT, auth_password TEXT, url TEXT NOT NULL, + force_update INTEGER(1) NOT NULL CHECK (force_update >= 0 AND force_update <= 1) DEFAULT 0, FOREIGN KEY (id) REFERENCES Accounts (id) ); @@ -25,16 +26,16 @@ DROP TABLE Messages; -- ! CREATE TABLE Messages ( id INTEGER PRIMARY KEY, - is_read INTEGER(1) NOT NULL CHECK (is_read >= 0 AND is_read <= 1) DEFAULT (0), - is_deleted INTEGER(1) NOT NULL CHECK (is_deleted >= 0 AND is_deleted <= 1) DEFAULT (0), - is_important INTEGER(1) NOT NULL CHECK (is_important >= 0 AND is_important <= 1) DEFAULT (0), + is_read INTEGER(1) NOT NULL CHECK (is_read >= 0 AND is_read <= 1) DEFAULT 0, + is_deleted INTEGER(1) NOT NULL CHECK (is_deleted >= 0 AND is_deleted <= 1) DEFAULT 0, + is_important INTEGER(1) NOT NULL CHECK (is_important >= 0 AND is_important <= 1) DEFAULT 0, feed TEXT NOT NULL, title TEXT NOT NULL CHECK (title != ''), url TEXT, author TEXT, date_created INTEGER NOT NULL CHECK (date_created != 0), contents TEXT, - is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1), + is_pdeleted INTEGER(1) NOT NULL CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1) DEFAULT 0, enclosures TEXT, account_id INTEGER NOT NULL, custom_id TEXT, diff --git a/src/gui/dialogs/formaddaccount.cpp b/src/gui/dialogs/formaddaccount.cpp index 60fa962af..d191d9128 100755 --- a/src/gui/dialogs/formaddaccount.cpp +++ b/src/gui/dialogs/formaddaccount.cpp @@ -59,9 +59,7 @@ void FormAddAccount::addSelectedAccount() { m_model->addServiceAccount(new_root); } else { - qApp->showGuiMessage(tr("Cannot add account"), - tr("Some critical error occurred, report this to developers."), - QSystemTrayIcon::Critical, parentWidget(), true); + qCritical("Cannot create new account."); } } diff --git a/src/services/tt-rss/gui/formeditaccount.cpp b/src/services/tt-rss/gui/formeditaccount.cpp index e0e1728b1..7d58ae34f 100755 --- a/src/services/tt-rss/gui/formeditaccount.cpp +++ b/src/services/tt-rss/gui/formeditaccount.cpp @@ -42,12 +42,12 @@ FormEditAccount::FormEditAccount(QWidget *parent) tr("No test done yet."), tr("Here, results of connection test are shown.")); - setTabOrder(m_ui->m_txtUrl->lineEdit(), m_ui->m_txtUsername->lineEdit()); + setTabOrder(m_ui->m_txtUrl->lineEdit(), m_ui->m_checkServerSideUpdate); + setTabOrder(m_ui->m_checkServerSideUpdate, m_ui->m_txtUsername->lineEdit()); setTabOrder(m_ui->m_txtUsername->lineEdit(), m_ui->m_txtPassword->lineEdit()); setTabOrder(m_ui->m_txtPassword->lineEdit(), m_ui->m_checkShowPassword); setTabOrder(m_ui->m_checkShowPassword, m_ui->m_gbHttpAuthentication); setTabOrder(m_ui->m_gbHttpAuthentication, m_ui->m_txtHttpUsername->lineEdit()); - setTabOrder(m_ui->m_txtHttpUsername->lineEdit(), m_ui->m_txtHttpPassword->lineEdit()); setTabOrder(m_ui->m_txtHttpPassword->lineEdit(), m_ui->m_checkShowHttpPassword); setTabOrder(m_ui->m_checkShowHttpPassword, m_ui->m_btnTestSetup); @@ -99,6 +99,7 @@ void FormEditAccount::execForEdit(TtRssServiceRoot *existing_root) { m_ui->m_txtUsername->lineEdit()->setText(existing_root->network()->username()); m_ui->m_txtPassword->lineEdit()->setText(existing_root->network()->password()); m_ui->m_txtUrl->lineEdit()->setText(existing_root->network()->url()); + m_ui->m_checkServerSideUpdate->setChecked(existing_root->network()->forceServerSideUpdate()); exec(); } @@ -120,6 +121,7 @@ void FormEditAccount::performTest() { factory.setAuthIsUsed(m_ui->m_gbHttpAuthentication->isChecked()); factory.setAuthUsername(m_ui->m_txtHttpUsername->lineEdit()->text()); factory.setAuthPassword(m_ui->m_txtHttpPassword->lineEdit()->text()); + factory.setForceServerSideUpdate(m_ui->m_checkServerSideUpdate->isChecked()); TtRssLoginResponse result = factory.login(); @@ -179,6 +181,7 @@ void FormEditAccount::onClickedOk() { m_editableRoot->network()->setAuthIsUsed(m_ui->m_gbHttpAuthentication->isChecked()); m_editableRoot->network()->setAuthUsername(m_ui->m_txtHttpUsername->lineEdit()->text()); m_editableRoot->network()->setAuthPassword(m_ui->m_txtHttpPassword->lineEdit()->text()); + m_editableRoot->network()->setForceServerSideUpdate(m_ui->m_checkServerSideUpdate->isChecked()); m_editableRoot->saveAccountDataToDatabase(); accept(); diff --git a/src/services/tt-rss/gui/formeditaccount.ui b/src/services/tt-rss/gui/formeditaccount.ui index adbf578f3..670b544db 100755 --- a/src/services/tt-rss/gui/formeditaccount.ui +++ b/src/services/tt-rss/gui/formeditaccount.ui @@ -14,7 +14,7 @@ Dialog - + Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. @@ -65,7 +65,7 @@ - + Some feeds require authentication, including GMail feeds. BASIC, NTLM-2 and DIGEST-MD5 authentication schemes are supported. @@ -80,7 +80,7 @@ true - true + false @@ -119,7 +119,7 @@ - + @@ -132,7 +132,7 @@ - + Qt::Horizontal @@ -159,13 +159,23 @@ - + &Test setup + + + + Force execution of server-side update when updating feeds from RSS Guard + + + true + + + diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.cpp b/src/services/tt-rss/network/ttrssnetworkfactory.cpp index 51fccd388..d14b0957b 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.cpp +++ b/src/services/tt-rss/network/ttrssnetworkfactory.cpp @@ -31,7 +31,7 @@ TtRssNetworkFactory::TtRssNetworkFactory() - : m_url(QString()), m_username(QString()), m_password(QString()), m_authIsUsed(false), + : m_url(QString()), m_username(QString()), m_password(QString()), m_forceServerSideUpdate(false), m_authIsUsed(false), m_authUsername(QString()), m_authPassword(QString()), m_sessionId(QString()), m_lastLoginTime(QDateTime()), m_lastError(QNetworkReply::NoError) { } @@ -145,14 +145,14 @@ TtRssGetFeedsCategoriesResponse TtRssNetworkFactory::getFeedsCategories() { return result; } -TtRssGetHeadlinesResponse TtRssNetworkFactory::getHeadlines(int feed_id, bool force_update, int limit, int skip, +TtRssGetHeadlinesResponse TtRssNetworkFactory::getHeadlines(int feed_id, int limit, int skip, bool show_content, bool include_attachments, bool sanitize) { QtJson::JsonObject json; json["op"] = "getHeadlines"; json["sid"] = m_sessionId; json["feed_id"] = feed_id; - json["force_update"] = force_update; + json["force_update"] = m_forceServerSideUpdate; json["limit"] = limit; json["skip"] = skip; json["show_content"] = show_content; @@ -206,8 +206,16 @@ TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QStringList m_lastError = network_reply.first; return result; } -bool TtRssNetworkFactory::authIsUsed() const -{ + +bool TtRssNetworkFactory::forceServerSideUpdate() const { + return m_forceServerSideUpdate; +} + +void TtRssNetworkFactory::setForceServerSideUpdate(bool force_server_side_update) { + m_forceServerSideUpdate = force_server_side_update; +} + +bool TtRssNetworkFactory::authIsUsed() const { return m_authIsUsed; } @@ -408,7 +416,7 @@ QList TtRssGetHeadlinesResponse::messages() const { QMap mapped = item.toMap(); Message message; - message.m_author = mapped["author"].toString(); + message.m_author = mapped["author"].toString(); message.m_isRead = !mapped["unread"].toBool(); message.m_isImportant = mapped["marked"].toBool(); message.m_contents = mapped["content"].toString(); diff --git a/src/services/tt-rss/network/ttrssnetworkfactory.h b/src/services/tt-rss/network/ttrssnetworkfactory.h index 55879056e..3d1cd2281 100755 --- a/src/services/tt-rss/network/ttrssnetworkfactory.h +++ b/src/services/tt-rss/network/ttrssnetworkfactory.h @@ -120,6 +120,10 @@ class TtRssNetworkFactory { QString authPassword() const; void setAuthPassword(const QString &auth_password); + bool forceServerSideUpdate() const; + void setForceServerSideUpdate(bool force_server_side_update); + + // Metadata. QDateTime lastLoginTime() const; @@ -137,7 +141,7 @@ class TtRssNetworkFactory { TtRssGetFeedsCategoriesResponse getFeedsCategories(); // Gets headlines (messages) from the server. - TtRssGetHeadlinesResponse getHeadlines(int feed_id, bool force_update, int limit, int skip, + TtRssGetHeadlinesResponse getHeadlines(int feed_id, int limit, int skip, bool show_content, bool include_attachments, bool sanitize); @@ -148,6 +152,7 @@ class TtRssNetworkFactory { QString m_url; QString m_username; QString m_password; + bool m_forceServerSideUpdate; bool m_authIsUsed; QString m_authUsername; QString m_authPassword; diff --git a/src/services/tt-rss/ttrssfeed.cpp b/src/services/tt-rss/ttrssfeed.cpp index f8ca2a0ca..2796008a1 100755 --- a/src/services/tt-rss/ttrssfeed.cpp +++ b/src/services/tt-rss/ttrssfeed.cpp @@ -91,7 +91,7 @@ int TtRssFeed::update() { int skip = 0; do { - TtRssGetHeadlinesResponse headlines = serviceRoot()->network()->getHeadlines(customId(), true, limit, skip, + TtRssGetHeadlinesResponse headlines = serviceRoot()->network()->getHeadlines(customId(), limit, skip, true, true, false); if (serviceRoot()->network()->lastError() != QNetworkReply::NoError) { diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp index 37a8d2dc9..14f50bcc9 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.cpp +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -87,12 +87,12 @@ QList TtRssServiceEntryPoint::initializeSubtree() { root->setAccountId(query.value(0).toInt()); root->network()->setUsername(query.value(1).toString()); root->network()->setPassword(TextFactory::decrypt(query.value(2).toString())); - root->network()->setAuthIsUsed(query.value(3).toBool()); root->network()->setAuthUsername(query.value(4).toString()); root->network()->setAuthPassword(TextFactory::decrypt(query.value(5).toString())); - root->network()->setUrl(query.value(6).toString()); + root->network()->setForceServerSideUpdate(query.value(7).toBool()); + root->updateTitle(); roots.append(root); } diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index 92e828b35..f1dd2d921 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -426,7 +426,7 @@ void TtRssServiceRoot::saveAccountDataToDatabase() { query.prepare("UPDATE TtRssAccounts " "SET username = :username, password = :password, url = :url, auth_protected = :auth_protected, " - "auth_username = :auth_username, auth_password = :auth_password " + "auth_username = :auth_username, auth_password = :auth_password, force_update = :force_update " "WHERE id = :id;"); query.bindValue(QSL(":username"), m_network->username()); query.bindValue(QSL(":password"), TextFactory::encrypt(m_network->password())); @@ -434,6 +434,7 @@ void TtRssServiceRoot::saveAccountDataToDatabase() { query.bindValue(QSL(":auth_protected"), m_network->authIsUsed()); query.bindValue(QSL(":auth_username"), m_network->authUsername()); query.bindValue(QSL(":auth_password"), TextFactory::encrypt(m_network->authPassword())); + query.bindValue(QSL(":force_update"), m_network->forceServerSideUpdate()); query.bindValue(QSL(":id"), accountId()); if (query.exec()) { @@ -452,13 +453,26 @@ void TtRssServiceRoot::saveAccountDataToDatabase() { } int id_to_assign = query.value(0).toInt() + 1; + bool saved = true; - bool saved = query.exec(QString("INSERT INTO Accounts (id, type) VALUES (%1, '%2');").arg(QString::number(id_to_assign), - SERVICE_CODE_TT_RSS)) && - query.exec(QString("INSERT INTO TtRssAccounts (id, username, password, url) VALUES (%1, '%2', '%3', '%4');").arg(QString::number(id_to_assign), - network()->username(), - network()->password(), - network()->url())); + query.prepare(QSL("INSERT INTO Accounts (id, type) VALUES (:id, :type);")); + query.bindValue(QSL(":id"), id_to_assign); + query.bindValue(QSL(":type"), SERVICE_CODE_TT_RSS); + + saved &= query.exec(); + + query.prepare("INSERT INTO TtRssAccounts (id, username, password, auth_protected, auth_username, auth_password, url, force_update) " + "VALUES (:id, :username, :password, :auth_protected, :auth_username, :auth_password, :url, :force_update);"); + query.bindValue(QSL(":id"), id_to_assign); + query.bindValue(QSL(":username"), m_network->username()); + query.bindValue(QSL(":password"), TextFactory::encrypt(m_network->password())); + query.bindValue(QSL(":auth_protected"), m_network->authIsUsed()); + query.bindValue(QSL(":auth_username"), m_network->authUsername()); + query.bindValue(QSL(":auth_password"), TextFactory::encrypt(m_network->authPassword())); + query.bindValue(QSL(":url"), m_network->url()); + query.bindValue(QSL(":force_update"), m_network->forceServerSideUpdate()); + + saved &= query.exec(); if (saved) { setId(id_to_assign);