From e465b1ec0faee2120eed9094cb41714b545bb219 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 30 Oct 2015 13:07:42 +0100 Subject: [PATCH] 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