92c84d72e026edad3003c2030ed0767717f46067
[profile/ivi/qtbase.git] / src / gui / widgets / 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 #include "qlinecontrol_p.h"
43
44 #ifndef QT_NO_LINEEDIT
45
46 #include "qabstractitemview.h"
47 #include "qclipboard.h"
48 #ifndef QT_NO_ACCESSIBILITY
49 #include "qaccessible.h"
50 #endif
51 #ifndef QT_NO_IM
52 #include "qinputcontext.h"
53 #include "qlist.h"
54 #endif
55 #include "qapplication.h"
56 #ifndef QT_NO_GRAPHICSVIEW
57 #include "qgraphicssceneevent.h"
58 #endif
59
60 QT_BEGIN_NAMESPACE
61
62 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
63 static int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY;
64 #endif
65
66 /*!
67     \macro QT_GUI_PASSWORD_ECHO_DELAY
68
69     \internal
70
71     Defines the amount of time in milliseconds the last entered character
72     should be displayed unmasked in the Password echo mode.
73
74     If not defined in qplatformdefs.h there will be no delay in masking
75     password characters.
76 */
77
78 /*!
79     \internal
80
81     Updates the display text based of the current edit text
82     If the text has changed will emit displayTextChanged()
83 */
84 void QLineControl::updateDisplayText(bool forceUpdate)
85 {
86     QString orig = m_textLayout.text();
87     QString str;
88     if (m_echoMode == QLineEdit::NoEcho)
89         str = QString::fromLatin1("");
90     else
91         str = m_text;
92
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);
99             str[cursor] = uc;
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;
106             }
107         }
108 #endif
109     } else if (m_echoMode == QLineEdit::PasswordEchoOnEdit && !m_passwordEchoEditing) {
110         str.fill(m_passwordCharacter);
111     }
112
113     // replace certain non-printable characters with spaces (to avoid
114     // drawing boxes when using fonts that don't have glyphs for such
115     // characters)
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);
123     }
124
125     m_textLayout.setText(str);
126
127     QTextOption option;
128     option.setTextDirection(m_layoutDirection);
129     option.setFlags(QTextOption::IncludeTrailingSpaces);
130     m_textLayout.setTextOption(option);
131
132     m_textLayout.beginLayout();
133     QTextLine l = m_textLayout.createLine();
134     m_textLayout.endLayout();
135     m_ascent = qRound(l.ascent());
136
137     if (str != orig || forceUpdate)
138         emit displayTextChanged(str);
139 }
140
141 #ifndef QT_NO_CLIPBOARD
142 /*!
143     \internal
144
145     Copies the currently selected text into the clipboard using the given
146     \a mode.
147
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.
151 */
152 void QLineControl::copy(QClipboard::Mode mode) const
153 {
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()));
160     }
161 }
162
163 /*!
164     \internal
165
166     Inserts the text stored in the application clipboard into the line
167     control.
168
169     \sa insert()
170 */
171 void QLineControl::paste(QClipboard::Mode clipboardMode)
172 {
173     QString clip = QApplication::clipboard()->text(clipboardMode);
174     if (!clip.isEmpty() || hasSelectedText()) {
175         separate(); //make it a separate undo/redo command
176         insert(clip);
177         separate();
178     }
179 }
180
181 #endif // !QT_NO_CLIPBOARD
182
183 /*!
184     \internal
185
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.
189
190     \sa del()
191 */
192 void QLineControl::backspace()
193 {
194     int priorState = m_undoState;
195     if (hasSelectedText()) {
196         removeSelectedText();
197     } else if (m_cursor) {
198             --m_cursor;
199             if (m_maskData)
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);
208                     --m_cursor;
209                 }
210             }
211             internalDelete(true);
212     }
213     finishChange(priorState);
214 }
215
216 /*!
217     \internal
218
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.
222
223     \sa del()
224 */
225 void QLineControl::del()
226 {
227     int priorState = m_undoState;
228     if (hasSelectedText()) {
229         removeSelectedText();
230     } else {
231         int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
232         while (n--)
233             internalDelete();
234     }
235     finishChange(priorState);
236 }
237
238 /*!
239     \internal
240
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
243     the new text.
244 */
245 void QLineControl::insert(const QString &newText)
246 {
247     int priorState = m_undoState;
248     removeSelectedText();
249     internalInsert(newText);
250     finishChange(priorState);
251 }
252
253 /*!
254     \internal
255
256     Clears the line control text.
257 */
258 void QLineControl::clear()
259 {
260     int priorState = m_undoState;
261     m_selstart = 0;
262     m_selend = m_text.length();
263     removeSelectedText();
264     separate();
265     finishChange(priorState, /*update*/false, /*edited*/false);
266 }
267
268 /*!
269     \internal
270
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.
275 */
276 void QLineControl::setSelection(int start, int length)
277 {
278     if(start < 0 || start > (int)m_text.length()){
279         qWarning("QLineControl::setSelection: Invalid start position");
280         return;
281     }
282
283     if (length > 0) {
284         m_selDirty |= (start != m_selstart || start + length != m_selend);
285         m_selstart = start;
286         m_selend = qMin(start + length, (int)m_text.length());
287         m_cursor = m_selend;
288     } else if (length < 0){
289         m_selDirty |= (start != m_selend || start + length != m_selstart);
290         m_selstart = qMax(start + length, 0);
291         m_selend = start;
292         m_cursor = m_selstart;
293     } else if (m_selstart != m_selend) {
294         m_selDirty = true;
295         m_selstart = 0;
296         m_selend = 0;
297         m_cursor = start;
298     } else {
299         m_cursor = start;
300     }
301     if (m_selDirty) {
302         m_selDirty = false;
303         emit selectionChanged();
304     }
305     emitCursorPositionChanged();
306 }
307
308 void QLineControl::_q_clipboardChanged()
309 {
310 }
311
312 void QLineControl::_q_deleteSelected()
313 {
314     if (!hasSelectedText())
315         return;
316
317     int priorState = m_undoState;
318     emit resetInputContext();
319     removeSelectedText();
320     separate();
321     finishChange(priorState);
322 }
323
324 /*!
325     \internal
326
327     Initializes the line control with a starting text value of \a txt.
328 */
329 void QLineControl::init(const QString &txt)
330 {
331     m_text = txt;
332     updateDisplayText();
333     m_cursor = m_text.length();
334 }
335
336 /*!
337     \internal
338
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.
343 */
344 void QLineControl::updatePasswordEchoEditing(bool editing)
345 {
346     cancelPasswordEchoTimer();
347     m_passwordEchoEditing = editing;
348     updateDisplayText();
349 }
350
351 /*!
352     \internal
353
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.
357 */
358 int QLineControl::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const
359 {
360     return m_textLayout.lineAt(0).xToCursor(x, betweenOrOn);
361 }
362
363 /*!
364     \internal
365
366     Returns the bounds of the current cursor, as defined as a
367     between characters cursor.
368 */
369 QRect QLineControl::cursorRect() const
370 {
371     QTextLine l = m_textLayout.lineAt(0);
372     int c = m_cursor;
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;
378
379     return QRect(cix-5, 0, w+9, ch);
380 }
381
382 /*!
383     \internal
384
385     Fixes the current text so that it is valid given any set validators.
386
387     Returns true if the text was changed.  Otherwise returns false.
388 */
389 bool QLineControl::fixup() // this function assumes that validate currently returns != Acceptable
390 {
391 #ifndef QT_NO_VALIDATOR
392     if (m_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);
399             return true;
400         }
401     }
402 #endif
403     return false;
404 }
405
406 /*!
407     \internal
408
409     Moves the cursor to the given position \a pos.   If \a mark is true will
410     adjust the currently selected text.
411 */
412 void QLineControl::moveCursor(int pos, bool mark)
413 {
414     if (pos != m_cursor) {
415         separate();
416         if (m_maskData)
417             pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
418     }
419     if (mark) {
420         int anchor;
421         if (m_selend > m_selstart && m_cursor == m_selstart)
422             anchor = m_selend;
423         else if (m_selend > m_selstart && m_cursor == m_selend)
424             anchor = m_selstart;
425         else
426             anchor = m_cursor;
427         m_selstart = qMin(anchor, pos);
428         m_selend = qMax(anchor, pos);
429         updateDisplayText();
430     } else {
431         internalDeselect();
432     }
433     m_cursor = pos;
434     if (mark || m_selDirty) {
435         m_selDirty = false;
436         emit selectionChanged();
437     }
438     emitCursorPositionChanged();
439 }
440
441 /*!
442     \internal
443
444     Applies the given input method event \a event to the text of the line
445     control
446 */
447 void QLineControl::processInputMethodEvent(QInputMethodEvent *event)
448 {
449     int priorState = 0;
450     bool isGettingInput = !event->commitString().isEmpty()
451             || event->preeditString() != preeditAreaText()
452             || event->replacementLength() > 0;
453     bool cursorPositionChanged = false;
454
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);
460             m_selstart = 0;
461             m_selend = m_text.length();
462         }
463         removeSelectedText();
464     }
465
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());
469
470     m_cursor += event->replacementStart();
471     if (m_cursor < 0)
472         m_cursor = 0;
473
474     // insert commit string
475     if (event->replacementLength()) {
476         m_selstart = m_cursor;
477         m_selend = m_selstart + event->replacementLength();
478         removeSelectedText();
479     }
480     if (!event->commitString().isEmpty()) {
481         internalInsert(event->commitString());
482         cursorPositionChanged = true;
483     }
484
485     m_cursor = qBound(0, c, m_text.length());
486
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());
491             if (a.length) {
492                 m_selstart = qMax(0, qMin(a.start, m_text.length()));
493                 m_selend = m_cursor;
494                 if (m_selend < m_selstart) {
495                     qSwap(m_selstart, m_selend);
496                 }
497                 m_selDirty = true;
498             } else {
499                 m_selstart = m_selend = 0;
500             }
501             cursorPositionChanged = true;
502         }
503     }
504 #ifndef QT_NO_IM
505     setPreeditArea(m_cursor, event->preeditString());
506 #endif //QT_NO_IM
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();
518             if (f.isValid()) {
519                 QTextLayout::FormatRange o;
520                 o.start = a.start + m_cursor;
521                 o.length = a.length;
522                 o.format = f;
523                 formats.append(o);
524             }
525         }
526     }
527     m_textLayout.setAdditionalFormats(formats);
528     updateDisplayText(/*force*/ true);
529     if (isGettingInput) {
530         finishChange(priorState);
531     } else {
532         if (cursorPositionChanged)
533             emitCursorPositionChanged();
534         else if (m_preeditCursor != oldPreeditCursor)
535             emit updateMicroFocus();
536         if (m_selDirty) {
537             m_selDirty = false;
538             emit selectionChanged();
539         }
540     }
541 }
542
543 /*!
544     \internal
545
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.
549
550     If the flags contain DrawSelections, then the selection or input mask
551     backgrounds and foregrounds will be applied before drawing the text.
552
553     If the flags contain DrawCursor a cursor of the current cursorWidth()
554     will be drawn after drawing the text.
555
556     The display text will only be drawn if the flags contain DrawText
557 */
558 void QLineControl::draw(QPainter *painter, const QPoint &offset, const QRect &clip, int flags)
559 {
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));
568         } else {
569             // mask selection
570             if(!m_blinkPeriod || m_blinkStatus){
571                 o.start = m_cursor;
572                 o.length = 1;
573                 o.format.setBackground(m_palette.brush(QPalette::Text));
574                 o.format.setForeground(m_palette.brush(QPalette::Window));
575             }
576         }
577         selections.append(o);
578     }
579
580     if (flags & DrawText)
581         m_textLayout.draw(painter, offset, selections, clip);
582
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);
589     }
590 }
591
592 /*!
593     \internal
594
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
597     cursor mode.
598 */
599 void QLineControl::selectWordAtPos(int cursor)
600 {
601     int next = cursor + 1;
602     if(next > end())
603         --next;
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())
609         --end;
610     moveCursor(end, true);
611 }
612
613 /*!
614     \internal
615
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.
618
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
621     change.
622
623     The \a update value is currently unused.
624 */
625 bool QLineControl::finishChange(int validateFromState, bool update, bool edited)
626 {
627     Q_UNUSED(update)
628     bool lineDirty = m_selDirty;
629     if (m_textDirty) {
630         // do validation
631         bool wasValidInput = m_validInput;
632         m_validInput = true;
633 #ifndef QT_NO_VALIDATOR
634         if (m_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);
639             if (m_validInput) {
640                 if (m_text != textCopy) {
641                     internalSetText(textCopy, cursorCopy);
642                     return true;
643                 }
644                 m_cursor = cursorCopy;
645             }
646         }
647 #endif
648         if (validateFromState >= 0 && wasValidInput && !m_validInput) {
649             if (m_transactions.count())
650                 return false;
651             internalUndo(validateFromState);
652             m_history.resize(m_undoState);
653             if (m_modifiedState > m_undoState)
654                 m_modifiedState = -1;
655             m_validInput = true;
656             m_textDirty = false;
657         }
658         updateDisplayText();
659         lineDirty |= m_textDirty;
660         if (m_textDirty) {
661             m_textDirty = false;
662             QString actualText = text();
663             if (edited)
664                 emit textEdited(actualText);
665             emit textChanged(actualText);
666         }
667     }
668     if (m_selDirty) {
669         m_selDirty = false;
670         emit selectionChanged();
671     }
672     emitCursorPositionChanged();
673     return true;
674 }
675
676 /*!
677     \internal
678
679     An internal function for setting the text of the line control.
680 */
681 void QLineControl::internalSetText(const QString &txt, int pos, bool edited)
682 {
683     cancelPasswordEchoTimer();
684     internalDeselect();
685     emit resetInputContext();
686     QString oldText = m_text;
687     if (m_maskData) {
688         m_text = maskString(0, txt, true);
689         m_text += clearString(m_text.length(), m_maxLength - m_text.length());
690     } else {
691         m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
692     }
693     m_history.clear();
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);
698
699 #ifndef QT_NO_ACCESSIBILITY
700     if (changed)
701         QAccessible::updateAccessibility(parent(), 0, QAccessible::TextUpdated);
702 #endif
703 }
704
705
706 /*!
707     \internal
708
709     Adds the given \a command to the undo history
710     of the line control.  Does not apply the command.
711 */
712 void QLineControl::addCommand(const Command &cmd)
713 {
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);
717     } else {
718         m_history.resize(m_undoState + 1);
719     }
720     m_separator = false;
721     m_history[m_undoState++] = cmd;
722 }
723
724 /*!
725     \internal
726
727     Inserts the given string \a s into the line
728     control.
729
730     Also adds the appropriate commands into the undo history.
731     This function does not call finishChange(), and may leave the text
732     in an invalid state.
733 */
734 void QLineControl::internalInsert(const QString &s)
735 {
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);
741     }
742 #endif
743     if (hasSelectedText())
744         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
745     if (m_maskData) {
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));
750         }
751         m_text.replace(m_cursor, ms.length(), ms);
752         m_cursor += ms.length();
753         m_cursor = nextMaskBlank(m_cursor);
754         m_textDirty = true;
755     } else {
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));
761             m_textDirty = true;
762         }
763     }
764 }
765
766 /*!
767     \internal
768
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.
772
773     Also adds the appropriate commands into the undo history.
774     This function does not call finishChange(), and may leave the text
775     in an invalid state.
776 */
777 void QLineControl::internalDelete(bool wasBackspace)
778 {
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));
785         if (m_maskData) {
786             m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
787             addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
788         } else {
789             m_text.remove(m_cursor, 1);
790         }
791         m_textDirty = true;
792     }
793 }
794
795 /*!
796     \internal
797
798     removes the currently selected text from the line control.
799
800     Also adds the appropriate commands into the undo history.
801     This function does not call finishChange(), and may leave the text
802     in an invalid state.
803 */
804 void QLineControl::removeSelectedText()
805 {
806     if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
807         cancelPasswordEchoTimer();
808         separate();
809         int i ;
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));
818         } else {
819             for (i = m_selend-1; i >= m_selstart; --i)
820                 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
821         }
822         if (m_maskData) {
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));
826         } else {
827             m_text.remove(m_selstart, m_selend - m_selstart);
828         }
829         if (m_cursor > m_selstart)
830             m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
831         internalDeselect();
832         m_textDirty = true;
833     }
834 }
835
836 /*!
837     \internal
838
839     Parses the input mask specified by \a maskFields to generate
840     the mask data used to handle input masks.
841 */
842 void QLineControl::parseInputMask(const QString &maskFields)
843 {
844     int delimiter = maskFields.indexOf(QLatin1Char(';'));
845     if (maskFields.isEmpty() || delimiter == 0) {
846         if (m_maskData) {
847             delete [] m_maskData;
848             m_maskData = 0;
849             m_maxLength = 32767;
850             internalSetText(QString());
851         }
852         return;
853     }
854
855     if (delimiter == -1) {
856         m_blank = QLatin1Char(' ');
857         m_inputMask = maskFields;
858     } else {
859         m_inputMask = maskFields.left(delimiter);
860         m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
861     }
862
863     // calculate m_maxLength / m_maskData length
864     m_maxLength = 0;
865     QChar c = 0;
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('\\')) {
869             m_maxLength++;
870             continue;
871         }
872         if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
873              c != QLatin1Char('<') && c != QLatin1Char('>') &&
874              c != QLatin1Char('{') && c != QLatin1Char('}') &&
875              c != QLatin1Char('[') && c != QLatin1Char(']'))
876             m_maxLength++;
877     }
878
879     delete [] m_maskData;
880     m_maskData = new MaskInputData[m_maxLength];
881
882     MaskInputData::Casemode m = MaskInputData::NoCaseMode;
883     c = 0;
884     bool s;
885     bool escape = false;
886     int index = 0;
887     for (int i = 0; i < m_inputMask.length(); i++) {
888         c = m_inputMask.at(i);
889         if (escape) {
890             s = true;
891             m_maskData[index].maskChar = c;
892             m_maskData[index].separator = s;
893             m_maskData[index].caseMode = m;
894             index++;
895             escape = false;
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()) {
904             case 'A':
905             case 'a':
906             case 'N':
907             case 'n':
908             case 'X':
909             case 'x':
910             case '9':
911             case '0':
912             case 'D':
913             case 'd':
914             case '#':
915             case 'H':
916             case 'h':
917             case 'B':
918             case 'b':
919                 s = false;
920                 break;
921             case '\\':
922                 escape = true;
923             default:
924                 s = true;
925                 break;
926             }
927
928             if (!escape) {
929                 m_maskData[index].maskChar = c;
930                 m_maskData[index].separator = s;
931                 m_maskData[index].caseMode = m;
932                 index++;
933             }
934         }
935     }
936     internalSetText(m_text);
937 }
938
939
940 /*!
941     \internal
942
943     checks if the key is valid compared to the inputMask
944 */
945 bool QLineControl::isValidInput(QChar key, QChar mask) const
946 {
947     switch (mask.unicode()) {
948     case 'A':
949         if (key.isLetter())
950             return true;
951         break;
952     case 'a':
953         if (key.isLetter() || key == m_blank)
954             return true;
955         break;
956     case 'N':
957         if (key.isLetterOrNumber())
958             return true;
959         break;
960     case 'n':
961         if (key.isLetterOrNumber() || key == m_blank)
962             return true;
963         break;
964     case 'X':
965         if (key.isPrint())
966             return true;
967         break;
968     case 'x':
969         if (key.isPrint() || key == m_blank)
970             return true;
971         break;
972     case '9':
973         if (key.isNumber())
974             return true;
975         break;
976     case '0':
977         if (key.isNumber() || key == m_blank)
978             return true;
979         break;
980     case 'D':
981         if (key.isNumber() && key.digitValue() > 0)
982             return true;
983         break;
984     case 'd':
985         if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
986             return true;
987         break;
988     case '#':
989         if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
990             return true;
991         break;
992     case 'B':
993         if (key == QLatin1Char('0') || key == QLatin1Char('1'))
994             return true;
995         break;
996     case 'b':
997         if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
998             return true;
999         break;
1000     case 'H':
1001         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
1002             return true;
1003         break;
1004     case 'h':
1005         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
1006             return true;
1007         break;
1008     default:
1009         break;
1010     }
1011     return false;
1012 }
1013
1014 /*!
1015     \internal
1016
1017     Returns true if the given text \a str is valid for any
1018     validator or input mask set for the line control.
1019
1020     Otherwise returns false
1021 */
1022 bool QLineControl::hasAcceptableInput(const QString &str) const
1023 {
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)
1029         return false;
1030 #endif
1031
1032     if (!m_maskData)
1033         return true;
1034
1035     if (str.length() != m_maxLength)
1036         return false;
1037
1038     for (int i=0; i < m_maxLength; ++i) {
1039         if (m_maskData[i].separator) {
1040             if (str.at(i) != m_maskData[i].maskChar)
1041                 return false;
1042         } else {
1043             if (!isValidInput(str.at(i), m_maskData[i].maskChar))
1044                 return false;
1045         }
1046     }
1047     return true;
1048 }
1049
1050 /*!
1051     \internal
1052
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.
1057 */
1058 QString QLineControl::maskString(uint pos, const QString &str, bool clear) const
1059 {
1060     if (pos >= (uint)m_maxLength)
1061         return QString::fromLatin1("");
1062
1063     QString fill;
1064     fill = clear ? clearString(0, m_maxLength) : m_text;
1065
1066     int strIndex = 0;
1067     QString s = QString::fromLatin1("");
1068     int i = pos;
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)
1074                     strIndex++;
1075                 ++i;
1076             } else {
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();
1081                         break;
1082                     case MaskInputData::Lower:
1083                         s += str[(int)strIndex].toLower();
1084                         break;
1085                     default:
1086                         s += str[(int)strIndex];
1087                     }
1088                     ++i;
1089                 } else {
1090                     // search for separator first
1091                     int n = findInMask(i, true, true, str[(int)strIndex]);
1092                     if (n != -1) {
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
1096                         }
1097                     } else {
1098                         // search for valid m_blank if not
1099                         n = findInMask(i, true, false, str[(int)strIndex]);
1100                         if (n != -1) {
1101                             s += fill.mid(i, n-i);
1102                             switch (m_maskData[n].caseMode) {
1103                             case MaskInputData::Upper:
1104                                 s += str[(int)strIndex].toUpper();
1105                                 break;
1106                             case MaskInputData::Lower:
1107                                 s += str[(int)strIndex].toLower();
1108                                 break;
1109                             default:
1110                                 s += str[(int)strIndex];
1111                             }
1112                             i = n + 1; // updates i to find + 1
1113                         }
1114                     }
1115                 }
1116                 ++strIndex;
1117             }
1118         } else
1119             break;
1120     }
1121
1122     return s;
1123 }
1124
1125
1126
1127 /*!
1128     \internal
1129
1130     Returns a "cleared" string with only separators and blank chars.
1131     Calling this when no inputMask is set is undefined.
1132 */
1133 QString QLineControl::clearString(uint pos, uint len) const
1134 {
1135     if (pos >= (uint)m_maxLength)
1136         return QString();
1137
1138     QString s;
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;
1143         else
1144             s += m_blank;
1145
1146     return s;
1147 }
1148
1149 /*!
1150     \internal
1151
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".
1154 */
1155 QString QLineControl::stripString(const QString &str) const
1156 {
1157     if (!m_maskData)
1158         return str;
1159
1160     QString s;
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;
1165         else
1166             if (str[i] != m_blank)
1167                 s += str[i];
1168
1169     return s;
1170 }
1171
1172 /*!
1173     \internal
1174     searches forward/backward in m_maskData for either a separator or a m_blank
1175 */
1176 int QLineControl::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
1177 {
1178     if (pos >= m_maxLength || pos < 0)
1179         return -1;
1180
1181     int end = forward ? m_maxLength : -1;
1182     int step = forward ? 1 : -1;
1183     int i = pos;
1184
1185     while (i != end) {
1186         if (findSeparator) {
1187             if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
1188                 return i;
1189         } else {
1190             if (!m_maskData[i].separator) {
1191                 if (searchChar.isNull())
1192                     return i;
1193                 else if (isValidInput(searchChar, m_maskData[i].maskChar))
1194                     return i;
1195             }
1196         }
1197         i += step;
1198     }
1199     return -1;
1200 }
1201
1202 void QLineControl::internalUndo(int until)
1203 {
1204     if (!isUndoAvailable())
1205         return;
1206     cancelPasswordEchoTimer();
1207     internalDeselect();
1208     while (m_undoState && m_undoState > until) {
1209         Command& cmd = m_history[--m_undoState];
1210         switch (cmd.type) {
1211         case Insert:
1212             m_text.remove(cmd.pos, 1);
1213             m_cursor = cmd.pos;
1214             break;
1215         case SetSelection:
1216             m_selstart = cmd.selStart;
1217             m_selend = cmd.selEnd;
1218             m_cursor = cmd.pos;
1219             break;
1220         case Remove:
1221         case RemoveSelection:
1222             m_text.insert(cmd.pos, cmd.uc);
1223             m_cursor = cmd.pos + 1;
1224             break;
1225         case Delete:
1226         case DeleteSelection:
1227             m_text.insert(cmd.pos, cmd.uc);
1228             m_cursor = cmd.pos;
1229             break;
1230         case Separator:
1231             continue;
1232         }
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))
1237                 break;
1238         }
1239     }
1240     m_textDirty = true;
1241     emitCursorPositionChanged();
1242 }
1243
1244 void QLineControl::internalRedo()
1245 {
1246     if (!isRedoAvailable())
1247         return;
1248     internalDeselect();
1249     while (m_undoState < (int)m_history.size()) {
1250         Command& cmd = m_history[m_undoState++];
1251         switch (cmd.type) {
1252         case Insert:
1253             m_text.insert(cmd.pos, cmd.uc);
1254             m_cursor = cmd.pos + 1;
1255             break;
1256         case SetSelection:
1257             m_selstart = cmd.selStart;
1258             m_selend = cmd.selEnd;
1259             m_cursor = cmd.pos;
1260             break;
1261         case Remove:
1262         case Delete:
1263         case RemoveSelection:
1264         case DeleteSelection:
1265             m_text.remove(cmd.pos, 1);
1266             m_selstart = cmd.selStart;
1267             m_selend = cmd.selEnd;
1268             m_cursor = cmd.pos;
1269             break;
1270         case Separator:
1271             m_selstart = cmd.selStart;
1272             m_selend = cmd.selEnd;
1273             m_cursor = cmd.pos;
1274             break;
1275         }
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))
1280                 break;
1281         }
1282     }
1283     m_textDirty = true;
1284     emitCursorPositionChanged();
1285 }
1286
1287 /*!
1288     \internal
1289
1290     If the current cursor position differs from the last emitted cursor
1291     position, emits cursorPositionChanged().
1292 */
1293 void QLineControl::emitCursorPositionChanged()
1294 {
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);
1301 #endif
1302     }
1303 }
1304
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)
1309 {
1310     int start = m_completer->currentRow();
1311     if (start == -1)
1312         return false;
1313     int i = start + dir;
1314     if (dir == 0) dir = 1;
1315     do {
1316         if (!m_completer->setCurrentRow(i)) {
1317             if (!m_completer->wrapAround())
1318                 break;
1319             i = i > 0 ? 0 : m_completer->completionCount() - 1;
1320         } else {
1321             QModelIndex currentIndex = m_completer->currentIndex();
1322             if (m_completer->completionModel()->flags(currentIndex) & Qt::ItemIsEnabled)
1323                 return true;
1324             i += dir;
1325         }
1326     } while (i != start);
1327
1328     m_completer->setCurrentRow(start); // restore
1329     return false;
1330 }
1331
1332 void QLineControl::complete(int key)
1333 {
1334     if (!m_completer || isReadOnly() || echoMode() != QLineEdit::Normal)
1335         return;
1336
1337     QString text = this->text();
1338     if (m_completer->completionMode() == QCompleter::InlineCompletion) {
1339         if (key == Qt::Key_Backspace)
1340             return;
1341         int n = 0;
1342         if (key == Qt::Key_Up || key == Qt::Key_Down) {
1343             if (textAfterSelection().length())
1344                 return;
1345             QString prefix = hasSelectedText() ? textBeforeSelection()
1346                 : text;
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);
1350             } else {
1351                 n = (key == Qt::Key_Up) ? -1 : +1;
1352             }
1353         } else {
1354             m_completer->setCompletionPrefix(text);
1355         }
1356         if (!advanceToEnabledItem(n))
1357             return;
1358     } else {
1359 #ifndef QT_KEYPAD_NAVIGATION
1360         if (text.isEmpty()) {
1361             m_completer->popup()->hide();
1362             return;
1363         }
1364 #endif
1365         m_completer->setCompletionPrefix(text);
1366     }
1367
1368     m_completer->complete();
1369 }
1370 #endif
1371
1372 void QLineControl::setCursorBlinkPeriod(int msec)
1373 {
1374     if (msec == m_blinkPeriod)
1375         return;
1376     if (m_blinkTimer) {
1377         killTimer(m_blinkTimer);
1378     }
1379     if (msec) {
1380         m_blinkTimer = startTimer(msec / 2);
1381         m_blinkStatus = 1;
1382     } else {
1383         m_blinkTimer = 0;
1384         if (m_blinkStatus == 1)
1385             emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect());
1386     }
1387     m_blinkPeriod = msec;
1388 }
1389
1390 void QLineControl::resetCursorBlinkTimer()
1391 {
1392     if (m_blinkPeriod == 0 || m_blinkTimer == 0)
1393         return;
1394     killTimer(m_blinkTimer);
1395     m_blinkTimer = startTimer(m_blinkPeriod / 2);
1396     m_blinkStatus = 1;
1397 }
1398
1399 void QLineControl::timerEvent(QTimerEvent *event)
1400 {
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;
1407         clear();
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();
1416 #endif
1417     }
1418 }
1419
1420 bool QLineControl::processEvent(QEvent* ev)
1421 {
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.
1429                     ke->accept();
1430                     return true;
1431                 }
1432                 if ((ev->type() == QEvent::KeyRelease)
1433                     && !isReadOnly()
1434                     && m_deleteAllTimer) {
1435                     killTimer(m_deleteAllTimer);
1436                     m_deleteAllTimer = 0;
1437                     backspace();
1438                     ke->accept();
1439                     return true;
1440                 }
1441             }
1442         }
1443     }
1444 #endif
1445     switch(ev->type()){
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;
1455         }
1456 #endif
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:{
1469             if (isReadOnly())
1470                 return false;
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) {
1490                 ke->accept();
1491             } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1492                        || ke->modifiers() == Qt::KeypadModifier) {
1493                 if (ke->key() < Qt::Key_Escape) {
1494                     ke->accept();
1495                 } else {
1496                     switch (ke->key()) {
1497                     case Qt::Key_Delete:
1498                     case Qt::Key_Home:
1499                     case Qt::Key_End:
1500                     case Qt::Key_Backspace:
1501                     case Qt::Key_Left:
1502                     case Qt::Key_Right:
1503                         ke->accept();
1504                     default:
1505                         break;
1506                     }
1507                 }
1508             }
1509         }
1510 #endif
1511         default:
1512             return false;
1513     }
1514     return true;
1515 }
1516
1517 void QLineControl::processMouseEvent(QMouseEvent* ev)
1518 {
1519
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()) {
1526                 selectAll();
1527                 return;
1528             }
1529             if (ev->button() == Qt::RightButton)
1530                 return;
1531
1532             bool mark = ev->modifiers() & Qt::ShiftModifier;
1533             int cursor = xToPos(ev->pos().x());
1534             moveCursor(cursor, mark);
1535             break;
1536         }
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();
1545             }
1546             break;
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) {
1554                     deselect();
1555                     insert(QApplication::clipboard()->text(QClipboard::Selection));
1556                 }
1557             }
1558 #endif
1559             break;
1560         case QEvent::GraphicsSceneMouseMove:
1561         case QEvent::MouseMove:
1562             if (ev->buttons() & Qt::LeftButton) {
1563                 moveCursor(xToPos(ev->pos().x()), true);
1564             }
1565             break;
1566         default:
1567             break;
1568     }
1569 }
1570
1571 void QLineControl::processKeyEvent(QKeyEvent* event)
1572 {
1573     bool inlineCompletionAccepted = false;
1574
1575 #ifndef QT_NO_COMPLETER
1576     if (m_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:
1586                 event->ignore();
1587                 return;
1588             case Qt::Key_Enter:
1589             case Qt::Key_Return:
1590             case Qt::Key_F4:
1591 #ifdef QT_KEYPAD_NAVIGATION
1592             case Qt::Key_Select:
1593                 if (!QApplication::keypadNavigationEnabled())
1594                     break;
1595 #endif
1596                 m_completer->popup()->hide(); // just hide. will end up propagating to parent
1597             default:
1598                 break; // normal key processing
1599             }
1600         } else if (completionMode == QCompleter::InlineCompletion) {
1601             switch (event->key()) {
1602             case Qt::Key_Enter:
1603             case Qt::Key_Return:
1604             case Qt::Key_F4:
1605 #ifdef QT_KEYPAD_NAVIGATION
1606             case Qt::Key_Select:
1607                 if (!QApplication::keypadNavigationEnabled())
1608                     break;
1609 #endif
1610                 if (!m_completer->currentCompletion().isEmpty() && hasSelectedText()
1611                     && textAfterSelection().isEmpty()) {
1612                     setText(m_completer->currentCompletion());
1613                     inlineCompletionAccepted = true;
1614                 }
1615             default:
1616                 break; // normal key processing
1617             }
1618         }
1619     }
1620 #endif // QT_NO_COMPLETER
1621
1622     if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
1623         if (hasAcceptableInput() || fixup()) {
1624             emit accepted();
1625             emit editingFinished();
1626         }
1627         if (inlineCompletionAccepted)
1628             event->accept();
1629         else
1630             event->ignore();
1631         return;
1632     }
1633
1634     if (echoMode() == QLineEdit::PasswordEchoOnEdit
1635         && !passwordEchoEditing()
1636         && !isReadOnly()
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
1643 #endif
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);
1651         clear();
1652     }
1653
1654     bool unknown = false;
1655     bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
1656
1657     if (false) {
1658     }
1659 #ifndef QT_NO_SHORTCUT
1660     else if (event == QKeySequence::Undo) {
1661         if (!isReadOnly())
1662             undo();
1663     }
1664     else if (event == QKeySequence::Redo) {
1665         if (!isReadOnly())
1666             redo();
1667     }
1668     else if (event == QKeySequence::SelectAll) {
1669         selectAll();
1670     }
1671 #ifndef QT_NO_CLIPBOARD
1672     else if (event == QKeySequence::Copy) {
1673         copy();
1674     }
1675     else if (event == QKeySequence::Paste) {
1676         if (!isReadOnly()) {
1677             QClipboard::Mode mode = QClipboard::Clipboard;
1678 #ifdef Q_WS_X11
1679             if (event->modifiers() == (Qt::CTRL | Qt::SHIFT) && event->key() == Qt::Key_Insert)
1680                 mode = QClipboard::Selection;
1681 #endif
1682             paste(mode);
1683         }
1684     }
1685     else if (event == QKeySequence::Cut) {
1686         if (!isReadOnly()) {
1687             copy();
1688             del();
1689         }
1690     }
1691     else if (event == QKeySequence::DeleteEndOfLine) {
1692         if (!isReadOnly()) {
1693             setSelection(cursor(), end());
1694             copy();
1695             del();
1696         }
1697     }
1698 #endif //QT_NO_CLIPBOARD
1699     else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
1700         home(0);
1701     }
1702     else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
1703         end(0);
1704     }
1705     else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
1706         home(1);
1707     }
1708     else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
1709         end(1);
1710     }
1711     else if (event == QKeySequence::MoveToNextChar) {
1712 #if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER)
1713         if (hasSelectedText()) {
1714 #else
1715         if (hasSelectedText() && m_completer
1716             && m_completer->completionMode() == QCompleter::InlineCompletion) {
1717 #endif
1718             moveCursor(selectionEnd(), false);
1719         } else {
1720             cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
1721         }
1722     }
1723     else if (event == QKeySequence::SelectNextChar) {
1724         cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
1725     }
1726     else if (event == QKeySequence::MoveToPreviousChar) {
1727 #if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER)
1728         if (hasSelectedText()) {
1729 #else
1730         if (hasSelectedText() && m_completer
1731             && m_completer->completionMode() == QCompleter::InlineCompletion) {
1732 #endif
1733             moveCursor(selectionStart(), false);
1734         } else {
1735             cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
1736         }
1737     }
1738     else if (event == QKeySequence::SelectPreviousChar) {
1739         cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
1740     }
1741     else if (event == QKeySequence::MoveToNextWord) {
1742         if (echoMode() == QLineEdit::Normal)
1743             layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
1744         else
1745             layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
1746     }
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);
1752         }
1753     }
1754     else if (event == QKeySequence::SelectNextWord) {
1755         if (echoMode() == QLineEdit::Normal)
1756             layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
1757         else
1758             layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
1759     }
1760     else if (event == QKeySequence::SelectPreviousWord) {
1761         if (echoMode() == QLineEdit::Normal)
1762             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
1763         else
1764             layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
1765     }
1766     else if (event == QKeySequence::Delete) {
1767         if (!isReadOnly())
1768             del();
1769     }
1770     else if (event == QKeySequence::DeleteEndOfWord) {
1771         if (!isReadOnly()) {
1772             cursorWordForward(true);
1773             del();
1774         }
1775     }
1776     else if (event == QKeySequence::DeleteStartOfWord) {
1777         if (!isReadOnly()) {
1778             cursorWordBackward(true);
1779             del();
1780         }
1781     }
1782 #endif // QT_NO_SHORTCUT
1783     else {
1784         bool handled = false;
1785 #ifdef Q_WS_MAC
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) {
1792
1793                     event->key() == Qt::Key_Up ? home(1) : end(1);
1794                 }
1795             } else {
1796                 if ((myModifiers == Qt::ControlModifier
1797                      || myModifiers == Qt::AltModifier
1798                      || myModifiers == Qt::NoModifier)) {
1799                     event->key() == Qt::Key_Up ? home(0) : end(0);
1800                 }
1801             }
1802             handled = true;
1803         }
1804 #endif
1805         if (event->modifiers() & Qt::ControlModifier) {
1806             switch (event->key()) {
1807             case Qt::Key_Backspace:
1808                 if (!isReadOnly()) {
1809                     cursorWordBackward(true);
1810                     del();
1811                 }
1812                 break;
1813 #ifndef QT_NO_COMPLETER
1814             case Qt::Key_Up:
1815             case Qt::Key_Down:
1816                 complete(event->key());
1817                 break;
1818 #endif
1819 #if defined(Q_WS_X11)
1820             case Qt::Key_E:
1821                 end(0);
1822                 break;
1823
1824             case Qt::Key_U:
1825                 if (!isReadOnly()) {
1826                     setSelection(0, text().size());
1827 #ifndef QT_NO_CLIPBOARD
1828                     copy();
1829 #endif
1830                     del();
1831                 }
1832             break;
1833 #endif
1834             default:
1835                 if (!handled)
1836                     unknown = true;
1837             }
1838         } else { // ### check for *no* modifier
1839             switch (event->key()) {
1840             case Qt::Key_Backspace:
1841                 if (!isReadOnly()) {
1842                     backspace();
1843 #ifndef QT_NO_COMPLETER
1844                     complete(Qt::Key_Backspace);
1845 #endif
1846                 }
1847                 break;
1848 #ifdef QT_KEYPAD_NAVIGATION
1849             case Qt::Key_Back:
1850                 if (QApplication::keypadNavigationEnabled() && !event->isAutoRepeat()
1851                     && !isReadOnly()) {
1852                     if (text().length() == 0) {
1853                         setText(m_cancelText);
1854
1855                         if (passwordEchoEditing())
1856                             updatePasswordEchoEditing(false);
1857
1858                         emit editFocusChange(false);
1859                     } else if (!m_deleteAllTimer) {
1860                         m_deleteAllTimer = startTimer(750);
1861                     }
1862                 } else {
1863                     unknown = true;
1864                 }
1865                 break;
1866 #endif
1867             default:
1868                 if (!handled)
1869                     unknown = true;
1870             }
1871         }
1872     }
1873
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);
1876         unknown = false;
1877     }
1878
1879     if (unknown && !isReadOnly()) {
1880         QString t = event->text();
1881         if (!t.isEmpty() && t.at(0).isPrint()) {
1882             insert(t);
1883 #ifndef QT_NO_COMPLETER
1884             complete(event->key());
1885 #endif
1886             event->accept();
1887             return;
1888         }
1889     }
1890
1891     if (unknown)
1892         event->ignore();
1893     else
1894         event->accept();
1895 }
1896
1897
1898 QT_END_NAMESPACE
1899
1900 #endif