source: vendor/trolltech/current/src/widgets/qlineedit.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 74.9 KB
Line 
1/**********************************************************************
2** $Id: qlineedit.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of QLineEdit widget class
5**
6** Created : 941011
7**
8** Copyright (C) 1992-2002 Trolltech AS. All rights reserved.
9**
10** This file is part of the widgets module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qlineedit.h"
39#ifndef QT_NO_LINEEDIT
40#include "qpainter.h"
41#include "qdrawutil.h"
42#include "qfontmetrics.h"
43#include "qpixmap.h"
44#include "qclipboard.h"
45#include "qapplication.h"
46#include "qvalidator.h"
47#include "qdragobject.h"
48#include "qtimer.h"
49#include "qpopupmenu.h"
50#include "qstringlist.h"
51#include "qguardedptr.h"
52#include "qstyle.h"
53#include "qwhatsthis.h"
54#include "../kernel/qinternal_p.h"
55#include "private/qtextlayout_p.h"
56#include "qvaluevector.h"
57#if defined(QT_ACCESSIBILITY_SUPPORT)
58#include "qaccessible.h"
59#endif
60
61#ifndef QT_NO_ACCEL
62#include "qkeysequence.h"
63#define ACCEL_KEY(k) "\t" + QString(QKeySequence( Qt::CTRL | Qt::Key_ ## k ))
64#else
65#define ACCEL_KEY(k) "\t" + QString("Ctrl+" #k)
66#endif
67
68#define innerMargin 1
69
70struct QLineEditPrivate : public Qt
71{
72 QLineEditPrivate( QLineEdit *q )
73 : q(q), cursor(0), cursorTimer(0), tripleClickTimer(0), frame(1),
74 cursorVisible(0), separator(0), readOnly(0), modified(0),
75 direction(QChar::DirON), dragEnabled(1), alignment(0),
76 echoMode(0), textDirty(0), selDirty(0), validInput(1),
77 ascent(0), maxLength(32767), menuId(0),
78 hscroll(0), validator(0), maskData(0),
79 undoState(0), selstart(0), selend(0),
80 imstart(0), imend(0), imselstart(0), imselend(0)
81#ifndef QT_NO_DRAGANDDROP
82 ,dndTimer(0)
83#endif
84 {}
85 void init( const QString&);
86
87 QLineEdit *q;
88 QString text;
89 int cursor;
90 int cursorTimer;
91 QPoint tripleClick;
92 int tripleClickTimer;
93 uint frame : 1;
94 uint cursorVisible : 1;
95 uint separator : 1;
96 uint readOnly : 1;
97 uint modified : 1;
98 uint direction : 5;
99 uint dragEnabled : 1;
100 uint alignment : 3;
101 uint echoMode : 2;
102 uint textDirty : 1;
103 uint selDirty : 1;
104 uint validInput : 1;
105 int ascent;
106 int maxLength;
107 int menuId;
108 int hscroll;
109 QChar passwordChar; // obsolete
110
111 void finishChange( int validateFromState = -1, bool setModified = TRUE );
112
113 const QValidator* validator;
114 struct MaskInputData {
115 enum Casemode { NoCaseMode, Upper, Lower };
116 QChar maskChar; // either the separator char or the inputmask
117 bool separator;
118 Casemode caseMode;
119 };
120 QString inputMask;
121 QChar blank;
122 MaskInputData *maskData;
123 inline int nextMaskBlank( int pos ) {
124 int c = findInMask( pos, TRUE, FALSE );
125 separator |= ( c != pos );
126 return ( c != -1 ? c : maxLength );
127 }
128 inline int prevMaskBlank( int pos ) {
129 int c = findInMask( pos, FALSE, FALSE );
130 separator |= ( c != pos );
131 return ( c != -1 ? c : 0 );
132 }
133
134 void setCursorVisible( bool visible );
135
136
137 // undo/redo handling
138 enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection };
139 struct Command {
140 inline Command(){}
141 inline Command( CommandType type, int pos, QChar c )
142 :type(type),c(c),pos(pos){}
143 uint type : 4;
144 QChar c;
145 int pos;
146 };
147 int undoState;
148 QValueVector<Command> history;
149 void addCommand( const Command& cmd );
150 void insert( const QString& s );
151 void del( bool wasBackspace = FALSE );
152 void remove( int pos );
153
154 inline void separate() { separator = TRUE; }
155 inline void undo( int until = -1 ) {
156 if ( !isUndoAvailable() )
157 return;
158 deselect();
159 while ( undoState && undoState > until ) {
160 Command& cmd = history[--undoState];
161 switch ( cmd.type ) {
162 case Insert:
163 text.remove( cmd.pos, 1);
164 cursor = cmd.pos;
165 break;
166 case Remove:
167 case RemoveSelection:
168 text.insert( cmd.pos, cmd.c );
169 cursor = cmd.pos + 1;
170 break;
171 case Delete:
172 case DeleteSelection:
173 text.insert( cmd.pos, cmd.c );
174 cursor = cmd.pos;
175 break;
176 case Separator:
177 continue;
178 }
179 if ( until < 0 && undoState ) {
180 Command& next = history[undoState-1];
181 if ( next.type != cmd.type && next.type < RemoveSelection
182 && !( cmd.type >= RemoveSelection && next.type != Separator ) )
183 break;
184 }
185 }
186 modified = ( undoState != 0 );
187 textDirty = TRUE;
188 }
189 inline void redo() {
190 if ( !isRedoAvailable() )
191 return;
192 deselect();
193 while ( undoState < (int)history.size() ) {
194 Command& cmd = history[undoState++];
195 switch ( cmd.type ) {
196 case Insert:
197 text.insert( cmd.pos, cmd.c );
198 cursor = cmd.pos + 1;
199 break;
200 case Remove:
201 case Delete:
202 case RemoveSelection:
203 case DeleteSelection:
204 text.remove( cmd.pos, 1 );
205 cursor = cmd.pos;
206 break;
207 case Separator:
208 continue;
209 }
210 if ( undoState < (int)history.size() ) {
211 Command& next = history[undoState];
212 if ( next.type != cmd.type && cmd.type < RemoveSelection
213 && !( next.type >= RemoveSelection && cmd.type != Separator ) )
214 break;
215 }
216 }
217 textDirty = TRUE;
218 }
219 inline bool isUndoAvailable() const { return !readOnly && undoState; }
220 inline bool isRedoAvailable() const { return !readOnly && undoState < (int)history.size(); }
221
222 // bidi
223 inline bool isRightToLeft() const { return direction==QChar::DirON?text.isRightToLeft():(direction==QChar::DirR); }
224
225 // selection
226 int selstart, selend;
227 inline bool allSelected() const { return !text.isEmpty() && selstart == 0 && selend == (int)text.length(); }
228 inline bool hasSelectedText() const { return !text.isEmpty() && selend > selstart; }
229 inline void deselect() { selDirty |= (selend > selstart); selstart = selend = 0; }
230 void removeSelectedText();
231#ifndef QT_NO_CLIPBOARD
232 void copy( bool clipboard = TRUE ) const;
233#endif
234 inline bool inSelection( int x ) const
235 { if ( selstart >= selend ) return FALSE;
236 int pos = xToPos( x, QTextItem::OnCharacters ); return pos >= selstart && pos < selend; }
237
238 // masking
239 void parseInputMask( const QString &maskFields );
240 bool isValidInput( QChar key, QChar mask ) const;
241 QString maskString( uint pos, const QString &str, bool clear = FALSE ) const;
242 QString clearString( uint pos, uint len ) const;
243 QString stripString( const QString &str ) const;
244 int findInMask( int pos, bool forward, bool findSeparator, QChar searchChar = QChar() ) const;
245
246 // input methods
247 int imstart, imend, imselstart, imselend;
248
249 // complex text layout
250 QTextLayout textLayout;
251 void updateTextLayout();
252 void moveCursor( int pos, bool mark = FALSE );
253 void setText( const QString& txt );
254 int xToPos( int x, QTextItem::CursorPosition = QTextItem::BetweenCharacters ) const;
255 inline int visualAlignment() const { return alignment ? alignment : int( isRightToLeft() ? AlignRight : AlignLeft ); }
256 QRect cursorRect() const;
257 void updateMicroFocusHint();
258
259#ifndef QT_NO_DRAGANDDROP
260 // drag and drop
261 QPoint dndPos;
262 int dndTimer;
263 void drag();
264#endif
265};
266
267
268/*!
269 \class QLineEdit
270 \brief The QLineEdit widget is a one-line text editor.
271
272 \ingroup basic
273 \mainclass
274
275 A line edit allows the user to enter and edit a single line of
276 plain text with a useful collection of editing functions,
277 including undo and redo, cut and paste, and drag and drop.
278
279 By changing the echoMode() of a line edit, it can also be used as
280 a "write-only" field, for inputs such as passwords.
281
282 The length of the text can be constrained to maxLength(). The text
283 can be arbitrarily constrained using a validator() or an
284 inputMask(), or both.
285
286 A related class is QTextEdit which allows multi-line, rich-text
287 editing.
288
289 You can change the text with setText() or insert(). The text is
290 retrieved with text(); the displayed text (which may be different,
291 see \l{EchoMode}) is retrieved with displayText(). Text can be
292 selected with setSelection() or selectAll(), and the selection can
293 be cut(), copy()ied and paste()d. The text can be aligned with
294 setAlignment().
295
296 When the text changes the textChanged() signal is emitted; when
297 the Return or Enter key is pressed the returnPressed() signal is
298 emitted. Note that if there is a validator set on the line edit,
299 the returnPressed() signal will only be emitted if the validator
300 returns \c Acceptable.
301
302 By default, QLineEdits have a frame as specified by the Windows
303 and Motif style guides; you can turn it off by calling
304 setFrame(FALSE).
305
306 The default key bindings are described below. The line edit also
307 provides a context menu (usually invoked by a right mouse click)
308 that presents some of these editing options.
309 \target desc
310 \table
311 \header \i Keypress \i Action
312 \row \i Left Arrow \i Moves the cursor one character to the left.
313 \row \i Shift+Left Arrow \i Moves and selects text one character to the left.
314 \row \i Right Arrow \i Moves the cursor one character to the right.
315 \row \i Shift+Right Arrow \i Moves and selects text one character to the right.
316 \row \i Home \i Moves the cursor to the beginning of the line.
317 \row \i End \i Moves the cursor to the end of the line.
318 \row \i Backspace \i Deletes the character to the left of the cursor.
319 \row \i Ctrl+Backspace \i Deletes the word to the left of the cursor.
320 \row \i Delete \i Deletes the character to the right of the cursor.
321 \row \i Ctrl+Delete \i Deletes the word to the right of the cursor.
322 \row \i Ctrl+A \i Moves the cursor to the beginning of the line.
323 \row \i Ctrl+B \i Moves the cursor one character to the left.
324 \row \i Ctrl+C \i Copies the selected text to the clipboard.
325 (Windows also supports Ctrl+Insert for this operation.)
326 \row \i Ctrl+D \i Deletes the character to the right of the cursor.
327 \row \i Ctrl+E \i Moves the cursor to the end of the line.
328 \row \i Ctrl+F \i Moves the cursor one character to the right.
329 \row \i Ctrl+H \i Deletes the character to the left of the cursor.
330 \row \i Ctrl+K \i Deletes to the end of the line.
331 \row \i Ctrl+V \i Pastes the clipboard text into line edit.
332 (Windows also supports Shift+Insert for this operation.)
333 \row \i Ctrl+X \i Deletes the selected text and copies it to the clipboard.
334 (Windows also supports Shift+Delete for this operation.)
335 \row \i Ctrl+Z \i Undoes the last operation.
336 \row \i Ctrl+Y \i Redoes the last undone operation.
337 \endtable
338
339 Any other key sequence that represents a valid character, will
340 cause the character to be inserted into the line edit.
341
342 <img src=qlined-m.png> <img src=qlined-w.png>
343
344 \sa QTextEdit QLabel QComboBox
345 \link guibooks.html#fowler GUI Design Handbook: Field, Entry\endlink
346*/
347
348
349/*!
350 \fn void QLineEdit::textChanged( const QString& )
351
352 This signal is emitted whenever the text changes. The argument is
353 the new text.
354*/
355
356/*!
357 \fn void QLineEdit::selectionChanged()
358
359 This signal is emitted whenever the selection changes.
360
361 \sa hasSelectedText(), selectedText()
362*/
363
364/*!
365 \fn void QLineEdit::lostFocus()
366
367 This signal is emitted when the line edit has lost focus.
368
369 \sa hasFocus(), QWidget::focusInEvent(), QWidget::focusOutEvent()
370*/
371
372
373
374/*!
375 Constructs a line edit with no text.
376
377 The maximum text length is set to 32767 characters.
378
379 The \a parent and \a name arguments are sent to the QWidget constructor.
380
381 \sa setText(), setMaxLength()
382*/
383
384QLineEdit::QLineEdit( QWidget* parent, const char* name )
385 : QFrame( parent, name, WNoAutoErase ), d(new QLineEditPrivate( this ))
386{
387 d->init( QString::null );
388}
389
390/*!
391 Constructs a line edit containing the text \a contents.
392
393 The cursor position is set to the end of the line and the maximum
394 text length to 32767 characters.
395
396 The \a parent and \a name arguments are sent to the QWidget
397 constructor.
398
399 \sa text(), setMaxLength()
400*/
401
402QLineEdit::QLineEdit( const QString& contents, QWidget* parent, const char* name )
403 : QFrame( parent, name, WNoAutoErase ), d(new QLineEditPrivate( this ))
404{
405 d->init( contents );
406}
407
408/*!
409 Constructs a line edit with an input \a inputMask and the text \a
410 contents.
411
412 The cursor position is set to the end of the line and the maximum
413 text length is set to the length of the mask (the number of mask
414 characters and separators).
415
416 The \a parent and \a name arguments are sent to the QWidget
417 constructor.
418
419 \sa setMask() text()
420*/
421QLineEdit::QLineEdit( const QString& contents, const QString &inputMask, QWidget* parent, const char* name )
422 : QFrame( parent, name, WNoAutoErase ), d(new QLineEditPrivate( this ))
423{
424 d->parseInputMask( inputMask );
425 if ( d->maskData ) {
426 QString ms = d->maskString( 0, contents );
427 d->init( ms + d->clearString( ms.length(), d->maxLength - ms.length() ) );
428 d->cursor = d->nextMaskBlank( ms.length() );
429 } else {
430 d->init( contents );
431 }
432}
433
434/*!
435 Destroys the line edit.
436*/
437
438QLineEdit::~QLineEdit()
439{
440 delete d;
441}
442
443
444/*!
445 \property QLineEdit::text
446 \brief the line edit's text
447
448 Setting this property clears the selection, clears the undo/redo
449 history, moves the cursor to the end of the line and resets the
450 \c modified property to FALSE. The text is not validated when
451 inserted with setText().
452
453 The text is truncated to maxLength() length.
454
455 \sa insert()
456*/
457QString QLineEdit::text() const
458{
459 if ( d->maskData )
460 return d->stripString( d->text );
461 return ( d->text.isNull() ? QString::fromLatin1("") : d->text );
462}
463
464void QLineEdit::setText( const QString& text)
465{
466 resetInputContext();
467 d->setText( text );
468 d->modified = FALSE;
469 d->finishChange( -1, FALSE );
470}
471
472
473/*!
474 \property QLineEdit::displayText
475 \brief the displayed text
476
477 If \c EchoMode is \c Normal this returns the same as text(); if
478 \c EchoMode is \c Password it returns a string of asterisks
479 text().length() characters long, e.g. "******"; if \c EchoMode is
480 \c NoEcho returns an empty string, "".
481
482 \sa setEchoMode() text() EchoMode
483*/
484
485QString QLineEdit::displayText() const
486{
487 if ( d->echoMode == NoEcho )
488 return QString::fromLatin1("");
489 QString res = d->text;
490 if ( d->echoMode == Password )
491 res.fill( passwordChar() );
492 return ( res.isNull() ? QString::fromLatin1("") : res );
493}
494
495
496/*!
497 \property QLineEdit::maxLength
498 \brief the maximum permitted length of the text
499
500 If the text is too long, it is truncated at the limit.
501
502 If truncation occurs any selected text will be unselected, the
503 cursor position is set to 0 and the first part of the string is
504 shown.
505
506 If the line edit has an input mask, the mask defines the maximum
507 string length.
508
509 \sa inputMask
510*/
511
512int QLineEdit::maxLength() const
513{
514 return d->maxLength;
515}
516
517void QLineEdit::setMaxLength( int maxLength )
518{
519 if ( d->maskData )
520 return;
521 d->maxLength = maxLength;
522 setText( d->text );
523}
524
525
526
527/*!
528 \property QLineEdit::frame
529 \brief whether the line edit draws itself with a frame
530
531 If enabled (the default) the line edit draws itself inside a
532 two-pixel frame, otherwise the line edit draws itself without any
533 frame.
534*/
535bool QLineEdit::frame() const
536{
537 return frameShape() != NoFrame;
538}
539
540
541void QLineEdit::setFrame( bool enable )
542{
543 setFrameStyle( enable ? ( LineEditPanel | Sunken ) : NoFrame );
544}
545
546
547/*!
548 \enum QLineEdit::EchoMode
549
550 This enum type describes how a line edit should display its
551 contents.
552
553 \value Normal Display characters as they are entered. This is the
554 default.
555 \value NoEcho Do not display anything. This may be appropriate
556 for passwords where even the length of the
557 password should be kept secret.
558 \value Password Display asterisks instead of the characters
559 actually entered.
560
561 \sa setEchoMode() echoMode()
562*/
563
564
565/*!
566 \property QLineEdit::echoMode
567 \brief the line edit's echo mode
568
569 The initial setting is \c Normal, but QLineEdit also supports \c
570 NoEcho and \c Password modes.
571
572 The widget's display and the ability to copy or drag the text is
573 affected by this setting.
574
575 \sa EchoMode displayText()
576*/
577
578QLineEdit::EchoMode QLineEdit::echoMode() const
579{
580 return (EchoMode) d->echoMode;
581}
582
583void QLineEdit::setEchoMode( EchoMode mode )
584{
585 d->echoMode = mode;
586 d->updateTextLayout();
587 update();
588}
589
590
591
592/*!
593 Returns a pointer to the current input validator, or 0 if no
594 validator has been set.
595
596 \sa setValidator()
597*/
598
599const QValidator * QLineEdit::validator() const
600{
601 return d->validator;
602}
603
604/*!
605 Sets this line edit to only accept input that the validator, \a v,
606 will accept. This allows you to place any arbitrary constraints on
607 the text which may be entered.
608
609 If \a v == 0, setValidator() removes the current input validator.
610 The initial setting is to have no input validator (i.e. any input
611 is accepted up to maxLength()).
612
613 \sa validator() QIntValidator QDoubleValidator QRegExpValidator
614*/
615
616void QLineEdit::setValidator( const QValidator *v )
617{
618 if ( d->validator )
619 disconnect( (QObject*)d->validator, SIGNAL( destroyed() ),
620 this, SLOT( clearValidator() ) );
621 d->validator = v;
622 if ( d->validator )
623 connect( (QObject*)d->validator, SIGNAL( destroyed() ),
624 this, SLOT( clearValidator() ) );
625}
626
627
628
629/*!
630 Returns a recommended size for the widget.
631
632 The width returned, in pixels, is usually enough for about 15 to
633 20 characters.
634*/
635
636QSize QLineEdit::sizeHint() const
637{
638 constPolish();
639 QFontMetrics fm( font() );
640 int h = QMAX(fm.lineSpacing(), 14) + 2*innerMargin;
641 int w = fm.width( 'x' ) * 17; // "some"
642 int m = frameWidth() * 2;
643 return (style().sizeFromContents(QStyle::CT_LineEdit, this,
644 QSize( w + m, h + m ).
645 expandedTo(QApplication::globalStrut())));
646}
647
648
649/*!
650 Returns a minimum size for the line edit.
651
652 The width returned is enough for at least one character.
653*/
654
655QSize QLineEdit::minimumSizeHint() const
656{
657 constPolish();
658 QFontMetrics fm = fontMetrics();
659 int h = fm.height() + QMAX( 2*innerMargin, fm.leading() );
660 int w = fm.maxWidth();
661 int m = frameWidth() * 2;
662 return QSize( w + m, h + m );
663}
664
665
666/*!
667 \property QLineEdit::cursorPosition
668 \brief the current cursor position for this line edit
669
670 Setting the cursor position causes a repaint when appropriate.
671*/
672
673int QLineEdit::cursorPosition() const
674{
675 return d->cursor;
676}
677
678
679void QLineEdit::setCursorPosition( int pos )
680{
681 if ( pos <= (int) d->text.length() )
682 d->moveCursor( pos );
683}
684
685
686/*! \obsolete Use setText(), setCursorPosition() and setSelection() instead.
687*/
688
689bool QLineEdit::validateAndSet( const QString &newText, int newPos,
690 int newMarkAnchor, int newMarkDrag )
691{
692 int priorState = d->undoState;
693 d->selstart = 0;
694 d->selend = d->text.length();
695 d->removeSelectedText();
696 d->insert( newText );
697 d->finishChange( priorState );
698 if ( d->undoState > priorState ) {
699 d->cursor = newPos;
700 d->selstart = QMIN( newMarkAnchor, newMarkDrag );
701 d->selend = QMAX( newMarkAnchor, newMarkDrag );
702 d->updateMicroFocusHint();
703 update();
704 return TRUE;
705 }
706 return FALSE;
707}
708
709
710/*!
711 \property QLineEdit::alignment
712 \brief the alignment of the line edit
713
714 Possible Values are \c Qt::AlignAuto, \c Qt::AlignLeft, \c
715 Qt::AlignRight and \c Qt::AlignHCenter.
716
717 Attempting to set the alignment to an illegal flag combination
718 does nothing.
719
720 \sa Qt::AlignmentFlags
721*/
722
723int QLineEdit::alignment() const
724{
725 return d->alignment;
726}
727
728void QLineEdit::setAlignment( int flag )
729{
730 d->alignment = flag & 0x7;
731 update();
732}
733
734
735/*!
736 \obsolete
737 \fn void QLineEdit::cursorRight( bool, int )
738
739 Use cursorForward() instead.
740
741 \sa cursorForward()
742*/
743
744/*!
745 \obsolete
746 \fn void QLineEdit::cursorLeft( bool, int )
747 For compatibilty with older applications only. Use cursorBackward()
748 instead.
749 \sa cursorBackward()
750*/
751
752/*!
753 Moves the cursor forward \a steps characters. If \a mark is TRUE
754 each character moved over is added to the selection; if \a mark is
755 FALSE the selection is cleared.
756
757 \sa cursorBackward()
758*/
759
760void QLineEdit::cursorForward( bool mark, int steps )
761{
762 int cursor = d->cursor;
763 if ( steps > 0 ) {
764 while( steps-- )
765 cursor = d->textLayout.nextCursorPosition( cursor );
766 } else if ( steps < 0 ) {
767 while ( steps++ )
768 cursor = d->textLayout.previousCursorPosition( cursor );
769 }
770 d->moveCursor( cursor, mark );
771}
772
773
774/*!
775 Moves the cursor back \a steps characters. If \a mark is TRUE each
776 character moved over is added to the selection; if \a mark is
777 FALSE the selection is cleared.
778
779 \sa cursorForward()
780*/
781void QLineEdit::cursorBackward( bool mark, int steps )
782{
783 cursorForward( mark, -steps );
784}
785
786/*!
787 Moves the cursor one word forward. If \a mark is TRUE, the word is
788 also selected.
789
790 \sa cursorWordBackward()
791*/
792void QLineEdit::cursorWordForward( bool mark )
793{
794 d->moveCursor( d->textLayout.nextCursorPosition(d->cursor, QTextLayout::SkipWords), mark );
795}
796
797/*!
798 Moves the cursor one word backward. If \a mark is TRUE, the word
799 is also selected.
800
801 \sa cursorWordForward()
802*/
803
804void QLineEdit::cursorWordBackward( bool mark )
805{
806 d->moveCursor( d->textLayout.previousCursorPosition(d->cursor, QTextLayout::SkipWords), mark );
807}
808
809
810/*!
811 If no text is selected, deletes the character to the left of the
812 text cursor and moves the cursor one position to the left. If any
813 text is selected, the cursor is moved to the beginning of the
814 selected text and the selected text is deleted.
815
816 \sa del()
817*/
818void QLineEdit::backspace()
819{
820 int priorState = d->undoState;
821 if ( d->hasSelectedText() ) {
822 d->removeSelectedText();
823 } else if ( d->cursor ) {
824 --d->cursor;
825 if ( d->maskData )
826 d->cursor = d->prevMaskBlank( d->cursor );
827 d->del( TRUE );
828 }
829 d->finishChange( priorState );
830}
831
832/*!
833 If no text is selected, deletes the character to the right of the
834 text cursor. If any text is selected, the cursor is moved to the
835 beginning of the selected text and the selected text is deleted.
836
837 \sa backspace()
838*/
839
840void QLineEdit::del()
841{
842 int priorState = d->undoState;
843 if ( d->hasSelectedText() ) {
844 d->removeSelectedText();
845 } else {
846 int n = d->textLayout.nextCursorPosition( d->cursor ) - d->cursor;
847 while ( n-- )
848 d->del();
849 }
850 d->finishChange( priorState );
851}
852
853/*!
854 Moves the text cursor to the beginning of the line unless it is
855 already there. If \a mark is TRUE, text is selected towards the
856 first position; otherwise, any selected text is unselected if the
857 cursor is moved.
858
859 \sa end()
860*/
861
862void QLineEdit::home( bool mark )
863{
864 d->moveCursor( 0, mark );
865}
866
867/*!
868 Moves the text cursor to the end of the line unless it is already
869 there. If \a mark is TRUE, text is selected towards the last
870 position; otherwise, any selected text is unselected if the cursor
871 is moved.
872
873 \sa home()
874*/
875
876void QLineEdit::end( bool mark )
877{
878 d->moveCursor( d->text.length(), mark );
879}
880
881
882/*!
883 \property QLineEdit::modified
884 \brief whether the line edit's contents has been modified by the user
885
886 The modified flag is never read by QLineEdit; it has a default value
887 of FALSE and is changed to TRUE whenever the user changes the line
888 edit's contents.
889
890 This is useful for things that need to provide a default value but
891 do not start out knowing what the default should be (perhaps it
892 depends on other fields on the form). Start the line edit without
893 the best default, and when the default is known, if modified()
894 returns FALSE (the user hasn't entered any text), insert the
895 default value.
896
897 Calling clearModified() or setText() resets the modified flag to
898 FALSE.
899*/
900
901bool QLineEdit::isModified() const
902{
903 return d->modified;
904}
905
906/*!
907 Resets the modified flag to FALSE.
908
909 \sa isModified()
910*/
911void QLineEdit::clearModified()
912{
913 d->modified = FALSE;
914 d->history.clear();
915 d->undoState = 0;
916}
917
918/*!
919 \obsolete
920 \property QLineEdit::edited
921 \brief whether the line edit has been edited. Use modified instead.
922*/
923bool QLineEdit::edited() const { return d->modified; }
924void QLineEdit::setEdited( bool on ) { d->modified = on; }
925
926/*!
927 \obsolete
928 \property QLineEdit::hasMarkedText
929 \brief whether part of the text has been selected by the user. Use hasSelectedText instead.
930*/
931
932/*!
933 \property QLineEdit::hasSelectedText
934 \brief whether there is any text selected
935
936 hasSelectedText() returns TRUE if some or all of the text has been
937 selected by the user; otherwise returns FALSE.
938
939 \sa selectedText()
940*/
941
942
943bool QLineEdit::hasSelectedText() const
944{
945 return d->hasSelectedText();
946}
947
948/*!
949 \obsolete
950 \property QLineEdit::markedText
951 \brief the text selected by the user. Use selectedText instead.
952*/
953
954/*!
955 \property QLineEdit::selectedText
956 \brief the selected text
957
958 If there is no selected text this property's value is
959 QString::null.
960
961 \sa hasSelectedText()
962*/
963
964QString QLineEdit::selectedText() const
965{
966 if ( d->hasSelectedText() )
967 return d->text.mid( d->selstart, d->selend - d->selstart );
968 return QString::null;
969}
970
971/*!
972 selectionStart() returns the index of the first selected character in the
973 line edit or -1 if no text is selected.
974
975 \sa selectedText()
976*/
977
978int QLineEdit::selectionStart() const
979{
980 return d->hasSelectedText() ? d->selstart : -1;
981}
982
983/*! \obsolete use selectedText(), selectionStart() */
984bool QLineEdit::getSelection( int *start, int *end )
985{
986 if ( d->hasSelectedText() && start && end ) {
987 *start = d->selstart;
988 *end = d->selend;
989 return TRUE;
990 }
991 return FALSE;
992}
993
994
995/*!
996 Selects text from position \a start and for \a length characters.
997
998 \sa deselect() selectAll() getSelection()
999*/
1000
1001void QLineEdit::setSelection( int start, int length )
1002{
1003 if ( start < 0 || start > (int)d->text.length() || length < 0 ) {
1004 d->selstart = d->selend = 0;
1005 } else {
1006 d->selstart = start;
1007 d->selend = QMIN( start + length, (int)d->text.length() );
1008 d->cursor = d->selend;
1009 }
1010 update();
1011}
1012
1013
1014/*!
1015 \property QLineEdit::undoAvailable
1016 \brief whether undo is available
1017*/
1018
1019bool QLineEdit::isUndoAvailable() const
1020{
1021 return d->isUndoAvailable();
1022}
1023
1024/*!
1025 \property QLineEdit::redoAvailable
1026 \brief whether redo is available
1027*/
1028
1029bool QLineEdit::isRedoAvailable() const
1030{
1031 return d->isRedoAvailable();
1032}
1033
1034/*!
1035 \property QLineEdit::dragEnabled
1036 \brief whether the lineedit starts a drag if the user presses and
1037 moves the mouse on some selected text
1038*/
1039
1040bool QLineEdit::dragEnabled() const
1041{
1042 return d->dragEnabled;
1043}
1044
1045void QLineEdit::setDragEnabled( bool b )
1046{
1047 d->dragEnabled = b;
1048}
1049
1050/*!
1051 \property QLineEdit::acceptableInput
1052 \brief whether the input satisfies the inputMask and the
1053 validator.
1054
1055 \sa setInputMask(), setValidator()
1056*/
1057bool QLineEdit::hasAcceptableInput() const
1058{
1059#ifndef QT_NO_VALIDATOR
1060 QString text = d->text;
1061 int cursor = d->cursor;
1062 if ( d->validator && d->validator->validate( text, cursor ) != QValidator::Acceptable )
1063 return FALSE;
1064#endif
1065
1066 if ( !d->maskData )
1067 return TRUE;
1068
1069 if ( d->text.length() != (uint)d->maxLength )
1070 return FALSE;
1071
1072 for ( uint i=0; i < (uint)d->maxLength; i++) {
1073 if ( d->maskData[i].separator ) {
1074 if ( d->text[(int)i] != d->maskData[i].maskChar )
1075 return FALSE;
1076 } else {
1077 if ( !d->isValidInput( d->text[(int)i], d->maskData[i].maskChar ) )
1078 return FALSE;
1079 }
1080 }
1081 return TRUE;
1082}
1083
1084
1085/*!
1086 \property QLineEdit::inputMask
1087 \brief The validation input mask
1088
1089 If no mask is set, inputMask() returns QString::null.
1090
1091 Sets the QLineEdit's validation mask. Validators can be used
1092 instead of, or in conjunction with masks; see setValidator().
1093
1094 Unset the mask and return to normal QLineEdit operation by passing
1095 an empty string ("") or just calling setInputMask() with no
1096 arguments.
1097
1098 The mask format understands these mask characters:
1099 \table
1100 \header \i Character \i Meaning
1101 \row \i \c A \i ASCII alphabetic character required. A-Z, a-z.
1102 \row \i \c a \i ASCII alphabetic character permitted but not required.
1103 \row \i \c N \i ASCII alphanumeric character required. A-Z, a-z, 0-9.
1104 \row \i \c n \i ASCII alphanumeric character permitted but not required.
1105 \row \i \c X \i Any character required.
1106 \row \i \c x \i Any character permitted but not required.
1107 \row \i \c 9 \i ASCII digit required. 0-9.
1108 \row \i \c 0 \i ASCII digit permitted but not required.
1109 \row \i \c D \i ASCII digit required. 1-9.
1110 \row \i \c d \i ASCII digit permitted but not required (1-9).
1111 \row \i \c # \i ASCII digit or plus/minus sign permitted but not required.
1112 \row \i \c > \i All following alphabetic characters are uppercased.
1113 \row \i \c < \i All following alphabetic characters are lowercased.
1114 \row \i \c ! \i Switch off case conversion.
1115 \row \i <tt>\\</tt> \i Use <tt>\\</tt> to escape the special
1116 characters listed above to use them as
1117 separators.
1118 \endtable
1119
1120 The mask consists of a string of mask characters and separators,
1121 optionally followed by a semi-colon and the character used for
1122 blanks: the blank characters are always removed from the text
1123 after editing. The default blank character is space.
1124
1125 Examples:
1126 \table
1127 \header \i Mask \i Notes
1128 \row \i \c 000.000.000.000;_ \i IP address; blanks are \c{_}.
1129 \row \i \c 0000-00-00 \i ISO Date; blanks are \c space
1130 \row \i \c >AAAAA-AAAAA-AAAAA-AAAAA-AAAAA;# \i License number;
1131 blanks are \c - and all (alphabetic) characters are converted to
1132 uppercase.
1133 \endtable
1134
1135 To get range control (e.g. for an IP address) use masks together
1136 with \link setValidator() validators\endlink.
1137
1138 \sa maxLength
1139*/
1140QString QLineEdit::inputMask() const
1141{
1142 return ( d->maskData ? d->inputMask + ';' + d->blank : QString::null );
1143}
1144
1145void QLineEdit::setInputMask( const QString &inputMask )
1146{
1147 d->parseInputMask( inputMask );
1148 if ( d->maskData )
1149 d->moveCursor( d->nextMaskBlank( 0 ) );
1150}
1151
1152/*!
1153 Selects all the text (i.e. highlights it) and moves the cursor to
1154 the end. This is useful when a default value has been inserted
1155 because if the user types before clicking on the widget, the
1156 selected text will be deleted.
1157
1158 \sa setSelection() deselect()
1159*/
1160
1161void QLineEdit::selectAll()
1162{
1163 d->selstart = d->selend = d->cursor = 0;
1164 d->moveCursor( d->text.length(), TRUE );
1165}
1166
1167/*!
1168 Deselects any selected text.
1169
1170 \sa setSelection() selectAll()
1171*/
1172
1173void QLineEdit::deselect()
1174{
1175 d->deselect();
1176 d->finishChange();
1177}
1178
1179
1180/*!
1181 This slot is equivalent to setValidator(0).
1182*/
1183
1184void QLineEdit::clearValidator()
1185{
1186 setValidator( 0 );
1187}
1188
1189/*!
1190 Deletes any selected text, inserts \a newText, and validates the
1191 result. If it is valid, it sets it as the new contents of the line
1192 edit.
1193*/
1194void QLineEdit::insert( const QString &newText )
1195{
1196// q->resetInputContext(); //#### FIX ME IN QT
1197 int priorState = d->undoState;
1198 d->removeSelectedText();
1199 d->insert( newText );
1200 d->finishChange( priorState );
1201}
1202
1203/*!
1204 Clears the contents of the line edit.
1205*/
1206void QLineEdit::clear()
1207{
1208 int priorState = d->undoState;
1209 resetInputContext();
1210 d->selstart = 0;
1211 d->selend = d->text.length();
1212 d->removeSelectedText();
1213 d->separate();
1214 d->finishChange( priorState );
1215}
1216
1217/*!
1218 Undoes the last operation if undo is \link
1219 QLineEdit::undoAvailable available\endlink. Deselects any current
1220 selection, and updates the selection start to the current cursor
1221 position.
1222*/
1223void QLineEdit::undo()
1224{
1225 resetInputContext();
1226 d->undo();
1227 d->finishChange( -1, FALSE );
1228}
1229
1230/*!
1231 Redoes the last operation if redo is \link
1232 QLineEdit::redoAvailable available\endlink.
1233*/
1234void QLineEdit::redo()
1235{
1236 resetInputContext();
1237 d->redo();
1238 d->finishChange();
1239}
1240
1241
1242/*!
1243 \property QLineEdit::readOnly
1244 \brief whether the line edit is read only.
1245
1246 In read-only mode, the user can still copy the text to the
1247 clipboard or drag-and-drop the text (if echoMode() is \c Normal),
1248 but cannot edit it.
1249
1250 QLineEdit does not show a cursor in read-only mode.
1251
1252 \sa setEnabled()
1253*/
1254
1255bool QLineEdit::isReadOnly() const
1256{
1257 return d->readOnly;
1258}
1259
1260void QLineEdit::setReadOnly( bool enable )
1261{
1262 d->readOnly = enable;
1263#ifndef QT_NO_CURSOR
1264 setCursor( enable ? arrowCursor : ibeamCursor );
1265#endif
1266 update();
1267}
1268
1269
1270#ifndef QT_NO_CLIPBOARD
1271/*!
1272 Copies the selected text to the clipboard and deletes it, if there
1273 is any, and if echoMode() is \c Normal.
1274
1275 If the current validator disallows deleting the selected text,
1276 cut() will copy without deleting.
1277
1278 \sa copy() paste() setValidator()
1279*/
1280
1281void QLineEdit::cut()
1282{
1283 if ( hasSelectedText() ) {
1284 copy();
1285 del();
1286 }
1287}
1288
1289
1290/*!
1291 Copies the selected text to the clipboard, if there is any, and if
1292 echoMode() is \c Normal.
1293
1294 \sa cut() paste()
1295*/
1296
1297void QLineEdit::copy() const
1298{
1299 d->copy();
1300}
1301
1302/*!
1303 Inserts the clipboard's text at the cursor position, deleting any
1304 selected text, providing the line edit is not \link
1305 QLineEdit::readOnly read-only\endlink.
1306
1307 If the end result would not be acceptable to the current
1308 \link setValidator() validator\endlink, nothing happens.
1309
1310 \sa copy() cut()
1311*/
1312
1313void QLineEdit::paste()
1314{
1315 insert( QApplication::clipboard()->text( QClipboard::Clipboard ) );
1316}
1317
1318void QLineEditPrivate::copy( bool clipboard ) const
1319{
1320 QString t = q->selectedText();
1321 if ( !t.isEmpty() && echoMode == QLineEdit::Normal ) {
1322 q->disconnect( QApplication::clipboard(), SIGNAL(selectionChanged()), q, 0);
1323 QApplication::clipboard()->setText( t, clipboard ? QClipboard::Clipboard : QClipboard::Selection );
1324 q->connect( QApplication::clipboard(), SIGNAL(selectionChanged()),
1325 q, SLOT(clipboardChanged()) );
1326 }
1327}
1328
1329#endif // !QT_NO_CLIPBOARD
1330
1331/*!\reimp
1332*/
1333
1334void QLineEdit::resizeEvent( QResizeEvent *e )
1335{
1336 QFrame::resizeEvent( e );
1337}
1338
1339/*! \reimp
1340*/
1341bool QLineEdit::event( QEvent * e )
1342{
1343 if ( e->type() == QEvent::AccelOverride && !d->readOnly ) {
1344 QKeyEvent* ke = (QKeyEvent*) e;
1345 if ( ke->state() == NoButton || ke->state() == ShiftButton
1346 || ke->state() == Keypad ) {
1347 if ( ke->key() < Key_Escape ) {
1348 ke->accept();
1349 } else if ( ke->state() == NoButton
1350 || ke->state() == ShiftButton ) {
1351 switch ( ke->key() ) {
1352 case Key_Delete:
1353 case Key_Home:
1354 case Key_End:
1355 case Key_Backspace:
1356 case Key_Left:
1357 case Key_Right:
1358 ke->accept();
1359 default:
1360 break;
1361 }
1362 }
1363 } else if ( ke->state() & ControlButton ) {
1364 switch ( ke->key() ) {
1365// Those are too frequently used for application functionality
1366/* case Key_A:
1367 case Key_B:
1368 case Key_D:
1369 case Key_E:
1370 case Key_F:
1371 case Key_H:
1372 case Key_K:
1373*/
1374 case Key_C:
1375 case Key_V:
1376 case Key_X:
1377 case Key_Y:
1378 case Key_Z:
1379 case Key_Left:
1380 case Key_Right:
1381#if defined (Q_WS_WIN)
1382 case Key_Insert:
1383 case Key_Delete:
1384#endif
1385 ke->accept();
1386 default:
1387 break;
1388 }
1389 }
1390 } else if ( e->type() == QEvent::Timer ) {
1391 // should be timerEvent, is here for binary compatibility
1392 int timerId = ((QTimerEvent*)e)->timerId();
1393 if ( timerId == d->cursorTimer ) {
1394 if(!hasSelectedText() || style().styleHint( QStyle::SH_BlinkCursorWhenTextSelected ))
1395 d->setCursorVisible( !d->cursorVisible );
1396#ifndef QT_NO_DRAGANDDROP
1397 } else if ( timerId == d->dndTimer ) {
1398 d->drag();
1399#endif
1400 } else if ( timerId == d->tripleClickTimer ) {
1401 killTimer( d->tripleClickTimer );
1402 d->tripleClickTimer = 0;
1403 }
1404 }
1405 return QWidget::event( e );
1406}
1407
1408/*! \reimp
1409*/
1410void QLineEdit::mousePressEvent( QMouseEvent* e )
1411{
1412 if ( e->button() == RightButton )
1413 return;
1414 if ( d->tripleClickTimer && ( e->pos() - d->tripleClick ).manhattanLength() <
1415 QApplication::startDragDistance() ) {
1416 selectAll();
1417 return;
1418 }
1419 bool mark = e->state() & ShiftButton;
1420 int cursor = d->xToPos( e->pos().x() );
1421#ifndef QT_NO_DRAGANDDROP
1422 if ( !mark && d->dragEnabled && d->echoMode == Normal &&
1423 e->button() == LeftButton && d->inSelection( e->pos().x() ) ) {
1424 d->cursor = cursor;
1425 d->updateMicroFocusHint();
1426 update();
1427 d->dndPos = e->pos();
1428 if ( !d->dndTimer )
1429 d->dndTimer = startTimer( QApplication::startDragTime() );
1430 } else
1431#endif
1432 {
1433 d->moveCursor( cursor, mark );
1434 }
1435}
1436
1437/*! \reimp
1438*/
1439void QLineEdit::mouseMoveEvent( QMouseEvent * e )
1440{
1441
1442#ifndef QT_NO_CURSOR
1443 if ( ( e->state() & MouseButtonMask ) == 0 ) {
1444 if ( !d->readOnly && d->dragEnabled
1445#ifndef QT_NO_WHATSTHIS
1446 && !QWhatsThis::inWhatsThisMode()
1447#endif
1448 )
1449 setCursor( ( d->inSelection( e->pos().x() ) ? arrowCursor : ibeamCursor ) );
1450 }
1451#endif
1452
1453 if ( e->state() & LeftButton ) {
1454#ifndef QT_NO_DRAGANDDROP
1455 if ( d->dndTimer ) {
1456 if ( ( d->dndPos - e->pos() ).manhattanLength() > QApplication::startDragDistance() )
1457 d->drag();
1458 } else
1459#endif
1460 {
1461 d->moveCursor( d->xToPos( e->pos().x() ), TRUE );
1462 }
1463 }
1464}
1465
1466/*! \reimp
1467*/
1468void QLineEdit::mouseReleaseEvent( QMouseEvent* e )
1469{
1470#ifndef QT_NO_DRAGANDDROP
1471 if ( e->button() == LeftButton ) {
1472 if ( d->dndTimer ) {
1473 killTimer( d->dndTimer );
1474 d->dndTimer = 0;
1475 deselect();
1476 return;
1477 }
1478 }
1479#endif
1480#ifndef QT_NO_CLIPBOARD
1481 if (QApplication::clipboard()->supportsSelection() ) {
1482 if ( e->button() == LeftButton ) {
1483 d->copy( FALSE );
1484 } else if ( !d->readOnly && e->button() == MidButton ) {
1485 d->deselect();
1486 insert( QApplication::clipboard()->text( QClipboard::Selection ) );
1487 }
1488 }
1489#endif
1490}
1491
1492/*! \reimp
1493*/
1494void QLineEdit::mouseDoubleClickEvent( QMouseEvent* e )
1495{
1496 if ( e->button() == Qt::LeftButton ) {
1497 deselect();
1498 d->cursor = d->xToPos( e->pos().x() );
1499 d->cursor = d->textLayout.previousCursorPosition( d->cursor, QTextLayout::SkipWords );
1500 // ## text layout should support end of words.
1501 int end = d->textLayout.nextCursorPosition( d->cursor, QTextLayout::SkipWords );
1502 while ( end > d->cursor && d->text[end-1].isSpace() )
1503 --end;
1504 d->moveCursor( end, TRUE );
1505 d->tripleClickTimer = startTimer( QApplication::doubleClickInterval() );
1506 d->tripleClick = e->pos();
1507 }
1508}
1509
1510/*!
1511 \fn void QLineEdit::returnPressed()
1512
1513 This signal is emitted when the Return or Enter key is pressed.
1514 Note that if there is a validator() or inputMask() set on the line
1515 edit, the returnPressed() signal will only be emitted if the input
1516 follows the inputMask() and the validator() returns \c Acceptable.
1517*/
1518
1519/*!
1520 Converts key press event \a e into a line edit action.
1521
1522 If Return or Enter is pressed and the current text is valid (or
1523 can be \link QValidator::fixup() made valid\endlink by the
1524 validator), the signal returnPressed() is emitted.
1525
1526 The default key bindings are listed in the \link #desc detailed
1527 description.\endlink
1528*/
1529
1530void QLineEdit::keyPressEvent( QKeyEvent * e )
1531{
1532 d->setCursorVisible( TRUE );
1533 if ( e->key() == Key_Enter || e->key() == Key_Return ) {
1534 const QValidator * v = d->validator;
1535 if ( hasAcceptableInput() ) {
1536 emit returnPressed();
1537 }
1538#ifndef QT_NO_VALIDATOR
1539 else if ( v && v->validate( d->text, d->cursor ) != QValidator::Acceptable ) {
1540 QString vstr = d->text;
1541 v->fixup( vstr );
1542 if ( vstr != d->text ) {
1543 setText( vstr );
1544 if ( hasAcceptableInput() )
1545 emit returnPressed();
1546 }
1547 }
1548#endif
1549 e->ignore();
1550 return;
1551 }
1552 if ( !d->readOnly ) {
1553 QString t = e->text();
1554 if ( !t.isEmpty() && (!e->ascii() || e->ascii()>=32) &&
1555 e->key() != Key_Delete &&
1556 e->key() != Key_Backspace ) {
1557#ifdef Q_WS_X11
1558 extern bool qt_hebrew_keyboard_hack;
1559 if ( qt_hebrew_keyboard_hack ) {
1560 // the X11 keyboard layout is broken and does not reverse
1561 // braces correctly. This is a hack to get halfway correct
1562 // behaviour
1563 if ( d->isRightToLeft() ) {
1564 QChar *c = (QChar *)t.unicode();
1565 int l = t.length();
1566 while( l-- ) {
1567 if ( c->mirrored() )
1568 *c = c->mirroredChar();
1569 c++;
1570 }
1571 }
1572 }
1573#endif
1574 insert( t );
1575 return;
1576 }
1577 }
1578 bool unknown = FALSE;
1579 if ( e->state() & ControlButton ) {
1580 switch ( e->key() ) {
1581 case Key_A:
1582#if defined(Q_WS_X11)
1583 home( e->state() & ShiftButton );
1584#else
1585 selectAll();
1586#endif
1587 break;
1588 case Key_B:
1589 cursorForward( e->state() & ShiftButton, -1 );
1590 break;
1591#ifndef QT_NO_CLIPBOARD
1592 case Key_C:
1593 copy();
1594 break;
1595#endif
1596 case Key_D:
1597 if ( !d->readOnly ) {
1598 del();
1599 }
1600 break;
1601 case Key_E:
1602 end( e->state() & ShiftButton );
1603 break;
1604 case Key_F:
1605 cursorForward( e->state() & ShiftButton, 1 );
1606 break;
1607 case Key_H:
1608 if ( !d->readOnly ) {
1609 backspace();
1610 }
1611 break;
1612 case Key_K:
1613 if ( !d->readOnly ) {
1614 int priorState = d->undoState;
1615 d->deselect();
1616 while ( d->cursor < (int) d->text.length() )
1617 d->del();
1618 d->finishChange( priorState );
1619 }
1620 break;
1621#if defined(Q_WS_X11)
1622 case Key_U:
1623 if ( !d->readOnly )
1624 clear();
1625 break;
1626#endif
1627#ifndef QT_NO_CLIPBOARD
1628 case Key_V:
1629 if ( !d->readOnly )
1630 paste();
1631 break;
1632 case Key_X:
1633 if ( !d->readOnly && d->hasSelectedText() && echoMode() == Normal ) {
1634 copy();
1635 del();
1636 }
1637 break;
1638#if defined (Q_WS_WIN)
1639 case Key_Insert:
1640 copy();
1641 break;
1642#endif
1643#endif
1644 case Key_Delete:
1645 if ( !d->readOnly ) {
1646 cursorWordForward( TRUE );
1647 del();
1648 }
1649 break;
1650 case Key_Backspace:
1651 if ( !d->readOnly ) {
1652 cursorWordBackward( TRUE );
1653 del();
1654 }
1655 break;
1656 case Key_Right:
1657 case Key_Left:
1658 if ( d->isRightToLeft() == (e->key() == Key_Right) ) {
1659 if ( echoMode() == Normal )
1660 cursorWordBackward( e->state() & ShiftButton );
1661 else
1662 home( e->state() & ShiftButton );
1663 } else {
1664 if ( echoMode() == Normal )
1665 cursorWordForward( e->state() & ShiftButton );
1666 else
1667 end( e->state() & ShiftButton );
1668 }
1669 break;
1670 case Key_Z:
1671 if ( !d->readOnly ) {
1672 if(e->state() & ShiftButton)
1673 redo();
1674 else
1675 undo();
1676 }
1677 break;
1678 case Key_Y:
1679 if ( !d->readOnly )
1680 redo();
1681 break;
1682 default:
1683 unknown = TRUE;
1684 }
1685 } else { // ### check for *no* modifier
1686 switch ( e->key() ) {
1687 case Key_Shift:
1688 // ### TODO
1689 break;
1690 case Key_Left:
1691 case Key_Right: {
1692 int step = (d->isRightToLeft() == (e->key() == Key_Right)) ? -1 : 1;
1693 cursorForward( e->state() & ShiftButton, step );
1694 }
1695 break;
1696 case Key_Backspace:
1697 if ( !d->readOnly ) {
1698 backspace();
1699 }
1700 break;
1701 case Key_Home:
1702#ifdef Q_WS_MACX
1703 case Key_Up:
1704#endif
1705 home( e->state() & ShiftButton );
1706 break;
1707 case Key_End:
1708#ifdef Q_WS_MACX
1709 case Key_Down:
1710#endif
1711 end( e->state() & ShiftButton );
1712 break;
1713 case Key_Delete:
1714 if ( !d->readOnly ) {
1715#if defined (Q_WS_WIN)
1716 if ( e->state() & ShiftButton ) {
1717 cut();
1718 break;
1719 }
1720#endif
1721 del();
1722 }
1723 break;
1724#if defined (Q_WS_WIN)
1725 case Key_Insert:
1726 if ( !d->readOnly && e->state() & ShiftButton )
1727 paste();
1728 else
1729 unknown = TRUE;
1730 break;
1731#endif
1732 case Key_F14: // Undo key on Sun keyboards
1733 if ( !d->readOnly )
1734 undo();
1735 break;
1736#ifndef QT_NO_CLIPBOARD
1737 case Key_F16: // Copy key on Sun keyboards
1738 copy();
1739 break;
1740 case Key_F18: // Paste key on Sun keyboards
1741 if ( !d->readOnly )
1742 paste();
1743 break;
1744 case Key_F20: // Cut key on Sun keyboards
1745 if ( !d->readOnly && hasSelectedText() && echoMode() == Normal ) {
1746 copy();
1747 del();
1748 }
1749 break;
1750#endif
1751 default:
1752 unknown = TRUE;
1753 }
1754 }
1755 if ( e->key() == Key_Direction_L || e->key() == Key_Direction_R ) {
1756 d->direction = (e->key() == Key_Direction_L) ? QChar::DirL : QChar::DirR;
1757 update();
1758 }
1759
1760 if ( unknown )
1761 e->ignore();
1762}
1763
1764/*! \reimp
1765 */
1766void QLineEdit::imStartEvent( QIMEvent *e )
1767{
1768 if ( d->readOnly ) {
1769 e->ignore();
1770 return;
1771 }
1772 d->removeSelectedText();
1773 d->updateMicroFocusHint();
1774 d->imstart = d->imend = d->imselstart = d->imselend = d->cursor;
1775}
1776
1777/*! \reimp
1778 */
1779void QLineEdit::imComposeEvent( QIMEvent *e )
1780{
1781 if ( d->readOnly ) {
1782 e->ignore();
1783 } else if (!e->text().isEmpty()) {
1784 d->text.replace( d->imstart, d->imend - d->imstart, e->text() );
1785 d->imend = d->imstart + e->text().length();
1786 d->imselstart = d->imstart + e->cursorPos();
1787 d->imselend = d->imselstart + e->selectionLength();
1788 d->cursor = e->selectionLength() ? d->imend : d->imselend;
1789 d->updateTextLayout();
1790 update();
1791 }
1792}
1793
1794/*! \reimp
1795 */
1796void QLineEdit::imEndEvent( QIMEvent *e )
1797{
1798 if ( d->readOnly) {
1799 e->ignore();
1800 } else if (!e->text().isEmpty()) {
1801 d->text.remove( d->imstart, d->imend - d->imstart );
1802 d->cursor = d->imselstart = d->imselend = d->imend = d->imstart;
1803 d->textDirty = TRUE;
1804 insert( e->text() );
1805 }
1806}
1807
1808/*!\reimp
1809*/
1810
1811void QLineEdit::focusInEvent( QFocusEvent* )
1812{
1813 if ( QFocusEvent::reason() == QFocusEvent::Tab ||
1814 QFocusEvent::reason() == QFocusEvent::Backtab ||
1815 QFocusEvent::reason() == QFocusEvent::Shortcut )
1816 d->maskData ? d->moveCursor( d->nextMaskBlank( 0 ) ) : selectAll();
1817 if ( !d->cursorTimer ) {
1818 int cft = QApplication::cursorFlashTime();
1819 d->cursorTimer = cft ? startTimer( cft/2 ) : -1;
1820 }
1821 if( !hasSelectedText() || style().styleHint( QStyle::SH_BlinkCursorWhenTextSelected ) )
1822 d->setCursorVisible( TRUE );
1823 d->updateMicroFocusHint();
1824}
1825
1826/*!\reimp
1827*/
1828
1829void QLineEdit::focusOutEvent( QFocusEvent* )
1830{
1831 if ( QFocusEvent::reason() != QFocusEvent::ActiveWindow &&
1832 QFocusEvent::reason() != QFocusEvent::Popup )
1833 deselect();
1834 d->setCursorVisible( FALSE );
1835 if ( d->cursorTimer > 0 )
1836 killTimer( d->cursorTimer );
1837 d->cursorTimer = 0;
1838 emit lostFocus();
1839}
1840
1841/*!\reimp
1842*/
1843void QLineEdit::drawContents( QPainter *p )
1844{
1845 const QColorGroup& cg = colorGroup();
1846 QRect cr = contentsRect();
1847 QFontMetrics fm = fontMetrics();
1848 QRect lineRect( cr.x() + innerMargin, cr.y() + (cr.height() - fm.height() + 1) / 2,
1849 cr.width() - 2*innerMargin, fm.height() );
1850 QBrush bg = QBrush( paletteBackgroundColor() );
1851 if ( paletteBackgroundPixmap() )
1852 bg = QBrush( cg.background(), *paletteBackgroundPixmap() );
1853 else if ( !isEnabled() )
1854 bg = cg.brush( QColorGroup::Background );
1855 p->save();
1856 p->setClipRegion( QRegion(cr) - lineRect );
1857 p->fillRect( cr, bg );
1858 p->restore();
1859 QSharedDoubleBuffer buffer( p, lineRect.x(), lineRect.y(),
1860 lineRect.width(), lineRect.height(),
1861 hasFocus() ? QSharedDoubleBuffer::Force : 0 );
1862 p = buffer.painter();
1863 p->fillRect( lineRect, bg );
1864
1865 // locate cursor position
1866 int cix = 0;
1867 QTextItem ci = d->textLayout.findItem( d->cursor );
1868 if ( ci.isValid() ) {
1869 if ( d->cursor != (int)d->text.length() && d->cursor == ci.from() + ci.length()
1870 && ci.isRightToLeft() != d->isRightToLeft() )
1871 ci = d->textLayout.findItem( d->cursor + 1 );
1872 cix = ci.x() + ci.cursorToX( d->cursor - ci.from() );
1873 }
1874
1875 // horizontal scrolling
1876 int minLB = QMAX( 0, -fm.minLeftBearing() );
1877 int minRB = QMAX( 0, -fm.minRightBearing() );
1878 int widthUsed = d->textLayout.widthUsed() + 1 + minRB;
1879 if ( (minLB + widthUsed) <= lineRect.width() ) {
1880 switch ( d->visualAlignment() ) {
1881 case AlignRight:
1882 d->hscroll = widthUsed - lineRect.width();
1883 break;
1884 case AlignHCenter:
1885 d->hscroll = ( widthUsed - lineRect.width() ) / 2;
1886 break;
1887 default:
1888 d->hscroll = 0;
1889 break;
1890 }
1891 d->hscroll -= minLB;
1892 } else if ( cix - d->hscroll >= lineRect.width() ) {
1893 d->hscroll = cix - lineRect.width() + 1;
1894 } else if ( cix - d->hscroll < 0 ) {
1895 d->hscroll = cix;
1896 } else if ( widthUsed - d->hscroll < lineRect.width() ) {
1897 d->hscroll = widthUsed - lineRect.width() + 1;
1898 }
1899 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1900 QPoint topLeft = lineRect.topLeft() - QPoint(d->hscroll, d->ascent-fm.ascent());
1901
1902 // draw text, selections and cursors
1903 p->setPen( cg.text() );
1904 bool supressCursor = d->readOnly, hasRightToLeft = d->isRightToLeft();
1905 int textflags = 0;
1906 if ( font().underline() )
1907 textflags |= Qt::Underline;
1908 if ( font().strikeOut() )
1909 textflags |= Qt::StrikeOut;
1910 if ( font().overline() )
1911 textflags |= Qt::Overline;
1912
1913 for ( int i = 0; i < d->textLayout.numItems(); i++ ) {
1914 QTextItem ti = d->textLayout.itemAt( i );
1915 hasRightToLeft |= ti.isRightToLeft();
1916 int tix = topLeft.x() + ti.x();
1917 int first = ti.from();
1918 int last = ti.from() + ti.length() - 1;
1919
1920 // text and selection
1921 if ( d->selstart < d->selend && (last >= d->selstart && first < d->selend ) ) {
1922 QRect highlight = QRect( QPoint( tix + ti.cursorToX( QMAX( d->selstart - first, 0 ) ),
1923 lineRect.top() ),
1924 QPoint( tix + ti.cursorToX( QMIN( d->selend - first, last - first + 1 ) ) - 1,
1925 lineRect.bottom() ) ).normalize();
1926 p->save();
1927 p->setClipRegion( QRegion( lineRect ) - highlight, QPainter::CoordPainter );
1928 p->drawTextItem( topLeft, ti, textflags );
1929 p->setClipRect( lineRect & highlight, QPainter::CoordPainter );
1930 p->fillRect( highlight, cg.highlight() );
1931 p->setPen( cg.highlightedText() );
1932 p->drawTextItem( topLeft, ti, textflags );
1933 p->restore();
1934 } else {
1935 p->drawTextItem( topLeft, ti, textflags );
1936 }
1937
1938 // input method edit area
1939 if ( d->imstart < d->imend && (last >= d->imstart && first < d->imend ) ) {
1940 QRect highlight = QRect( QPoint( tix + ti.cursorToX( QMAX( d->imstart - first, 0 ) ), lineRect.top() ),
1941 QPoint( tix + ti.cursorToX( QMIN( d->imend - first, last - first + 1 ) )-1, lineRect.bottom() ) ).normalize();
1942 p->save();
1943 p->setClipRect( lineRect & highlight, QPainter::CoordPainter );
1944
1945 int h1, s1, v1, h2, s2, v2;
1946 cg.color( QColorGroup::Base ).hsv( &h1, &s1, &v1 );
1947 cg.color( QColorGroup::Background ).hsv( &h2, &s2, &v2 );
1948 QColor imCol;
1949 imCol.setHsv( h1, s1, ( v1 + v2 ) / 2 );
1950 p->fillRect( highlight, imCol );
1951 p->drawTextItem( topLeft, ti, textflags );
1952 p->restore();
1953 }
1954
1955 // input method selection
1956 if ( d->imselstart < d->imselend && (last >= d->imselstart && first < d->imselend ) ) {
1957 QRect highlight = QRect( QPoint( tix + ti.cursorToX( QMAX( d->imselstart - first, 0 ) ), lineRect.top() ),
1958 QPoint( tix + ti.cursorToX( QMIN( d->imselend - first, last - first + 1 ) )-1, lineRect.bottom() ) ).normalize();
1959 p->save();
1960 p->setClipRect( lineRect & highlight, QPainter::CoordPainter );
1961 p->fillRect( highlight, cg.text() );
1962 p->setPen( paletteBackgroundColor() );
1963 p->drawTextItem( topLeft, ti, textflags );
1964 p->restore();
1965 }
1966
1967 // overwrite cursor
1968 if ( d->cursorVisible && d->maskData &&
1969 d->selend <= d->selstart && (last >= d->cursor && first <= d->cursor ) ) {
1970 QRect highlight = QRect( QPoint( tix + ti.cursorToX( QMAX( d->cursor - first, 0 ) ), lineRect.top() ),
1971 QPoint( tix + ti.cursorToX( QMIN( d->cursor + 1 - first, last - first + 1 ) )-1, lineRect.bottom() ) ).normalize();
1972 p->save();
1973 p->setClipRect( lineRect & highlight, QPainter::CoordPainter );
1974 p->fillRect( highlight, cg.text() );
1975 p->setPen( paletteBackgroundColor() );
1976 p->drawTextItem( topLeft, ti, textflags );
1977 p->restore();
1978 supressCursor = TRUE;
1979 }
1980 }
1981
1982 // draw cursor
1983 if ( d->cursorVisible && !supressCursor ) {
1984 QPoint from( topLeft.x() + cix, lineRect.top() );
1985 QPoint to = from + QPoint( 0, lineRect.height() );
1986 p->drawLine( from, to );
1987 if ( hasRightToLeft ) {
1988 bool rtl = ci.isValid() ? ci.isRightToLeft() : TRUE;
1989 to = from + QPoint( (rtl ? -2 : 2), 2 );
1990 p->drawLine( from, to );
1991 from.ry() += 4;
1992 p->drawLine( from, to );
1993 }
1994 }
1995 buffer.end();
1996}
1997
1998
1999#ifndef QT_NO_DRAGANDDROP
2000/*!\reimp
2001*/
2002void QLineEdit::dragMoveEvent( QDragMoveEvent *e )
2003{
2004 if ( !d->readOnly && QTextDrag::canDecode(e) ) {
2005 e->acceptAction();
2006 d->cursor = d->xToPos( e->pos().x() );
2007 d->cursorVisible = TRUE;
2008 update();
2009 }
2010}
2011
2012/*!\reimp */
2013void QLineEdit::dragEnterEvent( QDragEnterEvent * e )
2014{
2015 QLineEdit::dragMoveEvent( e );
2016}
2017
2018/*!\reimp */
2019void QLineEdit::dragLeaveEvent( QDragLeaveEvent *)
2020{
2021 if ( d->cursorVisible ) {
2022 d->cursorVisible = FALSE;
2023 update();
2024 }
2025}
2026
2027/*!\reimp */
2028void QLineEdit::dropEvent( QDropEvent* e )
2029{
2030 QString str;
2031 // try text/plain
2032 QCString plain = "plain";
2033 bool decoded = QTextDrag::decode(e, str, plain);
2034 // otherwise we'll accept any kind of text (like text/uri-list)
2035 if (! decoded)
2036 decoded = QTextDrag::decode(e, str);
2037
2038 if ( decoded && !d->readOnly ) {
2039 if ( e->source() == this && e->action() == QDropEvent::Copy )
2040 deselect();
2041 d->cursor =d->xToPos( e->pos().x() );
2042 int selStart = d->cursor;
2043 int oldSelStart = d->selstart;
2044 int oldSelEnd = d->selend;
2045 d->cursorVisible = FALSE;
2046 e->acceptAction();
2047 insert( str );
2048 if ( e->source() == this ) {
2049 if ( e->action() == QDropEvent::Move ) {
2050 if ( selStart > oldSelStart && selStart <= oldSelEnd )
2051 setSelection( oldSelStart, str.length() );
2052 else if ( selStart > oldSelEnd )
2053 setSelection( selStart - str.length(), str.length() );
2054 else
2055 setSelection( selStart, str.length() );
2056 } else {
2057 setSelection( selStart, str.length() );
2058 }
2059 }
2060 } else {
2061 e->ignore();
2062 update();
2063 }
2064}
2065
2066void QLineEditPrivate::drag()
2067{
2068 q->killTimer( dndTimer );
2069 dndTimer = 0;
2070 QTextDrag *tdo = new QTextDrag( q->selectedText(), q );
2071 // ### fix the check QDragObject::target() != q in Qt4 (should not be needed)
2072 if ( tdo->drag() && !readOnly && QDragObject::target() != q ) {
2073 int priorState = undoState;
2074 removeSelectedText();
2075 finishChange( priorState );
2076 }
2077#ifndef QT_NO_CURSOR
2078 q->setCursor( readOnly ? arrowCursor : ibeamCursor );
2079#endif
2080}
2081
2082#endif // QT_NO_DRAGANDDROP
2083
2084enum { IdUndo, IdRedo, IdSep1, IdCut, IdCopy, IdPaste, IdClear, IdSep2, IdSelectAll };
2085
2086/*!\reimp
2087*/
2088void QLineEdit::contextMenuEvent( QContextMenuEvent * e )
2089{
2090#ifndef QT_NO_POPUPMENU
2091 d->separate();
2092
2093 QGuardedPtr<QPopupMenu> popup = createPopupMenu();
2094 QGuardedPtr<QLineEdit> that = this;
2095 QPoint pos = e->reason() == QContextMenuEvent::Mouse ? e->globalPos() :
2096 mapToGlobal( QPoint(e->pos().x(), 0) ) + QPoint( width() / 2, height() / 2 );
2097 int r = popup->exec( pos );
2098 delete (QPopupMenu*)popup;
2099 if ( that && d->menuId ) {
2100 switch ( d->menuId - r ) {
2101 case IdClear: clear(); break;
2102 case IdSelectAll: selectAll(); break;
2103 case IdUndo: undo(); break;
2104 case IdRedo: redo(); break;
2105#ifndef QT_NO_CLIPBOARD
2106 case IdCut: cut(); break;
2107 case IdCopy: copy(); break;
2108 case IdPaste: paste(); break;
2109#endif
2110 default:
2111 ; // nothing selected or lineedit destroyed. Be careful.
2112 }
2113 }
2114#endif //QT_NO_POPUPMENU
2115}
2116
2117/*!
2118 This function is called to create the popup menu which is shown
2119 when the user clicks on the line edit with the right mouse button.
2120 If you want to create a custom popup menu, reimplement this
2121 function and return the popup menu you create. The popup menu's
2122 ownership is transferred to the caller.
2123*/
2124
2125QPopupMenu *QLineEdit::createPopupMenu()
2126{
2127#ifndef QT_NO_POPUPMENU
2128 QPopupMenu *popup = new QPopupMenu( this, "qt_edit_menu" );
2129 int id = d->menuId = popup->insertItem( tr( "&Undo" ) + ACCEL_KEY( Z ) );
2130 popup->insertItem( tr( "&Redo" ) + ACCEL_KEY( Y ) );
2131 popup->insertSeparator();
2132 popup->insertItem( tr( "Cu&t" ) + ACCEL_KEY( X ) );
2133 popup->insertItem( tr( "&Copy" ) + ACCEL_KEY( C ) );
2134 popup->insertItem( tr( "&Paste" ) + ACCEL_KEY( V ) );
2135 popup->insertItem( tr( "Clear" ) );
2136 popup->insertSeparator();
2137 popup->insertItem( tr( "Select All" )
2138#ifndef Q_WS_X11
2139 + ACCEL_KEY( A )
2140#endif
2141 );
2142 popup->setItemEnabled( id - IdUndo, d->isUndoAvailable() );
2143 popup->setItemEnabled( id - IdRedo, d->isRedoAvailable() );
2144#ifndef QT_NO_CLIPBOARD
2145 popup->setItemEnabled( id - IdCut, !d->readOnly && d->hasSelectedText() );
2146 popup->setItemEnabled( id - IdCopy, d->hasSelectedText() );
2147 popup->setItemEnabled( id - IdPaste, !d->readOnly && !QApplication::clipboard()->text().isEmpty() );
2148#else
2149 popup->setItemVisible( id - IdCut, FALSE );
2150 popup->setItemVisible( id - IdCopy, FALSE );
2151 popup->setItemVisible( id - IdPaste, FALSE );
2152#endif
2153 popup->setItemEnabled( id - IdClear, !d->readOnly && !d->text.isEmpty() );
2154 popup->setItemEnabled( id - IdSelectAll, !d->text.isEmpty() && !d->allSelected() );
2155 return popup;
2156#else
2157 return 0;
2158#endif
2159}
2160
2161/*! \reimp */
2162void QLineEdit::windowActivationChange( bool b )
2163{
2164 //### remove me with WHighlightSelection attribute
2165 if ( palette().active() != palette().inactive() )
2166 update();
2167 QWidget::windowActivationChange( b );
2168}
2169
2170/*! \reimp */
2171
2172void QLineEdit::setPalette( const QPalette & p )
2173{
2174 //### remove me with WHighlightSelection attribute
2175 QWidget::setPalette( p );
2176 update();
2177}
2178
2179/*!
2180 \obsolete
2181 \fn void QLineEdit::repaintArea( int from, int to )
2182 Repaints all characters from \a from to \a to. If cursorPos is
2183 between from and to, ensures that cursorPos is visible.
2184*/
2185
2186/*! \reimp
2187 */
2188void QLineEdit::setFont( const QFont & f )
2189{
2190 QWidget::setFont( f );
2191 d->updateTextLayout();
2192}
2193
2194/*! \obsolete
2195*/
2196int QLineEdit::characterAt( int xpos, QChar *chr ) const
2197{
2198 int pos = d->xToPos( xpos + contentsRect().x() - d->hscroll + innerMargin );
2199 if ( chr && pos < (int) d->text.length() )
2200 *chr = d->text.at( pos );
2201 return pos;
2202}
2203
2204/*!
2205 \internal
2206
2207 Sets the password character to \a c.
2208
2209 \sa passwordChar()
2210*/
2211
2212void QLineEdit::setPasswordChar( QChar c )
2213{
2214 d->passwordChar = c;
2215}
2216
2217/*!
2218 \internal
2219
2220 Returns the password character.
2221
2222 \sa setPasswordChar()
2223*/
2224QChar QLineEdit::passwordChar() const
2225{
2226 return ( d->passwordChar.isNull() ? QChar( style().styleHint( QStyle::SH_LineEdit_PasswordCharacter, this ) ) : d->passwordChar );
2227}
2228
2229void QLineEdit::clipboardChanged()
2230{
2231}
2232
2233void QLineEditPrivate::init( const QString& txt )
2234{
2235#ifndef QT_NO_CURSOR
2236 q->setCursor( readOnly ? arrowCursor : ibeamCursor );
2237#endif
2238 q->setFocusPolicy( QWidget::StrongFocus );
2239 q->setInputMethodEnabled( TRUE );
2240 // Specifies that this widget can use more, but is able to survive on
2241 // less, horizontal space; and is fixed vertically.
2242 q->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
2243 q->setBackgroundMode( PaletteBase );
2244 q->setKeyCompression( TRUE );
2245 q->setMouseTracking( TRUE );
2246 q->setAcceptDrops( TRUE );
2247 q->setFrame( TRUE );
2248 text = txt;
2249 updateTextLayout();
2250 cursor = text.length();
2251}
2252
2253void QLineEditPrivate::updateTextLayout()
2254{
2255 // replace all non-printable characters with spaces (to avoid
2256 // drawing boxes when using fonts that don't have glyphs for such
2257 // characters)
2258 const QString &displayText = q->displayText();
2259 QString str(displayText.unicode(), displayText.length());
2260 QChar* uc = (QChar*)str.unicode();
2261 for (int i = 0; i < (int)str.length(); ++i) {
2262 if (! uc[i].isPrint())
2263 uc[i] = QChar(0x0020);
2264 }
2265 textLayout.setText( str, q->font() );
2266 // ### want to do textLayout.setRightToLeft( text.isRightToLeft() );
2267 textLayout.beginLayout(QTextLayout::SingleLine);
2268 textLayout.beginLine( INT_MAX );
2269 while ( !textLayout.atEnd() )
2270 textLayout.addCurrentItem();
2271 ascent = 0;
2272 textLayout.endLine(0, 0, Qt::AlignLeft, &ascent);
2273}
2274
2275int QLineEditPrivate::xToPos( int x, QTextItem::CursorPosition betweenOrOn ) const
2276{
2277 x-= q->contentsRect().x() - hscroll + innerMargin;
2278 for ( int i = 0; i < textLayout.numItems(); ++i ) {
2279 QTextItem ti = textLayout.itemAt( i );
2280 QRect tir = ti.rect();
2281 if ( x >= tir.left() && x <= tir.right() )
2282 return ti.xToCursor( x - tir.x(), betweenOrOn ) + ti.from();
2283 }
2284 return x < 0 ? 0 : text.length();
2285}
2286
2287
2288QRect QLineEditPrivate::cursorRect() const
2289{
2290 QRect cr = q->contentsRect();
2291 int cix = cr.x() - hscroll + innerMargin;
2292 QTextItem ci = textLayout.findItem( cursor );
2293 if ( ci.isValid() ) {
2294 if ( cursor != (int)text.length() && cursor == ci.from() + ci.length()
2295 && ci.isRightToLeft() != isRightToLeft() )
2296 ci = textLayout.findItem( cursor + 1 );
2297 cix += ci.x() + ci.cursorToX( cursor - ci.from() );
2298 }
2299 int ch = q->fontMetrics().height();
2300 return QRect( cix-4, cr.y() + ( cr.height() - ch + 1) / 2, 8, ch + 1 );
2301}
2302
2303void QLineEditPrivate::updateMicroFocusHint()
2304{
2305 if ( q->hasFocus() ) {
2306 QRect r = cursorRect();
2307 q->setMicroFocusHint( r.x(), r.y(), r.width(), r.height() );
2308 }
2309}
2310
2311void QLineEditPrivate::moveCursor( int pos, bool mark )
2312{
2313 if ( pos != cursor )
2314 separate();
2315 if ( maskData && pos > cursor )
2316 pos = nextMaskBlank( pos );
2317 else if ( maskData && pos < cursor )
2318 pos = prevMaskBlank( pos );
2319 bool fullUpdate = mark || hasSelectedText();
2320 if ( mark ) {
2321 int anchor;
2322 if ( selend > selstart && cursor == selstart )
2323 anchor = selend;
2324 else if ( selend > selstart && cursor == selend )
2325 anchor = selstart;
2326 else
2327 anchor = cursor;
2328 selstart = QMIN( anchor, pos );
2329 selend = QMAX( anchor, pos );
2330 } else {
2331 deselect();
2332 }
2333 if ( fullUpdate ) {
2334 cursor = pos;
2335 q->update();
2336 } else {
2337 setCursorVisible( FALSE );
2338 cursor = pos;
2339 setCursorVisible( TRUE );
2340 }
2341 updateMicroFocusHint();
2342 if ( mark && !q->style().styleHint( QStyle::SH_BlinkCursorWhenTextSelected ) )
2343 setCursorVisible( FALSE );
2344 if ( mark || selDirty ) {
2345 selDirty = FALSE;
2346 emit q->selectionChanged();
2347 }
2348}
2349
2350void QLineEditPrivate::finishChange( int validateFromState, bool setModified )
2351{
2352 bool lineDirty = selDirty;
2353 if ( textDirty ) {
2354 // do validation
2355 bool wasValidInput = validInput;
2356 validInput = TRUE;
2357#ifndef QT_NO_VALIDATOR
2358 if ( validator && validateFromState >= 0 ) {
2359 QString textCopy = text;
2360 int cursorCopy = cursor;
2361 validInput = ( validator->validate( textCopy, cursorCopy ) != QValidator::Invalid );
2362 if ( validInput ) {
2363 if ( text != textCopy ) {
2364 q->setText( textCopy );
2365 cursor = cursorCopy;
2366 return;
2367 }
2368 cursor = cursorCopy;
2369 }
2370 }
2371#endif
2372 if ( validateFromState >= 0 && wasValidInput && !validInput ) {
2373 undo( validateFromState );
2374 history.resize( undoState );
2375 validInput = TRUE;
2376 textDirty = setModified = FALSE;
2377 }
2378 updateTextLayout();
2379 updateMicroFocusHint();
2380 lineDirty |= textDirty;
2381 if ( setModified )
2382 modified = TRUE;
2383 if ( textDirty ) {
2384 textDirty = FALSE;
2385 emit q->textChanged( maskData ? stripString(text) : text );
2386 }
2387#if defined(QT_ACCESSIBILITY_SUPPORT)
2388 QAccessible::updateAccessibility( q, 0, QAccessible::ValueChanged );
2389#endif
2390 }
2391 if ( selDirty ) {
2392 selDirty = FALSE;
2393 emit q->selectionChanged();
2394 }
2395 if ( lineDirty || !setModified )
2396 q->update();
2397}
2398
2399void QLineEditPrivate::setText( const QString& txt )
2400{
2401 deselect();
2402 QString oldText = text;
2403 if ( maskData ) {
2404 text = maskString( 0, txt, TRUE );
2405 text += clearString( text.length(), maxLength - text.length() );
2406 } else {
2407 text = txt.isEmpty() ? txt : txt.left( maxLength );
2408 }
2409 history.clear();
2410 undoState = 0;
2411 cursor = text.length();
2412 textDirty = ( oldText != text );
2413}
2414
2415
2416void QLineEditPrivate::setCursorVisible( bool visible )
2417{
2418 if ( (bool)cursorVisible == visible )
2419 return;
2420 if ( cursorTimer )
2421 cursorVisible = visible;
2422 QRect r = cursorRect();
2423 if ( maskData || !q->contentsRect().contains( r ) )
2424 q->update();
2425 else
2426 q->update( r );
2427}
2428
2429void QLineEditPrivate::addCommand( const Command& cmd )
2430{
2431 if ( separator && undoState && history[undoState-1].type != Separator ) {
2432 history.resize( undoState + 2 );
2433 history[undoState++] = Command( Separator, 0, 0 );
2434 } else {
2435 history.resize( undoState + 1);
2436 }
2437 separator = FALSE;
2438 history[ undoState++ ] = cmd;
2439}
2440
2441void QLineEditPrivate::insert( const QString& s )
2442{
2443 if ( maskData ) {
2444 QString ms = maskString( cursor, s );
2445 for ( int i = 0; i < (int) ms.length(); ++i ) {
2446 addCommand ( Command( DeleteSelection, cursor+i, text.at(cursor+i) ) );
2447 addCommand( Command( Insert, cursor+i, ms.at(i) ) );
2448 }
2449 text.replace( cursor, ms.length(), ms );
2450 cursor += ms.length();
2451 cursor = nextMaskBlank( cursor );
2452 } else {
2453 int remaining = maxLength - text.length();
2454 text.insert( cursor, s.left(remaining) );
2455 for ( int i = 0; i < (int) s.left(remaining).length(); ++i )
2456 addCommand( Command( Insert, cursor++, s.at(i) ) );
2457 }
2458 textDirty = TRUE;
2459}
2460
2461void QLineEditPrivate::del( bool wasBackspace )
2462{
2463 if ( cursor < (int) text.length() ) {
2464 addCommand ( Command( (CommandType)((maskData?2:0)+(wasBackspace?Remove:Delete)), cursor, text.at(cursor) ) );
2465 if ( maskData ) {
2466 text.replace( cursor, 1, clearString( cursor, 1 ) );
2467 addCommand( Command( Insert, cursor, text.at( cursor ) ) );
2468 } else {
2469 text.remove( cursor, 1 );
2470 }
2471 textDirty = TRUE;
2472 }
2473}
2474
2475void QLineEditPrivate::removeSelectedText()
2476{
2477 if ( selstart < selend && selend <= (int) text.length() ) {
2478 separate();
2479 int i ;
2480 if ( selstart <= cursor && cursor < selend ) {
2481 // cursor is within the selection. Split up the commands
2482 // to be able to restore the correct cursor position
2483 for ( i = cursor; i >= selstart; --i )
2484 addCommand ( Command( DeleteSelection, i, text.at(i) ) );
2485 for ( i = selend - 1; i > cursor; --i )
2486 addCommand ( Command( DeleteSelection, i - cursor + selstart - 1, text.at(i) ) );
2487 } else {
2488 for ( i = selend-1; i >= selstart; --i )
2489 addCommand ( Command( RemoveSelection, i, text.at(i) ) );
2490 }
2491 if ( maskData ) {
2492 text.replace( selstart, selend - selstart, clearString( selstart, selend - selstart ) );
2493 for ( int i = 0; i < selend - selstart; ++i )
2494 addCommand( Command( Insert, selstart + i, text.at( selstart + i ) ) );
2495 } else {
2496 text.remove( selstart, selend - selstart );
2497 }
2498 if ( cursor > selstart )
2499 cursor -= QMIN( cursor, selend ) - selstart;
2500 deselect();
2501 textDirty = TRUE;
2502 }
2503}
2504
2505void QLineEditPrivate::parseInputMask( const QString &maskFields )
2506{
2507 if ( maskFields.isEmpty() || maskFields.section( ';', 0, 0 ).isEmpty() ) {
2508 if ( maskData ) {
2509 delete [] maskData;
2510 maskData = 0;
2511 maxLength = 32767;
2512 q->setText( QString::null );
2513 }
2514 return;
2515 }
2516
2517 inputMask = maskFields.section( ';', 0, 0 );
2518 blank = maskFields.section( ';', 1, 1 ).at(0);
2519 if ( blank.isNull() )
2520 blank = ' ';
2521
2522 // calculate maxLength / maskData length
2523 maxLength = 0;
2524 QChar c = 0;
2525 uint i;
2526 for ( i=0; i<inputMask.length(); i++ ) {
2527 c = inputMask.at(i);
2528 if ( i > 0 && inputMask.at( i-1 ) == '\\' ) {
2529 maxLength++;
2530 continue;
2531 }
2532 if ( c != '\\' && c != '!' &&
2533 c != '<' && c != '>' &&
2534 c != '{' && c != '}' &&
2535 c != '[' && c != ']' )
2536 maxLength++;
2537 }
2538
2539 delete [] maskData;
2540 maskData = new MaskInputData[ maxLength ];
2541
2542 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
2543 c = 0;
2544 bool s;
2545 bool escape = FALSE;
2546 int index = 0;
2547 for ( i = 0; i < inputMask.length(); i++ ) {
2548 c = inputMask.at(i);
2549 if ( escape ) {
2550 s = TRUE;
2551 maskData[ index ].maskChar = c;
2552 maskData[ index ].separator = s;
2553 maskData[ index ].caseMode = m;
2554 index++;
2555 escape = FALSE;
2556 } else if ( c == '<' || c == '>' || c == '!') {
2557 switch ( c ) {
2558 case '<':
2559 m = MaskInputData::Lower;
2560 break;
2561 case '>':
2562 m = MaskInputData::Upper;
2563 break;
2564 case '!':
2565 m = MaskInputData::NoCaseMode;
2566 break;
2567 }
2568 } else if ( c != '{' && c != '}' && c != '[' && c != ']' ) {
2569 switch ( c ) {
2570 case 'A':
2571 case 'a':
2572 case 'N':
2573 case 'n':
2574 case 'X':
2575 case 'x':
2576 case '9':
2577 case '0':
2578 case 'D':
2579 case 'd':
2580 case '#':
2581 s = FALSE;
2582 break;
2583 case '\\':
2584 escape = TRUE;
2585 default:
2586 s = TRUE;
2587 break;
2588 }
2589
2590 if ( !escape ) {
2591 maskData[ index ].maskChar = c;
2592 maskData[ index ].separator = s;
2593 maskData[ index ].caseMode = m;
2594 index++;
2595 }
2596 }
2597 }
2598 q->setText( QString::null );
2599}
2600
2601
2602/* checks if the key is valid compared to the inputMask */
2603bool QLineEditPrivate::isValidInput( QChar key, QChar mask ) const
2604{
2605 switch ( mask ) {
2606 case 'A':
2607 if ( key.isLetter() && key != blank )
2608 return TRUE;
2609 break;
2610 case 'a':
2611 if ( key.isLetter() || key == blank )
2612 return TRUE;
2613 break;
2614 case 'N':
2615 if ( key.isLetterOrNumber() && key != blank )
2616 return TRUE;
2617 break;
2618 case 'n':
2619 if ( key.isLetterOrNumber() || key == blank )
2620 return TRUE;
2621 break;
2622 case 'X':
2623 if ( key.isPrint() && key != blank )
2624 return TRUE;
2625 break;
2626 case 'x':
2627 if ( key.isPrint() || key == blank )
2628 return TRUE;
2629 break;
2630 case '9':
2631 if ( key.isNumber() && key != blank )
2632 return TRUE;
2633 break;
2634 case '0':
2635 if ( key.isNumber() || key == blank )
2636 return TRUE;
2637 break;
2638 case 'D':
2639 if ( key.isNumber() && key.digitValue() > 0 && key != blank )
2640 return TRUE;
2641 break;
2642 case 'd':
2643 if ( (key.isNumber() && key.digitValue() > 0) || key == blank )
2644 return TRUE;
2645 break;
2646 case '#':
2647 if ( key.isNumber() || key == '+' || key == '-' || key == blank )
2648 return TRUE;
2649 break;
2650 default:
2651 break;
2652 }
2653 return FALSE;
2654}
2655
2656/*
2657 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
2658 specifies from where characters should be gotten when a separator is met in \a str - TRUE means
2659 that blanks will be used, FALSE that previous input is used.
2660 Calling this when no inputMask is set is undefined.
2661*/
2662QString QLineEditPrivate::maskString( uint pos, const QString &str, bool clear) const
2663{
2664 if ( pos >= (uint)maxLength )
2665 return QString::fromLatin1("");
2666
2667 QString fill;
2668 fill = clear ? clearString( 0, maxLength ) : text;
2669
2670 uint strIndex = 0;
2671 QString s = QString::fromLatin1("");
2672 int i = pos;
2673 while ( i < maxLength ) {
2674 if ( strIndex < str.length() ) {
2675 if ( maskData[ i ].separator ) {
2676 s += maskData[ i ].maskChar;
2677 if ( str[(int)strIndex] == maskData[ i ].maskChar )
2678 strIndex++;
2679 ++i;
2680 } else {
2681 if ( isValidInput( str[(int)strIndex], maskData[ i ].maskChar ) ) {
2682 switch ( maskData[ i ].caseMode ) {
2683 case MaskInputData::Upper:
2684 s += str[(int)strIndex].upper();
2685 break;
2686 case MaskInputData::Lower:
2687 s += str[(int)strIndex].lower();
2688 break;
2689 default:
2690 s += str[(int)strIndex];
2691 }
2692 ++i;
2693 } else {
2694 // search for separator first
2695 int n = findInMask( i, TRUE, TRUE, str[(int)strIndex] );
2696 if ( n != -1 ) {
2697 if ( str.length() != 1 || i == 0 || (i > 0 && (!maskData[i-1].separator || maskData[i-1].maskChar != str[(int)strIndex])) ) {
2698 s += fill.mid( i, n-i+1 );
2699 i = n + 1; // update i to find + 1
2700 }
2701 } else {
2702 // search for valid blank if not
2703 n = findInMask( i, TRUE, FALSE, str[(int)strIndex] );
2704 if ( n != -1 ) {
2705 s += fill.mid( i, n-i );
2706 switch ( maskData[ n ].caseMode ) {
2707 case MaskInputData::Upper:
2708 s += str[(int)strIndex].upper();
2709 break;
2710 case MaskInputData::Lower:
2711 s += str[(int)strIndex].lower();
2712 break;
2713 default:
2714 s += str[(int)strIndex];
2715 }
2716 i = n + 1; // updates i to find + 1
2717 }
2718 }
2719 }
2720 strIndex++;
2721 }
2722 } else
2723 break;
2724 }
2725
2726 return s;
2727}
2728
2729
2730
2731/*
2732 Returns a "cleared" string with only separators and blank chars.
2733 Calling this when no inputMask is set is undefined.
2734*/
2735QString QLineEditPrivate::clearString( uint pos, uint len ) const
2736{
2737 if ( pos >= (uint)maxLength )
2738 return QString::null;
2739
2740 QString s;
2741 int end = QMIN( (uint)maxLength, pos + len );
2742 for ( int i=pos; i<end; i++ )
2743 if ( maskData[ i ].separator )
2744 s += maskData[ i ].maskChar;
2745 else
2746 s += blank;
2747
2748 return s;
2749}
2750
2751/*
2752 Strips blank parts of the input in a QLineEdit when an inputMask is set,
2753 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
2754*/
2755QString QLineEditPrivate::stripString( const QString &str ) const
2756{
2757 if ( !maskData )
2758 return str;
2759
2760 QString s;
2761 int end = QMIN( maxLength, (int)str.length() );
2762 for (int i=0; i < end; i++ )
2763 if ( maskData[ i ].separator )
2764 s += maskData[ i ].maskChar;
2765 else
2766 if ( str[i] != blank )
2767 s += str[i];
2768
2769 return s;
2770}
2771
2772/* searches forward/backward in maskData for either a separator or a blank */
2773int QLineEditPrivate::findInMask( int pos, bool forward, bool findSeparator, QChar searchChar ) const
2774{
2775 if ( pos >= maxLength || pos < 0 )
2776 return -1;
2777
2778 int end = forward ? maxLength : -1;
2779 int step = forward ? 1 : -1;
2780 int i = pos;
2781
2782 while ( i != end ) {
2783 if ( findSeparator ) {
2784 if ( maskData[ i ].separator && maskData[ i ].maskChar == searchChar )
2785 return i;
2786 } else {
2787 if ( !maskData[ i ].separator ) {
2788 if ( searchChar.isNull() )
2789 return i;
2790 else if ( isValidInput( searchChar, maskData[ i ].maskChar ) )
2791 return i;
2792 }
2793 }
2794 i += step;
2795 }
2796 return -1;
2797}
2798
2799
2800#endif // QT_NO_LINEEDIT
Note: See TracBrowser for help on using the repository browser.