summaryrefslogtreecommitdiffstats
path: root/src/widgets/widgets/qwidgettextcontrol.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/widgets/qwidgettextcontrol.cpp')
-rw-r--r--src/widgets/widgets/qwidgettextcontrol.cpp497
1 files changed, 312 insertions, 185 deletions
diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp
index ee757bf870..6dcaeee0c8 100644
--- a/src/widgets/widgets/qwidgettextcontrol.cpp
+++ b/src/widgets/widgets/qwidgettextcontrol.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwidgettextcontrol_p.h"
#include "qwidgettextcontrol_p_p.h"
@@ -50,18 +14,17 @@
#include <qdrag.h>
#endif
#include <qclipboard.h>
-#if QT_CONFIG(menu)
-#include <qmenu.h>
-#endif
#include <qstyle.h>
#include <qtimer.h>
+#include "private/qapplication_p.h"
#include "private/qtextdocumentlayout_p.h"
#include "private/qabstracttextdocumentlayout_p.h"
-#if QT_CONFIG(textedit)
-#include "private/qtextedit_p.h"
+#if QT_CONFIG(menu)
+#include "private/qmenu_p.h"
#endif
#include "qtextdocument.h"
#include "private/qtextdocument_p.h"
+#include "private/qtextdocumentfragment_p.h"
#include "qtextlist.h"
#include "private/qwidgettextcontrol_p.h"
#if QT_CONFIG(style_stylesheet)
@@ -86,7 +49,9 @@
#include <qurl.h>
#include <qdesktopservices.h>
#include <qinputmethod.h>
+#if QT_CONFIG(tooltip)
#include <qtooltip.h>
+#endif
#include <qstyleoption.h>
#if QT_CONFIG(lineedit)
#include <QtWidgets/qlineedit.h>
@@ -94,14 +59,13 @@
#include <QtGui/qaccessible.h>
#include <QtCore/qmetaobject.h>
-#ifndef QT_NO_SHORTCUT
+#if QT_CONFIG(shortcut)
#include "private/qapplication_p.h"
#include "private/qshortcutmap_p.h"
#include <qkeysequence.h>
-#define ACCEL_KEY(k) ((!QCoreApplication::testAttribute(Qt::AA_DontShowShortcutsInContextMenus) \
- && QGuiApplication::styleHints()->showShortcutsInContextMenus()) \
- && !qApp->d_func()->shortcutMap.hasShortcutForKeySequence(k) ? \
- QLatin1Char('\t') + QKeySequence(k).toString(QKeySequence::NativeText) : QString())
+#define ACCEL_KEY(k) (!QCoreApplication::testAttribute(Qt::AA_DontShowShortcutsInContextMenus) \
+ && !QGuiApplicationPrivate::instance()->shortcutMap.hasShortcutForKeySequence(k) ? \
+ u'\t' + QKeySequence(k).toString(QKeySequence::NativeText) : QString())
#else
#define ACCEL_KEY(k) QString()
@@ -111,6 +75,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
// could go into QTextCursor...
static QTextLine currentTextLine(const QTextCursor &cursor)
{
@@ -127,7 +93,7 @@ static QTextLine currentTextLine(const QTextCursor &cursor)
}
QWidgetTextControlPrivate::QWidgetTextControlPrivate()
- : doc(0), cursorOn(false), cursorVisible(false), cursorIsFocusIndicator(false),
+ : doc(nullptr), cursorOn(false), cursorVisible(false), cursorIsFocusIndicator(false),
#ifndef Q_OS_ANDROID
interactionFlags(Qt::TextEditorInteraction),
#else
@@ -221,6 +187,14 @@ bool QWidgetTextControlPrivate::cursorMoveKeyEvent(QKeyEvent *e)
else if (e == QKeySequence::SelectPreviousLine) {
op = QTextCursor::Up;
mode = QTextCursor::KeepAnchor;
+ {
+ QTextBlock block = cursor.block();
+ QTextLine line = currentTextLine(cursor);
+ if (!block.previous().isValid()
+ && line.isValid()
+ && line.lineNumber() == 0)
+ op = QTextCursor::Start;
+ }
}
else if (e == QKeySequence::SelectNextLine) {
op = QTextCursor::Down;
@@ -289,7 +263,7 @@ bool QWidgetTextControlPrivate::cursorMoveKeyEvent(QKeyEvent *e)
bool isNavigationEvent = e->key() == Qt::Key_Up || e->key() == Qt::Key_Down;
#ifdef QT_KEYPAD_NAVIGATION
- ignoreNavigationEvents = ignoreNavigationEvents || QApplication::keypadNavigationEnabled();
+ ignoreNavigationEvents = ignoreNavigationEvents || QApplicationPrivate::keypadNavigationEnabled();
isNavigationEvent = isNavigationEvent ||
(QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
&& (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right));
@@ -439,25 +413,30 @@ void QWidgetTextControlPrivate::setContent(Qt::TextFormat format, const QString
if (!doc) {
if (document) {
doc = document;
- clearDocument = false;
} else {
palette = QApplication::palette("QWidgetTextControl");
doc = new QTextDocument(q);
}
+ clearDocument = false;
_q_documentLayoutChanged();
cursor = QTextCursor(doc);
// #### doc->documentLayout()->setPaintDevice(viewport);
- QObject::connect(doc, SIGNAL(contentsChanged()), q, SLOT(_q_updateCurrentCharFormatAndSelection()));
- QObject::connect(doc, SIGNAL(cursorPositionChanged(QTextCursor)), q, SLOT(_q_emitCursorPosChanged(QTextCursor)));
- QObject::connect(doc, SIGNAL(documentLayoutChanged()), q, SLOT(_q_documentLayoutChanged()));
+ QObjectPrivate::connect(doc, &QTextDocument::contentsChanged, this,
+ &QWidgetTextControlPrivate::_q_updateCurrentCharFormatAndSelection);
+ QObjectPrivate::connect(doc, &QTextDocument::cursorPositionChanged, this,
+ &QWidgetTextControlPrivate::_q_emitCursorPosChanged);
+ QObjectPrivate::connect(doc, &QTextDocument::documentLayoutChanged, this,
+ &QWidgetTextControlPrivate::_q_documentLayoutChanged);
// convenience signal forwards
- QObject::connect(doc, SIGNAL(undoAvailable(bool)), q, SIGNAL(undoAvailable(bool)));
- QObject::connect(doc, SIGNAL(redoAvailable(bool)), q, SIGNAL(redoAvailable(bool)));
- QObject::connect(doc, SIGNAL(modificationChanged(bool)), q, SIGNAL(modificationChanged(bool)));
- QObject::connect(doc, SIGNAL(blockCountChanged(int)), q, SIGNAL(blockCountChanged(int)));
+ QObject::connect(doc, &QTextDocument::undoAvailable, q, &QWidgetTextControl::undoAvailable);
+ QObject::connect(doc, &QTextDocument::redoAvailable, q, &QWidgetTextControl::redoAvailable);
+ QObject::connect(doc, &QTextDocument::modificationChanged, q,
+ &QWidgetTextControl::modificationChanged);
+ QObject::connect(doc, &QTextDocument::blockCountChanged, q,
+ &QWidgetTextControl::blockCountChanged);
}
bool previousUndoRedoState = doc->isUndoRedoEnabled();
@@ -489,6 +468,11 @@ void QWidgetTextControlPrivate::setContent(Qt::TextFormat format, const QString
formatCursor.select(QTextCursor::Document);
formatCursor.setCharFormat(charFormatForInsertion);
formatCursor.endEditBlock();
+#if QT_CONFIG(textmarkdownreader)
+ } else if (format == Qt::MarkdownText) {
+ doc->setMarkdown(text);
+ doc->setUndoRedoEnabled(false);
+#endif
} else {
#ifndef QT_NO_TEXTHTMLPARSER
doc->setHtml(text);
@@ -514,7 +498,8 @@ void QWidgetTextControlPrivate::setContent(Qt::TextFormat format, const QString
q->ensureCursorVisible();
emit q->cursorPositionChanged();
- QObject::connect(doc, SIGNAL(contentsChange(int,int,int)), q, SLOT(_q_contentsChanged(int,int,int)), Qt::UniqueConnection);
+ QObjectPrivate::connect(doc, &QTextDocument::contentsChange, this,
+ &QWidgetTextControlPrivate::_q_contentsChanged, Qt::UniqueConnection);
}
void QWidgetTextControlPrivate::startDrag()
@@ -594,7 +579,7 @@ void QWidgetTextControlPrivate::selectionChanged(bool forceEmitSelectionChanged
Q_Q(QWidgetTextControl);
if (forceEmitSelectionChanged) {
emit q->selectionChanged();
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
if (q->parent() && q->parent()->isWidgetType()) {
QAccessibleTextSelectionEvent ev(q->parent(), cursor.anchor(), cursor.position());
QAccessible::updateAccessibility(&ev);
@@ -617,7 +602,7 @@ void QWidgetTextControlPrivate::selectionChanged(bool forceEmitSelectionChanged
&& (cursor.position() != lastSelectionPosition
|| cursor.anchor() != lastSelectionAnchor)))) {
emit q->selectionChanged();
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
if (q->parent() && q->parent()->isWidgetType()) {
QAccessibleTextSelectionEvent ev(q->parent(), cursor.anchor(), cursor.position());
QAccessible::updateAccessibility(&ev);
@@ -638,7 +623,7 @@ void QWidgetTextControlPrivate::_q_updateCurrentCharFormatAndSelection()
#ifndef QT_NO_CLIPBOARD
void QWidgetTextControlPrivate::setClipboardSelection()
{
- QClipboard *clipboard = QApplication::clipboard();
+ QClipboard *clipboard = QGuiApplication::clipboard();
if (!cursor.hasSelection() || !clipboard->supportsSelection())
return;
Q_Q(QWidgetTextControl);
@@ -658,7 +643,7 @@ void QWidgetTextControlPrivate::_q_emitCursorPosChanged(const QTextCursor &someC
void QWidgetTextControlPrivate::_q_contentsChanged(int from, int charsRemoved, int charsAdded)
{
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
Q_Q(QWidgetTextControl);
if (QAccessible::isActive() && q->parent() && q->parent()->isWidgetType()) {
@@ -670,9 +655,9 @@ void QWidgetTextControlPrivate::_q_contentsChanged(int from, int charsRemoved, i
QString newText = tmp.selectedText();
// always report the right number of removed chars, but in lack of the real string use spaces
- QString oldText = QString(charsRemoved, QLatin1Char(' '));
+ QString oldText = QString(charsRemoved, u' ');
- QAccessibleEvent *ev = 0;
+ QAccessibleEvent *ev = nullptr;
if (charsRemoved == 0) {
ev = new QAccessibleTextInsertEvent(q->parent(), from, newText);
} else if (charsAdded == 0) {
@@ -684,9 +669,9 @@ void QWidgetTextControlPrivate::_q_contentsChanged(int from, int charsRemoved, i
delete ev;
}
#else
- Q_UNUSED(from)
- Q_UNUSED(charsRemoved)
- Q_UNUSED(charsAdded)
+ Q_UNUSED(from);
+ Q_UNUSED(charsRemoved);
+ Q_UNUSED(charsAdded);
#endif
}
@@ -694,10 +679,12 @@ void QWidgetTextControlPrivate::_q_documentLayoutChanged()
{
Q_Q(QWidgetTextControl);
QAbstractTextDocumentLayout *layout = doc->documentLayout();
- QObject::connect(layout, SIGNAL(update(QRectF)), q, SIGNAL(updateRequest(QRectF)));
- QObject::connect(layout, SIGNAL(updateBlock(QTextBlock)), q, SLOT(_q_updateBlock(QTextBlock)));
- QObject::connect(layout, SIGNAL(documentSizeChanged(QSizeF)), q, SIGNAL(documentSizeChanged(QSizeF)));
-
+ QObject::connect(layout, &QAbstractTextDocumentLayout::update, q,
+ &QWidgetTextControl::updateRequest);
+ QObjectPrivate::connect(layout, &QAbstractTextDocumentLayout::updateBlock, this,
+ &QWidgetTextControlPrivate::_q_updateBlock);
+ QObject::connect(layout, &QAbstractTextDocumentLayout::documentSizeChanged, q,
+ &QWidgetTextControl::documentSizeChanged);
}
void QWidgetTextControlPrivate::setCursorVisible(bool visible)
@@ -709,9 +696,9 @@ void QWidgetTextControlPrivate::setCursorVisible(bool visible)
updateCursorBlinking();
if (cursorVisible)
- connect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged, this, &QWidgetTextControlPrivate::updateCursorBlinking);
+ connect(QGuiApplication::styleHints(), &QStyleHints::cursorFlashTimeChanged, this, &QWidgetTextControlPrivate::updateCursorBlinking);
else
- disconnect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged, this, &QWidgetTextControlPrivate::updateCursorBlinking);
+ disconnect(QGuiApplication::styleHints(), &QStyleHints::cursorFlashTimeChanged, this, &QWidgetTextControlPrivate::updateCursorBlinking);
}
void QWidgetTextControlPrivate::updateCursorBlinking()
@@ -895,12 +882,12 @@ void QWidgetTextControl::setDocument(QTextDocument *document)
d->doc->disconnect(this);
d->doc->documentLayout()->disconnect(this);
- d->doc->documentLayout()->setPaintDevice(0);
+ d->doc->documentLayout()->setPaintDevice(nullptr);
if (d->doc->parent() == this)
delete d->doc;
- d->doc = 0;
+ d->doc = nullptr;
d->setContent(Qt::RichText, QString(), document);
}
@@ -910,7 +897,7 @@ QTextDocument *QWidgetTextControl::document() const
return d->doc;
}
-void QWidgetTextControl::setTextCursor(const QTextCursor &cursor)
+void QWidgetTextControl::setTextCursor(const QTextCursor &cursor, bool selectionClipboard)
{
Q_D(QWidgetTextControl);
d->cursorIsFocusIndicator = false;
@@ -924,6 +911,13 @@ void QWidgetTextControl::setTextCursor(const QTextCursor &cursor)
d->repaintOldAndNewSelection(oldSelection);
if (posChanged)
emit cursorPositionChanged();
+
+#ifndef QT_NO_CLIPBOARD
+ if (selectionClipboard)
+ d->setClipboardSelection();
+#else
+ Q_UNUSED(selectionClipboard);
+#endif
}
QTextCursor QWidgetTextControl::textCursor() const
@@ -949,12 +943,12 @@ void QWidgetTextControl::copy()
if (!d->cursor.hasSelection())
return;
QMimeData *data = createMimeDataFromSelection();
- QApplication::clipboard()->setMimeData(data);
+ QGuiApplication::clipboard()->setMimeData(data);
}
void QWidgetTextControl::paste(QClipboard::Mode mode)
{
- const QMimeData *md = QApplication::clipboard()->mimeData(mode);
+ const QMimeData *md = QGuiApplication::clipboard()->mimeData(mode);
if (md)
insertFromMimeData(md);
}
@@ -973,20 +967,23 @@ void QWidgetTextControl::selectAll()
{
Q_D(QWidgetTextControl);
const int selectionLength = qAbs(d->cursor.position() - d->cursor.anchor());
+ const int oldCursorPos = d->cursor.position();
d->cursor.select(QTextCursor::Document);
d->selectionChanged(selectionLength != qAbs(d->cursor.position() - d->cursor.anchor()));
d->cursorIsFocusIndicator = false;
+ if (d->cursor.position() != oldCursorPos)
+ emit cursorPositionChanged();
emit updateRequest();
}
void QWidgetTextControl::processEvent(QEvent *e, const QPointF &coordinateOffset, QWidget *contextWidget)
{
- QMatrix m;
- m.translate(coordinateOffset.x(), coordinateOffset.y());
- processEvent(e, m, contextWidget);
+ QTransform t;
+ t.translate(coordinateOffset.x(), coordinateOffset.y());
+ processEvent(e, t, contextWidget);
}
-void QWidgetTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget *contextWidget)
+void QWidgetTextControl::processEvent(QEvent *e, const QTransform &transform, QWidget *contextWidget)
{
Q_D(QWidgetTextControl);
if (d->interactionFlags == Qt::NoTextInteraction) {
@@ -1027,23 +1024,23 @@ void QWidgetTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget
break;
case QEvent::MouseButtonPress: {
QMouseEvent *ev = static_cast<QMouseEvent *>(e);
- d->mousePressEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
- ev->buttons(), ev->globalPos());
+ d->mousePressEvent(ev, ev->button(), transform.map(ev->position().toPoint()), ev->modifiers(),
+ ev->buttons(), ev->globalPosition().toPoint());
break; }
case QEvent::MouseMove: {
QMouseEvent *ev = static_cast<QMouseEvent *>(e);
- d->mouseMoveEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
- ev->buttons(), ev->globalPos());
+ d->mouseMoveEvent(ev, ev->button(), transform.map(ev->position().toPoint()), ev->modifiers(),
+ ev->buttons(), ev->globalPosition().toPoint());
break; }
case QEvent::MouseButtonRelease: {
QMouseEvent *ev = static_cast<QMouseEvent *>(e);
- d->mouseReleaseEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
- ev->buttons(), ev->globalPos());
+ d->mouseReleaseEvent(ev, ev->button(), transform.map(ev->position().toPoint()), ev->modifiers(),
+ ev->buttons(), ev->globalPosition().toPoint());
break; }
case QEvent::MouseButtonDblClick: {
QMouseEvent *ev = static_cast<QMouseEvent *>(e);
- d->mouseDoubleClickEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
- ev->buttons(), ev->globalPos());
+ d->mouseDoubleClickEvent(ev, ev->button(), transform.map(ev->position().toPoint()), ev->modifiers(),
+ ev->buttons(), ev->globalPosition().toPoint());
break; }
case QEvent::InputMethod:
d->inputMethodEvent(static_cast<QInputMethodEvent *>(e));
@@ -1051,7 +1048,7 @@ void QWidgetTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget
#ifndef QT_NO_CONTEXTMENU
case QEvent::ContextMenu: {
QContextMenuEvent *ev = static_cast<QContextMenuEvent *>(e);
- d->contextMenuEvent(ev->globalPos(), matrix.map(ev->pos()), contextWidget);
+ d->contextMenuEvent(ev->globalPos(), transform.map(ev->pos()), contextWidget);
break; }
#endif // QT_NO_CONTEXTMENU
case QEvent::FocusIn:
@@ -1063,13 +1060,13 @@ void QWidgetTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget
d->isEnabled = e->isAccepted();
break;
-#ifndef QT_NO_TOOLTIP
+#if QT_CONFIG(tooltip)
case QEvent::ToolTip: {
QHelpEvent *ev = static_cast<QHelpEvent *>(e);
- d->showToolTip(ev->globalPos(), matrix.map(ev->pos()), contextWidget);
+ d->showToolTip(ev->globalPos(), transform.map(ev->pos()), contextWidget);
break;
}
-#endif // QT_NO_TOOLTIP
+#endif // QT_CONFIG(tooltip)
#if QT_CONFIG(draganddrop)
case QEvent::DragEnter: {
@@ -1083,13 +1080,13 @@ void QWidgetTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget
break;
case QEvent::DragMove: {
QDragMoveEvent *ev = static_cast<QDragMoveEvent *>(e);
- if (d->dragMoveEvent(e, ev->mimeData(), matrix.map(ev->pos())))
+ if (d->dragMoveEvent(e, ev->mimeData(), transform.map(ev->position().toPoint())))
ev->acceptProposedAction();
break;
}
case QEvent::Drop: {
QDropEvent *ev = static_cast<QDropEvent *>(e);
- if (d->dropEvent(ev->mimeData(), matrix.map(ev->pos()), ev->dropAction(), ev->source()))
+ if (d->dropEvent(ev->mimeData(), transform.map(ev->position().toPoint()), ev->dropAction(), ev->source()))
ev->acceptProposedAction();
break;
}
@@ -1098,32 +1095,32 @@ void QWidgetTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget
#if QT_CONFIG(graphicsview)
case QEvent::GraphicsSceneMousePress: {
QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
- d->mousePressEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
+ d->mousePressEvent(ev, ev->button(), transform.map(ev->pos()), ev->modifiers(), ev->buttons(),
ev->screenPos());
break; }
case QEvent::GraphicsSceneMouseMove: {
QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
- d->mouseMoveEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
+ d->mouseMoveEvent(ev, ev->button(), transform.map(ev->pos()), ev->modifiers(), ev->buttons(),
ev->screenPos());
break; }
case QEvent::GraphicsSceneMouseRelease: {
QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
- d->mouseReleaseEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
+ d->mouseReleaseEvent(ev, ev->button(), transform.map(ev->pos()), ev->modifiers(), ev->buttons(),
ev->screenPos());
break; }
case QEvent::GraphicsSceneMouseDoubleClick: {
QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
- d->mouseDoubleClickEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
+ d->mouseDoubleClickEvent(ev, ev->button(), transform.map(ev->pos()), ev->modifiers(), ev->buttons(),
ev->screenPos());
break; }
case QEvent::GraphicsSceneContextMenu: {
QGraphicsSceneContextMenuEvent *ev = static_cast<QGraphicsSceneContextMenuEvent *>(e);
- d->contextMenuEvent(ev->screenPos(), matrix.map(ev->pos()), contextWidget);
+ d->contextMenuEvent(ev->screenPos(), transform.map(ev->pos()), contextWidget);
break; }
case QEvent::GraphicsSceneHoverMove: {
QGraphicsSceneHoverEvent *ev = static_cast<QGraphicsSceneHoverEvent *>(e);
- d->mouseMoveEvent(ev, Qt::NoButton, matrix.map(ev->pos()), ev->modifiers(),Qt::NoButton,
+ d->mouseMoveEvent(ev, Qt::NoButton, transform.map(ev->pos()), ev->modifiers(),Qt::NoButton,
ev->screenPos());
break; }
@@ -1137,19 +1134,19 @@ void QWidgetTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget
break;
case QEvent::GraphicsSceneDragMove: {
QGraphicsSceneDragDropEvent *ev = static_cast<QGraphicsSceneDragDropEvent *>(e);
- if (d->dragMoveEvent(e, ev->mimeData(), matrix.map(ev->pos())))
+ if (d->dragMoveEvent(e, ev->mimeData(), transform.map(ev->pos())))
ev->acceptProposedAction();
break; }
case QEvent::GraphicsSceneDrop: {
QGraphicsSceneDragDropEvent *ev = static_cast<QGraphicsSceneDragDropEvent *>(e);
- if (d->dropEvent(ev->mimeData(), matrix.map(ev->pos()), ev->dropAction(), ev->source()))
+ if (d->dropEvent(ev->mimeData(), transform.map(ev->pos()), ev->dropAction(), ev->source()))
ev->accept();
break; }
#endif // QT_CONFIG(graphicsview)
#ifdef QT_KEYPAD_NAVIGATION
case QEvent::EnterEditFocus:
case QEvent::LeaveEditFocus:
- if (QApplication::keypadNavigationEnabled())
+ if (QApplicationPrivate::keypadNavigationEnabled())
d->editFocusEvent(e);
break;
#endif
@@ -1192,6 +1189,14 @@ void QWidgetTextControl::setPlainText(const QString &text)
d->setContent(Qt::PlainText, text);
}
+#if QT_CONFIG(textmarkdownreader)
+void QWidgetTextControl::setMarkdown(const QString &text)
+{
+ Q_D(QWidgetTextControl);
+ d->setContent(Qt::MarkdownText, text);
+}
+#endif
+
void QWidgetTextControl::setHtml(const QString &text)
{
Q_D(QWidgetTextControl);
@@ -1205,6 +1210,9 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e)
if (e == QKeySequence::SelectAll) {
e->accept();
q->selectAll();
+#ifndef QT_NO_CLIPBOARD
+ setClipboardSelection();
+#endif
return;
}
#ifndef QT_NO_CLIPBOARD
@@ -1253,7 +1261,7 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e)
// example)
repaintSelection();
- if (e->key() == Qt::Key_Backspace && !(e->modifiers() & ~Qt::ShiftModifier)) {
+ if (e->key() == Qt::Key_Backspace && !(e->modifiers() & ~(Qt::ShiftModifier | Qt::GroupSwitchModifier))) {
QTextBlockFormat blockFmt = cursor.blockFormat();
QTextList *list = cursor.currentList();
if (list && cursor.atBlockStart() && !cursor.hasSelection()) {
@@ -1264,12 +1272,14 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e)
} else {
QTextCursor localCursor = cursor;
localCursor.deletePreviousChar();
+ if (cursor.d)
+ cursor.d->setX();
}
goto accept;
}
#ifndef QT_NO_SHORTCUT
else if (e == QKeySequence::InsertParagraphSeparator) {
- cursor.insertBlock();
+ insertParagraphSeparator();
e->accept();
goto accept;
} else if (e == QKeySequence::InsertLineSeparator) {
@@ -1303,9 +1313,13 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e)
else if (e == QKeySequence::Delete) {
QTextCursor localCursor = cursor;
localCursor.deleteChar();
+ if (cursor.d)
+ cursor.d->setX();
} else if (e == QKeySequence::Backspace) {
QTextCursor localCursor = cursor;
localCursor.deletePreviousChar();
+ if (cursor.d)
+ cursor.d->setX();
}else if (e == QKeySequence::DeleteEndOfWord) {
if (!cursor.hasSelection())
cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor);
@@ -1350,6 +1364,10 @@ process:
accept:
+#ifndef QT_NO_CLIPBOARD
+ setClipboardSelection();
+#endif
+
e->accept();
cursorOn = true;
@@ -1360,15 +1378,8 @@ process:
QVariant QWidgetTextControl::loadResource(int type, const QUrl &name)
{
-#if !QT_CONFIG(textedit)
Q_UNUSED(type);
Q_UNUSED(name);
-#else
- if (QTextEdit *textEdit = qobject_cast<QTextEdit *>(parent())) {
- QUrl resolvedName = textEdit->d_func()->resolveUrl(name);
- return textEdit->loadResource(type, resolvedName);
- }
-#endif
return QVariant();
}
@@ -1395,16 +1406,14 @@ QRectF QWidgetTextControlPrivate::rectForPosition(int position) const
if (relativePos == preeditPos)
relativePos += preeditCursor;
else if (relativePos > preeditPos)
- relativePos += layout->preeditAreaText().length();
+ relativePos += layout->preeditAreaText().size();
}
QTextLine line = layout->lineForTextPosition(relativePos);
int cursorWidth;
{
bool ok = false;
-#ifndef QT_NO_PROPERTIES
cursorWidth = docLayout->property("cursorWidth").toInt(&ok);
-#endif
if (!ok)
cursorWidth = 1;
}
@@ -1418,7 +1427,7 @@ QRectF QWidgetTextControlPrivate::rectForPosition(int position) const
if (relativePos < line.textLength() - line.textStart())
w = line.cursorToX(relativePos + 1) - x;
else
- w = QFontMetrics(block.layout()->font()).horizontalAdvance(QLatin1Char(' ')); // in sync with QTextLine::draw()
+ w = QFontMetrics(block.layout()->font()).horizontalAdvance(u' '); // in sync with QTextLine::draw()
}
r = QRectF(layoutPos.x() + x, layoutPos.y() + line.y(),
cursorWidth + w, line.height());
@@ -1573,6 +1582,11 @@ void QWidgetTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton butto
e->ignore();
return;
}
+ bool wasValid = blockWithMarkerUnderMouse.isValid();
+ blockWithMarkerUnderMouse = q->blockWithMarkerAt(pos);
+ if (wasValid != blockWithMarkerUnderMouse.isValid())
+ emit q->blockMarkerHovered(blockWithMarkerUnderMouse);
+
cursorIsFocusIndicator = false;
const QTextCursor oldSelection = cursor;
@@ -1591,6 +1605,8 @@ void QWidgetTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton butto
selectedBlockOnTrippleClick = cursor;
anchorOnMousePress = QString();
+ blockWithMarkerUnderMouse = QTextBlock();
+ emit q->blockMarkerHovered(blockWithMarkerUnderMouse);
trippleClickTimer.stop();
} else {
@@ -1730,6 +1746,11 @@ void QWidgetTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button
}
selectionChanged(true);
repaintOldAndNewSelection(oldSelection);
+ } else {
+ bool wasValid = blockWithMarkerUnderMouse.isValid();
+ blockWithMarkerUnderMouse = q->blockWithMarkerAt(mousePos);
+ if (wasValid != blockWithMarkerUnderMouse.isValid())
+ emit q->blockMarkerHovered(blockWithMarkerUnderMouse);
}
sendMouseEventToInputContext(e, QEvent::MouseMove, button, mousePos, modifiers, buttons, globalPos);
@@ -1762,11 +1783,11 @@ void QWidgetTextControlPrivate::mouseReleaseEvent(QEvent *e, Qt::MouseButton but
#ifndef QT_NO_CLIPBOARD
setClipboardSelection();
selectionChanged(true);
- } else if (button == Qt::MidButton
+ } else if (button == Qt::MiddleButton
&& (interactionFlags & Qt::TextEditable)
- && QApplication::clipboard()->supportsSelection()) {
+ && QGuiApplication::clipboard()->supportsSelection()) {
setCursorPosition(pos);
- const QMimeData *md = QApplication::clipboard()->mimeData(QClipboard::Selection);
+ const QMimeData *md = QGuiApplication::clipboard()->mimeData(QClipboard::Selection);
if (md)
q->insertFromMimeData(md);
#endif
@@ -1779,26 +1800,57 @@ void QWidgetTextControlPrivate::mouseReleaseEvent(QEvent *e, Qt::MouseButton but
emit q->microFocusChanged();
}
+ // toggle any checkbox that the user clicks
+ if ((interactionFlags & Qt::TextEditable) && (button & Qt::LeftButton) &&
+ (blockWithMarkerUnderMouse.isValid()) && !cursor.hasSelection()) {
+ QTextBlock markerBlock = q->blockWithMarkerAt(pos);
+ if (markerBlock == blockWithMarkerUnderMouse) {
+ auto fmt = blockWithMarkerUnderMouse.blockFormat();
+ switch (fmt.marker()) {
+ case QTextBlockFormat::MarkerType::Unchecked :
+ fmt.setMarker(QTextBlockFormat::MarkerType::Checked);
+ break;
+ case QTextBlockFormat::MarkerType::Checked:
+ fmt.setMarker(QTextBlockFormat::MarkerType::Unchecked);
+ break;
+ default:
+ break;
+ }
+ cursor.setBlockFormat(fmt);
+ }
+ }
+
if (interactionFlags & Qt::LinksAccessibleByMouse) {
- if (!(button & Qt::LeftButton))
+
+ // Ignore event unless left button has been pressed
+ if (!(button & Qt::LeftButton)) {
+ e->ignore();
return;
+ }
const QString anchor = q->anchorAt(pos);
- if (anchor.isEmpty())
+ // Ignore event without selection anchor
+ if (anchor.isEmpty()) {
+ e->ignore();
return;
+ }
if (!cursor.hasSelection()
|| (anchor == anchorOnMousePress && hadSelectionOnMousePress)) {
const int anchorPos = q->hitTest(pos, Qt::ExactHit);
- if (anchorPos != -1) {
- cursor.setPosition(anchorPos);
- QString anchor = anchorOnMousePress;
- anchorOnMousePress = QString();
- activateLinkUnderCursor(anchor);
+ // Ignore event without valid anchor position
+ if (anchorPos < 0) {
+ e->ignore();
+ return;
}
+
+ cursor.setPosition(anchorPos);
+ QString anchor = anchorOnMousePress;
+ anchorOnMousePress = QString();
+ activateLinkUnderCursor(anchor);
}
}
}
@@ -1862,7 +1914,7 @@ bool QWidgetTextControlPrivate::sendMouseEventToInputContext(
QTextLayout *layout = cursor.block().layout();
int cursorPos = q->hitTest(pos, Qt::FuzzyHit) - cursor.position();
- if (cursorPos < 0 || cursorPos > layout->preeditAreaText().length())
+ if (cursorPos < 0 || cursorPos > layout->preeditAreaText().size())
cursorPos = -1;
if (cursorPos >= 0) {
@@ -1891,6 +1943,12 @@ void QWidgetTextControlPrivate::contextMenuEvent(const QPoint &screenPos, const
if (!menu)
return;
menu->setAttribute(Qt::WA_DeleteOnClose);
+
+ if (auto *widget = qobject_cast<QWidget *>(parent)) {
+ if (auto *window = widget->window()->windowHandle())
+ QMenuPrivate::get(menu)->topData()->initialScreen = window->screen();
+ }
+
menu->popup(screenPos);
#endif
}
@@ -1969,7 +2027,7 @@ bool QWidgetTextControlPrivate::dropEvent(const QMimeData *mimeData, const QPoin
void QWidgetTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
{
Q_Q(QWidgetTextControl);
- if (!(interactionFlags & Qt::TextEditable) || cursor.isNull()) {
+ if (!(interactionFlags & (Qt::TextEditable | Qt::TextSelectableByMouse)) || cursor.isNull()) {
e->ignore();
return;
}
@@ -1977,6 +2035,11 @@ void QWidgetTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
|| e->preeditString() != cursor.block().layout()->preeditAreaText()
|| e->replacementLength() > 0;
+ if (!isGettingInput && e->attributes().isEmpty()) {
+ e->ignore();
+ return;
+ }
+
int oldCursorPos = cursor.position();
cursor.beginEditBlock();
@@ -2013,10 +2076,10 @@ void QWidgetTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
QTextLayout *layout = block.layout();
if (isGettingInput)
layout->setPreeditArea(cursor.position() - block.position(), e->preeditString());
- QVector<QTextLayout::FormatRange> overrides;
+ QList<QTextLayout::FormatRange> overrides;
overrides.reserve(e->attributes().size());
const int oldPreeditCursor = preeditCursor;
- preeditCursor = e->preeditString().length();
+ preeditCursor = e->preeditString().size();
hideCursor = false;
for (int i = 0; i < e->attributes().size(); ++i) {
const QInputMethodEvent::Attribute &a = e->attributes().at(i);
@@ -2033,9 +2096,9 @@ void QWidgetTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
o.format = f;
// Make sure list is sorted by start index
- QVector<QTextLayout::FormatRange>::iterator it = overrides.end();
+ QList<QTextLayout::FormatRange>::iterator it = overrides.end();
while (it != overrides.begin()) {
- QVector<QTextLayout::FormatRange>::iterator previous = it - 1;
+ QList<QTextLayout::FormatRange>::iterator previous = it - 1;
if (o.start >= previous->start) {
overrides.insert(it, o);
break;
@@ -2051,9 +2114,9 @@ void QWidgetTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
if (cursor.charFormat().isValid()) {
int start = cursor.position() - block.position();
- int end = start + e->preeditString().length();
+ int end = start + e->preeditString().size();
- QVector<QTextLayout::FormatRange>::iterator it = overrides.begin();
+ QList<QTextLayout::FormatRange>::iterator it = overrides.begin();
while (it != overrides.end()) {
QTextLayout::FormatRange range = *it;
int rangeStart = range.start;
@@ -2124,12 +2187,12 @@ QVariant QWidgetTextControl::inputMethodQuery(Qt::InputMethodQuery property, QVa
QTextCursor tmpCursor = d->cursor;
int localPos = d->cursor.position() - block.position();
QString result = block.text().mid(localPos);
- while (result.length() < maxLength) {
+ while (result.size() < maxLength) {
int currentBlock = tmpCursor.blockNumber();
tmpCursor.movePosition(QTextCursor::NextBlock);
if (tmpCursor.blockNumber() == currentBlock)
break;
- result += QLatin1Char('\n') + tmpCursor.block().text();
+ result += u'\n' + tmpCursor.block().text();
}
return QVariant(result);
}
@@ -2150,11 +2213,11 @@ QVariant QWidgetTextControl::inputMethodQuery(Qt::InputMethodQuery property, QVa
}
QString result;
while (numBlocks) {
- result += tmpCursor.block().text() + QLatin1Char('\n');
+ result += tmpCursor.block().text() + u'\n';
tmpCursor.movePosition(QTextCursor::NextBlock);
--numBlocks;
}
- result += block.text().midRef(0, localPos);
+ result += QStringView{block.text()}.mid(0, localPos);
return QVariant(result);
}
default:
@@ -2175,7 +2238,7 @@ void QWidgetTextControlPrivate::focusEvent(QFocusEvent *e)
emit q->updateRequest(q->selectionRect());
if (e->gotFocus()) {
#ifdef QT_KEYPAD_NAVIGATION
- if (!QApplication::keypadNavigationEnabled() || (hasEditFocus && (e->reason() == Qt::PopupFocusReason))) {
+ if (!QApplicationPrivate::keypadNavigationEnabled() || (hasEditFocus && (e->reason() == Qt::PopupFocusReason))) {
#endif
cursorOn = (interactionFlags & (Qt::TextSelectableByKeyboard | Qt::TextEditable));
if (interactionFlags & Qt::TextEditable) {
@@ -2186,6 +2249,7 @@ void QWidgetTextControlPrivate::focusEvent(QFocusEvent *e)
#endif
} else {
setCursorVisible(false);
+ cursorOn = false;
if (cursorIsFocusIndicator
&& e->reason() != Qt::ActiveWindowFocusReason
@@ -2216,7 +2280,7 @@ void QWidgetTextControlPrivate::editFocusEvent(QEvent *e)
{
Q_Q(QWidgetTextControl);
- if (QApplication::keypadNavigationEnabled()) {
+ if (QApplicationPrivate::keypadNavigationEnabled()) {
if (e->type() == QEvent::EnterEditFocus && interactionFlags & Qt::TextEditable) {
const QTextCursor oldSelection = cursor;
const int oldCursorPos = cursor.position();
@@ -2240,7 +2304,7 @@ void QWidgetTextControlPrivate::editFocusEvent(QEvent *e)
#endif
#ifndef QT_NO_CONTEXTMENU
-static inline void setActionIcon(QAction *action, const QString &name)
+void setActionIcon(QAction *action, const QString &name)
{
const QIcon icon = QIcon::fromTheme(name);
if (!icon.isNull())
@@ -2258,7 +2322,7 @@ QMenu *QWidgetTextControl::createStandardContextMenu(const QPointF &pos, QWidget
d->linkToCopy = anchorAt(pos);
if (d->linkToCopy.isEmpty() && !showTextSelectionActions)
- return 0;
+ return nullptr;
QMenu *menu = new QMenu(parent);
QAction *a;
@@ -2318,6 +2382,7 @@ QMenu *QWidgetTextControl::createStandardContextMenu(const QPointF &pos, QWidget
a = menu->addAction(tr("Select All") + ACCEL_KEY(QKeySequence::SelectAll), this, SLOT(selectAll()));
a->setEnabled(!d->doc->isEmpty());
a->setObjectName(QStringLiteral("select-all"));
+ setActionIcon(a, QStringLiteral("edit-select-all"));
}
if ((d->interactionFlags & Qt::TextEditable) && QGuiApplication::styleHints()->useRtlExtensions()) {
@@ -2377,6 +2442,12 @@ QString QWidgetTextControl::anchorAtCursor() const
return d->anchorForCursor(d->cursor);
}
+QTextBlock QWidgetTextControl::blockWithMarkerAt(const QPointF &pos) const
+{
+ Q_D(const QWidgetTextControl);
+ return d->doc->documentLayout()->blockWithMarkerAt(pos);
+}
+
bool QWidgetTextControl::overwriteMode() const
{
Q_D(const QWidgetTextControl);
@@ -2391,24 +2462,16 @@ void QWidgetTextControl::setOverwriteMode(bool overwrite)
int QWidgetTextControl::cursorWidth() const
{
-#ifndef QT_NO_PROPERTIES
Q_D(const QWidgetTextControl);
return d->doc->documentLayout()->property("cursorWidth").toInt();
-#else
- return 1;
-#endif
}
void QWidgetTextControl::setCursorWidth(int width)
{
Q_D(QWidgetTextControl);
-#ifdef QT_NO_PROPERTIES
- Q_UNUSED(width);
-#else
if (width == -1)
- width = QApplication::style()->pixelMetric(QStyle::PM_TextCursorWidth);
+ width = QApplication::style()->pixelMetric(QStyle::PM_TextCursorWidth, nullptr, qobject_cast<QWidget *>(parent()));
d->doc->documentLayout()->setProperty("cursorWidth", width);
-#endif
d->repaintCursor();
}
@@ -2430,13 +2493,13 @@ void QWidgetTextControl::setExtraSelections(const QList<QTextEdit::ExtraSelectio
{
Q_D(QWidgetTextControl);
- QHash<int, int> hash;
- for (int i = 0; i < d->extraSelections.count(); ++i) {
+ QMultiHash<int, int> hash;
+ for (int i = 0; i < d->extraSelections.size(); ++i) {
const QAbstractTextDocumentLayout::Selection &esel = d->extraSelections.at(i);
- hash.insertMulti(esel.cursor.anchor(), i);
+ hash.insert(esel.cursor.anchor(), i);
}
- for (int i = 0; i < selections.count(); ++i) {
+ for (int i = 0; i < selections.size(); ++i) {
const QTextEdit::ExtraSelection &sel = selections.at(i);
const auto it = hash.constFind(sel.cursor.anchor());
if (it != hash.cend()) {
@@ -2455,7 +2518,7 @@ void QWidgetTextControl::setExtraSelections(const QList<QTextEdit::ExtraSelectio
emit updateRequest(r);
}
- for (QHash<int, int>::iterator it = hash.begin(); it != hash.end(); ++it) {
+ for (auto it = hash.cbegin(); it != hash.cend(); ++it) {
const QAbstractTextDocumentLayout::Selection &esel = d->extraSelections.at(it.value());
QRectF r = selectionRect(esel.cursor);
if (esel.format.boolProperty(QTextFormat::FullWidthSelection)) {
@@ -2465,8 +2528,8 @@ void QWidgetTextControl::setExtraSelections(const QList<QTextEdit::ExtraSelectio
emit updateRequest(r);
}
- d->extraSelections.resize(selections.count());
- for (int i = 0; i < selections.count(); ++i) {
+ d->extraSelections.resize(selections.size());
+ for (int i = 0; i < selections.size(); ++i) {
d->extraSelections[i].cursor = selections.at(i).cursor;
d->extraSelections[i].format = selections.at(i).format;
}
@@ -2476,7 +2539,7 @@ QList<QTextEdit::ExtraSelection> QWidgetTextControl::extraSelections() const
{
Q_D(const QWidgetTextControl);
QList<QTextEdit::ExtraSelection> selections;
- const int numExtraSelections = d->extraSelections.count();
+ const int numExtraSelections = d->extraSelections.size();
selections.reserve(numExtraSelections);
for (int i = 0; i < numExtraSelections; ++i) {
QTextEdit::ExtraSelection sel;
@@ -2549,7 +2612,7 @@ bool QWidgetTextControl::canPaste() const
#ifndef QT_NO_CLIPBOARD
Q_D(const QWidgetTextControl);
if (d->interactionFlags & Qt::TextEditable) {
- const QMimeData *md = QApplication::clipboard()->mimeData();
+ const QMimeData *md = QGuiApplication::clipboard()->mimeData();
return md && canInsertFromMimeData(md);
}
#endif
@@ -2605,12 +2668,13 @@ void QWidgetTextControl::print(QPagedPaintDevice *printer) const
Q_D(const QWidgetTextControl);
if (!printer)
return;
- QTextDocument *tempDoc = 0;
+ QTextDocument *tempDoc = nullptr;
const QTextDocument *doc = d->doc;
if (QPagedPaintDevicePrivate::get(printer)->printSelectionOnly) {
if (!d->cursor.hasSelection())
return;
tempDoc = new QTextDocument(const_cast<QTextDocument *>(doc));
+ tempDoc->setResourceProvider(doc->resourceProvider());
tempDoc->setMetaInformation(QTextDocument::DocumentTitle, doc->metaInformation(QTextDocument::DocumentTitle));
tempDoc->setPageSize(doc->pageSize());
tempDoc->setDefaultFont(doc->defaultFont());
@@ -2639,8 +2703,8 @@ bool QWidgetTextControl::canInsertFromMimeData(const QMimeData *source) const
if (d->acceptRichText)
return (source->hasText() && !source->text().isEmpty())
|| source->hasHtml()
- || source->hasFormat(QLatin1String("application/x-qrichtext"))
- || source->hasFormat(QLatin1String("application/x-qt-richtext"));
+ || source->hasFormat("application/x-qrichtext"_L1)
+ || source->hasFormat("application/x-qt-richtext"_L1);
else
return source->hasText() && !source->text().isEmpty();
}
@@ -2653,26 +2717,33 @@ void QWidgetTextControl::insertFromMimeData(const QMimeData *source)
bool hasData = false;
QTextDocumentFragment fragment;
+#if QT_CONFIG(textmarkdownreader)
+ const auto formats = source->formats();
+ if (formats.size() && formats.first() == "text/markdown"_L1) {
+ auto s = QString::fromUtf8(source->data("text/markdown"_L1));
+ fragment = QTextDocumentFragment::fromMarkdown(s);
+ hasData = true;
+ } else
+#endif
#ifndef QT_NO_TEXTHTMLPARSER
- if (source->hasFormat(QLatin1String("application/x-qrichtext")) && d->acceptRichText) {
+ if (source->hasFormat("application/x-qrichtext"_L1) && d->acceptRichText) {
// x-qrichtext is always UTF-8 (taken from Qt3 since we don't use it anymore).
- const QString richtext = QLatin1String("<meta name=\"qrichtext\" content=\"1\" />")
- + QString::fromUtf8(source->data(QLatin1String("application/x-qrichtext")));
+ const QString richtext = "<meta name=\"qrichtext\" content=\"1\" />"_L1
+ + QString::fromUtf8(source->data("application/x-qrichtext"_L1));
fragment = QTextDocumentFragment::fromHtml(richtext, d->doc);
hasData = true;
} else if (source->hasHtml() && d->acceptRichText) {
fragment = QTextDocumentFragment::fromHtml(source->html(), d->doc);
hasData = true;
- } else {
- QString text = source->text();
+ }
+#endif // QT_NO_TEXTHTMLPARSER
+ if (!hasData) {
+ const QString text = source->text();
if (!text.isNull()) {
fragment = QTextDocumentFragment::fromPlainText(text);
hasData = true;
}
}
-#else
- fragment = QTextDocumentFragment::fromPlainText(source->text());
-#endif // QT_NO_TEXTHTMLPARSER
if (hasData)
d->cursor.insertFragment(fragment);
@@ -2890,7 +2961,7 @@ void QWidgetTextControlPrivate::activateLinkUnderCursor(QString href)
emit q_func()->linkActivated(href);
}
-#ifndef QT_NO_TOOLTIP
+#if QT_CONFIG(tooltip)
void QWidgetTextControlPrivate::showToolTip(const QPoint &globalPos, const QPointF &pos, QWidget *contextWidget)
{
const QString toolTip = q_func()->cursorForPosition(pos).charFormat().toolTip();
@@ -2898,7 +2969,7 @@ void QWidgetTextControlPrivate::showToolTip(const QPoint &globalPos, const QPoin
return;
QToolTip::showText(globalPos, toolTip, contextWidget);
}
-#endif // QT_NO_TOOLTIP
+#endif // QT_CONFIG(tooltip)
bool QWidgetTextControlPrivate::isPreediting() const
{
@@ -3088,8 +3159,8 @@ bool QWidgetTextControl::find(const QString &exp, QTextDocument::FindFlags optio
return true;
}
-#ifndef QT_NO_REGEXP
-bool QWidgetTextControl::find(const QRegExp &exp, QTextDocument::FindFlags options)
+#if QT_CONFIG(regularexpression)
+bool QWidgetTextControl::find(const QRegularExpression &exp, QTextDocument::FindFlags options)
{
Q_D(QWidgetTextControl);
QTextCursor search = d->doc->find(exp, d->cursor, options);
@@ -3113,6 +3184,56 @@ QString QWidgetTextControl::toHtml() const
}
#endif
+#if QT_CONFIG(textmarkdownwriter)
+QString QWidgetTextControl::toMarkdown(QTextDocument::MarkdownFeatures features) const
+{
+ return document()->toMarkdown(features);
+}
+#endif
+
+void QWidgetTextControlPrivate::insertParagraphSeparator()
+{
+ // clear blockFormat properties that the user is unlikely to want duplicated:
+ // - don't insert <hr/> automatically
+ // - the next paragraph after a heading should be a normal paragraph
+ // - remove the bottom margin from the last list item before appending
+ // - the next checklist item after a checked item should be unchecked
+ auto blockFmt = cursor.blockFormat();
+ auto charFmt = cursor.charFormat();
+ blockFmt.clearProperty(QTextFormat::BlockTrailingHorizontalRulerWidth);
+ if (blockFmt.hasProperty(QTextFormat::HeadingLevel)) {
+ blockFmt.clearProperty(QTextFormat::HeadingLevel);
+ charFmt = QTextCharFormat();
+ }
+ if (cursor.currentList()) {
+ auto existingFmt = cursor.blockFormat();
+ existingFmt.clearProperty(QTextBlockFormat::BlockBottomMargin);
+ cursor.setBlockFormat(existingFmt);
+ if (blockFmt.marker() == QTextBlockFormat::MarkerType::Checked)
+ blockFmt.setMarker(QTextBlockFormat::MarkerType::Unchecked);
+ }
+
+ // After a blank line, reset block and char formats. I.e. you can end a list,
+ // block quote, etc. by hitting enter twice, and get back to normal paragraph style.
+ if (cursor.block().text().isEmpty() &&
+ !cursor.blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth) &&
+ !cursor.blockFormat().hasProperty(QTextFormat::BlockCodeLanguage)) {
+ blockFmt = QTextBlockFormat();
+ const bool blockFmtChanged = (cursor.blockFormat() != blockFmt);
+ charFmt = QTextCharFormat();
+ cursor.setBlockFormat(blockFmt);
+ cursor.setCharFormat(charFmt);
+ // If the user hit enter twice just to get back to default format,
+ // don't actually insert a new block. But if the user then hits enter
+ // yet again, the block format will not change, so we will insert a block.
+ // This is what many word processors do.
+ if (blockFmtChanged)
+ return;
+ }
+
+ cursor.insertBlock(blockFmt, charFmt);
+}
+
void QWidgetTextControlPrivate::append(const QString &text, Qt::TextFormat format)
{
QTextCursor tmp(doc);
@@ -3211,7 +3332,7 @@ QAbstractTextDocumentLayout::PaintContext QWidgetTextControl::getPaintContext(QW
if (!d->dndFeedbackCursor.isNull())
ctx.cursorPosition = d->dndFeedbackCursor.position();
#ifdef QT_KEYPAD_NAVIGATION
- if (!QApplication::keypadNavigationEnabled() || d->hasEditFocus)
+ if (!QApplicationPrivate::keypadNavigationEnabled() || d->hasEditFocus)
#endif
if (d->cursor.hasSelection()) {
QAbstractTextDocumentLayout::Selection selection;
@@ -3262,7 +3383,7 @@ void QWidgetTextControlPrivate::_q_copyLink()
#ifndef QT_NO_CLIPBOARD
QMimeData *md = new QMimeData;
md->setText(linkToCopy);
- QApplication::clipboard()->setMimeData(md);
+ QGuiApplication::clipboard()->setMimeData(md);
#endif
}
@@ -3339,16 +3460,19 @@ void QUnicodeControlCharacterMenu::menuActionTriggered()
QStringList QTextEditMimeData::formats() const
{
if (!fragment.isEmpty())
- return QStringList() << QString::fromLatin1("text/plain") << QString::fromLatin1("text/html")
+ return QStringList() << u"text/plain"_s << u"text/html"_s
+#if QT_CONFIG(textmarkdownwriter)
+ << u"text/markdown"_s
+#endif
#ifndef QT_NO_TEXTODFWRITER
- << QString::fromLatin1("application/vnd.oasis.opendocument.text")
+ << u"application/vnd.oasis.opendocument.text"_s
#endif
;
else
return QMimeData::formats();
}
-QVariant QTextEditMimeData::retrieveData(const QString &mimeType, QVariant::Type type) const
+QVariant QTextEditMimeData::retrieveData(const QString &mimeType, QMetaType type) const
{
if (!fragment.isEmpty())
setup();
@@ -3359,7 +3483,10 @@ void QTextEditMimeData::setup() const
{
QTextEditMimeData *that = const_cast<QTextEditMimeData *>(this);
#ifndef QT_NO_TEXTHTMLPARSER
- that->setData(QLatin1String("text/html"), fragment.toHtml("utf-8").toUtf8());
+ that->setData("text/html"_L1, fragment.toHtml().toUtf8());
+#endif
+#if QT_CONFIG(textmarkdownwriter)
+ that->setData("text/markdown"_L1, fragment.toMarkdown().toUtf8());
#endif
#ifndef QT_NO_TEXTODFWRITER
{
@@ -3367,7 +3494,7 @@ void QTextEditMimeData::setup() const
QTextDocumentWriter writer(&buffer, "ODF");
writer.write(fragment);
buffer.close();
- that->setData(QLatin1String("application/vnd.oasis.opendocument.text"), buffer.data());
+ that->setData("application/vnd.oasis.opendocument.text"_L1, buffer.data());
}
#endif
that->setText(fragment.toPlainText());