| 1 | // Copyright (C) 2023 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 "qquicktextselection_p.h" |
| 5 | |
| 6 | #include <QFont> |
| 7 | #include <QTextOption> |
| 8 | #include <QtQuick/private/qquicktextcontrol_p.h> |
| 9 | #include <QtQuick/private/qquicktextcontrol_p_p.h> |
| 10 | #include <QtQuick/private/qquicktextedit_p_p.h> |
| 11 | |
| 12 | QT_BEGIN_NAMESPACE |
| 13 | |
| 14 | /*! |
| 15 | \qmltype TextSelection |
| 16 | \nativetype QQuickTextSelection |
| 17 | \inqmlmodule QtQuick |
| 18 | \ingroup qtquick-visual |
| 19 | \ingroup qtquick-input |
| 20 | \brief Represents a contiguous selection of text and its properties. |
| 21 | \since 6.7 |
| 22 | |
| 23 | \l {QtQuick::TextEdit::cursorSelection}{TextEdit.cursorSelection} |
| 24 | represents the range of text that is currently selected (for example by |
| 25 | dragging the mouse). It can be used to query and modify the selected text, |
| 26 | as well as properties in the \l {QTextCharFormat}{character} and |
| 27 | \l {QTextBlockFormat}{block} formats. |
| 28 | |
| 29 | \note This API is considered tech preview and may change or be removed in |
| 30 | future versions of Qt. |
| 31 | |
| 32 | \sa TextEdit, QTextCursor |
| 33 | */ |
| 34 | |
| 35 | /*! \internal |
| 36 | QQuickTextSelection provides QML API using QTextCursor. |
| 37 | QQuickTextControl owns a text cursor, and one instance of |
| 38 | QQuickTextSelection represents it and delegates all operations to it. |
| 39 | */ |
| 40 | QQuickTextSelection::QQuickTextSelection(QObject *parent) |
| 41 | : QObject(parent) |
| 42 | { |
| 43 | // When QQuickTextEdit creates its cursorSelection, it passes itself as the parent |
| 44 | if (auto *textEdit = qmlobject_cast<QQuickTextEdit *>(object: parent)) { |
| 45 | m_control = QQuickTextEditPrivate::get(item: textEdit)->control; |
| 46 | connect(sender: m_control, signal: &QQuickTextControl::currentCharFormatChanged, |
| 47 | context: this, slot: &QQuickTextSelection::updateFromCharFormat); |
| 48 | connect(sender: m_control, signal: &QQuickTextControl::cursorPositionChanged, |
| 49 | context: this, slot: &QQuickTextSelection::updateFromBlockFormat); |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | /*! |
| 54 | \qmlproperty string QtQuick::TextSelection::text |
| 55 | |
| 56 | The selected text, without any rich text markup. |
| 57 | |
| 58 | Setting this property replaces the selected text with the given string. |
| 59 | */ |
| 60 | QString QQuickTextSelection::text() const |
| 61 | { |
| 62 | return cursor().selectedText(); |
| 63 | } |
| 64 | |
| 65 | void QQuickTextSelection::setText(const QString &text) |
| 66 | { |
| 67 | auto cur = cursor(); |
| 68 | if (cur.selectedText() == text) |
| 69 | return; |
| 70 | |
| 71 | cur.insertText(text); |
| 72 | emit textChanged(); |
| 73 | } |
| 74 | |
| 75 | /*! |
| 76 | \qmlproperty color QtQuick::TextSelection::font |
| 77 | |
| 78 | The font of the selected text. |
| 79 | |
| 80 | \sa QTextCharFormat::font() |
| 81 | */ |
| 82 | QFont QQuickTextSelection::font() const |
| 83 | { |
| 84 | return cursor().charFormat().font(); |
| 85 | } |
| 86 | |
| 87 | void QQuickTextSelection::setFont(const QFont &font) |
| 88 | { |
| 89 | auto cur = cursor(); |
| 90 | if (cur.selection().isEmpty()) |
| 91 | cur.select(selection: QTextCursor::WordUnderCursor); |
| 92 | |
| 93 | if (font == cur.charFormat().font()) |
| 94 | return; |
| 95 | |
| 96 | QTextCharFormat fmt; |
| 97 | fmt.setFont(font); |
| 98 | cur.mergeCharFormat(modifier: fmt); |
| 99 | emit fontChanged(); |
| 100 | } |
| 101 | |
| 102 | /*! |
| 103 | \qmlproperty color QtQuick::TextSelection::color |
| 104 | |
| 105 | The foreground color of the selected text. |
| 106 | |
| 107 | \sa QTextCharFormat::foreground() |
| 108 | */ |
| 109 | QColor QQuickTextSelection::color() const |
| 110 | { |
| 111 | return cursor().charFormat().foreground().color(); |
| 112 | } |
| 113 | |
| 114 | void QQuickTextSelection::setColor(QColor color) |
| 115 | { |
| 116 | auto cur = cursor(); |
| 117 | if (cur.selection().isEmpty()) |
| 118 | cur.select(selection: QTextCursor::WordUnderCursor); |
| 119 | |
| 120 | if (color == cur.charFormat().foreground().color()) |
| 121 | return; |
| 122 | |
| 123 | QTextCharFormat fmt; |
| 124 | fmt.setForeground(color); |
| 125 | cur.mergeCharFormat(modifier: fmt); |
| 126 | emit colorChanged(); |
| 127 | } |
| 128 | |
| 129 | /*! |
| 130 | \qmlproperty enumeration QtQuick::TextSelection::alignment |
| 131 | |
| 132 | The alignment of the block containing the selected text. |
| 133 | |
| 134 | \sa QTextBlockFormat::alignment() |
| 135 | */ |
| 136 | Qt::Alignment QQuickTextSelection::alignment() const |
| 137 | { |
| 138 | return cursor().blockFormat().alignment(); |
| 139 | } |
| 140 | |
| 141 | void QQuickTextSelection::setAlignment(Qt::Alignment align) |
| 142 | { |
| 143 | if (align == alignment()) |
| 144 | return; |
| 145 | |
| 146 | QTextBlockFormat format; |
| 147 | format.setAlignment(align); |
| 148 | cursor().mergeBlockFormat(modifier: format); |
| 149 | emit alignmentChanged(); |
| 150 | } |
| 151 | |
| 152 | /*! \internal |
| 153 | Return the cursor, which is either the graphically-manipulable cursor from |
| 154 | QQuickTextControl if that is set, or else the internally-stored cursor |
| 155 | with which the user is trying to mutate and/or monitor the underlying document, |
| 156 | in the case that TextSelection is declared in QML. |
| 157 | */ |
| 158 | QTextCursor QQuickTextSelection::cursor() const |
| 159 | { |
| 160 | if (m_control) |
| 161 | return m_control->textCursor(); |
| 162 | return m_cursor; |
| 163 | } |
| 164 | |
| 165 | inline void QQuickTextSelection::updateFromCharFormat(const QTextCharFormat &fmt) |
| 166 | { |
| 167 | if (fmt.font() != m_charFormat.font()) |
| 168 | emit fontChanged(); |
| 169 | if (fmt.foreground().color() != m_charFormat.foreground().color()) |
| 170 | emit colorChanged(); |
| 171 | |
| 172 | m_charFormat = fmt; |
| 173 | } |
| 174 | |
| 175 | inline void QQuickTextSelection::updateFromBlockFormat() |
| 176 | { |
| 177 | QTextBlockFormat fmt = cursor().blockFormat(); |
| 178 | |
| 179 | if (fmt.alignment() != m_blockFormat.alignment()) |
| 180 | emit alignmentChanged(); |
| 181 | |
| 182 | m_blockFormat = fmt; |
| 183 | } |
| 184 | |
| 185 | QT_END_NAMESPACE |
| 186 | |
| 187 | #include "moc_qquicktextselection_p.cpp" |
| 188 | |