1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

feat: add search in text in group chats

This commit is contained in:
TriKriSta 2018-02-11 23:09:13 +02:00
parent 8bb80c770c
commit 7718734c9a
10 changed files with 216 additions and 180 deletions

View File

@ -53,12 +53,15 @@
<file>ui/chatArea/scrollBarRightArrow.svg</file>
<file>ui/chatForm/buttons.css</file>
<file>ui/chatForm/callButton.svg</file>
<file>ui/chatForm/hideButton.svg</file>
<file>ui/chatForm/micButton.svg</file>
<file>ui/chatForm/videoButton.svg</file>
<file>ui/chatForm/volButton.svg</file>
<file>ui/chatForm/emoteButton.svg</file>
<file>ui/chatForm/fileButton.svg</file>
<file>ui/chatForm/screenshotButton.svg</file>
<file>ui/chatForm/searchDownButton.svg</file>
<file>ui/chatForm/searchUpButton.svg</file>
<file>ui/chatForm/sendButton.svg</file>
<file>ui/emoticonWidget/dot_page.svg</file>
<file>ui/emoticonWidget/dot_page_current.svg</file>
@ -95,8 +98,5 @@
<file>img/caps_lock.svg</file>
<file>ui/contentDialog/contentDialog.css</file>
<file>ui/tooliconsZone/tooliconsZone.css</file>
<file>ui/chatForm/searchDownButton.svg</file>
<file>ui/chatForm/searchUpButton.svg</file>
<file>ui/chatForm/hideButton.svg</file>
</qresource>
</RCC>

View File

