+int MessageModel::indexForId(MsgId id)
+{
+ if (messagesIsEmpty() || id <= messageItemAt(0)->msgId())
+ return 0;
+
+ if (id > lastMessageItem()->msgId())
+ return messageCount();
+
+ // binary search
+ int start = 0; int end = messageCount() - 1;
+ while (1) {
+ if (end - start == 1)
+ return end;
+ int pivot = (end + start) / 2;
+ if (id <= messageItemAt(pivot)->msgId()) end = pivot;
+ else start = pivot;
+ }
+}
+
+
+void MessageModel::changeOfDay()
+{
+ _dayChangeTimer.setInterval(DAY_IN_MSECS);
+ if (!messagesIsEmpty()) {
+ int idx = messageCount();
+ while (idx > 0 && messageItemAt(idx - 1)->timestamp() > _nextDayChange) {
+ idx--;
+ }
+ beginInsertRows(QModelIndex(), idx, idx);
+ Message dayChangeMsg = Message::ChangeOfDay(_nextDayChange);
+ dayChangeMsg.setMsgId(messageItemAt(idx - 1)->msgId());
+ insertMessage__(idx, dayChangeMsg);
+ endInsertRows();
+ }
+ _nextDayChange = _nextDayChange.addMSecs(DAY_IN_MSECS);
+}
+
+
+void MessageModel::insertErrorMessage(BufferInfo bufferInfo, const QString &errorString)
+{
+ int idx = messageCount();
+ beginInsertRows(QModelIndex(), idx, idx);
+ Message msg(bufferInfo, Message::Error, errorString);
+ if (!messagesIsEmpty())
+ msg.setMsgId(messageItemAt(idx-1)->msgId());
+ else
+ msg.setMsgId(0);
+ insertMessage__(idx, msg);
+ endInsertRows();
+}
+
+
+void MessageModel::requestBacklog(BufferId bufferId)
+{
+ if (_messagesWaiting.contains(bufferId))
+ return;
+
+ BacklogSettings backlogSettings;
+ int requestCount = backlogSettings.dynamicBacklogAmount();
+
+ for (int i = 0; i < messageCount(); i++) {
+ if (messageItemAt(i)->bufferId() == bufferId) {
+ _messagesWaiting[bufferId] = requestCount;
+ Client::backlogManager()->emitMessagesRequested(tr("Requesting %1 messages from backlog for buffer %2:%3")
+ .arg(requestCount)
+ .arg(Client::networkModel()->networkName(bufferId))
+ .arg(Client::networkModel()->bufferName(bufferId)));
+ Client::backlogManager()->requestBacklog(bufferId, -1, messageItemAt(i)->msgId(), requestCount);
+ return;
+ }
+ }
+}
+
+
+void MessageModel::messagesReceived(BufferId bufferId, int count)
+{
+ if (!_messagesWaiting.contains(bufferId))
+ return;
+
+ _messagesWaiting[bufferId] -= count;
+ if (_messagesWaiting[bufferId] <= 0) {
+ _messagesWaiting.remove(bufferId);
+ emit finishedBacklogFetch(bufferId);
+ }
+}
+
+
+void MessageModel::buffersPermanentlyMerged(BufferId bufferId1, BufferId bufferId2)
+{
+ for (int i = 0; i < messageCount(); i++) {
+ if (messageItemAt(i)->bufferId() == bufferId2) {
+ messageItemAt(i)->setBufferId(bufferId1);
+ QModelIndex idx = index(i, 0);
+ emit dataChanged(idx, idx);
+ }
+ }
+}
+
+
+// ========================================
+// MessageModelItem
+// ========================================
+QVariant MessageModelItem::data(int column, int role) const
+{
+ if (column < MessageModel::TimestampColumn || column > MessageModel::ContentsColumn)
+ return QVariant();
+
+ switch (role) {
+ case MessageModel::MessageRole:
+ return QVariant::fromValue<Message>(message());
+ case MessageModel::MsgIdRole:
+ return QVariant::fromValue<MsgId>(msgId());
+ case MessageModel::BufferIdRole:
+ return QVariant::fromValue<BufferId>(bufferId());
+ case MessageModel::TypeRole:
+ return msgType();
+ case MessageModel::FlagsRole:
+ return (int)msgFlags();
+ case MessageModel::TimestampRole:
+ return timestamp();
+ case MessageModel::RedirectedToRole:
+ return qVariantFromValue<BufferId>(_redirectedTo);
+ default:
+ return QVariant();
+ }
+}
+
+
+bool MessageModelItem::setData(int column, const QVariant &value, int role)
+{
+ Q_UNUSED(column);
+
+ switch (role) {
+ case MessageModel::RedirectedToRole:
+ _redirectedTo = value.value<BufferId>();
+ return true;
+ default:
+ return false;
+ }