1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qlinecontrol_p.h"
44 #ifndef QT_NO_LINEEDIT
46 #include "qabstractitemview.h"
47 #include "qclipboard.h"
48 #ifndef QT_NO_ACCESSIBILITY
49 #include "qaccessible.h"
52 #include "qinputcontext.h"
55 #include "qapplication.h"
56 #ifndef QT_NO_GRAPHICSVIEW
57 #include "qgraphicssceneevent.h"
62 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
63 static int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY;
67 \macro QT_GUI_PASSWORD_ECHO_DELAY
71 Defines the amount of time in milliseconds the last entered character
72 should be displayed unmasked in the Password echo mode.
74 If not defined in qplatformdefs.h there will be no delay in masking
81 Updates the display text based of the current edit text
82 If the text has changed will emit displayTextChanged()
84 void QLineControl::updateDisplayText(bool forceUpdate)
86 QString orig = m_textLayout.text();
88 if (m_echoMode == QLineEdit::NoEcho)
89 str = QString::fromLatin1("");
93 if (m_echoMode == QLineEdit::Password) {
94 str.fill(m_passwordCharacter);
95 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
96 if (m_passwordEchoTimer != 0 && !str.isEmpty()) {
97 int cursor = m_text.length() - 1;
98 QChar uc = m_text.at(cursor);
100 if (cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
101 // second half of a surrogate, check if we have the first half as well,
102 // if yes restore both at once
103 uc = m_text.at(cursor - 1);
104 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
105 str[cursor - 1] = uc;
109 } else if (m_echoMode == QLineEdit::PasswordEchoOnEdit && !m_passwordEchoEditing) {
110 str.fill(m_passwordCharacter);
113 // replace certain non-printable characters with spaces (to avoid
114 // drawing boxes when using fonts that don't have glyphs for such
116 QChar* uc = str.data();
117 for (int i = 0; i < (int)str.length(); ++i) {
118 if ((uc[i] < 0x20 && uc[i] != 0x09)
119 || uc[i] == QChar::LineSeparator
120 || uc[i] == QChar::ParagraphSeparator
121 || uc[i] == QChar::ObjectReplacementCharacter)
122 uc[i] = QChar(0x0020);
125 m_textLayout.setText(str);
128 option.setTextDirection(m_layoutDirection);
129 option.setFlags(QTextOption::IncludeTrailingSpaces);
130 m_textLayout.setTextOption(option);
132 m_textLayout.beginLayout();
133 QTextLine l = m_textLayout.createLine();
134 m_textLayout.endLayout();
135 m_ascent = qRound(l.ascent());
137 if (str != orig || forceUpdate)
138 emit displayTextChanged(str);
141 #ifndef QT_NO_CLIPBOARD
145 Copies the currently selected text into the clipboard using the given
148 \note If the echo mode is set to a mode other than Normal then copy
149 will not work. This is to prevent using copy as a method of bypassing
150 password features of the line control.
152 void QLineControl::copy(QClipboard::Mode mode) const
154 QString t = selectedText();
155 if (!t.isEmpty() && m_echoMode == QLineEdit::Normal) {
156 disconnect(QApplication::clipboard(), SIGNAL(selectionChanged()), this, 0);
157 QApplication::clipboard()->setText(t, mode);
158 connect(QApplication::clipboard(), SIGNAL(selectionChanged()),
159 this, SLOT(_q_clipboardChanged()));
166 Inserts the text stored in the application clipboard into the line
171 void QLineControl::paste(QClipboard::Mode clipboardMode)
173 QString clip = QApplication::clipboard()->text(clipboardMode);
174 if (!clip.isEmpty() || hasSelectedText()) {
175 separate(); //make it a separate undo/redo command
181 #endif // !QT_NO_CLIPBOARD
186 Handles the behavior for the backspace key or function.
187 Removes the current selection if there is a selection, otherwise
188 removes the character prior to the cursor position.
192 void QLineControl::backspace()
194 int priorState = m_undoState;
195 if (hasSelectedText()) {
196 removeSelectedText();
197 } else if (m_cursor) {
200 m_cursor = prevMaskBlank(m_cursor);
201 QChar uc = m_text.at(m_cursor);
202 if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
203 // second half of a surrogate, check if we have the first half as well,
204 // if yes delete both at once
205 uc = m_text.at(m_cursor - 1);
206 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
207 internalDelete(true);
211 internalDelete(true);
213 finishChange(priorState);
219 Handles the behavior for the delete key or function.
220 Removes the current selection if there is a selection, otherwise
221 removes the character after the cursor position.
225 void QLineControl::del()
227 int priorState = m_undoState;
228 if (hasSelectedText()) {
229 removeSelectedText();
231 int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
235 finishChange(priorState);
241 Inserts the given \a newText at the current cursor position.
242 If there is any selected text it is removed prior to insertion of
245 void QLineControl::insert(const QString &newText)
247 int priorState = m_undoState;
248 removeSelectedText();
249 internalInsert(newText);
250 finishChange(priorState);
256 Clears the line control text.
258 void QLineControl::clear()
260 int priorState = m_undoState;
262 m_selend = m_text.length();
263 removeSelectedText();
265 finishChange(priorState, /*update*/false, /*edited*/false);
271 Sets \a length characters from the given \a start position as selected.
272 The given \a start position must be within the current text for
273 the line control. If \a length characters cannot be selected, then
274 the selection will extend to the end of the current text.
276 void QLineControl::setSelection(int start, int length)
278 if(start < 0 || start > (int)m_text.length()){
279 qWarning("QLineControl::setSelection: Invalid start position");
284 m_selDirty |= (start != m_selstart || start + length != m_selend);
286 m_selend = qMin(start + length, (int)m_text.length());
288 } else if (length < 0){
289 m_selDirty |= (start != m_selend || start + length != m_selstart);
290 m_selstart = qMax(start + length, 0);
292 m_cursor = m_selstart;
293 } else if (m_selstart != m_selend) {
303 emit selectionChanged();
305 emitCursorPositionChanged();
308 void QLineControl::_q_clipboardChanged()
312 void QLineControl::_q_deleteSelected()
314 if (!hasSelectedText())
317 int priorState = m_undoState;
318 emit resetInputContext();
319 removeSelectedText();
321 finishChange(priorState);
327 Initializes the line control with a starting text value of \a txt.
329 void QLineControl::init(const QString &txt)
333 m_cursor = m_text.length();
339 Sets the password echo editing to \a editing. If password echo editing
340 is true, then the text of the password is displayed even if the echo
341 mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing
342 does not affect other echo modes.
344 void QLineControl::updatePasswordEchoEditing(bool editing)
346 cancelPasswordEchoTimer();
347 m_passwordEchoEditing = editing;
354 Returns the cursor position of the given \a x pixel value in relation
355 to the displayed text. The given \a betweenOrOn specified what kind
356 of cursor position is requested.
358 int QLineControl::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const
360 return m_textLayout.lineAt(0).xToCursor(x, betweenOrOn);
366 Returns the bounds of the current cursor, as defined as a
367 between characters cursor.
369 QRect QLineControl::cursorRect() const
371 QTextLine l = m_textLayout.lineAt(0);
373 if (m_preeditCursor != -1)
374 c += m_preeditCursor;
375 int cix = qRound(l.cursorToX(c));
376 int w = m_cursorWidth;
377 int ch = l.height() + 1;
379 return QRect(cix-5, 0, w+9, ch);
385 Fixes the current text so that it is valid given any set validators.
387 Returns true if the text was changed. Otherwise returns false.
389 bool QLineControl::fixup() // this function assumes that validate currently returns != Acceptable
391 #ifndef QT_NO_VALIDATOR
393 QString textCopy = m_text;
394 int cursorCopy = m_cursor;
395 m_validator->fixup(textCopy);
396 if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
397 if (textCopy != m_text || cursorCopy != m_cursor)
398 internalSetText(textCopy, cursorCopy);
409 Moves the cursor to the given position \a pos. If \a mark is true will
410 adjust the currently selected text.
412 void QLineControl::moveCursor(int pos, bool mark)
414 if (pos != m_cursor) {
417 pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
421 if (m_selend > m_selstart && m_cursor == m_selstart)
423 else if (m_selend > m_selstart && m_cursor == m_selend)
427 m_selstart = qMin(anchor, pos);
428 m_selend = qMax(anchor, pos);
434 if (mark || m_selDirty) {
436 emit selectionChanged();
438 emitCursorPositionChanged();
444 Applies the given input method event \a event to the text of the line
447 void QLineControl::processInputMethodEvent(QInputMethodEvent *event)
450 bool isGettingInput = !event->commitString().isEmpty()
451 || event->preeditString() != preeditAreaText()
452 || event->replacementLength() > 0;
453 bool cursorPositionChanged = false;
455 if (isGettingInput) {
456 // If any text is being input, remove selected text.
457 priorState = m_undoState;
458 if (echoMode() == QLineEdit::PasswordEchoOnEdit && !passwordEchoEditing()) {
459 updatePasswordEchoEditing(true);
461 m_selend = m_text.length();
463 removeSelectedText();
466 int c = m_cursor; // cursor position after insertion of commit string
467 if (event->replacementStart() <= 0)
468 c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
470 m_cursor += event->replacementStart();
474 // insert commit string
475 if (event->replacementLength()) {
476 m_selstart = m_cursor;
477 m_selend = m_selstart + event->replacementLength();
478 removeSelectedText();
480 if (!event->commitString().isEmpty()) {
481 internalInsert(event->commitString());
482 cursorPositionChanged = true;
485 m_cursor = qBound(0, c, m_text.length());
487 for (int i = 0; i < event->attributes().size(); ++i) {
488 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
489 if (a.type == QInputMethodEvent::Selection) {
490 m_cursor = qBound(0, a.start + a.length, m_text.length());
492 m_selstart = qMax(0, qMin(a.start, m_text.length()));
494 if (m_selend < m_selstart) {
495 qSwap(m_selstart, m_selend);
499 m_selstart = m_selend = 0;
501 cursorPositionChanged = true;
505 setPreeditArea(m_cursor, event->preeditString());
507 const int oldPreeditCursor = m_preeditCursor;
508 m_preeditCursor = event->preeditString().length();
509 m_hideCursor = false;
510 QList<QTextLayout::FormatRange> formats;
511 for (int i = 0; i < event->attributes().size(); ++i) {
512 const QInputMethodEvent::Attribute &a = event->attributes().at(i);
513 if (a.type == QInputMethodEvent::Cursor) {
514 m_preeditCursor = a.start;
515 m_hideCursor = !a.length;
516 } else if (a.type == QInputMethodEvent::TextFormat) {
517 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
519 QTextLayout::FormatRange o;
520 o.start = a.start + m_cursor;
527 m_textLayout.setAdditionalFormats(formats);
528 updateDisplayText(/*force*/ true);
529 if (isGettingInput) {
530 finishChange(priorState);
532 if (cursorPositionChanged)
533 emitCursorPositionChanged();
534 else if (m_preeditCursor != oldPreeditCursor)
535 emit updateMicroFocus();
538 emit selectionChanged();
546 Draws the display text for the line control using the given
547 \a painter, \a clip, and \a offset. Which aspects of the display text
548 are drawn is specified by the given \a flags.
550 If the flags contain DrawSelections, then the selection or input mask
551 backgrounds and foregrounds will be applied before drawing the text.
553 If the flags contain DrawCursor a cursor of the current cursorWidth()
554 will be drawn after drawing the text.
556 The display text will only be drawn if the flags contain DrawText
558 void QLineControl::draw(QPainter *painter, const QPoint &offset, const QRect &clip, int flags)
560 QVector<QTextLayout::FormatRange> selections;
561 if (flags & DrawSelections) {
562 QTextLayout::FormatRange o;
563 if (m_selstart < m_selend) {
564 o.start = m_selstart;
565 o.length = m_selend - m_selstart;
566 o.format.setBackground(m_palette.brush(QPalette::Highlight));
567 o.format.setForeground(m_palette.brush(QPalette::HighlightedText));
570 if(!m_blinkPeriod || m_blinkStatus){
573 o.format.setBackground(m_palette.brush(QPalette::Text));
574 o.format.setForeground(m_palette.brush(QPalette::Window));
577 selections.append(o);
580 if (flags & DrawText)
581 m_textLayout.draw(painter, offset, selections, clip);
583 if (flags & DrawCursor){
584 int cursor = m_cursor;
585 if (m_preeditCursor != -1)
586 cursor += m_preeditCursor;
587 if (!m_hideCursor && (!m_blinkPeriod || m_blinkStatus))
588 m_textLayout.drawCursor(painter, offset, cursor, m_cursorWidth);
595 Sets the selection to cover the word at the given cursor position.
596 The word boundaries are defined by the behavior of QTextLayout::SkipWords
599 void QLineControl::selectWordAtPos(int cursor)
601 int next = cursor + 1;
604 int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
605 moveCursor(c, false);
606 // ## text layout should support end of words.
607 int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
608 while (end > cursor && m_text[end-1].isSpace())
610 moveCursor(end, true);
616 Completes a change to the line control text. If the change is not valid
617 will undo the line control state back to the given \a validateFromState.
619 If \a edited is true and the change is valid, will emit textEdited() in
620 addition to textChanged(). Otherwise only emits textChanged() on a valid
623 The \a update value is currently unused.
625 bool QLineControl::finishChange(int validateFromState, bool update, bool edited)
628 bool lineDirty = m_selDirty;
631 bool wasValidInput = m_validInput;
633 #ifndef QT_NO_VALIDATOR
635 m_validInput = false;
636 QString textCopy = m_text;
637 int cursorCopy = m_cursor;
638 m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
640 if (m_text != textCopy) {
641 internalSetText(textCopy, cursorCopy);
644 m_cursor = cursorCopy;
648 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
649 if (m_transactions.count())
651 internalUndo(validateFromState);
652 m_history.resize(m_undoState);
653 if (m_modifiedState > m_undoState)
654 m_modifiedState = -1;
659 lineDirty |= m_textDirty;
662 QString actualText = text();
664 emit textEdited(actualText);
665 emit textChanged(actualText);
670 emit selectionChanged();
672 emitCursorPositionChanged();
679 An internal function for setting the text of the line control.
681 void QLineControl::internalSetText(const QString &txt, int pos, bool edited)
683 cancelPasswordEchoTimer();
685 emit resetInputContext();
686 QString oldText = m_text;
688 m_text = maskString(0, txt, true);
689 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
691 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
694 m_modifiedState = m_undoState = 0;
695 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
696 m_textDirty = (oldText != m_text);
697 bool changed = finishChange(-1, true, edited);
699 #ifndef QT_NO_ACCESSIBILITY
701 QAccessible::updateAccessibility(parent(), 0, QAccessible::TextUpdated);
709 Adds the given \a command to the undo history
710 of the line control. Does not apply the command.
712 void QLineControl::addCommand(const Command &cmd)
714 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
715 m_history.resize(m_undoState + 2);
716 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
718 m_history.resize(m_undoState + 1);
721 m_history[m_undoState++] = cmd;
727 Inserts the given string \a s into the line
730 Also adds the appropriate commands into the undo history.
731 This function does not call finishChange(), and may leave the text
734 void QLineControl::internalInsert(const QString &s)
736 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
737 if (m_echoMode == QLineEdit::Password) {
738 if (m_passwordEchoTimer != 0)
739 killTimer(m_passwordEchoTimer);
740 m_passwordEchoTimer = startTimer(qt_passwordEchoDelay);
743 if (hasSelectedText())
744 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
746 QString ms = maskString(m_cursor, s);
747 for (int i = 0; i < (int) ms.length(); ++i) {
748 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
749 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
751 m_text.replace(m_cursor, ms.length(), ms);
752 m_cursor += ms.length();
753 m_cursor = nextMaskBlank(m_cursor);
756 int remaining = m_maxLength - m_text.length();
757 if (remaining != 0) {
758 m_text.insert(m_cursor, s.left(remaining));
759 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
760 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
769 deletes a single character from the current text. If \a wasBackspace,
770 the character prior to the cursor is removed. Otherwise the character
771 after the cursor is removed.
773 Also adds the appropriate commands into the undo history.
774 This function does not call finishChange(), and may leave the text
777 void QLineControl::internalDelete(bool wasBackspace)
779 if (m_cursor < (int) m_text.length()) {
780 cancelPasswordEchoTimer();
781 if (hasSelectedText())
782 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
783 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
784 m_cursor, m_text.at(m_cursor), -1, -1));
786 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
787 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
789 m_text.remove(m_cursor, 1);
798 removes the currently selected text from the line control.
800 Also adds the appropriate commands into the undo history.
801 This function does not call finishChange(), and may leave the text
804 void QLineControl::removeSelectedText()
806 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
807 cancelPasswordEchoTimer();
810 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
811 if (m_selstart <= m_cursor && m_cursor < m_selend) {
812 // cursor is within the selection. Split up the commands
813 // to be able to restore the correct cursor position
814 for (i = m_cursor; i >= m_selstart; --i)
815 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
816 for (i = m_selend - 1; i > m_cursor; --i)
817 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
819 for (i = m_selend-1; i >= m_selstart; --i)
820 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
823 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
824 for (int i = 0; i < m_selend - m_selstart; ++i)
825 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
827 m_text.remove(m_selstart, m_selend - m_selstart);
829 if (m_cursor > m_selstart)
830 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
839 Parses the input mask specified by \a maskFields to generate
840 the mask data used to handle input masks.
842 void QLineControl::parseInputMask(const QString &maskFields)
844 int delimiter = maskFields.indexOf(QLatin1Char(';'));
845 if (maskFields.isEmpty() || delimiter == 0) {
847 delete [] m_maskData;
850 internalSetText(QString());
855 if (delimiter == -1) {
856 m_blank = QLatin1Char(' ');
857 m_inputMask = maskFields;
859 m_inputMask = maskFields.left(delimiter);
860 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
863 // calculate m_maxLength / m_maskData length
866 for (int i=0; i<m_inputMask.length(); i++) {
867 c = m_inputMask.at(i);
868 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
872 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
873 c != QLatin1Char('<') && c != QLatin1Char('>') &&
874 c != QLatin1Char('{') && c != QLatin1Char('}') &&
875 c != QLatin1Char('[') && c != QLatin1Char(']'))
879 delete [] m_maskData;
880 m_maskData = new MaskInputData[m_maxLength];
882 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
887 for (int i = 0; i < m_inputMask.length(); i++) {
888 c = m_inputMask.at(i);
891 m_maskData[index].maskChar = c;
892 m_maskData[index].separator = s;
893 m_maskData[index].caseMode = m;
896 } else if (c == QLatin1Char('<')) {
897 m = MaskInputData::Lower;
898 } else if (c == QLatin1Char('>')) {
899 m = MaskInputData::Upper;
900 } else if (c == QLatin1Char('!')) {
901 m = MaskInputData::NoCaseMode;
902 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
903 switch (c.unicode()) {
929 m_maskData[index].maskChar = c;
930 m_maskData[index].separator = s;
931 m_maskData[index].caseMode = m;
936 internalSetText(m_text);
943 checks if the key is valid compared to the inputMask
945 bool QLineControl::isValidInput(QChar key, QChar mask) const
947 switch (mask.unicode()) {
953 if (key.isLetter() || key == m_blank)
957 if (key.isLetterOrNumber())
961 if (key.isLetterOrNumber() || key == m_blank)
969 if (key.isPrint() || key == m_blank)
977 if (key.isNumber() || key == m_blank)
981 if (key.isNumber() && key.digitValue() > 0)
985 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
989 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
993 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
997 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
1001 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
1005 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
1017 Returns true if the given text \a str is valid for any
1018 validator or input mask set for the line control.
1020 Otherwise returns false
1022 bool QLineControl::hasAcceptableInput(const QString &str) const
1024 #ifndef QT_NO_VALIDATOR
1025 QString textCopy = str;
1026 int cursorCopy = m_cursor;
1027 if (m_validator && m_validator->validate(textCopy, cursorCopy)
1028 != QValidator::Acceptable)
1035 if (str.length() != m_maxLength)
1038 for (int i=0; i < m_maxLength; ++i) {
1039 if (m_maskData[i].separator) {
1040 if (str.at(i) != m_maskData[i].maskChar)
1043 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
1053 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
1054 specifies from where characters should be gotten when a separator is met in \a str - true means
1055 that blanks will be used, false that previous input is used.
1056 Calling this when no inputMask is set is undefined.
1058 QString QLineControl::maskString(uint pos, const QString &str, bool clear) const
1060 if (pos >= (uint)m_maxLength)
1061 return QString::fromLatin1("");
1064 fill = clear ? clearString(0, m_maxLength) : m_text;
1067 QString s = QString::fromLatin1("");
1069 while (i < m_maxLength) {
1070 if (strIndex < str.length()) {
1071 if (m_maskData[i].separator) {
1072 s += m_maskData[i].maskChar;
1073 if (str[(int)strIndex] == m_maskData[i].maskChar)
1077 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
1078 switch (m_maskData[i].caseMode) {
1079 case MaskInputData::Upper:
1080 s += str[(int)strIndex].toUpper();
1082 case MaskInputData::Lower:
1083 s += str[(int)strIndex].toLower();
1086 s += str[(int)strIndex];
1090 // search for separator first
1091 int n = findInMask(i, true, true, str[(int)strIndex]);
1093 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
1094 s += fill.mid(i, n-i+1);
1095 i = n + 1; // update i to find + 1
1098 // search for valid m_blank if not
1099 n = findInMask(i, true, false, str[(int)strIndex]);
1101 s += fill.mid(i, n-i);
1102 switch (m_maskData[n].caseMode) {
1103 case MaskInputData::Upper:
1104 s += str[(int)strIndex].toUpper();
1106 case MaskInputData::Lower:
1107 s += str[(int)strIndex].toLower();
1110 s += str[(int)strIndex];
1112 i = n + 1; // updates i to find + 1
1130 Returns a "cleared" string with only separators and blank chars.
1131 Calling this when no inputMask is set is undefined.
1133 QString QLineControl::clearString(uint pos, uint len) const
1135 if (pos >= (uint)m_maxLength)
1139 int end = qMin((uint)m_maxLength, pos + len);
1140 for (int i = pos; i < end; ++i)
1141 if (m_maskData[i].separator)
1142 s += m_maskData[i].maskChar;
1152 Strips blank parts of the input in a QLineControl when an inputMask is set,
1153 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
1155 QString QLineControl::stripString(const QString &str) const
1161 int end = qMin(m_maxLength, (int)str.length());
1162 for (int i = 0; i < end; ++i)
1163 if (m_maskData[i].separator)
1164 s += m_maskData[i].maskChar;
1166 if (str[i] != m_blank)
1174 searches forward/backward in m_maskData for either a separator or a m_blank
1176 int QLineControl::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
1178 if (pos >= m_maxLength || pos < 0)
1181 int end = forward ? m_maxLength : -1;
1182 int step = forward ? 1 : -1;
1186 if (findSeparator) {
1187 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
1190 if (!m_maskData[i].separator) {
1191 if (searchChar.isNull())
1193 else if (isValidInput(searchChar, m_maskData[i].maskChar))
1202 void QLineControl::internalUndo(int until)
1204 if (!isUndoAvailable())
1206 cancelPasswordEchoTimer();
1208 while (m_undoState && m_undoState > until) {
1209 Command& cmd = m_history[--m_undoState];
1212 m_text.remove(cmd.pos, 1);
1216 m_selstart = cmd.selStart;
1217 m_selend = cmd.selEnd;
1221 case RemoveSelection:
1222 m_text.insert(cmd.pos, cmd.uc);
1223 m_cursor = cmd.pos + 1;
1226 case DeleteSelection:
1227 m_text.insert(cmd.pos, cmd.uc);
1233 if (until < 0 && m_undoState) {
1234 Command& next = m_history[m_undoState-1];
1235 if (next.type != cmd.type && next.type < RemoveSelection
1236 && (cmd.type < RemoveSelection || next.type == Separator))
1241 emitCursorPositionChanged();
1244 void QLineControl::internalRedo()
1246 if (!isRedoAvailable())
1249 while (m_undoState < (int)m_history.size()) {
1250 Command& cmd = m_history[m_undoState++];
1253 m_text.insert(cmd.pos, cmd.uc);
1254 m_cursor = cmd.pos + 1;
1257 m_selstart = cmd.selStart;
1258 m_selend = cmd.selEnd;
1263 case RemoveSelection:
1264 case DeleteSelection:
1265 m_text.remove(cmd.pos, 1);
1266 m_selstart = cmd.selStart;
1267 m_selend = cmd.selEnd;
1271 m_selstart = cmd.selStart;
1272 m_selend = cmd.selEnd;
1276 if (m_undoState < (int)m_history.size()) {
1277 Command& next = m_history[m_undoState];
1278 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
1279 && (next.type < RemoveSelection || cmd.type == Separator))
1284 emitCursorPositionChanged();
1290 If the current cursor position differs from the last emitted cursor
1291 position, emits cursorPositionChanged().
1293 void QLineControl::emitCursorPositionChanged()
1295 if (m_cursor != m_lastCursorPos) {
1296 const int oldLast = m_lastCursorPos;
1297 m_lastCursorPos = m_cursor;
1298 cursorPositionChanged(oldLast, m_cursor);
1299 #ifndef QT_NO_ACCESSIBILITY
1300 QAccessible::updateAccessibility(parent(), 0, QAccessible::TextCaretMoved);
1305 #ifndef QT_NO_COMPLETER
1306 // iterating forward(dir=1)/backward(dir=-1) from the
1307 // current row based. dir=0 indicates a new completion prefix was set.
1308 bool QLineControl::advanceToEnabledItem(int dir)
1310 int start = m_completer->currentRow();
1313 int i = start + dir;
1314 if (dir == 0) dir = 1;
1316 if (!m_completer->setCurrentRow(i)) {
1317 if (!m_completer->wrapAround())
1319 i = i > 0 ? 0 : m_completer->completionCount() - 1;
1321 QModelIndex currentIndex = m_completer->currentIndex();
1322 if (m_completer->completionModel()->flags(currentIndex) & Qt::ItemIsEnabled)
1326 } while (i != start);
1328 m_completer->setCurrentRow(start); // restore
1332 void QLineControl::complete(int key)
1334 if (!m_completer || isReadOnly() || echoMode() != QLineEdit::Normal)
1337 QString text = this->text();
1338 if (m_completer->completionMode() == QCompleter::InlineCompletion) {
1339 if (key == Qt::Key_Backspace)
1342 if (key == Qt::Key_Up || key == Qt::Key_Down) {
1343 if (textAfterSelection().length())
1345 QString prefix = hasSelectedText() ? textBeforeSelection()
1347 if (text.compare(m_completer->currentCompletion(), m_completer->caseSensitivity()) != 0
1348 || prefix.compare(m_completer->completionPrefix(), m_completer->caseSensitivity()) != 0) {
1349 m_completer->setCompletionPrefix(prefix);
1351 n = (key == Qt::Key_Up) ? -1 : +1;
1354 m_completer->setCompletionPrefix(text);
1356 if (!advanceToEnabledItem(n))
1359 #ifndef QT_KEYPAD_NAVIGATION
1360 if (text.isEmpty()) {
1361 m_completer->popup()->hide();
1365 m_completer->setCompletionPrefix(text);
1368 m_completer->complete();
1372 void QLineControl::setCursorBlinkPeriod(int msec)
1374 if (msec == m_blinkPeriod)
1377 killTimer(m_blinkTimer);
1380 m_blinkTimer = startTimer(msec / 2);
1384 if (m_blinkStatus == 1)
1385 emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect());
1387 m_blinkPeriod = msec;
1390 void QLineControl::resetCursorBlinkTimer()
1392 if (m_blinkPeriod == 0 || m_blinkTimer == 0)
1394 killTimer(m_blinkTimer);
1395 m_blinkTimer = startTimer(m_blinkPeriod / 2);
1399 void QLineControl::timerEvent(QTimerEvent *event)
1401 if (event->timerId() == m_blinkTimer) {
1402 m_blinkStatus = !m_blinkStatus;
1403 emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect());
1404 } else if (event->timerId() == m_deleteAllTimer) {
1405 killTimer(m_deleteAllTimer);
1406 m_deleteAllTimer = 0;
1408 } else if (event->timerId() == m_tripleClickTimer) {
1409 killTimer(m_tripleClickTimer);
1410 m_tripleClickTimer = 0;
1411 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1412 } else if (event->timerId() == m_passwordEchoTimer) {
1413 killTimer(m_passwordEchoTimer);
1414 m_passwordEchoTimer = 0;
1415 updateDisplayText();
1420 bool QLineControl::processEvent(QEvent* ev)
1422 #ifdef QT_KEYPAD_NAVIGATION
1423 if (QApplication::keypadNavigationEnabled()) {
1424 if ((ev->type() == QEvent::KeyPress) || (ev->type() == QEvent::KeyRelease)) {
1425 QKeyEvent *ke = (QKeyEvent *)ev;
1426 if (ke->key() == Qt::Key_Back) {
1427 if (ke->isAutoRepeat()) {
1428 // Swallow it. We don't want back keys running amok.
1432 if ((ev->type() == QEvent::KeyRelease)
1434 && m_deleteAllTimer) {
1435 killTimer(m_deleteAllTimer);
1436 m_deleteAllTimer = 0;
1446 #ifndef QT_NO_GRAPHICSVIEW
1447 case QEvent::GraphicsSceneMouseDoubleClick:
1448 case QEvent::GraphicsSceneMouseMove:
1449 case QEvent::GraphicsSceneMouseRelease:
1450 case QEvent::GraphicsSceneMousePress:{
1451 QGraphicsSceneMouseEvent *gvEv = static_cast<QGraphicsSceneMouseEvent*>(ev);
1452 QMouseEvent mouse(ev->type(),
1453 gvEv->pos().toPoint(), gvEv->button(), gvEv->buttons(), gvEv->modifiers());
1454 processMouseEvent(&mouse); break;
1457 case QEvent::MouseButtonPress:
1458 case QEvent::MouseButtonRelease:
1459 case QEvent::MouseButtonDblClick:
1460 case QEvent::MouseMove:
1461 processMouseEvent(static_cast<QMouseEvent*>(ev)); break;
1462 case QEvent::KeyPress:
1463 case QEvent::KeyRelease:
1464 processKeyEvent(static_cast<QKeyEvent*>(ev)); break;
1465 case QEvent::InputMethod:
1466 processInputMethodEvent(static_cast<QInputMethodEvent*>(ev)); break;
1467 #ifndef QT_NO_SHORTCUT
1468 case QEvent::ShortcutOverride:{
1471 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1472 if (ke == QKeySequence::Copy
1473 || ke == QKeySequence::Paste
1474 || ke == QKeySequence::Cut
1475 || ke == QKeySequence::Redo
1476 || ke == QKeySequence::Undo
1477 || ke == QKeySequence::MoveToNextWord
1478 || ke == QKeySequence::MoveToPreviousWord
1479 || ke == QKeySequence::MoveToStartOfDocument
1480 || ke == QKeySequence::MoveToEndOfDocument
1481 || ke == QKeySequence::SelectNextWord
1482 || ke == QKeySequence::SelectPreviousWord
1483 || ke == QKeySequence::SelectStartOfLine
1484 || ke == QKeySequence::SelectEndOfLine
1485 || ke == QKeySequence::SelectStartOfBlock
1486 || ke == QKeySequence::SelectEndOfBlock
1487 || ke == QKeySequence::SelectStartOfDocument
1488 || ke == QKeySequence::SelectAll
1489 || ke == QKeySequence::SelectEndOfDocument) {
1491 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1492 || ke->modifiers() == Qt::KeypadModifier) {
1493 if (ke->key() < Qt::Key_Escape) {
1496 switch (ke->key()) {
1497 case Qt::Key_Delete:
1500 case Qt::Key_Backspace:
1517 void QLineControl::processMouseEvent(QMouseEvent* ev)
1520 switch (ev->type()) {
1521 case QEvent::GraphicsSceneMousePress:
1522 case QEvent::MouseButtonPress:{
1523 if (m_tripleClickTimer
1524 && (ev->pos() - m_tripleClick).manhattanLength()
1525 < QApplication::startDragDistance()) {
1529 if (ev->button() == Qt::RightButton)
1532 bool mark = ev->modifiers() & Qt::ShiftModifier;
1533 int cursor = xToPos(ev->pos().x());
1534 moveCursor(cursor, mark);
1537 case QEvent::GraphicsSceneMouseDoubleClick:
1538 case QEvent::MouseButtonDblClick:
1539 if (ev->button() == Qt::LeftButton) {
1540 selectWordAtPos(xToPos(ev->pos().x()));
1541 if (m_tripleClickTimer)
1542 killTimer(m_tripleClickTimer);
1543 m_tripleClickTimer = startTimer(QApplication::doubleClickInterval());
1544 m_tripleClick = ev->pos();
1547 case QEvent::GraphicsSceneMouseRelease:
1548 case QEvent::MouseButtonRelease:
1549 #ifndef QT_NO_CLIPBOARD
1550 if (QApplication::clipboard()->supportsSelection()) {
1551 if (ev->button() == Qt::LeftButton) {
1552 copy(QClipboard::Selection);
1553 } else if (!isReadOnly() && ev->button() == Qt::MidButton) {
1555 insert(QApplication::clipboard()->text(QClipboard::Selection));
1560 case QEvent::GraphicsSceneMouseMove:
1561 case QEvent::MouseMove:
1562 if (ev->buttons() & Qt::LeftButton) {
1563 moveCursor(xToPos(ev->pos().x()), true);
1571 void QLineControl::processKeyEvent(QKeyEvent* event)
1573 bool inlineCompletionAccepted = false;
1575 #ifndef QT_NO_COMPLETER
1577 QCompleter::CompletionMode completionMode = m_completer->completionMode();
1578 if ((completionMode == QCompleter::PopupCompletion
1579 || completionMode == QCompleter::UnfilteredPopupCompletion)
1580 && m_completer->popup()
1581 && m_completer->popup()->isVisible()) {
1582 // The following keys are forwarded by the completer to the widget
1583 // Ignoring the events lets the completer provide suitable default behavior
1584 switch (event->key()) {
1585 case Qt::Key_Escape:
1589 case Qt::Key_Return:
1591 #ifdef QT_KEYPAD_NAVIGATION
1592 case Qt::Key_Select:
1593 if (!QApplication::keypadNavigationEnabled())
1596 m_completer->popup()->hide(); // just hide. will end up propagating to parent
1598 break; // normal key processing
1600 } else if (completionMode == QCompleter::InlineCompletion) {
1601 switch (event->key()) {
1603 case Qt::Key_Return:
1605 #ifdef QT_KEYPAD_NAVIGATION
1606 case Qt::Key_Select:
1607 if (!QApplication::keypadNavigationEnabled())
1610 if (!m_completer->currentCompletion().isEmpty() && hasSelectedText()
1611 && textAfterSelection().isEmpty()) {
1612 setText(m_completer->currentCompletion());
1613 inlineCompletionAccepted = true;
1616 break; // normal key processing
1620 #endif // QT_NO_COMPLETER
1622 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
1623 if (hasAcceptableInput() || fixup()) {
1625 emit editingFinished();
1627 if (inlineCompletionAccepted)
1634 if (echoMode() == QLineEdit::PasswordEchoOnEdit
1635 && !passwordEchoEditing()
1637 && !event->text().isEmpty()
1638 #ifdef QT_KEYPAD_NAVIGATION
1639 && event->key() != Qt::Key_Select
1640 && event->key() != Qt::Key_Up
1641 && event->key() != Qt::Key_Down
1642 && event->key() != Qt::Key_Back
1644 && !(event->modifiers() & Qt::ControlModifier)) {
1645 // Clear the edit and reset to normal echo mode while editing; the
1646 // echo mode switches back when the edit loses focus
1647 // ### resets current content. dubious code; you can
1648 // navigate with keys up, down, back, and select(?), but if you press
1649 // "left" or "right" it clears?
1650 updatePasswordEchoEditing(true);
1654 bool unknown = false;
1655 bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
1659 #ifndef QT_NO_SHORTCUT
1660 else if (event == QKeySequence::Undo) {
1664 else if (event == QKeySequence::Redo) {
1668 else if (event == QKeySequence::SelectAll) {
1671 #ifndef QT_NO_CLIPBOARD
1672 else if (event == QKeySequence::Copy) {
1675 else if (event == QKeySequence::Paste) {
1676 if (!isReadOnly()) {
1677 QClipboard::Mode mode = QClipboard::Clipboard;
1679 if (event->modifiers() == (Qt::CTRL | Qt::SHIFT) && event->key() == Qt::Key_Insert)
1680 mode = QClipboard::Selection;
1685 else if (event == QKeySequence::Cut) {
1686 if (!isReadOnly()) {
1691 else if (event == QKeySequence::DeleteEndOfLine) {
1692 if (!isReadOnly()) {
1693 setSelection(cursor(), end());
1698 #endif //QT_NO_CLIPBOARD
1699 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
1702 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
1705 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
1708 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
1711 else if (event == QKeySequence::MoveToNextChar) {
1712 #if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER)
1713 if (hasSelectedText()) {
1715 if (hasSelectedText() && m_completer
1716 && m_completer->completionMode() == QCompleter::InlineCompletion) {
1718 moveCursor(selectionEnd(), false);
1720 cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
1723 else if (event == QKeySequence::SelectNextChar) {
1724 cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
1726 else if (event == QKeySequence::MoveToPreviousChar) {
1727 #if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER)
1728 if (hasSelectedText()) {
1730 if (hasSelectedText() && m_completer
1731 && m_completer->completionMode() == QCompleter::InlineCompletion) {
1733 moveCursor(selectionStart(), false);
1735 cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
1738 else if (event == QKeySequence::SelectPreviousChar) {
1739 cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
1741 else if (event == QKeySequence::MoveToNextWord) {
1742 if (echoMode() == QLineEdit::Normal)
1743 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
1745 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
1747 else if (event == QKeySequence::MoveToPreviousWord) {
1748 if (echoMode() == QLineEdit::Normal)
1749 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
1750 else if (!isReadOnly()) {
1751 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
1754 else if (event == QKeySequence::SelectNextWord) {
1755 if (echoMode() == QLineEdit::Normal)
1756 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
1758 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
1760 else if (event == QKeySequence::SelectPreviousWord) {
1761 if (echoMode() == QLineEdit::Normal)
1762 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
1764 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
1766 else if (event == QKeySequence::Delete) {
1770 else if (event == QKeySequence::DeleteEndOfWord) {
1771 if (!isReadOnly()) {
1772 cursorWordForward(true);
1776 else if (event == QKeySequence::DeleteStartOfWord) {
1777 if (!isReadOnly()) {
1778 cursorWordBackward(true);
1782 #endif // QT_NO_SHORTCUT
1784 bool handled = false;
1786 if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down) {
1787 Qt::KeyboardModifiers myModifiers = (event->modifiers() & ~Qt::KeypadModifier);
1788 if (myModifiers & Qt::ShiftModifier) {
1789 if (myModifiers == (Qt::ControlModifier|Qt::ShiftModifier)
1790 || myModifiers == (Qt::AltModifier|Qt::ShiftModifier)
1791 || myModifiers == Qt::ShiftModifier) {
1793 event->key() == Qt::Key_Up ? home(1) : end(1);
1796 if ((myModifiers == Qt::ControlModifier
1797 || myModifiers == Qt::AltModifier
1798 || myModifiers == Qt::NoModifier)) {
1799 event->key() == Qt::Key_Up ? home(0) : end(0);
1805 if (event->modifiers() & Qt::ControlModifier) {
1806 switch (event->key()) {
1807 case Qt::Key_Backspace:
1808 if (!isReadOnly()) {
1809 cursorWordBackward(true);
1813 #ifndef QT_NO_COMPLETER
1816 complete(event->key());
1819 #if defined(Q_WS_X11)
1825 if (!isReadOnly()) {
1826 setSelection(0, text().size());
1827 #ifndef QT_NO_CLIPBOARD
1838 } else { // ### check for *no* modifier
1839 switch (event->key()) {
1840 case Qt::Key_Backspace:
1841 if (!isReadOnly()) {
1843 #ifndef QT_NO_COMPLETER
1844 complete(Qt::Key_Backspace);
1848 #ifdef QT_KEYPAD_NAVIGATION
1850 if (QApplication::keypadNavigationEnabled() && !event->isAutoRepeat()
1852 if (text().length() == 0) {
1853 setText(m_cancelText);
1855 if (passwordEchoEditing())
1856 updatePasswordEchoEditing(false);
1858 emit editFocusChange(false);
1859 } else if (!m_deleteAllTimer) {
1860 m_deleteAllTimer = startTimer(750);
1874 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
1875 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
1879 if (unknown && !isReadOnly()) {
1880 QString t = event->text();
1881 if (!t.isEmpty() && t.at(0).isPrint()) {
1883 #ifndef QT_NO_COMPLETER
1884 complete(event->key());