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