KTextAddons

texteditfindbarbase.cpp
1/*
2 SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "texteditfindbarbase.h"
8using namespace Qt::Literals::StringLiterals;
9
10#include "textcustomeditor_debug.h"
11#include "widgets/textfindreplacewidget.h"
12#include <KLocalizedString>
13#include <QEvent>
14#include <QHBoxLayout>
15#include <QIcon>
16#include <QKeyEvent>
17#include <QLineEdit>
18#include <QTimer>
19#include <QToolButton>
20#include <QVBoxLayout>
21
22using namespace TextCustomEditor;
23
24TextEditFindBarBase::TextEditFindBarBase(QWidget *parent)
25 : QWidget(parent)
26 , mFindWidget(new TextFindWidget(this))
27 , mReplaceWidget(new TextReplaceWidget(this))
28{
29 auto topLayout = new QVBoxLayout(this);
30 auto lay = new QHBoxLayout;
31 topLayout->addLayout(lay);
32
33 auto closeBtn = new QToolButton(this);
34 closeBtn->setIcon(QIcon::fromTheme(QStringLiteral("dialog-close")));
35 closeBtn->setIconSize(QSize(16, 16));
36 closeBtn->setToolTip(i18nc("@info:tooltip", "Close"));
37
38#ifndef QT_NO_ACCESSIBILITY
39 closeBtn->setAccessibleName(i18n("Close"));
40#endif
41
42 closeBtn->setAutoRaise(true);
43 lay->addWidget(closeBtn);
44
45 lay->addWidget(mFindWidget);
46
47 topLayout->addWidget(mReplaceWidget);
48 mReplaceWidget->hide();
49
50 connect(closeBtn, &QToolButton::clicked, this, &TextEditFindBarBase::closeBar);
51 connect(mFindWidget, &TextFindWidget::findNext, this, &TextEditFindBarBase::findNext);
52 connect(mFindWidget, &TextFindWidget::findPrev, this, &TextEditFindBarBase::findPrev);
53 connect(mFindWidget, &TextFindWidget::updateSearchOptions, this, &TextEditFindBarBase::slotUpdateSearchOptions);
54 connect(mFindWidget, &TextFindWidget::autoSearch, this, &TextEditFindBarBase::autoSearch);
55 connect(mFindWidget, &TextFindWidget::clearSearch, this, &TextEditFindBarBase::slotClearSearch);
56 connect(mFindWidget, &TextFindWidget::searchStringEmpty, mReplaceWidget, &TextReplaceWidget::slotSearchStringEmpty);
57 connect(mReplaceWidget, &TextReplaceWidget::replaceText, this, &TextEditFindBarBase::slotReplaceText);
58 connect(mReplaceWidget, &TextReplaceWidget::replaceAllText, this, &TextEditFindBarBase::slotReplaceAllText);
60 hide();
61}
62
63TextEditFindBarBase::~TextEditFindBarBase() = default;
64
65void TextEditFindBarBase::showFind()
66{
67 if (documentIsEmpty()) {
68 return;
69 }
70 mReplaceWidget->slotSearchStringEmpty(mFindWidget->searchText().isEmpty());
71 show();
72 if (mReplaceWidget->isVisible()) {
73 mReplaceWidget->hide();
75 }
76}
77
78void TextEditFindBarBase::setHideWhenClose(bool hide)
79{
80 mHideWhenClose = hide;
81}
82
83void TextEditFindBarBase::showReplace()
84{
85 if (viewIsReadOnly()) {
86 return;
87 }
88 if (documentIsEmpty()) {
89 return;
90 }
91 mReplaceWidget->slotSearchStringEmpty(mFindWidget->searchText().isEmpty());
92 show();
93 if (!mReplaceWidget->isVisible()) {
94 mReplaceWidget->show();
96 }
97}
98
99void TextEditFindBarBase::setText(const QString &text)
100{
101 mFindWidget->searchLineEdit()->setText(text);
102}
103
104QString TextEditFindBarBase::text() const
105{
106 return mFindWidget->searchText();
107}
108
109void TextEditFindBarBase::focusAndSetCursor()
110{
111 setFocus();
112 mFindWidget->searchLineEdit()->selectAll();
113 mFindWidget->searchLineEdit()->setFocus();
114}
115
116void TextEditFindBarBase::slotClearSearch()
117{
118 clearSelections();
119}
120
121void TextEditFindBarBase::autoSearch(const QString &str)
122{
123 const bool isNotEmpty = (!str.isEmpty());
124 if (isNotEmpty) {
125 QTimer::singleShot(0, this, [this]() {
126 slotSearchText();
127 });
128 } else {
129 clearSelections();
130 }
131}
132
133void TextEditFindBarBase::messageInfo(bool backward, bool isAutoSearch, bool found)
134{
135 Q_UNUSED(backward)
136 if (!found && !isAutoSearch) {
137 QString str = mLastSearchStr;
138 if (str.length() > 39) {
139 str.truncate(40);
140 str += "…"_L1;
141 }
142 Q_EMIT displayMessageIndicator(i18n("End of message reached.\nPhrase '%1' could not be found.", str));
143 }
144}
145
146bool TextEditFindBarBase::searchText(bool backward, bool isAutoSearch)
147{
148 mLastSearchStr = mFindWidget->searchText();
149 mLastSearchRegExp = mFindWidget->searchRegularExpression();
150 TextEditFindBarBase::FindFlags searchOptions = mFindWidget->searchOptions();
151 if (backward) {
152 searchOptions |= TextEditFindBarBase::FindBackward;
153 }
154
155 if (isAutoSearch) {
156 autoSearchMoveCursor();
157 } else if (mFindWidget->isRegularExpression()) {
158 // TODO
159 } else if (!mLastSearchStr.contains(mFindWidget->searchText(), Qt::CaseSensitive)) {
160 clearSelections();
161 }
162
163 bool found = false;
164 if (mFindWidget->isRegularExpression()) {
165 found = searchInDocument(mLastSearchRegExp, searchOptions);
166 } else {
167 found = searchInDocument(mLastSearchStr, searchOptions);
168 }
169 mFindWidget->setFoundMatch(found);
170 messageInfo(backward, isAutoSearch, found);
171 return found;
172}
173
174void TextEditFindBarBase::findNext()
175{
176 searchText(false, false);
177}
178
179void TextEditFindBarBase::findPrev()
180{
181 searchText(true, false);
182}
183
184void TextEditFindBarBase::slotUpdateSearchOptions()
185{
186 const TextEditFindBarBase::FindFlags searchOptions = mFindWidget->searchOptions();
187 mLastSearchStr = mFindWidget->searchText();
188 mLastSearchRegExp = mFindWidget->searchRegularExpression();
189 if (mFindWidget->isRegularExpression()) {
190 searchInDocument(mLastSearchRegExp, searchOptions);
191 } else {
192 searchInDocument(mLastSearchStr, searchOptions);
193 }
194}
195
196void TextEditFindBarBase::clearSelections()
197{
198 mFindWidget->setFoundMatch(false);
199}
200
201void TextEditFindBarBase::closeBar()
202{
203 // Make sure that all old searches are cleared
204 mFindWidget->searchLineEdit()->setText(QString());
205 mReplaceWidget->replaceLineEdit()->setText(QString());
206 clearSelections();
207 mReplaceWidget->hide();
209 if (mHideWhenClose) {
210 hide();
211 }
212 Q_EMIT hideFindBar();
213}
214
215bool TextEditFindBarBase::event(QEvent *e)
216{
217 // Close the bar when pressing Escape.
218 // Not using a QShortcut for this because it could conflict with
219 // window-global actions (e.g. Emil Sedgh binds Esc to "close tab").
220 // With a shortcut override we can catch this before it gets to kactions.
221 const bool shortCutOverride = (e->type() == QEvent::ShortcutOverride);
222 if (shortCutOverride || e->type() == QEvent::KeyPress) {
223 auto kev = static_cast<QKeyEvent *>(e);
224 if (kev->key() == Qt::Key_Escape) {
225 if (shortCutOverride) {
226 e->accept();
227 return true;
228 }
229 e->accept();
230 closeBar();
231 return true;
232 } else if (kev->key() == Qt::Key_Enter || kev->key() == Qt::Key_Return) {
233 e->accept();
234 if (shortCutOverride) {
235 return true;
236 }
237 if (mFindWidget->searchText().isEmpty()) {
238 return true;
239 }
240
241 if (kev->modifiers() & Qt::ShiftModifier) {
242 findPrev();
243 } else if (kev->modifiers() == Qt::NoModifier) {
244 findNext();
245 }
246 return true;
247 }
248 }
249 return QWidget::event(e);
250}
251
252#include "moc_texteditfindbarbase.cpp"
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
void clicked(bool checked)
void addLayout(QLayout *layout, int stretch)
ShortcutOverride
void accept()
Type type() const const
QIcon fromTheme(const QString &name)
void selectAll()
void setText(const QString &)
Q_EMITQ_EMIT
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype length() const const
void truncate(qsizetype position)
CaseSensitive
Key_Escape
ShiftModifier
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
virtual bool event(QEvent *event) override
void hide()
void setFocus()
void show()
void updateGeometry()
bool isVisible() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:51:28 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.