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.

This commit is contained in:
Martin Rotter 2015-10-30 13:07:42 +01:00
parent 52b41e19f4
commit e465b1ec0f
21 changed files with 244 additions and 249 deletions

View File

@ -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

View File

@ -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<ServiceRoot*> 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<StandardFeed::Type>(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<Feed*> FeedsModel::feedsForIndex(const QModelIndex &index) {
@ -768,49 +706,3 @@ QList<Feed*> FeedsModel::feedsForItem(RootItem *root) {
return feeds;
}
void FeedsModel::assembleFeeds(FeedAssignment feeds) {
QHash<int, StandardCategory*> 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<int, RootItem*> 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--;
}
}
}
}

View File

@ -28,16 +28,10 @@
class StandardCategory;
class Feed;
class RecycleBin;
class StandardRecycleBin;
class FeedsImportExportModel;
class QTimer;
typedef QList<QPair<int, StandardCategory*> > CategoryAssignment;
typedef QPair<int, StandardCategory*> CategoryAssignmentItem;
typedef QList<QPair<int, StandardFeed*> > FeedAssignment;
typedef QPair<int, StandardFeed*> 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<Feed*> &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<QString> m_headerData;
QList<QString> m_tooltipData;
QIcon m_countsIcon;

View File

@ -19,7 +19,6 @@
#include "services/standard/standardcategory.h"
#include "services/standard/standardfeed.h"
#include "core/recyclebin.h"
#include "miscellaneous/application.h"
#include <QVariant>
@ -112,10 +111,6 @@ bool RootItem::removeChild(RootItem *child) {
return m_childItems.removeOne(child);
}
RecycleBin *RootItem::toRecycleBin() {
return static_cast<RecycleBin*>(this);
}
StandardCategory *RootItem::toCategory() {
return static_cast<StandardCategory*>(this);
}

View File

@ -22,7 +22,7 @@
#include <QDateTime>
#include <QFont>
class RecycleBin;
class StandardRecycleBin;
class StandardCategory;
class StandardFeed;
@ -192,7 +192,6 @@ class RootItem {
}
// Converters
RecycleBin *toRecycleBin();
StandardCategory *toCategory();
StandardFeed *toFeed();

View File

@ -137,11 +137,6 @@ QList<QAction*> 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")));

View File

@ -176,14 +176,6 @@
<addaction name="m_actionSwitchImportanceOfSelectedMessages"/>
<addaction name="m_actionDeleteSelectedMessages"/>
</widget>
<widget class="QMenu" name="m_menuRecycleBin">
<property name="title">
<string>&amp;Recycle bin</string>
</property>
<addaction name="m_actionEmptyRecycleBin"/>
<addaction name="m_actionRestoreRecycleBin"/>
<addaction name="m_actionRestoreSelectedMessagesFromRecycleBin"/>
</widget>
<widget class="QMenu" name="m_menuServices">
<property name="title">
<string>&amp;Services</string>
@ -197,7 +189,6 @@
<addaction name="m_menuFeeds"/>
<addaction name="m_menuServices"/>
<addaction name="m_menuMessages"/>
<addaction name="m_menuRecycleBin"/>
<addaction name="m_menuWebBrowser"/>
<addaction name="m_menuTools"/>
<addaction name="m_menuHelp"/>
@ -606,21 +597,6 @@
<string>Display &amp;wiki</string>
</property>
</action>
<action name="m_actionEmptyRecycleBin">
<property name="text">
<string>&amp;Empty recycle bin</string>
</property>
</action>
<action name="m_actionRestoreRecycleBin">
<property name="text">
<string>&amp;Restore all messages</string>
</property>
</action>
<action name="m_actionRestoreSelectedMessagesFromRecycleBin">
<property name="text">
<string>Restore &amp;selected messages</string>
</property>
</action>
<action name="m_actionRestart">
<property name="text">
<string>&amp;Restart</string>

View File

@ -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,

View File

@ -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<QAction*>() <<
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.

View File

@ -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;

View File

@ -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) {

View File

@ -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);

View File

@ -23,6 +23,8 @@
#include <QString>
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<ServiceRoot*> 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.

View File

@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#include "core/recyclebin.h"
#include "services/standard/standardrecyclebin.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
@ -23,7 +23,7 @@
#include <QSqlQuery>
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);

View File

@ -23,12 +23,12 @@
#include <QCoreApplication>
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);

View File

@ -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<ServiceRoot*> StandardServiceEntryPoint::initializeSubtree() {
StandardServiceRoot *root = new StandardServiceRoot();
QList<ServiceRoot*> roots;
roots.append(root);
return roots;
}

View File

@ -36,6 +36,8 @@ class StandardServiceEntryPoint : public ServiceEntryPoint {
QString version();
QString author();
QIcon icon();
QList<ServiceRoot*> initializeSubtree();
};
#endif // STANDARDSERVICEENTRYPOINT_H

View File

@ -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 <QSqlQuery>
#include <QSqlError>
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<StandardFeed::Type>(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<int, StandardCategory*> StandardServiceRoot::categoriesForItem(RootItem *root) {
QHash<int, StandardCategory*> categories;
QList<RootItem*> 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<int, StandardCategory*> 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<int, RootItem*> 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--;
}
}
}
}

View File

@ -23,6 +23,16 @@
#include <QCoreApplication>
class StandardRecycleBin;
class StandardCategory;
class StandardFeed;
typedef QList<QPair<int, StandardCategory*> > CategoryAssignment;
typedef QPair<int, StandardCategory*> CategoryAssignmentItem;
typedef QList<QPair<int, StandardFeed*> > FeedAssignment;
typedef QPair<int, StandardFeed*> 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<int, StandardCategory*> 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

View File

@ -68,3 +68,7 @@ QString TtRssServiceEntryPoint::author() {
QIcon TtRssServiceEntryPoint::icon() {
return QIcon(APP_ICON_PATH);
}
QList<ServiceRoot*> TtRssServiceEntryPoint::initializeSubtree() {
return QList<ServiceRoot*>();
}

View File

@ -37,6 +37,8 @@ class TtRssServiceEntryPoint : public ServiceEntryPoint {
QString version();
QString author();
QIcon icon();
QList<ServiceRoot*> initializeSubtree();
};
#endif // TTRSSSERVICEENTRYPOINT_H