src/gui/widgets/qlineedit.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtGui module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 /*
00025     Changes since 4.1:
00026 
00027     Platform specific (read emacs) shortcuts have been removed from the documentation.
00028 
00029     Ctrl+A on X11 now means "Select all" like on other platforms, not home.
00030 
00031     Ctrl+D wil no longer work on Windows (but on X11/mac)
00032 
00033     Ctrl+B, Ctr+E, Ctrl+H, Ctrl+F are completely removed from line edit. If they are popular, we can add them
00034     as standardshortcuts on X11 so that they work in other widgets as well.
00035 */
00036 
00037 #include "qlineedit.h"
00038 #include "qlineedit_p.h"
00039 
00040 #ifndef QT_NO_LINEEDIT
00041 #include "qaction.h"
00042 #include "qapplication.h"
00043 #include "qclipboard.h"
00044 #include "qdrag.h"
00045 #include "qdrawutil.h"
00046 #include "qevent.h"
00047 #include "qfontmetrics.h"
00048 #include "qmenu.h"
00049 #include "qpainter.h"
00050 #include "qpixmap.h"
00051 #include "qpointer.h"
00052 #include "qstringlist.h"
00053 #include "qstyle.h"
00054 #include "qstyleoption.h"
00055 #include "qtimer.h"
00056 #include "qvalidator.h"
00057 #include "qvariant.h"
00058 #include "qvector.h"
00059 #include "qwhatsthis.h"
00060 #include "qdebug.h"
00061 #include "qtextedit.h"
00062 #include <private/qtextedit_p.h>
00063 #ifndef QT_NO_ACCESSIBILITY
00064 #include "qaccessible.h"
00065 #endif
00066 #ifndef QT_NO_IM
00067 #include "qinputcontext.h"
00068 #include "qlist.h"
00069 #endif
00070 #include "qabstractitemview.h"
00071 
00072 #ifndef QT_NO_SHORTCUT
00073 #include "qkeysequence.h"
00074 #define ACCEL_KEY(k) QLatin1String("\t") + QString(QKeySequence(Qt::CTRL | Qt::Key_ ## k))
00075 #else
00076 #define ACCEL_KEY(k) QLatin1String("\t") + QString("Ctrl+" #k)
00077 #endif
00078 
00079 #ifdef Q_WS_MAC
00080 extern void qt_mac_secure_keyboard(bool); //qapplication_mac.cpp
00081 #endif
00082 
00083 #include <limits.h>
00084 
00085 #define verticalMargin 1
00086 #define horizontalMargin 2
00087 
00088 QStyleOptionFrame QLineEditPrivate::getStyleOption() const
00089 {
00090     Q_Q(const QLineEdit);
00091     QStyleOptionFrame opt;
00092     opt.init(q);
00093     opt.rect = q->contentsRect();
00094     opt.lineWidth = frame ? q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth) : 0;
00095     opt.midLineWidth = 0;
00096     opt.state |= QStyle::State_Sunken;
00097     if (readOnly)
00098         opt.state |= QStyle::State_ReadOnly;
00099 #ifdef QT_KEYPAD_NAVIGATION
00100     if (q->hasEditFocus())
00101         opt.state |= QStyle::State_HasEditFocus;
00102 #endif
00103     return opt;
00104 }
00105 
00242 QLineEdit::QLineEdit(QWidget* parent)
00243     : QWidget(*new QLineEditPrivate, parent,0)
00244 {
00245     Q_D(QLineEdit);
00246     d->init(QString());
00247 }
00248 
00260 QLineEdit::QLineEdit(const QString& contents, QWidget* parent)
00261     : QWidget(*new QLineEditPrivate, parent, 0)
00262 {
00263     Q_D(QLineEdit);
00264     d->init(contents);
00265 }
00266 
00267 
00268 #ifdef QT3_SUPPORT
00269 
00278 QLineEdit::QLineEdit(QWidget* parent, const char* name)
00279     : QWidget(*new QLineEditPrivate, parent,0)
00280 {
00281     Q_D(QLineEdit);
00282     setObjectName(QString::fromAscii(name));
00283     d->init(QString());
00284 }
00285 
00298 QLineEdit::QLineEdit(const QString& contents, QWidget* parent, const char* name)
00299     : QWidget(*new QLineEditPrivate, parent, 0)
00300 {
00301     Q_D(QLineEdit);
00302     setObjectName(QString::fromAscii(name));
00303     d->init(contents);
00304 }
00305 
00319 QLineEdit::QLineEdit(const QString& contents, const QString &inputMask, QWidget* parent, const char* name)
00320     : QWidget(*new QLineEditPrivate, parent, 0)
00321 {
00322     Q_D(QLineEdit);
00323     setObjectName(QString::fromAscii(name));
00324     d->parseInputMask(inputMask);
00325     if (d->maskData) {
00326         QString ms = d->maskString(0, contents);
00327         d->init(ms + d->clearString(ms.length(), d->maxLength - ms.length()));
00328         d->cursor = d->nextMaskBlank(ms.length());
00329     } else {
00330         d->init(contents);
00331     }
00332 }
00333 #endif
00334 
00339 QLineEdit::~QLineEdit()
00340 {
00341 }
00342 
00343 
00357 QString QLineEdit::text() const
00358 {
00359     Q_D(const QLineEdit);
00360     QString res = d->text;
00361     if (d->maskData)
00362         res = d->stripString(d->text);
00363     return (res.isNull() ? QString::fromLatin1("") : res);
00364 }
00365 
00366 void QLineEdit::setText(const QString& text)
00367 {
00368     Q_D(QLineEdit);
00369     d->setText(text, -1, false);
00370 #ifdef QT_KEYPAD_NAVIGATION
00371     d->origText = d->text;
00372 #endif
00373 }
00374 
00375 
00388 QString QLineEdit::displayText() const
00389 {
00390     Q_D(const QLineEdit);
00391     if (d->echoMode == NoEcho)
00392         return QString::fromLatin1("");
00393     QString res = d->text;
00394 
00395     if (d->echoMode == Password || d->echoMode == PasswordEchoOnEdit) {
00396         QStyleOptionFrame opt = d->getStyleOption();
00397         res.fill(style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter, &opt, this));
00398     }
00399     return (res.isNull() ? QString::fromLatin1("") : res);
00400 }
00401 
00402 
00419 int QLineEdit::maxLength() const
00420 {
00421     Q_D(const QLineEdit);
00422     return d->maxLength;
00423 }
00424 
00425 void QLineEdit::setMaxLength(int maxLength)
00426 {
00427     Q_D(QLineEdit);
00428     if (d->maskData)
00429         return;
00430     d->maxLength = maxLength;
00431     setText(d->text);
00432 }
00433 
00434 
00435 
00443 bool QLineEdit::hasFrame() const
00444 {
00445     Q_D(const QLineEdit);
00446     return d->frame;
00447 }
00448 
00449 
00450 void QLineEdit::setFrame(bool enable)
00451 {
00452     Q_D(QLineEdit);
00453     d->frame = enable;
00454     update();
00455     updateGeometry();
00456 }
00457 
00458 
00492 QLineEdit::EchoMode QLineEdit::echoMode() const
00493 {
00494     Q_D(const QLineEdit);
00495     return (EchoMode) d->echoMode;
00496 }
00497 
00498 void QLineEdit::setEchoMode(EchoMode mode)
00499 {
00500     Q_D(QLineEdit);
00501     if(mode == (EchoMode)d->echoMode)
00502         return;
00503     d->echoMode = mode;
00504     d->updateTextLayout();
00505     update();
00506 #ifdef Q_WS_MAC
00507     if (hasFocus())
00508         qt_mac_secure_keyboard(d->echoMode == Password || d->echoMode == NoEcho);
00509 #endif
00510 }
00511 
00512 
00513 #ifndef QT_NO_VALIDATOR
00514 
00521 const QValidator * QLineEdit::validator() const
00522 {
00523     Q_D(const QLineEdit);
00524     return d->validator;
00525 }
00526 
00539 void QLineEdit::setValidator(const QValidator *v)
00540 {
00541     Q_D(QLineEdit);
00542     d->validator = const_cast<QValidator*>(v);
00543 }
00544 #endif // QT_NO_VALIDATOR
00545 
00546 #ifndef QT_NO_COMPLETER
00547 
00560 void QLineEdit::setCompleter(QCompleter *c)
00561 {
00562     Q_D(QLineEdit);
00563     if (c == d->completer)
00564         return;
00565     if (d->completer) {
00566         QObject::disconnect(d->completer, SIGNAL(activated(QString)),
00567                             this, SLOT(setText(QString)));
00568         QObject::disconnect(d->completer, SIGNAL(highlighted(QString)),
00569                          this, SLOT(_q_completionHighlighted(QString)));
00570         d->completer->setWidget(0);
00571         if (d->completer->parent() == this)
00572             delete d->completer;
00573     }
00574     d->completer = c;
00575     if (!c)
00576         return;
00577     c->setWidget(this);
00578     QObject::connect(c, SIGNAL(activated(QString)),
00579                      this, SLOT(setText(QString)));
00580     QObject::connect(c, SIGNAL(highlighted(QString)),
00581                      this, SLOT(_q_completionHighlighted(QString)));
00582 }
00583 
00589 QCompleter *QLineEdit::completer() const
00590 {
00591     Q_D(const QLineEdit);
00592     return d->completer;
00593 }
00594 
00595 bool QLineEditPrivate::advanceToNextEnabledItem(int n /* n = 1 ? forward : backward */)
00596 {
00597     while (true) {
00598         QModelIndex currentIndex = completer->currentIndex();
00599         if (!currentIndex.isValid())
00600             return false;
00601         if (completer->completionModel()->flags(currentIndex) & Qt::ItemIsEnabled)
00602             return true;
00603         if (!completer->setCurrentRow(completer->currentRow() + n))
00604             break;
00605     }
00606 
00607     return false;
00608 }
00609 
00610 void QLineEditPrivate::complete(int key)
00611 {
00612     if (!completer || readOnly || echoMode != QLineEdit::Normal)
00613         return;
00614 
00615     if (completer->completionMode() == QCompleter::InlineCompletion) {
00616         if (key == Qt::Key_Backspace)
00617             return;
00618         int n = 1;
00619         if (key == Qt::Key_Up || key == Qt::Key_Down) {
00620             if (selend != 0 && selend != text.length())
00621                 return;
00622             QString prefix = text.left(cursor);
00623             if (prefix != completer->completionPrefix()) {
00624                 completer->setCompletionPrefix(prefix);
00625             } else {
00626                 n = (key == Qt::Key_Up) ? -1 : +1;
00627                 completer->setCurrentRow(completer->currentRow() + n);
00628             }
00629         } else
00630             completer->setCompletionPrefix(text);
00631         if (!advanceToNextEnabledItem(n))
00632             return;
00633     } else {
00634         if (text.isEmpty()) {
00635             completer->popup()->hide();
00636             return;
00637         }
00638         completer->setCompletionPrefix(text);
00639     }
00640 
00641     completer->complete();
00642 }
00643 
00644 void QLineEditPrivate::_q_completionHighlighted(QString newText)
00645 {
00646     Q_Q(QLineEdit);
00647     if (completer->completionMode() != QCompleter::InlineCompletion)
00648         q->setText(newText);
00649     else {
00650         int c = cursor;
00651         q->setText(text.left(c) + newText.mid(c));
00652         q->setSelection(text.length(), c - newText.length());
00653     }
00654 }
00655 #endif // QT_NO_COMPLETER
00656 
00664 QSize QLineEdit::sizeHint() const
00665 {
00666     Q_D(const QLineEdit);
00667     ensurePolished();
00668     QFontMetrics fm(font());
00669     int h = qMax(fm.lineSpacing(), 14) + 2*verticalMargin
00670             + d->topmargin + d->bottommargin;
00671     int w = fm.width(QLatin1Char('x')) * 17 + 2*horizontalMargin
00672             + d->leftmargin + d->rightmargin; // "some"
00673     QStyleOptionFrame opt = d->getStyleOption();
00674     return (style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(w, h).
00675                                       expandedTo(QApplication::globalStrut()), this));
00676 }
00677 
00678 
00685 QSize QLineEdit::minimumSizeHint() const
00686 {
00687     Q_D(const QLineEdit);
00688     ensurePolished();
00689     QFontMetrics fm = fontMetrics();
00690     int h = fm.height() + qMax(2*horizontalMargin, fm.leading())
00691             + d->topmargin + d->bottommargin;
00692     int w = fm.maxWidth() + d->leftmargin + d->rightmargin;
00693     QStyleOptionFrame opt = d->getStyleOption();
00694     return (style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(w, h).
00695                                       expandedTo(QApplication::globalStrut()), this));
00696 }
00697 
00698 
00706 int QLineEdit::cursorPosition() const
00707 {
00708     Q_D(const QLineEdit);
00709     return d->cursor;
00710 }
00711 
00712 void QLineEdit::setCursorPosition(int pos)
00713 {
00714     Q_D(QLineEdit);
00715     if (pos < 0)
00716         pos = 0;
00717 
00718     if (pos <= d->text.length())
00719         d->moveCursor(pos);
00720 }
00721 
00725 // ### What should this do if the point is outside of contentsRect? Currently returns 0.
00726 int QLineEdit::cursorPositionAt(const QPoint &pos)
00727 {
00728     Q_D(QLineEdit);
00729     return d->xToPos(pos.x());
00730 }
00731 
00732 
00733 #ifdef QT3_SUPPORT
00734 
00738 bool QLineEdit::validateAndSet(const QString &newText, int newPos,
00739                                  int newMarkAnchor, int newMarkDrag)
00740 {
00741     Q_D(QLineEdit);
00742     int priorState = d->undoState;
00743     d->selstart = 0;
00744     d->selend = d->text.length();
00745     d->removeSelectedText();
00746     d->insert(newText);
00747     d->finishChange(priorState);
00748     if (d->undoState > priorState) {
00749         d->cursor = newPos;
00750         d->selstart = qMin(newMarkAnchor, newMarkDrag);
00751         d->selend = qMax(newMarkAnchor, newMarkDrag);
00752         update();
00753         d->emitCursorPositionChanged();
00754         return true;
00755     }
00756     return false;
00757 }
00758 #endif //QT3_SUPPORT
00759 
00770 Qt::Alignment QLineEdit::alignment() const
00771 {
00772     Q_D(const QLineEdit);
00773     return QFlag(d->alignment);
00774 }
00775 
00776 void QLineEdit::setAlignment(Qt::Alignment alignment)
00777 {
00778     Q_D(QLineEdit);
00779     d->alignment = alignment & Qt::AlignHorizontal_Mask;
00780     update();
00781 }
00782 
00783 
00792 void QLineEdit::cursorForward(bool mark, int steps)
00793 {
00794     Q_D(QLineEdit);
00795     int cursor = d->cursor;
00796     if (steps > 0) {
00797         while(steps--)
00798             cursor = d->textLayout.nextCursorPosition(cursor);
00799     } else if (steps < 0) {
00800         while (steps++)
00801             cursor = d->textLayout.previousCursorPosition(cursor);
00802     }
00803     d->moveCursor(cursor, mark);
00804 }
00805 
00806 
00814 void QLineEdit::cursorBackward(bool mark, int steps)
00815 {
00816     cursorForward(mark, -steps);
00817 }
00818 
00825 void QLineEdit::cursorWordForward(bool mark)
00826 {
00827     Q_D(QLineEdit);
00828     d->moveCursor(d->textLayout.nextCursorPosition(d->cursor, QTextLayout::SkipWords), mark);
00829 }
00830 
00838 void QLineEdit::cursorWordBackward(bool mark)
00839 {
00840     Q_D(QLineEdit);
00841     d->moveCursor(d->textLayout.previousCursorPosition(d->cursor, QTextLayout::SkipWords), mark);
00842 }
00843 
00844 
00853 void QLineEdit::backspace()
00854 {
00855     Q_D(QLineEdit);
00856     int priorState = d->undoState;
00857     if (d->hasSelectedText()) {
00858         d->removeSelectedText();
00859     } else if (d->cursor) {
00860             --d->cursor;
00861             if (d->maskData)
00862                 d->cursor = d->prevMaskBlank(d->cursor);
00863             QChar uc = d->text.at(d->cursor);
00864             if (d->cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
00865                 // second half of a surrogate, check if we have the first half as well,
00866                 // if yes delete both at once
00867                 uc = d->text.at(d->cursor - 1);
00868                 if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) {
00869                     d->del(true);
00870                     --d->cursor;
00871                 }
00872             }
00873             d->del(true);
00874     }
00875     d->finishChange(priorState);
00876 }
00877 
00886 void QLineEdit::del()
00887 {
00888     Q_D(QLineEdit);
00889     int priorState = d->undoState;
00890     if (d->hasSelectedText()) {
00891         d->removeSelectedText();
00892     } else {
00893         int n = d->textLayout.nextCursorPosition(d->cursor) - d->cursor;
00894         while (n--)
00895             d->del();
00896     }
00897     d->finishChange(priorState);
00898 }
00899 
00909 void QLineEdit::home(bool mark)
00910 {
00911     Q_D(QLineEdit);
00912     d->moveCursor(0, mark);
00913 }
00914 
00924 void QLineEdit::end(bool mark)
00925 {
00926     Q_D(QLineEdit);
00927     d->moveCursor(d->text.length(), mark);
00928 }
00929 
00930 
00949 bool QLineEdit::isModified() const
00950 {
00951     Q_D(const QLineEdit);
00952     return d->modifiedState != d->undoState;
00953 }
00954 
00955 void QLineEdit::setModified(bool modified)
00956 {
00957     Q_D(QLineEdit);
00958     if (modified)
00959         d->modifiedState = -1;
00960     else
00961         d->modifiedState = d->undoState;
00962 }
00963 
00964 
00984 bool QLineEdit::hasSelectedText() const
00985 {
00986     Q_D(const QLineEdit);
00987     return d->hasSelectedText();
00988 }
00989 
01000 QString QLineEdit::selectedText() const
01001 {
01002     Q_D(const QLineEdit);
01003     if (d->hasSelectedText())
01004         return d->text.mid(d->selstart, d->selend - d->selstart);
01005     return QString();
01006 }
01007 
01015 int QLineEdit::selectionStart() const
01016 {
01017     Q_D(const QLineEdit);
01018     return d->hasSelectedText() ? d->selstart : -1;
01019 }
01020 
01021 
01022 #ifdef QT3_SUPPORT
01023 
01036 bool QLineEdit::edited() const { return isModified(); }
01040 void QLineEdit::setEdited(bool on) { setModified(on); }
01041 
01045 int QLineEdit::characterAt(int xpos, QChar *chr) const
01046 {
01047     Q_D(const QLineEdit);
01048     int pos = d->xToPos(xpos + contentsRect().x() - d->hscroll + horizontalMargin);
01049     if (chr && pos < (int) d->text.length())
01050         *chr = d->text.at(pos);
01051     return pos;
01052 
01053 }
01054 
01058 bool QLineEdit::getSelection(int *start, int *end)
01059 {
01060     Q_D(QLineEdit);
01061     if (d->hasSelectedText() && start && end) {
01062         *start = d->selstart;
01063         *end = d->selend;
01064         return true;
01065     }
01066     return false;
01067 }
01068 #endif
01069 
01070 
01078 void QLineEdit::setSelection(int start, int length)
01079 {
01080     Q_D(QLineEdit);
01081     if (start < 0 || start > (int)d->text.length()) {
01082         qWarning("QLineEdit::setSelection: Invalid start position (%d)", start);
01083         return;
01084     } else {
01085         if (length > 0) {
01086             d->selstart = start;
01087             d->selend = qMin(start + length, (int)d->text.length());
01088             d->cursor = d->selend;
01089         } else {
01090             d->selstart = qMax(start + length, 0);
01091             d->selend = start;
01092             d->cursor = d->selstart;
01093         }
01094     }
01095     update();
01096     d->emitCursorPositionChanged();
01097 }
01098 
01099 
01105 bool QLineEdit::isUndoAvailable() const
01106 {
01107     Q_D(const QLineEdit);
01108     return d->isUndoAvailable();
01109 }
01110 
01116 bool QLineEdit::isRedoAvailable() const
01117 {
01118     Q_D(const QLineEdit);
01119     return d->isRedoAvailable();
01120 }
01121 
01130 bool QLineEdit::dragEnabled() const
01131 {
01132     Q_D(const QLineEdit);
01133     return d->dragEnabled;
01134 }
01135 
01136 void QLineEdit::setDragEnabled(bool b)
01137 {
01138     Q_D(QLineEdit);
01139     d->dragEnabled = b;
01140 }
01141 
01142 
01150 bool QLineEdit::hasAcceptableInput() const
01151 {
01152     Q_D(const QLineEdit);
01153     return d->hasAcceptableInput(d->text);
01154 }
01155 
01216 QString QLineEdit::inputMask() const
01217 {
01218     Q_D(const QLineEdit);
01219     return (d->maskData ? d->inputMask + QLatin1Char(';') + d->blank : QString());
01220 }
01221 
01222 void QLineEdit::setInputMask(const QString &inputMask)
01223 {
01224     Q_D(QLineEdit);
01225     d->parseInputMask(inputMask);
01226     if (d->maskData)
01227         d->moveCursor(d->nextMaskBlank(0));
01228 }
01229 
01239 void QLineEdit::selectAll()
01240 {
01241     Q_D(QLineEdit);
01242     d->selstart = d->selend = d->cursor = 0;
01243     d->moveCursor(d->text.length(), true);
01244 }
01245 
01252 void QLineEdit::deselect()
01253 {
01254     Q_D(QLineEdit);
01255     d->deselect();
01256     d->finishChange();
01257 }
01258 
01259 
01267 void QLineEdit::insert(const QString &newText)
01268 {
01269 //     q->resetInputContext(); //#### FIX ME IN QT
01270     Q_D(QLineEdit);
01271     int priorState = d->undoState;
01272     d->removeSelectedText();
01273     d->insert(newText);
01274     d->finishChange(priorState);
01275 }
01276 
01282 void QLineEdit::clear()
01283 {
01284     Q_D(QLineEdit);
01285     int priorState = d->undoState;
01286     resetInputContext();
01287     d->selstart = 0;
01288     d->selend = d->text.length();
01289     d->removeSelectedText();
01290     d->separate();
01291     d->finishChange(priorState);
01292 }
01293 
01300 void QLineEdit::undo()
01301 {
01302     Q_D(QLineEdit);
01303     resetInputContext();
01304     d->undo();
01305     d->finishChange(-1, true);
01306 }
01307 
01312 void QLineEdit::redo()
01313 {
01314     Q_D(QLineEdit);
01315     resetInputContext();
01316     d->redo();
01317     d->finishChange();
01318 }
01319 
01320 
01334 bool QLineEdit::isReadOnly() const
01335 {
01336     Q_D(const QLineEdit);
01337     return d->readOnly;
01338 }
01339 
01340 void QLineEdit::setReadOnly(bool enable)
01341 {
01342     Q_D(QLineEdit);
01343     d->readOnly = enable;
01344     update();
01345 }
01346 
01347 
01348 #ifndef QT_NO_CLIPBOARD
01349 
01359 void QLineEdit::cut()
01360 {
01361     if (hasSelectedText()) {
01362         copy();
01363         del();
01364     }
01365 }
01366 
01367 
01375 void QLineEdit::copy() const
01376 {
01377     Q_D(const QLineEdit);
01378     d->copy();
01379 }
01380 
01392 void QLineEdit::paste()
01393 {
01394     insert(QApplication::clipboard()->text(QClipboard::Clipboard));
01395 }
01396 
01397 void QLineEditPrivate::copy(bool clipboard) const
01398 {
01399     Q_Q(const QLineEdit);
01400     QString t = q->selectedText();
01401     if (!t.isEmpty() && echoMode == QLineEdit::Normal) {
01402         q->disconnect(QApplication::clipboard(), SIGNAL(selectionChanged()), q, 0);
01403         QApplication::clipboard()->setText(t, clipboard ? QClipboard::Clipboard : QClipboard::Selection);
01404         q->connect(QApplication::clipboard(), SIGNAL(selectionChanged()),
01405                    q, SLOT(_q_clipboardChanged()));
01406     }
01407 }
01408 
01409 #endif // !QT_NO_CLIPBOARD
01410 
01413 bool QLineEdit::event(QEvent * e)
01414 {
01415     Q_D(QLineEdit);
01416     if (e->type() == QEvent::ShortcutOverride && !d->readOnly) {
01417         QKeyEvent* ke = (QKeyEvent*) e;
01418         if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
01419             || ke->modifiers() == Qt::KeypadModifier) {
01420             if (ke->key() < Qt::Key_Escape) {
01421                 ke->accept();
01422             } else {
01423                 switch (ke->key()) {
01424                 case Qt::Key_Delete:
01425                 case Qt::Key_Home:
01426                 case Qt::Key_End:
01427                 case Qt::Key_Backspace:
01428                 case Qt::Key_Left:
01429                 case Qt::Key_Right:
01430                     ke->accept();
01431                 default:
01432                     break;
01433                 }
01434             }
01435         } else if (ke->modifiers() & Qt::ControlModifier) {
01436             switch (ke->key()) {
01437 // Those are too frequently used for application functionality
01438 /*            case Qt::Key_A:
01439             case Qt::Key_B:
01440             case Qt::Key_D:
01441             case Qt::Key_E:
01442             case Qt::Key_F:
01443             case Qt::Key_H:
01444             case Qt::Key_K:
01445 */
01446             case Qt::Key_C:
01447             case Qt::Key_V:
01448             case Qt::Key_X:
01449             case Qt::Key_Y:
01450             case Qt::Key_Z:
01451             case Qt::Key_Left:
01452             case Qt::Key_Right:
01453 #if !defined(Q_WS_MAC)
01454             case Qt::Key_Insert:
01455             case Qt::Key_Delete:
01456 #endif
01457                 ke->accept();
01458             default:
01459                 break;
01460             }
01461         }
01462     } else if (e->type() == QEvent::Timer) {
01463         // should be timerEvent, is here for binary compatibility
01464         int timerId = ((QTimerEvent*)e)->timerId();
01465         if (timerId == d->cursorTimer) {
01466             QStyleOptionFrame opt = d->getStyleOption();
01467             if(!hasSelectedText()
01468                || style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, this))
01469                 d->setCursorVisible(!d->cursorVisible);
01470 #ifndef QT_NO_DRAGANDDROP
01471         } else if (timerId == d->dndTimer.timerId()) {
01472             d->drag();
01473 #endif
01474         }
01475         else if (timerId == d->tripleClickTimer.timerId())
01476             d->tripleClickTimer.stop();
01477 #ifdef QT_KEYPAD_NAVIGATION
01478         else if (timerId == d->deleteAllTimer.timerId()) {
01479             d->deleteAllTimer.stop();
01480             clear();
01481         }
01482 #endif
01483     } else if (e->type() == QEvent::ContextMenu) {
01484 #ifndef QT_NO_IM
01485         if (d->composeMode())
01486             return true;
01487 #endif
01488         d->separate();
01489     }
01490 #ifdef QT_KEYPAD_NAVIGATION
01491     else if (e->type() == QEvent::KeyRelease) {
01492         if (QApplication::keypadNavigationEnabled()) {
01493             QKeyEvent *ke = (QKeyEvent *)e;
01494             if ( !ke->isAutoRepeat() && !isReadOnly()
01495                     && ke->key() == Qt::Key_Back
01496                     && d->deleteAllTimer.isActive()) {
01497                 d->deleteAllTimer.stop();
01498                 backspace();
01499                 ke->accept();
01500                 return true;
01501             }
01502         }
01503     }
01504 #endif
01505     return QWidget::event(e);
01506 }
01507 
01510 void QLineEdit::mousePressEvent(QMouseEvent* e)
01511 {
01512     Q_D(QLineEdit);
01513     if (d->sendMouseEventToInputContext(e))
01514   return;
01515     if (e->button() == Qt::RightButton)
01516         return;
01517 #ifdef QT_KEYPAD_NAVIGATION
01518     if (QApplication::keypadNavigationEnabled() && !hasEditFocus())
01519         setEditFocus(true);
01520 #endif
01521     if (d->tripleClickTimer.isActive() && (e->pos() - d->tripleClick).manhattanLength() <
01522          QApplication::startDragDistance()) {
01523         selectAll();
01524         return;
01525     }
01526     bool mark = e->modifiers() & Qt::ShiftModifier;
01527     int cursor = d->xToPos(e->pos().x());
01528 #ifndef QT_NO_DRAGANDDROP
01529     if (!mark && d->dragEnabled && d->echoMode == Normal &&
01530          e->button() == Qt::LeftButton && d->inSelection(e->pos().x())) {
01531         d->cursor = cursor;
01532         update();
01533         d->dndPos = e->pos();
01534         if (!d->dndTimer.isActive())
01535             d->dndTimer.start(QApplication::startDragTime(), this);
01536         d->emitCursorPositionChanged();
01537     } else
01538 #endif
01539     {
01540         d->moveCursor(cursor, mark);
01541     }
01542 }
01543 
01546 void QLineEdit::mouseMoveEvent(QMouseEvent * e)
01547 {
01548     Q_D(QLineEdit);
01549     if (d->sendMouseEventToInputContext(e))
01550   return;
01551 
01552     if (e->buttons() & Qt::LeftButton) {
01553 #ifndef QT_NO_DRAGANDDROP
01554         if (d->dndTimer.isActive()) {
01555             if ((d->dndPos - e->pos()).manhattanLength() > QApplication::startDragDistance())
01556                 d->drag();
01557         } else
01558 #endif
01559         {
01560             d->moveCursor(d->xToPos(e->pos().x()), true);
01561         }
01562     }
01563 }
01564 
01567 void QLineEdit::mouseReleaseEvent(QMouseEvent* e)
01568 {
01569     Q_D(QLineEdit);
01570     if (d->sendMouseEventToInputContext(e))
01571   return;
01572 #ifndef QT_NO_DRAGANDDROP
01573     if (e->button() == Qt::LeftButton) {
01574         if (d->dndTimer.isActive()) {
01575             d->dndTimer.stop();
01576             deselect();
01577             return;
01578         }
01579     }
01580 #endif
01581 #ifndef QT_NO_CLIPBOARD
01582     if (QApplication::clipboard()->supportsSelection()) {
01583         if (e->button() == Qt::LeftButton) {
01584             d->copy(false);
01585         } else if (!d->readOnly && e->button() == Qt::MidButton) {
01586             d->deselect();
01587             insert(QApplication::clipboard()->text(QClipboard::Selection));
01588         }
01589     }
01590 #endif
01591 }
01592 
01595 void QLineEdit::mouseDoubleClickEvent(QMouseEvent* e)
01596 {
01597     Q_D(QLineEdit);
01598     if (d->sendMouseEventToInputContext(e))
01599   return;
01600     if (e->button() == Qt::LeftButton) {
01601         deselect();
01602         d->cursor = d->xToPos(e->pos().x());
01603         d->cursor = d->textLayout.previousCursorPosition(d->cursor, QTextLayout::SkipWords);
01604         // ## text layout should support end of words.
01605         int end = d->textLayout.nextCursorPosition(d->cursor, QTextLayout::SkipWords);
01606         while (end > d->cursor && d->text[end-1].isSpace())
01607             --end;
01608         d->moveCursor(end, true);
01609         d->tripleClickTimer.start(QApplication::doubleClickInterval(), this);
01610         d->tripleClick = e->pos();
01611     }
01612 }
01613 
01645 void QLineEdit::keyPressEvent(QKeyEvent *event)
01646 {
01647     Q_D(QLineEdit);
01648 
01649 #ifndef QT_NO_COMPLETER
01650     if (d->completer && d->completer->popup()->isVisible()) {
01651         // The following keys are forwarded by the completer to the widget
01652         // Ignoring the events lets the completer provide suitable default behavior
01653        switch (event->key()) {
01654        case Qt::Key_Escape:
01655             event->ignore();
01656             return;
01657        case Qt::Key_Enter:
01658        case Qt::Key_Return:
01659        case Qt::Key_F4:
01660            d->completer->popup()->hide(); // just hide. will end up propagating to parent
01661        default:
01662            break; // normal key processing
01663        }
01664     }
01665 #endif // QT_NO_COMPLETER
01666 
01667 #ifdef QT_KEYPAD_NAVIGATION
01668     bool select = false;
01669     switch (event->key()) {
01670         case Qt::Key_Select:
01671             if (QApplication::keypadNavigationEnabled()) {
01672                 if (hasEditFocus()) {
01673                     setEditFocus(false);
01674                     select = true;
01675                 }
01676             }
01677             break;
01678         case Qt::Key_Back:
01679         case Qt::Key_No:
01680             if (!QApplication::keypadNavigationEnabled() || !hasEditFocus()) {
01681                 event->ignore();
01682                 return;
01683             }
01684             break;
01685         default:
01686             if (QApplication::keypadNavigationEnabled()) {
01687                 if (!hasEditFocus() && !(event->modifiers() & Qt::ControlModifier)) {
01688                     if (!event->text().isEmpty() && event->text().at(0).isPrint()
01689                         && !isReadOnly())
01690                     {
01691                         setEditFocus(true);
01692                         clear();
01693                     } else {
01694                         event->ignore();
01695                         return;
01696                     }
01697                 }
01698             }
01699     }
01700 
01701 
01702 
01703     if (QApplication::keypadNavigationEnabled() && !select && !hasEditFocus()) {
01704         setEditFocus(true);
01705         if (event->key() == Qt::Key_Select)
01706             return; // Just start. No action.
01707     }
01708 #endif
01709 
01710 
01711     if(echoMode() == PasswordEchoOnEdit &&
01712        !isReadOnly() &&
01713        !event->text().isEmpty() &&
01714 #ifdef QT_KEYPAD_NAVIGATION
01715        event->key() != Qt::Key_Select &&
01716        event->key() != Qt::Key_Up &&
01717        event->key() != Qt::Key_Down &&
01718        event->key() != Qt::Key_Back &&
01719 #endif
01720        !(event->modifiers() & Qt::ControlModifier))
01721     {
01722         setEchoMode(Normal);
01723         clear();
01724         d->resumePassword = true;
01725     }
01726 
01727     d->setCursorVisible(true);
01728     if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
01729         if (hasAcceptableInput() || d->fixup()) {
01730             emit returnPressed();
01731             d->emitingEditingFinished = true;
01732             emit editingFinished();
01733             d->emitingEditingFinished = false;
01734         }
01735         event->ignore();
01736         return;
01737     }
01738     bool unknown = false;
01739 
01740     if (false) {
01741     }
01742 #ifndef QT_NO_SHORTCUT
01743     else if (event == QKeySequence::Undo) {
01744         if (!d->readOnly)
01745             undo();
01746     }
01747     else if (event == QKeySequence::Redo) {
01748         if (!d->readOnly)
01749             redo();
01750     }
01751     else if (event == QKeySequence::SelectAll) {
01752         selectAll();
01753     }
01754 #ifndef QT_NO_CLIPBOARD
01755     else if (event == QKeySequence::Copy) {
01756         copy();
01757     }
01758     else if (event == QKeySequence::Paste) {
01759         if (!d->readOnly)
01760             paste();
01761     }
01762     else if (event == QKeySequence::Cut) {
01763         if (!d->readOnly) {
01764             copy();
01765             del();
01766         }
01767     }
01768     else if (event == QKeySequence::DeleteEndOfLine) {
01769         if (!d->readOnly) {
01770             setSelection(d->cursor, d->text.size());
01771             copy();
01772             del();
01773         }
01774     }
01775 #endif //QT_NO_CLIPBOARD
01776     else if (event == QKeySequence::MoveToStartOfLine) {
01777         home(0);
01778     }
01779     else if (event == QKeySequence::MoveToEndOfLine) {
01780         end(0);
01781     }
01782     else if (event == QKeySequence::SelectStartOfLine) {
01783         home(1);
01784     }
01785     else if (event == QKeySequence::SelectEndOfLine) {
01786         end(1);
01787     }
01788     else if (event == QKeySequence::MoveToNextChar) {
01789 #ifndef Q_WS_WIN
01790         if (d->hasSelectedText()) {
01791 #else
01792         if (d->hasSelectedText() && d->completer
01793             && d->completer->completionMode() == QCompleter::InlineCompletion) {
01794 #endif
01795             d->moveCursor(d->selend, false);
01796         } else {
01797             cursorForward(0, layoutDirection() == Qt::LeftToRight ? 1 : -1);
01798         }
01799     }
01800     else if (event == QKeySequence::SelectNextChar) {
01801         cursorForward(1, layoutDirection() == Qt::LeftToRight ? 1 : -1);
01802     }
01803     else if (event == QKeySequence::MoveToPreviousChar) {
01804 #ifndef Q_WS_WIN
01805         if (d->hasSelectedText()) {
01806 #else
01807         if (d->hasSelectedText() && d->completer
01808             && d->completer->completionMode() == QCompleter::InlineCompletion) {
01809 #endif
01810             d->moveCursor(d->selstart, false);
01811         } else {
01812             cursorBackward(0, layoutDirection() == Qt::LeftToRight ? 1 : -1);
01813         }
01814     }
01815     else if (event == QKeySequence::SelectPreviousChar) {
01816         cursorBackward(1, layoutDirection() == Qt::LeftToRight ? 1 : -1);
01817     }
01818     else if (event == QKeySequence::MoveToNextWord) {
01819         if (echoMode() == Normal)
01820             layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
01821         else
01822             layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
01823     }
01824     else if (event == QKeySequence::MoveToPreviousWord) {
01825         if (echoMode() == Normal)
01826             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
01827         else if (!d->readOnly) {
01828             layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
01829         }
01830     }
01831     else if (event == QKeySequence::SelectNextWord) {
01832         if (echoMode() == Normal)
01833             layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
01834         else
01835             layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
01836     }
01837     else if (event == QKeySequence::SelectPreviousWord) {
01838         if (echoMode() == Normal)
01839             layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
01840         else
01841             layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
01842     }
01843     else if (event == QKeySequence::Delete) {
01844         if (!d->readOnly)
01845             del();
01846     }
01847     else if (event == QKeySequence::DeleteEndOfWord) {
01848         if (!d->readOnly) {
01849             cursorWordForward(true);
01850             del();
01851         }
01852     }
01853     else if (event == QKeySequence::DeleteStartOfWord) {
01854         if (!d->readOnly) {
01855             cursorWordBackward(true);
01856             del();
01857         }
01858     }
01859 #endif // QT_NO_SHORTCUT
01860     else {
01861 #ifdef Q_WS_MAC
01862         if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down) {
01863             Qt::KeyboardModifiers myModifiers = (event->modifiers() & ~Qt::KeypadModifier);
01864             if (myModifiers & Qt::ShiftModifier) {
01865                 if (myModifiers == (Qt::ControlModifier|Qt::ShiftModifier)
01866                         || myModifiers == (Qt::AltModifier|Qt::ShiftModifier)
01867                         || myModifiers == Qt::ShiftModifier) {
01868 
01869                     event->key() == Qt::Key_Up ? home(1) : end(1);
01870                 }
01871             } else {
01872                 if ((myModifiers == Qt::ControlModifier
01873                      || myModifiers == Qt::AltModifier
01874                      || myModifiers == Qt::NoModifier)) {
01875                     event->key() == Qt::Key_Up ? home(0) : end(0);
01876                 }
01877             }
01878         }
01879 #endif
01880         if (event->modifiers() & Qt::ControlModifier) {
01881             switch (event->key()) {
01882             case Qt::Key_Backspace:
01883                 if (!d->readOnly) {
01884                     cursorWordBackward(true);
01885                     del();
01886                 }
01887                 break;
01888 #ifndef QT_NO_COMPLETER
01889             case Qt::Key_Up:
01890             case Qt::Key_Down:
01891                 d->complete(event->key());
01892                 break;
01893 #endif
01894 #if defined(Q_WS_X11)
01895             case Qt::Key_E:
01896                 end(0);
01897                 break;
01898 
01899             case Qt::Key_U:
01900                 if (!d->readOnly) {
01901                     setSelection(0, d->text.size());
01902 #ifndef QT_NO_CLIPBOARD
01903                     copy();
01904 #endif
01905                     del();
01906                 }
01907             break;
01908 #endif
01909             default:
01910                 unknown = true;
01911             }
01912         } else { // ### check for *no* modifier
01913             switch (event->key()) {
01914             case Qt::Key_Backspace:
01915                 if (!d->readOnly) {
01916                     backspace();
01917 #ifndef QT_NO_COMPLETER
01918                     d->complete(Qt::Key_Backspace);
01919 #endif
01920                 }
01921                 break;
01922 #ifdef QT_KEYPAD_NAVIGATION
01923             case Qt::Key_Back:
01924                 if (QApplication::keypadNavigationEnabled() && !event->isAutoRepeat()
01925                     && !isReadOnly()) {
01926                     if (text().length() == 0) {
01927                         setText(d->origText);
01928 
01929                         if (d->resumePassword)
01930                         {
01931                             setEchoMode(PasswordEchoOnEdit);
01932                             d->resumePassword = false;
01933                         }
01934 
01935                         setEditFocus(false);
01936                     } else if (!d->deleteAllTimer.isActive()) {
01937                         d->deleteAllTimer.start(750, this);
01938                     }
01939                 } else {
01940                     unknown = true;
01941                 }
01942                 break;
01943 #endif
01944 
01945             default:
01946                 unknown = true;
01947             }
01948         }
01949     }
01950 
01951     if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
01952         setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
01953         d->updateTextLayout();
01954         update();
01955         unknown = false;
01956     }
01957 
01958     if (unknown && !d->readOnly) {
01959         QString t = event->text();
01960         if (!t.isEmpty() && t.at(0).isPrint()) {
01961             insert(t);
01962 #ifndef QT_NO_COMPLETER
01963             d->complete(event->key());
01964 #endif
01965             event->accept();
01966             return;
01967         }
01968     }
01969 
01970     if (unknown)
01971         event->ignore();
01972     else
01973         event->accept();
01974 }
01975 
01981 bool QLineEditPrivate::sendMouseEventToInputContext( QMouseEvent *e )
01982 {
01983 #if !defined QT_NO_IM
01984     Q_Q(QLineEdit);
01985     if ( composeMode() ) {
01986   int tmp_cursor = xToPos(e->pos().x());
01987   int mousePos = tmp_cursor - cursor;
01988   if ( mousePos < 0 || mousePos > textLayout.preeditAreaText().length() ) {
01989             mousePos = -1;
01990       // don't send move events outside the preedit area
01991             if ( e->type() == QEvent::MouseMove )
01992                 return true;
01993         }
01994 
01995         QInputContext *qic = q->inputContext();
01996         if ( qic )
01997             // may be causing reset() in some input methods
01998             qic->mouseHandler(mousePos, e);
01999         if (!textLayout.preeditAreaText().isEmpty())
02000             return true;
02001     }
02002 #else
02003     Q_UNUSED(e);
02004 #endif
02005 
02006     return false;
02007 }
02008 
02011 void QLineEdit::inputMethodEvent(QInputMethodEvent *e)
02012 {
02013     Q_D(QLineEdit);
02014     if (d->readOnly) {
02015         e->ignore();
02016         return;
02017     }
02018 
02019 
02020     if(echoMode() == PasswordEchoOnEdit)
02021     {
02022         setEchoMode(Normal);
02023         clear();
02024         d->resumePassword = true;
02025     }
02026 
02027 
02028 #ifdef QT_KEYPAD_NAVIGATION
02029     if (QApplication::keypadNavigationEnabled() && !hasEditFocus())
02030         setEditFocus(true);
02031 #endif
02032 
02033     int priorState = d->undoState;
02034     d->removeSelectedText();
02035 
02036     int c = d->cursor; // cursor position after insertion of commit string
02037     if (e->replacementStart() <= 0)
02038         c += e->commitString().length() + qMin(-e->replacementStart(), e->replacementLength());
02039 
02040     d->cursor += e->replacementStart();
02041 
02042     // insert commit string
02043     if (e->replacementLength()) {
02044         d->selstart = d->cursor;
02045         d->selend = d->selstart + e->replacementLength();
02046         d->removeSelectedText();
02047     }
02048     if (!e->commitString().isEmpty())
02049         d->insert(e->commitString());
02050 
02051     d->cursor = c;
02052 
02053     d->textLayout.setPreeditArea(d->cursor, e->preeditString());
02054     d->preeditCursor = e->preeditString().length();
02055     d->hideCursor = false;
02056     QList<QTextLayout::FormatRange> formats;
02057     for (int i = 0; i < e->attributes().size(); ++i) {
02058         const QInputMethodEvent::Attribute &a = e->attributes().at(i);
02059         if (a.type == QInputMethodEvent::Cursor) {
02060             d->preeditCursor = a.start;
02061             d->hideCursor = !a.length;
02062         } else if (a.type == QInputMethodEvent::TextFormat) {
02063             QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
02064             if (f.isValid()) {
02065                 QTextLayout::FormatRange o;
02066                 o.start = a.start + d->cursor;
02067                 o.length = a.length;
02068                 o.format = f;
02069                 formats.append(o);
02070             }
02071         }
02072     }
02073     d->textLayout.setAdditionalFormats(formats);
02074     d->updateTextLayout();
02075     update();
02076     if (!e->commitString().isEmpty())
02077         d->emitCursorPositionChanged();
02078     d->finishChange(priorState);
02079 }
02080 
02083 QVariant QLineEdit::inputMethodQuery(Qt::InputMethodQuery property) const
02084 {
02085     Q_D(const QLineEdit);
02086     switch(property) {
02087     case Qt::ImMicroFocus:
02088         return d->cursorRect();
02089     case Qt::ImFont:
02090         return font();
02091     case Qt::ImCursorPosition:
02092         return QVariant(d->cursor);
02093     case Qt::ImSurroundingText:
02094         return QVariant(d->text);
02095     case Qt::ImCurrentSelection:
02096         return QVariant(selectedText());
02097     default:
02098         return QVariant();
02099     }
02100 }
02101 
02105 void QLineEdit::focusInEvent(QFocusEvent *e)
02106 {
02107     Q_D(QLineEdit);
02108     if (e->reason() == Qt::TabFocusReason ||
02109          e->reason() == Qt::BacktabFocusReason  ||
02110          e->reason() == Qt::ShortcutFocusReason)
02111         if (d->maskData)
02112             d->moveCursor(d->nextMaskBlank(0));
02113         else if (!d->hasSelectedText())
02114             selectAll();
02115     if (!d->cursorTimer) {
02116         int cft = QApplication::cursorFlashTime();
02117         d->cursorTimer = cft ? startTimer(cft/2) : -1;
02118     }
02119     QStyleOptionFrame opt = d->getStyleOption();
02120     if((!hasSelectedText() && d->textLayout.preeditAreaText().isEmpty())
02121        || style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, this))
02122         d->setCursorVisible(true);
02123 #ifdef Q_WS_MAC
02124     if (d->echoMode == Password || d->echoMode == NoEcho)
02125         qt_mac_secure_keyboard(true);
02126 #endif
02127 #ifdef QT_KEYPAD_NAVIGATION
02128     d->origText = d->text;
02129 #endif
02130     update();
02131 }
02132 
02136 void QLineEdit::focusOutEvent(QFocusEvent *e)
02137 {
02138     Q_D(QLineEdit);
02139 
02140 
02141     if(d->resumePassword){
02142         setEchoMode(PasswordEchoOnEdit);
02143         d->resumePassword = false;
02144     }
02145 
02146 
02147     Qt::FocusReason reason = e->reason();
02148     if (reason != Qt::ActiveWindowFocusReason &&
02149         reason != Qt::PopupFocusReason)
02150         deselect();
02151 
02152     d->setCursorVisible(false);
02153     if (d->cursorTimer > 0)
02154         killTimer(d->cursorTimer);
02155     d->cursorTimer = 0;
02156     if (reason != Qt::PopupFocusReason
02157         && !(QApplication::activePopupWidget() && QApplication::activePopupWidget()->parentWidget() == this)) {
02158         if (!d->emitingEditingFinished) {
02159             if (hasAcceptableInput() || d->fixup()) {
02160                 d->emitingEditingFinished = true;
02161                 emit editingFinished();
02162                 d->emitingEditingFinished = false;
02163             }
02164         }
02165 #ifdef QT3_SUPPORT
02166         emit lostFocus();
02167 #endif
02168     }
02169 #ifdef Q_WS_MAC
02170     if (d->echoMode == Password || d->echoMode == NoEcho)
02171         qt_mac_secure_keyboard(false);
02172 #endif
02173 #ifdef QT_KEYPAD_NAVIGATION
02174     d->origText = QString();
02175 #endif
02176     update();
02177 }
02178 
02181 void QLineEdit::paintEvent(QPaintEvent *)
02182 {
02183     Q_D(QLineEdit);
02184     QPainter p(this);
02185 
02186     QRect r = rect();
02187     const QPalette &pal = palette();
02188 
02189     QStyleOptionFrame panel = d->getStyleOption();
02190     style()->drawPrimitive(QStyle::PE_PanelLineEdit, &panel, &p, this);
02191     r = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this);
02192     p.setClipRect(r);
02193 
02194     QFontMetrics fm = fontMetrics();
02195     QRect lineRect(r.x() + horizontalMargin, r.y() + (r.height() - fm.height() + 1) / 2,
02196                     r.width() - 2*horizontalMargin, fm.height());
02197     QTextLine line = d->textLayout.lineAt(0);
02198 
02199     int cursor = d->cursor;
02200     if (d->preeditCursor != -1)
02201         cursor += d->preeditCursor;
02202     // locate cursor position
02203     int cix = qRound(line.cursorToX(cursor));
02204 
02205     // horizontal scrolling
02206     int minLB = qMax(0, -fm.minLeftBearing());
02207     int minRB = qMax(0, -fm.minRightBearing());
02208 
02209 
02210     int widthUsed = qRound(line.naturalTextWidth()) + 1 + minRB;
02211     if ((minLB + widthUsed) <=  lineRect.width()) {
02212         Qt::Alignment va = QStyle::visualAlignment(layoutDirection(), QFlag(d->alignment));
02213         va &= ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask);
02214         switch (va) {
02215         case Qt::AlignRight:
02216             d->hscroll = widthUsed - lineRect.width() + 1;
02217             break;
02218         case Qt::AlignHCenter:
02219             d->hscroll = (widthUsed - lineRect.width()) / 2;
02220             break;
02221         default:
02222             // Left
02223             d->hscroll = 0;
02224             break;
02225         }
02226         d->hscroll -= minLB;
02227     } else if (cix - d->hscroll >= lineRect.width()) {
02228         d->hscroll = cix - lineRect.width() + 1;
02229     } else if (cix - d->hscroll < 0) {
02230         d->hscroll = cix;
02231     } else if (widthUsed - d->hscroll < lineRect.width()) {
02232         d->hscroll = widthUsed - lineRect.width() + 1;
02233     }
02234     // the y offset is there to keep the baseline constant in case we have script changes in the text.
02235     QPoint topLeft = lineRect.topLeft() - QPoint(d->hscroll, d->ascent-fm.ascent());
02236 
02237     // draw text, selections and cursors
02238     p.setPen(pal.text().color());
02239 
02240     QVector<QTextLayout::FormatRange> selections;
02241     if (d->selstart < d->selend || (d->cursorVisible && d->maskData)) {
02242         QTextLayout::FormatRange o;
02243         const QPalette &pal = palette();
02244         if (d->selstart < d->selend) {
02245             o.start = d->selstart;
02246             o.length = d->selend - d->selstart;
02247             o.format.setBackground(pal.brush(QPalette::Highlight));
02248             o.format.setForeground(pal.brush(QPalette::HighlightedText));
02249         } else {
02250             // mask selection
02251             o.start = d->cursor;
02252             o.length = 1;
02253             o.format.setBackground(pal.brush(QPalette::Text));
02254             o.format.setForeground(pal.brush(QPalette::Window));
02255         }
02256         selections.append(o);
02257     }
02258 
02259     // Asian users see an IM selection text as cursor on candidate
02260     // selection phase of input method, so the ordinary cursor should be
02261     // invisible if we have a preedit string.
02262     d->textLayout.draw(&p, topLeft, selections, r);
02263     if (d->cursorVisible && !d->readOnly && !d->hideCursor)
02264         d->textLayout.drawCursor(&p, topLeft, cursor);
02265 
02266 }
02267 
02268 
02269 #ifndef QT_NO_DRAGANDDROP
02270 
02272 void QLineEdit::dragMoveEvent(QDragMoveEvent *e)
02273 {
02274     Q_D(QLineEdit);
02275     if (!d->readOnly && e->mimeData()->hasFormat(QLatin1String("text/plain"))) {
02276         e->acceptProposedAction();
02277         d->cursor = d->xToPos(e->pos().x());
02278         d->cursorVisible = true;
02279         update();
02280         d->emitCursorPositionChanged();
02281     }
02282 }
02283 
02285 void QLineEdit::dragEnterEvent(QDragEnterEvent * e)
02286 {
02287     QLineEdit::dragMoveEvent(e);
02288 }
02289 
02291 void QLineEdit::dragLeaveEvent(QDragLeaveEvent *)
02292 {
02293     Q_D(QLineEdit);
02294     if (d->cursorVisible) {
02295         d->cursorVisible = false;
02296         update();
02297     }
02298 }
02299 
02301 void QLineEdit::dropEvent(QDropEvent* e)
02302 {
02303     Q_D(QLineEdit);
02304     QString str = e->mimeData()->text();
02305 
02306     if (!str.isNull() && !d->readOnly) {
02307         if (e->source() == this && e->dropAction() == Qt::CopyAction)
02308             deselect();
02309         d->cursor =d->xToPos(e->pos().x());
02310         int selStart = d->cursor;
02311         int oldSelStart = d->selstart;
02312         int oldSelEnd = d->selend;
02313         d->cursorVisible = false;
02314         e->acceptProposedAction();
02315         insert(str);
02316         if (e->source() == this) {
02317             if (e->dropAction() == Qt::MoveAction) {
02318                 if (selStart > oldSelStart && selStart <= oldSelEnd)
02319                     setSelection(oldSelStart, str.length());
02320                 else if (selStart > oldSelEnd)
02321                     setSelection(selStart - str.length(), str.length());
02322                 else
02323                     setSelection(selStart, str.length());
02324             } else {
02325                 setSelection(selStart, str.length());
02326             }
02327         }
02328     } else {
02329         e->ignore();
02330         update();
02331     }
02332 }
02333 
02334 void QLineEditPrivate::drag()
02335 {
02336     Q_Q(QLineEdit);
02337     dndTimer.stop();
02338     QMimeData *data = new QMimeData;
02339     data->setText(q->selectedText());
02340     QDrag *drag = new QDrag(q);
02341     drag->setMimeData(data);
02342     Qt::DropAction action = drag->start();
02343     if (action == Qt::MoveAction && !readOnly && drag->target() != q) {
02344         int priorState = undoState;
02345         removeSelectedText();
02346         finishChange(priorState);
02347     }
02348 }
02349 
02350 #endif // QT_NO_DRAGANDDROP
02351 
02352 #ifndef QT_NO_CONTEXTMENU
02353 
02379 void QLineEdit::contextMenuEvent(QContextMenuEvent *event)
02380 {
02381     QPointer<QMenu> menu = createStandardContextMenu();
02382     menu->exec(event->globalPos());
02383     delete menu;
02384 }
02385 
02392 QMenu *QLineEdit::createStandardContextMenu()
02393 {
02394     Q_D(QLineEdit);
02395     d->actions[QLineEditPrivate::UndoAct]->setEnabled(d->isUndoAvailable());
02396     d->actions[QLineEditPrivate::RedoAct]->setEnabled(d->isRedoAvailable());
02397 #ifndef QT_NO_CLIPBOARD
02398     d->actions[QLineEditPrivate::CutAct]->setEnabled(!d->readOnly && d->hasSelectedText());
02399     d->actions[QLineEditPrivate::CopyAct]->setEnabled(d->hasSelectedText());
02400     d->actions[QLineEditPrivate::PasteAct]->setEnabled(!d->readOnly && !QApplication::clipboard()->text().isEmpty());
02401 #else
02402     d->actions[QLineEditPrivate::CutAct]->setEnabled(false);
02403     d->actions[QLineEditPrivate::CopyAct]->setEnabled(false);
02404     d->actions[QLineEditPrivate::PasteAct]->setEnabled(false);
02405 #endif
02406     d->actions[QLineEditPrivate::ClearAct]->setEnabled(!d->readOnly && !d->text.isEmpty() && d->hasSelectedText());
02407     d->actions[QLineEditPrivate::SelectAllAct]->setEnabled(!d->text.isEmpty() && !d->allSelected());
02408 
02409     QMenu *popup = new QMenu(this);
02410     popup->setObjectName(QLatin1String("qt_edit_menu"));
02411     popup->addAction(d->actions[QLineEditPrivate::UndoAct]);
02412     popup->addAction(d->actions[QLineEditPrivate::RedoAct]);
02413     popup->addSeparator();
02414     popup->addAction(d->actions[QLineEditPrivate::CutAct]);
02415     popup->addAction(d->actions[QLineEditPrivate::CopyAct]);
02416     popup->addAction(d->actions[QLineEditPrivate::PasteAct]);
02417     popup->addAction(d->actions[QLineEditPrivate::ClearAct]);
02418     popup->addSeparator();
02419     popup->addAction(d->actions[QLineEditPrivate::SelectAllAct]);
02420 #if !defined(QT_NO_IM)
02421     QInputContext *qic = inputContext();
02422     if (qic) {
02423         QList<QAction *> imActions = qic->actions();
02424         for (int i = 0; i < imActions.size(); ++i)
02425             popup->addAction(imActions.at(i));
02426     }
02427 #endif
02428 
02429 #if defined(Q_WS_WIN) || defined(Q_WS_X11)
02430 #if defined(Q_WS_WIN)
02431     extern bool qt_use_rtl_extensions;
02432     if (!d->readOnly && qt_use_rtl_extensions) {
02433 #elif defined(Q_WS_X11)
02434     if (!d->readOnly) {
02435 #endif
02436         popup->addSeparator();
02437         QUnicodeControlCharacterMenu *ctrlCharacterMenu = new QUnicodeControlCharacterMenu(this, popup);
02438         popup->addMenu(ctrlCharacterMenu);
02439     }
02440 #endif
02441     return popup;
02442 }
02443 #endif // QT_NO_CONTEXTMENU
02444 
02446 void QLineEdit::changeEvent(QEvent *ev)
02447 {
02448     Q_D(QLineEdit);
02449     if(ev->type() == QEvent::ActivationChange) {
02450         if (!palette().isEqual(QPalette::Active, QPalette::Inactive))
02451             update();
02452     } else if (ev->type() == QEvent::FontChange || ev->type() == QEvent::StyleChange) {
02453         d->updateTextLayout();
02454     }
02455     QWidget::changeEvent(ev);
02456 }
02457 
02458 void QLineEditPrivate::_q_clipboardChanged()
02459 {
02460 }
02461 
02462 void QLineEditPrivate::_q_deleteSelected()
02463 {
02464     Q_Q(QLineEdit);
02465     if (!hasSelectedText())
02466         return;
02467 
02468     int priorState = undoState;
02469     q->resetInputContext();
02470     removeSelectedText();
02471     separate();
02472     finishChange(priorState);
02473 }
02474 void QLineEditPrivate::init(const QString& txt)
02475 {
02476     Q_Q(QLineEdit);
02477 #ifndef QT_NO_CURSOR
02478     q->setCursor(Qt::IBeamCursor);
02479 #endif
02480     q->setFocusPolicy(Qt::StrongFocus);
02481     q->setAttribute(Qt::WA_InputMethodEnabled);
02482     //   Specifies that this widget can use more, but is able to survive on
02483     //   less, horizontal space; and is fixed vertically.
02484     q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
02485     q->setBackgroundRole(QPalette::Base);
02486     q->setAttribute(Qt::WA_KeyCompression);
02487     q->setMouseTracking(true);
02488     q->setAcceptDrops(true);
02489     text = txt;
02490     updateTextLayout();
02491     cursor = text.length();
02492 
02493 #ifndef QT_NO_MENU
02494     actions[UndoAct] = new QAction(QLineEdit::tr("&Undo") + ACCEL_KEY(Z), q);
02495     QObject::connect(actions[UndoAct], SIGNAL(triggered()), q, SLOT(undo()));
02496     actions[RedoAct] = new QAction(QLineEdit::tr("&Redo") + ACCEL_KEY(Y), q);
02497     QObject::connect(actions[RedoAct], SIGNAL(triggered()), q, SLOT(redo()));
02498     //popup->insertSeparator();
02499 #ifndef QT_NO_CLIPBOARD
02500     actions[CutAct] = new QAction(QLineEdit::tr("Cu&t") + ACCEL_KEY(X), q);
02501     QObject::connect(actions[CutAct], SIGNAL(triggered()), q, SLOT(cut()));
02502     actions[CopyAct] = new QAction(QLineEdit::tr("&Copy") + ACCEL_KEY(C), q);
02503     QObject::connect(actions[CopyAct], SIGNAL(triggered()), q, SLOT(copy()));
02504     actions[PasteAct] = new QAction(QLineEdit::tr("&Paste") + ACCEL_KEY(V), q);
02505     QObject::connect(actions[PasteAct], SIGNAL(triggered()), q, SLOT(paste()));
02506 #endif
02507     actions[ClearAct] = new QAction(QLineEdit::tr("Delete"), q);
02508     QObject::connect(actions[ClearAct], SIGNAL(triggered()), q, SLOT(_q_deleteSelected()));
02509     //popup->insertSeparator();
02510     actions[SelectAllAct] = new QAction(QLineEdit::tr("Select All")
02511                                         + ACCEL_KEY(A)
02512                                         , q);
02513     QObject::connect(actions[SelectAllAct], SIGNAL(triggered()), q, SLOT(selectAll()));
02514 #endif // QT_NO_MENU
02515 }
02516 
02517 void QLineEditPrivate::updateTextLayout()
02518 {
02519     // replace all non-printable characters with spaces (to avoid
02520     // drawing boxes when using fonts that don't have glyphs for such
02521     // characters)
02522     Q_Q(QLineEdit);
02523     QString str = q->displayText();
02524     QChar* uc = str.data();
02525     for (int i = 0; i < (int)str.length(); ++i) {
02526         if (!uc[i].isPrint() || uc[i] == QChar::LineSeparator)
02527             uc[i] = QChar(0x0020);
02528     }
02529     textLayout.setFont(q->font());
02530     textLayout.setText(str);
02531     QTextOption option;
02532     option.setTextDirection(q->layoutDirection());
02533     option.setFlags(QTextOption::IncludeTrailingSpaces);
02534     textLayout.setTextOption(option);
02535 
02536     textLayout.beginLayout();
02537     QTextLine l = textLayout.createLine();
02538     textLayout.endLayout();
02539     ascent = qRound(l.ascent());
02540 }
02541 
02542 int QLineEditPrivate::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const
02543 {
02544     QRect cr = adjustedContentsRect();
02545     x-= cr.x() - hscroll + horizontalMargin;
02546     QTextLine l = textLayout.lineAt(0);
02547     return l.xToCursor(x, betweenOrOn);
02548 }
02549 
02550 QRect QLineEditPrivate::cursorRect() const
02551 {
02552     Q_Q(const QLineEdit);
02553     QRect cr = adjustedContentsRect();
02554     int cix = cr.x() - hscroll + horizontalMargin;
02555     QTextLine l = textLayout.lineAt(0);
02556     int c = cursor;
02557     if (preeditCursor != -1)
02558         c += preeditCursor;
02559     cix += qRound(l.cursorToX(c));
02560     int ch = qMin(cr.height(), q->fontMetrics().height() + 1);
02561     return QRect(cix-5, cr.y() + (cr.height() -  ch) / 2, 10, ch);
02562 }
02563 
02564 QRect QLineEditPrivate::adjustedContentsRect() const
02565 {
02566     Q_Q(const QLineEdit);
02567     QStyleOptionFrame opt = getStyleOption();
02568     return q->style()->subElementRect(QStyle::SE_LineEditContents, &opt, q);
02569 }
02570 
02571 bool QLineEditPrivate::fixup() // this function assumes that validate currently returns != Acceptable
02572 {
02573 #ifndef QT_NO_VALIDATOR
02574     if (validator) {
02575         QString textCopy = text;
02576         int cursorCopy = cursor;
02577         validator->fixup(textCopy);
02578         if (validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) {
02579             if (textCopy != text || cursorCopy != cursor)
02580                 setText(textCopy, cursorCopy);
02581             return true;
02582         }
02583     }
02584 #endif
02585     return false;
02586 }
02587 
02588 
02589 void QLineEditPrivate::moveCursor(int pos, bool mark)
02590 {
02591     Q_Q(QLineEdit);
02592     if (pos != cursor) {
02593         separate();
02594         if (maskData)
02595             pos = pos > cursor ? nextMaskBlank(pos) : prevMaskBlank(pos);
02596     }
02597     bool fullUpdate = mark || hasSelectedText();
02598     if (mark) {
02599         int anchor;
02600         if (selend > selstart && cursor == selstart)
02601             anchor = selend;
02602         else if (selend > selstart && cursor == selend)
02603             anchor = selstart;
02604         else
02605             anchor = cursor;
02606         selstart = qMin(anchor, pos);
02607         selend = qMax(anchor, pos);
02608         updateTextLayout();
02609     } else {
02610         deselect();
02611     }
02612     if (fullUpdate) {
02613         cursor = pos;
02614         q->update();
02615     } else {
02616         setCursorVisible(false);
02617         cursor = pos;
02618         setCursorVisible(true);
02619         if (!adjustedContentsRect().contains(cursorRect()))
02620             q->update();
02621     }
02622     QStyleOptionFrame opt = getStyleOption();
02623     if (mark && !q->style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, q))
02624         setCursorVisible(false);
02625     if (mark || selDirty) {
02626         selDirty = false;
02627         emit q->selectionChanged();
02628     }
02629     emitCursorPositionChanged();
02630 }
02631 
02632 void QLineEditPrivate::finishChange(int validateFromState, bool update, bool edited)
02633 {
02634     Q_Q(QLineEdit);
02635     bool lineDirty = selDirty;
02636     if (textDirty) {
02637         // do validation
02638         bool wasValidInput = validInput;
02639         validInput = true;
02640 #ifndef QT_NO_VALIDATOR
02641         if (validator) {
02642             validInput = false;
02643             QString textCopy = text;
02644             int cursorCopy = cursor;
02645             validInput = (validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
02646             if (validInput) {
02647                 if (text != textCopy) {
02648                     setText(textCopy, cursorCopy);
02649                     return;
02650                 }
02651                 cursor = cursorCopy;
02652             }
02653         }
02654 #endif
02655         if (validateFromState >= 0 && wasValidInput && !validInput) {
02656             undo(validateFromState);
02657             history.resize(undoState);
02658             if (modifiedState > undoState)
02659                 modifiedState = -1;
02660             validInput = true;
02661             textDirty = false;
02662         }
02663         updateTextLayout();
02664         lineDirty |= textDirty;
02665         if (textDirty) {
02666             textDirty = false;
02667             QString actualText = maskData ? stripString(text) : text;
02668             if (edited)
02669                 emit q->textEdited(actualText);
02670             q->updateMicroFocus();
02671             emit q->textChanged(actualText);
02672 #ifndef QT_NO_COMPLETER
02673             if (edited && completer && completer->completionMode() != QCompleter::InlineCompletion)
02674                 complete(-1); // update the popup on cut/paste/del
02675 #endif
02676         }
02677 #ifndef QT_NO_ACCESSIBILITY
02678         QAccessible::updateAccessibility(q, 0, QAccessible::ValueChanged);
02679 #endif
02680     }
02681     if (selDirty) {
02682         selDirty = false;
02683         emit q->selectionChanged();
02684     }
02685     if (lineDirty || update)
02686         q->update();
02687     emitCursorPositionChanged();
02688 }
02689 
02690 void QLineEditPrivate::emitCursorPositionChanged()
02691 {
02692     Q_Q(QLineEdit);
02693     if (cursor != lastCursorPos) {
02694         const int oldLast = lastCursorPos;
02695         lastCursorPos = cursor;
02696         emit q->cursorPositionChanged(oldLast, cursor);
02697     }
02698 }
02699 
02700 void QLineEditPrivate::setText(const QString& txt, int pos, bool edited)
02701 {
02702     Q_Q(QLineEdit);
02703     q->resetInputContext();
02704     deselect();
02705     QString oldText = text;
02706     if (maskData) {
02707         text = maskString(0, txt, true);
02708         text += clearString(text.length(), maxLength - text.length());
02709     } else {
02710         text = txt.isEmpty() ? txt : txt.left(maxLength);
02711     }
02712     history.clear();
02713     modifiedState =  undoState = 0;
02714     cursor = (pos < 0 || pos > text.length()) ? text.length() : pos;
02715     textDirty = (oldText != text);
02716     finishChange(-1, true, edited);
02717 }
02718 
02719 
02720 void QLineEditPrivate::setCursorVisible(bool visible)
02721 {
02722     Q_Q(QLineEdit);
02723     if ((bool)cursorVisible == visible)
02724         return;
02725     if (cursorTimer)
02726         cursorVisible = visible;
02727     QRect r = cursorRect();
02728     if (maskData)
02729         q->update();
02730     else
02731         q->update(r);
02732 }
02733 
02734 void QLineEditPrivate::addCommand(const Command& cmd)
02735 {
02736     if (separator && undoState && history[undoState-1].type != Separator) {
02737         history.resize(undoState + 2);
02738         history[undoState++] = Command(Separator, 0, 0);
02739     } else {
02740         history.resize(undoState + 1);
02741     }
02742     separator = false;
02743     history[undoState++] = cmd;
02744 }
02745 
02746 void QLineEditPrivate::insert(const QString& s)
02747 {
02748     if (maskData) {
02749         QString ms = maskString(cursor, s);
02750         for (int i = 0; i < (int) ms.length(); ++i) {
02751             addCommand (Command(DeleteSelection, cursor+i, text.at(cursor+i)));
02752             addCommand(Command(Insert, cursor+i, ms.at(i)));
02753         }
02754         text.replace(cursor, ms.length(), ms);
02755         cursor += ms.length();
02756         cursor = nextMaskBlank(cursor);
02757     } else {
02758         int remaining = maxLength - text.length();
02759         text.insert(cursor, s.left(remaining));
02760         for (int i = 0; i < (int) s.left(remaining).length(); ++i)
02761             addCommand(Command(Insert, cursor++, s.at(i)));
02762     }
02763     textDirty = true;
02764 }
02765 
02766 void QLineEditPrivate::del(bool wasBackspace)
02767 {
02768     if (cursor < (int) text.length()) {
02769         addCommand (Command((CommandType)((maskData?2:0)+(wasBackspace?Remove:Delete)), cursor, text.at(cursor)));
02770         if (maskData) {
02771             text.replace(cursor, 1, clearString(cursor, 1));
02772             addCommand(Command(Insert, cursor, text.at(cursor)));
02773         } else {
02774             text.remove(cursor, 1);
02775         }
02776         textDirty = true;
02777     }
02778 }
02779 
02780 void QLineEditPrivate::removeSelectedText()
02781 {
02782     if (selstart < selend && selend <= (int) text.length()) {
02783         separate();
02784         int i ;
02785         if (selstart <= cursor && cursor < selend) {
02786             // cursor is within the selection. Split up the commands
02787             // to be able to restore the correct cursor position
02788             for (i = cursor; i >= selstart; --i)
02789                 addCommand (Command(DeleteSelection, i, text.at(i)));
02790             for (i = selend - 1; i > cursor; --i)
02791                 addCommand (Command(DeleteSelection, i - cursor + selstart - 1, text.at(i)));
02792         } else {
02793             for (i = selend-1; i >= selstart; --i)
02794                 addCommand (Command(RemoveSelection, i, text.at(i)));
02795         }
02796         if (maskData) {
02797             text.replace(selstart, selend - selstart,  clearString(selstart, selend - selstart));
02798             for (int i = 0; i < selend - selstart; ++i)
02799                 addCommand(Command(Insert, selstart + i, text.at(selstart + i)));
02800         } else {
02801             text.remove(selstart, selend - selstart);
02802         }
02803         if (cursor > selstart)
02804             cursor -= qMin(cursor, selend) - selstart;
02805         deselect();
02806         textDirty = true;
02807     }
02808 }
02809 
02810 void QLineEditPrivate::parseInputMask(const QString &maskFields)
02811 {
02812     int delimiter = maskFields.indexOf(QLatin1Char(';'));
02813     if (maskFields.isEmpty() || delimiter == 0) {
02814         if (maskData) {
02815             delete [] maskData;
02816             maskData = 0;
02817             maxLength = 32767;
02818             setText(QString());
02819         }
02820         return;
02821     }
02822 
02823     if (delimiter == -1) {
02824         blank = QLatin1Char(' ');
02825         inputMask = maskFields;
02826     } else {
02827         inputMask = maskFields.left(delimiter);
02828         blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
02829     }
02830 
02831     // calculate maxLength / maskData length
02832     maxLength = 0;
02833     QChar c = 0;
02834     for (int i=0; i<inputMask.length(); i++) {
02835         c = inputMask.at(i);
02836         if (i > 0 && inputMask.at(i-1) == QLatin1Char('\\')) {
02837             maxLength++;
02838             continue;
02839         }
02840         if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
02841              c != QLatin1Char('<') && c != QLatin1Char('>') &&
02842              c != QLatin1Char('{') && c != QLatin1Char('}') &&
02843              c != QLatin1Char('[') && c != QLatin1Char(']'))
02844             maxLength++;
02845     }
02846 
02847     delete [] maskData;
02848     maskData = new MaskInputData[maxLength];
02849 
02850     MaskInputData::Casemode m = MaskInputData::NoCaseMode;
02851     c = 0;
02852     bool s;
02853     bool escape = false;
02854     int index = 0;
02855     for (int i = 0; i < inputMask.length(); i++) {
02856         c = inputMask.at(i);
02857         if (escape) {
02858             s = true;
02859             maskData[index].maskChar = c;
02860             maskData[index].separator = s;
02861             maskData[index].caseMode = m;
02862             index++;
02863             escape = false;
02864         } else if (c == QLatin1Char('<')) {
02865                 m = MaskInputData::Lower;
02866         } else if (c == QLatin1Char('>')) {
02867             m = MaskInputData::Upper;
02868         } else if (c == QLatin1Char('!')) {
02869             m = MaskInputData::NoCaseMode;
02870         } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
02871             switch (c.unicode()) {
02872             case 'A':
02873             case 'a':
02874             case 'N':
02875             case 'n':
02876             case 'X':
02877             case 'x':
02878             case '9':
02879             case '0':
02880             case 'D':
02881             case 'd':
02882             case '#':
02883             case 'H':
02884             case 'h':
02885             case 'B':
02886             case 'b':
02887                 s = false;
02888                 break;
02889             case '\\':
02890                 escape = true;
02891             default:
02892                 s = true;
02893                 break;
02894             }
02895 
02896             if (!escape) {
02897                 maskData[index].maskChar = c;
02898                 maskData[index].separator = s;
02899                 maskData[index].caseMode = m;
02900                 index++;
02901             }
02902         }
02903     }
02904     setText(text);
02905 }
02906 
02907 
02908 /* checks if the key is valid compared to the inputMask */
02909 bool QLineEditPrivate::isValidInput(QChar key, QChar mask) const
02910 {
02911     switch (mask.unicode()) {
02912     case 'A':
02913         if (key.isLetter())
02914             return true;
02915         break;
02916     case 'a':
02917         if (key.isLetter() || key == blank)
02918             return true;
02919         break;
02920     case 'N':
02921         if (key.isLetterOrNumber())
02922             return true;
02923         break;
02924     case 'n':
02925         if (key.isLetterOrNumber() || key == blank)
02926             return true;
02927         break;
02928     case 'X':
02929         if (key.isPrint())
02930             return true;
02931         break;
02932     case 'x':
02933         if (key.isPrint() || key == blank)
02934             return true;
02935         break;
02936     case '9':
02937         if (key.isNumber())
02938             return true;
02939         break;
02940     case '0':
02941         if (key.isNumber() || key == blank)
02942             return true;
02943         break;
02944     case 'D':
02945         if (key.isNumber() && key.digitValue() > 0)
02946             return true;
02947         break;
02948     case 'd':
02949         if ((key.isNumber() && key.digitValue() > 0) || key == blank)
02950             return true;
02951         break;
02952     case '#':
02953         if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == blank)
02954             return true;
02955         break;
02956     case 'B':
02957         if (key == QLatin1Char('0') || key == QLatin1Char('1'))
02958             return true;
02959         break;
02960     case 'b':
02961         if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == blank)
02962             return true;
02963         break;
02964     case 'H':
02965         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
02966             return true;
02967         break;
02968     case 'h':
02969         if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == blank)
02970             return true;
02971         break;
02972     default:
02973         break;
02974     }
02975     return false;
02976 }
02977 
02978 bool QLineEditPrivate::hasAcceptableInput(const QString &str) const
02979 {
02980 #ifndef QT_NO_VALIDATOR
02981     QString textCopy = str;
02982     int cursorCopy = cursor;
02983     if (validator && validator->validate(textCopy, cursorCopy)
02984         != QValidator::Acceptable)
02985         return false;
02986 #endif
02987 
02988     if (!maskData)
02989         return true;
02990 
02991     if (str.length() != maxLength)
02992         return false;
02993 
02994     for (int i=0; i < maxLength; ++i) {
02995         if (maskData[i].separator) {
02996             if (str.at(i) != maskData[i].maskChar)
02997                 return false;
02998         } else {
02999             if (!isValidInput(str.at(i), maskData[i].maskChar))
03000                 return false;
03001         }
03002     }
03003     return true;
03004 }
03005 
03006 /*
03007   Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
03008   specifies from where characters should be gotten when a separator is met in \a str - true means
03009   that blanks will be used, false that previous input is used.
03010   Calling this when no inputMask is set is undefined.
03011 */
03012 QString QLineEditPrivate::maskString(uint pos, const QString &str, bool clear) const
03013 {
03014     if (pos >= (uint)maxLength)
03015         return QString::fromLatin1("");
03016 
03017     QString fill;
03018     fill = clear ? clearString(0, maxLength) : text;
03019 
03020     int strIndex = 0;
03021     QString s = QString::fromLatin1("");
03022     int i = pos;
03023     while (i < maxLength) {
03024         if (strIndex < str.length()) {
03025             if (maskData[i].separator) {
03026                 s += maskData[i].maskChar;
03027                 if (str[(int)strIndex] == maskData[i].maskChar)
03028                     strIndex++;
03029                 ++i;
03030             } else {
03031                 if (isValidInput(str[(int)strIndex], maskData[i].maskChar)) {
03032                     switch (maskData[i].caseMode) {
03033                     case MaskInputData::Upper:
03034                         s += str[(int)strIndex].toUpper();
03035                         break;
03036                     case MaskInputData::Lower:
03037                         s += str[(int)strIndex].toLower();
03038                         break;
03039                     default:
03040                         s += str[(int)strIndex];
03041                     }
03042                     ++i;
03043                 } else {
03044                     // search for separator first
03045                     int n = findInMask(i, true, true, str[(int)strIndex]);
03046                     if (n != -1) {
03047                         if (str.length() != 1 || i == 0 || (i > 0 && (!maskData[i-1].separator || maskData[i-1].maskChar != str[(int)strIndex]))) {
03048                             s += fill.mid(i, n-i+1);
03049                             i = n + 1; // update i to find + 1
03050                         }
03051                     } else {
03052                         // search for valid blank if not
03053                         n = findInMask(i, true, false, str[(int)strIndex]);
03054                         if (n != -1) {
03055                             s += fill.mid(i, n-i);
03056                             switch (maskData[n].caseMode) {
03057                             case MaskInputData::Upper:
03058                                 s += str[(int)strIndex].toUpper();
03059                                 break;
03060                             case MaskInputData::Lower:
03061                                 s += str[(int)strIndex].toLower();
03062                                 break;
03063                             default:
03064                                 s += str[(int)strIndex];
03065                             }
03066                             i = n + 1; // updates i to find + 1
03067                         }
03068                     }
03069                 }
03070                 strIndex++;
03071             }
03072         } else
03073             break;
03074     }
03075 
03076     return s;
03077 }
03078 
03079 
03080 
03081 /*
03082   Returns a "cleared" string with only separators and blank chars.
03083   Calling this when no inputMask is set is undefined.
03084 */
03085 QString QLineEditPrivate::clearString(uint pos, uint len) const
03086 {
03087     if (pos >= (uint)maxLength)
03088         return QString();
03089 
03090     QString s;
03091     int end = qMin((uint)maxLength, pos + len);
03092     for (int i=pos; i<end; i++)
03093         if (maskData[i].separator)
03094             s += maskData[i].maskChar;
03095         else
03096             s += blank;
03097 
03098     return s;
03099 }
03100 
03101 /*
03102   Strips blank parts of the input in a QLineEdit when an inputMask is set,
03103   separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
03104 */
03105 QString QLineEditPrivate::stripString(const QString &str) const
03106 {
03107     if (!maskData)
03108         return str;
03109 
03110     QString s;
03111     int end = qMin(maxLength, (int)str.length());
03112     for (int i=0; i < end; i++)
03113         if (maskData[i].separator)
03114             s += maskData[i].maskChar;
03115         else
03116             if (str[i] != blank)
03117                 s += str[i];
03118 
03119     return s;
03120 }
03121 
03122 /* searches forward/backward in maskData for either a separator or a blank */
03123 int QLineEditPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
03124 {
03125     if (pos >= maxLength || pos < 0)
03126         return -1;
03127 
03128     int end = forward ? maxLength : -1;
03129     int step = forward ? 1 : -1;
03130     int i = pos;
03131 
03132     while (i != end) {
03133         if (findSeparator) {
03134             if (maskData[i].separator && maskData[i].maskChar == searchChar)
03135                 return i;
03136         } else {
03137             if (!maskData[i].separator) {
03138                 if (searchChar.isNull())
03139                     return i;
03140                 else if (isValidInput(searchChar, maskData[i].maskChar))
03141                     return i;
03142             }
03143         }
03144         i += step;
03145     }
03146     return -1;
03147 }
03148 
03149 void QLineEditPrivate::undo(int until)
03150 {
03151     if (!isUndoAvailable())
03152         return;
03153     deselect();
03154     while (undoState && undoState > until) {
03155         Command& cmd = history[--undoState];
03156         switch (cmd.type) {
03157         case Insert:
03158             text.remove(cmd.pos, 1);
03159             cursor = cmd.pos;
03160             break;
03161         case Remove:
03162         case RemoveSelection:
03163             text.insert(cmd.pos, cmd.uc);
03164             cursor = cmd.pos + 1;
03165             break;
03166         case Delete:
03167         case DeleteSelection:
03168             text.insert(cmd.pos, cmd.uc);
03169             cursor = cmd.pos;
03170             break;
03171         case Separator:
03172             continue;
03173         }
03174         if (until < 0 && undoState) {
03175             Command& next = history[undoState-1];
03176             if (next.type != cmd.type && next.type < RemoveSelection
03177                  && !(cmd.type >= RemoveSelection && next.type != Separator))
03178                 break;
03179         }
03180     }
03181     textDirty = true;
03182     emitCursorPositionChanged();
03183 }
03184 
03185 void QLineEditPrivate::redo() {
03186     if (!isRedoAvailable())
03187         return;
03188     deselect();
03189     while (undoState < (int)history.size()) {
03190         Command& cmd = history[undoState++];
03191         switch (cmd.type) {
03192         case Insert:
03193             text.insert(cmd.pos, cmd.uc);
03194             cursor = cmd.pos + 1;
03195             break;
03196         case Remove:
03197         case Delete:
03198         case RemoveSelection:
03199         case DeleteSelection:
03200             text.remove(cmd.pos, 1);
03201             cursor = cmd.pos;
03202             break;
03203         case Separator:
03204             continue;
03205         }
03206         if (undoState < (int)history.size()) {
03207             Command& next = history[undoState];
03208             if (next.type != cmd.type && cmd.type < RemoveSelection
03209                  && !(next.type >= RemoveSelection && cmd.type != Separator))
03210                 break;
03211         }
03212     }
03213     textDirty = true;
03214     emitCursorPositionChanged();
03215 }
03216 
03364 #include "moc_qlineedit.cpp"
03365 
03366 #endif // QT_NO_LINEEDIT

Generated on Thu Mar 15 11:57:00 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1