1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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 const 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 */
updateDisplayText(bool forceUpdate)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 && m_cursor > 0 && m_cursor <= m_text.length()) {
97             int cursor = m_cursor - 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 */
copy(QClipboard::Mode mode) const152 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 */
paste(QClipboard::Mode clipboardMode)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 */
backspace()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             if (m_cursor > 0 && m_text.at(m_cursor).isLowSurrogate()) {
202                 // second half of a surrogate, check if we have the first half as well,
203                 // if yes delete both at once
204                 if (m_text.at(m_cursor - 1).isHighSurrogate()) {
205                     internalDelete(true);
206                     --m_cursor;
207                 }
208             }
209             internalDelete(true);
210     }
211     finishChange(priorState);
212 }
213 
214 /*!
215     \internal
216 
217     Handles the behavior for the delete key or function.
218     Removes the current selection if there is a selection, otherwise
219     removes the character after the cursor position.
220 
221     \sa del()
222 */
del()223 void QLineControl::del()
224 {
225     int priorState = m_undoState;
226     if (hasSelectedText()) {
227         removeSelectedText();
228     } else {
229         int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
230         while (n--)
231             internalDelete();
232     }
233     finishChange(priorState);
234 }
235 
236 /*!
237     \internal
238 
239     Inserts the given \a newText at the current cursor position.
240     If there is any selected text it is removed prior to insertion of
241     the new text.
242 */
insert(const QString & newText)243 void QLineControl::insert(const QString &newText)
244 {
245     int priorState = m_undoState;
246     removeSelectedText();
247     internalInsert(newText);
248     finishChange(priorState);
249 }
250 
251 /*!
252     \internal
253 
254     Clears the line control text.
255 */
clear()256 void QLineControl::clear()
257 {
258     int priorState = m_undoState;
259     m_selstart = 0;
260     m_selend = m_text.length();
261     removeSelectedText();
262     separate();
263     finishChange(priorState, /*update*/false, /*edited*/false);
264 }
265 
266 /*!
267     \internal
268 
269     Sets \a length characters from the given \a start position as selected.
270     The given \a start position must be within the current text for
271     the line control.  If \a length characters cannot be selected, then
272     the selection will extend to the end of the current text.
273 */
setSelection(int start,int length)274 void QLineControl::setSelection(int start, int length)
275 {
276     if(start < 0 || start > (int)m_text.length()){
277         qWarning("QLineControl::setSelection: Invalid start position");
278         return;
279     }
280 
281     if (length > 0) {
282         if (start == m_selstart && start + length == m_selend && m_cursor == m_selend)
283             return;
284         m_selstart = start;
285         m_selend = qMin(start + length, (int)m_text.length());
286         m_cursor = m_selend;
287     } else if (length < 0){
288         if (start == m_selend && start + length == m_selstart && m_cursor == m_selstart)
289             return;
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_selstart = 0;
295         m_selend = 0;
296         m_cursor = start;
297     } else {
298         m_cursor = start;
299         emitCursorPositionChanged();
300         return;
301     }
302     emit selectionChanged();
303     emitCursorPositionChanged();
304 }
305 
_q_clipboardChanged()306 void QLineControl::_q_clipboardChanged()
307 {
308 }
309 
_q_deleteSelected()310 void QLineControl::_q_deleteSelected()
311 {
312     if (!hasSelectedText())
313         return;
314 
315     int priorState = m_undoState;
316     emit resetInputContext();
317     removeSelectedText();
318     separate();
319     finishChange(priorState);
320 }
321 
322 /*!
323     \internal
324 
325     Initializes the line control with a starting text value of \a txt.
326 */
init(const QString & txt)327 void QLineControl::init(const QString &txt)
328 {
329     m_text = txt;
330     updateDisplayText();
331     m_cursor = m_text.length();
332 }
333 
334 /*!
335     \internal
336 
337     Sets the password echo editing to \a editing.  If password echo editing
338     is true, then the text of the password is displayed even if the echo
339     mode is set to QLineEdit::PasswordEchoOnEdit.  Password echoing editing
340     does not affect other echo modes.
341 */
updatePasswordEchoEditing(bool editing)342 void QLineControl::updatePasswordEchoEditing(bool editing)
343 {
344     cancelPasswordEchoTimer();
345     m_passwordEchoEditing = editing;
346     updateDisplayText();
347 }
348 
349 /*!
350     \internal
351 
352     Returns the cursor position of the given \a x pixel value in relation
353     to the displayed text.  The given \a betweenOrOn specified what kind
354     of cursor position is requested.
355 */
xToPos(int x,QTextLine::CursorPosition betweenOrOn) const356 int QLineControl::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const
357 {
358     return m_textLayout.lineAt(0).xToCursor(x, betweenOrOn);
359 }
360 
361 /*!
362     \internal
363 
364     Returns the bounds of the current cursor, as defined as a
365     between characters cursor.
366 */
cursorRect() const367 QRect QLineControl::cursorRect() const
368 {
369     QTextLine l = m_textLayout.lineAt(0);
370     int c = m_cursor;
371     if (m_preeditCursor != -1)
372         c += m_preeditCursor;
373     int cix = qRound(l.cursorToX(c));
374     int w = m_cursorWidth;
375     int ch = l.height() + 1;
376 
377     return QRect(cix-5, 0, w+9, ch);
378 }
379 
380 /*!
381     \internal
382 
383     Fixes the current text so that it is valid given any set validators.
384 
385     Returns true if the text was changed.  Otherwise returns false.
386 */
fixup()387 bool QLineControl::fixup() // this function assumes that validate currently returns != Acceptable
388 {
389 #ifndef QT_NO_VALIDATOR
390     if (m_validator) {
391         QString textCopy = m_text;
392         int cursorCopy = m_cursor;
393         m_validator->fixup(textCopy);
394         if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
395             if (textCopy != m_text || cursorCopy != m_cursor)
396                 internalSetText(textCopy, cursorCopy);
397             return true;
398         }
399     }
400 #endif
401     return false;
402 }
403 
404 /*!
405     \internal
406 
407     Moves the cursor to the given position \a pos.   If \a mark is true will
408     adjust the currently selected text.
409 */
moveCursor(int pos,bool mark)410 void QLineControl::moveCursor(int pos, bool mark)
411 {
412     if (pos != m_cursor) {
413         separate();
414         if (m_maskData)
415             pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
416     }
417     if (mark) {
418         int anchor;
419         if (m_selend > m_selstart && m_cursor == m_selstart)
420             anchor = m_selend;
421         else if (m_selend > m_selstart && m_cursor == m_selend)
422             anchor = m_selstart;
423         else
424             anchor = m_cursor;
425         m_selstart = qMin(anchor, pos);
426         m_selend = qMax(anchor, pos);
427         updateDisplayText();
428     } else {
429         internalDeselect();
430     }
431     m_cursor = pos;
432     if (mark || m_selDirty) {
433         m_selDirty = false;
434         emit selectionChanged();
435     }
436     emitCursorPositionChanged();
437 }
438 
439 /*!
440     \internal
441 
442     Applies the given input method event \a event to the text of the line
443     control
444 */
processInputMethodEvent(QInputMethodEvent * event)445 void QLineControl::processInputMethodEvent(QInputMethodEvent *event)
446 {
447     int priorState = 0;
448     int originalSelectionStart = m_selstart;
449     int originalSelectionEnd = m_selend;
450     bool isGettingInput = !event->commitString().isEmpty()
451             || event->preeditString() != preeditAreaText()
452             || event->replacementLength() > 0;
453     bool cursorPositionChanged = false;
454     bool selectionChange = false;
455 
456     if (isGettingInput) {
457         // If any text is being input, remove selected text.
458         priorState = m_undoState;
459         if (echoMode() == QLineEdit::PasswordEchoOnEdit && !passwordEchoEditing()) {
460             updatePasswordEchoEditing(true);
461             m_selstart = 0;
462             m_selend = m_text.length();
463         }
464         removeSelectedText();
465     }
466 
467     int c = m_cursor; // cursor position after insertion of commit string
468     if (event->replacementStart() <= 0)
469         c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
470 
471     m_cursor += event->replacementStart();
472     if (m_cursor < 0)
473         m_cursor = 0;
474 
475     // insert commit string
476     if (event->replacementLength()) {
477         m_selstart = m_cursor;
478         m_selend = m_selstart + event->replacementLength();
479         removeSelectedText();
480     }
481     if (!event->commitString().isEmpty()) {
482         internalInsert(event->commitString());
483         cursorPositionChanged = true;
484     }
485 
486     m_cursor = qBound(0, c, m_text.length());
487 
488     for (int i = 0; i < event->attributes().size(); ++i) {
489         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
490         if (a.type == QInputMethodEvent::Selection) {
491             m_cursor = qBound(0, a.start + a.length, m_text.length());
492             if (a.length) {
493                 m_selstart = qMax(0, qMin(a.start, m_text.length()));
494                 m_selend = m_cursor;
495                 if (m_selend < m_selstart) {
496                     qSwap(m_selstart, m_selend);
497                 }
498                 selectionChange = true;
499             } else {
500                 m_selstart = m_selend = 0;
501             }
502             cursorPositionChanged = true;
503         }
504     }
505 #ifndef QT_NO_IM
506     setPreeditArea(m_cursor, event->preeditString());
507 #endif //QT_NO_IM
508     const int oldPreeditCursor = m_preeditCursor;
509     m_preeditCursor = event->preeditString().length();
510     m_hideCursor = false;
511     QList<QTextLayout::FormatRange> formats;
512     for (int i = 0; i < event->attributes().size(); ++i) {
513         const QInputMethodEvent::Attribute &a = event->attributes().at(i);
514         if (a.type == QInputMethodEvent::Cursor) {
515             m_preeditCursor = a.start;
516             m_hideCursor = !a.length;
517         } else if (a.type == QInputMethodEvent::TextFormat) {
518             QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
519             if (f.isValid()) {
520                 if (f.background().color().alphaF() == 1 && f.background().style() == Qt::SolidPattern) {
521                     f.setForeground(f.background().color());
522                     f.setBackground(Qt::transparent);
523                     f.setUnderlineStyle(QTextCharFormat::SingleUnderline);
524                     f.setFontUnderline(true);
525                 }
526                 QTextLayout::FormatRange o;
527                 o.start = a.start + m_cursor;
528                 o.length = a.length;
529                 o.format = f;
530                 formats.append(o);
531             }
532         }
533     }
534     m_textLayout.setAdditionalFormats(formats);
535     updateDisplayText(/*force*/ true);
536     if (originalSelectionStart != m_selstart || originalSelectionEnd != m_selend)
537         emit selectionChanged();
538     if (cursorPositionChanged)
539         emitCursorPositionChanged();
540     else if (m_preeditCursor != oldPreeditCursor)
541         emit updateMicroFocus();
542     if (isGettingInput)
543         finishChange(priorState);
544     if (selectionChange)
545         emit selectionChanged();
546 }
547 
548 /*!
549     \internal
550 
551     Draws the display text for the line control using the given
552     \a painter, \a clip, and \a offset.  Which aspects of the display text
553     are drawn is specified by the given \a flags.
554 
555     If the flags contain DrawSelections, then the selection or input mask
556     backgrounds and foregrounds will be applied before drawing the text.
557 
558     If the flags contain DrawCursor a cursor of the current cursorWidth()
559     will be drawn after drawing the text.
560 
561     The display text will only be drawn if the flags contain DrawText
562 */
draw(QPainter * painter,const QPoint & offset,const QRect & clip,int flags)563 void QLineControl::draw(QPainter *painter, const QPoint &offset, const QRect &clip, int flags)
564 {
565     QVector<QTextLayout::FormatRange> selections;
566     if (flags & DrawSelections) {
567         QTextLayout::FormatRange o;
568         if (m_selstart < m_selend) {
569             o.start = m_selstart;
570             o.length = m_selend - m_selstart;
571             o.format.setBackground(m_palette.brush(QPalette::Highlight));
572             o.format.setForeground(m_palette.brush(QPalette::HighlightedText));
573         } else {
574             // mask selection
575             if(!m_blinkPeriod || m_blinkStatus){
576                 o.start = m_cursor;
577                 o.length = 1;
578                 o.format.setBackground(m_palette.brush(QPalette::Text));
579                 o.format.setForeground(m_palette.brush(QPalette::Window));
580             }
581         }
582         selections.append(o);
583     }
584 
585     if (flags & DrawText)
586         m_textLayout.draw(painter, offset, selections, clip);
587 
588     if (flags & DrawCursor){
589         int cursor = m_cursor;
590         if (m_preeditCursor != -1)
591             cursor += m_preeditCursor;
592         if (!m_hideCursor && (!m_blinkPeriod || m_blinkStatus))
593             m_textLayout.drawCursor(painter, offset, cursor, m_cursorWidth);
594     }
595 }
596 
597 /*!
598     \internal
599 
600     Sets the selection to cover the word at the given cursor position.
601     The word boundaries are defined by the behavior of QTextLayout::SkipWords
602     cursor mode.
603 */
selectWordAtPos(int cursor)604 void QLineControl::selectWordAtPos(int cursor)
605 {
606     int next = cursor + 1;
607     if(next > end())
608         --next;
609     int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
610     moveCursor(c, false);
611     // ## text layout should support end of words.
612     int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
613     while (end > cursor && m_text[end-1].isSpace())
614         --end;
615     moveCursor(end, true);
616 }
617 
618 /*!
619     \internal
620 
621     Completes a change to the line control text.  If the change is not valid
622     will undo the line control state back to the given \a validateFromState.
623 
624     If \a edited is true and the change is valid, will emit textEdited() in
625     addition to textChanged().  Otherwise only emits textChanged() on a valid
626     change.
627 
628     The \a update value is currently unused.
629 */
finishChange(int validateFromState,bool update,bool edited)630 bool QLineControl::finishChange(int validateFromState, bool update, bool edited)
631 {
632     Q_UNUSED(update)
633 
634     if (m_textDirty) {
635         // do validation
636         bool wasValidInput = m_validInput;
637         m_validInput = true;
638 #ifndef QT_NO_VALIDATOR
639         if (m_validator) {
640             m_validInput = false;
641             QString textCopy = m_text;
642             int cursorCopy = m_cursor;
643             m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
644             if (m_validInput) {
645                 if (m_text != textCopy) {
646                     internalSetText(textCopy, cursorCopy);
647                     return true;
648                 }
649                 m_cursor = cursorCopy;
650             }
651         }
652 #endif
653         if (validateFromState >= 0 && wasValidInput && !m_validInput) {
654             if (m_transactions.count())
655                 return false;
656             internalUndo(validateFromState);
657             m_history.resize(m_undoState);
658             if (m_modifiedState > m_undoState)
659                 m_modifiedState = -1;
660             m_validInput = true;
661             m_textDirty = false;
662         }
663         updateDisplayText();
664 
665         if (m_textDirty) {
666             m_textDirty = false;
667             QString actualText = text();
668             if (edited)
669                 emit textEdited(actualText);
670             emit textChanged(actualText);
671         }
672     }
673     if (m_selDirty) {
674         m_selDirty = false;
675         emit selectionChanged();
676     }
677     if (m_cursor == m_lastCursorPos)
678         updateMicroFocus();
679     emitCursorPositionChanged();
680     return true;
681 }
682 
683 /*!
684     \internal
685 
686     An internal function for setting the text of the line control.
687 */
internalSetText(const QString & txt,int pos,bool edited)688 void QLineControl::internalSetText(const QString &txt, int pos, bool edited)
689 {
690     cancelPasswordEchoTimer();
691     internalDeselect();
692     emit resetInputContext();
693     QString oldText = m_text;
694     if (m_maskData) {
695         m_text = maskString(0, txt, true);
696         m_text += clearString(m_text.length(), m_maxLength - m_text.length());
697     } else {
698         m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
699     }
700     m_history.clear();
701     m_modifiedState =  m_undoState = 0;
702     m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
703     m_textDirty = (oldText != m_text);
704     bool changed = finishChange(-1, true, edited);
705 
706 #ifndef QT_NO_ACCESSIBILITY
707     if (changed)
708         QAccessible::updateAccessibility(parent(), 0, QAccessible::TextUpdated);
709 #else
710     Q_UNUSED(changed);
711 #endif
712 }
713 
714 
715 /*!
716     \internal
717 
718     Adds the given \a command to the undo history
719     of the line control.  Does not apply the command.
720 */
addCommand(const Command & cmd)721 void QLineControl::addCommand(const Command &cmd)
722 {
723     if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
724         m_history.resize(m_undoState + 2);
725         m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
726     } else {
727         m_history.resize(m_undoState + 1);
728     }
729     m_separator = false;
730     m_history[m_undoState++] = cmd;
731 }
732 
733 /*!
734     \internal
735 
736     Inserts the given string \a s into the line
737     control.
738 
739     Also adds the appropriate commands into the undo history.
740     This function does not call finishChange(), and may leave the text
741     in an invalid state.
742 */
internalInsert(const QString & s)743 void QLineControl::internalInsert(const QString &s)
744 {
745 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
746     if (m_echoMode == QLineEdit::Password) {
747         if (m_passwordEchoTimer != 0)
748             killTimer(m_passwordEchoTimer);
749         m_passwordEchoTimer = startTimer(qt_passwordEchoDelay);
750     }
751 #endif
752     if (hasSelectedText())
753         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
754     if (m_maskData) {
755         QString ms = maskString(m_cursor, s);
756         for (int i = 0; i < (int) ms.length(); ++i) {
757             addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
758             addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
759         }
760         m_text.replace(m_cursor, ms.length(), ms);
761         m_cursor += ms.length();
762         m_cursor = nextMaskBlank(m_cursor);
763         m_textDirty = true;
764     } else {
765         int remaining = m_maxLength - m_text.length();
766         if (remaining != 0) {
767             m_text.insert(m_cursor, s.left(remaining));
768             for (int i = 0; i < (int) s.left(remaining).length(); ++i)
769                addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
770             m_textDirty = true;
771         }
772     }
773 }
774 
775 /*!
776     \internal
777 
778     deletes a single character from the current text.  If \a wasBackspace,
779     the character prior to the cursor is removed.  Otherwise the character
780     after the cursor is removed.
781 
782     Also adds the appropriate commands into the undo history.
783     This function does not call finishChange(), and may leave the text
784     in an invalid state.
785 */
internalDelete(bool wasBackspace)786 void QLineControl::internalDelete(bool wasBackspace)
787 {
788     if (m_cursor < (int) m_text.length()) {
789         cancelPasswordEchoTimer();
790         if (hasSelectedText())
791             addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
792         addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
793                    m_cursor, m_text.at(m_cursor), -1, -1));
794         if (m_maskData) {
795             m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
796             addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
797         } else {
798             m_text.remove(m_cursor, 1);
799         }
800         m_textDirty = true;
801     }
802 }
803 
804 /*!
805     \internal
806 
807     removes the currently selected text from the line control.
808 
809     Also adds the appropriate commands into the undo history.
810     This function does not call finishChange(), and may leave the text
811     in an invalid state.
812 */
removeSelectedText()813 void QLineControl::removeSelectedText()
814 {
815     if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
816         cancelPasswordEchoTimer();
817         separate();
818         int i ;
819         addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
820         if (m_selstart <= m_cursor && m_cursor < m_selend) {
821             // cursor is within the selection. Split up the commands
822             // to be able to restore the correct cursor position
823             for (i = m_cursor; i >= m_selstart; --i)
824                 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
825             for (i = m_selend - 1; i > m_cursor; --i)
826                 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
827         } else {
828             for (i = m_selend-1; i >= m_selstart; --i)
829                 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
830         }
831         if (m_maskData) {
832             m_text.replace(m_selstart, m_selend - m_selstart,  clearString(m_selstart, m_selend - m_selstart));
833             for (int i = 0; i < m_selend - m_selstart; ++i)
834                 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
835         } else {
836             m_text.remove(m_selstart, m_selend - m_selstart);
837         }
838         if (m_cursor > m_selstart)
839             m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
840         internalDeselect();
841         m_textDirty = true;
842     }
843 }
844 
845 /*!
846     \internal
847 
848     Parses the input mask specified by \a maskFields to generate
849     the mask data used to handle input masks.
850 */
parseInputMask(const QString & maskFields)851 void QLineControl::parseInputMask(const QString &maskFields)
852 {
853     int delimiter = maskFields.indexOf(QLatin1Char(';'));
854     if (maskFields.isEmpty() || delimiter == 0) {
855         if (m_maskData) {
856             delete [] m_maskData;
857             m_maskData = 0;
858             m_maxLength = 32767;
859             internalSetText(QString());
860         }
861         return;
862     }
863 
864     if (delimiter == -1) {
865         m_blank = QLatin1Char(' ');
866         m_inputMask = maskFields;
867     } else {
868         m_inputMask = maskFields.left(delimiter);
869         m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
870     }
871 
872     // calculate m_maxLength / m_maskData length
873     m_maxLength = 0;
874     QChar c = 0;
875     for (int i=0; i<m_inputMask.length(); i++) {
876         c = m_inputMask.at(i);
877         if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
878             m_maxLength++;
879             continue;
880         }
881         if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
882              c != QLatin1Char('<') && c != QLatin1Char('>') &&
883              c != QLatin1Char('{') && c != QLatin1Char('}') &&
884              c != QLatin1Char('[') && c != QLatin1Char(']'))
885             m_maxLength++;
886     }
887 
888     delete [] m_maskData;
889     m_maskData = new MaskInputData[m_maxLength];
890 
891     MaskInputData::Casemode m = MaskInputData::NoCaseMode;
892     c = 0;
893     bool s;
894     bool escape = false;
895     int index = 0;
896     for (int i = 0; i < m_inputMask.length(); i++) {
897         c = m_inputMask.at(i);
898         if (escape) {
899             s = true;
900             m_maskData[index].maskChar = c;
901             m_maskData[index].separator = s;
902             m_maskData[index].caseMode = m;
903             index++;
904             escape = false;
905         } else if (c == QLatin1Char('<')) {
906                 m = MaskInputData::Lower;
907         } else if (c == QLatin1Char('>')) {
908             m = MaskInputData::Upper;
909         } else if (c == QLatin1Char('!')) {
910             m = MaskInputData::NoCaseMode;
911         } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
912             switch (c.unicode()) {
913             case 'A':
914             case 'a':
915             case 'N':
916             case 'n':
917             case 'X':
918             case 'x':
919             case '9':
920             case '0':
921             case 'D':
922             case 'd':
923             case '#':
924             case 'H':
925             case 'h':
926             case 'B':
927             case 'b':
928                 s = false;
929                 break;
930             case '\\':
931                 escape = true;
932             default:
933                 s = true;
934                 break;
935             }
936 
937             if (!escape) {
938                 m_maskData[index].maskChar = c;
939                 m_maskData[index].separator = s;
940                 m_maskData[index].caseMode = m;
941                 index++;
942             }
943         }
944     }
945     internalSetText(m_text);
946 }
947 
948 
949 /*!
950     \internal
951 
952     checks if the key is valid compared to the inputMask
953 */
isValidInput(QChar key,QChar mask) const954 bool QLineControl::isValidInput(QChar key, QChar mask) const
955 {
956     switch (mask.unicode()) {
957     case 'A':
958         if (key.isLetter())
959             return true;
960         break;
961     case 'a':
962         if (key.isLetter() || key == m_blank)
963             return true;
964         break;
965     case 'N':
966         if (key.isLetterOrNumber())
967             return true;
968         break;
969     case 'n':
970         if (key.isLetterOrNumber() || key == m_blank)
971             return true;
972         break;
973     case 'X':
974         if (key.isPrint())
975             return true;
976         break;
977     case 'x':
978         if (key.isPrint() || key == m_blank)
979             return true;
980         break;
981     case '9':
982         if (key.isNumber())
983             return true;
984         break;
985     case '0':
986         if (key.isNumber() || key == m_blank)
987             return true;
988         break;
989     case 'D':
990         if (key.isNumber() && key.digitValue() > 0)
991             return true;
992         break;
993     case 'd':
994         if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
995             return true;
996         break;
997     case '#':
998         if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
999             return true;
1000         break;
1001     case 'B':
1002         if (key == QLatin1Char('0') || key == QLatin1Char('1'))
1003             return true;
1004         break;
1005     case 'b':
1006         if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
1007             return true;
1008         break;
1009     case 'H':
1010         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
1011             return true;
1012         break;
1013     case 'h':
1014         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
1015             return true;
1016         break;
1017     default:
1018         break;
1019     }
1020     return false;
1021 }
1022 
1023 /*!
1024     \internal
1025 
1026     Returns true if the given text \a str is valid for any
1027     validator or input mask set for the line control.
1028 
1029     Otherwise returns false
1030 */
hasAcceptableInput(const QString & str) const1031 bool QLineControl::hasAcceptableInput(const QString &str) const
1032 {
1033 #ifndef QT_NO_VALIDATOR
1034     QString textCopy = str;
1035     int cursorCopy = m_cursor;
1036     if (m_validator && m_validator->validate(textCopy, cursorCopy)
1037         != QValidator::Acceptable)
1038         return false;
1039 #endif
1040 
1041     if (!m_maskData)
1042         return true;
1043 
1044     if (str.length() != m_maxLength)
1045         return false;
1046 
1047     for (int i=0; i < m_maxLength; ++i) {
1048         if (m_maskData[i].separator) {
1049             if (str.at(i) != m_maskData[i].maskChar)
1050                 return false;
1051         } else {
1052             if (!isValidInput(str.at(i), m_maskData[i].maskChar))
1053                 return false;
1054         }
1055     }
1056     return true;
1057 }
1058 
1059 /*!
1060     \internal
1061 
1062     Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
1063     specifies from where characters should be gotten when a separator is met in \a str - true means
1064     that blanks will be used, false that previous input is used.
1065     Calling this when no inputMask is set is undefined.
1066 */
maskString(uint pos,const QString & str,bool clear) const1067 QString QLineControl::maskString(uint pos, const QString &str, bool clear) const
1068 {
1069     if (pos >= (uint)m_maxLength)
1070         return QString::fromLatin1("");
1071 
1072     QString fill;
1073     fill = clear ? clearString(0, m_maxLength) : m_text;
1074 
1075     int strIndex = 0;
1076     QString s = QString::fromLatin1("");
1077     int i = pos;
1078     while (i < m_maxLength) {
1079         if (strIndex < str.length()) {
1080             if (m_maskData[i].separator) {
1081                 s += m_maskData[i].maskChar;
1082                 if (str[(int)strIndex] == m_maskData[i].maskChar)
1083                     strIndex++;
1084                 ++i;
1085             } else {
1086                 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
1087                     switch (m_maskData[i].caseMode) {
1088                     case MaskInputData::Upper:
1089                         s += str[(int)strIndex].toUpper();
1090                         break;
1091                     case MaskInputData::Lower:
1092                         s += str[(int)strIndex].toLower();
1093                         break;
1094                     default:
1095                         s += str[(int)strIndex];
1096                     }
1097                     ++i;
1098                 } else {
1099                     // search for separator first
1100                     int n = findInMask(i, true, true, str[(int)strIndex]);
1101                     if (n != -1) {
1102                         if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
1103                             s += fill.mid(i, n-i+1);
1104                             i = n + 1; // update i to find + 1
1105                         }
1106                     } else {
1107                         // search for valid m_blank if not
1108                         n = findInMask(i, true, false, str[(int)strIndex]);
1109                         if (n != -1) {
1110                             s += fill.mid(i, n-i);
1111                             switch (m_maskData[n].caseMode) {
1112                             case MaskInputData::Upper:
1113                                 s += str[(int)strIndex].toUpper();
1114                                 break;
1115                             case MaskInputData::Lower:
1116                                 s += str[(int)strIndex].toLower();
1117                                 break;
1118                             default:
1119                                 s += str[(int)strIndex];
1120                             }
1121                             i = n + 1; // updates i to find + 1
1122                         }
1123                     }
1124                 }
1125                 ++strIndex;
1126             }
1127         } else
1128             break;
1129     }
1130 
1131     return s;
1132 }
1133 
1134 
1135 
1136 /*!
1137     \internal
1138 
1139     Returns a "cleared" string with only separators and blank chars.
1140     Calling this when no inputMask is set is undefined.
1141 */
clearString(uint pos,uint len) const1142 QString QLineControl::clearString(uint pos, uint len) const
1143 {
1144     if (pos >= (uint)m_maxLength)
1145         return QString();
1146 
1147     QString s;
1148     int end = qMin((uint)m_maxLength, pos + len);
1149     for (int i = pos; i < end; ++i)
1150         if (m_maskData[i].separator)
1151             s += m_maskData[i].maskChar;
1152         else
1153             s += m_blank;
1154 
1155     return s;
1156 }
1157 
1158 /*!
1159     \internal
1160 
1161     Strips blank parts of the input in a QLineControl when an inputMask is set,
1162     separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
1163 */
stripString(const QString & str) const1164 QString QLineControl::stripString(const QString &str) const
1165 {
1166     if (!m_maskData)
1167         return str;
1168 
1169     QString s;
1170     int end = qMin(m_maxLength, (int)str.length());
1171     for (int i = 0; i < end; ++i)
1172         if (m_maskData[i].separator)
1173             s += m_maskData[i].maskChar;
1174         else
1175             if (str[i] != m_blank)
1176                 s += str[i];
1177 
1178     return s;
1179 }
1180 
1181 /*!
1182     \internal
1183     searches forward/backward in m_maskData for either a separator or a m_blank
1184 */
findInMask(int pos,bool forward,bool findSeparator,QChar searchChar) const1185 int QLineControl::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
1186 {
1187     if (pos >= m_maxLength || pos < 0)
1188         return -1;
1189 
1190     int end = forward ? m_maxLength : -1;
1191     int step = forward ? 1 : -1;
1192     int i = pos;
1193 
1194     while (i != end) {
1195         if (findSeparator) {
1196             if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
1197                 return i;
1198         } else {
1199             if (!m_maskData[i].separator) {
1200                 if (searchChar.isNull())
1201                     return i;
1202                 else if (isValidInput(searchChar, m_maskData[i].maskChar))
1203                     return i;
1204             }
1205         }
1206         i += step;
1207     }
1208     return -1;
1209 }
1210 
internalUndo(int until)1211 void QLineControl::internalUndo(int until)
1212 {
1213     if (!isUndoAvailable())
1214         return;
1215     cancelPasswordEchoTimer();
1216     internalDeselect();
1217 
1218     // Undo works only for clearing the line when in any of password the modes
1219     if (m_echoMode != QLineEdit::Normal) {
1220         clear();
1221         return;
1222     }
1223 
1224     while (m_undoState && m_undoState > until) {
1225         Command& cmd = m_history[--m_undoState];
1226         switch (cmd.type) {
1227         case Insert:
1228             m_text.remove(cmd.pos, 1);
1229             m_cursor = cmd.pos;
1230             break;
1231         case SetSelection:
1232             m_selstart = cmd.selStart;
1233             m_selend = cmd.selEnd;
1234             m_cursor = cmd.pos;
1235             break;
1236         case Remove:
1237         case RemoveSelection:
1238             m_text.insert(cmd.pos, cmd.uc);
1239             m_cursor = cmd.pos + 1;
1240             break;
1241         case Delete:
1242         case DeleteSelection:
1243             m_text.insert(cmd.pos, cmd.uc);
1244             m_cursor = cmd.pos;
1245             break;
1246         case Separator:
1247             continue;
1248         }
1249         if (until < 0 && m_undoState) {
1250             Command& next = m_history[m_undoState-1];
1251             if (next.type != cmd.type && next.type < RemoveSelection
1252                  && (cmd.type < RemoveSelection || next.type == Separator))
1253                 break;
1254         }
1255     }
1256     m_textDirty = true;
1257     emitCursorPositionChanged();
1258 }
1259 
internalRedo()1260 void QLineControl::internalRedo()
1261 {
1262     if (!isRedoAvailable())
1263         return;
1264     internalDeselect();
1265     while (m_undoState < (int)m_history.size()) {
1266         Command& cmd = m_history[m_undoState++];
1267         switch (cmd.type) {
1268         case Insert:
1269             m_text.insert(cmd.pos, cmd.uc);
1270             m_cursor = cmd.pos + 1;
1271             break;
1272         case SetSelection:
1273             m_selstart = cmd.selStart;
1274             m_selend = cmd.selEnd;
1275             m_cursor = cmd.pos;
1276             break;
1277         case Remove:
1278         case Delete:
1279         case RemoveSelection:
1280         case DeleteSelection:
1281             m_text.remove(cmd.pos, 1);
1282             m_selstart = cmd.selStart;
1283             m_selend = cmd.selEnd;
1284             m_cursor = cmd.pos;
1285             break;
1286         case Separator:
1287             m_selstart = cmd.selStart;
1288             m_selend = cmd.selEnd;
1289             m_cursor = cmd.pos;
1290             break;
1291         }
1292         if (m_undoState < (int)m_history.size()) {
1293             Command& next = m_history[m_undoState];
1294             if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
1295                  && (next.type < RemoveSelection || cmd.type == Separator))
1296                 break;
1297         }
1298     }
1299     m_textDirty = true;
1300     emitCursorPositionChanged();
1301 }
1302 
1303 /*!
1304     \internal
1305 
1306     If the current cursor position differs from the last emitted cursor
1307     position, emits cursorPositionChanged().
1308 */
emitCursorPositionChanged()1309 void QLineControl::emitCursorPositionChanged()
1310 {
1311     if (m_cursor != m_lastCursorPos) {
1312         const int oldLast = m_lastCursorPos;
1313         m_lastCursorPos = m_cursor;
1314         cursorPositionChanged(oldLast, m_cursor);
1315 #ifndef QT_NO_ACCESSIBILITY
1316         QAccessible::updateAccessibility(parent(), 0, QAccessible::TextCaretMoved);
1317 #endif
1318     }
1319 }
1320 
1321 #ifndef QT_NO_COMPLETER
1322 // iterating forward(dir=1)/backward(dir=-1) from the
1323 // current row based. dir=0 indicates a new completion prefix was set.
advanceToEnabledItem(int dir)1324 bool QLineControl::advanceToEnabledItem(int dir)
1325 {
1326     int start = m_completer->currentRow();
1327     if (start == -1)
1328         return false;
1329     int i = start + dir;
1330     if (dir == 0) dir = 1;
1331     do {
1332         if (!m_completer->setCurrentRow(i)) {
1333             if (!m_completer->wrapAround())
1334                 break;
1335             i = i > 0 ? 0 : m_completer->completionCount() - 1;
1336         } else {
1337             QModelIndex currentIndex = m_completer->currentIndex();
1338             if (m_completer->completionModel()->flags(currentIndex) & Qt::ItemIsEnabled)
1339                 return true;
1340             i += dir;
1341         }
1342     } while (i != start);
1343 
1344     m_completer->setCurrentRow(start); // restore
1345     return false;
1346 }
1347 
complete(int key)1348 void QLineControl::complete(int key)
1349 {
1350     if (!m_completer || isReadOnly() || echoMode() != QLineEdit::Normal)
1351         return;
1352 
1353     QString text = this->text();
1354     if (m_completer->completionMode() == QCompleter::InlineCompletion) {
1355         if (key == Qt::Key_Backspace)
1356             return;
1357         int n = 0;
1358         if (key == Qt::Key_Up || key == Qt::Key_Down) {
1359             if (textAfterSelection().length())
1360                 return;
1361             QString prefix = hasSelectedText() ? textBeforeSelection()
1362                 : text;
1363             if (text.compare(m_completer->currentCompletion(), m_completer->caseSensitivity()) != 0
1364                 || prefix.compare(m_completer->completionPrefix(), m_completer->caseSensitivity()) != 0) {
1365                 m_completer->setCompletionPrefix(prefix);
1366             } else {
1367                 n = (key == Qt::Key_Up) ? -1 : +1;
1368             }
1369         } else {
1370             m_completer->setCompletionPrefix(text);
1371         }
1372         if (!advanceToEnabledItem(n))
1373             return;
1374     } else {
1375 #ifndef QT_KEYPAD_NAVIGATION
1376         if (text.isEmpty()) {
1377             m_completer->popup()->hide();
1378             return;
1379         }
1380 #endif
1381         m_completer->setCompletionPrefix(text);
1382     }
1383 
1384     m_completer->complete();
1385 }
1386 #endif
1387 
setCursorBlinkPeriod(int msec)1388 void QLineControl::setCursorBlinkPeriod(int msec)
1389 {
1390     if (msec == m_blinkPeriod)
1391         return;
1392     if (m_blinkTimer) {
1393         killTimer(m_blinkTimer);
1394     }
1395     if (msec) {
1396         m_blinkTimer = startTimer(msec / 2);
1397         m_blinkStatus = 1;
1398     } else {
1399         m_blinkTimer = 0;
1400         if (m_blinkStatus == 1)
1401             emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect());
1402     }
1403     m_blinkPeriod = msec;
1404 }
1405 
resetCursorBlinkTimer()1406 void QLineControl::resetCursorBlinkTimer()
1407 {
1408     if (m_blinkPeriod == 0 || m_blinkTimer == 0)
1409         return;
1410     killTimer(m_blinkTimer);
1411     m_blinkTimer = startTimer(m_blinkPeriod / 2);
1412     m_blinkStatus = 1;
1413 }
1414 
timerEvent(QTimerEvent * event)1415 void QLineControl::timerEvent(QTimerEvent *event)
1416 {
1417     if (event->timerId() == m_blinkTimer) {
1418         m_blinkStatus = !m_blinkStatus;
1419         emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect());
1420     } else if (event->timerId() == m_deleteAllTimer) {
1421         killTimer(m_deleteAllTimer);
1422         m_deleteAllTimer = 0;
1423         clear();
1424     } else if (event->timerId() == m_tripleClickTimer) {
1425         killTimer(m_tripleClickTimer);
1426         m_tripleClickTimer = 0;
1427 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
1428     } else if (event->timerId() == m_passwordEchoTimer) {
1429         killTimer(m_passwordEchoTimer);
1430         m_passwordEchoTimer = 0;
1431         updateDisplayText();
1432 #endif
1433     }
1434 }
1435 
processEvent(QEvent * ev)1436 bool QLineControl::processEvent(QEvent* ev)
1437 {
1438 #ifdef QT_KEYPAD_NAVIGATION
1439     if (QApplication::keypadNavigationEnabled()) {
1440         if ((ev->type() == QEvent::KeyPress) || (ev->type() == QEvent::KeyRelease)) {
1441             QKeyEvent *ke = (QKeyEvent *)ev;
1442             if (ke->key() == Qt::Key_Back) {
1443                 if (ke->isAutoRepeat()) {
1444                     // Swallow it. We don't want back keys running amok.
1445                     ke->accept();
1446                     return true;
1447                 }
1448                 if ((ev->type() == QEvent::KeyRelease)
1449                     && !isReadOnly()
1450                     && m_deleteAllTimer) {
1451                     killTimer(m_deleteAllTimer);
1452                     m_deleteAllTimer = 0;
1453                     backspace();
1454                     ke->accept();
1455                     return true;
1456                 }
1457             }
1458         }
1459     }
1460 #endif
1461     switch(ev->type()){
1462 #ifndef QT_NO_GRAPHICSVIEW
1463         case QEvent::GraphicsSceneMouseDoubleClick:
1464         case QEvent::GraphicsSceneMouseMove:
1465         case QEvent::GraphicsSceneMouseRelease:
1466         case QEvent::GraphicsSceneMousePress:{
1467                QGraphicsSceneMouseEvent *gvEv = static_cast<QGraphicsSceneMouseEvent*>(ev);
1468                QMouseEvent mouse(ev->type(),
1469                     gvEv->pos().toPoint(), gvEv->button(), gvEv->buttons(), gvEv->modifiers());
1470                processMouseEvent(&mouse); break;
1471         }
1472 #endif
1473         case QEvent::MouseButtonPress:
1474         case QEvent::MouseButtonRelease:
1475         case QEvent::MouseButtonDblClick:
1476         case QEvent::MouseMove:
1477             processMouseEvent(static_cast<QMouseEvent*>(ev)); break;
1478         case QEvent::KeyPress:
1479         case QEvent::KeyRelease:
1480             processKeyEvent(static_cast<QKeyEvent*>(ev)); break;
1481         case QEvent::InputMethod:
1482             processInputMethodEvent(static_cast<QInputMethodEvent*>(ev)); break;
1483 #ifndef QT_NO_SHORTCUT
1484         case QEvent::ShortcutOverride:{
1485             if (isReadOnly())
1486                 return false;
1487             QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1488             if (ke == QKeySequence::Copy
1489                 || ke == QKeySequence::Paste
1490                 || ke == QKeySequence::Cut
1491                 || ke == QKeySequence::Redo
1492                 || ke == QKeySequence::Undo
1493                 || ke == QKeySequence::MoveToNextWord
1494                 || ke == QKeySequence::MoveToPreviousWord
1495                 || ke == QKeySequence::MoveToStartOfDocument
1496                 || ke == QKeySequence::MoveToEndOfDocument
1497                 || ke == QKeySequence::SelectNextWord
1498                 || ke == QKeySequence::SelectPreviousWord
1499                 || ke == QKeySequence::SelectStartOfLine
1500                 || ke == QKeySequence::SelectEndOfLine
1501                 || ke == QKeySequence::SelectStartOfBlock
1502                 || ke == QKeySequence::SelectEndOfBlock
1503                 || ke == QKeySequence::SelectStartOfDocument
1504                 || ke == QKeySequence::SelectAll
1505                 || ke == QKeySequence::SelectEndOfDocument) {
1506                 ke->accept();
1507             } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1508                        || ke->modifiers() == Qt::KeypadModifier) {
1509                 if (ke->key() < Qt::Key_Escape) {
1510                     ke->accept();
1511                 } else {
1512                     switch (ke->key()) {
1513                     case Qt::Key_Delete:
1514                     case Qt::Key_Home:
1515                     case Qt::Key_End:
1516                     case Qt::Key_Backspace:
1517                     case Qt::Key_Left:
1518                     case Qt::Key_Right:
1519                         ke->accept();
1520                     default:
1521                         break;
1522                     }
1523                 }
1524             }
1525         }
1526 #endif
1527         default:
1528             return false;
1529     }
1530     return true;
1531 }
1532 
processMouseEvent(QMouseEvent * ev)1533 void QLineControl::processMouseEvent(QMouseEvent* ev)
1534 {
1535 
1536     switch (ev->type()) {
1537         case QEvent::GraphicsSceneMousePress:
1538         case QEvent::MouseButtonPress:{
1539             if (m_tripleClickTimer
1540                 && (ev->pos() - m_tripleClick).manhattanLength()
1541                     < QApplication::startDragDistance()) {
1542                 selectAll();
1543                 return;
1544             }
1545             if (ev->button() == Qt::RightButton)
1546                 return;
1547 
1548             bool mark = ev->modifiers() & Qt::ShiftModifier;
1549             int cursor = xToPos(ev->pos().x());
1550             moveCursor(cursor, mark);
1551             break;
1552         }
1553         case QEvent::GraphicsSceneMouseDoubleClick:
1554         case QEvent::MouseButtonDblClick:
1555             if (ev->button() == Qt::LeftButton) {
1556                 selectWordAtPos(xToPos(ev->pos().x()));
1557                 if (m_tripleClickTimer)
1558                     killTimer(m_tripleClickTimer);
1559                 m_tripleClickTimer = startTimer(QApplication::doubleClickInterval());
1560                 m_tripleClick = ev->pos();
1561             }
1562             break;
1563         case QEvent::GraphicsSceneMouseRelease:
1564         case QEvent::MouseButtonRelease:
1565 #ifndef QT_NO_CLIPBOARD
1566             if (QApplication::clipboard()->supportsSelection()) {
1567                 if (ev->button() == Qt::LeftButton) {
1568                     copy(QClipboard::Selection);
1569                 } else if (!isReadOnly() && ev->button() == Qt::MidButton) {
1570                     deselect();
1571                     insert(QApplication::clipboard()->text(QClipboard::Selection));
1572                 }
1573             }
1574 #endif
1575             break;
1576         case QEvent::GraphicsSceneMouseMove:
1577         case QEvent::MouseMove:
1578             if (ev->buttons() & Qt::LeftButton) {
1579                 moveCursor(xToPos(ev->pos().x()), true);
1580             }
1581             break;
1582         default:
1583             break;
1584     }
1585 }
1586 
processKeyEvent(QKeyEvent * event)1587 void QLineControl::processKeyEvent(QKeyEvent* event)
1588 {
1589     bool inlineCompletionAccepted = false;
1590 
1591 #ifndef QT_NO_COMPLETER
1592     if (m_completer) {
1593         QCompleter::CompletionMode completionMode = m_completer->completionMode();
1594         if ((completionMode == QCompleter::PopupCompletion
1595              || completionMode == QCompleter::UnfilteredPopupCompletion)
1596             && m_completer->popup()
1597             && m_completer->popup()->isVisible()) {
1598             // The following keys are forwarded by the completer to the widget
1599             // Ignoring the events lets the completer provide suitable default behavior
1600             switch (event->key()) {
1601             case Qt::Key_Escape:
1602                 event->ignore();
1603                 return;
1604             case Qt::Key_Enter:
1605             case Qt::Key_Return:
1606             case Qt::Key_F4:
1607 #ifdef QT_KEYPAD_NAVIGATION
1608             case Qt::Key_Select:
1609                 if (!QApplication::keypadNavigationEnabled())
1610                     break;
1611 #endif
1612                 m_completer->popup()->hide(); // just hide. will end up propagating to parent
1613             default:
1614                 break; // normal key processing
1615             }
1616         } else if (completionMode == QCompleter::InlineCompletion) {
1617             switch (event->key()) {
1618             case Qt::Key_Enter:
1619             case Qt::Key_Return:
1620             case Qt::Key_F4:
1621 #ifdef QT_KEYPAD_NAVIGATION
1622             case Qt::Key_Select:
1623                 if (!QApplication::keypadNavigationEnabled())
1624                     break;
1625 #endif
1626                 if (!m_completer->currentCompletion().isEmpty() && hasSelectedText()
1627                     && textAfterSelection().isEmpty()) {
1628                     setText(m_completer->currentCompletion());
1629                     inlineCompletionAccepted = true;
1630                 }
1631             default:
1632                 break; // normal key processing
1633             }
1634         }
1635     }
1636 #endif // QT_NO_COMPLETER
1637 
1638     if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
1639         if (hasAcceptableInput() || fixup()) {
1640             emit accepted();
1641             emit editingFinished();
1642         }
1643         if (inlineCompletionAccepted)
1644             event->accept();
1645         else
1646             event->ignore();
1647         return;
1648     }
1649 
1650     if (echoMode() == QLineEdit::PasswordEchoOnEdit
1651         && !passwordEchoEditing()
1652         && !isReadOnly()
1653         && !event->text().isEmpty()
1654 #ifdef QT_KEYPAD_NAVIGATION
1655         && event->key() != Qt::Key_Select
1656         && event->key() != Qt::Key_Up
1657         && event->key() != Qt::Key_Down
1658         && event->key() != Qt::Key_Back
1659 #endif
1660         && !(event->modifiers() & Qt::ControlModifier)) {
1661         // Clear the edit and reset to normal echo mode while editing; the
1662         // echo mode switches back when the edit loses focus
1663         // ### resets current content.  dubious code; you can
1664         // navigate with keys up, down, back, and select(?), but if you press
1665         // "left" or "right" it clears?
1666         updatePasswordEchoEditing(true);
1667         clear();
1668     }
1669 
1670     bool unknown = false;
1671     bool visual = cursorMoveStyle() == Qt::VisualMoveStyle;
1672 
1673     if (false) {
1674     }
1675 #ifndef QT_NO_SHORTCUT
1676     else if (event == QKeySequence::Undo) {
1677         if (!isReadOnly())
1678             undo();
1679     }
1680     else if (event == QKeySequence::Redo) {
1681         if (!isReadOnly())
1682             redo();
1683     }
1684     else if (event == QKeySequence::SelectAll) {
1685         selectAll();
1686     }
1687 #ifndef QT_NO_CLIPBOARD
1688     else if (event == QKeySequence::Copy) {
1689         copy();
1690     }
1691     else if (event == QKeySequence::Paste) {
1692         if (!isReadOnly()) {
1693             QClipboard::Mode mode = QClipboard::Clipboard;
1694 #ifdef Q_WS_X11
1695             if (event->modifiers() == (Qt::CTRL | Qt::SHIFT) && event->key() == Qt::Key_Insert)
1696                 mode = QClipboard::Selection;
1697 #endif
1698             paste(mode);
1699         }
1700     }
1701     else if (event == QKeySequence::Cut) {
1702         if (!isReadOnly() && hasSelectedText()) {
1703             copy();
1704             del();
1705         }
1706     }
1707     else if (event == QKeySequence::DeleteEndOfLine) {
1708         if (!isReadOnly()) {
1709             setSelection(cursor(), end());
1710             copy();
1711             del();
1712         }
1713     }
1714 #endif //QT_NO_CLIPBOARD
1715     else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
1716         home(0);
1717     }
1718     else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
1719         end(0);
1720     }
1721     else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
1722         home(1);
1723     }
1724     else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
1725         end(1);
1726     }
1727     else if (event == QKeySequence::MoveToNextChar) {
1728 #if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER)
1729         if (hasSelectedText()) {
1730 #else
1731         if (hasSelectedText() && m_completer
1732             && m_completer->completionMode() == QCompleter::InlineCompletion) {
1733 #endif
1734             moveCursor(selectionEnd(), false);
1735         } else {
1736             cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
1737         }
1738     }
1739     else if (event == QKeySequence::SelectNextChar) {
1740         cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
1741     }
1742     else if (event == QKeySequence::MoveToPreviousChar) {
1743 #if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER)
1744         if (hasSelectedText()) {
1745 #else
1746         if (hasSelectedText() && m_completer
1747             && m_completer->completionMode() == QCompleter::InlineCompletion) {
1748 #endif
1749             moveCursor(selectionStart(), false);
1750         } else {
1751             cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
1752         }
1753     }
1754     else if (event == QKeySequence::SelectPreviousChar) {
1755         cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
1756     }
1757     else if (event == QKeySequence::MoveToNextWord) {
1758         if (echoMode() == QLineEdit::Normal)
1759             layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
1760         else
1761             layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
1762     }
1763     else if (event == QKeySequence::MoveToPreviousWord) {
1764         if (echoMode() == QLineEdit::Normal)
1765             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
1766         else if (!isReadOnly()) {
1767             layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
1768         }
1769     }
1770     else if (event == QKeySequence::SelectNextWord) {
1771         if (echoMode() == QLineEdit::Normal)
1772             layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
1773         else
1774             layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
1775     }
1776     else if (event == QKeySequence::SelectPreviousWord) {
1777         if (echoMode() == QLineEdit::Normal)
1778             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
1779         else
1780             layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
1781     }
1782     else if (event == QKeySequence::Delete) {
1783         if (!isReadOnly())
1784             del();
1785     }
1786     else if (event == QKeySequence::DeleteEndOfWord) {
1787         if (!isReadOnly()) {
1788             cursorWordForward(true);
1789             del();
1790         }
1791     }
1792     else if (event == QKeySequence::DeleteStartOfWord) {
1793         if (!isReadOnly()) {
1794             cursorWordBackward(true);
1795             del();
1796         }
1797     }
1798 #endif // QT_NO_SHORTCUT
1799     else {
1800         bool handled = false;
1801 #ifdef Q_WS_MAC
1802         if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down) {
1803             Qt::KeyboardModifiers myModifiers = (event->modifiers() & ~Qt::KeypadModifier);
1804             if (myModifiers & Qt::ShiftModifier) {
1805                 if (myModifiers == (Qt::ControlModifier|Qt::ShiftModifier)
1806                         || myModifiers == (Qt::AltModifier|Qt::ShiftModifier)
1807                         || myModifiers == Qt::ShiftModifier) {
1808 
1809                     event->key() == Qt::Key_Up ? home(1) : end(1);
1810                 }
1811             } else {
1812                 if ((myModifiers == Qt::ControlModifier
1813                      || myModifiers == Qt::AltModifier
1814                      || myModifiers == Qt::NoModifier)) {
1815                     event->key() == Qt::Key_Up ? home(0) : end(0);
1816                 }
1817             }
1818             handled = true;
1819         }
1820 #endif
1821         if (event->modifiers() & Qt::ControlModifier) {
1822             switch (event->key()) {
1823             case Qt::Key_Backspace:
1824                 if (!isReadOnly()) {
1825                     cursorWordBackward(true);
1826                     del();
1827                 }
1828                 break;
1829 #ifndef QT_NO_COMPLETER
1830             case Qt::Key_Up:
1831             case Qt::Key_Down:
1832                 complete(event->key());
1833                 break;
1834 #endif
1835 #if defined(Q_WS_X11)
1836             case Qt::Key_E:
1837                 end(0);
1838                 break;
1839 
1840             case Qt::Key_U:
1841                 if (!isReadOnly()) {
1842                     setSelection(0, text().size());
1843 #ifndef QT_NO_CLIPBOARD
1844                     copy();
1845 #endif
1846                     del();
1847                 }
1848             break;
1849 #endif
1850             default:
1851                 if (!handled)
1852                     unknown = true;
1853             }
1854         } else { // ### check for *no* modifier
1855             switch (event->key()) {
1856             case Qt::Key_Backspace:
1857                 if (!isReadOnly()) {
1858                     backspace();
1859 #ifndef QT_NO_COMPLETER
1860                     complete(Qt::Key_Backspace);
1861 #endif
1862                 }
1863                 break;
1864 #ifdef QT_KEYPAD_NAVIGATION
1865             case Qt::Key_Back:
1866                 if (QApplication::keypadNavigationEnabled() && !event->isAutoRepeat()
1867                     && !isReadOnly()) {
1868                     if (text().length() == 0) {
1869                         setText(m_cancelText);
1870 
1871                         if (passwordEchoEditing())
1872                             updatePasswordEchoEditing(false);
1873 
1874                         emit editFocusChange(false);
1875                     } else if (!m_deleteAllTimer) {
1876                         m_deleteAllTimer = startTimer(750);
1877                     }
1878                 } else {
1879                     unknown = true;
1880                 }
1881                 break;
1882 #endif
1883             default:
1884                 if (!handled)
1885                     unknown = true;
1886             }
1887         }
1888     }
1889 
1890     if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
1891         setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
1892         unknown = false;
1893     }
1894 
1895     if (unknown && !isReadOnly()) {
1896         QString t = event->text();
1897         if (!t.isEmpty() && t.at(0).isPrint()) {
1898             insert(t);
1899 #ifndef QT_NO_COMPLETER
1900             complete(event->key());
1901 #endif
1902             event->accept();
1903             return;
1904         }
1905     }
1906 
1907     if (unknown)
1908         event->ignore();
1909     else
1910         event->accept();
1911 }
1912 
1913 bool QLineControl::isUndoAvailable() const
1914 {
1915     // For security reasons undo is not available in any password mode (NoEcho included)
1916     // with the exception that the user can clear the password with undo.
1917     return !m_readOnly && m_undoState
1918             && (m_echoMode == QLineEdit::Normal || m_history[m_undoState - 1].type == QLineControl::Insert);
1919 }
1920 
1921 bool QLineControl::isRedoAvailable() const
1922 {
1923     // Same as with undo. Disabled for password modes.
1924     return !m_readOnly
1925             && m_echoMode == QLineEdit::Normal
1926             && m_undoState < m_history.size();
1927 }
1928 
1929 QT_END_NAMESPACE
1930 
1931 #endif
1932