@ -62,12 +62,13 @@ void Text::selectText(const QString &txt, const int index)
{
regenerate();
if (!doc)
if (!doc) {
return;
}
QTextCursor cursor = doc->find(txt, index);
auto cursor = doc->find(txt, index);
if (cursor != QTextCursor()) {
if (!cursor.isNull()) {
cursor.beginEditBlock();
cursor.setPosition(index);
cursor.setPosition(index + txt.size(), QTextCursor::KeepAnchor);

View File

@ -179,11 +179,6 @@ ChatForm::ChatForm(Friend* chatFriend, History* history)
connect(headWidget, &ChatFormHeader::micMuteToggle, this, &ChatForm::onMicMuteToggle);
connect(headWidget, &ChatFormHeader::volMuteToggle, this, &ChatForm::onVolMuteToggle);
connect(searchForm, &SearchForm::searchInBegin, this, &ChatForm::searchInBegin);
connect(searchForm, &SearchForm::searchUp, this, &ChatForm::onSearchUp);
connect(searchForm, &SearchForm::searchDown, this, &ChatForm::onSearchDown);
connect(searchForm, &SearchForm::visibleChanged, this, &ChatForm::onSearchTrigered);
connect(msgEdit, &ChatTextEdit::enterPressed, this, &ChatForm::onSendTriggered);
connect(msgEdit, &ChatTextEdit::textChanged, this, &ChatForm::onTextEditChanged);
connect(msgEdit, &ChatTextEdit::pasteImage, this, &ChatForm::sendImage);
@ -208,8 +203,6 @@ ChatForm::ChatForm(Friend* chatFriend, History* history)
});
connect(headWidget, &ChatFormHeader::callRejected, this, &ChatForm::onRejectCallTriggered);
connect(chatWidget, &ChatLog::workerTimeoutFinished, this, &ChatForm::onContinueSearch);
updateCallButtons();
if (Nexus::getProfile()->isHistoryEnabled()) {
loadHistory(QDateTime::currentDateTime().addDays(-7), true);
@ -496,27 +489,7 @@ void ChatForm::onVolMuteToggle()
updateMuteVolButton();
}
void ChatForm::onSearchTrigered()
{
if (searchForm->isHidden()) {
searchForm->removeSearchPhrase();
desibleSearchText();
} else {
searchPoint = QPoint(1, -1);
searchAfterLoadHistory = false;
}
}
void ChatForm::searchInBegin(const QString &phrase)
{
desibleSearchText();
searchPoint = QPoint(1, -1);
onSearchUp(phrase);
}
void ChatForm::onSearchUp(const QString &phrase)
void ChatForm::onSearchUp(const QString& phrase)
{
if (phrase.isEmpty()) {
desibleSearchText();
@ -531,7 +504,7 @@ void ChatForm::onSearchUp(const QString &phrase)
QString pk = f->getPublicKey().toString();
QDateTime startDate = history->getStartDateChatHistory(pk);
if (startDate == earliestMessage) {
if (!startDate.isValid() || startDate == earliestMessage) {
return;
}
@ -547,109 +520,30 @@ void ChatForm::onSearchUp(const QString &phrase)
return;
}
for (int i = startLine; i >= 0; --i) {
ChatLine::Ptr l = lines[i];
bool isSearch = searchInText(phrase, true);
if (l->getColumnCount() >= 2) {
ChatLineContent* content = l->getContent(1);
Text* text = static_cast<Text*>(content);
if (!isSearch) {
QString pk = f->getPublicKey().toString();
QDateTime startDate = history->getStartDateChatHistory(pk);
QDateTime newBaseData = earliestMessage.addDays(-1);
if (searchPoint.y() == 0) {
text->deselectText();
searchPoint.setY(-1);
} else {
QString txt = content->getText();
if (txt.contains(phrase, Qt::CaseInsensitive)) {
int startIndex = -1;
if (searchPoint.y() > -1) {
startIndex = searchPoint.y() - 1;
}
int index = txt.lastIndexOf(phrase, startIndex, Qt::CaseInsensitive);
if ((index == -1 && searchPoint.y() > -1)) {
text->deselectText();
searchPoint.setY(-1);
} else {
chatWidget->scrollToLine(l);
text->deselectText();
text->selectText(phrase, index);
searchPoint = QPoint(numLines - i, index);
break;
}
}
}
if (i == 0) {
QString pk = f->getPublicKey().toString();
QDateTime startDate = history->getStartDateChatHistory(pk);
QDateTime newBaseData = earliestMessage.addDays(-1);
if (startDate > newBaseData) {
newBaseData = startDate;
}
searchPoint.setX(numLines);
searchAfterLoadHistory = true;
loadHistory(newBaseData);
}
if (!startDate.isValid()) {
return;
}
if (startDate > newBaseData) {
newBaseData = startDate;
}
searchPoint.setX(numLines);
searchAfterLoadHistory = true;
loadHistory(newBaseData);
}
}
void ChatForm::onSearchDown(const QString &phrase)
void ChatForm::onSearchDown(const QString& phrase)
{
if (phrase.isEmpty()) {
desibleSearchText();
}
QVector<ChatLine::Ptr> lines = chatWidget->getLines();
if (lines.isEmpty()) {
return;
}
int numLines = lines.size();
int startLine = numLines - searchPoint.x();
for (int i = startLine; i < numLines; ++i) {
ChatLine::Ptr l = lines[i];
if (l->getColumnCount() >= 2) {
ChatLineContent* content = l->getContent(1);
Text* text = static_cast<Text*>(content);
QString txt = content->getText();
if (txt.contains(phrase, Qt::CaseInsensitive)) {
int startIndex = 0;
if (searchPoint.y() > -1) {
startIndex = searchPoint.y() + 1;
}
int index = txt.indexOf(phrase, startIndex, Qt::CaseInsensitive);
if (index == -1 && searchPoint.y() > -1) {
text->deselectText();
searchPoint.setY(-1);
} else {
chatWidget->scrollToLine(l);
text->deselectText();
text->selectText(phrase, index);
searchPoint = QPoint(numLines - i, index);
break;
}
}
}
}
}
void ChatForm::onContinueSearch()
{
QString phrase = searchForm->getSearchPhrase();
if (!phrase.isEmpty() && searchAfterLoadHistory) {
searchAfterLoadHistory = false;
onSearchUp(phrase);
}
searchInText(phrase, false);
}
void ChatForm::onFileSendFailed(uint32_t friendId, const QString& fname)
@ -1124,21 +1018,6 @@ void ChatForm::SendMessageStr(QString msg)
}
}
void ChatForm::desibleSearchText()
{
if (searchPoint != QPoint(1, -1)) {
QVector<ChatLine::Ptr> lines = chatWidget->getLines();
int numLines = lines.size();
int index = numLines - searchPoint.x();
if (numLines > index) {
ChatLine::Ptr l = lines[index];
ChatLineContent* content = l->getContent(1);
Text* text = static_cast<Text*>(content);
text->deselectText();
}
}
}
void ChatForm::retranslateUi()
{
loadHistoryAction->setText(tr("Load chat history..."));

View File

@ -72,6 +72,10 @@ public slots:
void onAvatarChange(uint32_t friendId, const QPixmap& pic);
void onAvatarRemoved(uint32_t friendId);
protected slots:
void onSearchUp(const QString& phrase) override;
void onSearchDown(const QString& phrase) override;
private slots:
void clearChatArea(bool notInForm) override final;
void onSendTriggered() override;
@ -87,12 +91,7 @@ private slots:
void onRejectCallTriggered();
void onMicMuteToggle();
void onVolMuteToggle();
void onSearchTrigered();
void searchInBegin(const QString& phrase);
void onSearchUp(const QString& phrase);
void onSearchDown(const QString& phrase);
void onContinueSearch();
void onFileSendFailed(uint32_t friendId, const QString& fname);
void onFriendStatusChanged(quint32 friendId, Status status);
void onFriendTypingChanged(quint32 friendId, bool isTyping);
@ -117,8 +116,6 @@ private:
void updateCallButtons();
void SendMessageStr(QString msg);
void desibleSearchText();
protected:
GenericNetCamView* createNetcam() final override;
void insertChatMessage(ChatMessage::Ptr msg) final override;
@ -144,8 +141,6 @@ private:
QHash<uint, FileTransferInstance*> ftransWidgets;
bool isTyping;
bool lastCallIsVideo;
QPoint searchPoint;
bool searchAfterLoadHistory;
};
#endif // CHATFORM_H

View File

@ -224,6 +224,13 @@ GenericChatForm::GenericChatForm(QWidget* parent)
connect(chatWidget, &ChatLog::customContextMenuRequested, this,
&GenericChatForm::onChatContextMenuRequested);
connect(searchForm, &SearchForm::searchInBegin, this, &GenericChatForm::searchInBegin);
connect(searchForm, &SearchForm::searchUp, this, &GenericChatForm::onSearchUp);
connect(searchForm, &SearchForm::searchDown, this, &GenericChatForm::onSearchDown);
connect(searchForm, &SearchForm::visibleChanged, this, &GenericChatForm::onSearchTrigered);
connect(chatWidget, &ChatLog::workerTimeoutFinished, this, &GenericChatForm::onContinueSearch);
chatWidget->setStyleSheet(Style::getStylesheet(":/ui/chatArea/chatArea.css"));
headWidget->setStyleSheet(Style::getStylesheet(":/ui/chatArea/chatHead.css"));
@ -241,6 +248,7 @@ GenericChatForm::GenericChatForm(QWidget* parent)
GenericChatForm::~GenericChatForm()
{
Translator::unregister(this);
delete searchForm;
}
void GenericChatForm::adjustFileMenuPosition()
@ -531,6 +539,104 @@ void GenericChatForm::addSystemDateMessage()
insertChatMessage(ChatMessage::createChatInfoMessage(dateText, ChatMessage::INFO, QDateTime()));
}
void GenericChatForm::desibleSearchText()
{
if (searchPoint != QPoint(1, -1)) {
QVector<ChatLine::Ptr> lines = chatWidget->getLines();
int numLines = lines.size();
int index = numLines - searchPoint.x();
if (numLines > index) {
ChatLine::Ptr l = lines[index];
ChatLineContent* content = l->getContent(1);
Text* text = static_cast<Text*>(content);
text->deselectText();
}
}
}
bool GenericChatForm::searchInText(const QString& phrase, bool searchUp)
{
bool isSearch = false;
if (phrase.isEmpty()) {
desibleSearchText();
}
QVector<ChatLine::Ptr> lines = chatWidget->getLines();
if (lines.isEmpty()) {
return isSearch;
}
int numLines = lines.size();
int startLine = numLines - searchPoint.x();
if (startLine < 0 || startLine >= numLines) {
return isSearch;
}
for (int i = startLine; searchUp ? i >= 0 : i < numLines; searchUp ? --i : ++i) {
ChatLine::Ptr l = lines[i];
if (l->getColumnCount() < 2) {
continue;
}
ChatLineContent* content = l->getContent(1);
Text* text = static_cast<Text*>(content);
if (searchUp && searchPoint.y() == 0) {
text->deselectText();
searchPoint.setY(-1);
continue;
}
QString txt = content->getText();
if (txt.contains(phrase, Qt::CaseInsensitive)) {
int index = indexForSearchInLine(txt, phrase, searchUp);
if ((index == -1 && searchPoint.y() > -1)) {
text->deselectText();
searchPoint.setY(-1);
} else {
chatWidget->scrollToLine(l);
text->deselectText();
text->selectText(phrase, index);
searchPoint = QPoint(numLines - i, index);
isSearch = true;
break;
}
}
}
return isSearch;
}
int GenericChatForm::indexForSearchInLine(const QString& txt, const QString& phrase, bool searchUp)
{
int index = 0;
if (searchUp) {
int startIndex = -1;
if (searchPoint.y() > -1) {
startIndex = searchPoint.y() - 1;
}
index = txt.lastIndexOf(phrase, startIndex, Qt::CaseInsensitive);
} else {
int startIndex = 0;
if (searchPoint.y() > -1) {
startIndex = searchPoint.y() + 1;
}
index = txt.indexOf(phrase, startIndex, Qt::CaseInsensitive);
}
return index;
}
void GenericChatForm::clearChatArea()
{
clearChatArea(true);
@ -681,6 +787,35 @@ void GenericChatForm::searchFormShow()
}
}
void GenericChatForm::onSearchTrigered()
{
if (searchForm->isHidden()) {
searchForm->removeSearchPhrase();
desibleSearchText();
} else {
searchPoint = QPoint(1, -1);
searchAfterLoadHistory = false;
}
}
void GenericChatForm::searchInBegin(const QString& phrase)
{
desibleSearchText();
searchPoint = QPoint(1, -1);
onSearchUp(phrase);
}
void GenericChatForm::onContinueSearch()
{
QString phrase = searchForm->getSearchPhrase();
if (!phrase.isEmpty() && searchAfterLoadHistory) {
searchAfterLoadHistory = false;
onSearchUp(phrase);
}
}
void GenericChatForm::retranslateUi()
{
sendButton->setToolTip(tr("Send message"));

View File

@ -104,6 +104,12 @@ protected slots:
void quoteSelectedText();
void copyLink();
void searchFormShow();
void onSearchTrigered();
void searchInBegin(const QString& phrase);
virtual void onSearchUp(const QString& phrase) = 0;
virtual void onSearchDown(const QString& phrase) = 0;
void onContinueSearch();
private:
void retranslateUi();
@ -125,6 +131,9 @@ protected:
virtual bool event(QEvent*) final override;
virtual void resizeEvent(QResizeEvent* event) final override;
virtual bool eventFilter(QObject* object, QEvent* event) final override;
void desibleSearchText();
bool searchInText(const QString& phrase, bool searchUp);
int indexForSearchInLine(const QString& txt, const QString& phrase, bool searchUp);
protected:
bool audioInputFlag;
@ -160,6 +169,9 @@ protected:
FlyoutOverlayWidget* fileFlyout;
GenericNetCamView* netcam;
Widget* parent;
QPoint searchPoint;
bool searchAfterLoadHistory;
};
#endif // GENERICCHATFORM_H

