mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Merge pull request #5793
TriKriSta (5): fix: data validation during the search (fix: #5791, #5723) feat: check chat status before start a search feat: save selected search text after scrolling up refactor: optimize load messages during the search fix: update workerStb
This commit is contained in:
commit
834baff556
|
@ -683,7 +683,7 @@ void ChatLog::scrollToLine(ChatLine::Ptr line)
|
||||||
workerStb = false;
|
workerStb = false;
|
||||||
} else {
|
} else {
|
||||||
updateSceneRect();
|
updateSceneRect();
|
||||||
verticalScrollBar()->setValue(line->sceneBoundingRect().top()); // NOTE: start here
|
verticalScrollBar()->setValue(line->sceneBoundingRect().top());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -936,10 +936,12 @@ void ChatLog::onWorkerTimeout()
|
||||||
updateMultiSelectionRect();
|
updateMultiSelectionRect();
|
||||||
|
|
||||||
// scroll
|
// scroll
|
||||||
if (workerStb)
|
if (workerStb) {
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
else
|
workerStb = false;
|
||||||
|
} else {
|
||||||
scrollToLine(workerAnchorLine);
|
scrollToLine(workerAnchorLine);
|
||||||
|
}
|
||||||
|
|
||||||
// don't keep a Ptr to the anchor line
|
// don't keep a Ptr to the anchor line
|
||||||
workerAnchorLine = ChatLine::Ptr();
|
workerAnchorLine = ChatLine::Ptr();
|
||||||
|
|
|
@ -174,6 +174,7 @@ SearchResult ChatHistory::searchBackward(SearchPos startIdx, const QString& phra
|
||||||
history->getDateWhereFindPhrase(f.getPublicKey().toString(), earliestMessageDate, phrase,
|
history->getDateWhereFindPhrase(f.getPublicKey().toString(), earliestMessageDate, phrase,
|
||||||
parameter);
|
parameter);
|
||||||
|
|
||||||
|
if (dateWherePhraseFound.isValid()) {
|
||||||
auto loadIdx = history->getNumMessagesForFriendBeforeDate(f.getPublicKey(), dateWherePhraseFound);
|
auto loadIdx = history->getNumMessagesForFriendBeforeDate(f.getPublicKey(), dateWherePhraseFound);
|
||||||
loadHistoryIntoSessionChatLog(ChatLogIdx(loadIdx));
|
loadHistoryIntoSessionChatLog(ChatLogIdx(loadIdx));
|
||||||
|
|
||||||
|
@ -181,6 +182,11 @@ SearchResult ChatHistory::searchBackward(SearchPos startIdx, const QString& phra
|
||||||
startIdx.logIdx = ChatLogIdx(loadIdx);
|
startIdx.logIdx = ChatLogIdx(loadIdx);
|
||||||
startIdx.numMatches = 0;
|
startIdx.numMatches = 0;
|
||||||
return sessionChatLog.searchBackward(startIdx, phrase, parameter);
|
return sessionChatLog.searchBackward(startIdx, phrase, parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchResult ret;
|
||||||
|
ret.found = false;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatLogIdx ChatHistory::getFirstIdx() const
|
ChatLogIdx ChatHistory::getFirstIdx() const
|
||||||
|
|
|
@ -70,7 +70,7 @@ struct SearchPos
|
||||||
|
|
||||||
struct SearchResult
|
struct SearchResult
|
||||||
{
|
{
|
||||||
bool found;
|
bool found{false};
|
||||||
SearchPos pos;
|
SearchPos pos;
|
||||||
size_t start;
|
size_t start;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
|
@ -685,7 +685,11 @@ void GenericChatForm::loadHistoryTo(const QDateTime &time)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (begin != end) {
|
if (begin != end) {
|
||||||
|
if (searchResult.found == true && searchResult.pos.logIdx == end) {
|
||||||
|
renderMessages(begin, end, [this]{enableSearchText();});
|
||||||
|
} else {
|
||||||
renderMessages(begin, end);
|
renderMessages(begin, end);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
chatWidget->setScroll(true);
|
chatWidget->setScroll(true);
|
||||||
}
|
}
|
||||||
|
@ -730,13 +734,23 @@ void GenericChatForm::removeLastsMessages(const int num)
|
||||||
|
|
||||||
void GenericChatForm::disableSearchText()
|
void GenericChatForm::disableSearchText()
|
||||||
{
|
{
|
||||||
auto msgIt = messages.find(searchPos.logIdx);
|
auto msgIt = messages.find(searchResult.pos.logIdx);
|
||||||
if (msgIt != messages.end()) {
|
if (msgIt != messages.end()) {
|
||||||
auto text = qobject_cast<Text*>(msgIt->second->getContent(1));
|
auto text = qobject_cast<Text*>(msgIt->second->getContent(1));
|
||||||
text->deselectText();
|
text->deselectText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GenericChatForm::enableSearchText()
|
||||||
|
{
|
||||||
|
auto msg = messages.at(searchResult.pos.logIdx);
|
||||||
|
chatWidget->scrollToLine(msg);
|
||||||
|
|
||||||
|
auto text = qobject_cast<Text*>(msg->getContent(1));
|
||||||
|
text->visibilityChanged(true);
|
||||||
|
text->selectText(searchResult.exp, std::make_pair(searchResult.start, searchResult.len));
|
||||||
|
}
|
||||||
|
|
||||||
void GenericChatForm::clearChatArea()
|
void GenericChatForm::clearChatArea()
|
||||||
{
|
{
|
||||||
clearChatArea(/* confirm = */ true, /* inform = */ true);
|
clearChatArea(/* confirm = */ true, /* inform = */ true);
|
||||||
|
@ -933,6 +947,7 @@ void GenericChatForm::onExportChat()
|
||||||
void GenericChatForm::onSearchTriggered()
|
void GenericChatForm::onSearchTriggered()
|
||||||
{
|
{
|
||||||
if (searchForm->isHidden()) {
|
if (searchForm->isHidden()) {
|
||||||
|
searchResult.found = false;
|
||||||
searchForm->removeSearchPhrase();
|
searchForm->removeSearchPhrase();
|
||||||
}
|
}
|
||||||
disableSearchText();
|
disableSearchText();
|
||||||
|
@ -940,39 +955,43 @@ void GenericChatForm::onSearchTriggered()
|
||||||
|
|
||||||
void GenericChatForm::searchInBegin(const QString& phrase, const ParameterSearch& parameter)
|
void GenericChatForm::searchInBegin(const QString& phrase, const ParameterSearch& parameter)
|
||||||
{
|
{
|
||||||
|
if (phrase.isEmpty()) {
|
||||||
disableSearchText();
|
disableSearchText();
|
||||||
|
|
||||||
if (!parameter.time.isNull()) {
|
return;
|
||||||
LoadHistoryDialog::LoadType type = (parameter.period == PeriodSearch::BeforeDate)
|
}
|
||||||
? LoadHistoryDialog::to : LoadHistoryDialog::from;
|
|
||||||
loadHistory(parameter.time, type);
|
if (chatLog.getNextIdx().get() == messages.rbegin()->first.get() + 1) {
|
||||||
|
disableSearchText();
|
||||||
|
} else {
|
||||||
|
goToCurrentDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bForwardSearch = false;
|
bool bForwardSearch = false;
|
||||||
switch (parameter.period) {
|
switch (parameter.period) {
|
||||||
case PeriodSearch::WithTheFirst: {
|
case PeriodSearch::WithTheFirst: {
|
||||||
bForwardSearch = true;
|
bForwardSearch = true;
|
||||||
searchPos.logIdx = chatLog.getFirstIdx();
|
searchResult.pos.logIdx = chatLog.getFirstIdx();
|
||||||
searchPos.numMatches = 0;
|
searchResult.pos.numMatches = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PeriodSearch::WithTheEnd:
|
case PeriodSearch::WithTheEnd:
|
||||||
case PeriodSearch::None: {
|
case PeriodSearch::None: {
|
||||||
bForwardSearch = false;
|
bForwardSearch = false;
|
||||||
searchPos.logIdx = chatLog.getNextIdx();
|
searchResult.pos.logIdx = chatLog.getNextIdx();
|
||||||
searchPos.numMatches = 0;
|
searchResult.pos.numMatches = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PeriodSearch::AfterDate: {
|
case PeriodSearch::AfterDate: {
|
||||||
bForwardSearch = true;
|
bForwardSearch = true;
|
||||||
searchPos.logIdx = firstItemAfterDate(parameter.time.date(), chatLog);
|
searchResult.pos.logIdx = firstItemAfterDate(parameter.time.date(), chatLog);
|
||||||
searchPos.numMatches = 0;
|
searchResult.pos.numMatches = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PeriodSearch::BeforeDate: {
|
case PeriodSearch::BeforeDate: {
|
||||||
bForwardSearch = false;
|
bForwardSearch = false;
|
||||||
searchPos.logIdx = firstItemAfterDate(parameter.time.date(), chatLog);
|
searchResult.pos.logIdx = firstItemAfterDate(parameter.time.date(), chatLog);
|
||||||
searchPos.numMatches = 0;
|
searchResult.pos.numMatches = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -986,13 +1005,13 @@ void GenericChatForm::searchInBegin(const QString& phrase, const ParameterSearch
|
||||||
|
|
||||||
void GenericChatForm::onSearchUp(const QString& phrase, const ParameterSearch& parameter)
|
void GenericChatForm::onSearchUp(const QString& phrase, const ParameterSearch& parameter)
|
||||||
{
|
{
|
||||||
auto result = chatLog.searchBackward(searchPos, phrase, parameter);
|
auto result = chatLog.searchBackward(searchResult.pos, phrase, parameter);
|
||||||
handleSearchResult(result, SearchDirection::Up);
|
handleSearchResult(result, SearchDirection::Up);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericChatForm::onSearchDown(const QString& phrase, const ParameterSearch& parameter)
|
void GenericChatForm::onSearchDown(const QString& phrase, const ParameterSearch& parameter)
|
||||||
{
|
{
|
||||||
auto result = chatLog.searchForward(searchPos, phrase, parameter);
|
auto result = chatLog.searchForward(searchResult.pos, phrase, parameter);
|
||||||
handleSearchResult(result, SearchDirection::Down);
|
handleSearchResult(result, SearchDirection::Down);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1005,17 +1024,58 @@ void GenericChatForm::handleSearchResult(SearchResult result, SearchDirection di
|
||||||
|
|
||||||
disableSearchText();
|
disableSearchText();
|
||||||
|
|
||||||
searchPos = result.pos;
|
searchResult = result;
|
||||||
|
|
||||||
auto const firstRenderedIdx = (messages.empty()) ? chatLog.getNextIdx() : messages.begin()->first;
|
auto searchIdx = result.pos.logIdx;
|
||||||
|
|
||||||
renderMessages(searchPos.logIdx, firstRenderedIdx, [this, result] {
|
auto firstRenderedIdx = messages.begin()->first;
|
||||||
auto msg = messages.at(searchPos.logIdx);
|
auto endRenderedIdx = messages.rbegin()->first;
|
||||||
chatWidget->scrollToLine(msg);
|
|
||||||
|
|
||||||
auto text = qobject_cast<Text*>(msg->getContent(1));
|
if (direction == SearchDirection::Up) {
|
||||||
text->selectText(result.exp, std::make_pair(result.start, result.len));
|
if (searchIdx.get() < firstRenderedIdx.get()) {
|
||||||
});
|
if (searchIdx.get() > DEF_NUM_MSG_TO_LOAD / 2) {
|
||||||
|
firstRenderedIdx = ChatLogIdx(searchIdx.get() - DEF_NUM_MSG_TO_LOAD / 2);
|
||||||
|
} else {
|
||||||
|
firstRenderedIdx = ChatLogIdx(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endRenderedIdx.get() - firstRenderedIdx.get() > DEF_NUM_MSG_TO_LOAD) {
|
||||||
|
endRenderedIdx = ChatLogIdx(firstRenderedIdx.get() + DEF_NUM_MSG_TO_LOAD);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (searchIdx.get() < firstRenderedIdx.get()) {
|
||||||
|
firstRenderedIdx = searchIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstRenderedIdx == searchIdx || searchIdx.get() > endRenderedIdx.get()) {
|
||||||
|
if (searchIdx.get() + DEF_NUM_MSG_TO_LOAD > chatLog.getNextIdx().get()) {
|
||||||
|
endRenderedIdx = chatLog.getNextIdx();
|
||||||
|
} else {
|
||||||
|
endRenderedIdx = ChatLogIdx(searchIdx.get() + DEF_NUM_MSG_TO_LOAD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endRenderedIdx.get() - firstRenderedIdx.get() > DEF_NUM_MSG_TO_LOAD) {
|
||||||
|
if (endRenderedIdx.get() > DEF_NUM_MSG_TO_LOAD) {
|
||||||
|
firstRenderedIdx = ChatLogIdx(endRenderedIdx.get() - DEF_NUM_MSG_TO_LOAD);
|
||||||
|
} else {
|
||||||
|
firstRenderedIdx = ChatLogIdx(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!messages.empty() && (firstRenderedIdx.get() < messages.begin()->first.get()
|
||||||
|
|| endRenderedIdx.get() > messages.rbegin()->first.get())) {
|
||||||
|
chatWidget->clear();
|
||||||
|
messages.clear();
|
||||||
|
|
||||||
|
auto mediator = endRenderedIdx;
|
||||||
|
endRenderedIdx = firstRenderedIdx;
|
||||||
|
firstRenderedIdx = mediator;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderMessages(endRenderedIdx, firstRenderedIdx, [this]{enableSearchText();});
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericChatForm::renderMessage(ChatLogIdx idx)
|
void GenericChatForm::renderMessage(ChatLogIdx idx)
|
||||||
|
|
|
@ -156,6 +156,7 @@ protected:
|
||||||
virtual void resizeEvent(QResizeEvent* event) final override;
|
virtual void resizeEvent(QResizeEvent* event) final override;
|
||||||
virtual bool eventFilter(QObject* object, QEvent* event) final override;
|
virtual bool eventFilter(QObject* object, QEvent* event) final override;
|
||||||
void disableSearchText();
|
void disableSearchText();
|
||||||
|
void enableSearchText();
|
||||||
bool searchInText(const QString& phrase, const ParameterSearch& parameter, SearchDirection direction);
|
bool searchInText(const QString& phrase, const ParameterSearch& parameter, SearchDirection direction);
|
||||||
std::pair<int, int> indexForSearchInLine(const QString& txt, const QString& phrase, const ParameterSearch& parameter, SearchDirection direction);
|
std::pair<int, int> indexForSearchInLine(const QString& txt, const QString& phrase, const ParameterSearch& parameter, SearchDirection direction);
|
||||||
|
|
||||||
|
@ -198,7 +199,7 @@ protected:
|
||||||
|
|
||||||
IChatLog& chatLog;
|
IChatLog& chatLog;
|
||||||
IMessageDispatcher& messageDispatcher;
|
IMessageDispatcher& messageDispatcher;
|
||||||
SearchPos searchPos;
|
SearchResult searchResult;
|
||||||
std::map<ChatLogIdx, ChatMessage::Ptr> messages;
|
std::map<ChatLogIdx, ChatMessage::Ptr> messages;
|
||||||
bool colorizeNames = false;
|
bool colorizeNames = false;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user