Added very experimental brand new tree handling for standard service account. Also note, that recycle bin func is now broken, since there now each service account has OWN recycle bin, therefore there might be more than one recycle bin.

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

View File

@ -412,7 +412,6 @@ set(APP_SOURCES
src/core/rootitem.cpp src/core/rootitem.cpp
src/core/parsingfactory.cpp src/core/parsingfactory.cpp
src/core/feeddownloader.cpp src/core/feeddownloader.cpp
src/core/recyclebin.cpp
src/core/feedsselection.cpp src/core/feedsselection.cpp
# ABSTRACT service sources. # ABSTRACT service sources.
@ -429,6 +428,7 @@ set(APP_SOURCES
src/services/standard/gui/formstandardimportexport.cpp src/services/standard/gui/formstandardimportexport.cpp
src/services/standard/standardserviceentrypoint.cpp src/services/standard/standardserviceentrypoint.cpp
src/services/standard/standardserviceroot.cpp src/services/standard/standardserviceroot.cpp
src/services/standard/standardrecyclebin.cpp
# TT-RSS feed service sources. # TT-RSS feed service sources.
src/services/tt-rss/ttrssserviceentrypoint.cpp src/services/tt-rss/ttrssserviceentrypoint.cpp

View File

@ -19,10 +19,10 @@
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include "services/abstract/feed.h" #include "services/abstract/feed.h"
#include "services/abstract/serviceroot.h"
#include "services/standard/standardfeed.h" #include "services/standard/standardfeed.h"
#include "services/standard/standardcategory.h" #include "services/standard/standardcategory.h"
#include "services/standard/standardfeedsimportexportmodel.h" #include "services/standard/standardfeedsimportexportmodel.h"
#include "core/recyclebin.h"
#include "miscellaneous/textfactory.h" #include "miscellaneous/textfactory.h"
#include "miscellaneous/databasefactory.h" #include "miscellaneous/databasefactory.h"
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
@ -41,7 +41,7 @@
FeedsModel::FeedsModel(QObject *parent) FeedsModel::FeedsModel(QObject *parent)
: QAbstractItemModel(parent), m_recycleBin(new RecycleBin()), m_autoUpdateTimer(new QTimer(this)) { : QAbstractItemModel(parent), m_autoUpdateTimer(new QTimer(this)) {
setObjectName(QSL("FeedsModel")); setObjectName(QSL("FeedsModel"));
// Create root item. // Create root item.
@ -63,7 +63,7 @@ FeedsModel::FeedsModel(QObject *parent)
connect(m_autoUpdateTimer, SIGNAL(timeout()), this, SLOT(executeNextAutoUpdate())); connect(m_autoUpdateTimer, SIGNAL(timeout()), this, SLOT(executeNextAutoUpdate()));
loadFromDatabase(); loadActivatedServiceAccounts();
// Setup the timer. // Setup the timer.
updateAutoUpdateStatus(); updateAutoUpdateStatus();
@ -389,17 +389,6 @@ StandardCategory *FeedsModel::categoryForIndex(const QModelIndex &index) const {
} }
} }
RecycleBin *FeedsModel::recycleBinForIndex(const QModelIndex &index) const {
RootItem *item = itemForIndex(index);
if (item->kind() == RootItem::Bin) {
return item->toRecycleBin();
}
else {
return NULL;
}
}
QModelIndex FeedsModel::indexForItem(RootItem *item) const { QModelIndex FeedsModel::indexForItem(RootItem *item) const {
if (item == NULL || item->kind() == RootItem::Root) { if (item == NULL || item->kind() == RootItem::Root) {
// Root item lies on invalid index. // Root item lies on invalid index.
@ -539,70 +528,19 @@ void FeedsModel::reloadWholeLayout() {
emit layoutChanged(); emit layoutChanged();
} }
void FeedsModel::loadFromDatabase() { void FeedsModel::loadActivatedServiceAccounts() {
// Delete all childs of the root node and clear them from the memory. // Delete all childs of the root node and clear them from the memory.
qDeleteAll(m_rootItem->childItems()); qDeleteAll(m_rootItem->childItems());
m_rootItem->clearChildren(); m_rootItem->clearChildren();
QSqlDatabase database = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings); foreach (ServiceEntryPoint *entry_point, qApp->feedServices()) {
CategoryAssignment categories; // Load all stored root nodes from the entry point and add those to the model.
FeedAssignment feeds; QList<ServiceRoot*> roots = entry_point->initializeSubtree();
// Obtain data for categories from the database. foreach (ServiceRoot *root, roots) {
QSqlQuery query_categories(database); m_rootItem->appendChild(root);
query_categories.setForwardOnly(true);
if (!query_categories.exec(QSL("SELECT * FROM Categories;")) || query_categories.lastError().isValid()) {
qFatal("Query for obtaining categories failed. Error message: '%s'.",
qPrintable(query_categories.lastError().text()));
}
while (query_categories.next()) {
CategoryAssignmentItem pair;
pair.first = query_categories.value(CAT_DB_PARENT_ID_INDEX).toInt();
pair.second = new StandardCategory(query_categories.record());
categories << pair;
}
// All categories are now loaded.
QSqlQuery query_feeds(database);
query_feeds.setForwardOnly(true);
if (!query_feeds.exec(QSL("SELECT * FROM Feeds;")) || query_feeds.lastError().isValid()) {
qFatal("Query for obtaining feeds failed. Error message: '%s'.",
qPrintable(query_feeds.lastError().text()));
}
while (query_feeds.next()) {
// Process this feed.
StandardFeed::Type type = static_cast<StandardFeed::Type>(query_feeds.value(FDS_DB_TYPE_INDEX).toInt());
switch (type) {
case StandardFeed::Atom10:
case StandardFeed::Rdf:
case StandardFeed::Rss0X:
case StandardFeed::Rss2X: {
FeedAssignmentItem pair;
pair.first = query_feeds.value(FDS_DB_CATEGORY_INDEX).toInt();
pair.second = new StandardFeed(query_feeds.record());
pair.second->setType(type);
feeds << pair;
break;
}
default:
break;
} }
} }
// All data are now obtained, lets create the hierarchy.
assembleCategories(categories);
assembleFeeds(feeds);
// As the last item, add recycle bin, which is needed.
m_rootItem->appendChild(m_recycleBin);
} }
QList<Feed*> FeedsModel::feedsForIndex(const QModelIndex &index) { QList<Feed*> FeedsModel::feedsForIndex(const QModelIndex &index) {
@ -768,49 +706,3 @@ QList<Feed*> FeedsModel::feedsForItem(RootItem *root) {
return feeds; return feeds;
} }
void FeedsModel::assembleFeeds(FeedAssignment feeds) {
QHash<int, StandardCategory*> categories = allCategories();
foreach (const FeedAssignmentItem &feed, feeds) {
if (feed.first == NO_PARENT_CATEGORY) {
// This is top-level feed, add it to the root item.
m_rootItem->appendChild(feed.second);
}
else if (categories.contains(feed.first)) {
// This feed belongs to this category.
categories.value(feed.first)->appendChild(feed.second);
}
else {
qWarning("Feed '%s' is loose, skipping it.", qPrintable(feed.second->title()));
}
}
}
RecycleBin *FeedsModel::recycleBin() const {
return m_recycleBin;
}
void FeedsModel::assembleCategories(CategoryAssignment categories) {
QHash<int, RootItem*> assignments;
assignments.insert(NO_PARENT_CATEGORY, m_rootItem);
// Add top-level categories.
while (!categories.isEmpty()) {
for (int i = 0; i < categories.size(); i++) {
if (assignments.contains(categories.at(i).first)) {
// Parent category of this category is already added.
assignments.value(categories.at(i).first)->appendChild(categories.at(i).second);
// Now, added category can be parent for another categories, add it.
assignments.insert(categories.at(i).second->id(),
categories.at(i).second);
// Remove the category from the list, because it was
// added to the final collection.
categories.removeAt(i);
i--;
}
}
}
}

View File

@ -28,16 +28,10 @@
class StandardCategory; class StandardCategory;
class Feed; class Feed;
class RecycleBin; class StandardRecycleBin;
class FeedsImportExportModel; class FeedsImportExportModel;
class QTimer; class QTimer;
typedef QList<QPair<int, StandardCategory*> > CategoryAssignment;
typedef QPair<int, StandardCategory*> CategoryAssignmentItem;
typedef QList<QPair<int, StandardFeed*> > FeedAssignment;
typedef QPair<int, StandardFeed*> FeedAssignmentItem;
class FeedsModel : public QAbstractItemModel { class FeedsModel : public QAbstractItemModel {
Q_OBJECT Q_OBJECT
@ -121,10 +115,6 @@ class FeedsModel : public QAbstractItemModel {
// or NULL if no category lies on given index. // or NULL if no category lies on given index.
StandardCategory *categoryForIndex(const QModelIndex &index) const; StandardCategory *categoryForIndex(const QModelIndex &index) const;
// Returns pointer to recycle bin if lies on given index
// or NULL if no recycle bin lies on given index.
RecycleBin *recycleBinForIndex(const QModelIndex &index) const;
// Returns feed/category which lies at the specified index or // Returns feed/category which lies at the specified index or
// root item if index is invalid. // root item if index is invalid.
RootItem *itemForIndex(const QModelIndex &index) const; RootItem *itemForIndex(const QModelIndex &index) const;
@ -144,9 +134,6 @@ class FeedsModel : public QAbstractItemModel {
// it to active structure. // it to active structure.
bool mergeModel(FeedsImportExportModel *model, QString &output_message); bool mergeModel(FeedsImportExportModel *model, QString &output_message);
// Access to recycle bin.
RecycleBin *recycleBin() const;
// Resets global auto-update intervals according to settings // Resets global auto-update intervals according to settings
// and starts/stop the timer as needed. // and starts/stop the timer as needed.
void updateAutoUpdateStatus(); void updateAutoUpdateStatus();
@ -178,12 +165,7 @@ class FeedsModel : public QAbstractItemModel {
QStringList textualFeedIds(const QList<Feed*> &feeds); QStringList textualFeedIds(const QList<Feed*> &feeds);
// Loads feed/categories from the database. // Loads feed/categories from the database.
void loadFromDatabase(); void loadActivatedServiceAccounts();
// Takes lists of feeds/categories and assembles
// them into the tree structure.
void assembleCategories(CategoryAssignment categories);
void assembleFeeds(FeedAssignment feeds);
signals: signals:
// Emitted when model requests update of some feeds. // Emitted when model requests update of some feeds.
@ -191,7 +173,6 @@ class FeedsModel : public QAbstractItemModel {
private: private:
RootItem *m_rootItem; RootItem *m_rootItem;
RecycleBin *m_recycleBin;
QList<QString> m_headerData; QList<QString> m_headerData;
QList<QString> m_tooltipData; QList<QString> m_tooltipData;
QIcon m_countsIcon; QIcon m_countsIcon;

View File

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

View File

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

View File

@ -137,11 +137,6 @@ QList<QAction*> FormMain::allActions() {
actions << m_ui->m_actionFetchFeedMetadata; actions << m_ui->m_actionFetchFeedMetadata;
actions << m_ui->m_actionExpandCollapseFeedCategory; actions << m_ui->m_actionExpandCollapseFeedCategory;
// Add recycle bin actions.
actions << m_ui->m_actionRestoreRecycleBin;
actions << m_ui->m_actionEmptyRecycleBin;
actions << m_ui->m_actionRestoreSelectedMessagesFromRecycleBin;
return actions; return actions;
} }
@ -237,11 +232,6 @@ void FormMain::setupIcons() {
m_ui->m_actionSwitchMessageListOrientation->setIcon(icon_theme_factory->fromTheme(QSL("view-switch-layout-direction"))); m_ui->m_actionSwitchMessageListOrientation->setIcon(icon_theme_factory->fromTheme(QSL("view-switch-layout-direction")));
m_ui->m_menuShowHide->setIcon(icon_theme_factory->fromTheme(QSL("view-switch"))); m_ui->m_menuShowHide->setIcon(icon_theme_factory->fromTheme(QSL("view-switch")));
// Recycle bin.
m_ui->m_actionEmptyRecycleBin->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-empty")));
m_ui->m_actionRestoreRecycleBin->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-restore-all")));
m_ui->m_actionRestoreSelectedMessagesFromRecycleBin->setIcon(icon_theme_factory->fromTheme(QSL("recycle-bin-restore-one")));
// Web browser. // Web browser.
m_ui->m_actionAddBrowser->setIcon(icon_theme_factory->fromTheme(QSL("list-add"))); m_ui->m_actionAddBrowser->setIcon(icon_theme_factory->fromTheme(QSL("list-add")));
m_ui->m_actionCloseCurrentTab->setIcon(icon_theme_factory->fromTheme(QSL("list-remove"))); m_ui->m_actionCloseCurrentTab->setIcon(icon_theme_factory->fromTheme(QSL("list-remove")));

View File

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

View File

@ -290,7 +290,6 @@ void FeedMessageViewer::toggleShowOnlyUnreadFeeds() {
void FeedMessageViewer::updateMessageButtonsAvailability() { void FeedMessageViewer::updateMessageButtonsAvailability() {
bool one_message_selected = m_messagesView->selectionModel()->selectedRows().size() == 1; bool one_message_selected = m_messagesView->selectionModel()->selectedRows().size() == 1;
bool atleast_one_message_selected = !m_messagesView->selectionModel()->selectedRows().isEmpty(); bool atleast_one_message_selected = !m_messagesView->selectionModel()->selectedRows().isEmpty();
bool recycle_bin_selected = m_messagesView->sourceModel()->loadedSelection().mode() == FeedsSelection::MessagesFromRecycleBin;
FormMain *form_main = qApp->mainForm(); FormMain *form_main = qApp->mainForm();
form_main->m_ui->m_actionDeleteSelectedMessages->setEnabled(atleast_one_message_selected); form_main->m_ui->m_actionDeleteSelectedMessages->setEnabled(atleast_one_message_selected);
@ -301,8 +300,6 @@ void FeedMessageViewer::updateMessageButtonsAvailability() {
form_main->m_ui->m_actionOpenSelectedSourceArticlesInternally->setEnabled(atleast_one_message_selected); form_main->m_ui->m_actionOpenSelectedSourceArticlesInternally->setEnabled(atleast_one_message_selected);
form_main->m_ui->m_actionSendMessageViaEmail->setEnabled(one_message_selected); form_main->m_ui->m_actionSendMessageViaEmail->setEnabled(one_message_selected);
form_main->m_ui->m_actionSwitchImportanceOfSelectedMessages->setEnabled(atleast_one_message_selected); form_main->m_ui->m_actionSwitchImportanceOfSelectedMessages->setEnabled(atleast_one_message_selected);
form_main->m_ui->m_actionRestoreSelectedMessagesFromRecycleBin->setEnabled(recycle_bin_selected && atleast_one_message_selected);
} }
void FeedMessageViewer::updateFeedButtonsAvailability() { void FeedMessageViewer::updateFeedButtonsAvailability() {
@ -378,8 +375,6 @@ void FeedMessageViewer::createConnections() {
SIGNAL(triggered()), m_messagesView, SLOT(switchSelectedMessagesImportance())); SIGNAL(triggered()), m_messagesView, SLOT(switchSelectedMessagesImportance()));
connect(form_main->m_ui->m_actionDeleteSelectedMessages, connect(form_main->m_ui->m_actionDeleteSelectedMessages,
SIGNAL(triggered()), m_messagesView, SLOT(deleteSelectedMessages())); SIGNAL(triggered()), m_messagesView, SLOT(deleteSelectedMessages()));
connect(form_main->m_ui->m_actionRestoreSelectedMessagesFromRecycleBin,
SIGNAL(triggered()), m_messagesView, SLOT(restoreSelectedMessages()));
connect(form_main->m_ui->m_actionMarkSelectedMessagesAsRead, connect(form_main->m_ui->m_actionMarkSelectedMessagesAsRead,
SIGNAL(triggered()), m_messagesView, SLOT(markSelectedMessagesRead())); SIGNAL(triggered()), m_messagesView, SLOT(markSelectedMessagesRead()));
connect(form_main->m_ui->m_actionMarkSelectedMessagesAsUnread, connect(form_main->m_ui->m_actionMarkSelectedMessagesAsUnread,
@ -418,10 +413,6 @@ void FeedMessageViewer::createConnections() {
SIGNAL(triggered()), m_feedsView, SLOT(editSelectedItem())); SIGNAL(triggered()), m_feedsView, SLOT(editSelectedItem()));
connect(form_main->m_ui->m_actionViewSelectedItemsNewspaperMode, connect(form_main->m_ui->m_actionViewSelectedItemsNewspaperMode,
SIGNAL(triggered()), m_feedsView, SLOT(openSelectedFeedsInNewspaperMode())); SIGNAL(triggered()), m_feedsView, SLOT(openSelectedFeedsInNewspaperMode()));
connect(form_main->m_ui->m_actionEmptyRecycleBin,
SIGNAL(triggered()), m_feedsView, SLOT(emptyRecycleBin()));
connect(form_main->m_ui->m_actionRestoreRecycleBin,
SIGNAL(triggered()), m_feedsView, SLOT(restoreRecycleBin()));
connect(form_main->m_ui->m_actionDeleteSelectedFeedCategory, connect(form_main->m_ui->m_actionDeleteSelectedFeedCategory,
SIGNAL(triggered()), m_feedsView, SLOT(deleteSelectedItem())); SIGNAL(triggered()), m_feedsView, SLOT(deleteSelectedItem()));
connect(form_main->m_ui->m_actionSwitchFeedsList, connect(form_main->m_ui->m_actionSwitchFeedsList,

View File

@ -21,7 +21,6 @@
#include "core/feedsmodel.h" #include "core/feedsmodel.h"
#include "core/feedsproxymodel.h" #include "core/feedsproxymodel.h"
#include "core/rootitem.h" #include "core/rootitem.h"
#include "core/recyclebin.h"
#include "miscellaneous/systemfactory.h" #include "miscellaneous/systemfactory.h"
#include "miscellaneous/mutex.h" #include "miscellaneous/mutex.h"
#include "gui/systemtrayicon.h" #include "gui/systemtrayicon.h"
@ -46,8 +45,7 @@ FeedsView::FeedsView(QWidget *parent)
: QTreeView(parent), : QTreeView(parent),
m_contextMenuCategories(NULL), m_contextMenuCategories(NULL),
m_contextMenuFeeds(NULL), m_contextMenuFeeds(NULL),
m_contextMenuEmptySpace(NULL), m_contextMenuEmptySpace(NULL) {
m_contextMenuRecycleBin(NULL) {
setObjectName(QSL("FeedsView")); setObjectName(QSL("FeedsView"));
// Allocate models. // Allocate models.
@ -108,11 +106,6 @@ Feed *FeedsView::selectedFeed() const {
return m_sourceModel->feedForIndex(current_mapped); return m_sourceModel->feedForIndex(current_mapped);
} }
RecycleBin *FeedsView::selectedRecycleBin() const{
QModelIndex current_mapped = m_proxyModel->mapToSource(currentIndex());
return m_sourceModel->recycleBinForIndex(current_mapped);
}
void FeedsView::saveExpandedStates() { void FeedsView::saveExpandedStates() {
Settings *settings = qApp->settings(); Settings *settings = qApp->settings();
@ -398,7 +391,8 @@ void FeedsView::emptyRecycleBin() {
tr("You are about to permanenty delete all messages from your recycle bin."), tr("You are about to permanenty delete all messages from your recycle bin."),
tr("Do you really want to empty your recycle bin?"), tr("Do you really want to empty your recycle bin?"),
QString(), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) { QString(), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) {
m_sourceModel->recycleBin()->empty(); // TODO: pridat metodu cisteni standardniho kose nebo vsech kosu.
//m_sourceModel->recycleBin()->empty();
updateCountsOfSelectedFeeds(true); updateCountsOfSelectedFeeds(true);
emit feedsNeedToBeReloaded(true); emit feedsNeedToBeReloaded(true);
@ -406,7 +400,8 @@ void FeedsView::emptyRecycleBin() {
} }
void FeedsView::restoreRecycleBin() { void FeedsView::restoreRecycleBin() {
m_sourceModel->recycleBin()->restore(); // TODO: pridat metodu cisteni standardniho kose nebo vsech kosu.
//m_sourceModel->recycleBin()->restore();
updateCountsOfAllFeeds(true); updateCountsOfAllFeeds(true);
emit feedsNeedToBeReloaded(true); emit feedsNeedToBeReloaded(true);
@ -421,10 +416,14 @@ void FeedsView::updateCountsOfSelectedFeeds(bool update_total_too) {
if (update_total_too) { if (update_total_too) {
// Number of items in recycle bin has changed. // Number of items in recycle bin has changed.
m_sourceModel->recycleBin()->updateCounts(true);
// TODO: pridat metodu cisteni standardniho kose nebo vsech kosu.
//m_sourceModel->recycleBin()->updateCounts(true);
// We need to refresh data for recycle bin too. // We need to refresh data for recycle bin too.
selected_indexes.append(m_sourceModel->indexForItem(m_sourceModel->recycleBin()));
// TODO: pridat metodu cisteni standardniho kose nebo vsech kosu.
//selected_indexes.append(m_sourceModel->indexForItem(m_sourceModel->recycleBin()));
} }
// Make sure that selected view reloads changed indexes. // Make sure that selected view reloads changed indexes.
@ -433,8 +432,10 @@ void FeedsView::updateCountsOfSelectedFeeds(bool update_total_too) {
} }
void FeedsView::updateCountsOfRecycleBin(bool update_total_too) { void FeedsView::updateCountsOfRecycleBin(bool update_total_too) {
m_sourceModel->recycleBin()->updateCounts(update_total_too);
m_sourceModel->reloadChangedLayout(QModelIndexList() << m_sourceModel->indexForItem(m_sourceModel->recycleBin())); // TODO: pridat metodu cisteni standardniho kose nebo vsech kosu.
//m_sourceModel->recycleBin()->updateCounts(update_total_too);
//m_sourceModel->reloadChangedLayout(QModelIndexList() << m_sourceModel->indexForItem(m_sourceModel->recycleBin()));
notifyWithCounts(); notifyWithCounts();
} }
@ -445,7 +446,9 @@ void FeedsView::updateCountsOfAllFeeds(bool update_total_too) {
if (update_total_too) { if (update_total_too) {
// Number of items in recycle bin has changed. // Number of items in recycle bin has changed.
m_sourceModel->recycleBin()->updateCounts(true);
// TODO: pridat metodu cisteni standardniho kose nebo vsech kosu.
//m_sourceModel->recycleBin()->updateCounts(true);
} }
// Make sure that all views reloads its data. // Make sure that all views reloads its data.
@ -534,14 +537,6 @@ void FeedsView::initializeContextMenuEmptySpace() {
qApp->mainForm()->m_ui->m_actionAddFeed); qApp->mainForm()->m_ui->m_actionAddFeed);
} }
void FeedsView::initializeContextMenuRecycleBin() {
m_contextMenuRecycleBin = new QMenu(tr("Context menu for recycle bin"), this);
m_contextMenuRecycleBin->addActions(QList<QAction*>() <<
qApp->mainForm()->m_ui->m_actionRestoreRecycleBin <<
qApp->mainForm()->m_ui->m_actionRestoreSelectedMessagesFromRecycleBin <<
qApp->mainForm()->m_ui->m_actionEmptyRecycleBin);
}
void FeedsView::setupAppearance() { void FeedsView::setupAppearance() {
#if QT_VERSION >= 0x050000 #if QT_VERSION >= 0x050000
// Setup column resize strategies. // Setup column resize strategies.
@ -617,14 +612,6 @@ void FeedsView::contextMenuEvent(QContextMenuEvent *event) {
m_contextMenuFeeds->exec(event->globalPos()); m_contextMenuFeeds->exec(event->globalPos());
} }
else if (clicked_item->kind() == RootItem::Bin) {
// Display context menu for recycle bin.
if (m_contextMenuRecycleBin == NULL) {
initializeContextMenuRecycleBin();
}
m_contextMenuRecycleBin->exec(event->globalPos());
}
} }
else { else {
// Display menu for empty space. // Display menu for empty space.

View File

@ -61,7 +61,6 @@ class FeedsView : public QTreeView {
RootItem *selectedItem() const; RootItem *selectedItem() const;
StandardCategory *selectedCategory() const; StandardCategory *selectedCategory() const;
Feed *selectedFeed() const; Feed *selectedFeed() const;
RecycleBin *selectedRecycleBin() const;
// Saves/loads expand states of all nodes (feeds/categories) of the list to/from settings. // Saves/loads expand states of all nodes (feeds/categories) of the list to/from settings.
void saveExpandedStates(); void saveExpandedStates();
@ -146,7 +145,6 @@ class FeedsView : public QTreeView {
void initializeContextMenuCategories(); void initializeContextMenuCategories();
void initializeContextMenuFeeds(); void initializeContextMenuFeeds();
void initializeContextMenuEmptySpace(); void initializeContextMenuEmptySpace();
void initializeContextMenuRecycleBin();
// Sets up appearance of this widget. // Sets up appearance of this widget.
void setupAppearance(); void setupAppearance();
@ -184,7 +182,6 @@ class FeedsView : public QTreeView {
QMenu *m_contextMenuCategories; QMenu *m_contextMenuCategories;
QMenu *m_contextMenuFeeds; QMenu *m_contextMenuFeeds;
QMenu *m_contextMenuEmptySpace; QMenu *m_contextMenuEmptySpace;
QMenu *m_contextMenuRecycleBin;
FeedsModel *m_sourceModel; FeedsModel *m_sourceModel;
FeedsProxyModel *m_proxyModel; FeedsProxyModel *m_proxyModel;

View File

@ -146,13 +146,6 @@ void MessagesView::contextMenuEvent(QContextMenuEvent *event) {
initializeContextMenu(); initializeContextMenu();
} }
if (sourceModel()->loadedSelection().mode() == FeedsSelection::MessagesFromRecycleBin) {
m_contextMenu->addAction(qApp->mainForm()->m_ui->m_actionRestoreSelectedMessagesFromRecycleBin);
}
else {
m_contextMenu->removeAction(qApp->mainForm()->m_ui->m_actionRestoreSelectedMessagesFromRecycleBin);
}
m_contextMenu->exec(event->globalPos()); m_contextMenu->exec(event->globalPos());
} }
@ -166,8 +159,7 @@ void MessagesView::initializeContextMenu() {
qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsRead << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsRead <<
qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsUnread << qApp->mainForm()->m_ui->m_actionMarkSelectedMessagesAsUnread <<
qApp->mainForm()->m_ui->m_actionSwitchImportanceOfSelectedMessages << qApp->mainForm()->m_ui->m_actionSwitchImportanceOfSelectedMessages <<
qApp->mainForm()->m_ui->m_actionDeleteSelectedMessages << qApp->mainForm()->m_ui->m_actionDeleteSelectedMessages);
qApp->mainForm()->m_ui->m_actionRestoreSelectedMessagesFromRecycleBin);
} }
void MessagesView::mousePressEvent(QMouseEvent *event) { void MessagesView::mousePressEvent(QMouseEvent *event) {

View File

@ -71,7 +71,6 @@ void TabWidget::openMainMenu() {
m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuView); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuView);
m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuFeeds); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuFeeds);
m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuMessages); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuMessages);
m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuRecycleBin);
m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuWebBrowser); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuWebBrowser);
m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuTools); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuTools);
m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuHelp); m_menuMain->addMenu(qApp->mainForm()->m_ui->m_menuHelp);

View File

@ -23,6 +23,8 @@
#include <QString> #include <QString>
class ServiceRoot;
// TOP LEVEL class which provides basic information about the "service" // TOP LEVEL class which provides basic information about the "service"
class ServiceEntryPoint { class ServiceEntryPoint {
public: public:
@ -30,6 +32,12 @@ class ServiceEntryPoint {
explicit ServiceEntryPoint(); explicit ServiceEntryPoint();
virtual ~ServiceEntryPoint(); virtual ~ServiceEntryPoint();
// Performs initialization of all service accounts created using this entry
// point from persistent DB.
// Returns list of root nodes which will be afterwards added
// to the global feed model.
virtual QList<ServiceRoot*> initializeSubtree() = 0;
// Must this service account be activated by default? // Must this service account be activated by default?
// NOTE: This is true particularly for "standard" service // NOTE: This is true particularly for "standard" service
// which operates with normal RSS/ATOM feeds. // which operates with normal RSS/ATOM feeds.

View File

@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>. // along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#include "core/recyclebin.h" #include "services/standard/standardrecyclebin.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
@ -23,7 +23,7 @@
#include <QSqlQuery> #include <QSqlQuery>
RecycleBin::RecycleBin(RootItem *parent) StandardRecycleBin::StandardRecycleBin(RootItem *parent)
: RootItem(parent) { : RootItem(parent) {
m_kind = RootItem::Bin; m_kind = RootItem::Bin;
m_icon = qApp->icons()->fromTheme(QSL("folder-recycle-bin")); m_icon = qApp->icons()->fromTheme(QSL("folder-recycle-bin"));
@ -35,27 +35,27 @@ RecycleBin::RecycleBin(RootItem *parent)
updateCounts(true); updateCounts(true);
} }
RecycleBin::~RecycleBin() { StandardRecycleBin::~StandardRecycleBin() {
qDebug("Destroying RecycleBin instance."); qDebug("Destroying RecycleBin instance.");
} }
int RecycleBin::childCount() const { int StandardRecycleBin::childCount() const {
return 0; return 0;
} }
void RecycleBin::appendChild(RootItem *child) { void StandardRecycleBin::appendChild(RootItem *child) {
Q_UNUSED(child) Q_UNUSED(child)
} }
int RecycleBin::countOfUnreadMessages() const { int StandardRecycleBin::countOfUnreadMessages() const {
return m_unreadCount; return m_unreadCount;
} }
int RecycleBin::countOfAllMessages() const { int StandardRecycleBin::countOfAllMessages() const {
return m_totalCount; return m_totalCount;
} }
QVariant RecycleBin::data(int column, int role) const { QVariant StandardRecycleBin::data(int column, int role) const {
switch (role) { switch (role) {
case Qt::DisplayRole: case Qt::DisplayRole:
if (column == FDS_MODEL_TITLE_INDEX) { if (column == FDS_MODEL_TITLE_INDEX) {
@ -108,7 +108,7 @@ QVariant RecycleBin::data(int column, int role) const {
} }
} }
bool RecycleBin::empty() { bool StandardRecycleBin::empty() {
QSqlDatabase db_handle = qApp->database()->connection(QSL("RecycleBin"), DatabaseFactory::FromSettings); QSqlDatabase db_handle = qApp->database()->connection(QSL("RecycleBin"), DatabaseFactory::FromSettings);
if (!db_handle.transaction()) { if (!db_handle.transaction()) {
@ -135,7 +135,7 @@ bool RecycleBin::empty() {
} }
} }
bool RecycleBin::restore() { bool StandardRecycleBin::restore() {
QSqlDatabase db_handle = qApp->database()->connection(QSL("RecycleBin"), DatabaseFactory::FromSettings); QSqlDatabase db_handle = qApp->database()->connection(QSL("RecycleBin"), DatabaseFactory::FromSettings);
if (!db_handle.transaction()) { if (!db_handle.transaction()) {
@ -162,7 +162,7 @@ bool RecycleBin::restore() {
} }
} }
void RecycleBin::updateCounts(bool update_total_count) { void StandardRecycleBin::updateCounts(bool update_total_count) {
QSqlDatabase database = qApp->database()->connection(QSL("RecycleBin"), DatabaseFactory::FromSettings); QSqlDatabase database = qApp->database()->connection(QSL("RecycleBin"), DatabaseFactory::FromSettings);
QSqlQuery query_all(database); QSqlQuery query_all(database);
query_all.setForwardOnly(true); query_all.setForwardOnly(true);

View File

@ -23,12 +23,12 @@
#include <QCoreApplication> #include <QCoreApplication>
class RecycleBin : public RootItem { class StandardRecycleBin : public RootItem {
Q_DECLARE_TR_FUNCTIONS(RecycleBin) Q_DECLARE_TR_FUNCTIONS(StandardRecycleBin)
public: public:
explicit RecycleBin(RootItem *parent = NULL); explicit StandardRecycleBin(RootItem *parent = NULL);
virtual ~RecycleBin(); virtual ~StandardRecycleBin();
int childCount() const; int childCount() const;
void appendChild(RootItem *child); void appendChild(RootItem *child);

View File

@ -20,6 +20,7 @@
#include "definitions/definitions.h" #include "definitions/definitions.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include "services/standard/standardserviceroot.h"
StandardServiceEntryPoint::StandardServiceEntryPoint() { StandardServiceEntryPoint::StandardServiceEntryPoint() {
@ -67,3 +68,11 @@ QString StandardServiceEntryPoint::author() {
QIcon StandardServiceEntryPoint::icon() { QIcon StandardServiceEntryPoint::icon() {
return QIcon(APP_ICON_PATH); return QIcon(APP_ICON_PATH);
} }
QList<ServiceRoot*> StandardServiceEntryPoint::initializeSubtree() {
StandardServiceRoot *root = new StandardServiceRoot();
QList<ServiceRoot*> roots;
roots.append(root);
return roots;
}

View File

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

View File

@ -21,11 +21,20 @@
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include "miscellaneous/settings.h" #include "miscellaneous/settings.h"
#include "services/standard/standardserviceentrypoint.h" #include "services/standard/standardserviceentrypoint.h"
#include "services/standard/standardrecyclebin.h"
#include "services/standard/standardfeed.h"
#include "services/standard/standardcategory.h"
#include <QSqlQuery>
#include <QSqlError>
StandardServiceRoot::StandardServiceRoot(RootItem *parent) : ServiceRoot(parent) { StandardServiceRoot::StandardServiceRoot(RootItem *parent)
: ServiceRoot(parent), m_recycleBin(new StandardRecycleBin(this)) {
m_title = qApp->system()->getUsername() + "@" + APP_LOW_NAME; m_title = qApp->system()->getUsername() + "@" + APP_LOW_NAME;
m_icon = StandardServiceEntryPoint().icon(); m_icon = StandardServiceEntryPoint().icon();
loadFromDatabase();
} }
StandardServiceRoot::~StandardServiceRoot() { StandardServiceRoot::~StandardServiceRoot() {
@ -102,3 +111,138 @@ QVariant StandardServiceRoot::data(int column, int role) const {
return QVariant(); return QVariant();
} }
} }
void StandardServiceRoot::loadFromDatabase(){
// TODO: todo
QSqlDatabase database = qApp->database()->connection("StandardServiceRoot", DatabaseFactory::FromSettings);
CategoryAssignment categories;
FeedAssignment feeds;
// Obtain data for categories from the database.
QSqlQuery query_categories(database);
query_categories.setForwardOnly(true);
if (!query_categories.exec(QSL("SELECT * FROM Categories;")) || query_categories.lastError().isValid()) {
qFatal("Query for obtaining categories failed. Error message: '%s'.",
qPrintable(query_categories.lastError().text()));
}
while (query_categories.next()) {
CategoryAssignmentItem pair;
pair.first = query_categories.value(CAT_DB_PARENT_ID_INDEX).toInt();
pair.second = new StandardCategory(query_categories.record());
categories << pair;
}
// All categories are now loaded.
QSqlQuery query_feeds(database);
query_feeds.setForwardOnly(true);
if (!query_feeds.exec(QSL("SELECT * FROM Feeds;")) || query_feeds.lastError().isValid()) {
qFatal("Query for obtaining feeds failed. Error message: '%s'.",
qPrintable(query_feeds.lastError().text()));
}
while (query_feeds.next()) {
// Process this feed.
StandardFeed::Type type = static_cast<StandardFeed::Type>(query_feeds.value(FDS_DB_TYPE_INDEX).toInt());
switch (type) {
case StandardFeed::Atom10:
case StandardFeed::Rdf:
case StandardFeed::Rss0X:
case StandardFeed::Rss2X: {
FeedAssignmentItem pair;
pair.first = query_feeds.value(FDS_DB_CATEGORY_INDEX).toInt();
pair.second = new StandardFeed(query_feeds.record());
pair.second->setType(type);
feeds << pair;
break;
}
default:
break;
}
}
// All data are now obtained, lets create the hierarchy.
assembleCategories(categories);
assembleFeeds(feeds);
// As the last item, add recycle bin, which is needed.
appendChild(m_recycleBin);
}
QHash<int, StandardCategory*> StandardServiceRoot::categoriesForItem(RootItem *root) {
QHash<int, StandardCategory*> categories;
QList<RootItem*> parents;
parents.append(root->childItems());
while (!parents.isEmpty()) {
RootItem *item = parents.takeFirst();
if (item->kind() == RootItem::Cattegory) {
// This item is category, add it to the output list and
// scan its children.
int category_id = item->id();
StandardCategory *category = item->toCategory();
if (!categories.contains(category_id)) {
categories.insert(category_id, category);
}
parents.append(category->childItems());
}
}
return categories;
}
void StandardServiceRoot::assembleFeeds(FeedAssignment feeds) {
QHash<int, StandardCategory*> categories = categoriesForItem(this);
foreach (const FeedAssignmentItem &feed, feeds) {
if (feed.first == NO_PARENT_CATEGORY) {
// This is top-level feed, add it to the root item.
appendChild(feed.second);
}
else if (categories.contains(feed.first)) {
// This feed belongs to this category.
categories.value(feed.first)->appendChild(feed.second);
}
else {
qWarning("Feed '%s' is loose, skipping it.", qPrintable(feed.second->title()));
}
}
}
StandardRecycleBin *StandardServiceRoot::recycleBin() const {
return m_recycleBin;
}
void StandardServiceRoot::assembleCategories(CategoryAssignment categories) {
QHash<int, RootItem*> assignments;
assignments.insert(NO_PARENT_CATEGORY, this);
// Add top-level categories.
while (!categories.isEmpty()) {
for (int i = 0; i < categories.size(); i++) {
if (assignments.contains(categories.at(i).first)) {
// Parent category of this category is already added.
assignments.value(categories.at(i).first)->appendChild(categories.at(i).second);
// Now, added category can be parent for another categories, add it.
assignments.insert(categories.at(i).second->id(),
categories.at(i).second);
// Remove the category from the list, because it was
// added to the final collection.
categories.removeAt(i);
i--;
}
}
}
}

View File

@ -23,6 +23,16 @@
#include <QCoreApplication> #include <QCoreApplication>
class StandardRecycleBin;
class StandardCategory;
class StandardFeed;
typedef QList<QPair<int, StandardCategory*> > CategoryAssignment;
typedef QPair<int, StandardCategory*> CategoryAssignmentItem;
typedef QList<QPair<int, StandardFeed*> > FeedAssignment;
typedef QPair<int, StandardFeed*> FeedAssignmentItem;
class StandardServiceRoot : public ServiceRoot { class StandardServiceRoot : public ServiceRoot {
Q_DECLARE_TR_FUNCTIONS(StandardServiceRoot) Q_DECLARE_TR_FUNCTIONS(StandardServiceRoot)
@ -33,6 +43,23 @@ class StandardServiceRoot : public ServiceRoot {
bool canBeEdited(); bool canBeEdited();
bool canBeDeleted(); bool canBeDeleted();
QVariant data(int column, int role) const; QVariant data(int column, int role) const;
// Returns all standard categories which are lying under given root node.
// This does NOT include the root node even if the node is category.
QHash<int, StandardCategory*> categoriesForItem(RootItem *root);
// Access to standard recycle bin.
StandardRecycleBin *recycleBin() const;
private:
void loadFromDatabase();
// Takes lists of feeds/categories and assembles
// them into the tree structure.
void assembleCategories(CategoryAssignment categories);
void assembleFeeds(FeedAssignment feeds);
StandardRecycleBin *m_recycleBin;
}; };
#endif // STANDARDSERVICEROOT_H #endif // STANDARDSERVICEROOT_H

View File

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

View File

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