From 0a9e72020e3ec0bcfdca98891466e79cca8c23ec Mon Sep 17 00:00:00 2001 From: TriKriSta Date: Mon, 1 Jul 2019 14:27:58 +0300 Subject: [PATCH] refactor: edit load history when scrolling --- src/chatlog/chatlog.cpp | 68 ++++++++++++++++++++++++----- src/chatlog/chatlog.h | 10 ++++- src/model/chathistory.cpp | 5 ++- src/model/ichatlog.h | 2 - src/widget/form/genericchatform.cpp | 54 +++++++++++++---------- src/widget/form/genericchatform.h | 4 -- 6 files changed, 100 insertions(+), 43 deletions(-) diff --git a/src/chatlog/chatlog.cpp b/src/chatlog/chatlog.cpp index dd2ca0b82..6e761753f 100644 --- a/src/chatlog/chatlog.cpp +++ b/src/chatlog/chatlog.cpp @@ -363,6 +363,7 @@ void ChatLog::reposition(int start, int end, qreal deltaY) void ChatLog::insertChatlineAtBottom(ChatLine::Ptr l) { + numRemove = 0; if (!l.get()) return; @@ -386,9 +387,14 @@ void ChatLog::insertChatlineAtBottom(ChatLine::Ptr l) void ChatLog::insertChatlineAtBottom(const QList& newLines) { + numRemove = 0; if (newLines.isEmpty()) return; + if (lines.size() + DEF_NUM_MSG_TO_LOAD >= maxMessages) { + removeFirsts(DEF_NUM_MSG_TO_LOAD); + } + for (ChatLine::Ptr l : newLines) { l->setRow(lines.size()); l->addToScene(scene); @@ -397,11 +403,17 @@ void ChatLog::insertChatlineAtBottom(const QList& newLines) } layout(lines.last()->getRow(), lines.size(), useableWidth()); - startResizeWorker(); + + if (visibleLines.size() > 1) { + startResizeWorker(visibleLines[1]); + } else { + startResizeWorker(); + } } void ChatLog::insertChatlineOnTop(ChatLine::Ptr l) { + numRemove = 0; if (!l.get()) return; @@ -410,6 +422,7 @@ void ChatLog::insertChatlineOnTop(ChatLine::Ptr l) void ChatLog::insertChatlinesOnTop(const QList& newLines) { + numRemove = 0; if (newLines.isEmpty()) return; @@ -429,6 +442,10 @@ void ChatLog::insertChatlinesOnTop(const QList& newLines) combLines.push_back(l); } + if (lines.size() + DEF_NUM_MSG_TO_LOAD >= maxMessages) { + removeLasts(DEF_NUM_MSG_TO_LOAD); + } + // add the old lines for (ChatLine::Ptr l : lines) { l->setRow(i++); @@ -440,7 +457,12 @@ void ChatLog::insertChatlinesOnTop(const QList& newLines) scene->setItemIndexMethod(oldIndexMeth); // redo layout - startResizeWorker(); + if (visibleLines.size() > 1) { + startResizeWorker(visibleLines[1]); + } else { + startResizeWorker(); + } + } bool ChatLog::stickToBottom() const @@ -454,19 +476,22 @@ void ChatLog::scrollToBottom() verticalScrollBar()->setValue(verticalScrollBar()->maximum()); } -void ChatLog::startResizeWorker() +void ChatLog::startResizeWorker(ChatLine::Ptr anchorLine) { if (lines.empty()) { + isScroll = true; return; } // (re)start the worker if (!workerTimer->isActive()) { // these values must not be reevaluated while the worker is running - workerStb = stickToBottom(); - - if (!visibleLines.empty()) - workerAnchorLine = visibleLines.first(); + if (anchorLine) { + workerAnchorLine = anchorLine; + workerStb = false; + } else { + workerStb = stickToBottom(); + } } // switch to busy scene displaying the busy notification if there is a lot @@ -653,8 +678,13 @@ void ChatLog::scrollToLine(ChatLine::Ptr line) if (!line.get()) return; - updateSceneRect(); - verticalScrollBar()->setValue(line->sceneBoundingRect().top()); + if (workerTimer->isActive()) { + workerAnchorLine = line; + workerStb = false; + } else { + updateSceneRect(); + verticalScrollBar()->setValue(line->sceneBoundingRect().top()); // NOTE: start here + } } void ChatLog::selectAll() @@ -696,6 +726,7 @@ void ChatLog::removeFirsts(const int num) { if (lines.size() > num) { lines.erase(lines.begin(), lines.begin()+num); + numRemove = num; } else { lines.clear(); } @@ -709,11 +740,22 @@ void ChatLog::removeLasts(const int num) { if (lines.size() > num) { lines.erase(lines.end()-num, lines.end()); + numRemove = num; } else { lines.clear(); } } +void ChatLog::setScroll(const bool scroll) +{ + isScroll = scroll; +} + +int ChatLog::getNumRemove() const +{ + return numRemove; +} + void ChatLog::forceRelayout() { startResizeWorker(); @@ -762,6 +804,7 @@ void ChatLog::checkVisibility(bool causedWheelEvent) } if (causedWheelEvent) { + qDebug() << "causedWheelEvent"; if (lowerBound != lines.cend() && lowerBound->get()->row == 0) { emit loadHistoryLower(); } else if (upperBound == lines.cend()) { @@ -905,7 +948,8 @@ void ChatLog::onWorkerTimeout() // hidden during busy screen verticalScrollBar()->show(); - emit workerTimeoutFinished(); + isScroll = true; + emit workerTimeoutFinished(); } } @@ -972,6 +1016,10 @@ void ChatLog::focusOutEvent(QFocusEvent* ev) void ChatLog::wheelEvent(QWheelEvent *event) { + if (!isScroll) { + return; + } + QGraphicsView::wheelEvent(event); checkVisibility(true); } diff --git a/src/chatlog/chatlog.h b/src/chatlog/chatlog.h index 133a896ed..61c63304c 100644 --- a/src/chatlog/chatlog.h +++ b/src/chatlog/chatlog.h @@ -35,6 +35,8 @@ class QTimer; class ChatLineContent; struct ToxFile; +static const auto DEF_NUM_MSG_TO_LOAD = 100; + class ChatLog : public QGraphicsView { Q_OBJECT @@ -58,6 +60,8 @@ public: void reloadTheme(); void removeFirsts(const int num); void removeLasts(const int num); + void setScroll(const bool scroll); + int getNumRemove() const; QString getSelectedText() const; @@ -101,7 +105,7 @@ protected: void updateSceneRect(); void checkVisibility(bool causedWheelEvent = false); void scrollToBottom(); - void startResizeWorker(); + void startResizeWorker(ChatLine::Ptr anchorLine = nullptr); virtual void mouseDoubleClickEvent(QMouseEvent* ev) final override; virtual void mousePressEvent(QMouseEvent* ev) final override; @@ -165,6 +169,7 @@ private: int clickCount = 0; QPoint lastClickPos; Qt::MouseButton lastClickButton; + bool isScroll{true}; // worker vars int workerLastIndex = 0; @@ -174,6 +179,9 @@ private: // layout QMargins margins = QMargins(10, 10, 10, 10); qreal lineSpacing = 5.0f; + + int numRemove{0}; + const int maxMessages{300}; }; #endif // CHATLOG_H diff --git a/src/model/chathistory.cpp b/src/model/chathistory.cpp index 84bfb5d33..24096f710 100644 --- a/src/model/chathistory.cpp +++ b/src/model/chathistory.cpp @@ -110,9 +110,10 @@ ChatHistory::ChatHistory(Friend& f_, History* history_, const ICoreIdHandler& co // NOTE: this has to be done _after_ sending all sent messages since initial // state of the message has to be marked according to our dispatch state - auto firstChatLogIdx = sessionChatLog.getFirstIdx().get() < DEF_NUM_MSG_TO_LOAD + constexpr auto defaultNumMessagesToLoad = 100; + auto firstChatLogIdx = sessionChatLog.getFirstIdx().get() < defaultNumMessagesToLoad ? ChatLogIdx(0) - : sessionChatLog.getFirstIdx() - DEF_NUM_MSG_TO_LOAD; + : sessionChatLog.getFirstIdx() - defaultNumMessagesToLoad; if (canUseHistory()) { loadHistoryIntoSessionChatLog(firstChatLogIdx); diff --git a/src/model/ichatlog.h b/src/model/ichatlog.h index 1438610d6..2144c2d0d 100644 --- a/src/model/ichatlog.h +++ b/src/model/ichatlog.h @@ -35,8 +35,6 @@ #include -static const auto DEF_NUM_MSG_TO_LOAD = 100; - using ChatLogIdx = NamedType; Q_DECLARE_METATYPE(ChatLogIdx); diff --git a/src/widget/form/genericchatform.cpp b/src/widget/form/genericchatform.cpp index bd66e8bd3..0beb03a02 100644 --- a/src/widget/form/genericchatform.cpp +++ b/src/widget/form/genericchatform.cpp @@ -53,6 +53,8 @@ #include #include +#include + #ifdef SPELL_CHECKING #include #endif @@ -660,6 +662,7 @@ void GenericChatForm::loadHistory(const QDateTime &time, const LoadHistoryDialog if (type == LoadHistoryDialog::from) { loadHistoryFrom(time); auto msg = messages.cbegin()->second; + chatWidget->setScroll(true); chatWidget->scrollToLine(msg); } else { loadHistoryTo(time); @@ -668,15 +671,10 @@ void GenericChatForm::loadHistory(const QDateTime &time, const LoadHistoryDialog void GenericChatForm::loadHistoryTo(const QDateTime &time) { + chatWidget->setScroll(false); auto end = ChatLogIdx(0); if (time.isNull()) { - if (messages.size() + DEF_NUM_MSG_TO_LOAD >= maxMessages) { - end = ChatLogIdx(messages.rbegin()->first.get() - DEF_NUM_MSG_TO_LOAD); - chatWidget->removeLasts(DEF_NUM_MSG_TO_LOAD); - removeLastsMessages(DEF_NUM_MSG_TO_LOAD); - } else { - end = messages.begin()->first; - } + end = messages.begin()->first; } else { end = firstItemAfterDate(time.date(), chatLog); } @@ -686,28 +684,27 @@ void GenericChatForm::loadHistoryTo(const QDateTime &time) begin = ChatLogIdx(end.get() - DEF_NUM_MSG_TO_LOAD); } - renderMessages(begin, end); + if (begin != end) { + renderMessages(begin, end); + } else { + chatWidget->setScroll(true); + } } void GenericChatForm::loadHistoryFrom(const QDateTime &time) { + chatWidget->setScroll(false); auto begin = ChatLogIdx(0); if (time.isNull()) { - if (messages.size() + DEF_NUM_MSG_TO_LOAD >= maxMessages) { - begin = ChatLogIdx(messages.rbegin()->first.get() + DEF_NUM_MSG_TO_LOAD); - chatWidget->removeFirsts(DEF_NUM_MSG_TO_LOAD); - removeFirstsMessages(DEF_NUM_MSG_TO_LOAD); - } else { - begin = messages.rbegin()->first; - } - + begin = messages.rbegin()->first; } else { begin = firstItemAfterDate(time.date(), chatLog); } int add = DEF_NUM_MSG_TO_LOAD; if (begin.get() + DEF_NUM_MSG_TO_LOAD > chatLog.getNextIdx().get()) { - add = chatLog.getNextIdx().get() - (begin.get() + DEF_NUM_MSG_TO_LOAD); + auto aTest = chatLog.getNextIdx().get(); + add = chatLog.getNextIdx().get() - begin.get(); } auto end = ChatLogIdx(begin.get() + add); renderMessages(begin, end); @@ -1024,10 +1021,6 @@ void GenericChatForm::handleSearchResult(SearchResult result, SearchDirection di void GenericChatForm::renderMessage(ChatLogIdx idx) { - if (chatWidget->getLines().size() >= maxMessages) { - chatWidget->removeFirsts(optimalRemove); - removeFirstsMessages(optimalRemove); - } renderMessages(idx, idx + 1); } @@ -1037,6 +1030,11 @@ void GenericChatForm::renderMessages(ChatLogIdx begin, ChatLogIdx end, QList beforeLines; QList afterLines; + if (!messages.empty() && !(messages.rbegin()->first == begin || messages.begin()->first == end + || messages.rbegin()->first.get() + 1 == begin.get())) { + return; + } + for (auto i = begin; i < end; ++i) { auto chatMessage = getChatMessageForIdx(i, messages); renderItem(chatLog.at(i), needsToHideName(i), colorizeNames, chatMessage); @@ -1054,8 +1052,13 @@ void GenericChatForm::renderMessages(ChatLogIdx begin, ChatLogIdx end, } } - for (auto const& line : afterLines) { - chatWidget->insertChatlineAtBottom(line); + if (beforeLines.isEmpty() && afterLines.isEmpty()) { + chatWidget->setScroll(true); + } + + chatWidget->insertChatlineAtBottom(afterLines); + if (chatWidget->getNumRemove()) { + removeFirstsMessages(chatWidget->getNumRemove()); } if (!beforeLines.empty()) { @@ -1072,6 +1075,9 @@ void GenericChatForm::renderMessages(ChatLogIdx begin, ChatLogIdx end, } chatWidget->insertChatlinesOnTop(beforeLines); + if (chatWidget->getNumRemove()) { + removeLastsMessages(chatWidget->getNumRemove()); + } } else if (onCompletion) { onCompletion(); } @@ -1081,7 +1087,7 @@ void GenericChatForm::goToCurrentDate() { chatWidget->clear(); messages.clear(); - auto end = ChatLogIdx(chatLog.size() - 1); + auto end = ChatLogIdx(chatLog.size()); auto begin = end.get() > DEF_NUM_MSG_TO_LOAD ? ChatLogIdx(end.get() - DEF_NUM_MSG_TO_LOAD) : ChatLogIdx(0); renderMessages(begin, end); diff --git a/src/widget/form/genericchatform.h b/src/widget/form/genericchatform.h index aa4935a16..e4cb253ba 100644 --- a/src/widget/form/genericchatform.h +++ b/src/widget/form/genericchatform.h @@ -201,10 +201,6 @@ protected: SearchPos searchPos; std::map messages; bool colorizeNames = false; - -private: - const int maxMessages{300}; - const int optimalRemove{50}; }; #endif // GENERICCHATFORM_H