This commit is contained in:
Martin Rotter 2013-11-18 21:45:15 +01:00
parent d7dd476af8
commit 1c97bb852c
8 changed files with 153 additions and 212 deletions

View File

@ -14,6 +14,10 @@ option(USE_QT_5 "Use Qt 5 for building" OFF)
message(STATUS "[${APP_LOW_NAME}] Welcome to ${APP_NAME} compilation process.") message(STATUS "[${APP_LOW_NAME}] Welcome to ${APP_NAME} compilation process.")
message(STATUS "[${APP_LOW_NAME}] Compilation process begins right now.") message(STATUS "[${APP_LOW_NAME}] Compilation process begins right now.")
if(USE_QT_5 EQUAL false)
message(FATAL_ERROR "[${APP_LOW_NAME}] Only Qt 5 is supported now.")
endif(USE_QT_5 EQUAL false)
# Setup name for executable file. # Setup name for executable file.
if(APPLE) if(APPLE)
set(EXE_NAME ${APP_UP_NAME}) set(EXE_NAME ${APP_UP_NAME})

View File

@ -2,13 +2,13 @@
#define DEFS_H #define DEFS_H
#include <QtGlobal> #include <QtGlobal>
#if QT_VERSION >= 0x050000 #if QT_VERSION >= 0x050000
#include <qwebkitglobal.h> #include <qwebkitglobal.h>
#elif QT_VERSION >= 0x040600 #elif QT_VERSION >= 0x040600
#include <qwebkitversion.h> #include <qwebkitversion.h>
#endif #endif
#define CMAKE_VERSION "@CMAKE_VERSION@" #define CMAKE_VERSION "@CMAKE_VERSION@"
#define CMAKE_SYSTEM "@CMAKE_SYSTEM@" #define CMAKE_SYSTEM "@CMAKE_SYSTEM@"

View File

