Work on feeeds.

This commit is contained in:
Martin Rotter 2013-12-13 20:48:45 +01:00
parent ad107df537
commit cac5368480
21 changed files with 299 additions and 38 deletions

View File

@ -254,6 +254,7 @@ set(APP_SOURCES
src/gui/messagesview.cpp
src/gui/statusbar.cpp
src/gui/messagebox.cpp
src/gui/iconfactory.cpp
# CORE sources.
src/core/debugging.cpp

View File

@ -16,7 +16,7 @@ CREATE TABLE IF NOT EXISTS Categories (
description TEXT,
date_created TEXT NOT NULL CHECK (date_created != ''),
icon BLOB,
type INTEGER NOT NULL,
type INTEGER NOT NULL,
FOREIGN KEY (parent_id) REFERENCES Categories (id)
);
@ -33,7 +33,7 @@ CREATE TABLE IF NOT EXISTS Feeds (
encoding TEXT NOT NULL CHECK (encoding != ''),
url TEXT NOT NULL UNIQUE CHECK (url != ''),
language TEXT,
type INTEGER NOT NULL
type INTEGER NOT NULL CHECK (type > 0)
);
-- !
DROP TABLE IF EXISTS FeedsData;
@ -64,3 +64,10 @@ CREATE TABLE IF NOT EXISTS Messages (
FOREIGN KEY (feed) REFERENCES Feeds (id)
);
-- !
INSERT INTO Feeds (title, date_created, category, encoding, url, type) VALUES ('abcd', '1994-11-05T08:15:30-05:00', -1, 'UTF-8', 'http://www.seznam1.cz', 1);
INSERT INTO Feeds (title, date_created, category, encoding, url, type) VALUES ('qqq', '1994-11-05T08:15:30-05:00', 0, 'UTF-8', 'http://www.seznam2.cz', 1);
INSERT INTO Feeds (title, date_created, category, encoding, url, type) VALUES ('vwvw', '1994-11-05T08:15:30-05:00', 1, 'UTF-8', 'http://www.seznam3.cz', 1);
INSERT INTO Feeds (title, date_created, category, encoding, url, type) VALUES ('tttt', '1994-11-05T08:15:30-05:00', 1, 'UTF-8', 'http://www.seznam4.cz', 1);
INSERT INTO Categories (id, parent_id, title, date_created, type) VALUES (0, -1, 'aaa', '1994-11-05T08:15:30-05:00', 0);
INSERT INTO Categories (id, parent_id, title, date_created, type) VALUES (1, 0, 'bbb', '1994-11-05T08:15:30-05:00', 0);

View File

@ -135,11 +135,6 @@ QSqlDatabase DatabaseFactory::addConnection(const QString &connection_name) {
// Setup database file path.
database.setDatabaseName(db_file.fileName());
if (!database.open()) {
qFatal("Database was NOT opened. Delivered error message: '%s'",
qPrintable(database.lastError().text()));
}
return database;
}
}

View File

@ -65,9 +65,30 @@
#define MSG_DB_DUPDATED_INDEX 9
#define MSG_DB_CONTENTS_INDEX 10
// Indexes of columns as they are DEFINED IN THE TABLE for CATEGORIES.
#define CAT_DB_ID_INDEX 0
#define CAT_DB_PARENT_ID_INDEX 1
#define CAT_DB_TITLE_INDEX 2
#define CAT_DB_DESCRIPTION_INDEX 3
#define CAT_DB_DCREATED_INDEX 4
#define CAT_DB_ICON_INDEX 5
#define CAT_DB_TYPE_INDEX 6
// Indexes of columns as they are DEFINED IN THE TABLE for FEEDS.
#define FDS_DB_ID_INDEX 0
#define FDS_DB_TITLE_INDEX 1
#define FDS_DB_DESCRIPTION_INDEX 2
#define FDS_DB_DCREATED_INDEX 3
#define FDS_DB_ICON_INDEX 4
#define FDS_DB_CATEGORY_INDEX 5
#define FDS_DB_ENCODING_INDEX 6
#define FDS_DB_URL_INDEX 7
#define FDS_DB_LANGUAGE_INDEX 8
#define FDS_DB_TYPE_INDEX 9
// Indexes of columns for feed models.
#define FDS_TITLE_INDEX 0
#define FDS_COUNTS_INDEX 1
#define FDS_MODEL_TITLE_INDEX 0
#define FDS_MODEL_COUNTS_INDEX 1
#if defined(Q_OS_LINUX)
#define APP_DESKTOP_ENTRY_PATH "@DESKTOP_ENTRY_PATH@"

