Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquicktextinput_p_p.h
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
5#ifndef QQUICKTEXTINPUT_P_P_H
6#define QQUICKTEXTINPUT_P_P_H
7
9#include "qquicktext_p.h"
12
13#include <QtQml/qqml.h>
14#include <QtCore/qelapsedtimer.h>
15#include <QtCore/qpointer.h>
16#include <QtCore/qbasictimer.h>
17#include <QtGui/qclipboard.h>
18#include <QtGui/qguiapplication.h>
19#include <QtGui/qpalette.h>
20#include <QtGui/qtextlayout.h>
21#include <QtGui/qstylehints.h>
22#include <private/qlazilyallocated_p.h>
23
24#include "qplatformdefs.h"
25
26#include <memory>
27
28//
29// W A R N I N G
30// -------------
31//
32// This file is not part of the Qt API. It exists purely as an
33// implementation detail. This header file may change from version to
34// version without notice, or even be removed.
35//
36// We mean it.
37
38QT_BEGIN_NAMESPACE
39
40class QSGInternalTextNode;
41class QInputControl;
42
43class Q_QUICK_EXPORT QQuickTextInputPrivate : public QQuickImplicitSizeItemPrivate
44{
45public:
46 Q_DECLARE_PUBLIC(QQuickTextInput)
47
48 typedef QQuickTextInput Public;
49
50 struct ExtraData {
51 ExtraData();
52
53 qreal padding;
54 qreal topPadding;
55 qreal leftPadding;
56 qreal rightPadding;
57 qreal bottomPadding;
58 bool explicitTopPadding : 1;
59 bool explicitLeftPadding : 1;
60 bool explicitRightPadding : 1;
61 bool explicitBottomPadding : 1;
62 bool implicitResize : 1;
63 };
64 QLazilyAllocated<ExtraData> extra;
65
66 QQuickTextInputPrivate()
67 : hscroll(0)
68 , vscroll(0)
69 , cursorItem(nullptr)
70 , textNode(nullptr)
71 , m_maskData(nullptr)
72 , color(QRgb(0xFF000000))
73 , selectionColor(QRgb(0xFF000080))
74 , selectedTextColor(QRgb(0xFFFFFFFF))
75 , m_cursor(0)
76#if QT_CONFIG(im)
77 , m_preeditCursor(0)
78 , m_undoPreeditState(-1)
79#endif
80 , m_blinkEnabled(false)
81 , m_blinkTimer(0)
82 , m_maxLength(32767)
83 , m_lastCursorPos(-1)
84 , m_undoState(0)
85 , m_selstart(0)
86 , m_selend(0)
87#if QT_CONFIG(im)
88 , inputMethodHints(Qt::ImhNone)
89#endif
90 , hAlign(QQuickTextInput::AlignLeft)
91 , vAlign(QQuickTextInput::AlignTop)
92 , wrapMode(QQuickTextInput::NoWrap)
93 , m_echoMode(QQuickTextInput::Normal)
94 , renderType(QQuickTextUtil::textRenderType<QQuickTextInput>())
95 , updateType(UpdatePaintNode)
96 , mouseSelectionMode(QQuickTextInput::SelectCharacters)
97 , m_layoutDirection(Qt::LayoutDirectionAuto)
98 , m_passwordCharacter(QGuiApplication::styleHints()->passwordMaskCharacter())
99 , m_passwordMaskDelay(QGuiApplication::styleHints()->passwordMaskDelay())
100 , focusOnPress(true)
101 , cursorVisible(false)
102 , cursorPending(false)
103 , autoScroll(true)
104 , selectByMouse(true)
105 , canPaste(false)
106 , canPasteValid(false)
107 , canUndo(false)
108 , canRedo(false)
109 , hAlignImplicit(true)
110 , selectPressed(false)
111 , hadSelectionOnMousePress(false)
112 , textLayoutDirty(true)
113 , persistentSelection(false)
114 , hasImState(false)
115 , m_separator(0)
116 , m_readOnly(0)
117 , m_textDirty(0)
118#if QT_CONFIG(im)
119 , m_preeditDirty(0)
120#endif
121 , m_selDirty(0)
122 , m_validInput(1)
123 , m_acceptableInput(1)
124 , m_blinkStatus(0)
125 , m_passwordEchoEditing(false)
126 , inLayout(false)
127 , requireImplicitWidth(false)
128 , overwriteMode(false)
129 , containsUnscalableGlyphs(false)
130#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
131 , selectByTouchDrag(false)
132#endif
133 {
134 }
135
136 ~QQuickTextInputPrivate()
137 {
138 // If this control is used for password input, we don't want the
139 // password data to stay in the process memory, therefore we need
140 // to zero it out
141 if (m_echoMode != QQuickTextInput::Normal)
142 m_text.fill(u'\0');
143 }
144
145 void init();
146 void cancelInput();
147 void startCreatingCursor();
148 void ensureVisible(int position, int preeditCursor = 0, int preeditLength = 0);
149 void updateHorizontalScroll();
150 void updateVerticalScroll();
151 bool determineHorizontalAlignment();
152 bool setHAlign(QQuickTextInput::HAlignment, bool forceAlign = false);
153 void mirrorChange() override;
154#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
155 bool handleContextMenuEvent(QContextMenuEvent *event) override;
156#endif
157 bool sendMouseEventToInputContext(QMouseEvent *event);
158#if QT_CONFIG(im)
159 Qt::InputMethodHints effectiveInputMethodHints() const;
160#endif
161 void handleFocusEvent(QFocusEvent *event);
162
163 struct MaskInputData {
164 enum Casemode { NoCaseMode, Upper, Lower };
165 QChar maskChar; // either the separator char or the inputmask
166 bool separator;
167 Casemode caseMode;
168 };
169
170 // undo/redo handling
171 enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection, SetSelection };
172 struct Command {
173 inline Command() {}
174 inline Command(CommandType t, int p, QChar c, int ss, int se) : type(t),uc(c),pos(p),selStart(ss),selEnd(se) {}
175 uint type : 4;
176 QChar uc;
177 int pos, selStart, selEnd;
178 };
179
180 enum DrawFlags {
181 DrawText = 0x01,
182 DrawSelections = 0x02,
183 DrawCursor = 0x04,
184 DrawAll = DrawText | DrawSelections | DrawCursor
185 };
186
187 QElapsedTimer tripleClickTimer;
188 QSizeF contentSize;
189 QPointF pressPos;
190 QPointF tripleClickStartPoint;
191
192 QPointer<QQmlComponent> cursorComponent;
193#if QT_CONFIG(validator)
194 QPointer<QValidator> m_validator;
195#endif
196
197 qreal hscroll;
198 qreal vscroll;
199
200 QTextLayout m_textLayout;
201 QString m_text;
202 QString m_inputMask;
203 QString m_cancelText;
204 QFont font;
205 QFont sourceFont;
206
207 QQuickItem *cursorItem;
208 QSGInternalTextNode *textNode;
209 std::unique_ptr<MaskInputData[]> m_maskData;
210 QInputControl *m_inputControl;
211
212 QList<int> m_transactions;
213 QVector<Command> m_history;
214
215 QColor color;
216 QColor selectionColor;
217 QColor selectedTextColor;
218
219 QBasicTimer m_passwordEchoTimer;
220 int lastSelectionStart;
221 int lastSelectionEnd;
222 int m_cursor;
223#if QT_CONFIG(im)
224 int m_preeditCursor;
225 int m_undoPreeditState;
226#endif
227 bool m_blinkEnabled;
228 int m_blinkTimer;
229 int m_maxLength;
230 int m_lastCursorPos;
231 int m_undoState;
232 int m_selstart;
233 int m_selend;
234
235 enum UpdateType {
236 UpdateNone,
237 UpdateOnlyPreprocess,
238 UpdatePaintNode
239 };
240
241#if QT_CONFIG(im)
242 Qt::InputMethodHints inputMethodHints;
243#endif
244 QQuickTextInput::HAlignment hAlign;
245 QQuickTextInput::VAlignment vAlign;
246 QQuickTextInput::WrapMode wrapMode;
247 QQuickTextInput::EchoMode m_echoMode;
248 QQuickTextInput::RenderType renderType;
249 UpdateType updateType;
250 QQuickTextInput::SelectionMode mouseSelectionMode;
251 Qt::LayoutDirection m_layoutDirection;
252
253 QChar m_blank;
254 QChar m_passwordCharacter;
255 int m_passwordMaskDelay;
256
257 bool focusOnPress:1;
258 bool cursorVisible:1;
259 bool cursorPending:1;
260 bool autoScroll:1;
261 bool selectByMouse:1;
262 bool canPaste:1;
263 bool canPasteValid:1;
264 bool canUndo:1;
265 bool canRedo:1;
266 bool hAlignImplicit:1;
267 bool selectPressed:1;
268 bool hadSelectionOnMousePress:1;
269 bool textLayoutDirty:1;
270 bool persistentSelection:1;
271 bool hasImState : 1;
272 bool m_separator : 1;
273 bool m_readOnly : 1;
274 bool m_textDirty : 1;
275#if QT_CONFIG(im)
276 bool m_preeditDirty : 1;
277#endif
278 bool m_selDirty : 1;
279 bool m_validInput : 1;
280 bool m_acceptableInput : 1;
281 bool m_blinkStatus : 1;
282 bool m_passwordEchoEditing : 1;
283 bool inLayout:1;
284 bool requireImplicitWidth:1;
285 bool overwriteMode:1;
286 bool containsUnscalableGlyphs:1;
287#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
288 bool selectByTouchDrag:1;
289#endif
290
291 static inline QQuickTextInputPrivate *get(QQuickTextInput *t) {
292 return t->d_func();
293 }
294 bool hasPendingTripleClick() const {
295 return !tripleClickTimer.hasExpired(QGuiApplication::styleHints()->mouseDoubleClickInterval());
296 }
297
298 void setNativeCursorEnabled(bool) {
299 updateCursorBlinking();
300 }
301
302 int nextMaskBlank(int pos)
303 {
304 int c = findInMask(pos, true, false);
305 m_separator |= (c != pos);
306 return (c != -1 ? c : m_maxLength);
307 }
308
309 int prevMaskBlank(int pos)
310 {
311 int c = findInMask(pos, false, false);
312 m_separator |= (c != pos);
313 return (c != -1 ? c : 0);
314 }
315
316 bool isUndoAvailable() const { return !m_readOnly && m_undoState; }
317 bool isRedoAvailable() const { return !m_readOnly && m_undoState < (int)m_history.size(); }
318 void clearUndo() {
319 m_history.clear();
320 m_undoState = 0;
321#if QT_CONFIG(im)
322 m_undoPreeditState = -1;
323#endif
324 }
325
326 bool allSelected() const { return !m_text.isEmpty() && m_selstart == 0 && m_selend == (int)m_text.size(); }
327 bool hasSelectedText() const { return !m_text.isEmpty() && m_selend > m_selstart; }
328
329 void setSelection(int start, int length);
330
331 inline QString selectedText() const { return hasSelectedText() ? m_text.mid(m_selstart, m_selend - m_selstart) : QString(); }
332 QString textBeforeSelection() const { return hasSelectedText() ? m_text.left(m_selstart) : QString(); }
333 QString textAfterSelection() const { return hasSelectedText() ? m_text.mid(m_selend) : QString(); }
334
335 int selectionStart() const { return hasSelectedText() ? m_selstart : -1; }
336 int selectionEnd() const { return hasSelectedText() ? m_selend : -1; }
337
338 QRectF anchorRectangle() const;
339
340 int positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const;
341 int positionAt(const QPointF &point, QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters) const {
342 return positionAt(point.x(), point.y(), position);
343 }
344
345 void removeSelection()
346 {
347 int priorState = m_undoState;
348 removeSelectedText();
349 finishChange(priorState);
350 }
351
352 int start() const { return 0; }
353 int end() const { return m_text.size(); }
354
355 QString realText() const;
356
357#if QT_CONFIG(clipboard)
358 void copy(QClipboard::Mode mode = QClipboard::Clipboard) const;
359 void paste(QClipboard::Mode mode = QClipboard::Clipboard);
360#endif
361
362#if QT_CONFIG(im)
363 void commitPreedit();
364 void cancelPreedit();
365#endif
366
367 Qt::CursorMoveStyle cursorMoveStyle() const { return m_textLayout.cursorMoveStyle(); }
368 void setCursorMoveStyle(Qt::CursorMoveStyle style) { m_textLayout.setCursorMoveStyle(style); }
369
370 void moveCursor(int pos, bool mark = false);
371 void cursorForward(bool mark, int steps)
372 {
373 int c = m_cursor;
374 if (steps > 0) {
375 while (steps--)
376 c = cursorMoveStyle() == Qt::VisualMoveStyle ? m_textLayout.rightCursorPosition(c)
377 : m_textLayout.nextCursorPosition(c);
378 } else if (steps < 0) {
379 while (steps++)
380 c = cursorMoveStyle() == Qt::VisualMoveStyle ? m_textLayout.leftCursorPosition(c)
381 : m_textLayout.previousCursorPosition(c);
382 }
383 moveCursor(c, mark);
384 }
385
386 void cursorWordForward(bool mark) { moveCursor(m_textLayout.nextCursorPosition(m_cursor, QTextLayout::SkipWords), mark); }
387 void cursorWordBackward(bool mark) { moveCursor(m_textLayout.previousCursorPosition(m_cursor, QTextLayout::SkipWords), mark); }
388
389 void home(bool mark) { moveCursor(0, mark); }
390 void end(bool mark) { moveCursor(q_func()->text().size(), mark); }
391
392 void backspace();
393 void del();
394 void deselect() { internalDeselect(); finishChange(); }
395 void selectAll() { m_selstart = m_selend = m_cursor = 0; moveCursor(m_text.size(), true); }
396
397 void insert(const QString &);
398 void clear();
399 void selectWordAtPos(int);
400
401 void setCursorPosition(int pos) { if (pos <= m_text.size()) moveCursor(qMax(0, pos)); }
402
403 bool fixup();
404
405 QString inputMask() const { return m_maskData ? m_inputMask + QLatin1Char(';') + m_blank : QString(); }
406 void setInputMask(const QString &mask)
407 {
408 parseInputMask(mask);
409 if (m_maskData)
410 moveCursor(nextMaskBlank(0));
411 }
412
413 // input methods
414#if QT_CONFIG(im)
415 bool composeMode() const { return !m_textLayout.preeditAreaText().isEmpty(); }
416
417 QString preeditAreaText() const { return m_textLayout.preeditAreaText(); }
418#endif
419
420 void updatePasswordEchoEditing(bool editing);
421
422 void cancelPasswordEchoTimer() {
423 m_passwordEchoTimer.stop();
424 }
425
426 Qt::LayoutDirection textDirection() const;
427 Qt::LayoutDirection layoutDirection() const;
428 void setLayoutDirection(Qt::LayoutDirection direction)
429 {
430 if (direction != m_layoutDirection) {
431 m_layoutDirection = direction;
432 updateDisplayText();
433 }
434 }
435
436#if QT_CONFIG(im)
437 void processInputMethodEvent(QInputMethodEvent *event);
438#endif
439 void processKeyEvent(QKeyEvent* ev);
440
441 void setBlinkingCursorEnabled(bool enable);
442 void updateCursorBlinking();
443
444 void updateLayout();
445 void updateBaselineOffset();
446
447 qreal calculateImplicitWidthForText(const QString &text) const;
448 qreal getImplicitWidth() const override;
449
450 inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; }
451 void setTopPadding(qreal value, bool reset = false);
452 void setLeftPadding(qreal value, bool reset = false);
453 void setRightPadding(qreal value, bool reset = false);
454 void setBottomPadding(qreal value, bool reset = false);
455
456 bool isImplicitResizeEnabled() const;
457 void setImplicitResizeEnabled(bool enabled);
458
459private:
460 void removeSelectedText();
461 void internalSetText(const QString &txt, int pos = -1, bool edited = true);
462 void updateDisplayText(bool forceUpdate = false);
463
464 void internalInsert(const QString &s);
465 void internalDelete(bool wasBackspace = false);
466 void internalRemove(int pos);
467
468 inline void internalDeselect()
469 {
470 m_selDirty |= (m_selend > m_selstart);
471 m_selstart = m_selend = 0;
472 }
473
474 void internalUndo(int until = -1);
475 void internalRedo();
476 void emitUndoRedoChanged();
477
478 bool emitCursorPositionChanged();
479
480 bool finishChange(int validateFromState = -1, bool update = false, bool edited = true);
481
482 void addCommand(const Command& cmd);
483
484 inline void separate() { m_separator = true; }
485
486 bool separateSelection();
487 void deleteStartOfWord();
488 void deleteEndOfWord();
489 void deleteEndOfLine();
490
491 enum ValidatorState {
492#if QT_CONFIG(validator)
493 InvalidInput = QValidator::Invalid,
494 IntermediateInput = QValidator::Intermediate,
495 AcceptableInput = QValidator::Acceptable
496#else
497 InvalidInput,
498 IntermediateInput,
499 AcceptableInput
500#endif
501 };
502
503 // masking
504 void parseInputMask(const QString &maskFields);
505 bool isValidInput(QChar key, QChar mask) const;
506 ValidatorState hasAcceptableInput(const QString &text) const;
507 void checkIsValid();
508 QString maskString(uint pos, const QString &str, bool clear = false) const;
509 QString clearString(uint pos, uint len) const;
510 QString stripString(const QString &str) const;
511 int findInMask(int pos, bool forward, bool findSeparator, QChar searchChar = QChar()) const;
512};
513
514QT_END_NAMESPACE
515
516#endif // QQUICKTEXTINPUT_P_P_H