Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwidgetlinecontrol.cpp
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
5
6#if QT_CONFIG(itemviews)
7#include "qabstractitemview.h"
8#endif
9#include "qclipboard.h"
10#include <private/qguiapplication_p.h>
11#if QT_CONFIG(completer)
12#include <private/qcompleter_p.h>
13#endif
14#include <qpa/qplatformtheme.h>
15#include <qstylehints.h>
16#if QT_CONFIG(accessibility)
17#include "qaccessible.h"
18#endif
19
20#include "qapplication.h"
21#include "private/qapplication_p.h"
22#if QT_CONFIG(graphicsview)
23#include "qgraphicssceneevent.h"
24#endif
25
26#include "qvalidator.h"
27
29
30
37int QWidgetLineControl::redoTextLayout() const
38{
39 m_textLayout.clearLayout();
40
41 m_textLayout.beginLayout();
42 QTextLine l = m_textLayout.createLine();
43 m_textLayout.endLayout();
44
45 return qRound(l.ascent());
46}
47
54void QWidgetLineControl::updateDisplayText(bool forceUpdate)
55{
56 QString orig = m_textLayout.text();
58 if (m_echoMode == QLineEdit::NoEcho)
60 else
61 str = m_text;
62
63 if (m_echoMode == QLineEdit::Password) {
64 str.fill(m_passwordCharacter);
65 if (m_passwordEchoTimer != 0 && m_cursor > 0 && m_cursor <= m_text.size()) {
66 int cursor = m_cursor - 1;
67 QChar uc = m_text.at(cursor);
68 str[cursor] = uc;
69 if (cursor > 0 && uc.isLowSurrogate()) {
70 // second half of a surrogate, check if we have the first half as well,
71 // if yes restore both at once
72 uc = m_text.at(cursor - 1);
73 if (uc.isHighSurrogate())
74 str[cursor - 1] = uc;
75 }
76 }
77 } else if (m_echoMode == QLineEdit::PasswordEchoOnEdit && !m_passwordEchoEditing) {
78 str.fill(m_passwordCharacter);
79 }
80
81 // replace certain non-printable characters with spaces (to avoid
82 // drawing boxes when using fonts that don't have glyphs for such
83 // characters)
84 QChar* uc = str.data();
85 for (int i = 0; i < (int)str.size(); ++i) {
86 if ((uc[i].unicode() < 0x20 && uc[i].unicode() != 0x09)
87 || uc[i] == QChar::LineSeparator
88 || uc[i] == QChar::ParagraphSeparator)
89 uc[i] = QChar(0x0020);
90 }
91
92 m_textLayout.setText(str);
93
94 QTextOption option = m_textLayout.textOption();
95 option.setTextDirection(m_layoutDirection);
97 m_textLayout.setTextOption(option);
98
99 m_ascent = redoTextLayout();
100
101 if (str != orig || forceUpdate)
103}
104
105#ifndef QT_NO_CLIPBOARD
117{
119 if (!t.isEmpty() && m_echoMode == QLineEdit::Normal) {
120 QGuiApplication::clipboard()->setText(t, mode);
121 }
122}
123
133{
134 QString clip = QGuiApplication::clipboard()->text(clipboardMode);
135 if (!clip.isEmpty() || hasSelectedText()) {
136 separate(); //make it a separate undo/redo command
137 insert(clip);
138 separate();
139 }
140}
141
142#endif // !QT_NO_CLIPBOARD
143
148{
149#ifndef QT_NO_IM
150 if (!composeMode())
151 return;
152
154 if (!composeMode())
155 return;
156
157 m_preeditCursor = 0;
158 setPreeditArea(-1, QString());
159 m_textLayout.clearFormats();
160 updateDisplayText(/*force*/ true);
161#endif
162}
163
164
175{
176 int priorState = m_undoState;
177 if (hasSelectedText()) {
178 removeSelectedText();
179 } else if (m_cursor) {
180 --m_cursor;
181 if (m_maskData)
182 m_cursor = prevMaskBlank(m_cursor);
183 QChar uc = m_text.at(m_cursor);
184 if (m_cursor > 0 && uc.isLowSurrogate()) {
185 // second half of a surrogate, check if we have the first half as well,
186 // if yes delete both at once
187 uc = m_text.at(m_cursor - 1);
188 if (uc.isHighSurrogate()) {
189 internalDelete(true);
190 --m_cursor;
191 }
192 }
193 internalDelete(true);
194 }
195 finishChange(priorState);
196}
197
208{
209 int priorState = m_undoState;
210 if (hasSelectedText()) {
211 removeSelectedText();
212 } else {
213 int n = textLayout()->nextCursorPosition(m_cursor) - m_cursor;
214 while (n--)
215 internalDelete();
216 }
217 finishChange(priorState);
218}
219
228{
229 int priorState = m_undoState;
230 removeSelectedText();
231 internalInsert(newText);
232 finishChange(priorState);
233}
234
241{
242 int priorState = m_undoState;
243 m_selstart = 0;
244 m_selend = m_text.size();
245 removeSelectedText();
246 separate();
247 finishChange(priorState, /*update*/false, /*edited*/false);
248}
256{
257 // Undo works only for clearing the line when in any of password the modes
258 if (m_echoMode == QLineEdit::Normal) {
259 internalUndo();
260 finishChange(-1, true);
261 } else {
262 cancelPasswordEchoTimer();
263 clear();
264 }
265}
266
276{
278
279 if (Q_UNLIKELY(start < 0 || start > m_text.size())) {
280 qWarning("QWidgetLineControl::setSelection: Invalid start position");
281 return;
282 }
283
284 if (length > 0) {
285 if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
286 return;
287 m_selstart = start;
288 m_selend = qMin(start + length, (int)m_text.size());
289 m_cursor = m_selend;
290 } else if (length < 0){
291 if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
292 return;
293 m_selstart = qMax(start + length, 0);
294 m_selend = start;
295 m_cursor = m_selstart;
296 } else if (m_selstart != m_selend) {
297 m_selstart = 0;
298 m_selend = 0;
299 m_cursor = start;
300 } else {
301 m_cursor = start;
302 emitCursorPositionChanged();
303 return;
304 }
306 emitCursorPositionChanged();
307}
308
309void QWidgetLineControl::_q_deleteSelected()
310{
311 if (!hasSelectedText())
312 return;
313
314 int priorState = m_undoState;
316 removeSelectedText();
317 separate();
318 finishChange(priorState);
319}
320
326void QWidgetLineControl::init(const QString &txt)
327{
328 m_textLayout.setCacheEnabled(true);
329 m_text = txt;
330 updateDisplayText();
331 m_cursor = m_text.size();
333 m_keyboardScheme = theme->themeHint(QPlatformTheme::KeyboardScheme).toInt();
334 m_passwordMaskDelay = theme->themeHint(QPlatformTheme::PasswordMaskDelay).toInt();
335 }
336 // Generalize for X11
337 if (m_keyboardScheme == QPlatformTheme::KdeKeyboardScheme
338 || m_keyboardScheme == QPlatformTheme::GnomeKeyboardScheme
339 || m_keyboardScheme == QPlatformTheme::CdeKeyboardScheme) {
340 m_keyboardScheme = QPlatformTheme::X11KeyboardScheme;
341 }
342}
343
353{
354 cancelPasswordEchoTimer();
355 m_passwordEchoEditing = editing;
356 updateDisplayText();
357}
358
367{
368 return textLayout()->lineAt(0).xToCursor(x, betweenOrOn);
369}
370
377{
378 QTextLine l = textLayout()->lineAt(0);
379 if (m_preeditCursor != -1)
380 pos += m_preeditCursor;
381 int cix = qRound(l.cursorToX(pos));
382 int w = m_cursorWidth;
383 int ch = l.height() + 1;
384
385 return QRect(cix - 5, 0, w + 9, ch);
386}
387
395{
396 return rectForPos(m_cursor);
397}
398
405{
406 if (!hasSelectedText())
407 return cursorRect();
408 return rectForPos(m_cursor == m_selstart ? m_selend : m_selstart);
409}
410
418bool QWidgetLineControl::fixup() // this function assumes that validate currently returns != Acceptable
419{
420#ifndef QT_NO_VALIDATOR
421 if (m_validator) {
422 QString textCopy = m_text;
423 int cursorCopy = m_cursor;
424 m_validator->fixup(textCopy);
425 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
426 if (textCopy != m_text || cursorCopy != m_cursor)
427 internalSetText(textCopy, cursorCopy, false);
428 return true;
429 }
430 }
431#endif
432 return false;
433}
434
442{
444
445 if (pos != m_cursor) {
446 separate();
447 if (m_maskData)
448 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
449 }
450 if (mark) {
451 int anchor;
452 if (m_selend > m_selstart && m_cursor == m_selstart)
453 anchor = m_selend;
454 else if (m_selend > m_selstart && m_cursor == m_selend)
455 anchor = m_selstart;
456 else
457 anchor = m_cursor;
458 m_selstart = qMin(anchor, pos);
459 m_selend = qMax(anchor, pos);
460 updateDisplayText();
461 } else {
462 internalDeselect();
463 }
464 m_cursor = pos;
465 if (mark || m_selDirty) {
466 m_selDirty = false;
468 }
469 emitCursorPositionChanged();
470}
471
479{
480 int priorState = -1;
481 bool isGettingInput = !event->commitString().isEmpty()
482 || event->preeditString() != preeditAreaText()
483 || event->replacementLength() > 0;
484 bool cursorPositionChanged = false;
485 bool selectionChange = false;
486
487 if (isGettingInput) {
488 // If any text is being input, remove selected text.
489 priorState = m_undoState;
492 m_selstart = 0;
493 m_selend = m_text.size();
494 }
495 removeSelectedText();
496 }
497
498 int c = m_cursor; // cursor position after insertion of commit string
499 if (event->replacementStart() <= 0)
500 c += event->commitString().size() - qMin(-event->replacementStart(), event->replacementLength());
501
502 m_cursor += event->replacementStart();
503 if (m_cursor < 0)
504 m_cursor = 0;
505
506 // insert commit string
507 if (event->replacementLength()) {
508 m_selstart = m_cursor;
509 m_selend = m_selstart + event->replacementLength();
510 removeSelectedText();
511 }
512 if (!event->commitString().isEmpty()) {
513 internalInsert(event->commitString());
515 } else {
516 m_cursor = qBound(0, c, m_text.size());
517 }
518
519 for (int i = 0; i < event->attributes().size(); ++i) {
520 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
521 if (a.type == QInputMethodEvent::Selection) {
522 m_cursor = qBound(0, a.start + a.length, m_text.size());
523 if (a.length) {
524 m_selstart = qMax(0, qMin(a.start, m_text.size()));
525 m_selend = m_cursor;
526 if (m_selend < m_selstart) {
527 qSwap(m_selstart, m_selend);
528 }
529 selectionChange = true;
530 } else {
531 if (m_selstart != m_selend)
532 selectionChange = true;
533 m_selstart = m_selend = 0;
534 }
536 }
537 }
538#ifndef QT_NO_IM
539 // in NoEcho mode, the cursor is always at the beginning of the lineedit
540 switch (m_echoMode) {
543 break;
544 case QLineEdit::Password: {
545 QString preeditString = event->preeditString();
546 preeditString.fill(m_passwordCharacter);
547 setPreeditArea(m_cursor, preeditString);
548 break;
549 }
550 default:
551 setPreeditArea(m_cursor, event->preeditString());
552 break;
553 }
554#endif //QT_NO_IM
555 const int oldPreeditCursor = m_preeditCursor;
556 m_preeditCursor = event->preeditString().size();
557 m_hideCursor = false;
558 QList<QTextLayout::FormatRange> formats;
559 formats.reserve(event->attributes().size());
560 for (int i = 0; i < event->attributes().size(); ++i) {
561 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
562 if (a.type == QInputMethodEvent::Cursor) {
563 m_preeditCursor = a.start;
564 m_hideCursor = !a.length;
565 } else if (a.type == QInputMethodEvent::TextFormat) {
566 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
567 if (f.isValid()) {
569 o.start = a.start + m_cursor;
570 o.length = a.length;
571 o.format = f;
572 formats.append(o);
573 }
574 }
575 }
576 m_textLayout.setFormats(formats);
577 updateDisplayText(/*force*/ true);
579 emitCursorPositionChanged();
580 else if (m_preeditCursor != oldPreeditCursor)
582
583 if (isGettingInput)
584 finishChange(priorState);
585
586 if (selectionChange)
588}
589
606{
607 QList<QTextLayout::FormatRange> selections;
608 if (flags & DrawSelections) {
610 if (m_selstart < m_selend) {
611 o.start = m_selstart;
612 o.length = m_selend - m_selstart;
613 o.format.setBackground(m_palette.brush(QPalette::Highlight));
614 o.format.setForeground(m_palette.brush(QPalette::HighlightedText));
615 } else {
616 // mask selection
617 if (m_blinkStatus){
618 o.start = m_cursor;
619 o.length = 1;
620 o.format.setBackground(m_palette.brush(QPalette::Text));
621 o.format.setForeground(m_palette.brush(QPalette::Window));
622 }
623 }
624 selections.append(o);
625 }
626
627 if (flags & DrawText)
628 textLayout()->draw(painter, offset, selections, clip);
629
630 if (flags & DrawCursor){
631 int cursor = m_cursor;
632 if (m_preeditCursor != -1)
633 cursor += m_preeditCursor;
634 if (!m_hideCursor && m_blinkStatus)
635 textLayout()->drawCursor(painter, offset, cursor, m_cursorWidth);
636 }
637}
638
647{
648 int next = cursor + 1;
649 if (next > end())
650 --next;
652 moveCursor(c, false);
653 // ## text layout should support end of words.
655 while (end > cursor && m_text[end-1].isSpace())
656 --end;
657 moveCursor(end, true);
658}
659
672bool QWidgetLineControl::finishChange(int validateFromState, bool update, bool edited)
673{
674 Q_UNUSED(update);
675
676 if (m_textDirty) {
677 // do validation
678 bool wasValidInput = m_validInput;
679 m_validInput = true;
680#ifndef QT_NO_VALIDATOR
681 if (m_validator) {
682 QString textCopy = m_text;
683 int cursorCopy = m_cursor;
684 m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
685 if (m_validInput) {
686 if (m_text != textCopy) {
687 internalSetText(textCopy, cursorCopy, edited);
688 return true;
689 }
690 m_cursor = cursorCopy;
691 } else {
693 }
694 }
695#endif
696 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
697 if (m_transactions.size())
698 return false;
699 internalUndo(validateFromState);
700 m_history.erase(m_history.begin() + m_undoState, m_history.end());
701 if (m_modifiedState > m_undoState)
702 m_modifiedState = -1;
703 m_validInput = true;
704 m_textDirty = false;
705 }
706 updateDisplayText();
707
708 if (m_textDirty) {
709 m_textDirty = false;
710 QString actualText = text();
711 if (edited)
712 emit textEdited(actualText);
713 emit textChanged(actualText);
714 }
715 }
716 if (m_selDirty) {
717 m_selDirty = false;
719 }
720 if (m_cursor == m_lastCursorPos)
722 emitCursorPositionChanged();
723 return true;
724}
725
731void QWidgetLineControl::internalSetText(const QString &txt, int pos, bool edited)
732{
733 cancelPasswordEchoTimer();
734 internalDeselect();
736 QString oldText = m_text;
737 if (m_maskData) {
738 m_text = maskString(0, txt, true);
739 m_text += clearString(m_text.size(), m_maxLength - m_text.size());
740 if (edited && oldText == m_text)
742 } else {
743 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
744 }
745 m_history.clear();
746 m_modifiedState = m_undoState = 0;
747 m_cursor = (pos < 0 || pos > m_text.size()) ? m_text.size() : pos;
748 m_textDirty = (oldText != m_text);
749 const bool changed = finishChange(-1, true, edited);
750
751#if QT_CONFIG(accessibility)
752 if (changed) {
753 if (oldText.isEmpty()) {
754 QAccessibleTextInsertEvent event(accessibleObject(), 0, txt);
755 event.setCursorPosition(m_cursor);
756 QAccessible::updateAccessibility(&event);
757 } else if (txt.isEmpty()) {
758 QAccessibleTextRemoveEvent event(accessibleObject(), 0, oldText);
759 event.setCursorPosition(m_cursor);
760 QAccessible::updateAccessibility(&event);
761 } else {
762 QAccessibleTextUpdateEvent event(accessibleObject(), 0, oldText, txt);
763 event.setCursorPosition(m_cursor);
764 QAccessible::updateAccessibility(&event);
765 }
766 }
767#else
768 Q_UNUSED(changed);
769#endif
770}
771
772
779void QWidgetLineControl::addCommand(const Command &cmd)
780{
781 m_history.erase(m_history.begin() + m_undoState, m_history.end());
782
783 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator)
784 m_history.push_back(Command(Separator, m_cursor, u'\0', m_selstart, m_selend));
785
786 m_separator = false;
787 m_history.push_back(cmd);
788 m_undoState = int(m_history.size());
789}
790
801void QWidgetLineControl::internalInsert(const QString &s)
802{
803 if (m_echoMode == QLineEdit::Password) {
804 if (m_passwordEchoTimer != 0)
805 killTimer(m_passwordEchoTimer);
806 int delay = m_passwordMaskDelay;
807#ifdef QT_BUILD_INTERNAL
808 if (m_passwordMaskDelayOverride >= 0)
809 delay = m_passwordMaskDelayOverride;
810#endif
811
812 if (delay > 0)
813 m_passwordEchoTimer = startTimer(delay);
814 }
815 if (hasSelectedText())
816 addCommand(Command(SetSelection, m_cursor, u'\0', m_selstart, m_selend));
817 if (m_maskData) {
818 QString ms = maskString(m_cursor, s);
819 if (ms.isEmpty() && !s.isEmpty())
821#if QT_CONFIG(accessibility)
822 QAccessibleTextInsertEvent insertEvent(accessibleObject(), m_cursor, ms);
823 QAccessible::updateAccessibility(&insertEvent);
824#endif
825 for (int i = 0; i < (int) ms.size(); ++i) {
826 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
827 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
828 }
829 m_text.replace(m_cursor, ms.size(), ms);
830 m_cursor += ms.size();
831 m_cursor = nextMaskBlank(m_cursor);
832 m_textDirty = true;
833#if QT_CONFIG(accessibility)
834 QAccessibleTextCursorEvent event(accessibleObject(), m_cursor);
835 QAccessible::updateAccessibility(&event);
836#endif
837 } else {
838 int remaining = m_maxLength - m_text.size();
839 if (remaining != 0) {
840#if QT_CONFIG(accessibility)
841 QAccessibleTextInsertEvent insertEvent(accessibleObject(), m_cursor, s);
842 QAccessible::updateAccessibility(&insertEvent);
843#endif
844 m_text.insert(m_cursor, s.left(remaining));
845 for (int i = 0; i < (int) s.left(remaining).size(); ++i)
846 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
847 m_textDirty = true;
848 }
849 if (s.size() > remaining)
851 }
852}
853
865void QWidgetLineControl::internalDelete(bool wasBackspace)
866{
867 if (m_cursor < (int) m_text.size()) {
868 cancelPasswordEchoTimer();
869 if (hasSelectedText())
870 addCommand(Command(SetSelection, m_cursor, u'\0', m_selstart, m_selend));
871 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
872 m_cursor, m_text.at(m_cursor), -1, -1));
873#if QT_CONFIG(accessibility)
874 QAccessibleTextRemoveEvent event(accessibleObject(), m_cursor, m_text.at(m_cursor));
875 QAccessible::updateAccessibility(&event);
876#endif
877 if (m_maskData) {
878 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
879 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
880 } else {
881 m_text.remove(m_cursor, 1);
882 }
883 m_textDirty = true;
884 }
885}
886
896void QWidgetLineControl::removeSelectedText()
897{
898 if (m_selstart < m_selend && m_selend <= (int) m_text.size()) {
899 cancelPasswordEchoTimer();
900 separate();
901 int i ;
902 addCommand(Command(SetSelection, m_cursor, u'\0', m_selstart, m_selend));
903 if (m_selstart <= m_cursor && m_cursor < m_selend) {
904 // cursor is within the selection. Split up the commands
905 // to be able to restore the correct cursor position
906 for (i = m_cursor; i >= m_selstart; --i)
907 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
908 for (i = m_selend - 1; i > m_cursor; --i)
909 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
910 } else {
911 for (i = m_selend-1; i >= m_selstart; --i)
912 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
913 }
914#if QT_CONFIG(accessibility)
915 QAccessibleTextRemoveEvent event(accessibleObject(), m_selstart, m_text.mid(m_selstart, m_selend - m_selstart));
916 QAccessible::updateAccessibility(&event);
917#endif
918 if (m_maskData) {
919 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
920 for (int i = 0; i < m_selend - m_selstart; ++i)
921 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
922 } else {
923 m_text.remove(m_selstart, m_selend - m_selstart);
924 }
925 if (m_cursor > m_selstart)
926 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
927 internalDeselect();
928 m_textDirty = true;
929 }
930}
931
938void QWidgetLineControl::parseInputMask(const QString &maskFields)
939{
940 qsizetype delimiter = maskFields.indexOf(u';');
941 if (maskFields.isEmpty() || delimiter == 0) {
942 if (m_maskData) {
943 m_maskData.reset();
944 m_maxLength = 32767;
945 internalSetText(QString(), -1, false);
946 }
947 return;
948 }
949
950 if (delimiter == -1) {
951 m_blank = u' ';
952 m_inputMask = maskFields;
953 } else {
954 m_inputMask = maskFields.left(delimiter);
955 m_blank = (delimiter + 1 < maskFields.size()) ? maskFields[delimiter + 1] : u' ';
956 }
957
958 // calculate m_maxLength / m_maskData length
959 m_maxLength = 0;
960 bool escaped = false;
961 for (int i=0; i<m_inputMask.size(); i++) {
962 const auto c = m_inputMask.at(i);
963 if (escaped) {
964 ++m_maxLength;
965 escaped = false;
966 continue;
967 }
968
969 if (c == u'\\') {
970 escaped = true;
971 continue;
972 }
973
974 if (c != u'\\' && c != u'!' && c != u'<' && c != u'>' &&
975 c != u'{' && c != u'}' && c != u'[' && c != u']')
976 m_maxLength++;
977 }
978
979 m_maskData = std::make_unique<MaskInputData[]>(m_maxLength);
980
981 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
982 bool s;
983 bool escape = false;
984 int index = 0;
985 for (int i = 0; i < m_inputMask.size(); i++) {
986 const auto c = m_inputMask.at(i);
987 if (escape) {
988 s = true;
989 m_maskData[index].maskChar = c;
990 m_maskData[index].separator = s;
991 m_maskData[index].caseMode = m;
992 index++;
993 escape = false;
994 } else if (c == u'<') {
995 m = MaskInputData::Lower;
996 } else if (c == u'>') {
997 m = MaskInputData::Upper;
998 } else if (c == u'!') {
999 m = MaskInputData::NoCaseMode;
1000 } else if (c != u'{' && c != u'}' && c != u'[' && c != u']') {
1001 switch (c.unicode()) {
1002 case 'A':
1003 case 'a':
1004 case 'N':
1005 case 'n':
1006 case 'X':
1007 case 'x':
1008 case '9':
1009 case '0':
1010 case 'D':
1011 case 'd':
1012 case '#':
1013 case 'H':
1014 case 'h':
1015 case 'B':
1016 case 'b':
1017 s = false;
1018 break;
1019 case '\\':
1020 escape = true;
1021 Q_FALLTHROUGH();
1022 default:
1023 s = true;
1024 break;
1025 }
1026
1027 if (!escape) {
1028 m_maskData[index].maskChar = c;
1029 m_maskData[index].separator = s;
1030 m_maskData[index].caseMode = m;
1031 index++;
1032 }
1033 }
1034 }
1035 internalSetText(m_text, -1, false);
1036}
1037
1038
1044bool QWidgetLineControl::isValidInput(QChar key, QChar mask) const
1045{
1046 switch (mask.unicode()) {
1047 case 'A':
1048 if (key.isLetter())
1049 return true;
1050 break;
1051 case 'a':
1052 if (key.isLetter() || key == m_blank)
1053 return true;
1054 break;
1055 case 'N':
1056 if (key.isLetterOrNumber())
1057 return true;
1058 break;
1059 case 'n':
1060 if (key.isLetterOrNumber() || key == m_blank)
1061 return true;
1062 break;
1063 case 'X':
1064 if (key.isPrint() && key != m_blank)
1065 return true;
1066 break;
1067 case 'x':
1068 if (key.isPrint() || key == m_blank)
1069 return true;
1070 break;
1071 case '9':
1072 if (key.isNumber())
1073 return true;
1074 break;
1075 case '0':
1076 if (key.isNumber() || key == m_blank)
1077 return true;
1078 break;
1079 case 'D':
1080 if (key.isNumber() && key.digitValue() > 0)
1081 return true;
1082 break;
1083 case 'd':
1084 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
1085 return true;
1086 break;
1087 case '#':
1088 if (key.isNumber() || key == u'+' || key == u'-' || key == m_blank)
1089 return true;
1090 break;
1091 case 'B':
1092 if (key == u'0' || key == u'1')
1093 return true;
1094 break;
1095 case 'b':
1096 if (key == u'0' || key == u'1' || key == m_blank)
1097 return true;
1098 break;
1099 case 'H':
1100 if (key.isNumber() || (key >= u'a' && key <= u'f') || (key >= u'A' && key <= u'F'))
1101 return true;
1102 break;
1103 case 'h':
1104 if (key.isNumber() || (key >= u'a' && key <= u'f') || (key >= u'A' && key <= u'F') || key == m_blank)
1105 return true;
1106 break;
1107 default:
1108 break;
1109 }
1110 return false;
1111}
1112
1122{
1123#ifndef QT_NO_VALIDATOR
1124 QString textCopy = str;
1125 int cursorCopy = m_cursor;
1126 if (m_validator && m_validator->validate(textCopy, cursorCopy)
1128 return false;
1129#endif
1130
1131 if (!m_maskData)
1132 return true;
1133
1134 if (str.size() != m_maxLength)
1135 return false;
1136
1137 for (int i=0; i < m_maxLength; ++i) {
1138 if (m_maskData[i].separator) {
1139 if (str.at(i) != m_maskData[i].maskChar)
1140 return false;
1141 } else {
1142 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
1143 return false;
1144 }
1145 }
1146 return true;
1147}
1148
1157QString QWidgetLineControl::maskString(int pos, const QString &str, bool clear) const
1158{
1159 if (pos >= m_maxLength)
1160 return QString::fromLatin1("");
1161
1162 QString fill;
1163 fill = clear ? clearString(0, m_maxLength) : m_text;
1164
1165 int strIndex = 0;
1167 int i = pos;
1168 while (i < m_maxLength) {
1169 if (strIndex < str.size()) {
1170 if (m_maskData[i].separator) {
1171 s += m_maskData[i].maskChar;
1172 if (str[strIndex] == m_maskData[i].maskChar)
1173 strIndex++;
1174 ++i;
1175 } else {
1176 if (isValidInput(str[strIndex], m_maskData[i].maskChar)) {
1177 switch (m_maskData[i].caseMode) {
1178 case MaskInputData::Upper:
1179 s += str[strIndex].toUpper();
1180 break;
1181 case MaskInputData::Lower:
1182 s += str[strIndex].toLower();
1183 break;
1184 default:
1185 s += str[strIndex];
1186 }
1187 ++i;
1188 } else {
1189 // search for separator first
1190 int n = findInMask(i, true, true, str[strIndex]);
1191 if (n != -1) {
1192 if (str.size() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[strIndex]))) {
1193 s += QStringView{fill}.mid(i, n - i + 1);
1194 i = n + 1; // update i to find + 1
1195 }
1196 } else {
1197 // search for valid m_blank if not
1198 n = findInMask(i, true, false, str[strIndex]);
1199 if (n != -1) {
1200 s += QStringView{fill}.mid(i, n - i);
1201 switch (m_maskData[n].caseMode) {
1202 case MaskInputData::Upper:
1203 s += str[strIndex].toUpper();
1204 break;
1205 case MaskInputData::Lower:
1206 s += str[strIndex].toLower();
1207 break;
1208 default:
1209 s += str[strIndex];
1210 }
1211 i = n + 1; // updates i to find + 1
1212 }
1213 }
1214 }
1215 ++strIndex;
1216 }
1217 } else
1218 break;
1219 }
1220
1221 return s;
1222}
1223
1224
1225
1232QString QWidgetLineControl::clearString(int pos, int len) const
1233{
1234 if (pos >= m_maxLength)
1235 return QString();
1236
1237 QString s;
1238 int end = qMin(m_maxLength, pos + len);
1239 for (int i = pos; i < end; ++i)
1240 if (m_maskData[i].separator)
1241 s += m_maskData[i].maskChar;
1242 else
1243 s += m_blank;
1244
1245 return s;
1246}
1247
1254QString QWidgetLineControl::stripString(const QString &str) const
1255{
1256 if (!m_maskData)
1257 return str;
1258
1259 QString s;
1260 int end = qMin(m_maxLength, (int)str.size());
1261 for (int i = 0; i < end; ++i)
1262 if (m_maskData[i].separator)
1263 s += m_maskData[i].maskChar;
1264 else
1265 if (str[i] != m_blank)
1266 s += str[i];
1267
1268 return s;
1269}
1270
1275int QWidgetLineControl::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
1276{
1277 if (pos >= m_maxLength || pos < 0)
1278 return -1;
1279
1280 int end = forward ? m_maxLength : -1;
1281 int step = forward ? 1 : -1;
1282 int i = pos;
1283
1284 while (i != end) {
1285 if (findSeparator) {
1286 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
1287 return i;
1288 } else {
1289 if (!m_maskData[i].separator) {
1290 if (searchChar.isNull())
1291 return i;
1292 else if (isValidInput(searchChar, m_maskData[i].maskChar))
1293 return i;
1294 }
1295 }
1296 i += step;
1297 }
1298 return -1;
1299}
1300
1301void QWidgetLineControl::internalUndo(int until)
1302{
1303 if (!isUndoAvailable())
1304 return;
1305 cancelPasswordEchoTimer();
1306 internalDeselect();
1307
1308 while (m_undoState && m_undoState > until) {
1309 Command& cmd = m_history[--m_undoState];
1310 switch (cmd.type) {
1311 case Insert:
1312 m_text.remove(cmd.pos, 1);
1313 m_cursor = cmd.pos;
1314 break;
1315 case SetSelection:
1316 m_selstart = cmd.selStart;
1317 m_selend = cmd.selEnd;
1318 m_cursor = cmd.pos;
1319 break;
1320 case Remove:
1321 case RemoveSelection:
1322 m_text.insert(cmd.pos, cmd.uc);
1323 m_cursor = cmd.pos + 1;
1324 break;
1325 case Delete:
1326 case DeleteSelection:
1327 m_text.insert(cmd.pos, cmd.uc);
1328 m_cursor = cmd.pos;
1329 break;
1330 case Separator:
1331 continue;
1332 }
1333 if (until < 0 && m_undoState) {
1334 Command& next = m_history[m_undoState-1];
1335 if (next.type != cmd.type && next.type < RemoveSelection
1336 && (cmd.type < RemoveSelection || next.type == Separator))
1337 break;
1338 }
1339 }
1340 m_textDirty = true;
1341 emitCursorPositionChanged();
1342}
1343
1344void QWidgetLineControl::internalRedo()
1345{
1346 if (!isRedoAvailable())
1347 return;
1348 internalDeselect();
1349 while (m_undoState < (int)m_history.size()) {
1350 Command& cmd = m_history[m_undoState++];
1351 switch (cmd.type) {
1352 case Insert:
1353 m_text.insert(cmd.pos, cmd.uc);
1354 m_cursor = cmd.pos + 1;
1355 break;
1356 case SetSelection:
1357 m_selstart = cmd.selStart;
1358 m_selend = cmd.selEnd;
1359 m_cursor = cmd.pos;
1360 break;
1361 case Remove:
1362 case Delete:
1363 case RemoveSelection:
1364 case DeleteSelection:
1365 m_text.remove(cmd.pos, 1);
1366 m_selstart = cmd.selStart;
1367 m_selend = cmd.selEnd;
1368 m_cursor = cmd.pos;
1369 break;
1370 case Separator:
1371 m_selstart = cmd.selStart;
1372 m_selend = cmd.selEnd;
1373 m_cursor = cmd.pos;
1374 break;
1375 }
1376 if (m_undoState < (int)m_history.size()) {
1377 Command& next = m_history[m_undoState];
1378 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
1379 && (next.type < RemoveSelection || cmd.type == Separator))
1380 break;
1381 }
1382 }
1383 m_textDirty = true;
1384 emitCursorPositionChanged();
1385}
1386
1393void QWidgetLineControl::emitCursorPositionChanged()
1394{
1395 if (m_cursor != m_lastCursorPos) {
1396 const int oldLast = m_lastCursorPos;
1397 m_lastCursorPos = m_cursor;
1398 emit cursorPositionChanged(oldLast, m_cursor);
1399#if QT_CONFIG(accessibility)
1400 // otherwise we send a selection update which includes the cursor
1401 if (!hasSelectedText()) {
1402 QAccessibleTextCursorEvent event(accessibleObject(), m_cursor);
1403 QAccessible::updateAccessibility(&event);
1404 }
1405#endif
1406 }
1407}
1408
1409#if QT_CONFIG(completer)
1410// iterating forward(dir=1)/backward(dir=-1) from the
1411// current row based. dir=0 indicates a new completion prefix was set.
1412bool QWidgetLineControl::advanceToEnabledItem(int dir)
1413{
1414 int start = m_completer->currentRow();
1415 if (start == -1)
1416 return false;
1417 int i = start + dir;
1418 if (dir == 0) dir = 1;
1419 do {
1420 if (!m_completer->setCurrentRow(i)) {
1421 if (!m_completer->wrapAround())
1422 break;
1423 i = i > 0 ? 0 : m_completer->completionCount() - 1;
1424 } else {
1425 QModelIndex currentIndex = m_completer->currentIndex();
1426 if (m_completer->completionModel()->flags(currentIndex) & Qt::ItemIsEnabled)
1427 return true;
1428 i += dir;
1429 }
1430 } while (i != start);
1431
1432 m_completer->setCurrentRow(start); // restore
1433 return false;
1434}
1435
1436void QWidgetLineControl::complete(int key)
1437{
1438 if (!m_completer || isReadOnly() || echoMode() != QLineEdit::Normal)
1439 return;
1440
1441 QString text = this->text();
1442 if (m_completer->completionMode() == QCompleter::InlineCompletion) {
1443 if (key == Qt::Key_Backspace)
1444 return;
1445 int n = 0;
1446 if (key == Qt::Key_Up || key == Qt::Key_Down) {
1447 if (textAfterSelection().size())
1448 return;
1450 : text;
1451 if (text.compare(m_completer->currentCompletion(), m_completer->caseSensitivity()) != 0
1452 || prefix.compare(m_completer->completionPrefix(), m_completer->caseSensitivity()) != 0) {
1453 m_completer->setCompletionPrefix(prefix);
1454 } else {
1455 n = (key == Qt::Key_Up) ? -1 : +1;
1456 }
1457 } else {
1458 m_completer->setCompletionPrefix(text);
1459 }
1460 if (!advanceToEnabledItem(n))
1461 return;
1462 } else {
1463#ifndef QT_KEYPAD_NAVIGATION
1464 if (text.isEmpty()) {
1465 if (auto *popup = QCompleterPrivate::get(m_completer)->popup)
1466 popup->hide();
1467 return;
1468 }
1469#endif
1470 m_completer->setCompletionPrefix(text);
1471 }
1472
1473 m_completer->complete();
1474}
1475#endif
1476
1478{
1479 if (m_readOnly == enable)
1480 return;
1481
1482 m_readOnly = enable;
1484}
1485
1500
1502{
1503 if (m_blinkTimer) {
1504 killTimer(m_blinkTimer);
1505 m_blinkTimer = 0;
1506 }
1507
1508 if (m_blinkEnabled && !m_readOnly) {
1509 int flashTime = QGuiApplication::styleHints()->cursorFlashTime();
1510 if (flashTime >= 2)
1511 m_blinkTimer = startTimer(flashTime / 2);
1512 }
1513
1514 m_blinkStatus = 1;
1515 emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect());
1516}
1517
1518// This is still used by QDeclarativeTextInput in the qtquick1 repo
1520{
1521 if (!m_blinkEnabled || m_blinkTimer == 0)
1522 return;
1523 killTimer(m_blinkTimer);
1524 m_blinkTimer = 0;
1525 int flashTime = QGuiApplication::styleHints()->cursorFlashTime();
1526 if (flashTime >= 2)
1527 m_blinkTimer = startTimer(flashTime / 2);
1528 m_blinkStatus = 1;
1529}
1530
1532{
1533 if (event->timerId() == m_blinkTimer) {
1534 m_blinkStatus = !m_blinkStatus;
1535 emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect());
1536 } else if (event->timerId() == m_deleteAllTimer) {
1537 killTimer(m_deleteAllTimer);
1538 m_deleteAllTimer = 0;
1539 clear();
1540 } else if (event->timerId() == m_tripleClickTimer) {
1541 killTimer(m_tripleClickTimer);
1542 m_tripleClickTimer = 0;
1543 } else if (event->timerId() == m_passwordEchoTimer) {
1544 killTimer(m_passwordEchoTimer);
1545 m_passwordEchoTimer = 0;
1546 updateDisplayText();
1547 }
1548}
1549
1550#ifndef QT_NO_SHORTCUT
1552{
1553 if (ke == QKeySequence::Copy
1569 ke->accept();
1570 } else if (ke == QKeySequence::Paste
1571 || ke == QKeySequence::Cut
1572 || ke == QKeySequence::Redo
1573 || ke == QKeySequence::Undo
1575 if (!isReadOnly())
1576 ke->accept();
1577 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1578 || ke->modifiers() == Qt::KeypadModifier) {
1579 if (ke->key() < Qt::Key_Escape) {
1580 if (!isReadOnly())
1581 ke->accept();
1582 } else {
1583 switch (ke->key()) {
1584 case Qt::Key_Delete:
1585 case Qt::Key_Backspace:
1586 if (!isReadOnly())
1587 ke->accept();
1588 break;
1589
1590 case Qt::Key_Home:
1591 case Qt::Key_End:
1592 case Qt::Key_Left:
1593 case Qt::Key_Right:
1594 ke->accept();
1595 break;
1596
1597 default:
1598 break;
1599 }
1600 }
1601 }
1602}
1603#endif
1604
1606{
1607 bool inlineCompletionAccepted = false;
1608
1609#if QT_CONFIG(completer)
1610 if (m_completer) {
1611 QCompleter::CompletionMode completionMode = m_completer->completionMode();
1612 auto *popup = QCompleterPrivate::get(m_completer)->popup;
1613 if ((completionMode == QCompleter::PopupCompletion
1614 || completionMode == QCompleter::UnfilteredPopupCompletion)
1615 && popup && popup->isVisible()) {
1616 // The following keys are forwarded by the completer to the widget
1617 // Ignoring the events lets the completer provide suitable default behavior
1618 switch (event->key()) {
1619 case Qt::Key_Escape:
1620 event->ignore();
1621 return;
1622 default:
1623 break; // normal key processing
1624 }
1625 } else if (completionMode == QCompleter::InlineCompletion) {
1626 switch (event->key()) {
1627 case Qt::Key_Enter:
1628 case Qt::Key_Return:
1629 case Qt::Key_F4:
1630#ifdef QT_KEYPAD_NAVIGATION
1631 case Qt::Key_Select:
1632 if (!QApplicationPrivate::keypadNavigationEnabled())
1633 break;
1634#endif
1635 if (!m_completer->currentCompletion().isEmpty() && hasSelectedText()
1636 && !m_completer->completionPrefix().isEmpty()
1637 && textAfterSelection().isEmpty()) {
1638 setText(m_completer->currentCompletion());
1639 inlineCompletionAccepted = true;
1640 }
1641 break;
1642 default:
1643 break; // normal key processing
1644 }
1645 }
1646 }
1647#endif // QT_CONFIG(completer)
1648
1649 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
1650 if (hasAcceptableInput() || fixup()) {
1651
1653 inputMethod->commit();
1656 inputMethod->hide();
1657
1658 emit accepted();
1660 }
1661 if (inlineCompletionAccepted)
1662 event->accept();
1663 else
1664 event->ignore();
1665 return;
1666 }
1667
1670 && !isReadOnly()
1671 && !event->text().isEmpty()
1672#ifdef QT_KEYPAD_NAVIGATION
1673 && event->key() != Qt::Key_Select
1674 && event->key() != Qt::Key_Up
1675 && event->key() != Qt::Key_Down
1676 && event->key() != Qt::Key_Back
1677#endif
1678 && !(event->modifiers() & Qt::ControlModifier)) {
1679 // Clear the edit and reset to normal echo mode while editing; the
1680 // echo mode switches back when the edit loses focus
1681 // ### resets current content. dubious code; you can
1682 // navigate with keys up, down, back, and select(?), but if you press
1683 // "left" or "right" it clears?
1685 clear();
1686 }
1687
1688 bool unknown = false;
1689#if QT_CONFIG(shortcut)
1690 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
1691#endif
1692
1693 if (false) {
1694 }
1695#ifndef QT_NO_SHORTCUT
1696 else if (event == QKeySequence::Undo) {
1697 if (!isReadOnly())
1698 undo();
1699 }
1700 else if (event == QKeySequence::Redo) {
1701 if (!isReadOnly())
1702 redo();
1703 }
1704 else if (event == QKeySequence::SelectAll) {
1705 selectAll();
1706 }
1707#ifndef QT_NO_CLIPBOARD
1708 else if (event == QKeySequence::Copy) {
1709 copy();
1710 }
1711 else if (event == QKeySequence::Paste) {
1712 if (!isReadOnly()) {
1714 if (m_keyboardScheme == QPlatformTheme::X11KeyboardScheme
1715 && event->modifiers() == (Qt::CTRL | Qt::SHIFT)
1716 && event->key() == Qt::Key_Insert) {
1718 }
1719 paste(mode);
1720 }
1721 }
1722 else if (event == QKeySequence::Cut) {
1723 if (!isReadOnly() && hasSelectedText()) {
1724 copy();
1725 del();
1726 }
1727 }
1729 if (!isReadOnly()) {
1730 setSelection(cursor(), end());
1731 copy();
1732 del();
1733 }
1734 }
1735#endif //QT_NO_CLIPBOARD
1737 home(0);
1738 }
1740 end(0);
1741 }
1743 home(1);
1744 }
1746 end(1);
1747 }
1748 else if (event == QKeySequence::MoveToNextChar) {
1749#if !QT_CONFIG(completer)
1750 const bool inlineCompletion = false;
1751#else
1752 const bool inlineCompletion = m_completer && m_completer->completionMode() == QCompleter::InlineCompletion;
1753#endif
1754 if (hasSelectedText()
1755 && (m_keyboardScheme != QPlatformTheme::WindowsKeyboardScheme
1756 || inlineCompletion)) {
1757 moveCursor(selectionEnd(), false);
1758 } else {
1759 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
1760 }
1761 }
1762 else if (event == QKeySequence::SelectNextChar) {
1763 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
1764 }
1766#if !QT_CONFIG(completer)
1767 const bool inlineCompletion = false;
1768#else
1769 const bool inlineCompletion = m_completer && m_completer->completionMode() == QCompleter::InlineCompletion;
1770#endif
1771 if (hasSelectedText()
1772 && (m_keyboardScheme != QPlatformTheme::WindowsKeyboardScheme
1773 || inlineCompletion)) {
1774 moveCursor(selectionStart(), false);
1775 } else {
1776 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
1777 }
1778 }
1780 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
1781 }
1782 else if (event == QKeySequence::MoveToNextWord) {
1783 if (echoMode() == QLineEdit::Normal)
1785 else
1786 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
1787 }
1789 if (echoMode() == QLineEdit::Normal)
1791 else if (!isReadOnly()) {
1792 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
1793 }
1794 }
1795 else if (event == QKeySequence::SelectNextWord) {
1796 if (echoMode() == QLineEdit::Normal)
1798 else
1799 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
1800 }
1802 if (echoMode() == QLineEdit::Normal)
1804 else
1805 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
1806 }
1807 else if (event == QKeySequence::Delete) {
1808 if (!isReadOnly())
1809 del();
1810 }
1812 if (!isReadOnly()) {
1813 if (!hasSelectedText())
1814 cursorWordForward(true);
1815
1816 if (hasSelectedText())
1817 del();
1818 }
1819 }
1821 if (!isReadOnly()) {
1822 if (!hasSelectedText())
1823 cursorWordBackward(true);
1824
1825 if (hasSelectedText())
1826 del();
1827 }
1829 if (!isReadOnly()) {
1830 setSelection(0, text().size());
1831#ifndef QT_NO_CLIPBOARD
1832 copy();
1833#endif
1834 del();
1835 }
1836 }
1837#endif // QT_NO_SHORTCUT
1838 else {
1839 bool handled = false;
1840 if (m_keyboardScheme == QPlatformTheme::MacKeyboardScheme
1841 && (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down)) {
1842 Qt::KeyboardModifiers myModifiers = (event->modifiers() & ~Qt::KeypadModifier);
1843 if (myModifiers & Qt::ShiftModifier) {
1844 if (myModifiers == (Qt::ControlModifier|Qt::ShiftModifier)
1845 || myModifiers == (Qt::AltModifier|Qt::ShiftModifier)
1846 || myModifiers == Qt::ShiftModifier) {
1847
1848 event->key() == Qt::Key_Up ? home(1) : end(1);
1849 }
1850 } else {
1851 if ((myModifiers == Qt::ControlModifier
1852 || myModifiers == Qt::AltModifier
1853 || myModifiers == Qt::NoModifier)) {
1854 event->key() == Qt::Key_Up ? home(0) : end(0);
1855 }
1856 }
1857 handled = true;
1858 }
1859 if (event->modifiers() & Qt::ControlModifier) {
1860 switch (event->key()) {
1861 case Qt::Key_Backspace:
1862 if (!isReadOnly()) {
1863 cursorWordBackward(true);
1864 del();
1865 }
1866 break;
1867#if QT_CONFIG(completer)
1868 case Qt::Key_Up:
1869 case Qt::Key_Down:
1870 complete(event->key());
1871 break;
1872#endif
1873 default:
1874 if (!handled)
1875 unknown = true;
1876 }
1877 } else { // ### check for *no* modifier
1878 switch (event->key()) {
1879 case Qt::Key_Backspace:
1880 if (!isReadOnly()) {
1881 backspace();
1882#if QT_CONFIG(completer)
1883 complete(Qt::Key_Backspace);
1884#endif
1885 }
1886 break;
1887#ifdef QT_KEYPAD_NAVIGATION
1888 case Qt::Key_Back:
1889 if (QApplicationPrivate::keypadNavigationEnabled() && !event->isAutoRepeat()
1890 && !isReadOnly()) {
1891 if (text().length() == 0) {
1892 setText(m_cancelText);
1893
1894 if (passwordEchoEditing())
1896
1897 emit editFocusChange(false);
1898 } else if (!m_deleteAllTimer) {
1899 m_deleteAllTimer = startTimer(750);
1900 }
1901 } else {
1902 unknown = true;
1903 }
1904 break;
1905#endif
1906 default:
1907 if (!handled)
1908 unknown = true;
1909 }
1910 }
1911 }
1912
1913 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
1915 unknown = false;
1916 }
1917
1918 if (unknown
1919 && !isReadOnly()
1921 insert(event->text());
1922#if QT_CONFIG(completer)
1923 complete(event->key());
1924#endif
1925 event->accept();
1926 return;
1927 }
1928
1929 if (unknown) {
1930 event->ignore();
1931 } else {
1932#ifndef QT_NO_CLIPBOARD
1933 if (QApplication::clipboard()->supportsSelection())
1935#endif
1936 event->accept();
1937 }
1938}
1939
1941{
1942 // For security reasons undo is not available in any password mode (NoEcho included)
1943 // with the exception that the user can clear the password with undo.
1944 return !m_readOnly && m_undoState
1945 && (m_echoMode == QLineEdit::Normal || m_history[m_undoState - 1].type == QWidgetLineControl::Insert);
1946}
1947
1949{
1950 // Same as with undo. Disabled for password modes.
1951 return !m_readOnly
1952 && m_echoMode == QLineEdit::Normal
1953 && m_undoState < int(m_history.size());
1954}
1955
1957
1958#include "moc_qwidgetlinecontrol_p.cpp"
virtual Q_INVOKABLE Qt::ItemFlags flags(const QModelIndex &index) const
Returns the item flags for the given index.
\inmodule QtCore
Mode
\keyword clipboard mode
Definition qclipboard.h:27
static QCompleterPrivate * get(QCompleter *o)
int completionCount() const
Returns the number of completions for the current prefix.
CompletionMode
This enum specifies how completions are provided to the user.
Definition qcompleter.h:37
@ PopupCompletion
Definition qcompleter.h:38
@ InlineCompletion
Definition qcompleter.h:40
@ UnfilteredPopupCompletion
Definition qcompleter.h:39
bool wrapAround
the completions wrap around when navigating through items
Definition qcompleter.h:34
QString completionPrefix
the completion prefix used to provide completions.
Definition qcompleter.h:26
bool setCurrentRow(int row)
Sets the current row to the row specified.
Qt::CaseSensitivity caseSensitivity
the case sensitivity of the matching
Definition qcompleter.h:33
void complete(const QRect &rect=QRect())
For QCompleter::PopupCompletion and QCompletion::UnfilteredPopupCompletion modes, calling this functi...
QModelIndex currentIndex() const
Returns the model index of the current completion in the completionModel().
QString currentCompletion() const
Returns the current completion string.
CompletionMode completionMode
how the completions are provided to the user
Definition qcompleter.h:29
void setCompletionPrefix(const QString &prefix)
QAbstractItemModel * completionModel() const
Returns the completion model.
int currentRow() const
Returns the current row.
static QPlatformTheme * platformTheme()
static QClipboard * clipboard()
Returns the object for interacting with the clipboard.
static QStyleHints * styleHints()
Returns the application's style hints.
static QInputMethod * inputMethod()
returns the input method.
bool isAcceptableInput(const QKeyEvent *event) const
The QInputMethodEvent class provides parameters for input method events.
Definition qevent.h:625
The QInputMethod class provides access to the active text input method.
void hide()
Requests virtual keyboard to close.
void commit()
Commits the word user is currently composing to the editor.
The QKeyEvent class describes a key event.
Definition qevent.h:424
@ PasswordEchoOnEdit
Definition qlineedit.h:77
qsizetype size() const noexcept
Definition qlist.h:397
\inmodule QtCore
int startTimer(int interval, Qt::TimerType timerType=Qt::CoarseTimer)
This is an overloaded function that will start a timer of type timerType and a timeout of interval mi...
Definition qobject.cpp:1817
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
void killTimer(int id)
Kills the timer with timer identifier, id.
Definition qobject.cpp:1912
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
const QBrush & brush(ColorGroup cg, ColorRole cr) const
Returns the brush in the specified color group, used for the given color role.
Definition qpalette.cpp:748
@ HighlightedText
Definition qpalette.h:53
@ Highlight
Definition qpalette.h:53
The QPlatformTheme class allows customizing the UI based on themes.
\inmodule QtCore\reentrant
Definition qpoint.h:25
\inmodule QtCore\reentrant
Definition qrect.h:30
\inmodule QtCore
Definition qstringview.h:78
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString left(qsizetype n) const &
Definition qstring.h:363
QString & fill(QChar c, qsizetype size=-1)
Sets every character in the string to character ch.
Definition qstring.cpp:6358
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3824
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5300
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
int compare(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.cpp:6664
QString & insert(qsizetype i, QChar c)
Definition qstring.cpp:3132
QString toLower() const &
Definition qstring.h:435
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1240
QString & remove(qsizetype i, qsizetype len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
Definition qstring.cpp:3466
QString toUpper() const &
Definition qstring.h:439
void cursorFlashTimeChanged(int cursorFlashTime)
QTextCharFormat toCharFormat() const
Returns this format as a character format.
const QTextOption & textOption() const
Returns the current text option used to control the layout process.
QTextLine createLine()
Returns a new text line to be laid out if there is text to be inserted into the layout; otherwise ret...
void beginLayout()
Begins the layout process.
void setCacheEnabled(bool enable)
Enables caching of the complete layout information if enable is true; otherwise disables layout cachi...
void setFormats(const QList< FormatRange > &overrides)
void setText(const QString &string)
Sets the layout's text to the given string.
QString text() const
Returns the layout's text.
void clearFormats()
int previousCursorPosition(int oldPos, CursorMode mode=SkipCharacters) const
Returns the first valid cursor position before oldPos that respects the given cursor mode.
QTextLine lineAt(int i) const
Returns the {i}-th line of text in this text layout.
int nextCursorPosition(int oldPos, CursorMode mode=SkipCharacters) const
Returns the next valid cursor position after oldPos that respects the given cursor mode.
void setTextOption(const QTextOption &option)
Sets the text option structure that controls the layout process to the given option.
void draw(QPainter *p, const QPointF &pos, const QList< FormatRange > &selections=QList< FormatRange >(), const QRectF &clip=QRectF()) const
Draws the whole layout on the painter p at the position specified by pos.
void endLayout()
Ends the layout process.
void clearLayout()
void drawCursor(QPainter *p, const QPointF &pos, int cursorPosition) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
\reentrant
qreal height() const
Returns the line's height.
qreal cursorToX(int *cursorPos, Edge edge=Leading) const
Converts the cursor position cursorPos to the corresponding x position inside the line,...
CursorPosition
\value CursorBetweenCharacters \value CursorOnCharacter
qreal ascent() const
Returns the line's ascent.
int xToCursor(qreal x, CursorPosition=CursorBetweenCharacters) const
Converts the x-coordinate x, to the nearest matching cursor position, depending on the cursor positio...
\reentrant
Definition qtextoption.h:18
void setTextDirection(Qt::LayoutDirection aDirection)
Sets the direction of the text layout defined by the option to the given direction.
Definition qtextoption.h:57
@ IncludeTrailingSpaces
Definition qtextoption.h:76
\inmodule QtCore
Definition qcoreevent.h:366
virtual void fixup(QString &) const
This function attempts to change input to be valid according to this validator's rules.
virtual State validate(QString &, int &) const =0
This virtual function returns \l Invalid if input is invalid according to this validator's rules,...
void setText(const QString &txt)
void cursorWordForward(bool mark)
void updatePasswordEchoEditing(bool editing)
void moveCursor(int pos, bool mark=false)
void cursorWordBackward(bool mark)
int xToPos(int x, QTextLine::CursorPosition=QTextLine::CursorBetweenCharacters) const
virtual void timerEvent(QTimerEvent *event) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
void paste(QClipboard::Mode mode=QClipboard::Clipboard)
void cursorForward(bool mark, int steps)
void setPreeditArea(int cursor, const QString &text)
void processKeyEvent(QKeyEvent *ev)
void displayTextChanged(const QString &)
void setSelection(int start, int length)
void setBlinkingCursorEnabled(bool enable)
void setLayoutDirection(Qt::LayoutDirection direction)
QTextLayout * textLayout() const
void textChanged(const QString &)
void setReadOnly(bool enable)
void textEdited(const QString &)
QString textBeforeSelection() const
QString textAfterSelection() const
void cursorPositionChanged(int, int)
void processShortcutOverrideEvent(QKeyEvent *ke)
QRect rectForPos(int pos) const
QString selectedText() const
void insert(const QString &)
void updateNeeded(const QRect &)
void processInputMethodEvent(QInputMethodEvent *event)
QString preeditAreaText() const
void copy(QClipboard::Mode mode=QClipboard::Clipboard) const
Qt::CursorMoveStyle cursorMoveStyle() const
void draw(QPainter *, const QPoint &, const QRect &, int flags=DrawAll)
Qt::LayoutDirection layoutDirection() const
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
Qt::InputMethodHints inputMethodHints
What input method specific hints the widget has.
Definition qwidget.h:178
QString str
[2]
b clear()
QCursor cursor
short next
Definition keywords.cpp:445
EGLint EGLint * formats
Combined button and popup list for selecting options.
Definition qcompare.h:63
@ CTRL
@ SHIFT
@ LeftToRight
@ RightToLeft
@ ImhMultiLine
@ Key_Escape
Definition qnamespace.h:663
@ Key_Select
@ Key_Return
Definition qnamespace.h:667
@ Key_Right
Definition qnamespace.h:679
@ Key_Enter
Definition qnamespace.h:668
@ Key_Backspace
Definition qnamespace.h:666
@ Key_Direction_L
Definition qnamespace.h:731
@ Key_Insert
Definition qnamespace.h:669
@ Key_Left
Definition qnamespace.h:677
@ Key_Up
Definition qnamespace.h:678
@ Key_Down
Definition qnamespace.h:680
@ Key_F4
Definition qnamespace.h:693
@ Key_Delete
Definition qnamespace.h:670
@ Key_Direction_R
Definition qnamespace.h:732
@ Key_Back
Definition qnamespace.h:846
@ Key_Home
Definition qnamespace.h:675
@ Key_End
Definition qnamespace.h:676
@ ShiftModifier
@ ControlModifier
@ KeypadModifier
@ NoModifier
@ AltModifier
@ VisualMoveStyle
@ ItemIsEnabled
#define Q_FALLTHROUGH()
#define Q_UNLIKELY(x)
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
#define qWarning
Definition qlogging.h:166
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLint GLint GLint GLint GLint x
[0]
GLenum mode
const GLfloat * m
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLfloat GLfloat f
GLenum type
GLbitfield flags
GLboolean enable
GLuint start
GLenum GLuint GLintptr offset
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLfloat n
struct _cl_event * event
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint GLenum option
GLenum GLsizei len
void forceUpdate(QQuickItem *item)
static const struct ImageFormatTab unknown[]
QT_BEGIN_NAMESPACE constexpr void qSwap(T &value1, T &value2) noexcept(std::is_nothrow_swappable_v< T >)
Definition qswap.h:20
#define emit
#define Q_UNUSED(x)
ptrdiff_t qsizetype
Definition qtypes.h:165
static QString escape(const QString &input)
QWidget * qobject_cast< QWidget * >(QObject *o)
Definition qwidget.h:786
QLineEdit * lineEdit
myObject disconnect()
[26]
ba fill(true)
QString dir
[11]
Text files * txt
QPainter painter(this)
[7]
QAction * at