1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | /*! \class TextEditFindWidget |
5 | |
6 | \brief A search bar that is commonly added below the searchable text. |
7 | |
8 | \internal |
9 | |
10 | This widget implements a search bar which becomes visible when the user |
11 | wants to start searching. It is a modern replacement for the commonly used |
12 | search dialog. It is usually placed below a QTextEdit using a QVBoxLayout. |
13 | |
14 | The QTextEdit instance will need to be associated with this class using |
15 | setTextEdit(). |
16 | |
17 | The search is incremental and can be set to case sensitive or whole words |
18 | using buttons available on the search bar. |
19 | |
20 | \sa QTextEdit |
21 | */ |
22 | |
23 | #include "texteditfindwidget.h" |
24 | |
25 | #include <QtWidgets/QCheckBox> |
26 | #include <QtGui/QTextCursor> |
27 | #include <QtWidgets/QTextEdit> |
28 | |
29 | QT_BEGIN_NAMESPACE |
30 | |
31 | /*! |
32 | Constructs a TextEditFindWidget. |
33 | |
34 | \a flags is passed to the AbstractFindWidget constructor. |
35 | \a parent is passed to the QWidget constructor. |
36 | */ |
37 | TextEditFindWidget::TextEditFindWidget(FindFlags flags, QWidget *parent) |
38 | : AbstractFindWidget(flags, parent) |
39 | , m_textEdit(0) |
40 | { |
41 | } |
42 | |
43 | /*! |
44 | Associates a QTextEdit with this find widget. Searches done using this find |
45 | widget will then apply to the given QTextEdit. |
46 | |
47 | An event filter is set on the QTextEdit which intercepts the ESC key while |
48 | the find widget is active, and uses it to deactivate the find widget. |
49 | |
50 | If the find widget is already associated with a QTextEdit, the event filter |
51 | is removed from this QTextEdit first. |
52 | |
53 | \a textEdit may be NULL. |
54 | */ |
55 | void TextEditFindWidget::setTextEdit(QTextEdit *textEdit) |
56 | { |
57 | if (m_textEdit) |
58 | m_textEdit->removeEventFilter(obj: this); |
59 | |
60 | m_textEdit = textEdit; |
61 | |
62 | if (m_textEdit) |
63 | m_textEdit->installEventFilter(filterObj: this); |
64 | } |
65 | |
66 | /*! |
67 | \reimp |
68 | */ |
69 | void TextEditFindWidget::deactivate() |
70 | { |
71 | // Pass focus to the text edit |
72 | if (m_textEdit) |
73 | m_textEdit->setFocus(); |
74 | |
75 | AbstractFindWidget::deactivate(); |
76 | } |
77 | |
78 | /*! |
79 | \reimp |
80 | */ |
81 | void TextEditFindWidget::find(const QString &ttf, bool skipCurrent, bool backward, bool *found, bool *wrapped) |
82 | { |
83 | if (!m_textEdit) |
84 | return; |
85 | |
86 | QTextCursor cursor = m_textEdit->textCursor(); |
87 | QTextDocument *doc = m_textEdit->document(); |
88 | |
89 | if (!doc || cursor.isNull()) |
90 | return; |
91 | |
92 | if (cursor.hasSelection()) |
93 | cursor.setPosition(pos: (skipCurrent && !backward) ? cursor.position() : cursor.anchor()); |
94 | |
95 | *found = true; |
96 | QTextCursor newCursor = cursor; |
97 | |
98 | if (!ttf.isEmpty()) { |
99 | QTextDocument::FindFlags options; |
100 | |
101 | if (backward) |
102 | options |= QTextDocument::FindBackward; |
103 | |
104 | if (caseSensitive()) |
105 | options |= QTextDocument::FindCaseSensitively; |
106 | |
107 | if (wholeWords()) |
108 | options |= QTextDocument::FindWholeWords; |
109 | |
110 | newCursor = doc->find(subString: ttf, cursor, options); |
111 | if (newCursor.isNull()) { |
112 | QTextCursor ac(doc); |
113 | ac.movePosition(op: options & QTextDocument::FindBackward |
114 | ? QTextCursor::End : QTextCursor::Start); |
115 | newCursor = doc->find(subString: ttf, cursor: ac, options); |
116 | if (newCursor.isNull()) { |
117 | *found = false; |
118 | newCursor = cursor; |
119 | } else { |
120 | *wrapped = true; |
121 | } |
122 | } |
123 | } |
124 | |
125 | if (!isVisible()) |
126 | show(); |
127 | |
128 | m_textEdit->setTextCursor(newCursor); |
129 | } |
130 | |
131 | QT_END_NAMESPACE |
132 | |