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}] 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.
if(APPLE)
set(EXE_NAME ${APP_UP_NAME})

View File

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

View File

@ -11,102 +11,132 @@
MessagesModel::MessagesModel(QObject *parent)
: QAbstractItemModel(parent) {
: QSqlTableModel(parent, DatabaseFactory::getInstance()->addConnection("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();
setupIcons();
setupHeaderData();
// Set desired table and edit strategy.
setEditStrategy(QSqlTableModel::OnFieldChange);
setTable("Messages");
loadMessages(QList<int>());
}
MessagesModel::~MessagesModel() {
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() {
m_normalFont = QtSingleApplication::font("MessagesView");
m_boldFont = m_normalFont;
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() {
m_headerData << tr("Read") << tr("Important") <<
tr("Title") << tr("Author") <<
tr("Created on") << tr("Updated on");
m_headerData << tr("Id") << tr("Read") << tr("Deleted") << tr("Important") <<
tr("Feed") << tr("Title") << tr("Url") << tr("Author") <<
tr("Created on") << tr("Updated on") << tr("Contents");
}
Qt::ItemFlags MessagesModel::flags(const QModelIndex &index) const {
Q_UNUSED(index);
Qt::ItemFlags MessagesModel::flags(const QModelIndex &idx) const {
Q_UNUSED(idx);
// Each item can be selected and is enabled.
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
if (m_isInEditingMode) {
// 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 {
Q_UNUSED(parent);
QVariant MessagesModel::data(const QModelIndex &idx, int role) const {
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 {
Q_UNUSED(parent);
bool MessagesModel::setData(const QModelIndex &idx, const QVariant &value, int role) {
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 {
Q_UNUSED(child);
return QModelIndex();
}
QModelIndex MessagesModel::index(int row, int column,
const QModelIndex &parent) const {
Q_UNUSED(parent);
return createIndex(row, column);
return set_data_result;
}
QVariant MessagesModel::headerData(int section,
@ -114,27 +144,29 @@ QVariant MessagesModel::headerData(int section,
int role) const {
Q_UNUSED(orientation);
// TODO: Ehance this with graphics and other roles.
switch (role) {
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);
}
else {
return QVariant();
}
// Return RAW data for these roles.
case Qt::ToolTipRole:
case Qt::EditRole:
return m_headerData.at(section);
// Display icons for "read" and "important" columns.
case Qt::DecorationRole: {
switch (section) {
case MSG_MODEL_READ_INDEX:
case MSG_DB_READ_INDEX:
return m_readIcon;
case MSG_MODEL_IMPORTANT_INDEX:
case MSG_DB_IMPORTANT_INDEX:
return m_favoriteIcon;
default:
@ -146,100 +178,3 @@ QVariant MessagesModel::headerData(int section,
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
#define MESSAGESMODEL_H
#include <QAbstractItemModel>
#include <QSqlTableModel>
#include <QFont>
#include <QIcon>
#include "core/defs.h"
// Representation of ONE message.
class Message {
private:
QList<QVariant> m_data;
friend class MessagesModel;
friend class WebBrowser;
};
class MessagesModel : public QAbstractItemModel {
class MessagesModel : public QSqlTableModel {
Q_OBJECT
public:
@ -24,46 +17,40 @@ class MessagesModel : public QAbstractItemModel {
virtual ~MessagesModel();
// Model implementation.
// Data accessors/manipulators.
bool setData(const QModelIndex &idx, const QVariant &value, int role = Qt::EditRole);
QVariant data(const QModelIndex &idx, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
QVariant data(const QModelIndex &index, int role) 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;
Qt::ItemFlags flags(const QModelIndex &idx) const;
// Model dimensions.
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
// 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:
// Sets up all icons which are used directly by this model.
void setupIcons();
public slots:
// Sets "read" status of message with given row index.
void setMessageRead(int row_index, int read);
// Fetches ALL available data to the model.
// 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:
// Sets up header data.
void setupHeaderData();
// Creates "normal" and "bold" fonts.
void setupFonts();
private:
QHash<int, int> m_columnMappings;
QList<Message> m_messages;
QList<QString> m_headerData;
bool m_isInEditingMode;
QFont m_normalFont;
QFont m_boldFont;
QIcon m_favoriteIcon;
QIcon m_readIcon;
QIcon m_unreadIcon;
QList<QString> m_headerData;
};
#endif // MESSAGESMODEL_H

View File

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

View File

@ -16,12 +16,15 @@ class MessagesView : public QTreeView {
explicit MessagesView(QWidget *parent = 0);
virtual ~MessagesView();
// Model accessors.
MessagesProxyModel *model();
MessagesModel *sourceModel();
protected:
void setupAppearance();
void keyPressEvent(QKeyEvent *event);
void currentChanged(const QModelIndex &current,
const QModelIndex &previous);
@ -29,7 +32,8 @@ class MessagesView : public QTreeView {
const QItemSelection &deselected);
signals:
void currentMessageChanged(const Message &message);
// TODO: dodělat signál.
void currentMessageChanged(/* const Message &message */);
void currentMessageRemoved();
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.
/*
m_webView->setHtml(SkinFactory::getInstance()->getCurrentMarkup().arg(message.m_data.at(MSG_DB_TITLE_INDEX).toString(),
tr("Check your internet connection or website address"),
QString(),
@ -180,7 +181,7 @@ void WebBrowser::navigateToMessage(const Message &message) {
"<li>many other things.</li>"
"</ul>"),
"aa"));
*/
}
void WebBrowser::updateZoomGui() {

View File

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