mirror of
https://github.com/vale981/tdesktop
synced 2025-03-08 19:21:39 -05:00
Creating HistoryBlock only before adding an item to it.
Now invariants always should be kept true, including indexInBlock, indexInHistory and !block->items.isEmpty() Need to backport UniquePointer from other branch.
This commit is contained in:
parent
8f06244895
commit
fed715c1f4
2 changed files with 204 additions and 132 deletions
|
@ -577,14 +577,8 @@ void ChannelHistory::addNewGroup(const MTPMessageGroup &group) {
|
||||||
|
|
||||||
if (onlyImportant()) {
|
if (onlyImportant()) {
|
||||||
if (newLoaded) {
|
if (newLoaded) {
|
||||||
HistoryBlock *block = blocks.isEmpty() ? pushBackNewBlock() : blocks.back();
|
t_assert(!isBuildingFrontBlock());
|
||||||
HistoryItem *prev = block->items.isEmpty() ? nullptr : block->items.back();
|
addMessageGroup(d);
|
||||||
|
|
||||||
prev = addMessageGroupAfterPrevToBlock(d, prev, block);
|
|
||||||
if (block->items.isEmpty()) {
|
|
||||||
blocks.pop_back();
|
|
||||||
delete block;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setNotLoadedAtBottom();
|
setNotLoadedAtBottom();
|
||||||
|
@ -641,14 +635,12 @@ HistoryJoined *ChannelHistory::insertJoinedMessage(bool unread) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// adding new item to new block
|
startBuildingFrontBlock();
|
||||||
HistoryBlock *block = pushFrontNewBlock();
|
|
||||||
|
|
||||||
_joinedMessage = HistoryJoined::create(this, inviteDate, inviter, flags);
|
_joinedMessage = HistoryJoined::create(this, inviteDate, inviter, flags);
|
||||||
addItemToBlock(_joinedMessage, block);
|
addItemToBlock(_joinedMessage);
|
||||||
|
|
||||||
t_assert(blocks.size() > 1);
|
finishBuildingFrontBlock();
|
||||||
blocks.at(1)->items.front()->previousItemChanged();
|
|
||||||
|
|
||||||
return _joinedMessage;
|
return _joinedMessage;
|
||||||
}
|
}
|
||||||
|
@ -757,15 +749,15 @@ HistoryItem *ChannelHistory::addNewToBlocks(const MTPMessage &msg, NewMessageTyp
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isImportant && onlyImportant()) {
|
if (!isImportant && onlyImportant()) {
|
||||||
HistoryItem *item = addToHistory(msg), *prev = isEmpty() ? nullptr : blocks.back()->items.back();
|
HistoryItem *item = addToHistory(msg);
|
||||||
|
|
||||||
|
t_assert(!isBuildingFrontBlock());
|
||||||
|
addMessageGroup([item, this](HistoryItem *previous) -> HistoryItem* { // create(..)
|
||||||
|
return HistoryGroup::create(this, item, previous ? previous->date : item->date);
|
||||||
|
}, [item](HistoryGroup *existing) { // unite(..)
|
||||||
|
existing->uniteWith(item);
|
||||||
|
});
|
||||||
|
|
||||||
if (prev && prev->type() == HistoryItemGroup) {
|
|
||||||
static_cast<HistoryGroup*>(prev)->uniteWith(item);
|
|
||||||
} else {
|
|
||||||
QDateTime date = prev ? prev->date : item->date;
|
|
||||||
HistoryBlock *block = prev ? prev->block() : pushBackNewBlock();
|
|
||||||
addItemToBlock(HistoryGroup::create(this, item, date), block);
|
|
||||||
}
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -821,22 +813,15 @@ void ChannelHistory::switchMode() {
|
||||||
|
|
||||||
clear(true);
|
clear(true);
|
||||||
|
|
||||||
|
t_assert(!isBuildingFrontBlock());
|
||||||
|
|
||||||
newLoaded = _otherNewLoaded;
|
newLoaded = _otherNewLoaded;
|
||||||
oldLoaded = _otherOldLoaded;
|
oldLoaded = _otherOldLoaded;
|
||||||
if (int count = _otherList.size()) {
|
if (int count = _otherList.size()) {
|
||||||
blocks.reserve(qCeil(count / float64(MessagesPerPage)));
|
blocks.reserve((count / MessagesPerPage) + 1);
|
||||||
|
|
||||||
for (int i = 0; i < count;) {
|
for (int i = 0; i < count;) {
|
||||||
HistoryBlock *block = pushBackNewBlock();
|
t_assert(_otherList.at(i)->detached());
|
||||||
|
addItemToBlock(_otherList.at(i));
|
||||||
int willAddToBlock = qMin(int(MessagesPerPage), count - i);
|
|
||||||
block->items.reserve(willAddToBlock);
|
|
||||||
for (int till = i + willAddToBlock; i < till; ++i) {
|
|
||||||
t_assert(_otherList.at(i)->detached());
|
|
||||||
addItemToBlock(_otherList.at(i), block);
|
|
||||||
}
|
|
||||||
|
|
||||||
t_assert(!block->items.isEmpty());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1550,16 +1535,10 @@ void History::eraseFromOverview(MediaOverviewType type, MsgId msgId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) {
|
HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) {
|
||||||
t_assert(adding != nullptr);
|
t_assert(!isBuildingFrontBlock());
|
||||||
t_assert(adding->detached());
|
addItemToBlock(adding);
|
||||||
|
|
||||||
HistoryBlock *block = blocks.isEmpty() ? pushBackNewBlock() : blocks.back();
|
|
||||||
|
|
||||||
adding->attachToBlock(block, block->items.size());
|
|
||||||
block->items.push_back(adding);
|
|
||||||
adding->previousItemChanged();
|
|
||||||
setLastMessage(adding);
|
setLastMessage(adding);
|
||||||
|
|
||||||
if (newMsg) {
|
if (newMsg) {
|
||||||
newItemAdded(adding);
|
newItemAdded(adding);
|
||||||
}
|
}
|
||||||
|
@ -1671,19 +1650,50 @@ void History::newItemAdded(HistoryItem *item) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryItem *History::addItemToBlock(HistoryItem *item, HistoryBlock *block) {
|
HistoryBlock *History::prepareBlockForAddingItem() {
|
||||||
|
if (isBuildingFrontBlock()) {
|
||||||
|
if (_frontBlock->block) {
|
||||||
|
return _frontBlock->block;
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryBlock *result = _frontBlock->block = new HistoryBlock(this);
|
||||||
|
if (_frontBlock->expectedItemsCount > 0) {
|
||||||
|
result->items.reserve(_frontBlock->expectedItemsCount + 1);
|
||||||
|
}
|
||||||
|
result->setIndexInHistory(0);
|
||||||
|
blocks.push_front(result);
|
||||||
|
for (int i = 1, l = blocks.size(); i < l; ++i) {
|
||||||
|
blocks.at(i)->setIndexInHistory(i);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool addNewBlock = blocks.isEmpty() || (blocks.back()->items.size() >= MessagesPerPage);
|
||||||
|
if (!addNewBlock) {
|
||||||
|
return blocks.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryBlock *result = new HistoryBlock(this);
|
||||||
|
result->setIndexInHistory(blocks.size());
|
||||||
|
blocks.push_back(result);
|
||||||
|
|
||||||
|
result->items.reserve(MessagesPerPage);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
void History::addItemToBlock(HistoryItem *item) {
|
||||||
|
t_assert(item != nullptr);
|
||||||
|
t_assert(item->detached());
|
||||||
|
|
||||||
|
HistoryBlock *block = prepareBlockForAddingItem();
|
||||||
|
|
||||||
item->attachToBlock(block, block->items.size());
|
item->attachToBlock(block, block->items.size());
|
||||||
block->items.push_back(item);
|
block->items.push_back(item);
|
||||||
item->previousItemChanged();
|
item->previousItemChanged();
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryItem *History::addMessageGroupAfterPrevToBlock(const MTPDmessageGroup &group, HistoryItem *prev, HistoryBlock *block) {
|
if (isBuildingFrontBlock() && _frontBlock->expectedItemsCount > 0) {
|
||||||
if (prev && prev->type() == HistoryItemGroup) {
|
--_frontBlock->expectedItemsCount;
|
||||||
static_cast<HistoryGroup*>(prev)->uniteWith(group.vmin_id.v, group.vmax_id.v, group.vcount.v);
|
|
||||||
return prev;
|
|
||||||
}
|
}
|
||||||
return addItemToBlock(HistoryGroup::create(this, group, prev ? prev->date : date(group.vdate)), block);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPMessageGroup> *collapsed) {
|
void History::addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPMessageGroup> *collapsed) {
|
||||||
|
@ -1700,10 +1710,8 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
|
||||||
|
|
||||||
const MTPMessageGroup *groupsBegin = (isChannel() && collapsed) ? collapsed->constData() : 0, *groupsIt = groupsBegin, *groupsEnd = (isChannel() && collapsed) ? (groupsBegin + collapsed->size()) : 0;
|
const MTPMessageGroup *groupsBegin = (isChannel() && collapsed) ? collapsed->constData() : 0, *groupsIt = groupsBegin, *groupsEnd = (isChannel() && collapsed) ? (groupsBegin + collapsed->size()) : 0;
|
||||||
|
|
||||||
HistoryItem *prev = nullptr;
|
startBuildingFrontBlock(slice.size() + (collapsed ? collapsed->size() : 0));
|
||||||
HistoryBlock *block = pushFrontNewBlock();
|
|
||||||
|
|
||||||
block->items.reserve(slice.size() + (collapsed ? collapsed->size() : 0));
|
|
||||||
for (auto i = slice.cend(), e = slice.cbegin(); i != e;) {
|
for (auto i = slice.cend(), e = slice.cbegin(); i != e;) {
|
||||||
--i;
|
--i;
|
||||||
HistoryItem *adding = createItem(*i, false, true);
|
HistoryItem *adding = createItem(*i, false, true);
|
||||||
|
@ -1714,23 +1722,21 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
|
||||||
const MTPDmessageGroup &group(groupsIt->c_messageGroup());
|
const MTPDmessageGroup &group(groupsIt->c_messageGroup());
|
||||||
if (group.vmin_id.v >= adding->id) break;
|
if (group.vmin_id.v >= adding->id) break;
|
||||||
|
|
||||||
prev = addMessageGroupAfterPrevToBlock(group, prev, block);
|
addMessageGroup(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
prev = addItemToBlock(adding, block);
|
addItemToBlock(adding);
|
||||||
}
|
}
|
||||||
for (; groupsIt != groupsEnd; ++groupsIt) {
|
for (; groupsIt != groupsEnd; ++groupsIt) {
|
||||||
if (groupsIt->type() != mtpc_messageGroup) continue;
|
if (groupsIt->type() != mtpc_messageGroup) continue;
|
||||||
const MTPDmessageGroup &group(groupsIt->c_messageGroup());
|
const MTPDmessageGroup &group(groupsIt->c_messageGroup());
|
||||||
|
|
||||||
prev = addMessageGroupAfterPrevToBlock(group, prev, block);
|
addMessageGroup(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block->items.isEmpty()) {
|
HistoryBlock *block = finishBuildingFrontBlock();
|
||||||
blocks.pop_front();
|
if (!block) {
|
||||||
delete block;
|
// If no items were added it means we've loaded everything old.
|
||||||
block = nullptr;
|
|
||||||
|
|
||||||
oldLoaded = true;
|
oldLoaded = true;
|
||||||
} else if (loadedAtBottom()) { // add photos to overview and authors to lastAuthors / lastParticipants
|
} else if (loadedAtBottom()) { // add photos to overview and authors to lastAuthors / lastParticipants
|
||||||
bool channel = isChannel();
|
bool channel = isChannel();
|
||||||
|
@ -1808,28 +1814,6 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// some checks if there was some message history already
|
|
||||||
if (block && blocks.size() > 1) {
|
|
||||||
HistoryItem *last = block->items.back(); // ... item, item, item, last ], [ first, item, item ...
|
|
||||||
HistoryItem *first = blocks.at(1)->items.front();
|
|
||||||
|
|
||||||
// we've added a new front block, so previous item for
|
|
||||||
// the old first item of a first block was changed
|
|
||||||
first->previousItemChanged();
|
|
||||||
|
|
||||||
// we've added a new front block, now we check if both
|
|
||||||
// last message of the first block and first message of
|
|
||||||
// the second block are groups, if they are - unite them
|
|
||||||
if (first->type() == HistoryItemGroup && last->type() == HistoryItemGroup) {
|
|
||||||
static_cast<HistoryGroup*>(first)->uniteWith(static_cast<HistoryGroup*>(last));
|
|
||||||
last->destroy();
|
|
||||||
|
|
||||||
// last->destroy() could've destroyed this new block
|
|
||||||
// so we can't rely on this pointer any more
|
|
||||||
block = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isChannel()) {
|
if (isChannel()) {
|
||||||
asChannelHistory()->checkJoinedMessage();
|
asChannelHistory()->checkJoinedMessage();
|
||||||
asChannelHistory()->checkMaxReadMessageDate();
|
asChannelHistory()->checkMaxReadMessageDate();
|
||||||
|
@ -1845,14 +1829,11 @@ void History::addNewerSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
|
||||||
if (!lastMsg) setLastMessage(lastImportantMessage());
|
if (!lastMsg) setLastMessage(lastImportantMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t_assert(!isBuildingFrontBlock());
|
||||||
if (!slice.isEmpty() || (isChannel() && collapsed && !collapsed->isEmpty())) {
|
if (!slice.isEmpty() || (isChannel() && collapsed && !collapsed->isEmpty())) {
|
||||||
const MTPMessageGroup *groupsBegin = (isChannel() && collapsed) ? collapsed->constData() : 0, *groupsIt = groupsBegin, *groupsEnd = (isChannel() && collapsed) ? (groupsBegin + collapsed->size()) : 0;
|
const MTPMessageGroup *groupsBegin = (isChannel() && collapsed) ? collapsed->constData() : 0, *groupsIt = groupsBegin, *groupsEnd = (isChannel() && collapsed) ? (groupsBegin + collapsed->size()) : 0;
|
||||||
|
|
||||||
HistoryItem *prev = blocks.isEmpty() ? nullptr : blocks.back()->items.back();
|
bool atLeastOneAdded = false;
|
||||||
|
|
||||||
HistoryBlock *block = pushBackNewBlock();
|
|
||||||
|
|
||||||
block->items.reserve(slice.size() + (collapsed ? collapsed->size() : 0));
|
|
||||||
for (auto i = slice.cend(), e = slice.cbegin(); i != e;) {
|
for (auto i = slice.cend(), e = slice.cbegin(); i != e;) {
|
||||||
--i;
|
--i;
|
||||||
HistoryItem *adding = createItem(*i, false, true);
|
HistoryItem *adding = createItem(*i, false, true);
|
||||||
|
@ -1863,25 +1844,22 @@ void History::addNewerSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
|
||||||
const MTPDmessageGroup &group(groupsIt->c_messageGroup());
|
const MTPDmessageGroup &group(groupsIt->c_messageGroup());
|
||||||
if (group.vmin_id.v >= adding->id) break;
|
if (group.vmin_id.v >= adding->id) break;
|
||||||
|
|
||||||
prev = addMessageGroupAfterPrevToBlock(group, prev, block);
|
addMessageGroup(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
prev = addItemToBlock(adding, block);
|
addItemToBlock(adding);
|
||||||
|
atLeastOneAdded = true;
|
||||||
}
|
}
|
||||||
for (; groupsIt != groupsEnd; ++groupsIt) {
|
for (; groupsIt != groupsEnd; ++groupsIt) {
|
||||||
if (groupsIt->type() != mtpc_messageGroup) continue;
|
if (groupsIt->type() != mtpc_messageGroup) continue;
|
||||||
const MTPDmessageGroup &group(groupsIt->c_messageGroup());
|
const MTPDmessageGroup &group(groupsIt->c_messageGroup());
|
||||||
|
|
||||||
prev = addMessageGroupAfterPrevToBlock(group, prev, block);
|
addMessageGroup(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block->items.isEmpty()) {
|
if (!atLeastOneAdded) {
|
||||||
newLoaded = true;
|
newLoaded = true;
|
||||||
setLastMessage(lastImportantMessage());
|
setLastMessage(lastImportantMessage());
|
||||||
|
|
||||||
blocks.pop_back();
|
|
||||||
delete block;
|
|
||||||
block = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2181,21 +2159,76 @@ HistoryItem *History::addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex,
|
||||||
return newItem;
|
return newItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryBlock *History::pushBackNewBlock() {
|
template <typename CreateGroup, typename UniteGroup>
|
||||||
HistoryBlock *result = new HistoryBlock(this);
|
void History::addMessageGroup(CreateGroup create, UniteGroup unite) {
|
||||||
result->setIndexInHistory(blocks.size());
|
HistoryItem *previous = nullptr;
|
||||||
blocks.push_back(result);
|
if (isBuildingFrontBlock()) {
|
||||||
return result;
|
if (_frontBlock->block) {
|
||||||
|
previous = _frontBlock->block->items.back();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!blocks.isEmpty()) {
|
||||||
|
previous = blocks.back()->items.back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previous && previous->type() == HistoryItemGroup) {
|
||||||
|
unite(static_cast<HistoryGroup*>(previous));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryGroup *result = create(previous);
|
||||||
|
if (isBuildingFrontBlock()) {
|
||||||
|
addItemToBuildingFrontBlock(result);
|
||||||
|
} else {
|
||||||
|
addItemToBackBlock(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryBlock *History::pushFrontNewBlock() {
|
void History::addMessageGroup(const MTPDmessageGroup &group) {
|
||||||
HistoryBlock *result = new HistoryBlock(this);
|
addMessageGroup([&group, this](HistoryItem *previous) -> HistoryItem* { // create(..)
|
||||||
result->setIndexInHistory(0);
|
return HistoryGroup::create(this, group, previous ? previous->date : date(group.vdate));
|
||||||
blocks.push_front(result);
|
}, [&group](HistoryGroup *existing) { // unite(..)
|
||||||
for (int i = 1, l = blocks.size(); i < l; ++i) {
|
existing->uniteWith(group.vmin_id.v, group.vmax_id.v, group.vcount.v);
|
||||||
blocks.at(i)->setIndexInHistory(i);
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void History::startBuildingFrontBlock(int expectedItemsCount) {
|
||||||
|
t_assert(!isBuildingFrontBlock());
|
||||||
|
t_assert(expectedItemsCount > 0);
|
||||||
|
|
||||||
|
_frontBlock.reset(new BuildingBlock());
|
||||||
|
_frontBlock->expectedItemsCount = expectedItemsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryBlock *History::finishBuildingFrontBlock() {
|
||||||
|
t_assert(isBuildingFrontBlock());
|
||||||
|
|
||||||
|
// Some checks if there was some message history already
|
||||||
|
HistoryBlock *block = _frontBlock->block;
|
||||||
|
if (block && blocks.size() > 1) {
|
||||||
|
HistoryItem *last = block->items.back(); // ... item, item, item, last ], [ first, item, item ...
|
||||||
|
HistoryItem *first = blocks.at(1)->items.front();
|
||||||
|
|
||||||
|
// we've added a new front block, so previous item for
|
||||||
|
// the old first item of a first block was changed
|
||||||
|
first->previousItemChanged();
|
||||||
|
|
||||||
|
// we've added a new front block, now we check if both
|
||||||
|
// last message of the first block and first message of
|
||||||
|
// the second block are groups, if they are - unite them
|
||||||
|
if (first->type() == HistoryItemGroup && last->type() == HistoryItemGroup) {
|
||||||
|
static_cast<HistoryGroup*>(first)->uniteWith(static_cast<HistoryGroup*>(last));
|
||||||
|
last->destroy();
|
||||||
|
|
||||||
|
// last->destroy() could've destroyed this new block
|
||||||
|
// so we can't rely on this pointer any more
|
||||||
|
block = _frontBlock->block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
_frontBlock.clear();
|
||||||
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::clearNotifications() {
|
void History::clearNotifications() {
|
||||||
|
@ -2572,6 +2605,10 @@ void History::changeMsgId(MsgId oldId, MsgId newId) {
|
||||||
void History::removeBlock(HistoryBlock *block) {
|
void History::removeBlock(HistoryBlock *block) {
|
||||||
t_assert(block->items.isEmpty());
|
t_assert(block->items.isEmpty());
|
||||||
|
|
||||||
|
if (_frontBlock && block == _frontBlock->block) {
|
||||||
|
_frontBlock->block = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
int index = block->indexInHistory();
|
int index = block->indexInHistory();
|
||||||
blocks.removeAt(index);
|
blocks.removeAt(index);
|
||||||
for (int i = index, l = blocks.size(); i < l; ++i) {
|
for (int i = index, l = blocks.size(); i < l; ++i) {
|
||||||
|
|
|
@ -470,19 +470,64 @@ protected:
|
||||||
void clearOnDestroy();
|
void clearOnDestroy();
|
||||||
HistoryItem *addNewToLastBlock(const MTPMessage &msg, NewMessageType type);
|
HistoryItem *addNewToLastBlock(const MTPMessage &msg, NewMessageType type);
|
||||||
|
|
||||||
|
friend class HistoryBlock;
|
||||||
|
|
||||||
|
// this method just removes a block from the blocks list
|
||||||
|
// when the last item from this block was detached and
|
||||||
|
// calls the required previousItemChanged()
|
||||||
|
void removeBlock(HistoryBlock *block);
|
||||||
|
|
||||||
|
void clearBlocks(bool leaveItems);
|
||||||
|
|
||||||
|
HistoryItem *createItem(const MTPMessage &msg, bool applyServiceAction, bool detachExistingItem);
|
||||||
|
HistoryItem *createItemForwarded(MsgId id, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *msg);
|
||||||
|
HistoryItem *createItemDocument(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption);
|
||||||
|
HistoryItem *createItemPhoto(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption);
|
||||||
|
|
||||||
|
HistoryItem *addNewItem(HistoryItem *adding, bool newMsg);
|
||||||
|
HistoryItem *addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex, int32 itemIndex);
|
||||||
|
|
||||||
|
// All this methods add a new item to the first or last block
|
||||||
|
// depending on if we are in isBuildingFronBlock() state.
|
||||||
|
// The last block is created on the go if it is needed.
|
||||||
|
|
||||||
|
// If the previous item is a message group the new group is
|
||||||
|
// not created but is just united with the previous one.
|
||||||
|
// create(HistoryItem *previous) should return a new HistoryGroup*
|
||||||
|
// unite(HistoryGroup *existing) should unite a new group with an existing
|
||||||
|
template <typename CreateGroup, typename UniteGroup>
|
||||||
|
void addMessageGroup(CreateGroup create, UniteGroup unite);
|
||||||
|
void addMessageGroup(const MTPDmessageGroup &group);
|
||||||
|
|
||||||
|
// Adds the item to the back or front block, depending on
|
||||||
|
// isBuildingFrontBlock(), creating the block if necessary.
|
||||||
|
void addItemToBlock(HistoryItem *item);
|
||||||
|
|
||||||
|
// Usually all new items are added to the last block.
|
||||||
|
// Only when we scroll up and add a new slice to the
|
||||||
|
// front we want to create a new front block.
|
||||||
|
void startBuildingFrontBlock(int expectedItemsCount = 1);
|
||||||
|
HistoryBlock *finishBuildingFrontBlock(); // Returns the built block or nullptr if nothing was added.
|
||||||
|
bool isBuildingFrontBlock() const {
|
||||||
|
return !_buildingFrontBlock.isNull();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
enum Flag {
|
enum class Flag {
|
||||||
f_has_pending_resized_items = (1 << 0),
|
f_has_pending_resized_items = (1 << 0),
|
||||||
f_pending_resize = (1 << 1),
|
f_pending_resize = (1 << 1),
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(Flags, Flag);
|
Q_DECLARE_FLAGS(Flags, Flag);
|
||||||
Q_DECL_CONSTEXPR friend inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, Flags::enum_type f2) Q_DECL_NOTHROW {
|
Q_DECL_CONSTEXPR friend inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, Flags::enum_type f2) noexcept {
|
||||||
return QFlags<Flags::enum_type>(f1) | f2;
|
return QFlags<Flags::enum_type>(f1) | f2;
|
||||||
}
|
}
|
||||||
Q_DECL_CONSTEXPR friend inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, QFlags<Flags::enum_type> f2) Q_DECL_NOTHROW {
|
Q_DECL_CONSTEXPR friend inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, QFlags<Flags::enum_type> f2) noexcept {
|
||||||
return f2 | f1;
|
return f2 | f1;
|
||||||
}
|
}
|
||||||
|
Q_DECL_CONSTEXPR friend inline QFlags<Flags::enum_type> operator~(Flags::enum_type f) noexcept {
|
||||||
|
return ~QFlags<Flags::enum_type>(f);
|
||||||
|
}
|
||||||
Flags _flags;
|
Flags _flags;
|
||||||
|
|
||||||
ChatListLinksMap _chatListLinks;
|
ChatListLinksMap _chatListLinks;
|
||||||
|
@ -497,28 +542,18 @@ private:
|
||||||
MediaOverviewIds overviewIds[OverviewCount];
|
MediaOverviewIds overviewIds[OverviewCount];
|
||||||
int32 overviewCountData[OverviewCount]; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded
|
int32 overviewCountData[OverviewCount]; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded
|
||||||
|
|
||||||
friend class HistoryBlock;
|
// A pointer to the block that is currently being built.
|
||||||
friend class ChannelHistory;
|
// We hold this pointer so we can destroy it while building
|
||||||
|
// and then create a new one if it is necessary.
|
||||||
|
struct BuildingBlock {
|
||||||
|
int expectedItemsCount = 0; // optimization for block->items.reserve() call
|
||||||
|
HistoryBlock *block = nullptr;
|
||||||
|
};
|
||||||
|
UniquePointer<BuildingBlock> _buildingFrontBlock;
|
||||||
|
|
||||||
// this method just removes a block from the blocks list
|
// Creates if necessary a new block for adding item.
|
||||||
// when the last item from this block was detached and
|
// Depending on isBuildingFrontBlock() gets front or back block.
|
||||||
// calls the required previousItemChanged()
|
HistoryBlock *prepareBlockForAddingItem();
|
||||||
void removeBlock(HistoryBlock *block);
|
|
||||||
|
|
||||||
void clearBlocks(bool leaveItems);
|
|
||||||
|
|
||||||
HistoryItem *createItem(const MTPMessage &msg, bool applyServiceAction, bool detachExistingItem);
|
|
||||||
HistoryItem *createItemForwarded(MsgId id, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *msg);
|
|
||||||
HistoryItem *createItemDocument(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption);
|
|
||||||
HistoryItem *createItemPhoto(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption);
|
|
||||||
|
|
||||||
HistoryItem *addItemToBlock(HistoryItem *item, HistoryBlock *block);
|
|
||||||
HistoryItem *addNewItem(HistoryItem *adding, bool newMsg);
|
|
||||||
HistoryItem *addMessageGroupAfterPrevToBlock(const MTPDmessageGroup &group, HistoryItem *prev, HistoryBlock *block);
|
|
||||||
HistoryItem *addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex, int32 itemIndex);
|
|
||||||
|
|
||||||
HistoryBlock *pushBackNewBlock();
|
|
||||||
HistoryBlock *pushFrontNewBlock();
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue