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