Made many changes, removed loads of obsolote and ugly code. Added some abstract classes.

This commit is contained in:
Martin Rotter 2015-11-03 10:06:34 +01:00
parent e465b1ec0f
commit f912e24b7d
44 changed files with 378 additions and 361 deletions

View file

@ -417,6 +417,7 @@ set(APP_SOURCES
# ABSTRACT service sources.
src/services/abstract/serviceentrypoint.cpp
src/services/abstract/feed.cpp
src/services/abstract/category.cpp
src/services/abstract/serviceroot.cpp
# STANDARD feed service sources.
@ -429,6 +430,7 @@ set(APP_SOURCES
src/services/standard/standardserviceentrypoint.cpp
src/services/standard/standardserviceroot.cpp
src/services/standard/standardrecyclebin.cpp
src/services/standard/standarditem.cpp
# TT-RSS feed service sources.
src/services/tt-rss/ttrssserviceentrypoint.cpp

View file

@ -12,6 +12,19 @@
</style>
</head>
<body>
<center><h2>2.5.3</h2></center>
Added:
<ul>
<li></li>
</ul>
Fixed:
<ul>
<li></li>
</ul>
<hr/>
<center><h2>2.5.2</h2></center>
Added:

View file

@ -232,42 +232,15 @@ bool FeedsModel::removeItem(const QModelIndex &index) {
return false;
}
bool FeedsModel::addCategory(StandardCategory *category, RootItem *parent) {
void FeedsModel::assignNodeToNewParent(RootItem *item, RootItem *parent) {
// Get index of parent item (parent standard category).
QModelIndex parent_index = indexForItem(parent);
bool result = category->addItself(parent);
if (result) {
// Category was added to the persistent storage,
// so add it to the model.
// TODO: todle jde sloučit s metodou reassignNodeToNewParent.
beginInsertRows(parent_index, parent->childCount(), parent->childCount());
parent->appendChild(category);
parent->appendChild(item);
endInsertRows();
}
else {
// We cannot delete (*this) in its method, thus delete it here.
delete category;
}
return result;
}
bool FeedsModel::addFeed(StandardFeed *feed, RootItem *parent) {
// Get index of parent item (parent standard category or root item).
QModelIndex parent_index = indexForItem(parent);
bool result = feed->addItself(parent);
if (result) {
// Feed was added to the persistent storage so add it to the model.
beginInsertRows(parent_index, parent->childCount(), parent->childCount());
parent->appendChild(feed);
endInsertRows();
}
else {
delete feed;
}
return result;
}
void FeedsModel::reassignNodeToNewParent(RootItem *original_node, RootItem *new_parent) {
@ -378,10 +351,10 @@ RootItem *FeedsModel::itemForIndex(const QModelIndex &index) const {
}
}
StandardCategory *FeedsModel::categoryForIndex(const QModelIndex &index) const {
Category *FeedsModel::categoryForIndex(const QModelIndex &index) const {
RootItem *item = itemForIndex(index);
if (item->kind() == RootItem::Cattegory) {
if (item->kind() == RootItemKind::Category) {
return item->toCategory();
}
else {
@ -390,14 +363,14 @@ StandardCategory *FeedsModel::categoryForIndex(const QModelIndex &index) const {
}
QModelIndex FeedsModel::indexForItem(RootItem *item) const {
if (item == NULL || item->kind() == RootItem::Root) {
if (item == NULL || item->kind() == RootItemKind::Root) {
// Root item lies on invalid index.
return QModelIndex();
}
QStack<RootItem*> chain;
while (item->kind() != RootItem::Root) {
while (item->kind() != RootItemKind::Root) {
chain.push(item);
item = item->parent();
}
@ -424,84 +397,6 @@ bool FeedsModel::hasAnyFeedNewMessages() {
return false;
}
bool FeedsModel::mergeModel(FeedsImportExportModel *model, QString &output_message) {
if (model == NULL || model->rootItem() == NULL) {
output_message = tr("Invalid tree data.");
qDebug("Root item for merging two models is null.");
return false;
}
QStack<RootItem*> original_parents; original_parents.push(m_rootItem);
QStack<RootItem*> new_parents; new_parents.push(model->rootItem());
bool some_feed_category_error = false;
// We are definitely about to add some new items into the model.
//emit layoutAboutToBeChanged();
// Iterate all new items we would like to merge into current model.
while (!new_parents.isEmpty()) {
RootItem *target_parent = original_parents.pop();
RootItem *source_parent = new_parents.pop();
foreach (RootItem *source_item, source_parent->childItems()) {
if (!model->isItemChecked(source_item)) {
// We can skip this item, because it is not checked and should not be imported.
// NOTE: All descendants are thus skipped too.
continue;
}
if (source_item->kind() == RootItem::Cattegory) {
StandardCategory *source_category = source_item->toCategory();
StandardCategory *new_category = new StandardCategory(*source_category);
// Add category to model.
new_category->clearChildren();
if (addCategory(new_category, target_parent)) {
// Process all children of this category.
original_parents.push(new_category);
new_parents.push(source_category);
}
else {
// Add category failed, but this can mean that the same category (with same title)
// already exists. If such a category exists in current parent, then find it and
// add descendants to it.
RootItem *existing_category = target_parent->child(RootItem::Cattegory, new_category->title());
if (existing_category != NULL) {
original_parents.push(existing_category);
new_parents.push(source_category);
}
else {
some_feed_category_error = true;
}
}
}
else if (source_item->kind() == RootItem::Feeed) {
StandardFeed *source_feed = source_item->toFeed();
StandardFeed *new_feed = new StandardFeed(*source_feed);
// Append this feed and end this iteration.
if (!addFeed(new_feed, target_parent)) {
some_feed_category_error = true;
}
}
}
}
// Changes are done now. Finalize the new model.
//emit layoutChanged();
if (some_feed_category_error) {
output_message = tr("Import successfull, but some feeds/categories were not imported due to error.");
}
else {
output_message = tr("Import was completely successfull.");
}
return !some_feed_category_error;
}
void FeedsModel::reloadChangedLayout(QModelIndexList list) {
while (!list.isEmpty()) {
QModelIndex indx = list.takeFirst();
@ -535,7 +430,7 @@ void FeedsModel::loadActivatedServiceAccounts() {
foreach (ServiceEntryPoint *entry_point, qApp->feedServices()) {
// Load all stored root nodes from the entry point and add those to the model.
QList<ServiceRoot*> roots = entry_point->initializeSubtree();
QList<ServiceRoot*> roots = entry_point->initializeSubtree(this);
foreach (ServiceRoot *root, roots) {
m_rootItem->appendChild(root);
@ -551,8 +446,8 @@ QList<Feed*> FeedsModel::feedsForIndex(const QModelIndex &index) {
Feed *FeedsModel::feedForIndex(const QModelIndex &index) {
RootItem *item = itemForIndex(index);
if (item->kind() == RootItem::Feeed) {
return static_cast<Feed*>(item);
if (item->kind() == RootItemKind::Feed) {
return item->toFeed();
}
else {
return NULL;
@ -579,7 +474,7 @@ QList<Feed*> FeedsModel::feedsForIndexes(const QModelIndexList &indexes) {
return feeds;
}
bool FeedsModel::markFeedsRead(const QList<Feed *> &feeds, int read) {
bool FeedsModel::markFeedsRead(const QList<Feed*> &feeds, int read) {
QSqlDatabase db_handle = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings);
if (!db_handle.transaction()) {
@ -660,36 +555,6 @@ bool FeedsModel::markFeedsDeleted(const QList<Feed*> &feeds, int deleted, bool r
}
}
QHash<int, StandardCategory*> FeedsModel::allCategories() {
return categoriesForItem(m_rootItem);
}
QHash<int, StandardCategory*> FeedsModel::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;
}
QList<Feed*> FeedsModel::allFeeds() {
return feedsForItem(m_rootItem);
}
@ -699,8 +564,10 @@ QList<Feed*> FeedsModel::feedsForItem(RootItem *root) {
QList<Feed*> feeds;
foreach (RootItem *child, children) {
if (child->kind() == RootItem::Feeed) {
feeds.append(child->toFeed());
Feed *converted = dynamic_cast<Feed*>(child);
if (converted != NULL) {
feeds.append(converted);
}
}

View file

@ -26,9 +26,9 @@
#include <QIcon>
class Category;
class StandardCategory;
class Feed;
class StandardRecycleBin;
class FeedsImportExportModel;
class QTimer;
@ -64,11 +64,8 @@ class FeedsModel : public QAbstractItemModel {
// Removes item with given index.
bool removeItem(const QModelIndex &index);
// Standard category manipulators.
bool addCategory(StandardCategory *category, RootItem *parent);
// Standard feed manipulators.
bool addFeed(StandardFeed *feed, RootItem *parent);
// Assigns item to the new parent.
void assignNodeToNewParent(RootItem *item, RootItem *parent);
// Checks if new parent node is different from one used by original node.
// If it is, then it reassigns original_node to new parent.
@ -86,14 +83,6 @@ class FeedsModel : public QAbstractItemModel {
// in "newspaper" mode.
QList<Message> messagesForFeeds(const QList<Feed*> &feeds);
// Returns all categories, each pair
// consists of ID of parent item and pointer to category.
QHash<int, StandardCategory*> allCategories();
// Returns categories from the subtree with given root node, each pair
// consists of ID of parent item and pointer to category.
QHash<int, StandardCategory*> categoriesForItem(RootItem *root);
// Returns list of all feeds contained in the model.
QList<Feed*> allFeeds();
@ -113,7 +102,7 @@ class FeedsModel : public QAbstractItemModel {
// Returns pointer to category if it lies on given index
// or NULL if no category lies on given index.
StandardCategory *categoryForIndex(const QModelIndex &index) const;
Category *categoryForIndex(const QModelIndex &index) const;
// Returns feed/category which lies at the specified index or
// root item if index is invalid.
@ -130,10 +119,6 @@ class FeedsModel : public QAbstractItemModel {
return m_rootItem;
}
// Takes structure residing under given root item and adds feeds/categories from
// it to active structure.
bool mergeModel(FeedsImportExportModel *model, QString &output_message);
// Resets global auto-update intervals according to settings
// and starts/stop the timer as needed.
void updateAutoUpdateStatus();

View file

@ -155,15 +155,15 @@ bool FeedsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right
return QString::localeAwareCompare(left_item->title(), right_item->title()) < 0;
}
}
else if (left_item->kind() == RootItem::Bin) {
else if (left_item->kind() == RootItemKind::Bin) {
// Left item is recycle bin. Make sure it is "biggest" item if we have selected ascending order.
return sortOrder() == Qt::DescendingOrder;
}
else if (right_item->kind() == RootItem::Bin) {
else if (right_item->kind() == RootItemKind::Bin) {
// Right item is recycle bin. Make sure it is "smallest" item if we have selected descending order.
return sortOrder() == Qt::AscendingOrder;
}
else if (left_item->kind() == RootItem::Feeed) {
else if (left_item->kind() == RootItemKind::Feed) {
// Left item is feed, right item is category.
return false;
}
@ -193,7 +193,7 @@ bool FeedsProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source
RootItem *item = m_sourceModel->itemForIndex(idx);
if (item->kind() == RootItem::Bin) {
if (item->kind() == RootItemKind::Bin) {
// Recycle bin is always displayed.
return true;
}

View file

@ -39,11 +39,11 @@ FeedsSelection::SelectionMode FeedsSelection::mode() {
}
switch (m_selectedItem->kind()) {
case RootItem::Bin:
case RootItemKind::Bin:
return FeedsSelection::MessagesFromRecycleBin;
case RootItem::Cattegory:
case RootItem::Feeed:
case RootItemKind::Category:
case RootItemKind::Feed:
return FeedsSelection::MessagesFromFeeds;
default:
@ -57,12 +57,12 @@ RootItem *FeedsSelection::selectedItem() const {
QString FeedsSelection::generateListOfIds() {
if (m_selectedItem != NULL &&
(m_selectedItem->kind() == RootItem::Feeed || m_selectedItem->kind() == RootItem::Cattegory)) {
(m_selectedItem->kind() == RootItemKind::Feed || m_selectedItem->kind() == RootItemKind::Category)) {
QList<RootItem*> children = m_selectedItem->getRecursiveChildren();
QStringList stringy_ids;
foreach (RootItem *child, children) {
if (child->kind() == RootItem::Feeed) {
if (child->kind() == RootItemKind::Feed) {
stringy_ids.append(QString::number(child->id()));
}
}

View file

@ -25,7 +25,7 @@
RootItem::RootItem(RootItem *parent_item)
: m_kind(RootItem::Root),
: m_kind(RootItemKind::Root),
m_id(NO_PARENT_CATEGORY),
m_title(QString()),
m_description(QString()),
@ -77,8 +77,9 @@ int RootItem::countOfAllMessages() const {
QList<RootItem*> RootItem::getRecursiveChildren() {
QList<RootItem*> children;
if (kind() == RootItem::Feeed) {
// Root itself is a FEED.
if (childCount() == 0) {
// Root itself has no children, it is either feed or
// empty category?
children.append(this);
}
else {
@ -89,14 +90,14 @@ QList<RootItem*> RootItem::getRecursiveChildren() {
// Iterate all nested categories.
while (!traversable_items.isEmpty()) {
RootItem *active_category = traversable_items.takeFirst();
RootItem *active_item = traversable_items.takeFirst();
foreach (RootItem *child, active_category->childItems()) {
if (child->kind() == RootItem::Feeed) {
// This child is feed.
foreach (RootItem *child, active_item->childItems()) {
if (child->childCount() == 0) {
// This child is feed or empty category.
children.append(child);
}
else if (child->kind() == RootItem::Cattegory) {
else {
// This child is category, add its child feeds too.
traversable_items.append(child);
}
@ -111,25 +112,12 @@ bool RootItem::removeChild(RootItem *child) {
return m_childItems.removeOne(child);
}
StandardCategory *RootItem::toCategory() {
return static_cast<StandardCategory*>(this);
Category *RootItem::toCategory() {
return static_cast<Category*>(this);
}
StandardFeed *RootItem::toFeed() {
return static_cast<StandardFeed*>(this);
}
RootItem *RootItem::child(RootItem::Kind kind_of_child, const QString &identifier) {
foreach (RootItem *child, childItems()) {
if (child->kind() == kind_of_child) {
if ((kind_of_child == Cattegory && child->title() == identifier) ||
(kind_of_child == Feeed && child->toFeed()->url() == identifier)) {
return child;
}
}
}
return NULL;
Feed *RootItem::toFeed() {
return static_cast<Feed*>(this);
}
int RootItem::countOfUnreadMessages() const {

View file

@ -22,23 +22,24 @@
#include <QDateTime>
#include <QFont>
class StandardRecycleBin;
class StandardCategory;
class StandardFeed;
class Category;
class Feed;
namespace RootItemKind {
// Describes the kind of the item.
enum Kind {
Root = 1001,
Bin = 1002,
Feed = 1003,
Category = 1004
};
}
// Represents ROOT item of FeedsModel.
// NOTE: This class is derived to add functionality for
// all other non-root items of FeedsModel.
class RootItem {
public:
// Describes the kind of the item.
enum Kind {
Root = 1001,
Bin = 1002,
Feeed = 1003,
Cattegory = 1004
};
// Constructors and destructors.
explicit RootItem(RootItem *parent_item = NULL);
virtual ~RootItem();
@ -56,8 +57,6 @@ class RootItem {
return m_childItems.value(row);
}
virtual RootItem *child(RootItem::Kind kind_of_child, const QString &identifier);
inline virtual int childCount() const {
return m_childItems.size();
}
@ -110,7 +109,7 @@ class RootItem {
RootItem *this_item = this;
while (this_item->kind() != RootItem::Root) {
while (this_item->kind() != RootItemKind::Root) {
if (root->childItems().contains(this_item)) {
return true;
}
@ -122,6 +121,7 @@ class RootItem {
return false;
}
// Is "this" item parent if given child?
bool isParentOf(RootItem *child) {
if (child == NULL) {
return false;
@ -144,7 +144,7 @@ class RootItem {
bool removeChild(int index);
bool removeChild(RootItem *child);
inline Kind kind() const {
inline RootItemKind::Kind kind() const {
return m_kind;
}
@ -192,8 +192,8 @@ class RootItem {
}
// Converters
StandardCategory *toCategory();
StandardFeed *toFeed();
Category *toCategory();
Feed *toFeed();
// Compares two model items.
static bool isEqual(RootItem *lhs, RootItem *rhs);
@ -202,7 +202,7 @@ class RootItem {
protected:
void setupFonts();
Kind m_kind;
RootItemKind::Kind m_kind;
int m_id;
QString m_title;
QString m_description;

View file

@ -401,17 +401,25 @@ void FormMain::loadWebBrowserMenu(int index) {
}
void FormMain::exportFeeds() {
// TODO: dodelat globalni pristup ke globalnimu standard service rootu,
// ten předat
/*
QPointer<FormStandardImportExport> form = new FormStandardImportExport(this);
form.data()->setMode(FeedsImportExportModel::Export);
form.data()->exec();
delete form.data();
*/
}
void FormMain::importFeeds() {
// TODO: dodelat globalni pristup ke globalnimu standard service rootu,
// ten předat
/*
QPointer<FormStandardImportExport> form = new FormStandardImportExport(this);
form.data()->setMode(FeedsImportExportModel::Import);
form.data()->exec();
delete form.data();
*/
}
void FormMain::backupDatabaseSettings() {

View file

@ -209,9 +209,12 @@ void FeedMessageViewer::loadInitialFeeds() {
model.importAsOPML20(IOFactory::readTextFile(file_to_load));
model.checkAllItems();
// TODO: dodělat, předpokládá nějaký rozumný přístup k standardnímu root servicu.
/*
if (m_feedsView->sourceModel()->mergeModel(&model, output_msg)) {
m_feedsView->expandAll();
}
*/
}
catch (ApplicationException &ex) {
MessageBox::show(this, QMessageBox::Critical, tr("Error when loading initial feeds"), ex.message());

View file

@ -96,7 +96,7 @@ RootItem *FeedsView::selectedItem() const {
return selected_item == m_sourceModel->rootItem() ? NULL : selected_item;
}
StandardCategory *FeedsView::selectedCategory() const {
Category *FeedsView::selectedCategory() const {
QModelIndex current_mapped = m_proxyModel->mapToSource(currentIndex());
return m_sourceModel->categoryForIndex(current_mapped);
}
@ -109,22 +109,27 @@ Feed *FeedsView::selectedFeed() const {
void FeedsView::saveExpandedStates() {
Settings *settings = qApp->settings();
// TODO: doědlat
// Iterate all categories and save their expand statuses.
foreach (StandardCategory *category, sourceModel()->allCategories().values()) {
/*foreach (Category *category, sourceModel()->allCategories().values()) {
settings->setValue(GROUP(Categories),
QString::number(category->id()),
isExpanded(model()->mapFromSource(sourceModel()->indexForItem(category))));
}
}*/
}
void FeedsView::loadExpandedStates() {
Settings *settings = qApp->settings();
// TODO: doědlat
// Iterate all categories and save their expand statuses.
foreach (StandardCategory *category, sourceModel()->allCategories().values()) {
/*foreach (Category *category, sourceModel()->allCategories().values()) {
setExpanded(model()->mapFromSource(sourceModel()->indexForItem(category)),
settings->value(GROUP(Categories), QString::number(category->id()), true).toBool());
}
}*/
}
void FeedsView::invalidateReadFeedsFilter(bool set_new_value, bool show_unread_only) {
@ -185,48 +190,6 @@ void FeedsView::clearAllFeeds() {
setAllFeedsClearStatus(1);
}
void FeedsView::addNewCategory() {
if (!qApp->feedUpdateLock()->tryLock()) {
// Lock was not obtained because
// it is used probably by feed updater or application
// is quitting.
qApp->showGuiMessage(tr("Cannot add standard category"),
tr("You cannot add new standard category now because another critical operation is ongoing."),
QSystemTrayIcon::Warning, qApp->mainForm(), true);
return;
}
QPointer<FormStandardCategoryDetails> form_pointer = new FormStandardCategoryDetails(m_sourceModel, this);
form_pointer.data()->exec(NULL, selectedItem());
delete form_pointer.data();
// Changes are done, unlock the update master lock.
qApp->feedUpdateLock()->unlock();
}
void FeedsView::addNewFeed() {
if (!qApp->feedUpdateLock()->tryLock()) {
// Lock was not obtained because
// it is used probably by feed updater or application
// is quitting.
qApp->showGuiMessage(tr("Cannot add standard feed"),
tr("You cannot add new standard feed now because another critical operation is ongoing."),
QSystemTrayIcon::Warning, qApp->mainForm(), true);
return;
}
QPointer<FormStandardFeedDetails> form_pointer = new FormStandardFeedDetails(m_sourceModel, this);
form_pointer.data()->exec(NULL, selectedItem());
delete form_pointer.data();
// Changes are done, unlock the update master lock.
qApp->feedUpdateLock()->unlock();
}
void FeedsView::receiveMessageCountsChange(FeedsSelection::SelectionMode mode,
bool total_msg_count_changed,
bool any_msg_restored) {
@ -594,7 +557,7 @@ void FeedsView::contextMenuEvent(QContextMenuEvent *event) {
QModelIndex mapped_index = model()->mapToSource(clicked_index);
RootItem *clicked_item = sourceModel()->itemForIndex(mapped_index);
if (clicked_item->kind() == RootItem::Cattegory) {
if (clicked_item->kind() == RootItemKind::Category) {
// Display context menu for categories.
if (m_contextMenuCategories == NULL) {
// Context menu is not initialized, initialize.
@ -603,7 +566,7 @@ void FeedsView::contextMenuEvent(QContextMenuEvent *event) {
m_contextMenuCategories->exec(event->globalPos());
}
else if (clicked_item->kind() == RootItem::Feeed) {
else if (clicked_item->kind() == RootItemKind::Feed) {
// Display context menu for feeds.
if (m_contextMenuFeeds == NULL) {
// Context menu is not initialized, initialize.

View file

@ -29,6 +29,7 @@
class FeedsProxyModel;
class Feed;
class Category;
class StandardCategory;
class QTimer;
@ -59,7 +60,7 @@ class FeedsView : public QTreeView {
// Returns pointers to selected feed/category if they are really
// selected.
RootItem *selectedItem() const;
StandardCategory *selectedCategory() const;
Category *selectedCategory() const;
Feed *selectedFeed() const;
// Saves/loads expand states of all nodes (feeds/categories) of the list to/from settings.
@ -101,12 +102,6 @@ class FeedsView : public QTreeView {
void editSelectedItem();
void deleteSelectedItem();
// Standard category manipulators.
void addNewCategory();
// Standard feed manipulators.
void addNewFeed();
// Is called when counts of messages are changed externally,
// typically from message view.
void receiveMessageCountsChange(FeedsSelection::SelectionMode mode, bool total_msg_count_changed, bool any_msg_restored);

View file

@ -55,6 +55,8 @@ class Application : public QtSingleApplication {
explicit Application(const QString &id, int &argc, char **argv);
virtual ~Application();
// List of all installed "feed service plugins", including obligatory
// "standard" service entry point.
QList<ServiceEntryPoint*> feedServices();
QList<QAction*> userActions();

View file

@ -360,6 +360,7 @@ class Settings : public QSettings {
// Creates settings file in correct location.
static Settings *setupSettings(QObject *parent);
// Returns properties of the actual application-wide settings.
static SettingsProperties determineProperties();
private:

View file

@ -214,7 +214,9 @@ void WebBrowser::onIconChanged() {
void WebBrowser::addFeedFromWebsite(const QString &feed_link) {
qApp->clipboard()->setText(feed_link);
qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->addNewFeed();
// TODO: dodělat
//qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->addNewFeed();
}
void WebBrowser::onTitleChanged(const QString &new_title) {

View file

@ -0,0 +1,9 @@
#include "services/abstract/category.h"
Category::Category(RootItem *parent) : RootItem(parent) {
}
Category::~Category() {
}

View file

@ -0,0 +1,13 @@
#ifndef CATEGORY_H
#define CATEGORY_H
#include "core/rootitem.h"
class Category : public RootItem {
public:
explicit Category(RootItem *parent = NULL);
virtual ~Category();
};
#endif // CATEGORY_H

View file

@ -34,3 +34,7 @@ int Feed::childCount() const {
// Because feed has no children.
return 0;
}
void Feed::appendChild(RootItem *child) {
Q_UNUSED(child)
}

View file

@ -37,7 +37,9 @@ class Feed : public RootItem {
enum Status {
Normal = 0,
NewMessages = 1,
NetworkError = 2
NetworkError = 2,
ParsingError = 3,
OtherError = 4
};
// Constructors.
@ -47,6 +49,9 @@ class Feed : public RootItem {
// Returns 0, feeds have no children.
int childCount() const;
// Appending of childs to feed is not allowed.
void appendChild(RootItem *child);
// Performs synchronous update and returns number of newly updated messages.
virtual int update() = 0;

View file

@ -24,6 +24,7 @@
class ServiceRoot;
class FeedsModel;
// TOP LEVEL class which provides basic information about the "service"
class ServiceEntryPoint {
@ -36,7 +37,7 @@ class ServiceEntryPoint {
// point from persistent DB.
// Returns list of root nodes which will be afterwards added
// to the global feed model.
virtual QList<ServiceRoot*> initializeSubtree() = 0;
virtual QList<ServiceRoot*> initializeSubtree(FeedsModel *main_model) = 0;
// Must this service account be activated by default?
// NOTE: This is true particularly for "standard" service

View file

@ -17,10 +17,11 @@
#include "services/abstract/serviceroot.h"
#include "core/feedsmodel.h"
ServiceRoot::ServiceRoot(RootItem *parent) : RootItem(parent) {
ServiceRoot::ServiceRoot(FeedsModel *feeds_model, RootItem *parent) : RootItem(parent), m_feedsModel(feeds_model) {
}
ServiceRoot::~ServiceRoot() {
}

View file

@ -21,13 +21,22 @@
#include "core/rootitem.h"
class FeedsModel;
// THIS IS the root node of the service.
// NOTE: The root usually contains some core functionality of the
// service like service account username/password etc.
class ServiceRoot : public RootItem {
public:
explicit ServiceRoot(RootItem *parent = NULL);
explicit ServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL);
virtual ~ServiceRoot();
inline FeedsModel *feedsModel() const {
return m_feedsModel;
}
protected:
FeedsModel *m_feedsModel;
};
#endif // SERVICEROOT_H

View file

@ -20,13 +20,14 @@
#include "definitions/definitions.h"
#include "core/rootitem.h"
#include "core/feedsmodel.h"
#include "services/standard/standardcategory.h"
#include "miscellaneous/iconfactory.h"
#include "gui/feedsview.h"
#include "gui/baselineedit.h"
#include "gui/messagebox.h"
#include "gui/systemtrayicon.h"
#include "gui/dialogs/formmain.h"
#include "services/standard/standardcategory.h"
#include "services/standard/standardserviceroot.h"
#include <QLineEdit>
#include <QTextEdit>
@ -38,9 +39,8 @@
#include <QFileDialog>
FormStandardCategoryDetails::FormStandardCategoryDetails(FeedsModel *model, QWidget *parent) : QDialog(parent),
m_editableCategory(NULL),
m_feedsModel(model) {
FormStandardCategoryDetails::FormStandardCategoryDetails(StandardServiceRoot *service_root, QWidget *parent)
: QDialog(parent), m_editableCategory(NULL), m_serviceRoot(service_root) {
initialize();
createConnections();
@ -76,7 +76,7 @@ void FormStandardCategoryDetails::setEditableCategory(StandardCategory *editable
int FormStandardCategoryDetails::exec(StandardCategory *input_category, RootItem *parent_to_select) {
// Load categories.
loadCategories(m_feedsModel->allCategories().values(), m_feedsModel->rootItem(), input_category);
loadCategories(m_serviceRoot->allCategories().values(), m_serviceRoot, input_category);
if (input_category == NULL) {
// User is adding new category.
@ -88,10 +88,10 @@ int FormStandardCategoryDetails::exec(StandardCategory *input_category, RootItem
// Load parent from suggested item.
if (parent_to_select != NULL) {
if (parent_to_select->kind() == RootItem::Cattegory) {
if (parent_to_select->kind() == RootItemKind::Category) {
m_ui->m_cmbParentCategory->setCurrentIndex(m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select)));
}
else if (parent_to_select->kind() == RootItem::Feeed) {
else if (parent_to_select->kind() == RootItemKind::Feed) {
int target_item = m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select->parent()));
if (target_item >= 0) {
@ -122,10 +122,12 @@ void FormStandardCategoryDetails::apply() {
if (m_editableCategory == NULL) {
// Add the category.
if (m_feedsModel->addCategory(new_category, parent)) {
if (new_category->addItself(parent)) {
m_serviceRoot->feedsModel()->assignNodeToNewParent(new_category, parent);
accept();
}
else {
delete new_category;
qApp->showGuiMessage(tr("Cannot add category"),
tr("Category was not added due to error."),
QSystemTrayIcon::Critical,
@ -136,7 +138,7 @@ void FormStandardCategoryDetails::apply() {
bool edited = m_editableCategory->editItself(new_category);
if (edited) {
m_feedsModel->reassignNodeToNewParent(m_editableCategory, new_category->parent());
m_serviceRoot->feedsModel()->reassignNodeToNewParent(m_editableCategory, new_category->parent());
// Remove new temporary feed data holder object.
delete new_category;

View file

@ -28,7 +28,7 @@ namespace Ui {
}
class StandardCategory;
class StandardCategory;
class StandardServiceRoot;
class FeedsModel;
class RootItem;
class QMenu;
@ -39,7 +39,7 @@ class FormStandardCategoryDetails : public QDialog {
public:
// Constructors and destructors.
explicit FormStandardCategoryDetails(FeedsModel *model, QWidget *parent = 0);
explicit FormStandardCategoryDetails(StandardServiceRoot *service_root, QWidget *parent = 0);
virtual ~FormStandardCategoryDetails();
public slots:
@ -77,7 +77,7 @@ class FormStandardCategoryDetails : public QDialog {
private:
Ui::FormStandardCategoryDetails *m_ui;
StandardCategory *m_editableCategory;
FeedsModel *m_feedsModel;
StandardServiceRoot *m_serviceRoot;
QMenu *m_iconMenu;
QAction *m_actionLoadIconFromFile;

View file

@ -20,6 +20,7 @@
#include "definitions/definitions.h"
#include "core/feedsmodel.h"
#include "core/rootitem.h"
#include "services/standard/standardserviceroot.h"
#include "services/standard/standardcategory.h"
#include "services/standard/standardfeed.h"
#include "miscellaneous/textfactory.h"
@ -39,10 +40,10 @@
#include <QMimeData>
FormStandardFeedDetails::FormStandardFeedDetails(FeedsModel *model, QWidget *parent)
FormStandardFeedDetails::FormStandardFeedDetails(StandardServiceRoot *service_root, QWidget *parent)
: QDialog(parent),
m_editableFeed(NULL),
m_feedsModel(model) {
m_serviceRoot(service_root) {
initialize();
createConnections();
@ -60,7 +61,7 @@ FormStandardFeedDetails::~FormStandardFeedDetails() {
int FormStandardFeedDetails::exec(StandardFeed *input_feed, RootItem *parent_to_select) {
// Load categories.
loadCategories(m_feedsModel->allCategories().values(), m_feedsModel->rootItem());
loadCategories(m_serviceRoot->allCategories().values(), m_serviceRoot);
if (input_feed == NULL) {
// User is adding new category.
@ -77,10 +78,10 @@ int FormStandardFeedDetails::exec(StandardFeed *input_feed, RootItem *parent_to_
}
if (parent_to_select != NULL) {
if (parent_to_select->kind() == RootItem::Cattegory) {
if (parent_to_select->kind() == RootItemKind::Category) {
m_ui->m_cmbParentCategory->setCurrentIndex(m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select)));
}
else if (parent_to_select->kind() == RootItem::Feeed) {
else if (parent_to_select->kind() == RootItemKind::Feed) {
int target_item = m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select->parent()));
if (target_item >= 0) {
@ -240,10 +241,12 @@ void FormStandardFeedDetails::apply() {
if (m_editableFeed == NULL) {
// Add the feed.
if (m_feedsModel->addFeed(new_feed, parent)) {
if (new_feed->addItself(parent)) {
m_serviceRoot->feedsModel()->assignNodeToNewParent(new_feed, parent);
accept();
}
else {
delete new_feed;
qApp->showGuiMessage(tr("Cannot add feed"),
tr("Feed was not added due to error."),
QSystemTrayIcon::Critical, this, true);
@ -254,7 +257,7 @@ void FormStandardFeedDetails::apply() {
bool edited = m_editableFeed->editItself(new_feed);
if (edited) {
m_feedsModel->reassignNodeToNewParent(m_editableFeed, new_feed->parent());
m_serviceRoot->feedsModel()->reassignNodeToNewParent(m_editableFeed, new_feed->parent());
// Remove new temporary feed data holder object.
delete new_feed;

View file

@ -27,7 +27,7 @@ namespace Ui {
class FormStandardFeedDetails;
}
class FeedsModel;
class StandardServiceRoot;
class StandardFeed;
class StandardCategory;
class RootItem;
@ -37,7 +37,7 @@ class FormStandardFeedDetails : public QDialog {
public:
// Constructors and destructors.
explicit FormStandardFeedDetails(FeedsModel *model, QWidget *parent = 0);
explicit FormStandardFeedDetails(StandardServiceRoot *service_root, QWidget *parent = 0);
virtual ~FormStandardFeedDetails();
public slots:
@ -84,7 +84,7 @@ class FormStandardFeedDetails : public QDialog {
private:
Ui::FormStandardFeedDetails *m_ui;
StandardFeed *m_editableFeed;
FeedsModel *m_feedsModel;
StandardServiceRoot *m_serviceRoot;
QMenu *m_iconMenu;
QAction *m_actionLoadIconFromFile;

View file

@ -18,6 +18,7 @@
#include "services/standard/gui/formstandardimportexport.h"
#include "services/standard/standardfeedsimportexportmodel.h"
#include "services/standard/standardserviceroot.h"
#include "core/feedsmodel.h"
#include "miscellaneous/application.h"
#include "gui/feedmessageviewer.h"
@ -28,8 +29,8 @@
#include <QTextStream>
FormStandardImportExport::FormStandardImportExport(QWidget *parent)
: QDialog(parent), m_ui(new Ui::FormStandardImportExport) {
FormStandardImportExport::FormStandardImportExport(StandardServiceRoot *service_root, QWidget *parent)
: QDialog(parent), m_ui(new Ui::FormStandardImportExport), m_serviceRoot(service_root) {
m_ui->setupUi(this);
m_model = new FeedsImportExportModel(m_ui->m_treeFeeds);
@ -54,7 +55,7 @@ void FormStandardImportExport::setMode(const FeedsImportExportModel::Mode &mode)
switch (mode) {
case FeedsImportExportModel::Export: {
m_model->setRootItem(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->rootItem());
m_model->setRootItem(m_serviceRoot);
m_model->checkAllItems();
m_ui->m_treeFeeds->setModel(m_model);
m_ui->m_treeFeeds->expandAll();
@ -117,7 +118,6 @@ void FormStandardImportExport::selectExportFile() {
selected_file += QL1S(".opml");
}
}
// NOTE: Add other types here.
m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(selected_file), tr("File is selected."));
}
@ -141,7 +141,6 @@ void FormStandardImportExport::selectImportFile() {
if (selected_filter == filter_opml20) {
m_conversionType = OPML20;
}
// NOTE: Add other types here.
m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(selected_file), tr("File is selected."));
parseImportFile(selected_file);
@ -241,7 +240,8 @@ void FormStandardImportExport::exportFeeds() {
void FormStandardImportExport::importFeeds() {
QString output_message;
if (qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->mergeModel(m_model, output_message)) {
if (m_serviceRoot->mergeImportExportModel(m_model, output_message)) {
// TODO: Hate this global access, what about signal?
qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->expandAll();
m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, output_message, output_message);
}

View file

@ -23,11 +23,12 @@
#include "ui_formstandardimportexport.h"
#include "services/standard/standardfeedsimportexportmodel.h"
namespace Ui {
class FormStandardImportExport;
}
class StandardServiceRoot;
class FormStandardImportExport : public QDialog {
Q_OBJECT
@ -37,7 +38,7 @@ class FormStandardImportExport : public QDialog {
};
// Constructors.
explicit FormStandardImportExport(QWidget *parent = 0);
explicit FormStandardImportExport(StandardServiceRoot *service_root, QWidget *parent = 0);
virtual ~FormStandardImportExport();
void setMode(const FeedsImportExportModel::Mode &mode);
@ -57,6 +58,7 @@ class FormStandardImportExport : public QDialog {
Ui::FormStandardImportExport *m_ui;
ConversionType m_conversionType;
FeedsImportExportModel *m_model;
StandardServiceRoot *m_serviceRoot;
};
#endif // FORMEXPORT_H

View file

@ -34,12 +34,12 @@
#include <QPointer>
StandardCategory::StandardCategory(RootItem *parent_item) : RootItem(parent_item) {
StandardCategory::StandardCategory(RootItem *parent_item) : Category(parent_item) {
init();
}
StandardCategory::StandardCategory(const StandardCategory &other)
: RootItem(NULL) {
: Category(NULL) {
m_kind = other.kind();
m_id = other.id();
m_title = other.title();
@ -55,7 +55,7 @@ StandardCategory::~StandardCategory() {
}
void StandardCategory::init() {
m_kind = RootItem::Cattegory;
m_kind = RootItemKind::Category;
}
QVariant StandardCategory::data(int column, int role) const {
@ -127,13 +127,16 @@ QVariant StandardCategory::data(int column, int role) const {
}
void StandardCategory::editViaDialog() {
// TODO: fix passing of the model
// TODO: předávat service root.
/*
QPointer<FormStandardCategoryDetails> form_pointer = new FormStandardCategoryDetails(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel(),
qApp->mainForm());
form_pointer.data()->exec(this, NULL);
delete form_pointer.data();
*/
}
bool StandardCategory::removeItself() {
@ -230,7 +233,7 @@ bool StandardCategory::editItself(StandardCategory *new_category_data) {
return true;
}
StandardCategory::StandardCategory(const QSqlRecord &record) : RootItem(NULL) {
StandardCategory::StandardCategory(const QSqlRecord &record) : Category(NULL) {
init();
setId(record.value(CAT_DB_ID_INDEX).toInt());

View file

@ -18,7 +18,7 @@
#ifndef FEEDSMODELCATEGORY_H
#define FEEDSMODELCATEGORY_H
#include "core/rootitem.h"
#include "services/abstract/category.h"
#include <QSqlRecord>
#include <QCoreApplication>
@ -29,8 +29,8 @@ class FeedsModel;
// Base class for all categories contained in FeedsModel.
// NOTE: This class should be derived to create PARTICULAR category types.
// NOTE: This class should not be instantiated directly.
class StandardCategory : public RootItem {
Q_DECLARE_TR_FUNCTIONS(Category)
class StandardCategory : public Category {
Q_DECLARE_TR_FUNCTIONS(StandardCategory)
public:
// Constructors and destructors

View file

@ -53,7 +53,7 @@ void StandardFeed::init() {
m_unreadCount = 0;
m_encoding = QString();
m_url = QString();
m_kind = RootItem::Feeed;
m_kind = RootItemKind::Feed;
}
StandardFeed::StandardFeed(RootItem *parent_item)
@ -76,7 +76,7 @@ StandardFeed::StandardFeed(const StandardFeed &other)
m_autoUpdateRemainingInterval = other.autoUpdateRemainingInterval();
m_encoding = other.encoding();
m_url = other.url();
m_kind = RootItem::Feeed;
m_kind = RootItemKind::Feed;
m_title = other.title();
m_id = other.id();
m_icon = other.icon();
@ -100,11 +100,14 @@ int StandardFeed::countOfUnreadMessages() const {
void StandardFeed::editViaDialog() {
// TODO: fix passing of the model
/*
QPointer<FormStandardFeedDetails> form_pointer = new FormStandardFeedDetails(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel(),
qApp->mainForm());
form_pointer.data()->exec(this, NULL);
delete form_pointer.data();
*/
}
QString StandardFeed::typeToString(StandardFeed::Type type) {
@ -716,7 +719,7 @@ QNetworkReply::NetworkError StandardFeed::networkError() const {
}
StandardFeed::StandardFeed(const QSqlRecord &record) : Feed(NULL) {
m_kind = RootItem::Feeed;
m_kind = RootItemKind::Feed;
setTitle(record.value(FDS_DB_TITLE_INDEX).toString());
setId(record.value(FDS_DB_ID_INDEX).toInt());

View file

@ -99,7 +99,7 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray &result) {
}
switch (child_item->kind()) {
case RootItem::Cattegory: {
case RootItemKind::Category: {
QDomElement outline_category = opml_document.createElement(QSL("outline"));
outline_category.setAttribute(QSL("text"), child_item->title());
outline_category.setAttribute(QSL("description"), child_item->description());
@ -110,8 +110,8 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray &result) {
break;
}
case RootItem::Feeed: {
StandardFeed *child_feed = child_item->toFeed();
case RootItemKind::Feed: {
StandardFeed *child_feed = static_cast<StandardFeed*>(child_item);
QDomElement outline_feed = opml_document.createElement("outline");
outline_feed.setAttribute(QSL("text"), child_feed->title());
outline_feed.setAttribute(QSL("xmlUrl"), child_feed->url());
@ -264,7 +264,7 @@ void FeedsImportExportModel::setMode(const FeedsImportExportModel::Mode &mode) {
void FeedsImportExportModel::checkAllItems() {
foreach (RootItem *root_child, m_rootItem->childItems()) {
if (root_child->kind() != RootItem::Bin) {
if (root_child->kind() != RootItemKind::Bin) {
setData(indexForItem(root_child), Qt::Checked, Qt::CheckStateRole);
}
}
@ -272,7 +272,7 @@ void FeedsImportExportModel::checkAllItems() {
void FeedsImportExportModel::uncheckAllItems() {
foreach (RootItem *root_child, m_rootItem->childItems()) {
if (root_child->kind() != RootItem::Bin) {
if (root_child->kind() != RootItemKind::Bin) {
setData(indexForItem(root_child), Qt::Unchecked, Qt::CheckStateRole);
}
}
@ -295,7 +295,7 @@ QModelIndex FeedsImportExportModel::index(int row, int column, const QModelIndex
}
QModelIndex FeedsImportExportModel::indexForItem(RootItem *item) const {
if (item == NULL || item->kind() == RootItem::Root) {
if (item == NULL || item->kind() == RootItemKind::Root) {
// Root item lies on invalid index.
return QModelIndex();
}
@ -324,7 +324,7 @@ QModelIndex FeedsImportExportModel::indexForItem(RootItem *item) const {
for (int i = 0; i < row_count; i++) {
RootItem *possible_category = active_item->child(i);
if (possible_category->kind() == RootItem::Cattegory) {
if (possible_category->kind() == RootItemKind::Category) {
parents << index(i, 0, active_index);
}
}
@ -362,7 +362,6 @@ int FeedsImportExportModel::rowCount(const QModelIndex &parent) const {
int FeedsImportExportModel::columnCount(const QModelIndex &parent) const {
Q_UNUSED(parent)
return 1;
}
@ -383,9 +382,9 @@ QVariant FeedsImportExportModel::data(const QModelIndex &index, int role) const
}
else if (role == Qt::DecorationRole) {
switch (item->kind()) {
case RootItem::Cattegory:
case RootItem::Bin:
case RootItem::Feeed:
case RootItemKind::Category:
case RootItemKind::Bin:
case RootItemKind::Feed:
return item->icon();
default:
@ -394,10 +393,10 @@ QVariant FeedsImportExportModel::data(const QModelIndex &index, int role) const
}
else if (role == Qt::DisplayRole) {
switch (item->kind()) {
case RootItem::Cattegory:
case RootItemKind::Category:
return QVariant(item->data(index.column(), role).toString() + tr(" (category)"));
case RootItem::Feeed:
case RootItemKind::Feed:
return QVariant(item->data(index.column(), role).toString() + tr(" (feed)"));
default:
@ -462,7 +461,7 @@ bool FeedsImportExportModel::setData(const QModelIndex &index, const QVariant &v
}
Qt::ItemFlags FeedsImportExportModel::flags(const QModelIndex &index) const {
if (!index.isValid() || itemForIndex(index)->kind() == RootItem::Bin) {
if (!index.isValid() || itemForIndex(index)->kind() == RootItemKind::Bin) {
return Qt::NoItemFlags;
}

View file

@ -73,7 +73,6 @@ class FeedsImportExportModel : public QAbstractItemModel {
QHash<RootItem*, Qt::CheckState> m_checkStates;
RootItem *m_rootItem;
// When it's true, then
bool m_recursiveChange;
Mode m_mode;
};

View file

@ -0,0 +1,18 @@
#include "services/standard/standarditem.h"
#include "services/standard/standardserviceroot.h"
StandardItem::StandardItem(StandardServiceRoot *service_root) : m_serviceRoot(service_root) {
}
StandardItem::~StandardItem() {
}
StandardServiceRoot *StandardItem::serviceRoot() const {
return m_serviceRoot;
}
void StandardItem::setServiceRoot(StandardServiceRoot *service_root) {
m_serviceRoot = service_root;
}

View file

@ -0,0 +1,19 @@
#ifndef STANDARDITEM_H
#define STANDARDITEM_H
class StandardServiceRoot;
class StandardItem {
public:
explicit StandardItem(StandardServiceRoot *service_root);
virtual ~StandardItem();
StandardServiceRoot *serviceRoot() const;
void setServiceRoot(StandardServiceRoot *service_root);
protected:
StandardServiceRoot *m_serviceRoot;
};
#endif // STANDARDITEM_H

View file

@ -25,7 +25,7 @@
StandardRecycleBin::StandardRecycleBin(RootItem *parent)
: RootItem(parent) {
m_kind = RootItem::Bin;
m_kind = RootItemKind::Bin;
m_icon = qApp->icons()->fromTheme(QSL("folder-recycle-bin"));
m_id = ID_RECYCLE_BIN;
m_title = tr("Recycle bin");

View file

@ -69,8 +69,8 @@ QIcon StandardServiceEntryPoint::icon() {
return QIcon(APP_ICON_PATH);
}
QList<ServiceRoot*> StandardServiceEntryPoint::initializeSubtree() {
StandardServiceRoot *root = new StandardServiceRoot();
QList<ServiceRoot*> StandardServiceEntryPoint::initializeSubtree(FeedsModel *main_model) {
StandardServiceRoot *root = new StandardServiceRoot(main_model);
QList<ServiceRoot*> roots;
roots.append(root);

View file

@ -37,7 +37,7 @@ class StandardServiceEntryPoint : public ServiceEntryPoint {
QString author();
QIcon icon();
QList<ServiceRoot*> initializeSubtree();
QList<ServiceRoot*> initializeSubtree(FeedsModel *main_model);
};
#endif // STANDARDSERVICEENTRYPOINT_H

View file

@ -20,17 +20,20 @@
#include "definitions/definitions.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "core/feedsmodel.h"
#include "services/standard/standardserviceentrypoint.h"
#include "services/standard/standardrecyclebin.h"
#include "services/standard/standardfeed.h"
#include "services/standard/standardcategory.h"
#include "services/standard/standardfeedsimportexportmodel.h"
#include <QSqlQuery>
#include <QSqlError>
#include <QStack>
StandardServiceRoot::StandardServiceRoot(RootItem *parent)
: ServiceRoot(parent), m_recycleBin(new StandardRecycleBin(this)) {
StandardServiceRoot::StandardServiceRoot(FeedsModel *feeds_model, RootItem *parent)
: ServiceRoot(feeds_model, parent), m_recycleBin(new StandardRecycleBin(this)) {
m_title = qApp->system()->getUsername() + "@" + APP_LOW_NAME;
m_icon = StandardServiceEntryPoint().icon();
@ -113,7 +116,6 @@ QVariant StandardServiceRoot::data(int column, int role) const {
}
void StandardServiceRoot::loadFromDatabase(){
// TODO: todo
QSqlDatabase database = qApp->database()->connection("StandardServiceRoot", DatabaseFactory::FromSettings);
CategoryAssignment categories;
FeedAssignment feeds;
@ -175,8 +177,8 @@ void StandardServiceRoot::loadFromDatabase(){
appendChild(m_recycleBin);
}
QHash<int, StandardCategory*> StandardServiceRoot::categoriesForItem(RootItem *root) {
QHash<int, StandardCategory*> categories;
QHash<int,StandardCategory*> StandardServiceRoot::categoriesForItem(RootItem *root) {
QHash<int,StandardCategory*> categories;
QList<RootItem*> parents;
parents.append(root->childItems());
@ -184,11 +186,11 @@ QHash<int, StandardCategory*> StandardServiceRoot::categoriesForItem(RootItem *r
while (!parents.isEmpty()) {
RootItem *item = parents.takeFirst();
if (item->kind() == RootItem::Cattegory) {
if (item->kind() == RootItemKind::Category) {
// This item is category, add it to the output list and
// scan its children.
int category_id = item->id();
StandardCategory *category = item->toCategory();
StandardCategory *category = static_cast<StandardCategory*>(item);
if (!categories.contains(category_id)) {
categories.insert(category_id, category);
@ -201,8 +203,12 @@ QHash<int, StandardCategory*> StandardServiceRoot::categoriesForItem(RootItem *r
return categories;
}
QHash<int,StandardCategory*> StandardServiceRoot::allCategories() {
return categoriesForItem(this);
}
void StandardServiceRoot::assembleFeeds(FeedAssignment feeds) {
QHash<int, StandardCategory*> categories = categoriesForItem(this);
QHash<int,StandardCategory*> categories = categoriesForItem(this);
foreach (const FeedAssignmentItem &feed, feeds) {
if (feed.first == NO_PARENT_CATEGORY) {
@ -223,6 +229,86 @@ StandardRecycleBin *StandardServiceRoot::recycleBin() const {
return m_recycleBin;
}
bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, QString &output_message) {
QStack<RootItem*> original_parents; original_parents.push(this);
QStack<RootItem*> new_parents; new_parents.push(model->rootItem());
bool some_feed_category_error = false;
// Iterate all new items we would like to merge into current model.
while (!new_parents.isEmpty()) {
RootItem *target_parent = original_parents.pop();
RootItem *source_parent = new_parents.pop();
foreach (RootItem *source_item, source_parent->childItems()) {
if (!model->isItemChecked(source_item)) {
// We can skip this item, because it is not checked and should not be imported.
// NOTE: All descendants are thus skipped too.
continue;
}
if (source_item->kind() == RootItemKind::Category) {
StandardCategory *source_category = static_cast<StandardCategory*>(source_item);
StandardCategory *new_category = new StandardCategory(*source_category);
QString new_category_title = new_category->title();
// Add category to model.
new_category->clearChildren();
if (new_category->addItself(target_parent)) {
m_feedsModel->assignNodeToNewParent(new_category, target_parent);
// Process all children of this category.
original_parents.push(new_category);
new_parents.push(source_category);
}
else {
delete new_category;
// Add category failed, but this can mean that the same category (with same title)
// already exists. If such a category exists in current parent, then find it and
// add descendants to it.
RootItem *existing_category = NULL;
foreach (RootItem *child, target_parent->childItems()) {
if (child->kind() == RootItemKind::Category && child->title() == new_category_title) {
existing_category = child;
}
}
if (existing_category != NULL) {
original_parents.push(existing_category);
new_parents.push(source_category);
}
else {
some_feed_category_error = true;
}
}
}
else if (source_item->kind() == RootItemKind::Feed) {
StandardFeed *source_feed = static_cast<StandardFeed*>(source_item);
StandardFeed *new_feed = new StandardFeed(*source_feed);
// Append this feed and end this iteration.
if (!new_feed->addItself(target_parent)) {
delete new_feed;
some_feed_category_error = true;
}
}
}
}
// Changes are done now. Finalize the new model.
//emit layoutChanged();
if (some_feed_category_error) {
output_message = tr("Import successfull, but some feeds/categories were not imported due to error.");
}
else {
output_message = tr("Import was completely successfull.");
}
return !some_feed_category_error;
}
void StandardServiceRoot::assembleCategories(CategoryAssignment categories) {
QHash<int, RootItem*> assignments;
assignments.insert(NO_PARENT_CATEGORY, this);
@ -235,8 +321,7 @@ void StandardServiceRoot::assembleCategories(CategoryAssignment categories) {
assignments.value(categories.at(i).first)->appendChild(categories.at(i).second);
// Now, added category can be parent for another categories, add it.
assignments.insert(categories.at(i).second->id(),
categories.at(i).second);
assignments.insert(categories.at(i).second->id(), categories.at(i).second);
// Remove the category from the list, because it was
// added to the final collection.

View file

@ -26,6 +26,7 @@
class StandardRecycleBin;
class StandardCategory;
class StandardFeed;
class FeedsImportExportModel;
typedef QList<QPair<int, StandardCategory*> > CategoryAssignment;
typedef QPair<int, StandardCategory*> CategoryAssignmentItem;
@ -37,7 +38,7 @@ class StandardServiceRoot : public ServiceRoot {
Q_DECLARE_TR_FUNCTIONS(StandardServiceRoot)
public:
explicit StandardServiceRoot(RootItem *parent = NULL);
explicit StandardServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL);
virtual ~StandardServiceRoot();
bool canBeEdited();
@ -46,11 +47,20 @@ class StandardServiceRoot : public ServiceRoot {
// Returns all standard categories which are lying under given root node.
// This does NOT include the root node even if the node is category.
QHash<int, StandardCategory*> categoriesForItem(RootItem *root);
QHash<int,StandardCategory*> categoriesForItem(RootItem *root);
// Returns all categories from this root, each pair
// consists of ID of parent item and pointer to category.
QHash<int,StandardCategory*> allCategories();
// Access to standard recycle bin.
StandardRecycleBin *recycleBin() const;
// Takes structure residing under given root item and adds feeds/categories from
// it to active structure.
// NOTE: This is used for import/export of the model.
bool mergeImportExportModel(FeedsImportExportModel *model, QString &output_message);
private:
void loadFromDatabase();

View file

@ -69,6 +69,6 @@ QIcon TtRssServiceEntryPoint::icon() {
return QIcon(APP_ICON_PATH);
}
QList<ServiceRoot*> TtRssServiceEntryPoint::initializeSubtree() {
QList<ServiceRoot*> TtRssServiceEntryPoint::initializeSubtree(FeedsModel *main_model) {
return QList<ServiceRoot*>();
}

View file

@ -38,7 +38,7 @@ class TtRssServiceEntryPoint : public ServiceEntryPoint {
QString author();
QIcon icon();
QList<ServiceRoot*> initializeSubtree();
QList<ServiceRoot*> initializeSubtree(FeedsModel *main_model);
};
#endif // TTRSSSERVICEENTRYPOINT_H

View file

@ -20,9 +20,10 @@
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "services/tt-rss/ttrssserviceentrypoint.h"
#include "core/feedsmodel.h"
TtRssServiceRoot::TtRssServiceRoot(RootItem *parent) : ServiceRoot(parent) {
TtRssServiceRoot::TtRssServiceRoot(FeedsModel *feeds_model, RootItem *parent) : ServiceRoot(feeds_model, parent) {
// TODO: nadpis se bude měnit podle nastavení uživatelského
// jména a serveru tohoto ttrss učtu
m_title = qApp->system()->getUsername() + "@ttrss";

View file

@ -23,11 +23,13 @@
#include <QCoreApplication>
class FeedsModel;
class TtRssServiceRoot : public ServiceRoot {
Q_DECLARE_TR_FUNCTIONS(StandardServiceRoot)
public:
explicit TtRssServiceRoot(RootItem *parent = NULL);
explicit TtRssServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL);
virtual ~TtRssServiceRoot();
bool canBeEdited();