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 setStatus(QQuickTextDocument::Status::Loaded, {});
357 qCDebug(lcTextDoc) << editor <<
"loaded" << filePath
358 <<
"as" << editor->textFormat() <<
"detected" << detectedFormat
359#if QT_CONFIG(mimetype)
360 <<
"(file type" << mimeType <<
')'
363 doc->setModified(
false);
366 setStatus(QQuickTextDocument::Status::ReadError,
367 QQuickTextDocument::tr(
"Failed to read: %1").arg(file.errorString()));
369 setStatus(QQuickTextDocument::Status::ReadError,
370 QQuickTextDocument::tr(
"%1 does not exist").arg(filePath));
376 auto *doc =
editor->document();
380 const QString filePath = fileUrl.toLocalFile();
381 const bool sameUrl = fileUrl == url;
383#if QT_CONFIG(mimetype)
384 const auto type = QMimeDatabase().mimeTypeForUrl(fileUrl);
385 if (type.inherits(
"text/html"_L1))
386 detectedFormat = Qt::RichText;
387 else if (type.inherits(
"text/markdown"_L1))
388 detectedFormat = Qt::MarkdownText;
390 detectedFormat = Qt::PlainText;
392 if (filePath.endsWith(
".html"_L1, Qt::CaseInsensitive) ||
393 filePath.endsWith(
".htm"_L1, Qt::CaseInsensitive))
394 detectedFormat = Qt::RichText;
395 else if (filePath.endsWith(
".md"_L1, Qt::CaseInsensitive) ||
396 filePath.endsWith(
".markdown"_L1, Qt::CaseInsensitive))
397 detectedFormat = Qt::MarkdownText;
399 detectedFormat = Qt::PlainText;
402 QFile file(filePath);
403 if (!file.open(QFile::WriteOnly | QFile::Truncate |
404 (detectedFormat == Qt::RichText ? QFile::NotOpen : QFile::Text))) {
405 setStatus(QQuickTextDocument::Status::WriteError,
406 QQuickTextDocument::tr(
"Cannot save: %1").arg(file.errorString()));
409 setStatus(QQuickTextDocument::Status::Saving, {});
412 switch (detectedFormat) {
413#if QT_CONFIG(textmarkdownwriter)
414 case Qt::MarkdownText:
415 raw = doc->toMarkdown().toUtf8();
418#if QT_CONFIG(texthtmlparser)
420 if (sameUrl && encoding) {
421 QStringEncoder enc(*encoding);
422 raw = enc.encode(doc->toHtml());
425 raw = doc->toHtml().toUtf8();
430 raw = doc->toPlainText().toUtf8();
436 setStatus(QQuickTextDocument::Status::Saved, {});
437 doc->setModified(
false);
590 QTextDocument *doc,
int,
const QTextFormat &format)
592 if (format.isImageFormat()) {
593 QTextImageFormat imageFormat = format.toImageFormat();
594 int width = qRound(imageFormat.width());
595 const bool hasWidth = imageFormat.hasProperty(QTextFormat::ImageWidth) && width > 0;
596 const int height = qRound(imageFormat.height());
597 const bool hasHeight = imageFormat.hasProperty(QTextFormat::ImageHeight) && height > 0;
598 const auto maxWidth = imageFormat.maximumWidth();
599 const bool hasMaxWidth = imageFormat.hasProperty(QTextFormat::ImageMaxWidth) && maxWidth.type() != QTextLength::VariableLength;
601 int effectiveMaxWidth = INT_MAX;
603 if (maxWidth.type() == QTextLength::PercentageLength) {
604 effectiveMaxWidth = (doc->pageSize().width() - 2 * doc->documentMargin()) * maxWidth.value(100) / 100;
606 effectiveMaxWidth = maxWidth.rawValue();
609 width = qMin(effectiveMaxWidth, width);
612 QSizeF size(width, height);
613 if (!hasWidth || !hasHeight) {
614 QVariant res = doc->resource(QTextDocument::ImageResource, QUrl(imageFormat.name()));
615 QImage image = res.value<QImage>();
616 if (image.isNull()) {
625 QSize imgSize = image.size();
626 if (imgSize.width() > effectiveMaxWidth) {
628 imgSize.setHeight(effectiveMaxWidth * imgSize.height() / (qreal) imgSize.width());
629 imgSize.setWidth(effectiveMaxWidth);
634 size.setWidth(imgSize.width());
636 size.setWidth(qMin(effectiveMaxWidth, qRound(height * (imgSize.width() / (qreal) imgSize.height()))));
640 size.setHeight(imgSize.height());
642 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...