diff --git a/CMakeLists.txt b/CMakeLists.txt index 0df1f5a53..cd6c78b8a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -417,6 +417,7 @@ set(APP_SOURCES # ABSTRACT service sources. src/services/abstract/serviceentrypoint.cpp src/services/abstract/feed.cpp + src/services/abstract/category.cpp src/services/abstract/serviceroot.cpp # STANDARD feed service sources. @@ -429,6 +430,7 @@ set(APP_SOURCES src/services/standard/standardserviceentrypoint.cpp src/services/standard/standardserviceroot.cpp src/services/standard/standardrecyclebin.cpp + src/services/standard/standarditem.cpp # TT-RSS feed service sources. src/services/tt-rss/ttrssserviceentrypoint.cpp diff --git a/resources/text/CHANGELOG b/resources/text/CHANGELOG index 936cec063..030cf17d3 100644 --- a/resources/text/CHANGELOG +++ b/resources/text/CHANGELOG @@ -12,6 +12,19 @@ +

2.5.3

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

2.5.2

Added: diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index cd6bc51e7..494d12bc8 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -232,42 +232,15 @@ bool FeedsModel::removeItem(const QModelIndex &index) { return false; } -bool FeedsModel::addCategory(StandardCategory *category, RootItem *parent) { +void FeedsModel::assignNodeToNewParent(RootItem *item, RootItem *parent) { // Get index of parent item (parent standard category). QModelIndex parent_index = indexForItem(parent); - bool result = category->addItself(parent); - if (result) { - // Category was added to the persistent storage, - // so add it to the model. - beginInsertRows(parent_index, parent->childCount(), parent->childCount()); - parent->appendChild(category); - endInsertRows(); - } - else { - // We cannot delete (*this) in its method, thus delete it here. - delete category; - } + // TODO: todle jde sloučit s metodou reassignNodeToNewParent. - return result; -} - -bool FeedsModel::addFeed(StandardFeed *feed, RootItem *parent) { - // Get index of parent item (parent standard category or root item). - QModelIndex parent_index = indexForItem(parent); - bool result = feed->addItself(parent); - - if (result) { - // Feed was added to the persistent storage so add it to the model. - beginInsertRows(parent_index, parent->childCount(), parent->childCount()); - parent->appendChild(feed); - endInsertRows(); - } - else { - delete feed; - } - - return result; + beginInsertRows(parent_index, parent->childCount(), parent->childCount()); + parent->appendChild(item); + endInsertRows(); } void FeedsModel::reassignNodeToNewParent(RootItem *original_node, RootItem *new_parent) { @@ -378,10 +351,10 @@ RootItem *FeedsModel::itemForIndex(const QModelIndex &index) const { } } -StandardCategory *FeedsModel::categoryForIndex(const QModelIndex &index) const { +Category *FeedsModel::categoryForIndex(const QModelIndex &index) const { RootItem *item = itemForIndex(index); - if (item->kind() == RootItem::Cattegory) { + if (item->kind() == RootItemKind::Category) { return item->toCategory(); } else { @@ -390,14 +363,14 @@ StandardCategory *FeedsModel::categoryForIndex(const QModelIndex &index) const { } QModelIndex FeedsModel::indexForItem(RootItem *item) const { - if (item == NULL || item->kind() == RootItem::Root) { + if (item == NULL || item->kind() == RootItemKind::Root) { // Root item lies on invalid index. return QModelIndex(); } QStack chain; - while (item->kind() != RootItem::Root) { + while (item->kind() != RootItemKind::Root) { chain.push(item); item = item->parent(); } @@ -424,84 +397,6 @@ bool FeedsModel::hasAnyFeedNewMessages() { return false; } -bool FeedsModel::mergeModel(FeedsImportExportModel *model, QString &output_message) { - if (model == NULL || model->rootItem() == NULL) { - output_message = tr("Invalid tree data."); - qDebug("Root item for merging two models is null."); - return false; - } - - QStack original_parents; original_parents.push(m_rootItem); - QStack new_parents; new_parents.push(model->rootItem()); - bool some_feed_category_error = false; - - // We are definitely about to add some new items into the model. - //emit layoutAboutToBeChanged(); - - // Iterate all new items we would like to merge into current model. - while (!new_parents.isEmpty()) { - RootItem *target_parent = original_parents.pop(); - RootItem *source_parent = new_parents.pop(); - - foreach (RootItem *source_item, source_parent->childItems()) { - if (!model->isItemChecked(source_item)) { - // We can skip this item, because it is not checked and should not be imported. - // NOTE: All descendants are thus skipped too. - continue; - } - - if (source_item->kind() == RootItem::Cattegory) { - StandardCategory *source_category = source_item->toCategory(); - StandardCategory *new_category = new StandardCategory(*source_category); - - // Add category to model. - new_category->clearChildren(); - - if (addCategory(new_category, target_parent)) { - // Process all children of this category. - original_parents.push(new_category); - new_parents.push(source_category); - } - else { - // Add category failed, but this can mean that the same category (with same title) - // already exists. If such a category exists in current parent, then find it and - // add descendants to it. - RootItem *existing_category = target_parent->child(RootItem::Cattegory, new_category->title()); - - if (existing_category != NULL) { - original_parents.push(existing_category); - new_parents.push(source_category); - } - else { - some_feed_category_error = true; - } - } - } - else if (source_item->kind() == RootItem::Feeed) { - StandardFeed *source_feed = source_item->toFeed(); - StandardFeed *new_feed = new StandardFeed(*source_feed); - - // Append this feed and end this iteration. - if (!addFeed(new_feed, target_parent)) { - some_feed_category_error = true; - } - } - } - } - - // Changes are done now. Finalize the new model. - //emit layoutChanged(); - - if (some_feed_category_error) { - output_message = tr("Import successfull, but some feeds/categories were not imported due to error."); - } - else { - output_message = tr("Import was completely successfull."); - } - - return !some_feed_category_error; -} - void FeedsModel::reloadChangedLayout(QModelIndexList list) { while (!list.isEmpty()) { QModelIndex indx = list.takeFirst(); @@ -535,7 +430,7 @@ void FeedsModel::loadActivatedServiceAccounts() { foreach (ServiceEntryPoint *entry_point, qApp->feedServices()) { // Load all stored root nodes from the entry point and add those to the model. - QList roots = entry_point->initializeSubtree(); + QList roots = entry_point->initializeSubtree(this); foreach (ServiceRoot *root, roots) { m_rootItem->appendChild(root); @@ -551,8 +446,8 @@ QList FeedsModel::feedsForIndex(const QModelIndex &index) { Feed *FeedsModel::feedForIndex(const QModelIndex &index) { RootItem *item = itemForIndex(index); - if (item->kind() == RootItem::Feeed) { - return static_cast(item); + if (item->kind() == RootItemKind::Feed) { + return item->toFeed(); } else { return NULL; @@ -579,7 +474,7 @@ QList FeedsModel::feedsForIndexes(const QModelIndexList &indexes) { return feeds; } -bool FeedsModel::markFeedsRead(const QList &feeds, int read) { +bool FeedsModel::markFeedsRead(const QList &feeds, int read) { QSqlDatabase db_handle = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings); if (!db_handle.transaction()) { @@ -660,36 +555,6 @@ bool FeedsModel::markFeedsDeleted(const QList &feeds, int deleted, bool r } } -QHash FeedsModel::allCategories() { - return categoriesForItem(m_rootItem); -} - -QHash FeedsModel::categoriesForItem(RootItem *root) { - QHash categories; - QList parents; - - parents.append(root->childItems()); - - while (!parents.isEmpty()) { - RootItem *item = parents.takeFirst(); - - if (item->kind() == RootItem::Cattegory) { - // This item is category, add it to the output list and - // scan its children. - int category_id = item->id(); - StandardCategory *category = item->toCategory(); - - if (!categories.contains(category_id)) { - categories.insert(category_id, category); - } - - parents.append(category->childItems()); - } - } - - return categories; -} - QList FeedsModel::allFeeds() { return feedsForItem(m_rootItem); } @@ -699,8 +564,10 @@ QList FeedsModel::feedsForItem(RootItem *root) { QList feeds; foreach (RootItem *child, children) { - if (child->kind() == RootItem::Feeed) { - feeds.append(child->toFeed()); + Feed *converted = dynamic_cast(child); + + if (converted != NULL) { + feeds.append(converted); } } diff --git a/src/core/feedsmodel.h b/src/core/feedsmodel.h index e8854e403..4470ccc0d 100755 --- a/src/core/feedsmodel.h +++ b/src/core/feedsmodel.h @@ -26,9 +26,9 @@ #include +class Category; class StandardCategory; class Feed; -class StandardRecycleBin; class FeedsImportExportModel; class QTimer; @@ -64,11 +64,8 @@ class FeedsModel : public QAbstractItemModel { // Removes item with given index. bool removeItem(const QModelIndex &index); - // Standard category manipulators. - bool addCategory(StandardCategory *category, RootItem *parent); - - // Standard feed manipulators. - bool addFeed(StandardFeed *feed, RootItem *parent); + // Assigns item to the new parent. + void assignNodeToNewParent(RootItem *item, RootItem *parent); // Checks if new parent node is different from one used by original node. // If it is, then it reassigns original_node to new parent. @@ -86,14 +83,6 @@ class FeedsModel : public QAbstractItemModel { // in "newspaper" mode. QList messagesForFeeds(const QList &feeds); - // Returns all categories, each pair - // consists of ID of parent item and pointer to category. - QHash allCategories(); - - // Returns categories from the subtree with given root node, each pair - // consists of ID of parent item and pointer to category. - QHash categoriesForItem(RootItem *root); - // Returns list of all feeds contained in the model. QList allFeeds(); @@ -113,7 +102,7 @@ class FeedsModel : public QAbstractItemModel { // Returns pointer to category if it lies on given index // or NULL if no category lies on given index. - StandardCategory *categoryForIndex(const QModelIndex &index) const; + Category *categoryForIndex(const QModelIndex &index) const; // Returns feed/category which lies at the specified index or // root item if index is invalid. @@ -130,10 +119,6 @@ class FeedsModel : public QAbstractItemModel { return m_rootItem; } - // Takes structure residing under given root item and adds feeds/categories from - // it to active structure. - bool mergeModel(FeedsImportExportModel *model, QString &output_message); - // Resets global auto-update intervals according to settings // and starts/stop the timer as needed. void updateAutoUpdateStatus(); diff --git a/src/core/feedsproxymodel.cpp b/src/core/feedsproxymodel.cpp index 9c1b54f6c..d2b6fbd9f 100755 --- a/src/core/feedsproxymodel.cpp +++ b/src/core/feedsproxymodel.cpp @@ -155,15 +155,15 @@ bool FeedsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right return QString::localeAwareCompare(left_item->title(), right_item->title()) < 0; } } - else if (left_item->kind() == RootItem::Bin) { + else if (left_item->kind() == RootItemKind::Bin) { // Left item is recycle bin. Make sure it is "biggest" item if we have selected ascending order. return sortOrder() == Qt::DescendingOrder; } - else if (right_item->kind() == RootItem::Bin) { + else if (right_item->kind() == RootItemKind::Bin) { // Right item is recycle bin. Make sure it is "smallest" item if we have selected descending order. return sortOrder() == Qt::AscendingOrder; } - else if (left_item->kind() == RootItem::Feeed) { + else if (left_item->kind() == RootItemKind::Feed) { // Left item is feed, right item is category. return false; } @@ -193,7 +193,7 @@ bool FeedsProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source RootItem *item = m_sourceModel->itemForIndex(idx); - if (item->kind() == RootItem::Bin) { + if (item->kind() == RootItemKind::Bin) { // Recycle bin is always displayed. return true; } diff --git a/src/core/feedsselection.cpp b/src/core/feedsselection.cpp index e01624d21..ba563eb95 100755 --- a/src/core/feedsselection.cpp +++ b/src/core/feedsselection.cpp @@ -39,11 +39,11 @@ FeedsSelection::SelectionMode FeedsSelection::mode() { } switch (m_selectedItem->kind()) { - case RootItem::Bin: + case RootItemKind::Bin: return FeedsSelection::MessagesFromRecycleBin; - case RootItem::Cattegory: - case RootItem::Feeed: + case RootItemKind::Category: + case RootItemKind::Feed: return FeedsSelection::MessagesFromFeeds; default: @@ -57,12 +57,12 @@ RootItem *FeedsSelection::selectedItem() const { QString FeedsSelection::generateListOfIds() { if (m_selectedItem != NULL && - (m_selectedItem->kind() == RootItem::Feeed || m_selectedItem->kind() == RootItem::Cattegory)) { + (m_selectedItem->kind() == RootItemKind::Feed || m_selectedItem->kind() == RootItemKind::Category)) { QList children = m_selectedItem->getRecursiveChildren(); QStringList stringy_ids; foreach (RootItem *child, children) { - if (child->kind() == RootItem::Feeed) { + if (child->kind() == RootItemKind::Feed) { stringy_ids.append(QString::number(child->id())); } } diff --git a/src/core/rootitem.cpp b/src/core/rootitem.cpp index 79bac83e7..62f7cf587 100755 --- a/src/core/rootitem.cpp +++ b/src/core/rootitem.cpp @@ -25,7 +25,7 @@ RootItem::RootItem(RootItem *parent_item) - : m_kind(RootItem::Root), + : m_kind(RootItemKind::Root), m_id(NO_PARENT_CATEGORY), m_title(QString()), m_description(QString()), @@ -77,8 +77,9 @@ int RootItem::countOfAllMessages() const { QList RootItem::getRecursiveChildren() { QList children; - if (kind() == RootItem::Feeed) { - // Root itself is a FEED. + if (childCount() == 0) { + // Root itself has no children, it is either feed or + // empty category? children.append(this); } else { @@ -89,14 +90,14 @@ QList RootItem::getRecursiveChildren() { // Iterate all nested categories. while (!traversable_items.isEmpty()) { - RootItem *active_category = traversable_items.takeFirst(); + RootItem *active_item = traversable_items.takeFirst(); - foreach (RootItem *child, active_category->childItems()) { - if (child->kind() == RootItem::Feeed) { - // This child is feed. + foreach (RootItem *child, active_item->childItems()) { + if (child->childCount() == 0) { + // This child is feed or empty category. children.append(child); } - else if (child->kind() == RootItem::Cattegory) { + else { // This child is category, add its child feeds too. traversable_items.append(child); } @@ -111,25 +112,12 @@ bool RootItem::removeChild(RootItem *child) { return m_childItems.removeOne(child); } -StandardCategory *RootItem::toCategory() { - return static_cast(this); +Category *RootItem::toCategory() { + return static_cast(this); } -StandardFeed *RootItem::toFeed() { - return static_cast(this); -} - -RootItem *RootItem::child(RootItem::Kind kind_of_child, const QString &identifier) { - foreach (RootItem *child, childItems()) { - if (child->kind() == kind_of_child) { - if ((kind_of_child == Cattegory && child->title() == identifier) || - (kind_of_child == Feeed && child->toFeed()->url() == identifier)) { - return child; - } - } - } - - return NULL; +Feed *RootItem::toFeed() { + return static_cast(this); } int RootItem::countOfUnreadMessages() const { diff --git a/src/core/rootitem.h b/src/core/rootitem.h index 6e8fca168..812528ed9 100755 --- a/src/core/rootitem.h +++ b/src/core/rootitem.h @@ -22,23 +22,24 @@ #include #include -class StandardRecycleBin; -class StandardCategory; -class StandardFeed; +class Category; +class Feed; + +namespace RootItemKind { + // Describes the kind of the item. + enum Kind { + Root = 1001, + Bin = 1002, + Feed = 1003, + Category = 1004 + }; +} // Represents ROOT item of FeedsModel. // NOTE: This class is derived to add functionality for // all other non-root items of FeedsModel. class RootItem { public: - // Describes the kind of the item. - enum Kind { - Root = 1001, - Bin = 1002, - Feeed = 1003, - Cattegory = 1004 - }; - // Constructors and destructors. explicit RootItem(RootItem *parent_item = NULL); virtual ~RootItem(); @@ -56,8 +57,6 @@ class RootItem { return m_childItems.value(row); } - virtual RootItem *child(RootItem::Kind kind_of_child, const QString &identifier); - inline virtual int childCount() const { return m_childItems.size(); } @@ -110,7 +109,7 @@ class RootItem { RootItem *this_item = this; - while (this_item->kind() != RootItem::Root) { + while (this_item->kind() != RootItemKind::Root) { if (root->childItems().contains(this_item)) { return true; } @@ -122,6 +121,7 @@ class RootItem { return false; } + // Is "this" item parent if given child? bool isParentOf(RootItem *child) { if (child == NULL) { return false; @@ -144,7 +144,7 @@ class RootItem { bool removeChild(int index); bool removeChild(RootItem *child); - inline Kind kind() const { + inline RootItemKind::Kind kind() const { return m_kind; } @@ -192,8 +192,8 @@ class RootItem { } // Converters - StandardCategory *toCategory(); - StandardFeed *toFeed(); + Category *toCategory(); + Feed *toFeed(); // Compares two model items. static bool isEqual(RootItem *lhs, RootItem *rhs); @@ -202,7 +202,7 @@ class RootItem { protected: void setupFonts(); - Kind m_kind; + RootItemKind::Kind m_kind; int m_id; QString m_title; QString m_description; diff --git a/src/gui/dialogs/formmain.cpp b/src/gui/dialogs/formmain.cpp index 1c06b20d1..4baef3183 100755 --- a/src/gui/dialogs/formmain.cpp +++ b/src/gui/dialogs/formmain.cpp @@ -401,17 +401,25 @@ void FormMain::loadWebBrowserMenu(int index) { } void FormMain::exportFeeds() { + // TODO: dodelat globalni pristup ke globalnimu standard service rootu, + // ten předat + /* QPointer form = new FormStandardImportExport(this); form.data()->setMode(FeedsImportExportModel::Export); form.data()->exec(); delete form.data(); + */ } void FormMain::importFeeds() { + // TODO: dodelat globalni pristup ke globalnimu standard service rootu, + // ten předat + /* QPointer form = new FormStandardImportExport(this); form.data()->setMode(FeedsImportExportModel::Import); form.data()->exec(); delete form.data(); + */ } void FormMain::backupDatabaseSettings() { diff --git a/src/gui/feedmessageviewer.cpp b/src/gui/feedmessageviewer.cpp index 94ec10de0..df6fc5af8 100755 --- a/src/gui/feedmessageviewer.cpp +++ b/src/gui/feedmessageviewer.cpp @@ -209,9 +209,12 @@ void FeedMessageViewer::loadInitialFeeds() { model.importAsOPML20(IOFactory::readTextFile(file_to_load)); model.checkAllItems(); + // TODO: dodělat, předpokládá nějaký rozumný přístup k standardnímu root servicu. + /* if (m_feedsView->sourceModel()->mergeModel(&model, output_msg)) { m_feedsView->expandAll(); } + */ } catch (ApplicationException &ex) { MessageBox::show(this, QMessageBox::Critical, tr("Error when loading initial feeds"), ex.message()); diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index fe501e073..d780bcf61 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -96,7 +96,7 @@ RootItem *FeedsView::selectedItem() const { return selected_item == m_sourceModel->rootItem() ? NULL : selected_item; } -StandardCategory *FeedsView::selectedCategory() const { +Category *FeedsView::selectedCategory() const { QModelIndex current_mapped = m_proxyModel->mapToSource(currentIndex()); return m_sourceModel->categoryForIndex(current_mapped); } @@ -109,22 +109,27 @@ Feed *FeedsView::selectedFeed() const { void FeedsView::saveExpandedStates() { Settings *settings = qApp->settings(); + // TODO: doědlat + // Iterate all categories and save their expand statuses. - foreach (StandardCategory *category, sourceModel()->allCategories().values()) { + + /*foreach (Category *category, sourceModel()->allCategories().values()) { settings->setValue(GROUP(Categories), QString::number(category->id()), isExpanded(model()->mapFromSource(sourceModel()->indexForItem(category)))); - } + }*/ } void FeedsView::loadExpandedStates() { Settings *settings = qApp->settings(); + // TODO: doědlat + // Iterate all categories and save their expand statuses. - foreach (StandardCategory *category, sourceModel()->allCategories().values()) { + /*foreach (Category *category, sourceModel()->allCategories().values()) { setExpanded(model()->mapFromSource(sourceModel()->indexForItem(category)), settings->value(GROUP(Categories), QString::number(category->id()), true).toBool()); - } + }*/ } void FeedsView::invalidateReadFeedsFilter(bool set_new_value, bool show_unread_only) { @@ -185,48 +190,6 @@ void FeedsView::clearAllFeeds() { setAllFeedsClearStatus(1); } -void FeedsView::addNewCategory() { - if (!qApp->feedUpdateLock()->tryLock()) { - // Lock was not obtained because - // it is used probably by feed updater or application - // is quitting. - qApp->showGuiMessage(tr("Cannot add standard category"), - tr("You cannot add new standard category now because another critical operation is ongoing."), - QSystemTrayIcon::Warning, qApp->mainForm(), true); - return; - } - - QPointer form_pointer = new FormStandardCategoryDetails(m_sourceModel, this); - - form_pointer.data()->exec(NULL, selectedItem()); - - delete form_pointer.data(); - - // Changes are done, unlock the update master lock. - qApp->feedUpdateLock()->unlock(); -} - -void FeedsView::addNewFeed() { - if (!qApp->feedUpdateLock()->tryLock()) { - // Lock was not obtained because - // it is used probably by feed updater or application - // is quitting. - qApp->showGuiMessage(tr("Cannot add standard feed"), - tr("You cannot add new standard feed now because another critical operation is ongoing."), - QSystemTrayIcon::Warning, qApp->mainForm(), true); - return; - } - - QPointer form_pointer = new FormStandardFeedDetails(m_sourceModel, this); - - form_pointer.data()->exec(NULL, selectedItem()); - - delete form_pointer.data(); - - // Changes are done, unlock the update master lock. - qApp->feedUpdateLock()->unlock(); -} - void FeedsView::receiveMessageCountsChange(FeedsSelection::SelectionMode mode, bool total_msg_count_changed, bool any_msg_restored) { @@ -594,7 +557,7 @@ void FeedsView::contextMenuEvent(QContextMenuEvent *event) { QModelIndex mapped_index = model()->mapToSource(clicked_index); RootItem *clicked_item = sourceModel()->itemForIndex(mapped_index); - if (clicked_item->kind() == RootItem::Cattegory) { + if (clicked_item->kind() == RootItemKind::Category) { // Display context menu for categories. if (m_contextMenuCategories == NULL) { // Context menu is not initialized, initialize. @@ -603,7 +566,7 @@ void FeedsView::contextMenuEvent(QContextMenuEvent *event) { m_contextMenuCategories->exec(event->globalPos()); } - else if (clicked_item->kind() == RootItem::Feeed) { + else if (clicked_item->kind() == RootItemKind::Feed) { // Display context menu for feeds. if (m_contextMenuFeeds == NULL) { // Context menu is not initialized, initialize. diff --git a/src/gui/feedsview.h b/src/gui/feedsview.h index d96a61932..c1725f2c6 100755 --- a/src/gui/feedsview.h +++ b/src/gui/feedsview.h @@ -29,6 +29,7 @@ class FeedsProxyModel; class Feed; +class Category; class StandardCategory; class QTimer; @@ -59,7 +60,7 @@ class FeedsView : public QTreeView { // Returns pointers to selected feed/category if they are really // selected. RootItem *selectedItem() const; - StandardCategory *selectedCategory() const; + Category *selectedCategory() const; Feed *selectedFeed() const; // Saves/loads expand states of all nodes (feeds/categories) of the list to/from settings. @@ -101,12 +102,6 @@ class FeedsView : public QTreeView { void editSelectedItem(); void deleteSelectedItem(); - // Standard category manipulators. - void addNewCategory(); - - // Standard feed manipulators. - void addNewFeed(); - // Is called when counts of messages are changed externally, // typically from message view. void receiveMessageCountsChange(FeedsSelection::SelectionMode mode, bool total_msg_count_changed, bool any_msg_restored); diff --git a/src/miscellaneous/application.h b/src/miscellaneous/application.h index d23a7a847..c9aa87cb5 100755 --- a/src/miscellaneous/application.h +++ b/src/miscellaneous/application.h @@ -55,6 +55,8 @@ class Application : public QtSingleApplication { explicit Application(const QString &id, int &argc, char **argv); virtual ~Application(); + // List of all installed "feed service plugins", including obligatory + // "standard" service entry point. QList feedServices(); QList userActions(); diff --git a/src/miscellaneous/settings.h b/src/miscellaneous/settings.h index 5c9d4ac7a..c254e7cee 100755 --- a/src/miscellaneous/settings.h +++ b/src/miscellaneous/settings.h @@ -360,6 +360,7 @@ class Settings : public QSettings { // Creates settings file in correct location. static Settings *setupSettings(QObject *parent); + // Returns properties of the actual application-wide settings. static SettingsProperties determineProperties(); private: diff --git a/src/network-web/webbrowser.cpp b/src/network-web/webbrowser.cpp index eda30878a..c1da07cae 100755 --- a/src/network-web/webbrowser.cpp +++ b/src/network-web/webbrowser.cpp @@ -214,7 +214,9 @@ void WebBrowser::onIconChanged() { void WebBrowser::addFeedFromWebsite(const QString &feed_link) { qApp->clipboard()->setText(feed_link); - qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->addNewFeed(); + + // TODO: dodělat + //qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->addNewFeed(); } void WebBrowser::onTitleChanged(const QString &new_title) { diff --git a/src/services/abstract/category.cpp b/src/services/abstract/category.cpp new file mode 100755 index 000000000..52707e0ac --- /dev/null +++ b/src/services/abstract/category.cpp @@ -0,0 +1,9 @@ +#include "services/abstract/category.h" + + +Category::Category(RootItem *parent) : RootItem(parent) { +} + +Category::~Category() { +} + diff --git a/src/services/abstract/category.h b/src/services/abstract/category.h new file mode 100755 index 000000000..aaf55caef --- /dev/null +++ b/src/services/abstract/category.h @@ -0,0 +1,13 @@ +#ifndef CATEGORY_H +#define CATEGORY_H + +#include "core/rootitem.h" + + +class Category : public RootItem { + public: + explicit Category(RootItem *parent = NULL); + virtual ~Category(); +}; + +#endif // CATEGORY_H diff --git a/src/services/abstract/feed.cpp b/src/services/abstract/feed.cpp index b3d8c61e8..c7a030a5f 100755 --- a/src/services/abstract/feed.cpp +++ b/src/services/abstract/feed.cpp @@ -34,3 +34,7 @@ int Feed::childCount() const { // Because feed has no children. return 0; } + +void Feed::appendChild(RootItem *child) { + Q_UNUSED(child) +} diff --git a/src/services/abstract/feed.h b/src/services/abstract/feed.h index df2b28776..62ba9d2b2 100755 --- a/src/services/abstract/feed.h +++ b/src/services/abstract/feed.h @@ -37,7 +37,9 @@ class Feed : public RootItem { enum Status { Normal = 0, NewMessages = 1, - NetworkError = 2 + NetworkError = 2, + ParsingError = 3, + OtherError = 4 }; // Constructors. @@ -47,6 +49,9 @@ class Feed : public RootItem { // Returns 0, feeds have no children. int childCount() const; + // Appending of childs to feed is not allowed. + void appendChild(RootItem *child); + // Performs synchronous update and returns number of newly updated messages. virtual int update() = 0; diff --git a/src/services/abstract/serviceentrypoint.h b/src/services/abstract/serviceentrypoint.h index f6a257989..ecfc75334 100755 --- a/src/services/abstract/serviceentrypoint.h +++ b/src/services/abstract/serviceentrypoint.h @@ -24,6 +24,7 @@ class ServiceRoot; +class FeedsModel; // TOP LEVEL class which provides basic information about the "service" class ServiceEntryPoint { @@ -36,7 +37,7 @@ class ServiceEntryPoint { // point from persistent DB. // Returns list of root nodes which will be afterwards added // to the global feed model. - virtual QList initializeSubtree() = 0; + virtual QList initializeSubtree(FeedsModel *main_model) = 0; // Must this service account be activated by default? // NOTE: This is true particularly for "standard" service diff --git a/src/services/abstract/serviceroot.cpp b/src/services/abstract/serviceroot.cpp index 109f00ead..5a455e306 100755 --- a/src/services/abstract/serviceroot.cpp +++ b/src/services/abstract/serviceroot.cpp @@ -17,10 +17,11 @@ #include "services/abstract/serviceroot.h" +#include "core/feedsmodel.h" -ServiceRoot::ServiceRoot(RootItem *parent) : RootItem(parent) { + +ServiceRoot::ServiceRoot(FeedsModel *feeds_model, RootItem *parent) : RootItem(parent), m_feedsModel(feeds_model) { } ServiceRoot::~ServiceRoot() { } - diff --git a/src/services/abstract/serviceroot.h b/src/services/abstract/serviceroot.h index 1355f1fb7..94e6b472e 100755 --- a/src/services/abstract/serviceroot.h +++ b/src/services/abstract/serviceroot.h @@ -21,13 +21,22 @@ #include "core/rootitem.h" +class FeedsModel; + // THIS IS the root node of the service. // NOTE: The root usually contains some core functionality of the // service like service account username/password etc. class ServiceRoot : public RootItem { public: - explicit ServiceRoot(RootItem *parent = NULL); + explicit ServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL); virtual ~ServiceRoot(); + + inline FeedsModel *feedsModel() const { + return m_feedsModel; + } + + protected: + FeedsModel *m_feedsModel; }; #endif // SERVICEROOT_H diff --git a/src/services/standard/gui/formstandardcategorydetails.cpp b/src/services/standard/gui/formstandardcategorydetails.cpp index 34bba3718..b3fd72720 100755 --- a/src/services/standard/gui/formstandardcategorydetails.cpp +++ b/src/services/standard/gui/formstandardcategorydetails.cpp @@ -20,13 +20,14 @@ #include "definitions/definitions.h" #include "core/rootitem.h" #include "core/feedsmodel.h" -#include "services/standard/standardcategory.h" #include "miscellaneous/iconfactory.h" #include "gui/feedsview.h" #include "gui/baselineedit.h" #include "gui/messagebox.h" #include "gui/systemtrayicon.h" #include "gui/dialogs/formmain.h" +#include "services/standard/standardcategory.h" +#include "services/standard/standardserviceroot.h" #include #include @@ -38,9 +39,8 @@ #include -FormStandardCategoryDetails::FormStandardCategoryDetails(FeedsModel *model, QWidget *parent) : QDialog(parent), - m_editableCategory(NULL), - m_feedsModel(model) { +FormStandardCategoryDetails::FormStandardCategoryDetails(StandardServiceRoot *service_root, QWidget *parent) + : QDialog(parent), m_editableCategory(NULL), m_serviceRoot(service_root) { initialize(); createConnections(); @@ -76,7 +76,7 @@ void FormStandardCategoryDetails::setEditableCategory(StandardCategory *editable int FormStandardCategoryDetails::exec(StandardCategory *input_category, RootItem *parent_to_select) { // Load categories. - loadCategories(m_feedsModel->allCategories().values(), m_feedsModel->rootItem(), input_category); + loadCategories(m_serviceRoot->allCategories().values(), m_serviceRoot, input_category); if (input_category == NULL) { // User is adding new category. @@ -88,10 +88,10 @@ int FormStandardCategoryDetails::exec(StandardCategory *input_category, RootItem // Load parent from suggested item. if (parent_to_select != NULL) { - if (parent_to_select->kind() == RootItem::Cattegory) { + if (parent_to_select->kind() == RootItemKind::Category) { m_ui->m_cmbParentCategory->setCurrentIndex(m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select))); } - else if (parent_to_select->kind() == RootItem::Feeed) { + else if (parent_to_select->kind() == RootItemKind::Feed) { int target_item = m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select->parent())); if (target_item >= 0) { @@ -122,10 +122,12 @@ void FormStandardCategoryDetails::apply() { if (m_editableCategory == NULL) { // Add the category. - if (m_feedsModel->addCategory(new_category, parent)) { + if (new_category->addItself(parent)) { + m_serviceRoot->feedsModel()->assignNodeToNewParent(new_category, parent); accept(); } else { + delete new_category; qApp->showGuiMessage(tr("Cannot add category"), tr("Category was not added due to error."), QSystemTrayIcon::Critical, @@ -136,7 +138,7 @@ void FormStandardCategoryDetails::apply() { bool edited = m_editableCategory->editItself(new_category); if (edited) { - m_feedsModel->reassignNodeToNewParent(m_editableCategory, new_category->parent()); + m_serviceRoot->feedsModel()->reassignNodeToNewParent(m_editableCategory, new_category->parent()); // Remove new temporary feed data holder object. delete new_category; @@ -245,8 +247,8 @@ void FormStandardCategoryDetails::initialize() { } void FormStandardCategoryDetails::loadCategories(const QList categories, - RootItem *root_item, - StandardCategory *input_category) { + RootItem *root_item, + StandardCategory *input_category) { m_ui->m_cmbParentCategory->addItem(root_item->icon(), root_item->title(), QVariant::fromValue((void*) root_item)); diff --git a/src/services/standard/gui/formstandardcategorydetails.h b/src/services/standard/gui/formstandardcategorydetails.h index 51c9f60c4..3717b3251 100755 --- a/src/services/standard/gui/formstandardcategorydetails.h +++ b/src/services/standard/gui/formstandardcategorydetails.h @@ -28,7 +28,7 @@ namespace Ui { } class StandardCategory; -class StandardCategory; +class StandardServiceRoot; class FeedsModel; class RootItem; class QMenu; @@ -39,7 +39,7 @@ class FormStandardCategoryDetails : public QDialog { public: // Constructors and destructors. - explicit FormStandardCategoryDetails(FeedsModel *model, QWidget *parent = 0); + explicit FormStandardCategoryDetails(StandardServiceRoot *service_root, QWidget *parent = 0); virtual ~FormStandardCategoryDetails(); public slots: @@ -77,7 +77,7 @@ class FormStandardCategoryDetails : public QDialog { private: Ui::FormStandardCategoryDetails *m_ui; StandardCategory *m_editableCategory; - FeedsModel *m_feedsModel; + StandardServiceRoot *m_serviceRoot; QMenu *m_iconMenu; QAction *m_actionLoadIconFromFile; diff --git a/src/services/standard/gui/formstandardfeeddetails.cpp b/src/services/standard/gui/formstandardfeeddetails.cpp index adf3cf666..7fa6d6c8c 100755 --- a/src/services/standard/gui/formstandardfeeddetails.cpp +++ b/src/services/standard/gui/formstandardfeeddetails.cpp @@ -20,6 +20,7 @@ #include "definitions/definitions.h" #include "core/feedsmodel.h" #include "core/rootitem.h" +#include "services/standard/standardserviceroot.h" #include "services/standard/standardcategory.h" #include "services/standard/standardfeed.h" #include "miscellaneous/textfactory.h" @@ -39,10 +40,10 @@ #include -FormStandardFeedDetails::FormStandardFeedDetails(FeedsModel *model, QWidget *parent) +FormStandardFeedDetails::FormStandardFeedDetails(StandardServiceRoot *service_root, QWidget *parent) : QDialog(parent), m_editableFeed(NULL), - m_feedsModel(model) { + m_serviceRoot(service_root) { initialize(); createConnections(); @@ -60,7 +61,7 @@ FormStandardFeedDetails::~FormStandardFeedDetails() { int FormStandardFeedDetails::exec(StandardFeed *input_feed, RootItem *parent_to_select) { // Load categories. - loadCategories(m_feedsModel->allCategories().values(), m_feedsModel->rootItem()); + loadCategories(m_serviceRoot->allCategories().values(), m_serviceRoot); if (input_feed == NULL) { // User is adding new category. @@ -77,10 +78,10 @@ int FormStandardFeedDetails::exec(StandardFeed *input_feed, RootItem *parent_to_ } if (parent_to_select != NULL) { - if (parent_to_select->kind() == RootItem::Cattegory) { + if (parent_to_select->kind() == RootItemKind::Category) { m_ui->m_cmbParentCategory->setCurrentIndex(m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select))); } - else if (parent_to_select->kind() == RootItem::Feeed) { + else if (parent_to_select->kind() == RootItemKind::Feed) { int target_item = m_ui->m_cmbParentCategory->findData(QVariant::fromValue((void*) parent_to_select->parent())); if (target_item >= 0) { @@ -240,10 +241,12 @@ void FormStandardFeedDetails::apply() { if (m_editableFeed == NULL) { // Add the feed. - if (m_feedsModel->addFeed(new_feed, parent)) { + if (new_feed->addItself(parent)) { + m_serviceRoot->feedsModel()->assignNodeToNewParent(new_feed, parent); accept(); } else { + delete new_feed; qApp->showGuiMessage(tr("Cannot add feed"), tr("Feed was not added due to error."), QSystemTrayIcon::Critical, this, true); @@ -254,7 +257,7 @@ void FormStandardFeedDetails::apply() { bool edited = m_editableFeed->editItself(new_feed); if (edited) { - m_feedsModel->reassignNodeToNewParent(m_editableFeed, new_feed->parent()); + m_serviceRoot->feedsModel()->reassignNodeToNewParent(m_editableFeed, new_feed->parent()); // Remove new temporary feed data holder object. delete new_feed; diff --git a/src/services/standard/gui/formstandardfeeddetails.h b/src/services/standard/gui/formstandardfeeddetails.h index 6b3ed95a7..d3651f969 100755 --- a/src/services/standard/gui/formstandardfeeddetails.h +++ b/src/services/standard/gui/formstandardfeeddetails.h @@ -27,7 +27,7 @@ namespace Ui { class FormStandardFeedDetails; } -class FeedsModel; +class StandardServiceRoot; class StandardFeed; class StandardCategory; class RootItem; @@ -37,7 +37,7 @@ class FormStandardFeedDetails : public QDialog { public: // Constructors and destructors. - explicit FormStandardFeedDetails(FeedsModel *model, QWidget *parent = 0); + explicit FormStandardFeedDetails(StandardServiceRoot *service_root, QWidget *parent = 0); virtual ~FormStandardFeedDetails(); public slots: @@ -84,7 +84,7 @@ class FormStandardFeedDetails : public QDialog { private: Ui::FormStandardFeedDetails *m_ui; StandardFeed *m_editableFeed; - FeedsModel *m_feedsModel; + StandardServiceRoot *m_serviceRoot; QMenu *m_iconMenu; QAction *m_actionLoadIconFromFile; diff --git a/src/services/standard/gui/formstandardimportexport.cpp b/src/services/standard/gui/formstandardimportexport.cpp index e0c4188b3..d8e4cf418 100755 --- a/src/services/standard/gui/formstandardimportexport.cpp +++ b/src/services/standard/gui/formstandardimportexport.cpp @@ -18,6 +18,7 @@ #include "services/standard/gui/formstandardimportexport.h" #include "services/standard/standardfeedsimportexportmodel.h" +#include "services/standard/standardserviceroot.h" #include "core/feedsmodel.h" #include "miscellaneous/application.h" #include "gui/feedmessageviewer.h" @@ -28,8 +29,8 @@ #include -FormStandardImportExport::FormStandardImportExport(QWidget *parent) - : QDialog(parent), m_ui(new Ui::FormStandardImportExport) { +FormStandardImportExport::FormStandardImportExport(StandardServiceRoot *service_root, QWidget *parent) + : QDialog(parent), m_ui(new Ui::FormStandardImportExport), m_serviceRoot(service_root) { m_ui->setupUi(this); m_model = new FeedsImportExportModel(m_ui->m_treeFeeds); @@ -54,7 +55,7 @@ void FormStandardImportExport::setMode(const FeedsImportExportModel::Mode &mode) switch (mode) { case FeedsImportExportModel::Export: { - m_model->setRootItem(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->rootItem()); + m_model->setRootItem(m_serviceRoot); m_model->checkAllItems(); m_ui->m_treeFeeds->setModel(m_model); m_ui->m_treeFeeds->expandAll(); @@ -117,7 +118,6 @@ void FormStandardImportExport::selectExportFile() { selected_file += QL1S(".opml"); } } - // NOTE: Add other types here. m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(selected_file), tr("File is selected.")); } @@ -141,7 +141,6 @@ void FormStandardImportExport::selectImportFile() { if (selected_filter == filter_opml20) { m_conversionType = OPML20; } - // NOTE: Add other types here. m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::Ok, QDir::toNativeSeparators(selected_file), tr("File is selected.")); parseImportFile(selected_file); @@ -241,7 +240,8 @@ void FormStandardImportExport::exportFeeds() { void FormStandardImportExport::importFeeds() { QString output_message; - if (qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->mergeModel(m_model, output_message)) { + if (m_serviceRoot->mergeImportExportModel(m_model, output_message)) { + // TODO: Hate this global access, what about signal? qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->expandAll(); m_ui->m_lblResult->setStatus(WidgetWithStatus::Ok, output_message, output_message); } diff --git a/src/services/standard/gui/formstandardimportexport.h b/src/services/standard/gui/formstandardimportexport.h index fc1fa85dd..4b36f1ebc 100755 --- a/src/services/standard/gui/formstandardimportexport.h +++ b/src/services/standard/gui/formstandardimportexport.h @@ -23,11 +23,12 @@ #include "ui_formstandardimportexport.h" #include "services/standard/standardfeedsimportexportmodel.h" - namespace Ui { class FormStandardImportExport; } +class StandardServiceRoot; + class FormStandardImportExport : public QDialog { Q_OBJECT @@ -37,7 +38,7 @@ class FormStandardImportExport : public QDialog { }; // Constructors. - explicit FormStandardImportExport(QWidget *parent = 0); + explicit FormStandardImportExport(StandardServiceRoot *service_root, QWidget *parent = 0); virtual ~FormStandardImportExport(); void setMode(const FeedsImportExportModel::Mode &mode); @@ -57,6 +58,7 @@ class FormStandardImportExport : public QDialog { Ui::FormStandardImportExport *m_ui; ConversionType m_conversionType; FeedsImportExportModel *m_model; + StandardServiceRoot *m_serviceRoot; }; #endif // FORMEXPORT_H diff --git a/src/services/standard/standardcategory.cpp b/src/services/standard/standardcategory.cpp index 41e46b865..7d822c215 100755 --- a/src/services/standard/standardcategory.cpp +++ b/src/services/standard/standardcategory.cpp @@ -34,12 +34,12 @@ #include -StandardCategory::StandardCategory(RootItem *parent_item) : RootItem(parent_item) { +StandardCategory::StandardCategory(RootItem *parent_item) : Category(parent_item) { init(); } StandardCategory::StandardCategory(const StandardCategory &other) - : RootItem(NULL) { + : Category(NULL) { m_kind = other.kind(); m_id = other.id(); m_title = other.title(); @@ -55,7 +55,7 @@ StandardCategory::~StandardCategory() { } void StandardCategory::init() { - m_kind = RootItem::Cattegory; + m_kind = RootItemKind::Category; } QVariant StandardCategory::data(int column, int role) const { @@ -127,13 +127,16 @@ QVariant StandardCategory::data(int column, int role) const { } void StandardCategory::editViaDialog() { - // TODO: fix passing of the model + // TODO: předávat service root. +/* QPointer form_pointer = new FormStandardCategoryDetails(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel(), qApp->mainForm()); + form_pointer.data()->exec(this, NULL); delete form_pointer.data(); + */ } bool StandardCategory::removeItself() { @@ -230,7 +233,7 @@ bool StandardCategory::editItself(StandardCategory *new_category_data) { return true; } -StandardCategory::StandardCategory(const QSqlRecord &record) : RootItem(NULL) { +StandardCategory::StandardCategory(const QSqlRecord &record) : Category(NULL) { init(); setId(record.value(CAT_DB_ID_INDEX).toInt()); diff --git a/src/services/standard/standardcategory.h b/src/services/standard/standardcategory.h index 9affc61b6..b50f2bfaf 100755 --- a/src/services/standard/standardcategory.h +++ b/src/services/standard/standardcategory.h @@ -18,7 +18,7 @@ #ifndef FEEDSMODELCATEGORY_H #define FEEDSMODELCATEGORY_H -#include "core/rootitem.h" +#include "services/abstract/category.h" #include #include @@ -29,8 +29,8 @@ class FeedsModel; // Base class for all categories contained in FeedsModel. // NOTE: This class should be derived to create PARTICULAR category types. // NOTE: This class should not be instantiated directly. -class StandardCategory : public RootItem { - Q_DECLARE_TR_FUNCTIONS(Category) +class StandardCategory : public Category { + Q_DECLARE_TR_FUNCTIONS(StandardCategory) public: // Constructors and destructors diff --git a/src/services/standard/standardfeed.cpp b/src/services/standard/standardfeed.cpp index 5d83d2626..6091e2f77 100755 --- a/src/services/standard/standardfeed.cpp +++ b/src/services/standard/standardfeed.cpp @@ -53,7 +53,7 @@ void StandardFeed::init() { m_unreadCount = 0; m_encoding = QString(); m_url = QString(); - m_kind = RootItem::Feeed; + m_kind = RootItemKind::Feed; } StandardFeed::StandardFeed(RootItem *parent_item) @@ -76,7 +76,7 @@ StandardFeed::StandardFeed(const StandardFeed &other) m_autoUpdateRemainingInterval = other.autoUpdateRemainingInterval(); m_encoding = other.encoding(); m_url = other.url(); - m_kind = RootItem::Feeed; + m_kind = RootItemKind::Feed; m_title = other.title(); m_id = other.id(); m_icon = other.icon(); @@ -100,11 +100,14 @@ int StandardFeed::countOfUnreadMessages() const { void StandardFeed::editViaDialog() { // TODO: fix passing of the model + + /* QPointer form_pointer = new FormStandardFeedDetails(qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel(), qApp->mainForm()); form_pointer.data()->exec(this, NULL); delete form_pointer.data(); + */ } QString StandardFeed::typeToString(StandardFeed::Type type) { @@ -716,7 +719,7 @@ QNetworkReply::NetworkError StandardFeed::networkError() const { } StandardFeed::StandardFeed(const QSqlRecord &record) : Feed(NULL) { - m_kind = RootItem::Feeed; + m_kind = RootItemKind::Feed; setTitle(record.value(FDS_DB_TITLE_INDEX).toString()); setId(record.value(FDS_DB_ID_INDEX).toInt()); diff --git a/src/services/standard/standardfeedsimportexportmodel.cpp b/src/services/standard/standardfeedsimportexportmodel.cpp index 96c01a16f..3133be8a3 100755 --- a/src/services/standard/standardfeedsimportexportmodel.cpp +++ b/src/services/standard/standardfeedsimportexportmodel.cpp @@ -99,7 +99,7 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray &result) { } switch (child_item->kind()) { - case RootItem::Cattegory: { + case RootItemKind::Category: { QDomElement outline_category = opml_document.createElement(QSL("outline")); outline_category.setAttribute(QSL("text"), child_item->title()); outline_category.setAttribute(QSL("description"), child_item->description()); @@ -110,8 +110,8 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray &result) { break; } - case RootItem::Feeed: { - StandardFeed *child_feed = child_item->toFeed(); + case RootItemKind::Feed: { + StandardFeed *child_feed = static_cast(child_item); QDomElement outline_feed = opml_document.createElement("outline"); outline_feed.setAttribute(QSL("text"), child_feed->title()); outline_feed.setAttribute(QSL("xmlUrl"), child_feed->url()); @@ -264,7 +264,7 @@ void FeedsImportExportModel::setMode(const FeedsImportExportModel::Mode &mode) { void FeedsImportExportModel::checkAllItems() { foreach (RootItem *root_child, m_rootItem->childItems()) { - if (root_child->kind() != RootItem::Bin) { + if (root_child->kind() != RootItemKind::Bin) { setData(indexForItem(root_child), Qt::Checked, Qt::CheckStateRole); } } @@ -272,7 +272,7 @@ void FeedsImportExportModel::checkAllItems() { void FeedsImportExportModel::uncheckAllItems() { foreach (RootItem *root_child, m_rootItem->childItems()) { - if (root_child->kind() != RootItem::Bin) { + if (root_child->kind() != RootItemKind::Bin) { setData(indexForItem(root_child), Qt::Unchecked, Qt::CheckStateRole); } } @@ -295,7 +295,7 @@ QModelIndex FeedsImportExportModel::index(int row, int column, const QModelIndex } QModelIndex FeedsImportExportModel::indexForItem(RootItem *item) const { - if (item == NULL || item->kind() == RootItem::Root) { + if (item == NULL || item->kind() == RootItemKind::Root) { // Root item lies on invalid index. return QModelIndex(); } @@ -324,7 +324,7 @@ QModelIndex FeedsImportExportModel::indexForItem(RootItem *item) const { for (int i = 0; i < row_count; i++) { RootItem *possible_category = active_item->child(i); - if (possible_category->kind() == RootItem::Cattegory) { + if (possible_category->kind() == RootItemKind::Category) { parents << index(i, 0, active_index); } } @@ -362,7 +362,6 @@ int FeedsImportExportModel::rowCount(const QModelIndex &parent) const { int FeedsImportExportModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) - return 1; } @@ -383,9 +382,9 @@ QVariant FeedsImportExportModel::data(const QModelIndex &index, int role) const } else if (role == Qt::DecorationRole) { switch (item->kind()) { - case RootItem::Cattegory: - case RootItem::Bin: - case RootItem::Feeed: + case RootItemKind::Category: + case RootItemKind::Bin: + case RootItemKind::Feed: return item->icon(); default: @@ -394,10 +393,10 @@ QVariant FeedsImportExportModel::data(const QModelIndex &index, int role) const } else if (role == Qt::DisplayRole) { switch (item->kind()) { - case RootItem::Cattegory: + case RootItemKind::Category: return QVariant(item->data(index.column(), role).toString() + tr(" (category)")); - case RootItem::Feeed: + case RootItemKind::Feed: return QVariant(item->data(index.column(), role).toString() + tr(" (feed)")); default: @@ -462,7 +461,7 @@ bool FeedsImportExportModel::setData(const QModelIndex &index, const QVariant &v } Qt::ItemFlags FeedsImportExportModel::flags(const QModelIndex &index) const { - if (!index.isValid() || itemForIndex(index)->kind() == RootItem::Bin) { + if (!index.isValid() || itemForIndex(index)->kind() == RootItemKind::Bin) { return Qt::NoItemFlags; } diff --git a/src/services/standard/standardfeedsimportexportmodel.h b/src/services/standard/standardfeedsimportexportmodel.h index 972ed5e3c..e5bc8c54f 100755 --- a/src/services/standard/standardfeedsimportexportmodel.h +++ b/src/services/standard/standardfeedsimportexportmodel.h @@ -73,7 +73,6 @@ class FeedsImportExportModel : public QAbstractItemModel { QHash m_checkStates; RootItem *m_rootItem; - // When it's true, then bool m_recursiveChange; Mode m_mode; }; diff --git a/src/services/standard/standarditem.cpp b/src/services/standard/standarditem.cpp new file mode 100755 index 000000000..bde2b13d8 --- /dev/null +++ b/src/services/standard/standarditem.cpp @@ -0,0 +1,18 @@ +#include "services/standard/standarditem.h" + +#include "services/standard/standardserviceroot.h" + + +StandardItem::StandardItem(StandardServiceRoot *service_root) : m_serviceRoot(service_root) { +} + +StandardItem::~StandardItem() { +} + +StandardServiceRoot *StandardItem::serviceRoot() const { + return m_serviceRoot; +} + +void StandardItem::setServiceRoot(StandardServiceRoot *service_root) { + m_serviceRoot = service_root; +} diff --git a/src/services/standard/standarditem.h b/src/services/standard/standarditem.h new file mode 100755 index 000000000..efe3210d1 --- /dev/null +++ b/src/services/standard/standarditem.h @@ -0,0 +1,19 @@ +#ifndef STANDARDITEM_H +#define STANDARDITEM_H + + +class StandardServiceRoot; + +class StandardItem { + public: + explicit StandardItem(StandardServiceRoot *service_root); + virtual ~StandardItem(); + + StandardServiceRoot *serviceRoot() const; + void setServiceRoot(StandardServiceRoot *service_root); + + protected: + StandardServiceRoot *m_serviceRoot; +}; + +#endif // STANDARDITEM_H diff --git a/src/services/standard/standardrecyclebin.cpp b/src/services/standard/standardrecyclebin.cpp index fa26177ba..ace8c3ee9 100755 --- a/src/services/standard/standardrecyclebin.cpp +++ b/src/services/standard/standardrecyclebin.cpp @@ -25,7 +25,7 @@ StandardRecycleBin::StandardRecycleBin(RootItem *parent) : RootItem(parent) { - m_kind = RootItem::Bin; + m_kind = RootItemKind::Bin; m_icon = qApp->icons()->fromTheme(QSL("folder-recycle-bin")); m_id = ID_RECYCLE_BIN; m_title = tr("Recycle bin"); diff --git a/src/services/standard/standardserviceentrypoint.cpp b/src/services/standard/standardserviceentrypoint.cpp index 01f85fda8..de70987d7 100755 --- a/src/services/standard/standardserviceentrypoint.cpp +++ b/src/services/standard/standardserviceentrypoint.cpp @@ -69,8 +69,8 @@ QIcon StandardServiceEntryPoint::icon() { return QIcon(APP_ICON_PATH); } -QList StandardServiceEntryPoint::initializeSubtree() { - StandardServiceRoot *root = new StandardServiceRoot(); +QList StandardServiceEntryPoint::initializeSubtree(FeedsModel *main_model) { + StandardServiceRoot *root = new StandardServiceRoot(main_model); QList roots; roots.append(root); diff --git a/src/services/standard/standardserviceentrypoint.h b/src/services/standard/standardserviceentrypoint.h index 6729922dd..1bf1e1654 100755 --- a/src/services/standard/standardserviceentrypoint.h +++ b/src/services/standard/standardserviceentrypoint.h @@ -37,7 +37,7 @@ class StandardServiceEntryPoint : public ServiceEntryPoint { QString author(); QIcon icon(); - QList initializeSubtree(); + QList initializeSubtree(FeedsModel *main_model); }; #endif // STANDARDSERVICEENTRYPOINT_H diff --git a/src/services/standard/standardserviceroot.cpp b/src/services/standard/standardserviceroot.cpp index 12592850d..adf773f35 100755 --- a/src/services/standard/standardserviceroot.cpp +++ b/src/services/standard/standardserviceroot.cpp @@ -20,17 +20,20 @@ #include "definitions/definitions.h" #include "miscellaneous/application.h" #include "miscellaneous/settings.h" +#include "core/feedsmodel.h" #include "services/standard/standardserviceentrypoint.h" #include "services/standard/standardrecyclebin.h" #include "services/standard/standardfeed.h" #include "services/standard/standardcategory.h" +#include "services/standard/standardfeedsimportexportmodel.h" #include #include +#include -StandardServiceRoot::StandardServiceRoot(RootItem *parent) - : ServiceRoot(parent), m_recycleBin(new StandardRecycleBin(this)) { +StandardServiceRoot::StandardServiceRoot(FeedsModel *feeds_model, RootItem *parent) + : ServiceRoot(feeds_model, parent), m_recycleBin(new StandardRecycleBin(this)) { m_title = qApp->system()->getUsername() + "@" + APP_LOW_NAME; m_icon = StandardServiceEntryPoint().icon(); @@ -113,7 +116,6 @@ QVariant StandardServiceRoot::data(int column, int role) const { } void StandardServiceRoot::loadFromDatabase(){ - // TODO: todo QSqlDatabase database = qApp->database()->connection("StandardServiceRoot", DatabaseFactory::FromSettings); CategoryAssignment categories; FeedAssignment feeds; @@ -175,8 +177,8 @@ void StandardServiceRoot::loadFromDatabase(){ appendChild(m_recycleBin); } -QHash StandardServiceRoot::categoriesForItem(RootItem *root) { - QHash categories; +QHash StandardServiceRoot::categoriesForItem(RootItem *root) { + QHash categories; QList parents; parents.append(root->childItems()); @@ -184,11 +186,11 @@ QHash StandardServiceRoot::categoriesForItem(RootItem *r while (!parents.isEmpty()) { RootItem *item = parents.takeFirst(); - if (item->kind() == RootItem::Cattegory) { + if (item->kind() == RootItemKind::Category) { // This item is category, add it to the output list and // scan its children. int category_id = item->id(); - StandardCategory *category = item->toCategory(); + StandardCategory *category = static_cast(item); if (!categories.contains(category_id)) { categories.insert(category_id, category); @@ -201,8 +203,12 @@ QHash StandardServiceRoot::categoriesForItem(RootItem *r return categories; } +QHash StandardServiceRoot::allCategories() { + return categoriesForItem(this); +} + void StandardServiceRoot::assembleFeeds(FeedAssignment feeds) { - QHash categories = categoriesForItem(this); + QHash categories = categoriesForItem(this); foreach (const FeedAssignmentItem &feed, feeds) { if (feed.first == NO_PARENT_CATEGORY) { @@ -223,6 +229,86 @@ StandardRecycleBin *StandardServiceRoot::recycleBin() const { return m_recycleBin; } +bool StandardServiceRoot::mergeImportExportModel(FeedsImportExportModel *model, QString &output_message) { + QStack original_parents; original_parents.push(this); + QStack new_parents; new_parents.push(model->rootItem()); + bool some_feed_category_error = false; + + // Iterate all new items we would like to merge into current model. + while (!new_parents.isEmpty()) { + RootItem *target_parent = original_parents.pop(); + RootItem *source_parent = new_parents.pop(); + + foreach (RootItem *source_item, source_parent->childItems()) { + if (!model->isItemChecked(source_item)) { + // We can skip this item, because it is not checked and should not be imported. + // NOTE: All descendants are thus skipped too. + continue; + } + + if (source_item->kind() == RootItemKind::Category) { + StandardCategory *source_category = static_cast(source_item); + StandardCategory *new_category = new StandardCategory(*source_category); + QString new_category_title = new_category->title(); + + // Add category to model. + new_category->clearChildren(); + + if (new_category->addItself(target_parent)) { + m_feedsModel->assignNodeToNewParent(new_category, target_parent); + + // Process all children of this category. + original_parents.push(new_category); + new_parents.push(source_category); + } + else { + delete new_category; + + // Add category failed, but this can mean that the same category (with same title) + // already exists. If such a category exists in current parent, then find it and + // add descendants to it. + RootItem *existing_category = NULL; + foreach (RootItem *child, target_parent->childItems()) { + if (child->kind() == RootItemKind::Category && child->title() == new_category_title) { + existing_category = child; + } + } + + if (existing_category != NULL) { + original_parents.push(existing_category); + new_parents.push(source_category); + } + else { + some_feed_category_error = true; + } + } + } + else if (source_item->kind() == RootItemKind::Feed) { + StandardFeed *source_feed = static_cast(source_item); + StandardFeed *new_feed = new StandardFeed(*source_feed); + + // Append this feed and end this iteration. + if (!new_feed->addItself(target_parent)) { + delete new_feed; + some_feed_category_error = true; + } + } + } + } + + // Changes are done now. Finalize the new model. + //emit layoutChanged(); + + if (some_feed_category_error) { + output_message = tr("Import successfull, but some feeds/categories were not imported due to error."); + } + else { + output_message = tr("Import was completely successfull."); + } + + return !some_feed_category_error; +} + void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { QHash assignments; assignments.insert(NO_PARENT_CATEGORY, this); @@ -235,8 +321,7 @@ void StandardServiceRoot::assembleCategories(CategoryAssignment categories) { assignments.value(categories.at(i).first)->appendChild(categories.at(i).second); // Now, added category can be parent for another categories, add it. - assignments.insert(categories.at(i).second->id(), - categories.at(i).second); + assignments.insert(categories.at(i).second->id(), categories.at(i).second); // Remove the category from the list, because it was // added to the final collection. diff --git a/src/services/standard/standardserviceroot.h b/src/services/standard/standardserviceroot.h index 5e1013feb..f43d08239 100755 --- a/src/services/standard/standardserviceroot.h +++ b/src/services/standard/standardserviceroot.h @@ -26,6 +26,7 @@ class StandardRecycleBin; class StandardCategory; class StandardFeed; +class FeedsImportExportModel; typedef QList > CategoryAssignment; typedef QPair CategoryAssignmentItem; @@ -37,7 +38,7 @@ class StandardServiceRoot : public ServiceRoot { Q_DECLARE_TR_FUNCTIONS(StandardServiceRoot) public: - explicit StandardServiceRoot(RootItem *parent = NULL); + explicit StandardServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL); virtual ~StandardServiceRoot(); bool canBeEdited(); @@ -46,11 +47,20 @@ class StandardServiceRoot : public ServiceRoot { // Returns all standard categories which are lying under given root node. // This does NOT include the root node even if the node is category. - QHash categoriesForItem(RootItem *root); + QHash categoriesForItem(RootItem *root); + + // Returns all categories from this root, each pair + // consists of ID of parent item and pointer to category. + QHash allCategories(); // Access to standard recycle bin. StandardRecycleBin *recycleBin() const; + // Takes structure residing under given root item and adds feeds/categories from + // it to active structure. + // NOTE: This is used for import/export of the model. + bool mergeImportExportModel(FeedsImportExportModel *model, QString &output_message); + private: void loadFromDatabase(); diff --git a/src/services/tt-rss/ttrssserviceentrypoint.cpp b/src/services/tt-rss/ttrssserviceentrypoint.cpp index 7efd1d1f1..c37c17f2a 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.cpp +++ b/src/services/tt-rss/ttrssserviceentrypoint.cpp @@ -69,6 +69,6 @@ QIcon TtRssServiceEntryPoint::icon() { return QIcon(APP_ICON_PATH); } -QList TtRssServiceEntryPoint::initializeSubtree() { +QList TtRssServiceEntryPoint::initializeSubtree(FeedsModel *main_model) { return QList(); } diff --git a/src/services/tt-rss/ttrssserviceentrypoint.h b/src/services/tt-rss/ttrssserviceentrypoint.h index 63402ffdd..6447cc567 100755 --- a/src/services/tt-rss/ttrssserviceentrypoint.h +++ b/src/services/tt-rss/ttrssserviceentrypoint.h @@ -38,7 +38,7 @@ class TtRssServiceEntryPoint : public ServiceEntryPoint { QString author(); QIcon icon(); - QList initializeSubtree(); + QList initializeSubtree(FeedsModel *main_model); }; #endif // TTRSSSERVICEENTRYPOINT_H diff --git a/src/services/tt-rss/ttrssserviceroot.cpp b/src/services/tt-rss/ttrssserviceroot.cpp index e1e52c269..07dd463f8 100755 --- a/src/services/tt-rss/ttrssserviceroot.cpp +++ b/src/services/tt-rss/ttrssserviceroot.cpp @@ -20,9 +20,10 @@ #include "miscellaneous/application.h" #include "miscellaneous/settings.h" #include "services/tt-rss/ttrssserviceentrypoint.h" +#include "core/feedsmodel.h" -TtRssServiceRoot::TtRssServiceRoot(RootItem *parent) : ServiceRoot(parent) { +TtRssServiceRoot::TtRssServiceRoot(FeedsModel *feeds_model, RootItem *parent) : ServiceRoot(feeds_model, parent) { // TODO: nadpis se bude měnit podle nastavení uživatelského // jména a serveru tohoto ttrss učtu m_title = qApp->system()->getUsername() + "@ttrss"; diff --git a/src/services/tt-rss/ttrssserviceroot.h b/src/services/tt-rss/ttrssserviceroot.h index 986c99e21..a747a9773 100755 --- a/src/services/tt-rss/ttrssserviceroot.h +++ b/src/services/tt-rss/ttrssserviceroot.h @@ -23,11 +23,13 @@ #include +class FeedsModel; + class TtRssServiceRoot : public ServiceRoot { Q_DECLARE_TR_FUNCTIONS(StandardServiceRoot) public: - explicit TtRssServiceRoot(RootItem *parent = NULL); + explicit TtRssServiceRoot(FeedsModel *feeds_model, RootItem *parent = NULL); virtual ~TtRssServiceRoot(); bool canBeEdited();