View File

@ -1,11 +1,19 @@
#include <QSqlError>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QPair>
#include "core/feedsmodel.h"
#include "core/feedsmodelstandardcategory.h"
#include "core/feedsmodelstandardfeed.h"
#include "core/defs.h"
#include "core/databasefactory.h"
#include "gui/iconthemefactory.h"
FeedsModel::FeedsModel(QObject *parent) : QAbstractItemModel(parent) {
setObjectName("FeedsModel");
m_rootItem = new FeedsModelRootItem();
m_countsIcon = IconThemeFactory::getInstance()->fromTheme("mail-mark-unread");
@ -13,6 +21,8 @@ FeedsModel::FeedsModel(QObject *parent) : QAbstractItemModel(parent) {
m_tooltipData << tr("Titles of feeds/categories.") <<
tr("Counts of unread/all meesages.");
loadFromDatabase();
FeedsModelStandardCategory *cat1 = new FeedsModelStandardCategory();
FeedsModelStandardCategory *cat2 = new FeedsModelStandardCategory();
FeedsModelStandardFeed *feed1 = new FeedsModelStandardFeed();
@ -61,8 +71,8 @@ QVariant FeedsModel::headerData(int section,
switch (role) {
case Qt::DisplayRole:
if (section == FDS_TITLE_INDEX) {
return m_headerData.at(FDS_TITLE_INDEX);
if (section == FDS_MODEL_TITLE_INDEX) {
return m_headerData.at(FDS_MODEL_TITLE_INDEX);
}
else {
return QVariant();
@ -72,7 +82,7 @@ QVariant FeedsModel::headerData(int section,
return m_tooltipData.at(section);
case Qt::DecorationRole:
if (section == FDS_COUNTS_INDEX) {
if (section == FDS_MODEL_COUNTS_INDEX) {
return m_countsIcon;
}
else {
@ -149,3 +159,71 @@ int FeedsModel::columnCount(const QModelIndex &parent) const {
return m_rootItem->columnCount();
}
}
void FeedsModel::loadFromDatabase() {
QSqlDatabase database = DatabaseFactory::getInstance()->addConnection(objectName());
QList<QPair<int, FeedsModelCategory*> > categories;
QList<QPair<int, FeedsModelFeed*> > feeds;
if (!database.open()) {
qFatal("Database was NOT opened. Delivered error message: '%s'",
qPrintable(database.lastError().text()));
}
QSqlQuery query_categories = database.exec("SELECT * FROM Categories;");
if (query_categories.lastError().isValid()) {
qFatal("Query for obtaining categories failed.");
}
while (query_categories.next()) {
// Process this category.
FeedsModelCategory::Type type = static_cast<FeedsModelCategory::Type>(query_categories.value(CAT_DB_TYPE_INDEX).toInt());
switch (type) {
case FeedsModelCategory::Standard: {
QPair<int, FeedsModelCategory*> pair;
pair.first = query_categories.value(CAT_DB_PARENT_ID_INDEX).toInt();
pair.second = FeedsModelStandardCategory::loadFromRecord(query_categories.record());
categories << pair;
break;
}
case FeedsModelCategory::Feedly:
case FeedsModelCategory::TinyTinyRss:
default:
// NOTE: Not yet implemented.
break;
}
}
// All categories are now loaded.
QSqlQuery query_feeds = database.exec("SELECT * FROM Feeds;");
if (query_feeds.lastError().isValid()) {
qFatal("Query for obtaining feeds failed.");
}
while (query_feeds.next()) {
// Process this feed.
FeedsModelFeed::Type type = static_cast<FeedsModelFeed::Type>(query_feeds.value(FDS_DB_TYPE_INDEX).toInt());
switch (type) {
case FeedsModelFeed::StandardAtom:
case FeedsModelFeed::StandardRdf:
case FeedsModelFeed::StandardRss: {
QPair<int, FeedsModelFeed*> pair;
pair.first = query_feeds.value(FDS_DB_CATEGORY_INDEX).toInt();
// TODO: pokračovat tady, ve stejnym stylu jako u kategorii
break;
}
default:
break;
}
}
}

View File

@ -22,6 +22,8 @@ class FeedsModel : public QAbstractItemModel {
int columnCount(const QModelIndex &parent) const;
int rowCount(const QModelIndex &parent) const;
void loadFromDatabase();
private:
FeedsModelRootItem *m_rootItem;
QList<QString> m_headerData;

View File

@ -27,3 +27,11 @@ int FeedsModelCategory::countOfUnreadMessages() const {
return total_count;
}
FeedsModelCategory:: Type FeedsModelCategory::type() const {
return m_type;
}
void FeedsModelCategory::setType(const Type &type) {
m_type = type;
}

View File

@ -8,6 +8,14 @@
// NOTE: This class should be derived to create PARTICULAR category types.
class FeedsModelCategory : public FeedsModelRootItem {
public:
// Describes possible types of categories.
// NOTE: This is equivavelnt to Categories(type).
enum Type {
Standard = 0,
Feedly = 1,
TinyTinyRss = 2
};
// Constructors and destructors
explicit FeedsModelCategory(FeedsModelRootItem *parent_item = NULL);
virtual ~FeedsModelCategory();
@ -15,6 +23,12 @@ class FeedsModelCategory : public FeedsModelRootItem {
int countOfAllMessages() const;
int countOfUnreadMessages() const;
Type type() const;
void setType(const Type &type);
protected:
Type m_type;
};
#endif // FEEDSMODELCLASSICCATEGORY_H

View File

@ -13,6 +13,7 @@ int FeedsModelFeed::childCount() const {
return 0;
}
int FeedsModelFeed::countOfAllMessages() const {
return m_totalCount;
}
@ -20,3 +21,20 @@ int FeedsModelFeed::countOfAllMessages() const {
int FeedsModelFeed::countOfUnreadMessages() const {
return m_unreadCount;
}
void FeedsModelFeed::setCountOfAllMessages(int count_total) {
m_totalCount = count_total;
}
void FeedsModelFeed::setCountOfUnreadMessages(int count_unread) {
m_unreadCount = count_unread;
}
FeedsModelFeed::Type FeedsModelFeed::type() const {
return m_type;
}
void FeedsModelFeed::setType(const Type &type) {
m_type = type;
}

View File

@ -22,10 +22,16 @@ class FeedsModelFeed : public FeedsModelRootItem {
int childCount() const;
int countOfUnreadMessages() const;
int countOfAllMessages() const;
int countOfUnreadMessages() const;
void setCountOfAllMessages(int count_total);
void setCountOfUnreadMessages(int count_unread);
Type type() const;
void setType(const Type &type);
protected:
Type m_type;
int m_totalCount;
int m_unreadCount;
};

View File

@ -64,3 +64,11 @@ int FeedsModelRootItem::countOfUnreadMessages() const {
void FeedsModelRootItem::setIcon(const QIcon &icon) {
m_icon = icon;
}
int FeedsModelRootItem::id() const {
return m_id;
}
void FeedsModelRootItem::setId(int id) {
m_id = id;
}

View File

@ -27,7 +27,11 @@ class FeedsModelRootItem {
void setIcon(const QIcon &icon);
int id() const;
void setId(int id);
protected:
int m_id;
QIcon m_icon;
QList<FeedsModelRootItem*> m_childItems;
FeedsModelRootItem *m_parentItem;

View File

@ -1,11 +1,14 @@
#include <QVariant>
#include "core/textfactory.h"
#include "core/feedsmodelstandardcategory.h"
#include "core/defs.h"
#include "gui/iconfactory.h"
FeedsModelStandardCategory::FeedsModelStandardCategory(FeedsModelRootItem *parent_item)
: FeedsModelCategory(parent_item) {
m_type = Standard;
}
FeedsModelStandardCategory::~FeedsModelStandardCategory() {
@ -15,20 +18,20 @@ FeedsModelStandardCategory::~FeedsModelStandardCategory() {
QVariant FeedsModelStandardCategory::data(int column, int role) const {
switch (role) {
case Qt::DisplayRole:
if (column == FDS_TITLE_INDEX) {
if (column == FDS_MODEL_TITLE_INDEX) {
return "m_title";
}
else if (column == FDS_COUNTS_INDEX) {
else if (column == FDS_MODEL_COUNTS_INDEX) {
return QString("(%1)").arg(QString::number(countOfUnreadMessages()));
}
case Qt::DecorationRole:
return column == FDS_TITLE_INDEX ?
return column == FDS_MODEL_TITLE_INDEX ?
m_icon :
QVariant();
case Qt::TextAlignmentRole:
if (column == FDS_COUNTS_INDEX) {
if (column == FDS_MODEL_COUNTS_INDEX) {
return Qt::AlignCenter;
}
else {
@ -39,3 +42,43 @@ QVariant FeedsModelStandardCategory::data(int column, int role) const {
return QVariant();
}
}
FeedsModelStandardCategory *FeedsModelStandardCategory::loadFromRecord(const QSqlRecord &record) {
FeedsModelStandardCategory *category = new FeedsModelStandardCategory(NULL);
category->setId(record.value(CAT_DB_ID_INDEX).toInt());
category->setTitle(record.value(CAT_DB_TITLE_INDEX).toString());
category->setDescription(record.value(CAT_DB_DESCRIPTION_INDEX).toString());
category->setCreationDate(QDateTime::fromString(record.value(CAT_DB_DCREATED_INDEX).toString(),
Qt::ISODate));
category->setIcon(IconFactory::fromByteArray(record.value(CAT_DB_ICON_INDEX).toByteArray()));
return category;
}
QString FeedsModelStandardCategory::title() const {
return m_title;
}
void FeedsModelStandardCategory::setTitle(const QString &title) {
m_title = title;
}
QString FeedsModelStandardCategory::description() const {
return m_description;
}
void FeedsModelStandardCategory::setDescription(const QString &description) {
m_description = description;
}
QDateTime FeedsModelStandardCategory::creationDate() const {
return m_creationDate;
}
void FeedsModelStandardCategory::setCreationDate(const QDateTime &creation_date) {
m_creationDate = creation_date;
}

View File

@ -1,6 +1,9 @@
#ifndef FEEDSMODELSTANDARDCATEGORY_H
#define FEEDSMODELSTANDARDCATEGORY_H
#include <QSqlRecord>
#include <QDateTime>
#include "core/feedsmodelcategory.h"
@ -16,6 +19,23 @@ class FeedsModelStandardCategory : public FeedsModelCategory {
virtual ~FeedsModelStandardCategory();
QVariant data(int column, int role) const;
static FeedsModelStandardCategory *loadFromRecord(const QSqlRecord &record);
QString title() const;
void setTitle(const QString &title);
QString description() const;
void setDescription(const QString &description);
QDateTime creationDate() const;
void setCreationDate(const QDateTime &creation_date);
private:
QDateTime m_creationDate;
QString m_title;
QString m_description;
};
#endif // FEEDSMODELSTANDARDCATEGORY_H

View File

@ -24,20 +24,20 @@ void FeedsModelStandardFeed::setTitle(const QString &title) {
QVariant FeedsModelStandardFeed::data(int column, int role) const {
switch (role) {
case Qt::DisplayRole:
if (column == FDS_TITLE_INDEX) {
if (column == FDS_MODEL_TITLE_INDEX) {
return m_title;
}
else if (column == FDS_COUNTS_INDEX) {
else if (column == FDS_MODEL_COUNTS_INDEX) {
return QString("(%1)").arg(QString::number(countOfUnreadMessages()));
}
case Qt::DecorationRole:
return column == FDS_TITLE_INDEX ?
return column == FDS_MODEL_TITLE_INDEX ?
m_icon :
QVariant();
case Qt::TextAlignmentRole:
if (column == FDS_COUNTS_INDEX) {
if (column == FDS_MODEL_COUNTS_INDEX) {
return Qt::AlignCenter;
}
else {

View File

@ -25,7 +25,6 @@ MessagesModel::MessagesModel(QObject *parent)
// via model, but DIRECT SQL calls are used to do persistent messages.
setEditStrategy(QSqlTableModel::OnManualSubmit);
setTable("Messages");
loadMessages(QList<int>());
}
@ -146,12 +145,6 @@ QVariant MessagesModel::data(const QModelIndex &idx, int role) const {
return record(idx.row()).value(MSG_DB_READ_INDEX).toInt() == 1 ?
m_normalFont :
m_boldFont;
/*
case Qt::BackgroundRole:
return record(idx.row()).value(MSG_DB_DELETED_INDEX).toInt() == 1 ?
QColor(255, 0, 0, 100) :
QVariant();
*/
case Qt::DecorationRole: {
int index_column = idx.column();

View File

@ -10,9 +10,6 @@
TextFactory::TextFactory() {
}
TextFactory::~TextFactory() {
}
QDateTime TextFactory::parseDateTime(const QString &date_time) {
QString date = date_time.simplified();
QDateTime dt;

View File

@ -11,8 +11,6 @@ class TextFactory {
explicit TextFactory();
public:
virtual ~TextFactory();
// Tries to parse input textual date/time representation.
// Returns invalid date/time if processing fails.
static QDateTime parseDateTime(const QString &date_time);

View File

@ -21,12 +21,12 @@ FeedsView::~FeedsView() {
void FeedsView::setupAppearance() {
#if QT_VERSION >= 0x050000
// Setup column resize strategies.
header()->setSectionResizeMode(FDS_TITLE_INDEX, QHeaderView::Stretch);
header()->setSectionResizeMode(FDS_COUNTS_INDEX, QHeaderView::ResizeToContents);
header()->setSectionResizeMode(FDS_MODEL_TITLE_INDEX, QHeaderView::Stretch);
header()->setSectionResizeMode(FDS_MODEL_COUNTS_INDEX, QHeaderView::ResizeToContents);
#else
// Setup column resize strategies.
header()->setResizeMode(FDS_TITLE_INDEX, QHeaderView::Stretch);
header()->setResizeMode(FDS_COUNTS_INDEX, QHeaderView::ResizeToContents);
header()->setResizeMode(FDS_MODEL_TITLE_INDEX, QHeaderView::Stretch);
header()->setResizeMode(FDS_MODEL_COUNTS_INDEX, QHeaderView::ResizeToContents);
#endif
header()->setStretchLastSection(false);

31
src/gui/iconfactory.cpp Normal file
View File

@ -0,0 +1,31 @@
#include <QBuffer>
#include "gui/iconfactory.h"
IconFactory::IconFactory() {
}
QIcon IconFactory::fromByteArray(QByteArray array) {
QIcon icon;
QBuffer buffer(&array);
buffer.open(QIODevice::ReadOnly);
QDataStream in(&buffer);
in >> icon;
buffer.close();
return icon;
}
QByteArray IconFactory::toByteArray(const QIcon &icon) {
QByteArray array;
QBuffer buffer(&array);
buffer.open(QIODevice::WriteOnly);
QDataStream out(&buffer);
out << icon;
buffer.close();
return array;
}

17
src/gui/iconfactory.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef ICONFACTORY_H
#define ICONFACTORY_H
#include <QIcon>
class IconFactory {
private:
IconFactory();
public:
static QIcon fromByteArray(QByteArray array);
static QByteArray toByteArray(const QIcon &icon);
};
#endif // ICONFACTORY_H