Export QTextImageHandler and add accessor for image
[profile/ivi/qtbase.git] / src / gui / text / qlinecontrol.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
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.
17 **
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.
21 **
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.
29 **
30 ** Other Usage
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.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 // ###
43 #define QT_NO_ACCESSIBILITY
44
45 #include "qlinecontrol_p.h"
46
47 #ifndef QT_NO_LINEEDIT
48
49 #include "qclipboard.h"
50 #ifndef QT_NO_ACCESSIBILITY
51 #include "qaccessible.h"
52 #endif
53 #include "qguiapplication.h"
54 #include "qstylehints.h"
55
56 QT_BEGIN_NAMESPACE
57
58 // ### these should come from QStyleHints
59 const int textCursorWidth = 1;
60 const bool fullWidthSelection = true;
61
62 /*!
63     \internal
64
65     Updates the display text based of the current edit text
66     If the text has changed will emit displayTextChanged()
67 */
68 void QLineControl::updateDisplayText(bool forceUpdate)
69 {
70     QString orig = m_textLayout.text();
71     QString str;
72     if (m_echoMode == NoEcho)
73         str = QString::fromLatin1("");
74     else
75         str = m_text;
76
77     if (m_echoMode == Password || (m_echoMode == PasswordEchoOnEdit
78                 && !m_passwordEchoEditing))
79         str.fill(m_passwordCharacter);
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.length(); ++i) {
86         if ((uc[i] < 0x20 && uc[i] != 0x09)
87             || uc[i] == QChar::LineSeparator
88             || uc[i] == QChar::ParagraphSeparator
89             || uc[i] == QChar::ObjectReplacementCharacter)
90             uc[i] = QChar(0x0020);
91     }
92
93     m_textLayout.setText(str);
94
95     QTextOption option;
96     option.setTextDirection(m_layoutDirection);
97     option.setFlags(QTextOption::IncludeTrailingSpaces);
98     m_textLayout.setTextOption(option);
99
100     m_textLayout.beginLayout();
101     QTextLine l = m_textLayout.createLine();
102     m_textLayout.endLayout();
103     m_ascent = qRound(l.ascent());
104
105     if (str != orig || forceUpdate)
106         emit displayTextChanged(str);
107 }
108
109 #ifndef QT_NO_CLIPBOARD
110 /*!
111     \internal
112
113     Copies the currently selected text into the clipboard using the given
114     \a mode.
115
116     \note If the echo mode is set to a mode other than Normal then copy
117     will not work.  This is to prevent using copy as a method of bypassing
118     password features of the line control.
119 */
120 void QLineControl::copy(QClipboard::Mode mode) const
121 {
122     QString t = selectedText();
123     if (!t.isEmpty() && m_echoMode == Normal) {
124         disconnect(QGuiApplication::clipboard(), SIGNAL(selectionChanged()), this, 0);
125         QGuiApplication::clipboard()->setText(t, mode);
126         connect(QGuiApplication::clipboard(), SIGNAL(selectionChanged()),
127                    this, SLOT(_q_clipboardChanged()));
128     }
129 }
130
131 /*!
132     \internal
133
134     Inserts the text stored in the application clipboard into the line
135     control.
136
137     \sa insert()
138 */
139 void QLineControl::paste(QClipboard::Mode clipboardMode)
140 {
141     QString clip = QGuiApplication::clipboard()->text(clipboardMode);
142     if (!clip.isEmpty() || hasSelectedText()) {
143         separate(); //make it a separate undo/redo command
144         insert(clip);
145         separate();
146     }
147 }
148
149 #endif // !QT_NO_CLIPBOARD
150
151 /*!
152     \internal
153
154     Handles the behavior for the backspace key or function.
155     Removes the current selection if there is a selection, otherwise
156     removes the character prior to the cursor position.
157
158     \sa del()
159 */
160 void QLineControl::backspace()
161 {
162     int priorState = m_undoState;
163     if (hasSelectedText()) {
164         removeSelectedText();
165     } else if (m_cursor) {
166             --m_cursor;
167             if (m_maskData)
168                 m_cursor = prevMaskBlank(m_cursor);
169             QChar uc = m_text.at(m_cursor);
170             if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
171                 // second half of a surrogate, check if we have the first half as well,
172                 // if yes delete both at once
173                 uc = m_text.at(m_cursor - 1);
174                 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
175                     internalDelete(true);
176                     --m_cursor;
177                 }
178             }
179             internalDelete(true);
180     }
181     finishChange(priorState);
182 }
183
184 /*!
185     \internal
186
187     Handles the behavior for the delete key or function.
188     Removes the current selection if there is a selection, otherwise
189     removes the character after the cursor position.
190
191     \sa del()
192 */
193 void QLineControl::del()
194 {
195     int priorState = m_undoState;
196     if (hasSelectedText()) {
197         removeSelectedText();
198     } else {
199         int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
200         while (n--)
201             internalDelete();
202     }
203     finishChange(priorState);
204 }
205
206 /*!
207     \internal
208
209     Inserts the given \a newText at the current cursor position.
210     If there is any selected text it is removed prior to insertion of
211     the new text.
212 */
213 void QLineControl::insert(const QString &newText)
214 {
215     int priorState = m_undoState;
216     removeSelectedText();
217     internalInsert(newText);
218     finishChange(priorState);
219 }
220
221 /*!
222     \internal
223
224     Clears the line control text.
225 */
226 void QLineControl::clear()
227 {
228     int priorState = m_undoState;
229     m_selstart = 0;
230     m_selend = m_text.length();
231     removeSelectedText();
232     separate();
233     finishChange(priorState, /*update*/false, /*edited*/false);
234 }
235
236 /*!
237     \internal
238
239     Sets \a length characters from the given \a start position as selected.
240     The given \a start position must be within the current text for
241     the line control.  If \a length characters cannot be selected, then
242     the selection will extend to the end of the current text.
243 */
244 void QLineControl::setSelection(int start, int length)
245 {
246     if(start < 0 || start > (int)m_text.length()){
247         qWarning("QLineControl::setSelection: Invalid start position");
248         return;
249     }
250
251     if (length > 0) {
252         if (start == m_selstart && start + length == m_selend)
253             return;
254         m_selstart = start;
255         m_selend = qMin(start + length, (int)m_text.length());
256         m_cursor = m_selend;
257     } else if (length < 0){
258         if (start == m_selend && start + length == m_selstart)
259             return;
260         m_selstart = qMax(start + length, 0);
261         m_selend = start;
262         m_cursor = m_selstart;
263     } else if (m_selstart != m_selend) {
264         m_selstart = 0;
265         m_selend = 0;
266         m_cursor = start;
267     } else {
268         m_cursor = start;
269         emitCursorPositionChanged();
270         return;
271     }
272     emit selectionChanged();
273     emitCursorPositionChanged();
274 }
275
276 void QLineControl::_q_clipboardChanged()
277 {
278 }
279
280 void QLineControl::_q_deleteSelected()
281 {
282     if (!hasSelectedText())
283         return;
284
285     int priorState = m_undoState;
286     emit resetInputContext();
287     removeSelectedText();
288     separate();
289     finishChange(priorState);
290 }
291
292 /*!
293     \internal
294
295     Initializes the line control with a starting text value of \a txt.
296 */
297 void QLineControl::init(const QString &txt)
298 {
299     m_text = txt;
300     updateDisplayText();
301     m_cursor = m_text.length();
302 }
303
304 /*!
305     \internal
306
307     Sets the password echo editing to \a editing.  If password echo editing
308     is true, then the text of the password is displayed even if the echo
309     mode is set to QLineEdit::PasswordEchoOnEdit.  Password echoing editing
310     does not affect other echo modes.
311 */
312 void QLineControl::updatePasswordEchoEditing(bool editing)
313 {
314     m_passwordEchoEditing = editing;
315     updateDisplayText();
316 }
317
318 /*!
319     \internal
320
321     Returns the cursor position of the given \a x pixel value in relation
322     to the displayed text.  The given \a betweenOrOn specified what kind
323     of cursor position is requested.
324 */
325 int QLineControl::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const
326 {
327     return m_textLayout.lineAt(0).xToCursor(x, betweenOrOn);
328 }
329
330 /*!
331     \internal
332
333     Returns the bounds of the current cursor, as defined as a
334     between characters cursor.
335 */
336 QRect QLineControl::cursorRect() const
337 {
338     QTextLine l = m_textLayout.lineAt(0);
339     int c = m_cursor;
340     if (m_preeditCursor != -1)
341         c += m_preeditCursor;
342     int cix = qRound(l.cursorToX(c));
343     int w = m_cursorWidth;
344     int ch = l.height() + 1;
345
346     return QRect(cix-5, 0, w+9, ch);
347 }
348
349 /*!
350     \internal
351
352     Fixes the current text so that it is valid given any set validators.
353
354     Returns true if the text was changed.  Otherwise returns false.
355 */
356 bool QLineControl::fixup() // this function assumes that validate currently returns != Acceptable
357 {
358 #ifndef QT_NO_VALIDATOR
359     if (m_validator) {
360         QString textCopy = m_text;
361         int cursorCopy = m_cursor;
362         m_validator->fixup(textCopy);
363         if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
364             if (textCopy != m_text || cursorCopy != m_cursor)
365                 internalSetText(textCopy, cursorCopy);
366             return true;
367         }
368     }
369 #endif
370     return false;
371 }
372
373 /*!
374     \internal
375
376     Moves the cursor to the given position \a pos.   If \a mark is true will
377     adjust the currently selected text.
378 */
379 void QLineControl::moveCursor(int pos, bool mark)
380 {
381     if (pos != m_cursor) {
382         separate();
383         if (m_maskData)
384             pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
385     }
386     if (mark) {
387         int anchor;
388         if (m_selend > m_selstart && m_cursor == m_selstart)
389             anchor = m_selend;
390         else if (m_selend > m_selstart && m_cursor == m_selend)
391             anchor = m_selstart;
392         else
393             anchor = m_cursor;
394         m_selstart = qMin(anchor, pos);
395         m_selend = qMax(anchor, pos);
396         updateDisplayText();
397     } else {
398         internalDeselect();
399     }
400     m_cursor = pos;
401     if (mark || m_selDirty) {
402         m_selDirty = false;
403         emit selectionChanged();
404     }
405     emitCursorPositionChanged();
406 }
407
408 /*!
409     \internal
410
411     Applies the given input method event \a event to the text of the line
412     control
413 */
414 void QLineControl::processInputMethodEvent(QInputMethodEvent *event)
415 {
416     int priorState = 0;
417     bool isGettingInput = !event->commitString().isEmpty()
418             || event->preeditString() != preeditAreaText()
419             || event->replacementLength() > 0;
420     bool cursorPositionChanged = false;
421
422     if (isGettingInput) {
423         // If any text is being input, remove selected text.
424         priorState = m_undoState;
425         if (echoMode() == PasswordEchoOnEdit && !passwordEchoEditing()) {
426             updatePasswordEchoEditing(true);
427             m_selstart = 0;
428             m_selend = m_text.length();
429         }
430         removeSelectedText();
431     }
432
433     int c = m_cursor; // cursor position after insertion of commit string
434     if (event->replacementStart() <= 0)
435         c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
436
437     m_cursor += event->replacementStart();
438     if (m_cursor < 0)
439         m_cursor = 0;
440
441     // insert commit string
442     if (event->replacementLength()) {
443         m_selstart = m_cursor;
444         m_selend = m_selstart + event->replacementLength();
445         removeSelectedText();
446     }
447     if (!event->commitString().isEmpty()) {
448         internalInsert(event->commitString());
449         cursorPositionChanged = true;
450     }
451
452     m_cursor = qBound(0, c, m_text.length());
453
454     for (int i = 0; i < event->attributes().size(); ++i) {
455         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
456         if (a.type == QInputMethodEvent::Selection) {
457             m_cursor = qBound(0, a.start + a.length, m_text.length());
458             if (a.length) {
459                 m_selstart = qMax(0, qMin(a.start, m_text.length()));
460                 m_selend = m_cursor;
461                 if (m_selend < m_selstart) {
462                     qSwap(m_selstart, m_selend);
463                 }
464             } else {
465                 m_selstart = m_selend = 0;
466             }
467             cursorPositionChanged = true;
468         }
469     }
470 #ifndef QT_NO_IM
471     setPreeditArea(m_cursor, event->preeditString());
472 #endif //QT_NO_IM
473     const int oldPreeditCursor = m_preeditCursor;
474     m_preeditCursor = event->preeditString().length();
475     m_hideCursor = false;
476     QList<QTextLayout::FormatRange> formats;
477     for (int i = 0; i < event->attributes().size(); ++i) {
478         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
479         if (a.type == QInputMethodEvent::Cursor) {
480             m_preeditCursor = a.start;
481             m_hideCursor = !a.length;
482         } else if (a.type == QInputMethodEvent::TextFormat) {
483             QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
484             if (f.isValid()) {
485                 QTextLayout::FormatRange o;
486                 o.start = a.start + m_cursor;
487                 o.length = a.length;
488                 o.format = f;
489                 formats.append(o);
490             }
491         }
492     }
493     m_textLayout.setAdditionalFormats(formats);
494     updateDisplayText(/*force*/ true);
495     if (cursorPositionChanged)
496         emitCursorPositionChanged();
497     else if (m_preeditCursor != oldPreeditCursor)
498         emit updateMicroFocus();
499     if (isGettingInput)
500         finishChange(priorState);
501 }
502
503 /*!
504     \internal
505
506     Draws the display text for the line control using the given
507     \a painter, \a clip, and \a offset.  Which aspects of the display text
508     are drawn is specified by the given \a flags.
509
510     If the flags contain DrawSelections, then the selection or input mask
511     backgrounds and foregrounds will be applied before drawing the text.
512
513     If the flags contain DrawCursor a cursor of the current cursorWidth()
514     will be drawn after drawing the text.
515
516     The display text will only be drawn if the flags contain DrawText
517 */
518 void QLineControl::draw(QPainter *painter, const QPoint &offset, const QRect &clip, int flags)
519 {
520     QVector<QTextLayout::FormatRange> selections;
521     if (flags & DrawSelections) {
522         QTextLayout::FormatRange o;
523         if (m_selstart < m_selend) {
524             o.start = m_selstart;
525             o.length = m_selend - m_selstart;
526             o.format.setBackground(m_palette.brush(QPalette::Highlight));
527             o.format.setForeground(m_palette.brush(QPalette::HighlightedText));
528         } else {
529             // mask selection
530             if(!m_blinkPeriod || m_blinkStatus){
531                 o.start = m_cursor;
532                 o.length = 1;
533                 o.format.setBackground(m_palette.brush(QPalette::Text));
534                 o.format.setForeground(m_palette.brush(QPalette::Window));
535             }
536         }
537         selections.append(o);
538     }
539
540     if (flags & DrawText)
541         m_textLayout.draw(painter, offset, selections, clip);
542
543     if (flags & DrawCursor){
544         int cursor = m_cursor;
545         if (m_preeditCursor != -1)
546             cursor += m_preeditCursor;
547         if (!m_hideCursor && (!m_blinkPeriod || m_blinkStatus))
548             m_textLayout.drawCursor(painter, offset, cursor, m_cursorWidth);
549     }
550 }
551
552 /*!
553     \internal
554
555     Sets the selection to cover the word at the given cursor position.
556     The word boundaries are defined by the behavior of QTextLayout::SkipWords
557     cursor mode.
558 */
559 void QLineControl::selectWordAtPos(int cursor)
560 {
561     int next = cursor + 1;
562     if(next > end())
563         --next;
564     int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
565     moveCursor(c, false);
566     // ## text layout should support end of words.
567     int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
568     while (end > cursor && m_text[end-1].isSpace())
569         --end;
570     moveCursor(end, true);
571 }
572
573 /*!
574     \internal
575
576     Completes a change to the line control text.  If the change is not valid
577     will undo the line control state back to the given \a validateFromState.
578
579     If \a edited is true and the change is valid, will emit textEdited() in
580     addition to textChanged().  Otherwise only emits textChanged() on a valid
581     change.
582
583     The \a update value is currently unused.
584 */
585 bool QLineControl::finishChange(int validateFromState, bool update, bool edited)
586 {
587     Q_UNUSED(update)
588     bool lineDirty = m_selDirty;
589     if (m_textDirty) {
590         // do validation
591         bool wasValidInput = m_validInput;
592         m_validInput = true;
593 #ifndef QT_NO_VALIDATOR
594         if (m_validator) {
595             m_validInput = false;
596             QString textCopy = m_text;
597             int cursorCopy = m_cursor;
598             m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
599             if (m_validInput) {
600                 if (m_text != textCopy) {
601                     internalSetText(textCopy, cursorCopy);
602                     return true;
603                 }
604                 m_cursor = cursorCopy;
605             }
606         }
607 #endif
608         if (validateFromState >= 0 && wasValidInput && !m_validInput) {
609             if (m_transactions.count())
610                 return false;
611             internalUndo(validateFromState);
612             m_history.resize(m_undoState);
613             if (m_modifiedState > m_undoState)
614                 m_modifiedState = -1;
615             m_validInput = true;
616             m_textDirty = false;
617         }
618         updateDisplayText();
619         lineDirty |= m_textDirty;
620         if (m_textDirty) {
621             m_textDirty = false;
622             QString actualText = text();
623             if (edited)
624                 emit textEdited(actualText);
625             emit textChanged(actualText);
626         }
627     }
628     if (m_selDirty) {
629         m_selDirty = false;
630         emit selectionChanged();
631     }
632     emitCursorPositionChanged();
633     return true;
634 }
635
636 /*!
637     \internal
638
639     An internal function for setting the text of the line control.
640 */
641 void QLineControl::internalSetText(const QString &txt, int pos, bool edited)
642 {
643     internalDeselect();
644     emit resetInputContext();
645     QString oldText = m_text;
646     if (m_maskData) {
647         m_text = maskString(0, txt, true);
648         m_text += clearString(m_text.length(), m_maxLength - m_text.length());
649     } else {
650         m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
651     }
652     m_history.clear();
653     m_modifiedState =  m_undoState = 0;
654     m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
655     m_textDirty = (oldText != m_text);
656
657 #ifdef QT_NO_ACCESSIBILITY
658     Q_UNUSED(edited)
659 #else
660     bool changed = finishChange(-1, true, edited);
661     if (changed)
662         QAccessible::updateAccessibility(parent(), 0, QAccessible::TextUpdated);
663 #endif
664 }
665
666
667 /*!
668     \internal
669
670     Adds the given \a command to the undo history
671     of the line control.  Does not apply the command.
672 */
673 void QLineControl::addCommand(const Command &cmd)
674 {
675     if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
676         m_history.resize(m_undoState + 2);
677         m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
678     } else {
679         m_history.resize(m_undoState + 1);
680     }
681     m_separator = false;
682     m_history[m_undoState++] = cmd;
683 }
684
685 /*!
686     \internal
687
688     Inserts the given string \a s into the line
689     control.
690
691     Also adds the appropriate commands into the undo history.
692     This function does not call finishChange(), and may leave the text
693     in an invalid state.
694 */
695 void QLineControl::internalInsert(const QString &s)
696 {
697     if (hasSelectedText())
698         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
699     if (m_maskData) {
700         QString ms = maskString(m_cursor, s);
701         for (int i = 0; i < (int) ms.length(); ++i) {
702             addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
703             addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
704         }
705         m_text.replace(m_cursor, ms.length(), ms);
706         m_cursor += ms.length();
707         m_cursor = nextMaskBlank(m_cursor);
708         m_textDirty = true;
709     } else {
710         int remaining = m_maxLength - m_text.length();
711         if (remaining != 0) {
712             m_text.insert(m_cursor, s.left(remaining));
713             for (int i = 0; i < (int) s.left(remaining).length(); ++i)
714                addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
715             m_textDirty = true;
716         }
717     }
718 }
719
720 /*!
721     \internal
722
723     deletes a single character from the current text.  If \a wasBackspace,
724     the character prior to the cursor is removed.  Otherwise the character
725     after the cursor is removed.
726
727     Also adds the appropriate commands into the undo history.
728     This function does not call finishChange(), and may leave the text
729     in an invalid state.
730 */
731 void QLineControl::internalDelete(bool wasBackspace)
732 {
733     if (m_cursor < (int) m_text.length()) {
734         if (hasSelectedText())
735             addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
736         addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
737                    m_cursor, m_text.at(m_cursor), -1, -1));
738         if (m_maskData) {
739             m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
740             addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
741         } else {
742             m_text.remove(m_cursor, 1);
743         }
744         m_textDirty = true;
745     }
746 }
747
748 /*!
749     \internal
750
751     removes the currently selected text from the line control.
752
753     Also adds the appropriate commands into the undo history.
754     This function does not call finishChange(), and may leave the text
755     in an invalid state.
756 */
757 void QLineControl::removeSelectedText()
758 {
759     if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
760         separate();
761         int i ;
762         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
763         if (m_selstart <= m_cursor && m_cursor < m_selend) {
764             // cursor is within the selection. Split up the commands
765             // to be able to restore the correct cursor position
766             for (i = m_cursor; i >= m_selstart; --i)
767                 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
768             for (i = m_selend - 1; i > m_cursor; --i)
769                 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
770         } else {
771             for (i = m_selend-1; i >= m_selstart; --i)
772                 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
773         }
774         if (m_maskData) {
775             m_text.replace(m_selstart, m_selend - m_selstart,  clearString(m_selstart, m_selend - m_selstart));
776             for (int i = 0; i < m_selend - m_selstart; ++i)
777                 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
778         } else {
779             m_text.remove(m_selstart, m_selend - m_selstart);
780         }
781         if (m_cursor > m_selstart)
782             m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
783         internalDeselect();
784         m_textDirty = true;
785     }
786 }
787
788 /*!
789     \internal
790
791     Parses the input mask specified by \a maskFields to generate
792     the mask data used to handle input masks.
793 */
794 void QLineControl::parseInputMask(const QString &maskFields)
795 {
796     int delimiter = maskFields.indexOf(QLatin1Char(';'));
797     if (maskFields.isEmpty() || delimiter == 0) {
798         if (m_maskData) {
799             delete [] m_maskData;
800             m_maskData = 0;
801             m_maxLength = 32767;
802             internalSetText(QString());
803         }
804         return;
805     }
806
807     if (delimiter == -1) {
808         m_blank = QLatin1Char(' ');
809         m_inputMask = maskFields;
810     } else {
811         m_inputMask = maskFields.left(delimiter);
812         m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
813     }
814
815     // calculate m_maxLength / m_maskData length
816     m_maxLength = 0;
817     QChar c = 0;
818     for (int i=0; i<m_inputMask.length(); i++) {
819         c = m_inputMask.at(i);
820         if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
821             m_maxLength++;
822             continue;
823         }
824         if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
825              c != QLatin1Char('<') && c != QLatin1Char('>') &&
826              c != QLatin1Char('{') && c != QLatin1Char('}') &&
827              c != QLatin1Char('[') && c != QLatin1Char(']'))
828             m_maxLength++;
829     }
830
831     delete [] m_maskData;
832     m_maskData = new MaskInputData[m_maxLength];
833
834     MaskInputData::Casemode m = MaskInputData::NoCaseMode;
835     c = 0;
836     bool s;
837     bool escape = false;
838     int index = 0;
839     for (int i = 0; i < m_inputMask.length(); i++) {
840         c = m_inputMask.at(i);
841         if (escape) {
842             s = true;
843             m_maskData[index].maskChar = c;
844             m_maskData[index].separator = s;
845             m_maskData[index].caseMode = m;
846             index++;
847             escape = false;
848         } else if (c == QLatin1Char('<')) {
849                 m = MaskInputData::Lower;
850         } else if (c == QLatin1Char('>')) {
851             m = MaskInputData::Upper;
852         } else if (c == QLatin1Char('!')) {
853             m = MaskInputData::NoCaseMode;
854         } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
855             switch (c.unicode()) {
856             case 'A':
857             case 'a':
858             case 'N':
859             case 'n':
860             case 'X':
861             case 'x':
862             case '9':
863             case '0':
864             case 'D':
865             case 'd':
866             case '#':
867             case 'H':
868             case 'h':
869             case 'B':
870             case 'b':
871                 s = false;
872                 break;
873             case '\\':
874                 escape = true;
875             default:
876                 s = true;
877                 break;
878             }
879
880             if (!escape) {
881                 m_maskData[index].maskChar = c;
882                 m_maskData[index].separator = s;
883                 m_maskData[index].caseMode = m;
884                 index++;
885             }
886         }
887     }
888     internalSetText(m_text);
889 }
890
891
892 /*!
893     \internal
894
895     checks if the key is valid compared to the inputMask
896 */
897 bool QLineControl::isValidInput(QChar key, QChar mask) const
898 {
899     switch (mask.unicode()) {
900     case 'A':
901         if (key.isLetter())
902             return true;
903         break;
904     case 'a':
905         if (key.isLetter() || key == m_blank)
906             return true;
907         break;
908     case 'N':
909         if (key.isLetterOrNumber())
910             return true;
911         break;
912     case 'n':
913         if (key.isLetterOrNumber() || key == m_blank)
914             return true;
915         break;
916     case 'X':
917         if (key.isPrint())
918             return true;
919         break;
920     case 'x':
921         if (key.isPrint() || key == m_blank)
922             return true;
923         break;
924     case '9':
925         if (key.isNumber())
926             return true;
927         break;
928     case '0':
929         if (key.isNumber() || key == m_blank)
930             return true;
931         break;
932     case 'D':
933         if (key.isNumber() && key.digitValue() > 0)
934             return true;
935         break;
936     case 'd':
937         if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
938             return true;
939         break;
940     case '#':
941         if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
942             return true;
943         break;
944     case 'B':
945         if (key == QLatin1Char('0') || key == QLatin1Char('1'))
946             return true;
947         break;
948     case 'b':
949         if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
950             return true;
951         break;
952     case 'H':
953         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
954             return true;
955         break;
956     case 'h':
957         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
958             return true;
959         break;
960     default:
961         break;
962     }
963     return false;
964 }
965
966 /*!
967     \internal
968
969     Returns true if the given text \a str is valid for any
970     validator or input mask set for the line control.
971
972     Otherwise returns false
973 */
974 bool QLineControl::hasAcceptableInput(const QString &str) const
975 {
976 #ifndef QT_NO_VALIDATOR
977     QString textCopy = str;
978     int cursorCopy = m_cursor;
979     if (m_validator && m_validator->validate(textCopy, cursorCopy)
980         != QValidator::Acceptable)
981         return false;
982 #endif
983
984     if (!m_maskData)
985         return true;
986
987     if (str.length() != m_maxLength)
988         return false;
989
990     for (int i=0; i < m_maxLength; ++i) {
991         if (m_maskData[i].separator) {
992             if (str.at(i) != m_maskData[i].maskChar)
993                 return false;
994         } else {
995             if (!isValidInput(str.at(i), m_maskData[i].maskChar))
996                 return false;
997         }
998     }
999     return true;
1000 }
1001
1002 /*!
1003     \internal
1004
1005     Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
1006     specifies from where characters should be gotten when a separator is met in \a str - true means
1007     that blanks will be used, false that previous input is used.
1008     Calling this when no inputMask is set is undefined.
1009 */
1010 QString QLineControl::maskString(uint pos, const QString &str, bool clear) const
1011 {
1012     if (pos >= (uint)m_maxLength)
1013         return QString::fromLatin1("");
1014
1015     QString fill;
1016     fill = clear ? clearString(0, m_maxLength) : m_text;
1017
1018     int strIndex = 0;
1019     QString s = QString::fromLatin1("");
1020     int i = pos;
1021     while (i < m_maxLength) {
1022         if (strIndex < str.length()) {
1023             if (m_maskData[i].separator) {
1024                 s += m_maskData[i].maskChar;
1025                 if (str[(int)strIndex] == m_maskData[i].maskChar)
1026                     strIndex++;
1027                 ++i;
1028             } else {
1029                 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
1030                     switch (m_maskData[i].caseMode) {
1031                     case MaskInputData::Upper:
1032                         s += str[(int)strIndex].toUpper();
1033                         break;
1034                     case MaskInputData::Lower:
1035                         s += str[(int)strIndex].toLower();
1036                         break;
1037                     default:
1038                         s += str[(int)strIndex];
1039                     }
1040                     ++i;
1041                 } else {
1042                     // search for separator first
1043                     int n = findInMask(i, true, true, str[(int)strIndex]);
1044                     if (n != -1) {
1045                         if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
1046                             s += fill.mid(i, n-i+1);
1047                             i = n + 1; // update i to find + 1
1048                         }
1049                     } else {
1050                         // search for valid m_blank if not
1051                         n = findInMask(i, true, false, str[(int)strIndex]);
1052                         if (n != -1) {
1053                             s += fill.mid(i, n-i);
1054                             switch (m_maskData[n].caseMode) {
1055                             case MaskInputData::Upper:
1056                                 s += str[(int)strIndex].toUpper();
1057                                 break;
1058                             case MaskInputData::Lower:
1059                                 s += str[(int)strIndex].toLower();
1060                                 break;
1061                             default:
1062                                 s += str[(int)strIndex];
1063                             }
1064                             i = n + 1; // updates i to find + 1
1065                         }
1066                     }
1067                 }
1068                 ++strIndex;
1069             }
1070         } else
1071             break;
1072     }
1073
1074     return s;
1075 }
1076
1077
1078
1079 /*!
1080     \internal
1081
1082     Returns a "cleared" string with only separators and blank chars.
1083     Calling this when no inputMask is set is undefined.
1084 */
1085 QString QLineControl::clearString(uint pos, uint len) const
1086 {
1087     if (pos >= (uint)m_maxLength)
1088         return QString();
1089
1090     QString s;
1091     int end = qMin((uint)m_maxLength, pos + len);
1092     for (int i = pos; i < end; ++i)
1093         if (m_maskData[i].separator)
1094             s += m_maskData[i].maskChar;
1095         else
1096             s += m_blank;
1097
1098     return s;
1099 }
1100
1101 /*!
1102     \internal
1103
1104     Strips blank parts of the input in a QLineControl when an inputMask is set,
1105     separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
1106 */
1107 QString QLineControl::stripString(const QString &str) const
1108 {
1109     if (!m_maskData)
1110         return str;
1111
1112     QString s;
1113     int end = qMin(m_maxLength, (int)str.length());
1114     for (int i = 0; i < end; ++i)
1115         if (m_maskData[i].separator)
1116             s += m_maskData[i].maskChar;
1117         else
1118             if (str[i] != m_blank)
1119                 s += str[i];
1120
1121     return s;
1122 }
1123
1124 /*!
1125     \internal
1126     searches forward/backward in m_maskData for either a separator or a m_blank
1127 */
1128 int QLineControl::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
1129 {
1130     if (pos >= m_maxLength || pos < 0)
1131         return -1;
1132
1133     int end = forward ? m_maxLength : -1;
1134     int step = forward ? 1 : -1;
1135     int i = pos;
1136
1137     while (i != end) {
1138         if (findSeparator) {
1139             if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
1140                 return i;
1141         } else {
1142             if (!m_maskData[i].separator) {
1143                 if (searchChar.isNull())
1144                     return i;
1145                 else if (isValidInput(searchChar, m_maskData[i].maskChar))
1146                     return i;
1147             }
1148         }
1149         i += step;
1150     }
1151     return -1;
1152 }
1153
1154 void QLineControl::internalUndo(int until)
1155 {
1156     if (!isUndoAvailable())
1157         return;
1158     internalDeselect();
1159     while (m_undoState && m_undoState > until) {
1160         Command& cmd = m_history[--m_undoState];
1161         switch (cmd.type) {
1162         case Insert:
1163             m_text.remove(cmd.pos, 1);
1164             m_cursor = cmd.pos;
1165             break;
1166         case SetSelection:
1167             m_selstart = cmd.selStart;
1168             m_selend = cmd.selEnd;
1169             m_cursor = cmd.pos;
1170             break;
1171         case Remove:
1172         case RemoveSelection:
1173             m_text.insert(cmd.pos, cmd.uc);
1174             m_cursor = cmd.pos + 1;
1175             break;
1176         case Delete:
1177         case DeleteSelection:
1178             m_text.insert(cmd.pos, cmd.uc);
1179             m_cursor = cmd.pos;
1180             break;
1181         case Separator:
1182             continue;
1183         }
1184         if (until < 0 && m_undoState) {
1185             Command& next = m_history[m_undoState-1];
1186             if (next.type != cmd.type && next.type < RemoveSelection
1187                  && (cmd.type < RemoveSelection || next.type == Separator))
1188                 break;
1189         }
1190     }
1191     m_textDirty = true;
1192     emitCursorPositionChanged();
1193 }
1194
1195 void QLineControl::internalRedo()
1196 {
1197     if (!isRedoAvailable())
1198         return;
1199     internalDeselect();
1200     while (m_undoState < (int)m_history.size()) {
1201         Command& cmd = m_history[m_undoState++];
1202         switch (cmd.type) {
1203         case Insert:
1204             m_text.insert(cmd.pos, cmd.uc);
1205             m_cursor = cmd.pos + 1;
1206             break;
1207         case SetSelection:
1208             m_selstart = cmd.selStart;
1209             m_selend = cmd.selEnd;
1210             m_cursor = cmd.pos;
1211             break;
1212         case Remove:
1213         case Delete:
1214         case RemoveSelection:
1215         case DeleteSelection:
1216             m_text.remove(cmd.pos, 1);
1217             m_selstart = cmd.selStart;
1218             m_selend = cmd.selEnd;
1219             m_cursor = cmd.pos;
1220             break;
1221         case Separator:
1222             m_selstart = cmd.selStart;
1223             m_selend = cmd.selEnd;
1224             m_cursor = cmd.pos;
1225             break;
1226         }
1227         if (m_undoState < (int)m_history.size()) {
1228             Command& next = m_history[m_undoState];
1229             if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
1230                  && (next.type < RemoveSelection || cmd.type == Separator))
1231                 break;
1232         }
1233     }
1234     m_textDirty = true;
1235     emitCursorPositionChanged();
1236 }
1237
1238 /*!
1239     \internal
1240
1241     If the current cursor position differs from the last emitted cursor
1242     position, emits cursorPositionChanged().
1243 */
1244 void QLineControl::emitCursorPositionChanged()
1245 {
1246     if (m_cursor != m_lastCursorPos) {
1247         const int oldLast = m_lastCursorPos;
1248         m_lastCursorPos = m_cursor;
1249         cursorPositionChanged(oldLast, m_cursor);
1250 #ifndef QT_NO_ACCESSIBILITY
1251         QAccessible::updateAccessibility(parent(), 0, QAccessible::TextCaretMoved);
1252 #endif
1253     }
1254 }
1255
1256
1257 void QLineControl::setCursorBlinkPeriod(int msec)
1258 {
1259     if (msec == m_blinkPeriod)
1260         return;
1261     if (m_blinkTimer) {
1262         killTimer(m_blinkTimer);
1263     }
1264     if (msec) {
1265         m_blinkTimer = startTimer(msec / 2);
1266         m_blinkStatus = 1;
1267     } else {
1268         m_blinkTimer = 0;
1269         if (m_blinkStatus == 1)
1270             emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect());
1271     }
1272     m_blinkPeriod = msec;
1273 }
1274
1275 void QLineControl::resetCursorBlinkTimer()
1276 {
1277     if (m_blinkPeriod == 0 || m_blinkTimer == 0)
1278         return;
1279     killTimer(m_blinkTimer);
1280     m_blinkTimer = startTimer(m_blinkPeriod / 2);
1281     m_blinkStatus = 1;
1282 }
1283
1284 void QLineControl::timerEvent(QTimerEvent *event)
1285 {
1286     if (event->timerId() == m_blinkTimer) {
1287         m_blinkStatus = !m_blinkStatus;
1288         emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect());
1289     } else if (event->timerId() == m_deleteAllTimer) {
1290         killTimer(m_deleteAllTimer);
1291         m_deleteAllTimer = 0;
1292         clear();
1293     } else if (event->timerId() == m_tripleClickTimer) {
1294         killTimer(m_tripleClickTimer);
1295         m_tripleClickTimer = 0;
1296     }
1297 }
1298
1299 bool QLineControl::processEvent(QEvent* ev)
1300 {
1301 #ifdef QT_KEYPAD_NAVIGATION
1302     if (QGuiApplication::keypadNavigationEnabled()) {
1303         if ((ev->type() == QEvent::KeyPress) || (ev->type() == QEvent::KeyRelease)) {
1304             QKeyEvent *ke = (QKeyEvent *)ev;
1305             if (ke->key() == Qt::Key_Back) {
1306                 if (ke->isAutoRepeat()) {
1307                     // Swallow it. We don't want back keys running amok.
1308                     ke->accept();
1309                     return true;
1310                 }
1311                 if ((ev->type() == QEvent::KeyRelease)
1312                     && !isReadOnly()
1313                     && m_deleteAllTimer) {
1314                     killTimer(m_deleteAllTimer);
1315                     m_deleteAllTimer = 0;
1316                     backspace();
1317                     ke->accept();
1318                     return true;
1319                 }
1320             }
1321         }
1322     }
1323 #endif
1324     switch(ev->type()){
1325         case QEvent::MouseButtonPress:
1326         case QEvent::MouseButtonRelease:
1327         case QEvent::MouseButtonDblClick:
1328         case QEvent::MouseMove:
1329             processMouseEvent(static_cast<QMouseEvent*>(ev)); break;
1330         case QEvent::KeyPress:
1331         case QEvent::KeyRelease:
1332             processKeyEvent(static_cast<QKeyEvent*>(ev)); break;
1333         case QEvent::InputMethod:
1334             processInputMethodEvent(static_cast<QInputMethodEvent*>(ev)); break;
1335 #ifndef QT_NO_SHORTCUT
1336         case QEvent::ShortcutOverride:{
1337             if (isReadOnly())
1338                 return false;
1339             QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1340             if (ke == QKeySequence::Copy
1341                 || ke == QKeySequence::Paste
1342                 || ke == QKeySequence::Cut
1343                 || ke == QKeySequence::Redo
1344                 || ke == QKeySequence::Undo
1345                 || ke == QKeySequence::MoveToNextWord
1346                 || ke == QKeySequence::MoveToPreviousWord
1347                 || ke == QKeySequence::MoveToStartOfDocument
1348                 || ke == QKeySequence::MoveToEndOfDocument
1349                 || ke == QKeySequence::SelectNextWord
1350                 || ke == QKeySequence::SelectPreviousWord
1351                 || ke == QKeySequence::SelectStartOfLine
1352                 || ke == QKeySequence::SelectEndOfLine
1353                 || ke == QKeySequence::SelectStartOfBlock
1354                 || ke == QKeySequence::SelectEndOfBlock
1355                 || ke == QKeySequence::SelectStartOfDocument
1356                 || ke == QKeySequence::SelectAll
1357                 || ke == QKeySequence::SelectEndOfDocument) {
1358                 ke->accept();
1359             } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1360                        || ke->modifiers() == Qt::KeypadModifier) {
1361                 if (ke->key() < Qt::Key_Escape) {
1362                     ke->accept();
1363                 } else {
1364                     switch (ke->key()) {
1365                     case Qt::Key_Delete:
1366                     case Qt::Key_Home:
1367                     case Qt::Key_End:
1368                     case Qt::Key_Backspace:
1369                     case Qt::Key_Left:
1370                     case Qt::Key_Right:
1371                         ke->accept();
1372                     default:
1373                         break;
1374                     }
1375                 }
1376             }
1377         }
1378 #endif
1379         default:
1380             return false;
1381     }
1382     return true;
1383 }
1384
1385 void QLineControl::processMouseEvent(QMouseEvent* ev)
1386 {
1387
1388     switch (ev->type()) {
1389         case QEvent::MouseButtonPress:{
1390             if (m_tripleClickTimer
1391                 && (ev->pos() - m_tripleClick).manhattanLength() < qApp->styleHints()->startDragDistance()) {
1392                 selectAll();
1393                 return;
1394             }
1395             if (ev->button() == Qt::RightButton)
1396                 return;
1397
1398             bool mark = ev->modifiers() & Qt::ShiftModifier;
1399             int cursor = xToPos(ev->pos().x());
1400             moveCursor(cursor, mark);
1401             break;
1402         }
1403         case QEvent::MouseButtonDblClick:
1404             if (ev->button() == Qt::LeftButton) {
1405                 selectWordAtPos(xToPos(ev->pos().x()));
1406                 if (m_tripleClickTimer)
1407                     killTimer(m_tripleClickTimer);
1408                 m_tripleClickTimer = startTimer(qApp->styleHints()->mouseDoubleClickInterval());
1409                 m_tripleClick = ev->pos();
1410             }
1411             break;
1412         case QEvent::MouseButtonRelease:
1413 #ifndef QT_NO_CLIPBOARD
1414             if (QGuiApplication::clipboard()->supportsSelection()) {
1415                 if (ev->button() == Qt::LeftButton) {
1416                     copy(QClipboard::Selection);
1417                 } else if (!isReadOnly() && ev->button() == Qt::MidButton) {
1418                     deselect();
1419                     insert(QGuiApplication::clipboard()->text(QClipboard::Selection));
1420                 }
1421             }
1422 #endif
1423             break;
1424         case QEvent::MouseMove:
1425             if (ev->buttons() & Qt::LeftButton) {
1426                 moveCursor(xToPos(ev->pos().x()), true);
1427             }
1428             break;
1429         default:
1430             break;
1431     }
1432 }
1433
1434 void QLineControl::processKeyEvent(QKeyEvent* event)
1435 {
1436     bool inlineCompletionAccepted = false;
1437
1438     if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
1439         if (hasAcceptableInput() || fixup()) {
1440             emit accepted();
1441             emit editingFinished();
1442         }
1443         if (inlineCompletionAccepted)
1444             event->accept();
1445         else
1446             event->ignore();
1447         return;
1448     }
1449
1450     if (echoMode() == PasswordEchoOnEdit
1451         && !passwordEchoEditing()
1452         && !isReadOnly()
1453         && !event->text().isEmpty()
1454 #ifdef QT_KEYPAD_NAVIGATION
1455         && event->key() != Qt::Key_Select
1456         && event->key() != Qt::Key_Up
1457         && event->key() != Qt::Key_Down
1458         && event->key() != Qt::Key_Back
1459 #endif
1460         && !(event->modifiers() & Qt::ControlModifier)) {
1461         // Clear the edit and reset to normal echo mode while editing; the
1462         // echo mode switches back when the edit loses focus
1463         // ### resets current content.  dubious code; you can
1464         // navigate with keys up, down, back, and select(?), but if you press
1465         // "left" or "right" it clears?
1466         updatePasswordEchoEditing(true);
1467         clear();
1468     }
1469
1470     bool unknown = false;
1471     bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
1472
1473     if (false) {
1474     }
1475 #ifndef QT_NO_SHORTCUT
1476     else if (event == QKeySequence::Undo) {
1477         if (!isReadOnly())
1478             undo();
1479     }
1480     else if (event == QKeySequence::Redo) {
1481         if (!isReadOnly())
1482             redo();
1483     }
1484     else if (event == QKeySequence::SelectAll) {
1485         selectAll();
1486     }
1487 #ifndef QT_NO_CLIPBOARD
1488     else if (event == QKeySequence::Copy) {
1489         copy();
1490     }
1491     else if (event == QKeySequence::Paste) {
1492         if (!isReadOnly()) {
1493             QClipboard::Mode mode = QClipboard::Clipboard;
1494 #ifdef Q_WS_X11
1495             if (event->modifiers() == (Qt::CTRL | Qt::SHIFT) && event->key() == Qt::Key_Insert)
1496                 mode = QClipboard::Selection;
1497 #endif
1498             paste(mode);
1499         }
1500     }
1501     else if (event == QKeySequence::Cut) {
1502         if (!isReadOnly()) {
1503             copy();
1504             del();
1505         }
1506     }
1507     else if (event == QKeySequence::DeleteEndOfLine) {
1508         if (!isReadOnly()) {
1509             setSelection(cursor(), end());
1510             copy();
1511             del();
1512         }
1513     }
1514 #endif //QT_NO_CLIPBOARD
1515     else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
1516         home(0);
1517     }
1518     else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
1519         end(0);
1520     }
1521     else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
1522         home(1);
1523     }
1524     else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
1525         end(1);
1526     }
1527     else if (event == QKeySequence::MoveToNextChar) {
1528 #if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER)
1529         if (hasSelectedText()) {
1530 #else
1531         if (hasSelectedText() && m_completer
1532             && m_completer->completionMode() == QCompleter::InlineCompletion) {
1533 #endif
1534             moveCursor(selectionEnd(), false);
1535         } else {
1536             cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
1537         }
1538     }
1539     else if (event == QKeySequence::SelectNextChar) {
1540         cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
1541     }
1542     else if (event == QKeySequence::MoveToPreviousChar) {
1543 #if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER)
1544         if (hasSelectedText()) {
1545 #else
1546         if (hasSelectedText() && m_completer
1547             && m_completer->completionMode() == QCompleter::InlineCompletion) {
1548 #endif
1549             moveCursor(selectionStart(), false);
1550         } else {
1551             cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
1552         }
1553     }
1554     else if (event == QKeySequence::SelectPreviousChar) {
1555         cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
1556     }
1557     else if (event == QKeySequence::MoveToNextWord) {
1558         if (echoMode() == Normal)
1559             layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
1560         else
1561             layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
1562     }
1563     else if (event == QKeySequence::MoveToPreviousWord) {
1564         if (echoMode() == Normal)
1565             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
1566         else if (!isReadOnly()) {
1567             layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
1568         }
1569     }
1570     else if (event == QKeySequence::SelectNextWord) {
1571         if (echoMode() == Normal)
1572             layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
1573         else
1574             layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
1575     }
1576     else if (event == QKeySequence::SelectPreviousWord) {
1577         if (echoMode() == Normal)
1578             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
1579         else
1580             layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
1581     }
1582     else if (event == QKeySequence::Delete) {
1583         if (!isReadOnly())
1584             del();
1585     }
1586     else if (event == QKeySequence::DeleteEndOfWord) {
1587         if (!isReadOnly()) {
1588             cursorWordForward(true);
1589             del();
1590         }
1591     }
1592     else if (event == QKeySequence::DeleteStartOfWord) {
1593         if (!isReadOnly()) {
1594             cursorWordBackward(true);
1595             del();
1596         }
1597     }
1598 #endif // QT_NO_SHORTCUT
1599     else {
1600         bool handled = false;
1601 #ifdef Q_WS_MAC
1602         if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down) {
1603             Qt::KeyboardModifiers myModifiers = (event->modifiers() & ~Qt::KeypadModifier);
1604             if (myModifiers & Qt::ShiftModifier) {
1605                 if (myModifiers == (Qt::ControlModifier|Qt::ShiftModifier)
1606                         || myModifiers == (Qt::AltModifier|Qt::ShiftModifier)
1607                         || myModifiers == Qt::ShiftModifier) {
1608
1609                     event->key() == Qt::Key_Up ? home(1) : end(1);
1610                 }
1611             } else {
1612                 if ((myModifiers == Qt::ControlModifier
1613                      || myModifiers == Qt::AltModifier
1614                      || myModifiers == Qt::NoModifier)) {
1615                     event->key() == Qt::Key_Up ? home(0) : end(0);
1616                 }
1617             }
1618             handled = true;
1619         }
1620 #endif
1621         if (event->modifiers() & Qt::ControlModifier) {
1622             switch (event->key()) {
1623             case Qt::Key_Backspace:
1624                 if (!isReadOnly()) {
1625                     cursorWordBackward(true);
1626                     del();
1627                 }
1628                 break;
1629 #if defined(Q_WS_X11)
1630             case Qt::Key_E:
1631                 end(0);
1632                 break;
1633
1634             case Qt::Key_U:
1635                 if (!isReadOnly()) {
1636                     setSelection(0, text().size());
1637 #ifndef QT_NO_CLIPBOARD
1638                     copy();
1639 #endif
1640                     del();
1641                 }
1642             break;
1643 #endif
1644             default:
1645                 if (!handled)
1646                     unknown = true;
1647             }
1648         } else { // ### check for *no* modifier
1649             switch (event->key()) {
1650             case Qt::Key_Backspace:
1651                 if (!isReadOnly()) {
1652                     backspace();
1653                 }
1654                 break;
1655 #ifdef QT_KEYPAD_NAVIGATION
1656             case Qt::Key_Back:
1657                 if (QGuiApplication::keypadNavigationEnabled() && !event->isAutoRepeat()
1658                     && !isReadOnly()) {
1659                     if (text().length() == 0) {
1660                         setText(m_cancelText);
1661
1662                         if (passwordEchoEditing())
1663                             updatePasswordEchoEditing(false);
1664
1665                         emit editFocusChange(false);
1666                     } else if (!m_deleteAllTimer) {
1667                         m_deleteAllTimer = startTimer(750);
1668                     }
1669                 } else {
1670                     unknown = true;
1671                 }
1672                 break;
1673 #endif
1674             default:
1675                 if (!handled)
1676                     unknown = true;
1677             }
1678         }
1679     }
1680
1681     if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
1682         setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
1683         unknown = false;
1684     }
1685
1686     if (unknown && !isReadOnly()) {
1687         QString t = event->text();
1688         if (!t.isEmpty() && t.at(0).isPrint()) {
1689             insert(t);
1690             event->accept();
1691             return;
1692         }
1693     }
1694
1695     if (unknown)
1696         event->ignore();
1697     else
1698         event->accept();
1699 }
1700
1701
1702 QT_END_NAMESPACE
1703
1704 #endif