From 1b4faa4c97a0584678d576dbe6abe4d5e38352df Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sat, 13 Sep 2014 16:11:53 +0200 Subject: [PATCH] Very experimental trash bin. --- CMakeLists.txt | 2 + .../icons/mini-kfaenza/folder-recycle-bin.png | Bin 0 -> 4967 bytes src/core/feedsmodel.cpp | 3 + src/core/feedsmodelrecyclebin.cpp | 87 ++++++++++++++++++ src/core/feedsmodelrecyclebin.h | 23 +++++ src/core/feedsmodelrootitem.cpp | 1 - src/core/feedsmodelrootitem.h | 7 +- src/core/messagesmodel.cpp | 15 ++- src/definitions/definitions.h.in | 1 + src/gui/feedsview.cpp | 38 ++++++-- 10 files changed, 159 insertions(+), 18 deletions(-) create mode 100644 resources/graphics/icons/mini-kfaenza/folder-recycle-bin.png create mode 100644 src/core/feedsmodelrecyclebin.cpp create mode 100644 src/core/feedsmodelrecyclebin.h diff --git a/CMakeLists.txt b/CMakeLists.txt index aad1d82bf..c99512ae7 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -381,6 +381,7 @@ set(APP_SOURCES src/core/parsingfactory.cpp src/core/feeddownloader.cpp src/core/feedsimportexportmodel.cpp + src/core/feedsmodelrecyclebin.cpp # NETWORK-WEB sources. src/network-web/basenetworkaccessmanager.cpp @@ -457,6 +458,7 @@ set(APP_HEADERS src/core/feedsproxymodel.h src/core/feeddownloader.h src/core/feedsimportexportmodel.h + src/core/feedsmodelrecyclebin.h # NETWORK-WEB headers. src/network-web/webpage.h diff --git a/resources/graphics/icons/mini-kfaenza/folder-recycle-bin.png b/resources/graphics/icons/mini-kfaenza/folder-recycle-bin.png new file mode 100644 index 0000000000000000000000000000000000000000..3bf56a1d3499fb0ceaaa6598cb19ffadb0c84350 GIT binary patch literal 4967 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 literal 0 HcmV?d00001 diff --git a/src/core/feedsmodel.cpp b/src/core/feedsmodel.cpp index 85d12de9e..b4d399e15 100755 --- a/src/core/feedsmodel.cpp +++ b/src/core/feedsmodel.cpp @@ -20,6 +20,7 @@ #include "definitions/definitions.h" #include "core/feedsmodelcategory.h" #include "core/feedsmodelfeed.h" +#include "core/feedsmodelrecyclebin.h" #include "core/feedsimportexportmodel.h" #include "miscellaneous/textfactory.h" #include "miscellaneous/databasefactory.h" @@ -690,6 +691,8 @@ void FeedsModel::loadFromDatabase() { // All data are now obtained, lets create the hierarchy. assembleCategories(categories); assembleFeeds(feeds); + + m_rootItem->appendChild(new FeedsModelRecycleBin()); } QList FeedsModel::feedsForIndex(const QModelIndex &index) { diff --git a/src/core/feedsmodelrecyclebin.cpp b/src/core/feedsmodelrecyclebin.cpp new file mode 100644 index 000000000..c29219664 --- /dev/null +++ b/src/core/feedsmodelrecyclebin.cpp @@ -0,0 +1,87 @@ +#include "core/feedsmodelrecyclebin.h" + +#include "miscellaneous/application.h" +#include "miscellaneous/iconfactory.h" + + +FeedsModelRecycleBin::FeedsModelRecycleBin(FeedsModelRootItem *parent) : FeedsModelRootItem(parent) { + m_kind = FeedsModelRootItem::RecycleBin; + m_icon = qApp->icons()->fromTheme("folder-recycle-bin"); + m_id = ID_RECYCLE_BIN; + m_title = tr("Recycle bin"); + m_description = tr("Recycle bin contains all deleted messages from all feeds."); + m_creationDate = QDateTime::currentDateTime(); +} + +FeedsModelRecycleBin::~FeedsModelRecycleBin() { +} + + +int FeedsModelRecycleBin::childCount() const { + return 0; +} + +void FeedsModelRecycleBin::appendChild(FeedsModelRootItem *child) { + Q_UNUSED(child) +} + +int FeedsModelRecycleBin::countOfUnreadMessages() const { + return 0; +} + +int FeedsModelRecycleBin::countOfAllMessages() const { + return 0; +} + + +QVariant FeedsModelRecycleBin::data(int column, int role) const { + switch (role) { + case Qt::DisplayRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return m_title; + } + else if (column == FDS_MODEL_COUNTS_INDEX) { + return qApp->settings()->value(APP_CFG_FEEDS, + "count_format", + "(%unread)").toString() + .replace("%unread", QString::number(countOfUnreadMessages())) + .replace("%all", QString::number(countOfAllMessages())); + } + else { + return QVariant(); + } + + case Qt::EditRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return m_title; + } + else if (column == FDS_MODEL_COUNTS_INDEX) { + return countOfUnreadMessages(); + } + else { + return QVariant(); + } + + case Qt::FontRole: + return countOfUnreadMessages() > 0 ? m_boldFont : m_normalFont; + + case Qt::DecorationRole: + if (column == FDS_MODEL_TITLE_INDEX) { + return m_icon; + } + else { + return QVariant(); + } + + case Qt::TextAlignmentRole: + if (column == FDS_MODEL_COUNTS_INDEX) { + return Qt::AlignCenter; + } + else { + return QVariant(); + } + + default: + return QVariant(); + } +} diff --git a/src/core/feedsmodelrecyclebin.h b/src/core/feedsmodelrecyclebin.h new file mode 100644 index 000000000..c3e624d32 --- /dev/null +++ b/src/core/feedsmodelrecyclebin.h @@ -0,0 +1,23 @@ +#ifndef FEEDSMODELRECYCLEBIN_H +#define FEEDSMODELRECYCLEBIN_H + +#include "core/feedsmodelrootitem.h" + +#include + + +class FeedsModelRecycleBin : public FeedsModelRootItem { + Q_DECLARE_TR_FUNCTIONS(FeedsModelRecycleBin) + + public: + explicit FeedsModelRecycleBin(FeedsModelRootItem *parent = NULL); + virtual ~FeedsModelRecycleBin(); + + int childCount() const; + void appendChild(FeedsModelRootItem *child); + int countOfUnreadMessages() const; + int countOfAllMessages() const; + QVariant data(int column, int role) const; +}; + +#endif // FEEDSMODELRECYCLEBIN_H diff --git a/src/core/feedsmodelrootitem.cpp b/src/core/feedsmodelrootitem.cpp index 6189e2922..71bd81a74 100755 --- a/src/core/feedsmodelrootitem.cpp +++ b/src/core/feedsmodelrootitem.cpp @@ -38,7 +38,6 @@ FeedsModelRootItem::FeedsModelRootItem(FeedsModelRootItem *parent_item) FeedsModelRootItem::~FeedsModelRootItem() { qDebug("Destroying FeedsModelRootItem instance."); - qDeleteAll(m_childItems); } diff --git a/src/core/feedsmodelrootitem.h b/src/core/feedsmodelrootitem.h index 266b8b04f..65614fd84 100755 --- a/src/core/feedsmodelrootitem.h +++ b/src/core/feedsmodelrootitem.h @@ -31,9 +31,10 @@ class FeedsModelRootItem { public: // Describes the kind of the item. enum Kind { - RootItem = 1001, - Feed = 1002, - Category = 1003 + RootItem = 1001, + RecycleBin = 1002, + Feed = 1003, + Category = 1004 }; // Constructors and destructors. diff --git a/src/core/messagesmodel.cpp b/src/core/messagesmodel.cpp index 5507083e6..6882517f0 100755 --- a/src/core/messagesmodel.cpp +++ b/src/core/messagesmodel.cpp @@ -31,7 +31,7 @@ MessagesModel::MessagesModel(QObject *parent) : QSqlTableModel(parent, qApp->database()->connection("MessagesModel", - DatabaseFactory::FromSettings)) { + DatabaseFactory::FromSettings)) { setObjectName("MessagesModel"); setupFonts(); setupIcons(); @@ -70,13 +70,18 @@ void MessagesModel::setupFonts() { void MessagesModel::loadMessages(const QList feed_ids) { m_currentFeeds = feed_ids; - QString assembled_ids = textualFeeds().join(", "); + if (feed_ids.size() == 1 && feed_ids[0] == ID_RECYCLE_BIN) { + setFilter("is_deleted = 1"); + } + else { + QString assembled_ids = textualFeeds().join(", "); + + setFilter(QString("feed IN (%1) AND is_deleted = 0").arg(assembled_ids)); + qDebug("Loading messages from feeds: %s.", qPrintable(assembled_ids)); + } - setFilter(QString("feed IN (%1) AND is_deleted = 0").arg(assembled_ids)); select(); fetchAll(); - - qDebug("Loading messages from feeds: %s.", qPrintable(assembled_ids)); } void MessagesModel::filterMessages(MessagesModel::DisplayFilter filter) { diff --git a/src/definitions/definitions.h.in b/src/definitions/definitions.h.in index 9f8bb6492..b0b5b19f0 100755 --- a/src/definitions/definitions.h.in +++ b/src/definitions/definitions.h.in @@ -47,6 +47,7 @@ #define MAX_ZOOM_FACTOR 10.0 #define ICON_SIZE_SETTINGS 16 #define NO_PARENT_CATEGORY -1 +#define ID_RECYCLE_BIN -2 #define TRAY_ICON_BUBBLE_TIMEOUT 20000 #define KEY_MESSAGES_VIEW "messages_view_column_" #define CLOSE_LOCK_TIMEOUT 3000 diff --git a/src/gui/feedsview.cpp b/src/gui/feedsview.cpp index d4afae555..f86fc8dc5 100755 --- a/src/gui/feedsview.cpp +++ b/src/gui/feedsview.cpp @@ -347,8 +347,8 @@ void FeedsView::deleteSelectedItem() { } if (MessageBox::show(qApp->mainForm(), QMessageBox::Question, tr("Deleting feed or category"), - tr("You are about to delete selected feed or category."), tr("Do you really want to delete selected item?"), - QString(), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::No) { + tr("You are about to delete selected feed or category."), tr("Do you really want to delete selected item?"), + QString(), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::No) { // User changed his mind. qApp->closeLock()->unlock(); return; @@ -545,6 +545,16 @@ void FeedsView::selectionChanged(const QItemSelection &selected, m_selectedFeeds << feed->id(); } + if (m_selectedFeeds.isEmpty() && selectionModel()->selectedIndexes().size() > 0) { + QModelIndex selected_index = selectionModel()->selectedIndexes().at(0); + QModelIndex mapped_index = model()->mapToSource(selected_index); + FeedsModelRootItem *item = sourceModel()->itemForIndex(mapped_index); + + if (item->kind() == FeedsModelRootItem::RecycleBin) { + m_selectedFeeds.append(ID_RECYCLE_BIN); + } + } + emit feedsSelected(m_selectedFeeds); } @@ -557,14 +567,24 @@ void FeedsView::keyPressEvent(QKeyEvent *event) { } void FeedsView::contextMenuEvent(QContextMenuEvent *event) { - if (indexAt(event->pos()).isValid()) { - // Display context menu for categories. - if (m_contextMenuCategoriesFeeds == NULL) { - // Context menu is not initialized, initialize. - initializeContextMenuCategoriesFeeds(); - } + QModelIndex clicked_index = indexAt(event->pos()); - m_contextMenuCategoriesFeeds->exec(event->globalPos()); + if (clicked_index.isValid()) { + QModelIndex mapped_index = model()->mapToSource(clicked_index); + FeedsModelRootItem *clicked_item = sourceModel()->itemForIndex(mapped_index); + + if (clicked_item->kind() == FeedsModelRootItem::Category || clicked_item->kind() == FeedsModelRootItem::Feed) { + // Display context menu for categories. + if (m_contextMenuCategoriesFeeds == NULL) { + // Context menu is not initialized, initialize. + initializeContextMenuCategoriesFeeds(); + } + + m_contextMenuCategoriesFeeds->exec(event->globalPos()); + } + else if (clicked_item->kind() == FeedsModelRootItem::RecycleBin) { + // TODO: Display context menu for recycle bin. + } } else { // Display menu for empty space.