@ -11,102 +11,132 @@
MessagesModel::MessagesModel(QObject *parent) MessagesModel::MessagesModel(QObject *parent)
: QAbstractItemModel(parent) { : QSqlTableModel(parent, DatabaseFactory::getInstance()->addConnection("MessagesModel")) {
setObjectName("MessagesModel"); setObjectName("MessagesModel");
// TODO: Separovat do samostatné skupiny metod.
// Bude potřeba metoda "loadFeed(int feed_id)"
// a v te se bude volat SELECT .... FROM Messages WHERE id IN (feed_id,feed_id2)
// a tak dále.
QSqlDatabase d = DatabaseFactory::getInstance()->addConnection("MessagesModel2");
QSqlQuery prikaz = d.exec("SELECT id, read, deleted, important, feed, "
"title, url, author, date_created, "
"date_updated, contents FROM Messages;");
// TODO: Oddělit toto do samostatné metody setupIcons(),
// aby bylo možno měnit ikony dynamicky.
m_favoriteIcon = IconThemeFactory::getInstance()->fromTheme("mail-mark-important");
m_readIcon = IconThemeFactory::getInstance()->fromTheme("mail-mark-read");
m_unreadIcon = IconThemeFactory::getInstance()->fromTheme("mail-mark-unread");
// Prepare correct columns mappings.
m_columnMappings.insert(MSG_MODEL_READ_INDEX, MSG_DB_READ_INDEX);
m_columnMappings.insert(MSG_MODEL_IMPORTANT_INDEX, MSG_DB_IMPORTANT_INDEX);
m_columnMappings.insert(MSG_MODEL_TITLE_INDEX, MSG_DB_TITLE_INDEX);
m_columnMappings.insert(MSG_MODEL_AUTHOR_INDEX, MSG_DB_AUTHOR_INDEX);
m_columnMappings.insert(MSG_MODEL_DCREATED_INDEX, MSG_DB_DCREATED_INDEX);
m_columnMappings.insert(MSG_MODEL_DUPDATED_INDEX, MSG_DB_DUPDATED_INDEX);
QList<Message> list;
while (prikaz.next()) {
Message mess;
mess.m_data.append(prikaz.value(MSG_DB_ID_INDEX).toInt());
mess.m_data.append(prikaz.value(MSG_DB_READ_INDEX).toInt());
mess.m_data.append(prikaz.value(MSG_DB_DELETED_INDEX).toInt());
mess.m_data.append(prikaz.value(MSG_DB_IMPORTANT_INDEX).toInt());
mess.m_data.append(prikaz.value(MSG_DB_FEED_INDEX).toInt());
mess.m_data.append(prikaz.value(MSG_DB_TITLE_INDEX).toString());
mess.m_data.append(prikaz.value(MSG_DB_URL_INDEX).toString());
mess.m_data.append(prikaz.value(MSG_DB_AUTHOR_INDEX).toString());
mess.m_data.append(prikaz.value(MSG_DB_DCREATED_INDEX).toString());
mess.m_data.append(prikaz.value(MSG_DB_DUPDATED_INDEX).toString());
mess.m_data.append(prikaz.value(MSG_DB_CONTENTS_INDEX).toString());
list.append(mess);
}
m_messages = list;
setupFonts(); setupFonts();
setupIcons();
setupHeaderData(); setupHeaderData();
// Set desired table and edit strategy.
setEditStrategy(QSqlTableModel::OnFieldChange);
setTable("Messages");
loadMessages(QList<int>());
} }
MessagesModel::~MessagesModel() { MessagesModel::~MessagesModel() {
qDebug("Destroying MessagesModel instance."); qDebug("Destroying MessagesModel instance.");
} }
void MessagesModel::setupIcons() {
m_favoriteIcon = IconThemeFactory::getInstance()->fromTheme("mail-mark-important");
m_readIcon = IconThemeFactory::getInstance()->fromTheme("mail-mark-read");
m_unreadIcon = IconThemeFactory::getInstance()->fromTheme("mail-mark-unread");
}
void MessagesModel::fetchAll() {
while (canFetchMore()) {
fetchMore();
}
}
void MessagesModel::setupFonts() { void MessagesModel::setupFonts() {
m_normalFont = QtSingleApplication::font("MessagesView"); m_normalFont = QtSingleApplication::font("MessagesView");
m_boldFont = m_normalFont; m_boldFont = m_normalFont;
m_boldFont.setBold(true); m_boldFont.setBold(true);
} }
void MessagesModel::loadMessages(const QList<int> feed_ids) {
// TODO: Doplnit "AND deleted = 0"
// Conversion of parameter.
QStringList stringy_ids;
stringy_ids.reserve(feed_ids.count());
foreach (int feed_id, feed_ids) {
stringy_ids.append(QString::number(feed_id));
}
// TODO: časem povolit.
//setFilter(QString("feed IN (%1) ").arg(stringy_ids.join(',')));
select();
fetchAll();
}
void MessagesModel::setupHeaderData() { void MessagesModel::setupHeaderData() {
m_headerData << tr("Read") << tr("Important") << m_headerData << tr("Id") << tr("Read") << tr("Deleted") << tr("Important") <<
tr("Title") << tr("Author") << tr("Feed") << tr("Title") << tr("Url") << tr("Author") <<
tr("Created on") << tr("Updated on"); tr("Created on") << tr("Updated on") << tr("Contents");
} }
Qt::ItemFlags MessagesModel::flags(const QModelIndex &index) const { Qt::ItemFlags MessagesModel::flags(const QModelIndex &idx) const {
Q_UNUSED(index); Q_UNUSED(idx);
// Each item can be selected and is enabled. if (m_isInEditingMode) {
return Qt::ItemIsSelectable | Qt::ItemIsEnabled; // NOTE: Editing of model must be temporarily enabled here.
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
}
else {
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
} }
int MessagesModel::rowCount(const QModelIndex &parent) const { QVariant MessagesModel::data(const QModelIndex &idx, int role) const {
Q_UNUSED(parent); switch (role) {
case Qt::DisplayRole:
case Qt::EditRole:
return QSqlTableModel::data(idx, role);
return m_messages.count(); case Qt::FontRole:
return record(idx.row()).value(MSG_DB_READ_INDEX).toInt() == 1 ?
m_normalFont :
m_boldFont;
case Qt::DecorationRole: {
int index_column = idx.column();
if (index_column == MSG_DB_READ_INDEX) {
return record(idx.row()).value(MSG_DB_READ_INDEX).toInt() == 1 ?
m_readIcon :
m_unreadIcon;
}
else {
return QVariant();
}
}
default:
return QVariant();
}
/*
if (role == Qt::FontRole && idx.column() == 1) {
return record(idx.row()).value(1).toInt() == 1 ? m_normalFont : m_boldFont;
}
else if (role == Qt::DecorationRole && idx.column() == 3) {
if (record(idx.row()).value(1).toInt() == 1) {
return IconThemeFactory::getInstance()->fromTheme("mail-mark-read");
}
else {
return IconThemeFactory::getInstance()->fromTheme("mail-mark-unread");
}
}
else {
return QSqlTableModel::data(idx, role);
}*/
} }
int MessagesModel::columnCount(const QModelIndex &parent) const { bool MessagesModel::setData(const QModelIndex &idx, const QVariant &value, int role) {
Q_UNUSED(parent); if (!idx.isValid()) {
return false;
}
return m_headerData.count(); m_isInEditingMode = true;
} bool set_data_result = QSqlTableModel::setData(idx, value, role);
m_isInEditingMode = false;
QModelIndex MessagesModel::parent(const QModelIndex &child) const { return set_data_result;
Q_UNUSED(child);
return QModelIndex();
}
QModelIndex MessagesModel::index(int row, int column,
const QModelIndex &parent) const {
Q_UNUSED(parent);
return createIndex(row, column);
} }
QVariant MessagesModel::headerData(int section, QVariant MessagesModel::headerData(int section,
@ -114,27 +144,29 @@ QVariant MessagesModel::headerData(int section,
int role) const { int role) const {
Q_UNUSED(orientation); Q_UNUSED(orientation);
// TODO: Ehance this with graphics and other roles.
switch (role) { switch (role) {
case Qt::DisplayRole: case Qt::DisplayRole:
if (section > MSG_MODEL_IMPORTANT_INDEX) { // Display textual headers for all columns except "read" and
// "important" columns.
if (section != MSG_DB_READ_INDEX && section != MSG_DB_IMPORTANT_INDEX) {
return m_headerData.at(section); return m_headerData.at(section);
} }
else { else {
return QVariant(); return QVariant();
} }
// Return RAW data for these roles.
case Qt::ToolTipRole: case Qt::ToolTipRole:
case Qt::EditRole: case Qt::EditRole:
return m_headerData.at(section); return m_headerData.at(section);
// Display icons for "read" and "important" columns.
case Qt::DecorationRole: { case Qt::DecorationRole: {
switch (section) { switch (section) {
case MSG_MODEL_READ_INDEX: case MSG_DB_READ_INDEX:
return m_readIcon; return m_readIcon;
case MSG_MODEL_IMPORTANT_INDEX: case MSG_DB_IMPORTANT_INDEX:
return m_favoriteIcon; return m_favoriteIcon;
default: default:
@ -146,100 +178,3 @@ QVariant MessagesModel::headerData(int section,
return QVariant(); return QVariant();
} }
} }
QVariant MessagesModel::data(int row, int column, int role) const {
return data(index(row, column), role);
}
QVariant MessagesModel::data(const QModelIndex &index, int role) const {
// TODO: Return ISO date on EditRole and human readable date on
// DisplayRole. EditRole is used for sorting (and ISO date can be
// sorted as a string.
switch (role) {
case Qt::EditRole:
// Just return RAW data.
return m_messages.at(index.row()).m_data.at(m_columnMappings[index.column()]);
case Qt::ToolTipRole:
case Qt::DisplayRole: {
int index_column = index.column();
if (index_column > MSG_MODEL_IMPORTANT_INDEX) {
return m_messages.at(index.row()).m_data.at(m_columnMappings[index_column]);
}
else {
return QVariant();
}
}
case Qt::FontRole:
return m_messages.at(index.row()).m_data.at(m_columnMappings[MSG_MODEL_READ_INDEX]).toInt() == 1 ?
m_normalFont :
m_boldFont;
case Qt::DecorationRole: {
int index_column = index.column();
switch (index_column) {
case MSG_MODEL_READ_INDEX:
if (m_messages.at(index.row()).m_data.at(m_columnMappings[index_column]).toInt() == 1) {
return m_readIcon;
}
else {
return m_unreadIcon;
}
case MSG_MODEL_IMPORTANT_INDEX:
if (m_messages.at(index.row()).m_data.at(m_columnMappings[index_column]).toInt() == 1) {
return m_favoriteIcon;
}
default:
return QVariant();
}
}
default:
return QVariant();
}
}
bool MessagesModel::setData(const QModelIndex &index, const QVariant &value,
int role) {
Q_UNUSED(role);
m_messages[index.row()].m_data[m_columnMappings[index.column()]] = value;
QModelIndex left = this->index(index.row(), 0);
QModelIndex right = this->index(index.row(), columnCount() - 1);
emit dataChanged(left, right);
return true;
}
bool MessagesModel::setData(int row, int column, const QVariant &value) {
return setData(index(row, column), value);
}
const Message &MessagesModel::messageAt(int row_index) const {
return m_messages.at(row_index);
}
void MessagesModel::setMessageRead(int row_index, int read) {
//int read_column = fieldIndex("read");
//blockSignals(true);
if (data(row_index, MSG_MODEL_READ_INDEX).toInt() != read) {
// Old "read" status of this message differs from
// the new status, update it.
setData(row_index, MSG_MODEL_READ_INDEX, read);
}
//blockSignals(false);
//submitAll();
//emit dataChanged(index(message_row_index, 0), index(message_row_index, columnCount()));
}

View File

@ -1,21 +1,14 @@
#ifndef MESSAGESMODEL_H #ifndef MESSAGESMODEL_H
#define MESSAGESMODEL_H #define MESSAGESMODEL_H
#include <QAbstractItemModel> #include <QSqlTableModel>
#include <QFont> #include <QFont>
#include <QIcon> #include <QIcon>
#include "core/defs.h"
// Representation of ONE message.
class Message {
private:
QList<QVariant> m_data;
friend class MessagesModel; class MessagesModel : public QSqlTableModel {
friend class WebBrowser;
};
class MessagesModel : public QAbstractItemModel {
Q_OBJECT Q_OBJECT
public: public:
@ -24,46 +17,40 @@ class MessagesModel : public QAbstractItemModel {
virtual ~MessagesModel(); virtual ~MessagesModel();
// Model implementation. // Model implementation.
bool setData(const QModelIndex &idx, const QVariant &value, int role = Qt::EditRole);
// Data accessors/manipulators. QVariant data(const QModelIndex &idx, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const;
QVariant data(const QModelIndex &index, int role) const; Qt::ItemFlags flags(const QModelIndex &idx) const;
QVariant data(int row, int column, int role = Qt::EditRole) const;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
bool setData(int row, int column, const QVariant &value);
Qt::ItemFlags flags(const QModelIndex &index) const;
// Model dimensions. public:
int rowCount(const QModelIndex &parent = QModelIndex()) const; // Sets up all icons which are used directly by this model.
int columnCount(const QModelIndex &parent = QModelIndex()) const; void setupIcons();
// Model navigation.
QModelIndex parent(const QModelIndex &child) const;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
const Message &messageAt(int row_index) const;
public slots: public slots:
// Sets "read" status of message with given row index. // Fetches ALL available data to the model.
void setMessageRead(int row_index, int read); // NOTE: This is almost needed when sorting
// and makes the model more predictable.
void fetchAll();
// Loads messages of given feeds.
void loadMessages(const QList<int> feed_ids);
private: private:
// Sets up header data.
void setupHeaderData(); void setupHeaderData();
// Creates "normal" and "bold" fonts. // Creates "normal" and "bold" fonts.
void setupFonts(); void setupFonts();
private: private:
QHash<int, int> m_columnMappings; QList<QString> m_headerData;
QList<Message> m_messages; bool m_isInEditingMode;
QFont m_normalFont; QFont m_normalFont;
QFont m_boldFont; QFont m_boldFont;
QIcon m_favoriteIcon; QIcon m_favoriteIcon;
QIcon m_readIcon; QIcon m_readIcon;
QIcon m_unreadIcon; QIcon m_unreadIcon;
QList<QString> m_headerData;
}; };
#endif // MESSAGESMODEL_H #endif // MESSAGESMODEL_H

View File

@ -1,4 +1,5 @@
#include <QHeaderView> #include <QHeaderView>
#include <QKeyEvent>
#include "gui/messagesview.h" #include "gui/messagesview.h"
#include "core/messagesproxymodel.h" #include "core/messagesproxymodel.h"
@ -10,6 +11,12 @@ MessagesView::MessagesView(QWidget *parent) : QTreeView(parent) {
m_sourceModel = m_proxyModel->sourceModel(); m_sourceModel = m_proxyModel->sourceModel();
setModel(m_proxyModel); setModel(m_proxyModel);
hideColumn(0);
header()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
// NOTE: It is recommended to call this after the model is set
// due to sorting performance.
setupAppearance(); setupAppearance();
} }
@ -28,13 +35,14 @@ MessagesProxyModel *MessagesView::model() {
void MessagesView::setupAppearance() { void MessagesView::setupAppearance() {
header()->setStretchLastSection(true); header()->setStretchLastSection(true);
setUniformRowHeights(true);
setAcceptDrops(false); setAcceptDrops(false);
setDragEnabled(false); setDragEnabled(false);
setDragDropMode(QAbstractItemView::NoDragDrop); setDragDropMode(QAbstractItemView::NoDragDrop);
setExpandsOnDoubleClick(false); setExpandsOnDoubleClick(false);
setRootIsDecorated(false); setRootIsDecorated(false);
setItemsExpandable(false); setItemsExpandable(false);
setSortingEnabled(false); setSortingEnabled(true);
setAllColumnsShowFocus(true); setAllColumnsShowFocus(true);
setSelectionMode(QAbstractItemView::ExtendedSelection); setSelectionMode(QAbstractItemView::ExtendedSelection);
} }
@ -44,6 +52,10 @@ void MessagesView::selectionChanged(const QItemSelection &selected,
QTreeView::selectionChanged(selected, deselected); QTreeView::selectionChanged(selected, deselected);
} }
void MessagesView::keyPressEvent(QKeyEvent *event) {
QTreeView::keyPressEvent(event);
}
void MessagesView::currentChanged(const QModelIndex &current, void MessagesView::currentChanged(const QModelIndex &current,
const QModelIndex &previous) { const QModelIndex &previous) {
QModelIndex ind = m_proxyModel->mapToSource(current); QModelIndex ind = m_proxyModel->mapToSource(current);
@ -53,9 +65,7 @@ void MessagesView::currentChanged(const QModelIndex &current,
current.row(), current.column(), current.row(), current.column(),
ind.row(), ind.column()); ind.row(), ind.column());
m_sourceModel->setMessageRead(ind.row(), 1); m_sourceModel->setData(m_sourceModel->index(ind.row(), 1), 1, Qt::EditRole);
emit currentMessageChanged(m_sourceModel->messageAt(ind.row()));
QTreeView::currentChanged(current, previous); QTreeView::currentChanged(current, previous);
} }

View File

@ -16,12 +16,15 @@ class MessagesView : public QTreeView {
explicit MessagesView(QWidget *parent = 0); explicit MessagesView(QWidget *parent = 0);
virtual ~MessagesView(); virtual ~MessagesView();
// Model accessors.
MessagesProxyModel *model(); MessagesProxyModel *model();
MessagesModel *sourceModel(); MessagesModel *sourceModel();
protected: protected:
void setupAppearance(); void setupAppearance();
void keyPressEvent(QKeyEvent *event);
void currentChanged(const QModelIndex &current, void currentChanged(const QModelIndex &current,
const QModelIndex &previous); const QModelIndex &previous);
@ -29,7 +32,8 @@ class MessagesView : public QTreeView {
const QItemSelection &deselected); const QItemSelection &deselected);
signals: signals:
void currentMessageChanged(const Message &message); // TODO: dodělat signál.
void currentMessageChanged(/* const Message &message */);
void currentMessageRemoved(); void currentMessageRemoved();
private: private:

View File

@ -167,8 +167,9 @@ void WebBrowser::navigateToUrl(const QUrl &url) {
} }
} }
void WebBrowser::navigateToMessage(const Message &message) { void WebBrowser::navigateToMessage() {
// TODO: dodělat. // TODO: dodělat.
/*
m_webView->setHtml(SkinFactory::getInstance()->getCurrentMarkup().arg(message.m_data.at(MSG_DB_TITLE_INDEX).toString(), m_webView->setHtml(SkinFactory::getInstance()->getCurrentMarkup().arg(message.m_data.at(MSG_DB_TITLE_INDEX).toString(),
tr("Check your internet connection or website address"), tr("Check your internet connection or website address"),
QString(), QString(),
@ -180,7 +181,7 @@ void WebBrowser::navigateToMessage(const Message &message) {
"<li>many other things.</li>" "<li>many other things.</li>"
"</ul>"), "</ul>"),
"aa")); "aa"));
*/
} }
void WebBrowser::updateZoomGui() { void WebBrowser::updateZoomGui() {

View File

@ -61,7 +61,7 @@ class WebBrowser : public TabContent {
void navigateToUrl(const QUrl &url); void navigateToUrl(const QUrl &url);
// Navigates to message. // Navigates to message.
void navigateToMessage(const Message &message); void navigateToMessage();
// Zoom manipulators. // Zoom manipulators.
void increaseZoom(); void increaseZoom();