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 QtQuick module 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#include "qquicktextdocument.h"
41#include "qquicktextdocument_p.h"
42
43#include "qquicktextedit_p.h"
44#include "qquicktextedit_p_p.h"
45#include "qquicktext_p_p.h"
46
47#include <QtQml/qqmlinfo.h>
48#include <QtQml/qqmlcontext.h>
49#include <QtQuick/private/qquickpixmapcache_p.h>
50
51QT_BEGIN_NAMESPACE
52
53/*!
54 \class QQuickTextDocument
55 \since 5.1
56 \brief The QQuickTextDocument class provides access to the QTextDocument of QQuickTextEdit.
57 \inmodule QtQuick
58
59 This class provides access to the QTextDocument of QQuickTextEdit elements.
60 This is provided to allow usage of the \l{Rich Text Processing} functionalities of Qt.
61 You are not allowed to modify the document, but it can be used to output content, for example with \l{QTextDocumentWriter}),
62 or provide additional formatting, for example with \l{QSyntaxHighlighter}.
63
64 The class has to be used from C++ directly, using the property of the \l TextEdit.
65
66 Warning: The QTextDocument provided is used internally by \l {Qt Quick} elements to provide text manipulation primitives.
67 You are not allowed to perform any modification of the internal state of the QTextDocument. If you do, the element
68 in question may stop functioning or crash.
69*/
70
71class QQuickTextDocumentPrivate : public QObjectPrivate
72{
73public:
74 QPointer<QTextDocument> document;
75};
76
77/*!
78 Constructs a QQuickTextDocument object with
79 \a parent as the parent object.
80*/
81QQuickTextDocument::QQuickTextDocument(QQuickItem *parent)
82 : QObject(*(new QQuickTextDocumentPrivate), parent)
83{
84 Q_D(QQuickTextDocument);
85 Q_ASSERT(parent);
86 Q_ASSERT(qobject_cast<QQuickTextEdit*>(parent));
87 d->document = QPointer<QTextDocument>(qobject_cast<QQuickTextEdit*>(object: parent)->d_func()->document);
88}
89
90/*!
91 Returns a pointer to the QTextDocument object.
92*/
93QTextDocument* QQuickTextDocument::textDocument() const
94{
95 Q_D(const QQuickTextDocument);
96 return d->document.data();
97}
98
99QQuickTextDocumentWithImageResources::QQuickTextDocumentWithImageResources(QQuickItem *parent)
100: QTextDocument(parent), outstanding(0)
101{
102 setUndoRedoEnabled(false);
103 documentLayout()->registerHandler(objectType: QTextFormat::ImageObject, component: this);
104 connect(sender: this, SIGNAL(baseUrlChanged(QUrl)), receiver: this, SLOT(reset()));
105}
106
107QQuickTextDocumentWithImageResources::~QQuickTextDocumentWithImageResources()
108{
109 if (!m_resources.isEmpty())
110 qDeleteAll(c: m_resources);
111}
112
113QVariant QQuickTextDocumentWithImageResources::loadResource(int type, const QUrl &name)
114{
115 QVariant resource = QTextDocument::loadResource(type, name);
116 if (resource.isNull() && type == QTextDocument::ImageResource) {
117 QQmlContext *context = qmlContext(parent());
118 QUrl url = baseUrl().resolved(relative: name);
119 QQuickPixmap *p = loadPixmap(context, name: url);
120 resource = p->image();
121 }
122
123 return resource;
124}
125
126void QQuickTextDocumentWithImageResources::requestFinished()
127{
128 outstanding--;
129 if (outstanding == 0) {
130 markContentsDirty(from: 0, length: characterCount());
131 emit imagesLoaded();
132 }
133}
134
135QSizeF QQuickTextDocumentWithImageResources::intrinsicSize(
136 QTextDocument *, int, const QTextFormat &format)
137{
138 if (format.isImageFormat()) {
139 QTextImageFormat imageFormat = format.toImageFormat();
140
141 const int width = qRound(d: imageFormat.width());
142 const bool hasWidth = imageFormat.hasProperty(propertyId: QTextFormat::ImageWidth) && width > 0;
143 const int height = qRound(d: imageFormat.height());
144 const bool hasHeight = imageFormat.hasProperty(propertyId: QTextFormat::ImageHeight) && height > 0;
145
146 QSizeF size(width, height);
147 if (!hasWidth || !hasHeight) {
148 QVariant res = resource(type: QTextDocument::ImageResource, name: QUrl(imageFormat.name()));
149 QImage image = res.value<QImage>();
150 if (image.isNull()) {
151 if (!hasWidth)
152 size.setWidth(16);
153 if (!hasHeight)
154 size.setHeight(16);
155 return size;
156 }
157 QSize imgSize = image.size();
158
159 if (!hasWidth) {
160 if (!hasHeight)
161 size.setWidth(imgSize.width());
162 else
163 size.setWidth(qRound(d: height * (imgSize.width() / (qreal) imgSize.height())));
164 }
165 if (!hasHeight) {
166 if (!hasWidth)
167 size.setHeight(imgSize.height());
168 else
169 size.setHeight(qRound(d: width * (imgSize.height() / (qreal) imgSize.width())));
170 }
171 }
172 return size;
173 }
174 return QSizeF();
175}
176
177void QQuickTextDocumentWithImageResources::drawObject(
178 QPainter *, const QRectF &, QTextDocument *, int, const QTextFormat &)
179{
180}
181
182QImage QQuickTextDocumentWithImageResources::image(const QTextImageFormat &format) const
183{
184 QVariant res = resource(type: QTextDocument::ImageResource, name: QUrl(format.name()));
185 return res.value<QImage>();
186}
187
188void QQuickTextDocumentWithImageResources::reset()
189{
190 clearResources();
191 markContentsDirty(from: 0, length: characterCount());
192}
193
194QQuickPixmap *QQuickTextDocumentWithImageResources::loadPixmap(
195 QQmlContext *context, const QUrl &url)
196{
197
198 QHash<QUrl, QQuickPixmap *>::Iterator iter = m_resources.find(akey: url);
199
200 if (iter == m_resources.end()) {
201 QQuickPixmap *p = new QQuickPixmap(context->engine(), url);
202 iter = m_resources.insert(akey: url, avalue: p);
203
204 if (p->isLoading()) {
205 p->connectFinished(this, SLOT(requestFinished()));
206 outstanding++;
207 }
208 }
209
210 QQuickPixmap *p = *iter;
211 if (p->isError()) {
212 if (!errors.contains(value: url)) {
213 errors.insert(value: url);
214 qmlWarning(me: parent()) << p->error();
215 }
216 }
217 return p;
218}
219
220void QQuickTextDocumentWithImageResources::clearResources()
221{
222 for (QQuickPixmap *pixmap : qAsConst(t&: m_resources))
223 pixmap->clear(this);
224 qDeleteAll(c: m_resources);
225 m_resources.clear();
226 outstanding = 0;
227}
228
229void QQuickTextDocumentWithImageResources::setText(const QString &text)
230{
231 clearResources();
232
233#if QT_CONFIG(texthtmlparser)
234 setHtml(text);
235#else
236 setPlainText(text);
237#endif
238}
239
240#if QT_CONFIG(textmarkdownreader)
241void QQuickTextDocumentWithImageResources::setMarkdownText(const QString &text)
242{
243 clearResources();
244 QTextDocument::setMarkdown(markdown: text);
245}
246#endif
247
248QSet<QUrl> QQuickTextDocumentWithImageResources::errors;
249
250QT_END_NAMESPACE
251
252#include "moc_qquicktextdocument.cpp"
253#include "moc_qquicktextdocument_p.cpp"
254

source code of qtdeclarative/src/quick/items/qquicktextdocument.cpp