From 93660233fdbf71b4002c9c7b18f5271934182f37 Mon Sep 17 00:00:00 2001 From: fourtf Date: Thu, 2 Feb 2017 20:35:12 +0100 Subject: [PATCH] added limited queue --- channel.cpp | 22 +++----- channel.h | 25 +++++---- chatterino.pro | 4 +- messages/limitedqueue.h | 97 +++++++++++++++++++++++++++++++++ messages/limitedqueuesnapshot.h | 48 ++++++++++++++++ messages/message.h | 2 +- widgets/chatwidgetview.cpp | 22 ++++---- widgets/notebook.cpp | 4 -- widgets/scrollbar.cpp | 9 +-- widgets/scrollbar.h | 4 +- 10 files changed, 191 insertions(+), 46 deletions(-) create mode 100644 messages/limitedqueue.h create mode 100644 messages/limitedqueuesnapshot.h diff --git a/channel.cpp b/channel.cpp index 360e88d7..75ad0364 100644 --- a/channel.cpp +++ b/channel.cpp @@ -128,23 +128,17 @@ Channel::reloadFfzEmotes() }); } -QVector> -Channel::getMessagesClone() -{ - this->messageMutex.lock(); - QVector> M(this->messages); - M.detach(); - this->messageMutex.unlock(); - return M; -} - void Channel::addMessage(std::shared_ptr message) { - this->messageMutex.lock(); - this->messages.append(message); - this->messageMutex.unlock(); + std::shared_ptr deleted; - Windows::repaintVisibleChatWidgets(); + if (this->messages.appendItem(message, deleted)) { + this->messageRemovedFromStart(deleted); + } + + this->messageAppended(message); + + Windows::repaintVisibleChatWidgets(this); } } diff --git a/channel.h b/channel.h index b340e459..24da99ab 100644 --- a/channel.h +++ b/channel.h @@ -3,11 +3,13 @@ #include "concurrentmap.h" #include "messages/lazyloadedimage.h" +#include "messages/limitedqueue.h" #include #include #include #include +#include #include namespace chatterino { @@ -20,6 +22,11 @@ class Channel public: Channel(const QString &channel); + boost::signals2::signal &)> + messageRemovedFromStart; + boost::signals2::signal &)> + messageAppended; + // properties ConcurrentMap & getBttvChannelEmotes() @@ -95,25 +102,23 @@ public: } // methods - void addMessage(std::shared_ptr message); - - QVector> getMessagesClone(); - - QVector> & - getMessages() + messages::LimitedQueueSnapshot> + getMessageSnapshot() { - return messages; + return messages.getSnapshot(); } + void addMessage(std::shared_ptr message); + void reloadChannelEmotes() { - reloadBttvEmotes(); - reloadFfzEmotes(); + this->reloadBttvEmotes(); + this->reloadFfzEmotes(); } private: - QVector> messages; + messages::LimitedQueue> messages; QString name; int roomID; diff --git a/chatterino.pro b/chatterino.pro index 4f5358e8..cea92840 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -95,7 +95,9 @@ HEADERS += account.h \ windows.h \ widgets/resizingtextedit.h \ settingssnapshot.h \ - logging.h + logging.h \ + messages/limitedqueue.h \ + messages/limitedqueuesnapshot.h PRECOMPILED_HEADER = diff --git a/messages/limitedqueue.h b/messages/limitedqueue.h new file mode 100644 index 00000000..b7f764c0 --- /dev/null +++ b/messages/limitedqueue.h @@ -0,0 +1,97 @@ +#ifndef LIMITEDQUEUE_H +#define LIMITEDQUEUE_H + +#include "messages/limitedqueuesnapshot.h" + +#include +#include +#include +#include + +namespace chatterino { +namespace messages { + +template +class LimitedQueue +{ +public: + LimitedQueue(int limit = 10, int buffer = 5) + : vector(new std::vector(limit + buffer)) + , vectorPtr(this->vector) + , mutex() + , offset(0) + , length(0) + , limit(limit) + , buffer(buffer) + { + ; + } + + // return true if an item was deleted + // deleted will be set if the item was deleted + bool + appendItem(const T &item, T &deleted) + { + std::lock_guard lock(this->mutex); + + if (this->length == this->limit) { + // vector is full + if (this->offset == this->buffer) { + deleted = this->vector->at(this->offset); + + // create new vector + auto *vector = new std::vector(this->limit + this->buffer); + + for (int i = 0; i < this->limit; i++) { + vector->at(i) = this->vector->at(i + this->offset); + } + + vector->at(limit - 1) = item; + + this->offset = 0; + + this->vector = vector; + this->vectorPtr = std::shared_ptr>(vector); + + return true; + } else { + // append item and remove first + deleted = this->vector->at(this->offset); + + this->vector->at(this->length + this->offset) = item; + this->offset++; + + return true; + } + } else { + // append item + this->vector->at(this->length) = item; + this->length++; + + return false; + } + } + + messages::LimitedQueueSnapshot + getSnapshot() + { + std::lock_guard lock(mutex); + + return LimitedQueueSnapshot(vectorPtr, offset, length); + } + +private: + std::vector *vector; + std::shared_ptr> vectorPtr; + + std::mutex mutex; + + int offset; + int length; + int limit; + int buffer; +}; +} +} + +#endif // LIMITEDQUEUE_H diff --git a/messages/limitedqueuesnapshot.h b/messages/limitedqueuesnapshot.h new file mode 100644 index 00000000..60045d61 --- /dev/null +++ b/messages/limitedqueuesnapshot.h @@ -0,0 +1,48 @@ +#ifndef LIMITEDQUEUESNAPSHOT_H +#define LIMITEDQUEUESNAPSHOT_H + +#include +#include +#include + +namespace chatterino { +namespace messages { + +template +class LimitedQueueSnapshot +{ +public: + LimitedQueueSnapshot(std::shared_ptr> ptr, int offset, + int length) + : vectorPtr(ptr) + , vector(ptr.get()) + , offset(offset) + , length(length) + { + } + + int + getLength() + { + return length; + } + + T const &operator[](int index) const + { + assert(index >= 0); + assert(index < length); + + return vector->at(index + offset); + } + +private: + std::shared_ptr> vectorPtr; + std::vector *vector; + + int offset; + int length; +}; +} +} + +#endif // LIMITEDQUEUESNAPSHOT_H diff --git a/messages/message.h b/messages/message.h index 993dc6ed..9540523c 100644 --- a/messages/message.h +++ b/messages/message.h @@ -16,7 +16,7 @@ class Message { public: Message(const QString &text); - Message(const IrcPrivateMessage &ircMessage, Channel &Channel, + Message(const IrcPrivateMessage &ircMessage, Channel &channel, bool enablePingSound = true, bool isReceivedWhisper = false, bool isSentWhisper = false, bool includeChannel = false); diff --git a/widgets/chatwidgetview.cpp b/widgets/chatwidgetview.cpp index 879d3107..0a462cff 100644 --- a/widgets/chatwidgetview.cpp +++ b/widgets/chatwidgetview.cpp @@ -47,17 +47,19 @@ ChatWidgetView::layoutMessages() bool showScrollbar = false; - auto messages = c->getMessagesClone(); + auto messages = c->getMessageSnapshot(); bool redraw = false; - for (std::shared_ptr &message : messages) { - redraw |= message.get()->layout(this->width(), true); - } + // for (std::shared_ptr &message : messages) { + // redraw |= message.get()->layout(this->width(), true); + // } + + redraw = true; int h = this->height() - 8; - for (int i = messages.size() - 1; i >= 0; i--) { + for (int i = messages.getLength() - 1; i >= 0; i--) { auto *message = messages[i].get(); message->layout(this->width(), true); @@ -65,7 +67,7 @@ ChatWidgetView::layoutMessages() h -= message->getHeight(); if (h < 0) { - this->scrollbar.setLargeChange((messages.size() - i) + + this->scrollbar.setLargeChange((messages.getLength() - i) + (qreal)h / message->getHeight()); this->scrollbar.setDesiredValue(this->scrollbar.getDesiredValue()); @@ -76,7 +78,7 @@ ChatWidgetView::layoutMessages() this->scrollbar.setVisible(showScrollbar); - this->scrollbar.setMaximum(c->getMessages().size()); + this->scrollbar.setMaximum(messages.getLength()); return redraw; } @@ -138,18 +140,18 @@ ChatWidgetView::paintEvent(QPaintEvent *) if (c == NULL) return; - auto messages = c->getMessagesClone(); + auto messages = c->getMessageSnapshot(); int start = this->scrollbar.getCurrentValue(); - if (start >= messages.length()) { + if (start >= messages.getLength()) { return; } int y = -(messages[start].get()->getHeight() * (fmod(this->scrollbar.getCurrentValue(), 1))); - for (int i = start; i < messages.size(); ++i) { + for (int i = start; i < messages.getLength(); ++i) { messages::Message *message = messages[i].get(); for (messages::WordPart const &wordPart : message->getWordParts()) { diff --git a/widgets/notebook.cpp b/widgets/notebook.cpp index 83fe60af..9030e886 100644 --- a/widgets/notebook.cpp +++ b/widgets/notebook.cpp @@ -133,12 +133,8 @@ Notebook::tabAt(QPoint point, int &index) void Notebook::rearrangePage(NotebookPage *page, int index) { - int i1 = pages.indexOf(page); - pages.move(pages.indexOf(page), index); - int i2 = pages.indexOf(page); - performLayout(); } diff --git a/widgets/scrollbar.cpp b/widgets/scrollbar.cpp index 114f73d2..334661bc 100644 --- a/widgets/scrollbar.cpp +++ b/widgets/scrollbar.cpp @@ -28,10 +28,11 @@ ScrollBar::ScrollBar(QWidget *widget) , currentValueChanged() , currentValue() { - resize(16, 100); + this->resize(16, 100); - currentValueAnimation.setDuration(300); - currentValueAnimation.setEasingCurve(QEasingCurve(QEasingCurve::OutCubic)); + this->currentValueAnimation.setDuration(300); + this->currentValueAnimation.setEasingCurve( + QEasingCurve(QEasingCurve::OutCubic)); this->setMouseTracking(true); } @@ -211,7 +212,7 @@ ScrollBar::updateScroll() this->thumbRect = QRect(0, - (int)(this->desiredValue / this->maximum * this->trackHeight) + + (int)(this->currentValue / this->maximum * this->trackHeight) + 1 + this->buttonHeight, width(), (int)(this->largeChange / this->maximum * this->trackHeight) + diff --git a/widgets/scrollbar.h b/widgets/scrollbar.h index e20345cb..f4e1d074 100644 --- a/widgets/scrollbar.h +++ b/widgets/scrollbar.h @@ -63,8 +63,6 @@ public: value = std::max(this->minimum, std::min(this->maximum - this->largeChange, value)); - this->desiredValue = value; - if (this->desiredValue != value) { if (animated) { this->currentValueAnimation.stop(); @@ -78,6 +76,8 @@ public: this->setCurrentValue(value); } } + + this->desiredValue = value; } qreal