View File

@ -22,6 +22,8 @@
#include "tabcompleter.h"
#include "src/core/core.h"
#include "src/core/coreav.h"
#include "src/chatlog/chatlog.h"
#include "src/chatlog/content/text.h"
#include "src/model/friend.h"
#include "src/friendlist.h"
#include "src/model/group.h"
@ -189,6 +191,16 @@ void GroupChatForm::onTitleChanged(uint32_t groupId, const QString& author, cons
addSystemInfoMessage(message, ChatMessage::INFO, curTime);
}
void GroupChatForm::onSearchUp(const QString& phrase)
{
searchInText(phrase, true);
}
void GroupChatForm::onSearchDown(const QString& phrase)
{
searchInText(phrase, false);
}
void GroupChatForm::onScreenshotClicked()
{
// Unsupported

View File

@ -49,6 +49,8 @@ private slots:
void onCallClicked();
void onUserListChanged();
void onTitleChanged(uint32_t groupId, const QString& author, const QString& title);
void onSearchUp(const QString& phrase) override;
void onSearchDown(const QString& phrase) override;
protected:
virtual GenericNetCamView* createNetcam() final override;

View File

@ -23,27 +23,14 @@
#include <QLineEdit>
#include <QPushButton>
SearchForm::SearchForm(QWidget *parent) : QWidget(parent)
SearchForm::SearchForm(QWidget* parent) : QWidget(parent)
{
QHBoxLayout *layout = new QHBoxLayout();
searchLine = new QLineEdit();
upButton = new QPushButton();
upButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
upButton->setObjectName("searchUpButton");
upButton->setProperty("state", "green");
upButton->setStyleSheet(Style::getStylesheet(QStringLiteral(":/ui/chatForm/buttons.css")));
downButton = new QPushButton();
downButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
downButton->setObjectName("searchDownButton");
downButton->setProperty("state", "green");
downButton->setStyleSheet(Style::getStylesheet(QStringLiteral(":/ui/chatForm/buttons.css")));
hideButton = new QPushButton();
hideButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
hideButton->setObjectName("hideButton");
hideButton->setProperty("state", "red");
hideButton->setStyleSheet(Style::getStylesheet(QStringLiteral(":/ui/chatForm/buttons.css")));
upButton = createButton("searchUpButton", "green");
downButton = createButton("searchDownButton", "green");
hideButton = createButton("hideButton","red");
layout->setMargin(0);
layout->addWidget(searchLine);
@ -69,13 +56,24 @@ QString SearchForm::getSearchPhrase() const
return searchPhrase;
}
void SearchForm::showEvent(QShowEvent *event)
QPushButton *SearchForm::createButton(const QString& name, const QString& state)
{
QPushButton* btn = new QPushButton();
btn->setAttribute(Qt::WA_LayoutUsesWidgetRect);
btn->setObjectName(name);
btn->setProperty("state", state);
btn->setStyleSheet(Style::getStylesheet(QStringLiteral(":/ui/chatForm/buttons.css")));
return btn;
}
void SearchForm::showEvent(QShowEvent* event)
{
QWidget::showEvent(event);
emit visibleChanged();
}
void SearchForm::changedSearchPhrase(const QString &text)
void SearchForm::changedSearchPhrase(const QString& text)
{
searchPhrase = text;
emit searchInBegin(searchPhrase);

View File

@ -29,11 +29,13 @@ class SearchForm final : public QWidget
{
Q_OBJECT
public:
explicit SearchForm(QWidget *parent = nullptr);
explicit SearchForm(QWidget* parent = nullptr);
void removeSearchPhrase();
QString getSearchPhrase() const;
private:
QPushButton* createButton(const QString& name, const QString& state);
QPushButton* upButton;
QPushButton* downButton;
QPushButton* hideButton;
@ -42,18 +44,18 @@ private:
QString searchPhrase;
protected:
virtual void showEvent(QShowEvent *event);
virtual void showEvent(QShowEvent* event);
private slots:
void changedSearchPhrase(const QString &text);
void changedSearchPhrase(const QString& text);
void clickedUp();
void clickedDown();
void clickedHide();
signals:
void searchInBegin(const QString &);
void searchUp(const QString &);
void searchDown(const QString &);
void searchInBegin(const QString& phrase);
void searchUp(const QString& phrase);
void searchDown(const QString& phrase);
void visibleChanged();
};