1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the tools applications of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | /*! \class TextEditFindWidget |
41 | |
42 | \brief A search bar that is commonly added below the searchable text. |
43 | |
44 | \internal |
45 | |
46 | This widget implements a search bar which becomes visible when the user |
47 | wants to start searching. It is a modern replacement for the commonly used |
48 | search dialog. It is usually placed below a QTextEdit using a QVBoxLayout. |
49 | |
50 | The QTextEdit instance will need to be associated with this class using |
51 | setTextEdit(). |
52 | |
53 | The search is incremental and can be set to case sensitive or whole words |
54 | using buttons available on the search bar. |
55 | |
56 | \sa QTextEdit |
57 | */ |
58 | |
59 | #include "texteditfindwidget.h" |
60 | |
61 | #include <QtWidgets/QCheckBox> |
62 | #include <QtGui/QTextCursor> |
63 | #include <QtWidgets/QTextEdit> |
64 | |
65 | QT_BEGIN_NAMESPACE |
66 | |
67 | /*! |
68 | Constructs a TextEditFindWidget. |
69 | |
70 | \a flags is passed to the AbstractFindWidget constructor. |
71 | \a parent is passed to the QWidget constructor. |
72 | */ |
73 | TextEditFindWidget::TextEditFindWidget(FindFlags flags, QWidget *parent) |
74 | : AbstractFindWidget(flags, parent) |
75 | , m_textEdit(0) |
76 | { |
77 | } |
78 | |
79 | /*! |
80 | Associates a QTextEdit with this find widget. Searches done using this find |
81 | widget will then apply to the given QTextEdit. |
82 | |
83 | An event filter is set on the QTextEdit which intercepts the ESC key while |
84 | the find widget is active, and uses it to deactivate the find widget. |
85 | |
86 | If the find widget is already associated with a QTextEdit, the event filter |
87 | is removed from this QTextEdit first. |
88 | |
89 | \a textEdit may be NULL. |
90 | */ |
91 | void TextEditFindWidget::setTextEdit(QTextEdit *textEdit) |
92 | { |
93 | if (m_textEdit) |
94 | m_textEdit->removeEventFilter(obj: this); |
95 | |
96 | m_textEdit = textEdit; |
97 | |
98 | if (m_textEdit) |
99 | m_textEdit->installEventFilter(filterObj: this); |
100 | } |
101 | |
102 | /*! |
103 | \reimp |
104 | */ |
105 | void TextEditFindWidget::deactivate() |
106 | { |
107 | // Pass focus to the text edit |
108 | if (m_textEdit) |
109 | m_textEdit->setFocus(); |
110 | |
111 | AbstractFindWidget::deactivate(); |
112 | } |
113 | |
114 | /*! |
115 | \reimp |
116 | */ |
117 | void TextEditFindWidget::find(const QString &ttf, bool skipCurrent, bool backward, bool *found, bool *wrapped) |
118 | { |
119 | if (!m_textEdit) |
120 | return; |
121 | |
122 | QTextCursor cursor = m_textEdit->textCursor(); |
123 | QTextDocument *doc = m_textEdit->document(); |
124 | |
125 | if (!doc || cursor.isNull()) |
126 | return; |
127 | |
128 | if (cursor.hasSelection()) |
129 | cursor.setPosition(pos: (skipCurrent && !backward) ? cursor.position() : cursor.anchor()); |
130 | |
131 | *found = true; |
132 | QTextCursor newCursor = cursor; |
133 | |
134 | if (!ttf.isEmpty()) { |
135 | QTextDocument::FindFlags options; |
136 | |
137 | if (backward) |
138 | options |= QTextDocument::FindBackward; |
139 | |
140 | if (caseSensitive()) |
141 | options |= QTextDocument::FindCaseSensitively; |
142 | |
143 | if (wholeWords()) |
144 | options |= QTextDocument::FindWholeWords; |
145 | |
146 | newCursor = doc->find(subString: ttf, cursor, options); |
147 | if (newCursor.isNull()) { |
148 | QTextCursor ac(doc); |
149 | ac.movePosition(op: options & QTextDocument::FindBackward |
150 | ? QTextCursor::End : QTextCursor::Start); |
151 | newCursor = doc->find(subString: ttf, cursor: ac, options); |
152 | if (newCursor.isNull()) { |
153 | *found = false; |
154 | newCursor = cursor; |
155 | } else { |
156 | *wrapped = true; |
157 | } |
158 | } |
159 | } |
160 | |
161 | if (!isVisible()) |
162 | show(); |
163 | |
164 | m_textEdit->setTextCursor(newCursor); |
165 | } |
166 | |
167 | QT_END_NAMESPACE |
168 | |