62QQuickTextDocument::QQuickTextDocument(QQuickItem *parent)
63 : QObject(*(
new QQuickTextDocumentPrivate), parent)
65 Q_D(QQuickTextDocument);
67 d->editor = qobject_cast<QQuickTextEdit *>(parent);
69 connect(textDocument(), &QTextDocument::modificationChanged,
70 this, &QQuickTextDocument::modifiedChanged);
299 auto *doc =
editor->document();
301 setStatus(QQuickTextDocument::Status::ReadError,
302 QQuickTextDocument::tr(
"Null document object: cannot load"));
305 const QQmlContext *context = qmlContext(
editor);
306 const QUrl &resolvedUrl = context ? context->resolvedUrl(url) : url;
307 const QString filePath = QQmlFile::urlToLocalFileOrQrc(resolvedUrl);
308 QFile file(filePath);
310#if QT_CONFIG(mimetype)
311 QMimeType mimeType = QMimeDatabase().mimeTypeForFile(filePath);
312 const bool isHtml = mimeType.inherits(
"text/html"_L1);
313 const bool isMarkdown = mimeType.inherits(
"text/markdown"_L1)
314 || mimeType.inherits(
"text/x-web-markdown"_L1);
316 const bool isHtml = filePath.endsWith(
".html"_L1, Qt::CaseInsensitive) ||
317 filePath.endsWith(
".htm"_L1, Qt::CaseInsensitive);
318 const bool isMarkdown = filePath.endsWith(
".md"_L1, Qt::CaseInsensitive) ||
319 filePath.endsWith(
".markdown"_L1, Qt::CaseInsensitive);
322 detectedFormat = Qt::RichText;
324 detectedFormat = Qt::MarkdownText;
326 detectedFormat = Qt::PlainText;
327 if (file.open(QFile::ReadOnly | QFile::Text)) {
328 setStatus(QQuickTextDocument::Status::Loading, {});
329 QByteArray data = file.readAll();
330 doc->setBaseUrl(resolvedUrl.adjusted(QUrl::RemoveFilename));
331#if QT_CONFIG(textmarkdownreader) || QT_CONFIG(texthtmlparser)
332 const bool plainText = editor->textFormat() == QQuickTextEdit::PlainText;
334#if QT_CONFIG(textmarkdownreader)
335 if (!plainText && isMarkdown) {
336 doc->setMarkdown(QString::fromUtf8(data));
339#if QT_CONFIG(texthtmlparser)
340 if (!plainText && isHtml) {
343 encoding = QStringConverter::encodingForHtml(data);
345 QStringDecoder decoder(*encoding);
346 doc->setHtml(decoder(data));
349 doc->setHtml(QString::fromUtf8(data));
354 doc->setPlainText(QString::fromUtf8(data));
356 editor->setCursorPosition(0);
357 setStatus(QQuickTextDocument::Status::Loaded, {});
358 qCDebug(lcTextDoc) << editor <<
"loaded" << filePath
359 <<
"as" << editor->textFormat() <<
"detected" << detectedFormat
360#if QT_CONFIG(mimetype)
361 <<
"(file type" << mimeType <<
')'
364 doc->setModified(
false);
367 setStatus(QQuickTextDocument::Status::ReadError,
368 QQuickTextDocument::tr(
"Failed to read: %1").arg(file.errorString()));
370 setStatus(QQuickTextDocument::Status::ReadError,
371 QQuickTextDocument::tr(
"%1 does not exist").arg(filePath));
377 auto *doc =
editor->document();
381 const QString filePath = QQmlFile::urlToLocalFileOrQrc(fileUrl);
382 const bool sameUrl = fileUrl == url;
384#if QT_CONFIG(mimetype)
385 const auto type = QMimeDatabase().mimeTypeForUrl(fileUrl);
386 if (type.inherits(
"text/html"_L1))
387 detectedFormat = Qt::RichText;
388 else if (type.inherits(
"text/markdown"_L1))
389 detectedFormat = Qt::MarkdownText;
391 detectedFormat = Qt::PlainText;
393 if (filePath.endsWith(
".html"_L1, Qt::CaseInsensitive) ||
394 filePath.endsWith(
".htm"_L1, Qt::CaseInsensitive))
395 detectedFormat = Qt::RichText;
396 else if (filePath.endsWith(
".md"_L1, Qt::CaseInsensitive) ||
397 filePath.endsWith(
".markdown"_L1, Qt::CaseInsensitive))
398 detectedFormat = Qt::MarkdownText;
400 detectedFormat = Qt::PlainText;
403 QFile file(filePath);
404 if (!file.open(QFile::WriteOnly | QFile::Truncate |
405 (detectedFormat == Qt::RichText ? QFile::NotOpen : QFile::Text))) {
406 setStatus(QQuickTextDocument::Status::WriteError,
407 QQuickTextDocument::tr(
"Cannot save: %1").arg(file.errorString()));
410 setStatus(QQuickTextDocument::Status::Saving, {});
413 switch (detectedFormat) {
414#if QT_CONFIG(textmarkdownwriter)
415 case Qt::MarkdownText:
416 raw = doc->toMarkdown().toUtf8();
419#if QT_CONFIG(texthtmlparser)
421 if (sameUrl && encoding) {
422 QStringEncoder enc(*encoding);
423 raw = enc.encode(doc->toHtml());
426 raw = doc->toHtml().toUtf8();
431 raw = doc->toPlainText().toUtf8();
437 setStatus(QQuickTextDocument::Status::Saved, {});
438 doc->setModified(
false);
595 QTextDocument *doc,
int,
const QTextFormat &format)
597 if (format.isImageFormat()) {
598 QTextImageFormat imageFormat = format.toImageFormat();
599 int width = qRound(qBound(qreal(INT_MIN), imageFormat.width(), qreal(INT_MAX)));
600 const bool hasWidth = imageFormat.hasProperty(QTextFormat::ImageWidth) && width > 0;
601 const int height = qRound(qBound(qreal(INT_MIN), imageFormat.height(), qreal(INT_MAX)));
602 const bool hasHeight = imageFormat.hasProperty(QTextFormat::ImageHeight) && height > 0;
603 const auto maxWidth = imageFormat.maximumWidth();
604 const bool hasMaxWidth = imageFormat.hasProperty(QTextFormat::ImageMaxWidth) && maxWidth.type() != QTextLength::VariableLength;
606 int effectiveMaxWidth = INT_MAX;
608 if (maxWidth.type() == QTextLength::PercentageLength) {
609 effectiveMaxWidth = (doc->pageSize().width() - 2 * doc->documentMargin()) * maxWidth.value(100) / 100;
611 effectiveMaxWidth = maxWidth.rawValue();
614 width = qMin(effectiveMaxWidth, width);
617 QSizeF size(width, height);
618 if (!hasWidth || !hasHeight) {
619 QVariant res = doc->resource(QTextDocument::ImageResource, QUrl(imageFormat.name()));
620 QImage image = res.value<QImage>();
621 if (image.isNull()) {
630 QSize imgSize = image.size();
631 if (imgSize.width() > effectiveMaxWidth) {
633 imgSize.setHeight(effectiveMaxWidth * imgSize.height() / (qreal) imgSize.width());
634 imgSize.setWidth(effectiveMaxWidth);
639 size.setWidth(imgSize.width());
641 size.setWidth(qMin(effectiveMaxWidth, qRound(height * (imgSize.width() / (qreal) imgSize.height()))));
645 size.setHeight(imgSize.height());
647 size.setHeight(qRound(width * (imgSize.height() / (qreal) imgSize.width())));
QTextDocument * document() const
void setStatus(QQuickTextDocument::Status s, const QString &err)
void setDocument(QTextDocument *doc)
void writeTo(const QUrl &fileUrl)
QSizeF intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format) override
The intrinsicSize() function returns the size of the text object represented by format in the given d...