Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickpdfsearchmodel.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 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
5#include <QtCore/qloggingcategory.h>
6#include <QtPdf/private/qtpdfglobal_p.h>
7
8QT_BEGIN_NAMESPACE
9
10Q_PDF_LOGGING_CATEGORY(qLcSearch, "qt.pdf.search")
11
12/*!
13 \qmltype PdfSearchModel
14//! \nativetype QQuickPdfSearchModel
15 \inqmlmodule QtQuick.Pdf
16 \ingroup pdf
17 \brief A representation of text search results within a PDF Document.
18 \since 5.15
19
20 PdfSearchModel provides the ability to search for text strings within a
21 document and get the geometric locations of matches on each page.
22*/
23
24QQuickPdfSearchModel::QQuickPdfSearchModel(QObject *parent)
25 : QPdfSearchModel(parent)
26{
27 connect(this, &QPdfSearchModel::searchStringChanged,
28 this, &QQuickPdfSearchModel::onResultsChanged);
29}
30
31/*!
32 \internal
33*/
34QQuickPdfSearchModel::~QQuickPdfSearchModel() = default;
35
36QQuickPdfDocument *QQuickPdfSearchModel::document() const
37{
38 return m_quickDocument;
39}
40
41void QQuickPdfSearchModel::setDocument(QQuickPdfDocument *document)
42{
43 if (document == m_quickDocument || !document)
44 return;
45
46 m_quickDocument = document;
47 QPdfSearchModel::setDocument(document->document());
48}
49
50/*!
51 \qmlproperty list<list<point>> PdfSearchModel::currentResultBoundingPolygons
52
53 A set of paths in a form that can be bound to the \c paths property of a
54 \l {QtQuick::PathMultiline}{PathMultiline} instance to render a batch of
55 rectangles around the regions comprising the search result \l currentResult
56 on \l currentPage. This is normally used to highlight one search result
57 at a time, in a UI that allows stepping through the results:
58
59 \qml
60 PdfDocument {
61 id: doc
62 }
63 PdfSearchModel {
64 id: searchModel
65 document: doc
66 currentPage: view.currentPage
67 currentResult: ...
68 }
69 Shape {
70 ShapePath {
71 PathMultiline {
72 paths: searchModel.currentResultBoundingPolygons
73 }
74 }
75 }
76 \endqml
77
78 It becomes empty whenever \c {currentPage != currentResultLink.page}.
79
80 \sa PathMultiline
81*/
82QList<QPolygonF> QQuickPdfSearchModel::currentResultBoundingPolygons() const
83{
84 QList<QPolygonF> ret;
85 const auto result = currentResultLink();
86 if (result.page() != m_currentPage)
87 return ret;
88 for (auto rect : result.rectangles())
89 ret << QPolygonF(rect);
90 return ret;
91}
92
93/*!
94 \qmlproperty point PdfSearchModel::currentResultBoundingRect
95
96 The bounding box containing all \l currentResultBoundingPolygons,
97 if \c {currentPage == currentResultLink.page}; otherwise, an invalid rectangle.
98*/
99QRectF QQuickPdfSearchModel::currentResultBoundingRect() const
100{
101 QRectF ret;
102 const auto result = currentResultLink();
103 if (result.page() != m_currentPage)
104 return ret;
105 auto rects = result.rectangles();
106 if (!rects.isEmpty()) {
107 ret = rects.takeFirst();
108 for (auto rect : rects)
109 ret = ret.united(rect);
110 }
111 return ret;
112}
113
114void QQuickPdfSearchModel::onResultsChanged()
115{
116 emit currentPageBoundingPolygonsChanged();
117 emit currentResultBoundingPolygonsChanged();
118}
119
120/*!
121 \qmlproperty list<list<point>> PdfSearchModel::currentPageBoundingPolygons
122
123 A set of paths in a form that can be bound to the \c paths property of a
124 \l {QtQuick::PathMultiline}{PathMultiline} instance to render a batch of
125 rectangles around all the regions where search results are found on
126 \l currentPage:
127
128 \qml
129 PdfDocument {
130 id: doc
131 }
132 PdfSearchModel {
133 id: searchModel
134 document: doc
135 }
136 Shape {
137 ShapePath {
138 PathMultiline {
139 paths: searchModel.matchGeometry(view.currentPage)
140 }
141 }
142 }
143 \endqml
144
145 \sa PathMultiline
146*/
147QList<QPolygonF> QQuickPdfSearchModel::currentPageBoundingPolygons() const
148{
149 return const_cast<QQuickPdfSearchModel *>(this)->boundingPolygonsOnPage(m_currentPage);
150}
151
152/*!
153 \qmlmethod list<list<point>> PdfSearchModel::boundingPolygonsOnPage(int page)
154
155 Returns a set of paths in a form that can be bound to the \c paths property of a
156 \l {QtQuick::PathMultiline}{PathMultiline} instance, which is used to render a
157 batch of rectangles around all the matching locations on the \a page:
158
159 \qml
160 PdfDocument {
161 id: doc
162 }
163 PdfSearchModel {
164 id: searchModel
165 document: doc
166 }
167 Shape {
168 ShapePath {
169 PathMultiline {
170 paths: searchModel.matchGeometry(view.currentPage)
171 }
172 }
173 }
174 \endqml
175
176 \sa PathMultiline
177*/
178QList<QPolygonF> QQuickPdfSearchModel::boundingPolygonsOnPage(int page)
179{
180 if (!document() || searchString().isEmpty() || page < 0 || page > document()->document()->pageCount())
181 return {};
182
183 updatePage(page);
184
185 QList<QPolygonF> ret;
186 const auto m = QPdfSearchModel::resultsOnPage(page);
187 for (const auto &result : m) {
188 for (const auto &rect : result.rectangles())
189 ret << QPolygonF(rect);
190 }
191
192 return ret;
193}
194
195/*!
196 \qmlproperty int PdfSearchModel::currentPage
197
198 The page on which \l currentResultBoundingPolygons should provide filtered
199 search results.
200*/
201void QQuickPdfSearchModel::setCurrentPage(int currentPage)
202{
203 if (m_currentPage == currentPage || !document())
204 return;
205
206 const auto pageCount = document()->document()->pageCount();
207 if (currentPage < 0)
208 currentPage = pageCount - 1;
209 else if (currentPage >= pageCount)
210 currentPage = 0;
211
212 m_currentPage = currentPage;
213 if (!m_suspendSignals) {
214 emit currentPageChanged();
215 onResultsChanged();
216 }
217}
218
219/*!
220 \qmlproperty int PdfSearchModel::currentResult
221
222 The result index within the whole set of search results, for which
223 \l currentResultBoundingPolygons should provide the regions to highlight
224 if currentPage matches \c currentResultLink.page.
225*/
226void QQuickPdfSearchModel::setCurrentResult(int currentResult)
227{
228 if (m_currentResult == currentResult)
229 return;
230
231 const int currentResultWas = m_currentResult;
232 const int currentPageWas = m_currentPage;
233 const int resultCount = rowCount({});
234
235 // wrap around at the ends
236 if (currentResult >= resultCount) {
237 currentResult = 0;
238 } else if (currentResult < 0) {
239 currentResult = resultCount - 1;
240 }
241
242 const QPdfLink link = resultAtIndex(currentResult);
243 if (link.isValid()) {
244 setCurrentPage(link.page());
245 m_currentResult = currentResult;
246 emit currentResultChanged();
247 emit currentResultLinkChanged();
248 emit currentResultBoundingPolygonsChanged();
249 emit currentResultBoundingRectChanged();
250 qCDebug(qLcSearch) << "currentResult was" << currentResultWas
251 << "requested" << currentResult << "on page" << currentPageWas
252 << "->" << m_currentResult << "on page" << m_currentPage;
253 } else {
254 qWarning() << "failed to find result" << currentResult << "in range 0 ->" << resultCount;
255 }
256}
257
258/*!
259 \qmlproperty QPdfLink PdfSearchModel::currentResultLink
260
261 The result at index \l currentResult.
262*/
263QPdfLink QQuickPdfSearchModel::currentResultLink() const
264{
265 return resultAtIndex(m_currentResult);
266}
267
268/*!
269 \qmlproperty string PdfSearchModel::searchString
270
271 The string to search for.
272*/
273
274/*!
275 \since 6.8
276 \qmlproperty int PdfSearchModel::count
277
278 The number of search results found.
279*/
280
281QT_END_NAMESPACE
282
283#include "moc_qquickpdfsearchmodel_p.cpp"