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 | #include "qquicktextdocument.h" |
5 | #include "qquicktextdocument_p.h" |
6 | |
7 | #include "qquicktextedit_p.h" |
8 | |
9 | #include <QtQml/qqmlcontext.h> |
10 | #include <QtQml/qqmlfile.h> |
11 | #include <QtQml/qqmlinfo.h> |
12 | #include <QtQuick/private/qquickpixmap_p.h> |
13 | |
14 | #include <QtCore/qfile.h> |
15 | #include <QtCore/qpointer.h> |
16 | |
17 | QT_BEGIN_NAMESPACE |
18 | |
19 | Q_LOGGING_CATEGORY(lcTextDoc, "qt.quick.textdocument" ) |
20 | |
21 | using namespace Qt::StringLiterals; |
22 | |
23 | /*! |
24 | \qmltype TextDocument |
25 | \nativetype QQuickTextDocument |
26 | \inqmlmodule QtQuick |
27 | \brief A wrapper around TextEdit's backing QTextDocument. |
28 | \preliminary |
29 | |
30 | To load text into the document, set the \l source property. If the user then |
31 | modifies the text and wants to save the same document, call \l save() to save |
32 | it to the same source again (only if \l {QUrl::isLocalFile()}{it's a local file}). |
33 | Or call \l saveAs() to save it to a different file. |
34 | |
35 | This class cannot be instantiated in QML, but is available from \l TextEdit::textDocument. |
36 | |
37 | \note All loading and saving is done synchronously for now. |
38 | This may block the UI if the \l source is a slow network drive. |
39 | This may be improved in future versions of Qt. |
40 | |
41 | \note This API is considered tech preview and may change in future versions of Qt. |
42 | */ |
43 | |
44 | /*! |
45 | \class QQuickTextDocument |
46 | \since 5.1 |
47 | \brief The QQuickTextDocument class provides access to the QTextDocument of QQuickTextEdit. |
48 | \inmodule QtQuick |
49 | |
50 | This class provides access to the QTextDocument of QQuickTextEdit elements. |
51 | This is provided to allow usage of the \l{Rich Text Processing} functionalities of Qt, |
52 | including document modifications. It can also be used to output content, |
53 | for example with \l{QTextDocumentWriter}, or provide additional formatting, |
54 | for example with \l{QSyntaxHighlighter}. |
55 | */ |
56 | |
57 | /*! |
58 | Constructs a QQuickTextDocument object with |
59 | \a parent as the parent object. |
60 | */ |
61 | QQuickTextDocument::QQuickTextDocument(QQuickItem *parent) |
62 | : QObject(*(new QQuickTextDocumentPrivate), parent) |
63 | { |
64 | Q_D(QQuickTextDocument); |
65 | Q_ASSERT(parent); |
66 | d->editor = qobject_cast<QQuickTextEdit *>(object: parent); |
67 | Q_ASSERT(d->editor); |
68 | connect(sender: textDocument(), signal: &QTextDocument::modificationChanged, |
69 | context: this, slot: &QQuickTextDocument::modifiedChanged); |
70 | } |
71 | |
72 | /*! |
73 | \property QQuickTextDocument::status |
74 | \brief the status of document loading or saving |
75 | \since 6.7 |
76 | \preliminary |
77 | |
78 | This property holds the status of document loading or saving. It can be one of: |
79 | |
80 | \value Null No file has been loaded |
81 | \value Loading Reading from \l source has begun |
82 | \value Loaded Reading has successfully finished |
83 | \value Saving File writing has begun after save() or saveAs() |
84 | \value Saved Writing has successfully finished |
85 | \value ReadError An error occurred while reading from \l source |
86 | \value WriteError An error occurred in save() or saveAs() |
87 | \value NonLocalFileError saveAs() was called with a URL pointing |
88 | to a remote resource rather than a local file |
89 | |
90 | \sa errorString, source, save(), saveAs() |
91 | */ |
92 | |
93 | /*! |
94 | \qmlproperty enumeration QtQuick::TextDocument::status |
95 | \readonly |
96 | \since 6.7 |
97 | \preliminary |
98 | |
99 | This property holds the status of document loading or saving. It can be one of: |
100 | |
101 | \value TextDocument.Null No file has been loaded |
102 | \value TextDocument.Loading Reading from \l source has begun |
103 | \value TextDocument.Loaded Reading has successfully finished |
104 | \value TextDocument.Saving File writing has begun after save() or saveAs() |
105 | \value TextDocument.Saved Writing has successfully finished |
106 | \value TextDocument.ReadError An error occurred while reading from \l source |
107 | \value TextDocument.WriteError An error occurred in save() or saveAs() |
108 | \value TextDocument.NonLocalFileError saveAs() was called with a URL pointing |
109 | to a remote resource rather than a local file |
110 | |
111 | Use this status to provide an update or respond to the status change in some way. |
112 | For example, you could: |
113 | |
114 | \list |
115 | \li Trigger a state change: |
116 | \qml |
117 | State { |
118 | name: 'loaded' |
119 | when: textEdit.textDocument.status == textEdit.textDocument.Loaded |
120 | } |
121 | \endqml |
122 | |
123 | \li Implement an \c onStatusChanged signal handler: |
124 | \qml |
125 | TextEdit { |
126 | onStatusChanged: { |
127 | if (textDocument.status === textDocument.Loaded) |
128 | console.log('Loaded') |
129 | } |
130 | } |
131 | \endqml |
132 | |
133 | \li Bind to the status value: |
134 | |
135 | \snippet qml/textEditStatusSwitch.qml 0 |
136 | |
137 | \endlist |
138 | |
139 | \sa errorString, source, save(), saveAs() |
140 | */ |
141 | QQuickTextDocument::Status QQuickTextDocument::status() const |
142 | { |
143 | Q_D(const QQuickTextDocument); |
144 | return d->status; |
145 | } |
146 | |
147 | /*! |
148 | \property QQuickTextDocument::errorString |
149 | \brief a human-readable string describing the error that occurred during loading or saving, if any |
150 | \since 6.7 |
151 | \preliminary |
152 | |
153 | By default this string is empty. |
154 | |
155 | \sa status, source, save(), saveAs() |
156 | */ |
157 | |
158 | /*! |
159 | \qmlproperty string QtQuick::TextDocument::errorString |
160 | \readonly |
161 | \since 6.7 |
162 | \preliminary |
163 | |
164 | This property holds a human-readable string describing the error that |
165 | occurred during loading or saving, if any; otherwise, an empty string. |
166 | |
167 | \sa status, source, save(), saveAs() |
168 | */ |
169 | QString QQuickTextDocument::errorString() const |
170 | { |
171 | Q_D(const QQuickTextDocument); |
172 | return d->errorString; |
173 | } |
174 | |
175 | void QQuickTextDocumentPrivate::setStatus(QQuickTextDocument::Status s, const QString &err) |
176 | { |
177 | Q_Q(QQuickTextDocument); |
178 | if (status == s) |
179 | return; |
180 | |
181 | status = s; |
182 | emit q->statusChanged(); |
183 | |
184 | if (errorString == err) |
185 | return; |
186 | errorString = err; |
187 | emit q->errorStringChanged(); |
188 | if (!err.isEmpty()) |
189 | qmlWarning(me: q) << err; |
190 | } |
191 | |
192 | /*! |
193 | \property QQuickTextDocument::source |
194 | \brief the URL from which to load document contents |
195 | \since 6.7 |
196 | \preliminary |
197 | |
198 | QQuickTextDocument can handle any text format supported by Qt, loaded from |
199 | any URL scheme supported by Qt. |
200 | |
201 | The \c source property cannot be changed while the document's \l modified |
202 | state is \c true. If the user has modified the document contents, you |
203 | should prompt the user whether to \l save(), or else discard changes by |
204 | setting \l modified to \c false before setting the \c source property to a |
205 | different URL. |
206 | |
207 | \sa QTextDocumentWriter::supportedDocumentFormats() |
208 | */ |
209 | |
210 | /*! |
211 | \qmlproperty url QtQuick::TextDocument::source |
212 | \since 6.7 |
213 | \preliminary |
214 | |
215 | QQuickTextDocument can handle any text format supported by Qt, loaded from |
216 | any URL scheme supported by Qt. |
217 | |
218 | The URL may be absolute, or relative to the URL of the component. |
219 | |
220 | The \c source property cannot be changed while the document's \l modified |
221 | state is \c true. If the user has modified the document contents, you |
222 | should prompt the user whether to \l save(), or else discard changes by |
223 | setting \c {modified = false} before setting the \l source property to a |
224 | different URL. |
225 | |
226 | \sa QTextDocumentWriter::supportedDocumentFormats() |
227 | */ |
228 | QUrl QQuickTextDocument::source() const |
229 | { |
230 | Q_D(const QQuickTextDocument); |
231 | return d->url; |
232 | } |
233 | |
234 | void QQuickTextDocument::setSource(const QUrl &url) |
235 | { |
236 | Q_D(QQuickTextDocument); |
237 | |
238 | if (url == d->url) |
239 | return; |
240 | |
241 | if (isModified()) { |
242 | qmlWarning(me: this) << "Existing document modified: you should save()," |
243 | "or call TextEdit.clear() before setting a different source" ; |
244 | return; |
245 | } |
246 | |
247 | d->url = url; |
248 | emit sourceChanged(); |
249 | d->load(); |
250 | } |
251 | |
252 | /*! |
253 | \property QQuickTextDocument::modified |
254 | \brief whether the document has been modified by the user |
255 | \since 6.7 |
256 | \preliminary |
257 | |
258 | This property holds whether the document has been modified by the user |
259 | since the last time it was loaded or saved. By default, this property is |
260 | \c false. |
261 | |
262 | As with \l QTextDocument::modified, you can set the modified property: |
263 | for example, set it to \c false to allow setting the \l source property |
264 | to a different URL (thus discarding the user's changes). |
265 | |
266 | \sa QTextDocument::modified |
267 | */ |
268 | |
269 | /*! |
270 | \qmlproperty bool QtQuick::TextDocument::modified |
271 | \since 6.7 |
272 | \preliminary |
273 | |
274 | This property holds whether the document has been modified by the user |
275 | since the last time it was loaded or saved. By default, this property is |
276 | \c false. |
277 | |
278 | As with \l QTextDocument::modified, you can set the modified property: |
279 | for example, set it to \c false to allow setting the \l source property |
280 | to a different URL (thus discarding the user's changes). |
281 | |
282 | \sa QTextDocument::modified |
283 | */ |
284 | bool QQuickTextDocument::isModified() const |
285 | { |
286 | const auto *doc = textDocument(); |
287 | return doc && doc->isModified(); |
288 | } |
289 | |
290 | void QQuickTextDocument::setModified(bool modified) |
291 | { |
292 | if (auto *doc = textDocument()) |
293 | doc->setModified(modified); |
294 | } |
295 | |
296 | void QQuickTextDocumentPrivate::load() |
297 | { |
298 | auto *doc = editor->document(); |
299 | if (!doc) { |
300 | setStatus(s: QQuickTextDocument::Status::ReadError, |
301 | err: QQuickTextDocument::tr(s: "Null document object: cannot load" )); |
302 | return; |
303 | } |
304 | const QQmlContext *context = qmlContext(editor); |
305 | const QUrl &resolvedUrl = context ? context->resolvedUrl(url) : url; |
306 | const QString filePath = QQmlFile::urlToLocalFileOrQrc(resolvedUrl); |
307 | QFile file(filePath); |
308 | if (file.exists()) { |
309 | #if QT_CONFIG(mimetype) |
310 | QMimeType mimeType = QMimeDatabase().mimeTypeForFile(fileName: filePath); |
311 | const bool isHtml = mimeType.inherits(mimeTypeName: "text/html"_L1 ); |
312 | const bool isMarkdown = mimeType.inherits(mimeTypeName: "text/markdown"_L1 ) |
313 | || mimeType.inherits(mimeTypeName: "text/x-web-markdown"_L1 ); //Tika database |
314 | #else |
315 | const bool isHtml = filePath.endsWith(".html"_L1 , Qt::CaseInsensitive) || |
316 | filePath.endsWith(".htm"_L1 , Qt::CaseInsensitive); |
317 | const bool isMarkdown = filePath.endsWith(".md"_L1 , Qt::CaseInsensitive) || |
318 | filePath.endsWith(".markdown"_L1 , Qt::CaseInsensitive); |
319 | #endif |
320 | if (isHtml) |
321 | detectedFormat = Qt::RichText; |
322 | else if (isMarkdown) |
323 | detectedFormat = Qt::MarkdownText; |
324 | else |
325 | detectedFormat = Qt::PlainText; |
326 | if (file.open(flags: QFile::ReadOnly | QFile::Text)) { |
327 | setStatus(s: QQuickTextDocument::Status::Loading, err: {}); |
328 | QByteArray data = file.readAll(); |
329 | doc->setBaseUrl(resolvedUrl.adjusted(options: QUrl::RemoveFilename)); |
330 | #if QT_CONFIG(textmarkdownreader) || QT_CONFIG(texthtmlparser) |
331 | const bool plainText = editor->textFormat() == QQuickTextEdit::PlainText; |
332 | #endif |
333 | #if QT_CONFIG(textmarkdownreader) |
334 | if (!plainText && isMarkdown) { |
335 | doc->setMarkdown(markdown: QString::fromUtf8(ba: data)); |
336 | } else |
337 | #endif |
338 | #if QT_CONFIG(texthtmlparser) |
339 | if (!plainText && isHtml) { |
340 | // If a user loads an HTML file, remember the encoding. |
341 | // If the user then calls save() later, the same encoding will be used. |
342 | encoding = QStringConverter::encodingForHtml(data); |
343 | if (encoding) { |
344 | QStringDecoder decoder(*encoding); |
345 | doc->setHtml(decoder(data)); |
346 | } else { |
347 | // fall back to utf8 |
348 | doc->setHtml(QString::fromUtf8(ba: data)); |
349 | } |
350 | } else |
351 | #endif |
352 | { |
353 | doc->setPlainText(QString::fromUtf8(ba: data)); |
354 | } |
355 | setStatus(s: QQuickTextDocument::Status::Loaded, err: {}); |
356 | qCDebug(lcTextDoc) << editor << "loaded" << filePath |
357 | << "as" << editor->textFormat() << "detected" << detectedFormat |
358 | #if QT_CONFIG(mimetype) |
359 | << "(file type" << mimeType << ')' |
360 | #endif |
361 | ; |
362 | doc->setModified(false); |
363 | return; |
364 | } |
365 | setStatus(s: QQuickTextDocument::Status::ReadError, |
366 | err: QQuickTextDocument::tr(s: "Failed to read: %1" ).arg(a: file.errorString())); |
367 | } else { |
368 | setStatus(s: QQuickTextDocument::Status::ReadError, |
369 | err: QQuickTextDocument::tr(s: "%1 does not exist" ).arg(a: filePath)); |
370 | } |
371 | } |
372 | |
373 | void QQuickTextDocumentPrivate::writeTo(const QUrl &fileUrl) |
374 | { |
375 | auto *doc = editor->document(); |
376 | if (!doc) |
377 | return; |
378 | |
379 | const QString filePath = fileUrl.toLocalFile(); |
380 | const bool sameUrl = fileUrl == url; |
381 | if (!sameUrl) { |
382 | #if QT_CONFIG(mimetype) |
383 | const auto type = QMimeDatabase().mimeTypeForUrl(url: fileUrl); |
384 | if (type.inherits(mimeTypeName: "text/html"_L1 )) |
385 | detectedFormat = Qt::RichText; |
386 | else if (type.inherits(mimeTypeName: "text/markdown"_L1 )) |
387 | detectedFormat = Qt::MarkdownText; |
388 | else |
389 | detectedFormat = Qt::PlainText; |
390 | #else |
391 | if (filePath.endsWith(".html"_L1 , Qt::CaseInsensitive) || |
392 | filePath.endsWith(".htm"_L1 , Qt::CaseInsensitive)) |
393 | detectedFormat = Qt::RichText; |
394 | else if (filePath.endsWith(".md"_L1 , Qt::CaseInsensitive) || |
395 | filePath.endsWith(".markdown"_L1 , Qt::CaseInsensitive)) |
396 | detectedFormat = Qt::MarkdownText; |
397 | else |
398 | detectedFormat = Qt::PlainText; |
399 | #endif |
400 | } |
401 | QFile file(filePath); |
402 | if (!file.open(flags: QFile::WriteOnly | QFile::Truncate | |
403 | (detectedFormat == Qt::RichText ? QFile::NotOpen : QFile::Text))) { |
404 | setStatus(s: QQuickTextDocument::Status::WriteError, |
405 | err: QQuickTextDocument::tr(s: "Cannot save: %1" ).arg(a: file.errorString())); |
406 | return; |
407 | } |
408 | setStatus(s: QQuickTextDocument::Status::Saving, err: {}); |
409 | QByteArray raw; |
410 | |
411 | switch (detectedFormat) { |
412 | #if QT_CONFIG(textmarkdownwriter) |
413 | case Qt::MarkdownText: |
414 | raw = doc->toMarkdown().toUtf8(); |
415 | break; |
416 | #endif |
417 | #if QT_CONFIG(texthtmlparser) |
418 | case Qt::RichText: |
419 | if (sameUrl && encoding) { |
420 | QStringEncoder enc(*encoding); |
421 | raw = enc.encode(str: doc->toHtml()); |
422 | } else { |
423 | // default to UTF-8 unless the user is saving the same file as previously loaded |
424 | raw = doc->toHtml().toUtf8(); |
425 | } |
426 | break; |
427 | #endif |
428 | default: |
429 | raw = doc->toPlainText().toUtf8(); |
430 | break; |
431 | } |
432 | |
433 | file.write(data: raw); |
434 | file.close(); |
435 | setStatus(s: QQuickTextDocument::Status::Saved, err: {}); |
436 | doc->setModified(false); |
437 | } |
438 | |
439 | QTextDocument *QQuickTextDocumentPrivate::document() const |
440 | { |
441 | return editor->document(); |
442 | } |
443 | |
444 | void QQuickTextDocumentPrivate::setDocument(QTextDocument *doc) |
445 | { |
446 | Q_Q(QQuickTextDocument); |
447 | QTextDocument *oldDoc = editor->document(); |
448 | if (doc == oldDoc) |
449 | return; |
450 | |
451 | if (oldDoc) |
452 | oldDoc->disconnect(receiver: q); |
453 | if (doc) { |
454 | q->connect(sender: doc, signal: &QTextDocument::modificationChanged, |
455 | context: q, slot: &QQuickTextDocument::modifiedChanged); |
456 | } |
457 | editor->setDocument(doc); |
458 | emit q->textDocumentChanged(); |
459 | } |
460 | |
461 | /*! |
462 | Returns a pointer to the QTextDocument object. |
463 | */ |
464 | QTextDocument *QQuickTextDocument::textDocument() const |
465 | { |
466 | Q_D(const QQuickTextDocument); |
467 | return d->document(); |
468 | } |
469 | |
470 | /*! |
471 | \brief Sets the given \a document. |
472 | \since 6.7 |
473 | |
474 | The caller retains ownership of the document. |
475 | */ |
476 | void QQuickTextDocument::setTextDocument(QTextDocument *document) |
477 | { |
478 | d_func()->setDocument(document); |
479 | } |
480 | |
481 | /*! |
482 | \fn void QQuickTextDocument::textDocumentChanged() |
483 | \since 6.7 |
484 | |
485 | This signal is emitted when the underlying QTextDocument is |
486 | replaced with a different instance. |
487 | |
488 | \sa setTextDocument() |
489 | */ |
490 | |
491 | /*! |
492 | \preliminary |
493 | \fn void QQuickTextDocument::sourceChanged() |
494 | */ |
495 | |
496 | /*! |
497 | \preliminary |
498 | \fn void QQuickTextDocument::modifiedChanged() |
499 | */ |
500 | |
501 | /*! |
502 | \preliminary |
503 | \fn void QQuickTextDocument::statusChanged() |
504 | */ |
505 | |
506 | /*! |
507 | \preliminary |
508 | \fn void QQuickTextDocument::errorStringChanged() |
509 | */ |
510 | |
511 | /*! |
512 | \fn void QQuickTextDocument::save() |
513 | \since 6.7 |
514 | \preliminary |
515 | |
516 | Saves the contents to the same file and format specified by \l source. |
517 | |
518 | \note You can save only to a \l {QUrl::isLocalFile()}{file on a mounted filesystem}. |
519 | |
520 | \sa source, saveAs() |
521 | */ |
522 | |
523 | /*! |
524 | \qmlmethod void QtQuick::TextDocument::save() |
525 | \brief Saves the contents to the same file and format specified by \l source. |
526 | \since 6.7 |
527 | \preliminary |
528 | |
529 | \note You can save only to a \l {QUrl::isLocalFile()}{file on a mounted filesystem}. |
530 | |
531 | \sa source, saveAs() |
532 | */ |
533 | void QQuickTextDocument::save() |
534 | { |
535 | Q_D(QQuickTextDocument); |
536 | d->writeTo(fileUrl: d->url); |
537 | } |
538 | |
539 | /*! |
540 | \fn void QQuickTextDocument::saveAs(const QUrl &url) |
541 | \brief Saves the contents to the file and format specified by \a url. |
542 | \since 6.7 |
543 | \preliminary |
544 | |
545 | The file extension in \a url specifies the file format |
546 | (as determined by QMimeDatabase::mimeTypeForUrl()). |
547 | |
548 | \note You can save only to a \l {QUrl::isLocalFile()}{file on a mounted filesystem}. |
549 | |
550 | \sa source, save() |
551 | */ |
552 | |
553 | /*! |
554 | \qmlmethod void QtQuick::TextDocument::saveAs(url url) |
555 | \brief Saves the contents to the file and format specified by \a url. |
556 | \since 6.7 |
557 | \preliminary |
558 | |
559 | The file extension in \a url specifies the file format |
560 | (as determined by QMimeDatabase::mimeTypeForUrl()). |
561 | |
562 | \note You can save only to a \l {QUrl::isLocalFile()}{file on a mounted filesystem}. |
563 | |
564 | \sa source, save() |
565 | */ |
566 | void QQuickTextDocument::saveAs(const QUrl &url) |
567 | { |
568 | Q_D(QQuickTextDocument); |
569 | if (!url.isLocalFile()) { |
570 | d->setStatus(s: QQuickTextDocument::Status::NonLocalFileError, |
571 | err: QQuickTextDocument::tr(s: "Can only save to local files" )); |
572 | return; |
573 | } |
574 | d->writeTo(fileUrl: url); |
575 | |
576 | if (url == d->url) |
577 | return; |
578 | |
579 | d->url = url; |
580 | emit sourceChanged(); |
581 | } |
582 | |
583 | QQuickTextImageHandler::QQuickTextImageHandler(QObject *parent) |
584 | : QObject(parent) |
585 | { |
586 | } |
587 | |
588 | QSizeF QQuickTextImageHandler::intrinsicSize( |
589 | QTextDocument *doc, int, const QTextFormat &format) |
590 | { |
591 | if (format.isImageFormat()) { |
592 | QTextImageFormat imageFormat = format.toImageFormat(); |
593 | int width = qRound(d: imageFormat.width()); |
594 | const bool hasWidth = imageFormat.hasProperty(propertyId: QTextFormat::ImageWidth) && width > 0; |
595 | const int height = qRound(d: imageFormat.height()); |
596 | const bool hasHeight = imageFormat.hasProperty(propertyId: QTextFormat::ImageHeight) && height > 0; |
597 | const auto maxWidth = imageFormat.maximumWidth(); |
598 | const bool hasMaxWidth = imageFormat.hasProperty(propertyId: QTextFormat::ImageMaxWidth) && maxWidth.type() != QTextLength::VariableLength; |
599 | |
600 | int effectiveMaxWidth = INT_MAX; |
601 | if (hasMaxWidth) { |
602 | if (maxWidth.type() == QTextLength::PercentageLength) { |
603 | effectiveMaxWidth = (doc->pageSize().width() - 2 * doc->documentMargin()) * maxWidth.value(maximumLength: 100) / 100; |
604 | } else { |
605 | effectiveMaxWidth = maxWidth.rawValue(); |
606 | } |
607 | |
608 | width = qMin(a: effectiveMaxWidth, b: width); |
609 | } |
610 | |
611 | QSizeF size(width, height); |
612 | if (!hasWidth || !hasHeight) { |
613 | QVariant res = doc->resource(type: QTextDocument::ImageResource, name: QUrl(imageFormat.name())); |
614 | QImage image = res.value<QImage>(); |
615 | if (image.isNull()) { |
616 | // autotests expect us to reserve a 16x16 space for a "broken image" icon, |
617 | // even though we don't actually display one |
618 | if (!hasWidth) |
619 | size.setWidth(16); |
620 | if (!hasHeight) |
621 | size.setHeight(16); |
622 | return size; |
623 | } |
624 | QSize imgSize = image.size(); |
625 | if (imgSize.width() > effectiveMaxWidth) { |
626 | // image is bigger than effectiveMaxWidth, scale it down |
627 | imgSize.setHeight(effectiveMaxWidth * imgSize.height() / (qreal) imgSize.width()); |
628 | imgSize.setWidth(effectiveMaxWidth); |
629 | } |
630 | |
631 | if (!hasWidth) { |
632 | if (!hasHeight) |
633 | size.setWidth(imgSize.width()); |
634 | else |
635 | size.setWidth(qMin(a: effectiveMaxWidth, b: qRound(d: height * (imgSize.width() / (qreal) imgSize.height())))); |
636 | } |
637 | if (!hasHeight) { |
638 | if (!hasWidth) |
639 | size.setHeight(imgSize.height()); |
640 | else |
641 | size.setHeight(qRound(d: width * (imgSize.height() / (qreal) imgSize.width()))); |
642 | } |
643 | } |
644 | return size; |
645 | } |
646 | return QSizeF(); |
647 | } |
648 | |
649 | QT_END_NAMESPACE |
650 | |
651 | #include "moc_qquicktextdocument.cpp" |
652 | #include "moc_qquicktextdocument_p.cpp" |
653 | |