summaryrefslogtreecommitdiff
path: root/forummodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'forummodel.cpp')
-rw-r--r--forummodel.cpp212
1 files changed, 162 insertions, 50 deletions
diff --git a/forummodel.cpp b/forummodel.cpp
index ea54f8e..14f053f 100644
--- a/forummodel.cpp
+++ b/forummodel.cpp
@@ -8,7 +8,8 @@
#include "forummodel.h"
ForumModel::ForumModel(QObject *parent) :
- QAbstractListModel(parent), _board(0), _forumId(-1), _eof(false)
+ QAbstractListModel(parent), _board(0), _forumId(-1),
+ _numAnnouncements(0), _numSticky(0), _eof(false)
{
QHash<int, QByteArray> roles = roleNames();
roles[TitleRole] = QByteArray("title");
@@ -27,15 +28,15 @@ Board * ForumModel::board() const
void ForumModel::setBoard(Board *board)
{
if (_board != board) {
- disconnect(this, SLOT(handleForumTopicsChanged(int,int,int)));
+ disconnect(this, SLOT(handleForumTopicsChanged(int,Board::TopicType,int,int)));
disconnect(this, SLOT(handleForumTopicChanged(int,int)));
clearModel();
_board = board;
if (_board) {
- connect(_board, SIGNAL(forumTopicsChanged(int,int,int)),
- SLOT(handleForumTopicsChanged(int,int,int)));
+ connect(_board, SIGNAL(forumTopicsChanged(int,Board::TopicType,int,int)),
+ SLOT(handleForumTopicsChanged(int,Board::TopicType,int,int)));
connect(_board, SIGNAL(forumTopicChanged(int,int)),
SLOT(handleForumTopicChanged(int,int)));
if (_forumId >= 0) {
@@ -86,6 +87,8 @@ QVariant ForumModel::data(const QModelIndex &index, int role) const
return _data[row].title;
case TopicIdRole:
return _data[row].topic_id;
+ case TopicTypeRole:
+ return _data[row].type;
case NumRepliesRole:
return _data[row].num_replies;
case UnreadRole:
@@ -107,15 +110,18 @@ void ForumModel::fetchMore(const QModelIndex &parent)
if (!_board || _forumId < 0) return;
if (_eof) return;
- const int start = _data.size();
- QList<Topic> topics = loadTopics(start, start + FORUM_PAGE_SIZE - 1);
- const int new_end = start + topics.size() - 1;
+ const int normal_offset = _numAnnouncements + _numSticky;
+ const int normal_start = _data.size() - normal_offset;
+ QList<Topic> topics = loadTopics(Board::Normal,
+ normal_start, normal_start + FORUM_PAGE_SIZE - 1);
+ const int normal_new_end = normal_start + topics.size() - 1;
if (topics.empty()) {
// We could not load anything more from DB!
_eof = true;
} else {
- beginInsertRows(QModelIndex(), start, new_end);
+ beginInsertRows(QModelIndex(),
+ normal_offset + normal_start, normal_offset + normal_new_end);
_data.append(topics);
_eof = topics.size() < FORUM_PAGE_SIZE; // If short read, we reached EOF.
endInsertRows();
@@ -127,10 +133,11 @@ void ForumModel::fetchMore(const QModelIndex &parent)
// If the topics we got from DB are too old, refresh online.
if (last.secsTo(QDateTime::currentDateTimeUtc()) > FORUM_TOPICS_TLL) {
qDebug() << "Fetching topics because of old";
- Q_ASSERT(new_end >= 0);
+ Q_ASSERT(normal_new_end >= 0);
_board->enqueueAction(new FetchTopicsAction(_forumId,
- start,
- new_end,
+ Board::Normal,
+ normal_start,
+ normal_new_end,
_board));
}
}
@@ -138,9 +145,11 @@ void ForumModel::fetchMore(const QModelIndex &parent)
// Try to fetch more topics if board is online and we reached the end of DB
if (_eof) {
qDebug() << "Fetching topics because of EOF";
+ const int normal_cur_end = _data.size() - 1 - normal_offset;
_board->enqueueAction(new FetchTopicsAction(_forumId,
- _data.size(),
- _data.size() + FORUM_PAGE_SIZE - 1,
+ Board::Normal,
+ normal_cur_end + 1,
+ normal_cur_end + FORUM_PAGE_SIZE,
_board));
}
}
@@ -150,6 +159,17 @@ void ForumModel::refresh()
{
// Forcefully refresh all topics on this forum
_board->enqueueAction(new FetchTopicsAction(_forumId,
+ Board::Announcement,
+ 0,
+ FetchTopicsAction::FetchAllTopics,
+ _board));
+ _board->enqueueAction(new FetchTopicsAction(_forumId,
+ Board::Sticky,
+ 0,
+ FetchTopicsAction::FetchAllTopics,
+ _board));
+ _board->enqueueAction(new FetchTopicsAction(_forumId,
+ Board::Normal,
0,
FetchTopicsAction::FetchAllTopics,
_board));
@@ -178,10 +198,8 @@ QDateTime ForumModel::lastTopPostUpdate()
if (!_board) return QDateTime();
QSqlDatabase db = _board->database();
QSqlQuery query(db);
- query.prepare("SELECT last_update_time FROM topics "
- "WHERE forum_id = :forum_id "
- "ORDER BY position ASC "
- "LIMIT 1");
+ query.prepare("SELECT MIN(last_update_time) FROM topics "
+ "WHERE forum_id = :forum_id AND position = 0");
query.bindValue(":forum_id", _forumId);
if (query.exec()) {
if (query.next()) {
@@ -193,15 +211,16 @@ QDateTime ForumModel::lastTopPostUpdate()
return QDateTime();
}
-QList<ForumModel::Topic> ForumModel::loadTopics(int start, int end)
+QList<ForumModel::Topic> ForumModel::loadTopics(Board::TopicType type, int start, int end)
{
Q_ASSERT(_board);
QList<Topic> topics;
QSqlQuery query(_board->database());
- query.prepare("SELECT topic_id, topic_title, reply_number, new_post, last_reply_time, last_update_time FROM topics "
- "WHERE forum_id = :forum_id AND position BETWEEN :start AND :end "
+ query.prepare("SELECT topic_id, topic_type, topic_title, reply_number, new_post, last_reply_time, last_update_time FROM topics "
+ "WHERE forum_id = :forum_id AND topic_type = :topic_type AND position BETWEEN :start AND :end "
"ORDER by position ASC ");
query.bindValue(":forum_id", _forumId);
+ query.bindValue(":topic_type", type);
query.bindValue(":start", start);
query.bindValue(":end", end);
if (query.exec()) {
@@ -209,11 +228,12 @@ QList<ForumModel::Topic> ForumModel::loadTopics(int start, int end)
while (query.next()) {
Topic topic;
topic.topic_id = query.value(0).toInt();
- topic.title = query.value(1).toString();
- topic.num_replies = query.value(2).toInt();
- topic.unread = query.value(3).toBool();
- topic.last_reply_time = parseDateTime(query.value(4));
- topic.last_update_time = parseDateTime(query.value(5));
+ topic.type = type;
+ topic.title = query.value(2).toString();
+ topic.num_replies = query.value(3).toInt();
+ topic.unread = query.value(4).toBool();
+ topic.last_reply_time = parseDateTime(query.value(5));
+ topic.last_update_time = parseDateTime(query.value(6));
topics.append(topic);
}
} else {
@@ -230,66 +250,130 @@ void ForumModel::clearModel()
endResetModel();
}
-void ForumModel::handleForumTopicsChanged(int forumId, int start, int end)
+void ForumModel::handleForumTopicsChanged(int forumId, Board::TopicType type,
+ int start, int end)
{
- if (forumId == _forumId) {
+ if (forumId != _forumId) {
+ return; // Not our topics
+ }
+ if (type == Board::Normal) {
// Yep, our topics list changed.
+ const int normal_offset = _numAnnouncements + _numSticky;
+ int current_normal_end = _data.size() - 1 - normal_offset;
+
qDebug() << "My topics changed" << start << end;
- if (end > _data.size()) {
+
+ if (end >= current_normal_end) {
// If for any reason we have more topics now, it means we might
// no longer be EOF...
_eof = false;
}
- if (start > _data.size() + 1) {
- // We are still not interested into these topics.
+ if (start > current_normal_end + 1) {
+ // On the other hand, if the topics are too far away,
+ // do not load them until we fetchMore().
qDebug() << "Topics too far";
return;
}
- QList<Topic> topics = loadTopics(start, end);
+ QList<Topic> topics = loadTopics(Board::Normal, start, end);
if (topics.size() < end - start + 1) {
_eof = true; // Short read
end = start + topics.size() - 1;
- if (_data.size() > end + 1) {
- beginRemoveRows(QModelIndex(), end + 1, _data.size());
- while (_data.size() > end + 1) {
+ if (current_normal_end > end) {
+ const int current_full_end = _data.size() - 1;
+ const int new_full_end = end + normal_offset;
+
+ Q_ASSERT(new_full_end < current_full_end);
+ beginRemoveRows(QModelIndex(),
+ new_full_end, current_full_end);
+ while (_data.size() > new_full_end) {
_data.removeLast();
}
+ current_normal_end = _data.size() - 1 - normal_offset;
+ Q_ASSERT(current_normal_end == end);
endRemoveRows();
}
}
- if (end >= _data.size()) {
- qDebug() << "Call insert rows" << _data.size() << end;
- beginInsertRows(QModelIndex(), _data.size(), end);
- _data.reserve(end + 1);
- for (int i = start; i < _data.size(); i++) {
- _data[i] = topics[i - start];
+ if (end > current_normal_end) {
+ const int current_full_end = _data.size() - 1;
+ const int new_full_end = end + normal_offset;
+ qDebug() << "Insert rows" << current_full_end + 1 << new_full_end;
+ beginInsertRows(QModelIndex(), current_full_end + 1, new_full_end);
+ _data.reserve(new_full_end + 1);
+ const int full_start = normal_offset + start;
+ for (int i = full_start; i <= current_full_end; i++) {
+ _data[i] = topics[i - full_start];
}
- for (int i = _data.size(); i <= end; i++) {
- Q_ASSERT(i >= start);
- _data.append(topics[i - start]);
+ Q_ASSERT(current_full_end + 1 >= full_start);
+ for (int i = current_full_end + 1; i <= new_full_end; i++) {
+ _data.append(topics[i - full_start]);
}
endInsertRows();
- emit dataChanged(createIndex(start, 0), createIndex(_data.size() - 1, 0));
+ Q_ASSERT(new_full_end == _data.size() - 1);
+ emit dataChanged(createIndex(full_start, 0), createIndex(new_full_end, 0));
} else {
qDebug() << "Just refresh the data";
- for (int i = start; i < end; i++) {
- _data[i] = topics[i - start];
+ const int full_start = normal_offset + start;
+ const int full_end = normal_offset + end;
+ for (int i = full_start; i < full_end; i++) {
+ _data[i] = topics[i - full_start];
+ }
+ emit dataChanged(createIndex(full_start, 0), createIndex(full_end, 0));
+ }
+ } else if (type == Board::Sticky || type == Board::Announcement) {
+ // We just reload these fully
+ QList<Topic> topics = loadTopics(type, 0, MAX_FORUM_PAGE_SIZE - 1);
+ const int offset = type == Board::Sticky ? _numAnnouncements : 0;
+ int * const cur_number_p = type == Board::Sticky ? &_numSticky : &_numAnnouncements;
+ const int cur_number = *cur_number_p;
+
+ if (topics.size() < cur_number) {
+ const int cur_end = offset + cur_number - 1;
+ const int new_end = offset + topics.size() - 1;
+ beginRemoveRows(QModelIndex(), new_end + 1, cur_end);
+ for (int i = new_end + 1; i <= cur_end; i++) {
+ _data.removeAt(i);
+ (*cur_number_p)--;
+ }
+ endRemoveRows();
+ } else if (topics.size() > cur_number) {
+ const int cur_end = offset + cur_number - 1;
+ const int new_end = offset + topics.size() - 1;
+ const int new_start = cur_end + 1;
+ Q_ASSERT(new_end - offset == topics.size() - 1);
+ beginInsertRows(QModelIndex(), new_start, new_end);
+ for (int i = new_start; i <= new_end; i++) {
+ _data.insert(i, topics.takeAt(new_start - offset));
+ (*cur_number_p)++;
}
- emit dataChanged(createIndex(start, 0), createIndex(end, 0));
+ endInsertRows();
+ Q_ASSERT(topics.size() == cur_number);
+ }
+
+ const int start = offset;
+ const int end = offset + topics.size() - 1;
+ for (int i = start; i <= end; i++) {
+ _data.insert(i, topics.at(i - offset));
}
+ emit dataChanged(createIndex(start, 0), createIndex(end, 0));
}
}
void ForumModel::handleForumTopicChanged(int forumId, int topicId)
{
if (forumId == _forumId) {
+ Board::TopicType type = Board::Announcement;
+ int pos = 0;
for (int i = 0; i < _data.size(); i++) {
Topic& topic = _data[i];
+ if (topic.type != type) {
+ type = topic.type;
+ pos = 0;
+ }
if (topic.topic_id == topicId) {
// Need to refresh this topic
- QList<Topic> topics = loadTopics(i, i);
+ QList<Topic> topics = loadTopics(type, pos, pos);
if (topics.size() == 1) {
_data[i] = topics[0];
emit dataChanged(createIndex(i, 0), createIndex(i, 0));
@@ -297,6 +381,7 @@ void ForumModel::handleForumTopicChanged(int forumId, int topicId)
qWarning() << "Topic changed yet not in DB";
}
}
+ pos++;
}
}
}
@@ -311,7 +396,12 @@ void ForumModel::update()
last.secsTo(QDateTime::currentDateTimeUtc()) > FORUM_TOP_TLL) {
// Outdated or empty, refresh.
qDebug() << "Fetching topics because the top are old";
- _board->enqueueAction(new FetchTopicsAction(_forumId, 0, FORUM_PAGE_SIZE - 1, _board));
+ _board->enqueueAction(new FetchTopicsAction(_forumId, Board::Announcement,
+ 0, FORUM_PAGE_SIZE - 1, _board));
+ _board->enqueueAction(new FetchTopicsAction(_forumId, Board::Sticky,
+ 0, FORUM_PAGE_SIZE - 1, _board));
+ _board->enqueueAction(new FetchTopicsAction(_forumId, Board::Normal,
+ 0, FORUM_PAGE_SIZE - 1, _board));
} else {
qDebug() << "Topics not outdated";
}
@@ -321,6 +411,28 @@ void ForumModel::reload()
{
Q_ASSERT(_data.empty());
Q_ASSERT(!_eof);
- // Fetch an initial bunch of topics
+ // Load announcements / sticky topics fully
+ QList<Topic> topics;
+ topics = loadTopics(Board::Announcement, 0, MAX_FORUM_PAGE_SIZE - 1);
+ if (!topics.empty()) {
+ beginInsertRows(QModelIndex(), 0, topics.size() - 1);
+ _data.append(topics);
+ _numAnnouncements = topics.size();
+ endInsertRows();
+ } else {
+ _numAnnouncements = 0;
+ }
+
+ topics = loadTopics(Board::Sticky, 0, MAX_FORUM_PAGE_SIZE - 1);
+ if (!topics.empty()) {
+ beginInsertRows(QModelIndex(), _numAnnouncements, _numAnnouncements + topics.size() - 1);
+ _data.append(topics);
+ _numSticky = topics.size();
+ endInsertRows();
+ } else {
+ _numSticky = 0;
+ }
+
+ // Fetch an initial bunch of normal topics
fetchMore();
}