From 3c88a76b1be759d13097810877d6e990b3371726 Mon Sep 17 00:00:00 2001 From: "Javier S. Pedro" Date: Thu, 4 Apr 2013 01:15:54 +0200 Subject: implement refresh action --- board.cpp | 11 +++++++---- boardmodel.cpp | 1 + fetchpostsaction.cpp | 26 ++++++++++++++++++++++++-- fetchpostsaction.h | 4 ++++ fetchtopicsaction.cpp | 31 +++++++++++++++++++++++++++---- fetchtopicsaction.h | 4 ++++ forummodel.cpp | 14 ++++++++++++-- forummodel.h | 7 ++++++- global.h | 6 ++++++ qml/tapasboard/BoardPage.qml | 20 ++++++++++++++++++-- qml/tapasboard/ForumPage.qml | 20 ++++++++++++++++++-- qml/tapasboard/TopicPage.qml | 20 ++++++++++++++++++-- topicmodel.cpp | 9 +++++++++ topicmodel.h | 3 +++ 14 files changed, 157 insertions(+), 19 deletions(-) diff --git a/board.cpp b/board.cpp index 2cad565..d8660ef 100644 --- a/board.cpp +++ b/board.cpp @@ -215,10 +215,13 @@ QString Board::renderHumanTime(const QDateTime &dateTime) void Board::cancelAllActions() { - disconnect(this, SLOT(handleActionFinished(Action*))); - while (!_queue.isEmpty()) { - Action *action = _queue.dequeue(); - delete action; + if (!_queue.isEmpty()) { + disconnect(this, SLOT(handleActionFinished(Action*))); + while (!_queue.isEmpty()) { + Action *action = _queue.dequeue(); + delete action; + } + emit busyChanged(); } } diff --git a/boardmodel.cpp b/boardmodel.cpp index 7454d6f..dc1757e 100644 --- a/boardmodel.cpp +++ b/boardmodel.cpp @@ -119,6 +119,7 @@ void BoardModel::fetchMore(const QModelIndex &parent) void BoardModel::refresh() { + // Forcefully refresh the forums list if (_board) { _board->enqueueAction(new FetchForumsAction(_board)); } diff --git a/fetchpostsaction.cpp b/fetchpostsaction.cpp index 0e4284b..2493aa3 100644 --- a/fetchpostsaction.cpp +++ b/fetchpostsaction.cpp @@ -3,6 +3,7 @@ #include #include +#include "global.h" #include "board.h" #include "xmlrpcinterface.h" #include "xmlrpcreply.h" @@ -18,7 +19,15 @@ bool FetchPostsAction::isSupersetOf(Action *action) const FetchPostsAction *other = qobject_cast(action); if (other) { if (other->_topicId == _topicId) { - if (_start <= other->_start && _end >= other->_end) { + if (_end == FetchAllPosts) { + // If this is fetching all posts, then this is a superset + // of every other action... except those that also fetch all. + return other->_end != FetchAllPosts; + } else if (other->_end == FetchAllPosts) { + // If the other action fetches all posts, this cannot be a + // superset + return false; + } else if (_start <= other->_start && _end >= other->_end) { return true; } } @@ -28,8 +37,15 @@ bool FetchPostsAction::isSupersetOf(Action *action) const void FetchPostsAction::execute() { + int end = _end; + if (end == FetchAllPosts) { + // Fetch posts in blocks of size 50. + end = _start + MAX_TOPIC_PAGE_SIZE; + // After finishing this action, a new one will be enqueued with the next 50. + } + _call = _board->service()->asyncCall("get_thread", - QString::number(_topicId), _start, _end); + QString::number(_topicId), _start, end); _call->setParent(this); connect(_call, SIGNAL(finished(XmlRpcPendingCall*)), SLOT(handleFinishedCall())); } @@ -84,6 +100,12 @@ void FetchPostsAction::handleFinishedCall() _board->notifyTopicPostsChanged(_topicId, _start, _start + posts.size() - 1); } + if (_end == FetchAllPosts && posts.size() == MAX_TOPIC_PAGE_SIZE) { + // Ok, let's prepare to fetch the next block of posts because + // there are probably more of them + int start = _start + MAX_TOPIC_PAGE_SIZE; + _board->enqueueAction(new FetchPostsAction(_topicId, start, FetchAllPosts, _board)); + } } else { qWarning() << "Could not fetch posts"; // TODO emit error ... diff --git a/fetchpostsaction.h b/fetchpostsaction.h index 9951989..732c0d2 100644 --- a/fetchpostsaction.h +++ b/fetchpostsaction.h @@ -13,6 +13,10 @@ class FetchPostsAction : public Action public: explicit FetchPostsAction(int topicId, int start, int end, Board *board); + enum { + FetchAllPosts = -1 + }; + bool isSupersetOf(Action *action) const; void execute(); diff --git a/fetchtopicsaction.cpp b/fetchtopicsaction.cpp index ead8d4d..bc94965 100644 --- a/fetchtopicsaction.cpp +++ b/fetchtopicsaction.cpp @@ -3,6 +3,7 @@ #include #include +#include "global.h" #include "board.h" #include "xmlrpcinterface.h" #include "xmlrpcreply.h" @@ -18,7 +19,18 @@ bool FetchTopicsAction::isSupersetOf(Action *action) const FetchTopicsAction *other = qobject_cast(action); if (other) { if (other->_forumId == _forumId) { - if (_start <= other->_start && _end >= other->_end) { + if (_end == FetchAllTopics) { + // If this is fetching all topics, then this is a superset + // of every other action... except those that also fetch all + // topics. + return other->_end != FetchAllTopics; + } else if (other->_end == FetchAllTopics) { + // If the other action fetches all topics, this cannot be a + // superset + return false; + } else if (_start <= other->_start && _end >= other->_end) { + // Otherwise, check if the range of posts fetched by this + // action fully contains the other action. return true; } } @@ -28,8 +40,15 @@ bool FetchTopicsAction::isSupersetOf(Action *action) const void FetchTopicsAction::execute() { + int end = _end; + if (end == FetchAllTopics) { + // Fetch topics in blocks of size 50. + end = _start + MAX_FORUM_PAGE_SIZE; + // After finishing this action, a new one will be enqueued with the next 50. + } + _call = _board->service()->asyncCall("get_topic", - QString::number(_forumId), _start, _end); + QString::number(_forumId), _start, end); _call->setParent(this); connect(_call, SIGNAL(finished(XmlRpcPendingCall*)), SLOT(handleFinishedCall())); } @@ -85,8 +104,12 @@ void FetchTopicsAction::handleFinishedCall() if (topics.size() > 0) { _board->notifyForumTopicsChanged(_forumId, _start, _start + topics.size() - 1); - } else { - qWarning() << "Asked for topics, got none..."; + } + if (_end == FetchAllTopics && topics.size() == MAX_FORUM_PAGE_SIZE) { + // Ok, let's prepare to fetch the next block of topics because + // there are probably more of them + int start = _start + MAX_FORUM_PAGE_SIZE; + _board->enqueueAction(new FetchTopicsAction(_forumId, start, FetchAllTopics, _board)); } } else { qWarning() << "Could not fetch topics"; diff --git a/fetchtopicsaction.h b/fetchtopicsaction.h index 0b02fa3..9c12784 100644 --- a/fetchtopicsaction.h +++ b/fetchtopicsaction.h @@ -13,6 +13,10 @@ class FetchTopicsAction : public Action public: explicit FetchTopicsAction(int forumId, int start, int end, Board *board); + enum { + FetchAllTopics = -1 + }; + bool isSupersetOf(Action *action) const; void execute(); diff --git a/forummodel.cpp b/forummodel.cpp index bdc2d17..4d59916 100644 --- a/forummodel.cpp +++ b/forummodel.cpp @@ -14,6 +14,7 @@ ForumModel::ForumModel(QObject *parent) : roles[TitleRole] = QByteArray("title"); roles[IconRole] = QByteArray("icon"); roles[TopicIdRole] = QByteArray("topicId"); + roles[NumPostsRole] = QByteArray("numPosts"); setRoleNames(roles); } @@ -79,10 +80,10 @@ QVariant ForumModel::data(const QModelIndex &index, int role) const switch (role) { case TitleRole: return _data[row].title; - break; case TopicIdRole: return _data[row].topic_id; - break; + case NumPostsRole: + return _data[row].num_replies; } return QVariant(); @@ -138,6 +139,15 @@ void ForumModel::fetchMore(const QModelIndex &parent) } } +void ForumModel::refresh() +{ + // Forcefully refresh all topics on this forum + _board->enqueueAction(new FetchTopicsAction(_forumId, + 0, + FetchTopicsAction::FetchAllTopics, + _board)); +} + QDateTime ForumModel::parseDateTime(const QVariant &v) { QString s = v.toString(); diff --git a/forummodel.h b/forummodel.h index 5a84f64..0458cfd 100644 --- a/forummodel.h +++ b/forummodel.h @@ -21,7 +21,8 @@ public: IconRole = Qt::DecorationRole, TopicIdRole = Qt::UserRole, - TopicTypeRole + TopicTypeRole, + NumPostsRole }; Board * board() const; @@ -36,6 +37,9 @@ public: bool canFetchMore(const QModelIndex &parent = QModelIndex()) const; void fetchMore(const QModelIndex &parent = QModelIndex()); +public slots: + void refresh(); + signals: void boardChanged(); void forumIdChanged(); @@ -44,6 +48,7 @@ protected: struct Topic { int topic_id; QString title; + int num_replies; QDateTime last_reply_time; QDateTime last_update_time; }; diff --git a/global.h b/global.h index 3b1d6ae..694dce0 100644 --- a/global.h +++ b/global.h @@ -21,6 +21,9 @@ /** Number of topics per "block" in subforum view */ #define FORUM_PAGE_SIZE 20 +/** This is the absolute maximum page size the API will allow. */ +#define MAX_FORUM_PAGE_SIZE 50 + /** Time we should consider the most recent posts in a topic up to date, in seconds. */ #define TOPIC_TOP_TLL 5 * 60 @@ -30,6 +33,9 @@ /** Number of posts per "block" in topic view */ #define TOPIC_PAGE_SIZE 20 +/** This is the absolute maximum page size the API will allow. */ +#define MAX_TOPIC_PAGE_SIZE 50 + // Some singletons extern BoardManager *board_manager; diff --git a/qml/tapasboard/BoardPage.qml b/qml/tapasboard/BoardPage.qml index dd1bd24..7efc6db 100644 --- a/qml/tapasboard/BoardPage.qml +++ b/qml/tapasboard/BoardPage.qml @@ -14,17 +14,26 @@ Page { tools: ToolBarLayout { ToolIcon { - id: backToolIcon platformIconId: "toolbar-back" - anchors.left: parent.left onClicked: pageStack.pop() } + ToolIcon { + platformIconId: board.busy ? "toolbar-cancle" : "toolbar-refresh" + onClicked: { + if (board.busy) { + board.cancelAllActions(); + } else { + boardModel.refresh(); + } + } + } } ListView { id: forumsView anchors.fill: parent model: BoardModel { + id: boardModel board: boardPage.board forumId: boardPage.forumId } @@ -87,4 +96,11 @@ Page { ScrollDecorator { flickableItem: forumsView } + + BusyIndicator { + anchors.centerIn: parent + platformStyle: BusyIndicatorStyle { size: "large" } + visible: forumsView.count == 0 && board.busy + running: visible + } } diff --git a/qml/tapasboard/ForumPage.qml b/qml/tapasboard/ForumPage.qml index 18953cb..aed65a0 100644 --- a/qml/tapasboard/ForumPage.qml +++ b/qml/tapasboard/ForumPage.qml @@ -14,17 +14,26 @@ Page { tools: ToolBarLayout { ToolIcon { - id: backToolIcon platformIconId: "toolbar-back" - anchors.left: parent.left onClicked: pageStack.pop() } + ToolIcon { + platformIconId: board.busy ? "toolbar-cancle" : "toolbar-refresh" + onClicked: { + if (board.busy) { + board.cancelAllActions(); + } else { + forumModel.refresh(); + } + } + } } ListView { id: topicsView anchors.fill: parent model: ForumModel { + id: forumModel board: forumPage.board forumId: forumPage.forumId } @@ -66,4 +75,11 @@ Page { ScrollDecorator { flickableItem: topicsView } + + BusyIndicator { + anchors.centerIn: parent + platformStyle: BusyIndicatorStyle { size: "large" } + visible: topicsView.count == 0 && board.busy + running: visible + } } diff --git a/qml/tapasboard/TopicPage.qml b/qml/tapasboard/TopicPage.qml index ba132b5..689dce7 100644 --- a/qml/tapasboard/TopicPage.qml +++ b/qml/tapasboard/TopicPage.qml @@ -14,17 +14,26 @@ Page { tools: ToolBarLayout { ToolIcon { - id: backToolIcon platformIconId: "toolbar-back" - anchors.left: parent.left onClicked: pageStack.pop() } + ToolIcon { + platformIconId: board.busy ? "toolbar-cancle" : "toolbar-refresh" + onClicked: { + if (board.busy) { + board.cancelAllActions(); + } else { + topicModel.refresh(); + } + } + } } ListView { id: postsView anchors.fill: parent model: TopicModel { + id: topicModel board: topicPage.board topicId: topicPage.topicId } @@ -103,4 +112,11 @@ Page { ScrollDecorator { flickableItem: postsView } + + BusyIndicator { + anchors.centerIn: parent + platformStyle: BusyIndicatorStyle { size: "large" } + visible: postsView.count == 0 && board.busy + running: visible + } } diff --git a/topicmodel.cpp b/topicmodel.cpp index 965481f..c058a6a 100644 --- a/topicmodel.cpp +++ b/topicmodel.cpp @@ -156,6 +156,15 @@ void TopicModel::fetchMore(const QModelIndex &parent) } } +void TopicModel::refresh() +{ + // Forcefully refresh all posts on this topic + _board->enqueueAction(new FetchPostsAction(_topicId, + 0, + FetchPostsAction::FetchAllPosts, + _board)); +} + QDateTime TopicModel::parseDbDateTime(const QVariant &v) { QString s = v.toString(); diff --git a/topicmodel.h b/topicmodel.h index 6f1e99f..0151242 100644 --- a/topicmodel.h +++ b/topicmodel.h @@ -41,6 +41,9 @@ public: bool canFetchMore(const QModelIndex &parent = QModelIndex()) const; void fetchMore(const QModelIndex &parent = QModelIndex()); +public slots: + void refresh(); + signals: void boardChanged(); void topicIdChanged(); -- cgit v1.2.3