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