1 /* secqlineedit.cpp - Secure version of TQLineEdit.
2  * Copyright (C) 1992-2002 Trolltech AS.  All rights reserved.
3  * Copyright (C) 2003 g10 Code GmbH
4  *
5  * The license of the original qlineedit.cpp file from which this file
6  * is derived can be found below.  Modified by Marcus Brinkmann
7  * <marcus@g10code.de>.  All modifications are licensed as follows, so
8  * that the intersection of the two licenses is then the GNU General
9  * Public License version 2.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation; either version 2 of the
14  * License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, see <https://www.gnu.org/licenses/>.
23  * SPDX-License-Identifier: GPL-2.0
24  */
25 
26 
27 /* Undo/Redo is disabled, because it uses unsecure memory for the
28    history buffer.  */
29 #define SECURE_NO_UNDO	1
30 
31 
32 /**********************************************************************
33 ** $Id$
34 **
35 ** Implementation of SecTQLineEdit widget class
36 **
37 ** Created : 941011
38 **
39 ** Copyright (C) 1992-2002 Trolltech AS.  All rights reserved.
40 **
41 ** This file is part of the widgets module of the TQt GUI Toolkit.
42 **
43 ** This file may be distributed under the terms of the Q Public License
44 ** as defined by Trolltech AS of Norway and appearing in the file
45 ** LICENSE.TQPL included in the packaging of this file.
46 **
47 ** This file may be distributed and/or modified under the terms of the
48 ** GNU General Public License version 2 as published by the Free Software
49 ** Foundation and appearing in the file LICENSE.GPL included in the
50 ** packaging of this file.
51 **
52 ** Licensees holding valid TQt Enterprise Edition or TQt Professional Edition
53 ** licenses may use this file in accordance with the TQt Commercial License
54 ** Agreement provided with the Software.
55 **
56 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
57 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
58 **
59 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
60 **   information about TQt Commercial License Agreements.
61 ** See http://www.trolltech.com/qpl/ for TQPL licensing information.
62 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
63 **
64 ** Contact info@trolltech.com if any conditions of this licensing are
65 ** not clear to you.
66 **
67 **********************************************************************/
68 
69 #include "secqlineedit.h"
70 #include "ntqpainter.h"
71 #include "ntqdrawutil.h"
72 #include "ntqfontmetrics.h"
73 #include "ntqpixmap.h"
74 #include "ntqclipboard.h"
75 #include "ntqapplication.h"
76 #include "ntqtimer.h"
77 #include "ntqpopupmenu.h"
78 #include "ntqstringlist.h"
79 #include "ntqguardedptr.h"
80 #include "ntqstyle.h"
81 #include "ntqwhatsthis.h"
82 #include "secqinternal_p.h"
83 #include "private/qtextlayout_p.h"
84 #include "ntqvaluevector.h"
85 #if defined(QT_ACCESSIBILITY_SUPPORT)
86 #include "ntqaccessible.h"
87 #endif
88 
89 #ifndef QT_NO_ACCEL
90 #include "ntqkeysequence.h"
91 #define ACCEL_KEY(k) "\t" + TQString(TQKeySequence( TQt::CTRL | TQt::Key_ ## k ))
92 #else
93 #define ACCEL_KEY(k) "\t" + TQString("Ctrl+" #k)
94 #endif
95 
96 #define innerMargin 1
97 
98 struct SecTQLineEditPrivate : public TQt
99 {
100     SecTQLineEditPrivate( SecTQLineEdit *q )
101 	: q(q), cursor(0), cursorTimer(0), tripleClickTimer(0), frame(1),
102 	  cursorVisible(0), separator(0), readOnly(0), modified(0),
103 	  direction(TQChar::DirON), alignment(0),
104 	  echoMode(0), textDirty(0), selDirty(0),
105 	  ascent(0), maxLength(32767), menuId(0),
106 	  hscroll(0),
107 	  undoState(0), selstart(0), selend(0),
108 	  imstart(0), imend(0), imselstart(0), imselend(0)
109 	{}
110     void init( const SecTQString&);
111 
112     SecTQLineEdit *q;
113     SecTQString text;
114     int cursor;
115     int cursorTimer;
116     TQPoint tripleClick;
117     int tripleClickTimer;
118     uint frame : 1;
119     uint cursorVisible : 1;
120     uint separator : 1;
121     uint readOnly : 1;
122     uint modified : 1;
123     uint direction : 5;
124     uint alignment : 3;
125     uint echoMode : 2;
126     uint textDirty : 1;
127     uint selDirty : 1;
128     int ascent;
129     int maxLength;
130     int menuId;
131     int hscroll;
132 
133     void finishChange( int validateFromState = -1, bool setModified = TRUE );
134 
135     void setCursorVisible( bool visible );
136 
137 
138     // undo/redo handling
139     enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection };
140     struct Command {
141 	inline Command(){}
142 	inline Command( CommandType type, int pos, TQChar c )
143 	    :type(type),c(c),pos(pos){}
144 	uint type : 4;
145 	TQChar c;
146 	int pos;
147     };
148     int undoState;
149     TQValueVector<Command> history;
150 #ifndef SECURE_NO_UNDO
151     void addCommand( const Command& cmd );
152 #endif /* SECURE_NO_UNDO */
153 
154     void insert( const SecTQString& s );
155     void del( bool wasBackspace = FALSE );
156     void remove( int pos );
157 
158     inline void separate() { separator = TRUE; }
159 #ifndef SECURE_NO_UNDO
160     inline void undo( int until = -1 ) {
161 	if ( !isUndoAvailable() )
162 	    return;
163 	deselect();
164 	while ( undoState && undoState > until ) {
165 	    Command& cmd = history[--undoState];
166 	    switch ( cmd.type ) {
167 	    case Insert:
168 		text.remove( cmd.pos, 1);
169 		cursor = cmd.pos;
170 		break;
171 	    case Remove:
172 	    case RemoveSelection:
173 		text.insert( cmd.pos, cmd.c );
174 		cursor = cmd.pos + 1;
175 		break;
176 	    case Delete:
177 	    case DeleteSelection:
178 		text.insert( cmd.pos, cmd.c );
179 		cursor = cmd.pos;
180 		break;
181 	    case Separator:
182 		continue;
183 	    }
184 	    if ( until < 0 && undoState ) {
185 		Command& next = history[undoState-1];
186 		if ( next.type != cmd.type && next.type < RemoveSelection
187 		     && !( cmd.type >= RemoveSelection && next.type != Separator ) )
188 		    break;
189 	    }
190 	}
191 	modified = ( undoState != 0 );
192 	textDirty = TRUE;
193     }
194     inline void redo() {
195 	if ( !isRedoAvailable() )
196 	    return;
197 	deselect();
198 	while ( undoState < (int)history.size() ) {
199 	    Command& cmd = history[undoState++];
200 	    switch ( cmd.type ) {
201 	    case Insert:
202 		text.insert( cmd.pos, cmd.c );
203 		cursor = cmd.pos + 1;
204 		break;
205 	    case Remove:
206 	    case Delete:
207 	    case RemoveSelection:
208 	    case DeleteSelection:
209 		text.remove( cmd.pos, 1 );
210 		cursor = cmd.pos;
211 		break;
212 	    case Separator:
213 		continue;
214 	    }
215 	    if ( undoState < (int)history.size() ) {
216 		Command& next = history[undoState];
217 		if ( next.type != cmd.type && cmd.type < RemoveSelection
218 		     && !( next.type >= RemoveSelection && cmd.type != Separator ) )
219 		    break;
220 	    }
221 	}
222 	textDirty = TRUE;
223     }
224 #endif  /* SECURE_NO_UNDO */
225     inline bool isUndoAvailable() const { return !readOnly && undoState; }
226     inline bool isRedoAvailable() const { return !readOnly && undoState < (int)history.size(); }
227 
228 
229     // bidi
230     inline bool isRightToLeft() const { return direction==TQChar::DirON?text.isRightToLeft():(direction==TQChar::DirR); }
231 
232     // selection
233     int selstart, selend;
234     inline bool allSelected() const { return !text.isEmpty() && selstart == 0 && selend == (int)text.length(); }
235     inline bool hasSelectedText() const { return !text.isEmpty() && selend > selstart; }
236     inline void deselect() { selDirty |= (selend > selstart); selstart = selend = 0; }
237     void removeSelectedText();
238 #ifndef QT_NO_CLIPBOARD
239     void copy( bool clipboard = TRUE ) const;
240 #endif
241     inline bool inSelection( int x ) const
242     { if ( selstart >= selend ) return FALSE;
243     int pos = xToPos( x, TQTextItem::OnCharacters );  return pos >= selstart && pos < selend; }
244 
245     // input methods
246     int imstart, imend, imselstart, imselend;
247 
248     // complex text layout
249     TQTextLayout textLayout;
250     void updateTextLayout();
251     void moveCursor( int pos, bool mark = FALSE );
252     void setText( const SecTQString& txt );
253     int xToPos( int x, TQTextItem::CursorPosition = TQTextItem::BetweenCharacters ) const;
254     inline int visualAlignment() const { return alignment ? alignment : int( isRightToLeft() ? AlignRight : AlignLeft ); }
255     TQRect cursorRect() const;
256     void updateMicroFocusHint();
257 
258 };
259 
260 
261 /*!
262     \class SecTQLineEdit
263     \brief The SecTQLineEdit widget is a one-line text editor.
264 
265     \ingroup basic
266     \mainclass
267 
268     A line edit allows the user to enter and edit a single line of
269     plain text with a useful collection of editing functions,
270     including undo and redo, cut and paste,
271 
272     By changing the echoMode() of a line edit, it can also be used as
273     a "write-only" field, for inputs such as passwords.
274 
275     The length of the text can be constrained to maxLength().
276 
277     A related class is TQTextEdit which allows multi-line, rich-text
278     editing.
279 
280     You can change the text with setText() or insert(). The text is
281     retrieved with text(); the displayed text (which may be different,
282     see \l{EchoMode}) is retrieved with displayText(). Text can be
283     selected with setSelection() or selectAll(), and the selection can
284     be cut(), copy()ied and paste()d. The text can be aligned with
285     setAlignment().
286 
287     When the text changes the textChanged() signal is emitted; when
288     the Return or Enter key is pressed the returnPressed() signal is
289     emitted.
290 
291     When the text changes the textModified() signal is emitted in all
292     cases.
293 
294     By default, SecTQLineEdits have a frame as specified by the Windows
295     and Motif style guides; you can turn it off by calling
296     setFrame(FALSE).
297 
298     The default key bindings are described below.
299     \target desc
300     \table
301     \header \i Keypress \i Action
302     \row \i Left Arrow \i Moves the cursor one character to the left.
303     \row \i Shift+Left Arrow \i Moves and selects text one character to the left.
304     \row \i Right Arrow \i Moves the cursor one character to the right.
305     \row \i Shift+Right Arrow \i Moves and selects text one character to the right.
306     \row \i Home \i Moves the cursor to the beginning of the line.
307     \row \i End \i Moves the cursor to the end of the line.
308     \row \i Backspace \i Deletes the character to the left of the cursor.
309     \row \i Ctrl+Backspace \i Deletes the word to the left of the cursor.
310     \row \i Delete \i Deletes the character to the right of the cursor.
311     \row \i Ctrl+Delete \i Deletes the word to the right of the cursor.
312     \row \i Ctrl+A \i Moves the cursor to the beginning of the line.
313     \row \i Ctrl+B \i Moves the cursor one character to the left.
314     \row \i Ctrl+C \i Copies the selected text to the clipboard.
315 		      (Windows also supports Ctrl+Insert for this operation.)
316     \row \i Ctrl+D \i Deletes the character to the right of the cursor.
317     \row \i Ctrl+E \i Moves the cursor to the end of the line.
318     \row \i Ctrl+F \i Moves the cursor one character to the right.
319     \row \i Ctrl+H \i Deletes the character to the left of the cursor.
320     \row \i Ctrl+K \i Deletes to the end of the line.
321     \row \i Ctrl+V \i Pastes the clipboard text into line edit.
322 		      (Windows also supports Shift+Insert for this operation.)
323     \row \i Ctrl+X \i Deletes the selected text and copies it to the clipboard.
324 		      (Windows also supports Shift+Delete for this operation.)
325     \row \i Ctrl+Z \i Undoes the last operation.
326     \row \i Ctrl+Y \i Redoes the last undone operation.
327     \endtable
328 
329     Any other key sequence that represents a valid character, will
330     cause the character to be inserted into the line edit.
331 
332     <img src=qlined-m.png> <img src=qlined-w.png>
333 
334     \sa TQTextEdit TQLabel TQComboBox
335 	\link guibooks.html#fowler GUI Design Handbook: Field, Entry\endlink
336 */
337 
338 
339 /*!
340     \fn void SecTQLineEdit::textChanged( const SecTQString& )
341 
342     This signal is emitted whenever the text changes. The argument is
343     the new text.
344 */
345 
346 /*!
347     \fn void SecTQLineEdit::selectionChanged()
348 
349     This signal is emitted whenever the selection changes.
350 
351     \sa hasSelectedText(), selectedText()
352 */
353 
354 /*!
355     \fn void SecTQLineEdit::lostFocus()
356 
357     This signal is emitted when the line edit has lost focus.
358 
359     \sa hasFocus(), TQWidget::focusInEvent(), TQWidget::focusOutEvent()
360 */
361 
362 
363 
364 /*!
365     Constructs a line edit with no text.
366 
367     The maximum text length is set to 32767 characters.
368 
369     The \a parent and \a name arguments are sent to the TQWidget constructor.
370 
371     \sa setText(), setMaxLength()
372 */
373 
374 SecTQLineEdit::SecTQLineEdit( TQWidget* parent, const char* name )
375     : TQFrame( parent, name, WNoAutoErase ), d(new SecTQLineEditPrivate( this ))
376 {
377     d->init( SecTQString::null );
378 }
379 
380 /*!
381     Constructs a line edit containing the text \a contents.
382 
383     The cursor position is set to the end of the line and the maximum
384     text length to 32767 characters.
385 
386     The \a parent and \a name arguments are sent to the TQWidget
387     constructor.
388 
389     \sa text(), setMaxLength()
390 */
391 
392 SecTQLineEdit::SecTQLineEdit( const SecTQString& contents, TQWidget* parent, const char* name )
393     : TQFrame( parent, name, WNoAutoErase ), d(new SecTQLineEditPrivate( this ))
394 {
395     d->init( contents );
396 }
397 
398 /*!
399     Destroys the line edit.
400 */
401 
402 SecTQLineEdit::~SecTQLineEdit()
403 {
404     delete d;
405 }
406 
407 
408 /*!
409     \property SecTQLineEdit::text
410     \brief the line edit's text
411 
412     Setting this property clears the selection, clears the undo/redo
413     history, moves the cursor to the end of the line and resets the
414     \c modified property to FALSE.
415 
416     The text is truncated to maxLength() length.
417 
418     \sa insert()
419 */
420 SecTQString SecTQLineEdit::text() const
421 {
422     return ( d->text.isNull() ? SecTQString ("") : d->text );
423 }
424 
425 void SecTQLineEdit::setText( const SecTQString& text)
426 {
427     resetInputContext();
428     d->setText( text );
429     d->modified = FALSE;
430     d->finishChange( -1, FALSE );
431 }
432 
433 
434 /*!
435     \property SecTQLineEdit::displayText
436     \brief the displayed text
437 
438     If \c EchoMode is \c Normal this returns the same as text(); if
439     \c EchoMode is \c Password it returns a string of asterisks
440     text().length() characters long, e.g. "******"; if \c EchoMode is
441     \c NoEcho returns an empty string, "".
442 
443     \sa setEchoMode() text() EchoMode
444 */
445 
446 TQString SecTQLineEdit::displayText() const
447 {
448     if ( d->echoMode == NoEcho )
449 	return TQString::fromLatin1("");
450 
451     TQChar pwd_char = TQChar (style().styleHint( TQStyle::SH_LineEdit_PasswordCharacter, this));
452     TQString res;
453     res.fill (pwd_char, d->text.length ());
454     return res;
455 }
456 
457 
458 /*!
459     \property SecTQLineEdit::maxLength
460     \brief the maximum permitted length of the text
461 
462     If the text is too long, it is truncated at the limit.
463 
464     If truncation occurs any selected text will be unselected, the
465     cursor position is set to 0 and the first part of the string is
466     shown.
467 */
468 
469 int SecTQLineEdit::maxLength() const
470 {
471     return d->maxLength;
472 }
473 
474 void SecTQLineEdit::setMaxLength( int maxLength )
475 {
476     d->maxLength = maxLength;
477     setText( d->text );
478 }
479 
480 
481 
482 /*!
483     \property SecTQLineEdit::frame
484     \brief whether the line edit draws itself with a frame
485 
486     If enabled (the default) the line edit draws itself inside a
487     two-pixel frame, otherwise the line edit draws itself without any
488     frame.
489 */
490 bool SecTQLineEdit::frame() const
491 {
492     return frameShape() != NoFrame;
493 }
494 
495 
496 void SecTQLineEdit::setFrame( bool enable )
497 {
498     setFrameStyle( enable ? ( LineEditPanel | Sunken ) : NoFrame  );
499 }
500 
501 
502 /*!
503     \enum SecTQLineEdit::EchoMode
504 
505     This enum type describes how a line edit should display its
506     contents.
507 
508     \value Normal   Display characters as they are entered. This is the
509 		    default.
510     \value NoEcho   Do not display anything. This may be appropriate
511 		    for passwords where even the length of the
512 		    password should be kept secret.
513     \value Password  Display asterisks instead of the characters
514 		    actually entered.
515 
516     \sa setEchoMode() echoMode()
517 */
518 
519 
520 /*!
521     \property SecTQLineEdit::echoMode
522     \brief the line edit's echo mode
523 
524     The initial setting is \c Normal, but SecTQLineEdit also supports \c
525     NoEcho and \c Password modes.
526 
527     The widget's display and the ability to copy the text is affected
528     by this setting.
529 
530     \sa EchoMode displayText()
531 */
532 
533 SecTQLineEdit::EchoMode SecTQLineEdit::echoMode() const
534 {
535     return (EchoMode) d->echoMode;
536 }
537 
538 void SecTQLineEdit::setEchoMode( EchoMode mode )
539 {
540     d->echoMode = mode;
541     d->updateTextLayout();
542     update();
543 }
544 
545 
546 
547 /*!
548     Returns a recommended size for the widget.
549 
550     The width returned, in pixels, is usually enough for about 15 to
551     20 characters.
552 */
553 
554 TQSize SecTQLineEdit::sizeHint() const
555 {
556     constPolish();
557     TQFontMetrics fm( font() );
558     int h = TQMAX(fm.lineSpacing(), 14) + 2*innerMargin;
559     int w = fm.width( 'x' ) * 17; // "some"
560     int m = frameWidth() * 2;
561     return (style().sizeFromContents(TQStyle::CT_LineEdit, this,
562 				     TQSize( w + m, h + m ).
563 				     expandedTo(TQApplication::globalStrut())));
564 }
565 
566 
567 /*!
568     Returns a minimum size for the line edit.
569 
570     The width returned is enough for at least one character.
571 */
572 
573 TQSize SecTQLineEdit::minimumSizeHint() const
574 {
575     constPolish();
576     TQFontMetrics fm = fontMetrics();
577     int h = fm.height() + TQMAX( 2*innerMargin, fm.leading() );
578     int w = fm.maxWidth();
579     int m = frameWidth() * 2;
580     return TQSize( w + m, h + m );
581 }
582 
583 
584 /*!
585     \property SecTQLineEdit::cursorPosition
586     \brief the current cursor position for this line edit
587 
588     Setting the cursor position causes a repaint when appropriate.
589 */
590 
591 int SecTQLineEdit::cursorPosition() const
592 {
593     return d->cursor;
594 }
595 
596 
597 void SecTQLineEdit::setCursorPosition( int pos )
598 {
599     if ( pos <= (int) d->text.length() )
600 	d->moveCursor( pos );
601 }
602 
603 
604 /*!
605     \property SecTQLineEdit::alignment
606     \brief the alignment of the line edit
607 
608     Possible Values are \c TQt::AlignAuto, \c TQt::AlignLeft, \c
609     TQt::AlignRight and \c TQt::AlignHCenter.
610 
611     Attempting to set the alignment to an illegal flag combination
612     does nothing.
613 
614     \sa TQt::AlignmentFlags
615 */
616 
617 int SecTQLineEdit::alignment() const
618 {
619     return d->alignment;
620 }
621 
622 void SecTQLineEdit::setAlignment( int flag )
623 {
624     d->alignment = flag & 0x7;
625     update();
626 }
627 
628 
629 /*!
630   \obsolete
631   \fn void SecTQLineEdit::cursorRight( bool, int )
632 
633   Use cursorForward() instead.
634 
635   \sa cursorForward()
636 */
637 
638 /*!
639   \obsolete
640   \fn void SecTQLineEdit::cursorLeft( bool, int )
641   For compatibilty with older applications only. Use cursorBackward()
642   instead.
643   \sa cursorBackward()
644 */
645 
646 /*!
647     Moves the cursor forward \a steps characters. If \a mark is TRUE
648     each character moved over is added to the selection; if \a mark is
649     FALSE the selection is cleared.
650 
651     \sa cursorBackward()
652 */
653 
654 void SecTQLineEdit::cursorForward( bool mark, int steps )
655 {
656     int cursor = d->cursor;
657     if ( steps > 0 ) {
658 	while( steps-- )
659 	    cursor = d->textLayout.nextCursorPosition( cursor );
660     } else if ( steps < 0 ) {
661 	while ( steps++ )
662 	    cursor = d->textLayout.previousCursorPosition( cursor );
663     }
664     d->moveCursor( cursor, mark );
665 }
666 
667 
668 /*!
669     Moves the cursor back \a steps characters. If \a mark is TRUE each
670     character moved over is added to the selection; if \a mark is
671     FALSE the selection is cleared.
672 
673     \sa cursorForward()
674 */
675 void SecTQLineEdit::cursorBackward( bool mark, int steps )
676 {
677     cursorForward( mark, -steps );
678 }
679 
680 /*!
681     Moves the cursor one word forward. If \a mark is TRUE, the word is
682     also selected.
683 
684     \sa cursorWordBackward()
685 */
686 void SecTQLineEdit::cursorWordForward( bool mark )
687 {
688     d->moveCursor( d->textLayout.nextCursorPosition(d->cursor, TQTextLayout::SkipWords), mark );
689 }
690 
691 /*!
692     Moves the cursor one word backward. If \a mark is TRUE, the word
693     is also selected.
694 
695     \sa cursorWordForward()
696 */
697 
698 void SecTQLineEdit::cursorWordBackward( bool mark )
699 {
700     d->moveCursor( d->textLayout.previousCursorPosition(d->cursor, TQTextLayout::SkipWords), mark );
701 }
702 
703 
704 /*!
705     If no text is selected, deletes the character to the left of the
706     text cursor and moves the cursor one position to the left. If any
707     text is selected, the cursor is moved to the beginning of the
708     selected text and the selected text is deleted.
709 
710     \sa del()
711 */
712 void SecTQLineEdit::backspace()
713 {
714     int priorState = d->undoState;
715     if ( d->hasSelectedText() ) {
716 	d->removeSelectedText();
717     } else if ( d->cursor ) {
718 	    --d->cursor;
719 	    d->del( TRUE );
720     }
721     d->finishChange( priorState );
722 
723     emit backspacePressed();
724 }
725 
726 /*!
727     If no text is selected, deletes the character to the right of the
728     text cursor. If any text is selected, the cursor is moved to the
729     beginning of the selected text and the selected text is deleted.
730 
731     \sa backspace()
732 */
733 
734 void SecTQLineEdit::del()
735 {
736     int priorState = d->undoState;
737     if ( d->hasSelectedText() ) {
738 	d->removeSelectedText();
739     } else {
740 	int n = d->textLayout.nextCursorPosition( d->cursor ) - d->cursor;
741 	while ( n-- )
742 	    d->del();
743     }
744     d->finishChange( priorState );
745 }
746 
747 /*!
748     Moves the text cursor to the beginning of the line unless it is
749     already there. If \a mark is TRUE, text is selected towards the
750     first position; otherwise, any selected text is unselected if the
751     cursor is moved.
752 
753     \sa end()
754 */
755 
756 void SecTQLineEdit::home( bool mark )
757 {
758     d->moveCursor( 0, mark );
759 }
760 
761 /*!
762     Moves the text cursor to the end of the line unless it is already
763     there. If \a mark is TRUE, text is selected towards the last
764     position; otherwise, any selected text is unselected if the cursor
765     is moved.
766 
767     \sa home()
768 */
769 
770 void SecTQLineEdit::end( bool mark )
771 {
772     d->moveCursor( d->text.length(), mark );
773 }
774 
775 
776 /*!
777     \property SecTQLineEdit::modified
778     \brief whether the line edit's contents has been modified by the user
779 
780     The modified flag is never read by SecTQLineEdit; it has a default value
781     of FALSE and is changed to TRUE whenever the user changes the line
782     edit's contents.
783 
784     This is useful for things that need to provide a default value but
785     do not start out knowing what the default should be (perhaps it
786     depends on other fields on the form). Start the line edit without
787     the best default, and when the default is known, if modified()
788     returns FALSE (the user hasn't entered any text), insert the
789     default value.
790 
791     Calling clearModified() or setText() resets the modified flag to
792     FALSE.
793 */
794 
795 bool SecTQLineEdit::isModified() const
796 {
797     return d->modified;
798 }
799 
800 /*!
801     Resets the modified flag to FALSE.
802 
803     \sa isModified()
804 */
805 void SecTQLineEdit::clearModified()
806 {
807     d->modified = FALSE;
808     d->history.clear();
809     d->undoState = 0;
810 }
811 
812 /*!
813   \obsolete
814   \property SecTQLineEdit::edited
815   \brief whether the line edit has been edited. Use modified instead.
816 */
817 bool SecTQLineEdit::edited() const { return d->modified; }
818 void SecTQLineEdit::setEdited( bool on ) { d->modified = on; }
819 
820 /*!
821     \obsolete
822     \property SecTQLineEdit::hasMarkedText
823     \brief whether part of the text has been selected by the user. Use hasSelectedText instead.
824 */
825 
826 /*!
827     \property SecTQLineEdit::hasSelectedText
828     \brief whether there is any text selected
829 
830     hasSelectedText() returns TRUE if some or all of the text has been
831     selected by the user; otherwise returns FALSE.
832 
833     \sa selectedText()
834 */
835 
836 
837 bool SecTQLineEdit::hasSelectedText() const
838 {
839     return d->hasSelectedText();
840 }
841 
842 /*!
843   \obsolete
844   \property SecTQLineEdit::markedText
845   \brief the text selected by the user. Use selectedText instead.
846 */
847 
848 /*!
849     \property SecTQLineEdit::selectedText
850     \brief the selected text
851 
852     If there is no selected text this property's value is
853     TQString::null.
854 
855     \sa hasSelectedText()
856 */
857 
858 SecTQString SecTQLineEdit::selectedText() const
859 {
860     if ( d->hasSelectedText() )
861 	return d->text.mid( d->selstart, d->selend - d->selstart );
862     return SecTQString::null;
863 }
864 
865 /*!
866     selectionStart() returns the index of the first selected character in the
867     line edit or -1 if no text is selected.
868 
869     \sa selectedText()
870 */
871 
872 int SecTQLineEdit::selectionStart() const
873 {
874     return d->hasSelectedText() ? d->selstart : -1;
875 }
876 
877 
878 /*!
879     Selects text from position \a start and for \a length characters.
880 
881     \sa deselect() selectAll()
882 */
883 
884 void SecTQLineEdit::setSelection( int start, int length )
885 {
886     if ( start < 0 || start > (int)d->text.length() || length < 0 ) {
887 	d->selstart = d->selend = 0;
888     } else {
889 	d->selstart = start;
890 	d->selend = TQMIN( start + length, (int)d->text.length() );
891 	d->cursor = d->selend;
892     }
893     update();
894 }
895 
896 
897 /*!
898     \property SecTQLineEdit::undoAvailable
899     \brief whether undo is available
900 */
901 
902 bool SecTQLineEdit::isUndoAvailable() const
903 {
904     return d->isUndoAvailable();
905 }
906 
907 /*!
908     \property SecTQLineEdit::redoAvailable
909     \brief whether redo is available
910 */
911 
912 bool SecTQLineEdit::isRedoAvailable() const
913 {
914     return d->isRedoAvailable();
915 }
916 
917 /*!
918     Selects all the text (i.e. highlights it) and moves the cursor to
919     the end. This is useful when a default value has been inserted
920     because if the user types before clicking on the widget, the
921     selected text will be deleted.
922 
923     \sa setSelection() deselect()
924 */
925 
926 void SecTQLineEdit::selectAll()
927 {
928     d->selstart = d->selend = d->cursor = 0;
929     d->moveCursor( d->text.length(), TRUE );
930 }
931 
932 /*!
933     Deselects any selected text.
934 
935     \sa setSelection() selectAll()
936 */
937 
938 void SecTQLineEdit::deselect()
939 {
940     d->deselect();
941     d->finishChange();
942 }
943 
944 
945 /*!
946     Deletes any selected text, inserts \a newText and sets it as the
947     new contents of the line edit.
948 */
949 void SecTQLineEdit::insert( const SecTQString &newText )
950 {
951 //     q->resetInputContext(); //#### FIX ME IN QT
952     int priorState = d->undoState;
953     d->removeSelectedText();
954     d->insert( newText );
955     d->finishChange( priorState );
956 }
957 
958 /*!
959     Clears the contents of the line edit.
960 */
961 void SecTQLineEdit::clear()
962 {
963     int priorState = d->undoState;
964     resetInputContext();
965     d->selstart = 0;
966     d->selend = d->text.length();
967     d->removeSelectedText();
968     d->separate();
969     d->finishChange( priorState );
970 }
971 
972 /*!
973     Undoes the last operation if undo is \link
974     SecTQLineEdit::undoAvailable available\endlink. Deselects any current
975     selection, and updates the selection start to the current cursor
976     position.
977 */
978 void SecTQLineEdit::undo()
979 {
980 #ifndef SECURE_NO_UNDO
981     resetInputContext();
982     d->undo();
983     d->finishChange( -1, FALSE );
984 #endif
985 }
986 
987 /*!
988     Redoes the last operation if redo is \link
989     SecTQLineEdit::redoAvailable available\endlink.
990 */
991 void SecTQLineEdit::redo()
992 {
993 #ifndef SECURE_NO_UNDO
994     resetInputContext();
995     d->redo();
996     d->finishChange();
997 #endif
998 }
999 
1000 
1001 /*!
1002     \property SecTQLineEdit::readOnly
1003     \brief whether the line edit is read only.
1004 
1005     In read-only mode, the user can still copy the text to the
1006     clipboard (if echoMode() is \c Normal), but cannot edit it.
1007 
1008     SecTQLineEdit does not show a cursor in read-only mode.
1009 
1010     \sa setEnabled()
1011 */
1012 
1013 bool SecTQLineEdit::isReadOnly() const
1014 {
1015     return d->readOnly;
1016 }
1017 
1018 void SecTQLineEdit::setReadOnly( bool enable )
1019 {
1020     d->readOnly = enable;
1021 #ifndef QT_NO_CURSOR
1022     setCursor( enable ? arrowCursor : ibeamCursor );
1023 #endif
1024     update();
1025 }
1026 
1027 
1028 #ifndef QT_NO_CLIPBOARD
1029 /*!
1030     Copies the selected text to the clipboard and deletes it, if there
1031     is any, and if echoMode() is \c Normal.
1032 
1033     \sa copy() paste() setValidator()
1034 */
1035 
1036 void SecTQLineEdit::cut()
1037 {
1038     if ( hasSelectedText() ) {
1039 	copy();
1040 	del();
1041     }
1042 }
1043 
1044 
1045 /*!
1046     Copies the selected text to the clipboard, if there is any, and if
1047     echoMode() is \c Normal.
1048 
1049     \sa cut() paste()
1050 */
1051 
1052 void SecTQLineEdit::copy() const
1053 {
1054     d->copy();
1055 }
1056 
1057 /*!
1058     Inserts the clipboard's text at the cursor position, deleting any
1059     selected text, providing the line edit is not \link
1060     SecTQLineEdit::readOnly read-only\endlink.
1061 
1062     \sa copy() cut()
1063 */
1064 
1065 void SecTQLineEdit::paste()
1066 {
1067     d->removeSelectedText();
1068     insert( TQApplication::clipboard()->text( TQClipboard::Clipboard ) );
1069 }
1070 
1071 void SecTQLineEditPrivate::copy( bool clipboard ) const
1072 {
1073 #ifndef SECURE
1074     TQString t = q->selectedText();
1075     if ( !t.isEmpty() && echoMode == SecTQLineEdit::Normal ) {
1076 	q->disconnect( TQApplication::clipboard(), SIGNAL(selectionChanged()), q, 0);
1077 	TQApplication::clipboard()->setText( t, clipboard ? TQClipboard::Clipboard : TQClipboard::Selection );
1078 	q->connect( TQApplication::clipboard(), SIGNAL(selectionChanged()),
1079 		 q, SLOT(clipboardChanged()) );
1080     }
1081 #endif
1082 }
1083 
1084 #endif // !QT_NO_CLIPBOARD
1085 
1086 /*!\reimp
1087 */
1088 
1089 void SecTQLineEdit::resizeEvent( TQResizeEvent *e )
1090 {
1091     TQFrame::resizeEvent( e );
1092 }
1093 
1094 /*! \reimp
1095 */
1096 bool SecTQLineEdit::event( TQEvent * e )
1097 {
1098     if ( e->type() == TQEvent::AccelOverride && !d->readOnly ) {
1099 	TQKeyEvent* ke = (TQKeyEvent*) e;
1100 	if ( ke->state() == NoButton || ke->state() == ShiftButton
1101 	     || ke->state() == Keypad ) {
1102 	    if ( ke->key() < Key_Escape ) {
1103 		ke->accept();
1104 	    } else if ( ke->state() == NoButton
1105 			|| ke->state() == ShiftButton ) {
1106 		switch ( ke->key() ) {
1107 		case Key_Delete:
1108 		case Key_Home:
1109 		case Key_End:
1110 		case Key_Backspace:
1111 		case Key_Left:
1112 		case Key_Right:
1113 		    ke->accept();
1114 		default:
1115 		    break;
1116 		}
1117 	    }
1118 	} else if ( ke->state() & ControlButton ) {
1119 	    switch ( ke->key() ) {
1120 // Those are too frequently used for application functionality
1121 /*	    case Key_A:
1122 	    case Key_B:
1123 	    case Key_D:
1124 	    case Key_E:
1125 	    case Key_F:
1126 	    case Key_H:
1127 	    case Key_K:
1128 */
1129 	    case Key_C:
1130 	    case Key_V:
1131 	    case Key_X:
1132 	    case Key_Y:
1133 	    case Key_Z:
1134 	    case Key_Left:
1135 	    case Key_Right:
1136 #if defined (Q_WS_WIN)
1137 	    case Key_Insert:
1138 	    case Key_Delete:
1139 #endif
1140 		ke->accept();
1141 	    default:
1142 		break;
1143 	    }
1144 	}
1145     } else if ( e->type() == TQEvent::Timer ) {
1146 	// should be timerEvent, is here for binary compatibility
1147 	int timerId = ((TQTimerEvent*)e)->timerId();
1148 	if ( timerId == d->cursorTimer ) {
1149 	    if(!hasSelectedText() || style().styleHint( TQStyle::SH_BlinkCursorWhenTextSelected ))
1150 		d->setCursorVisible( !d->cursorVisible );
1151 	} else if ( timerId == d->tripleClickTimer ) {
1152 	    killTimer( d->tripleClickTimer );
1153 	    d->tripleClickTimer = 0;
1154 	}
1155     }
1156     return TQWidget::event( e );
1157 }
1158 
1159 /*! \reimp
1160 */
1161 void SecTQLineEdit::mousePressEvent( TQMouseEvent* e )
1162 {
1163     if ( e->button() == RightButton )
1164 	return;
1165     if ( d->tripleClickTimer && ( e->pos() - d->tripleClick ).manhattanLength() <
1166 	 TQApplication::startDragDistance() ) {
1167 	selectAll();
1168 	return;
1169     }
1170     bool mark = e->state() & ShiftButton;
1171     int cursor = d->xToPos( e->pos().x() );
1172     d->moveCursor( cursor, mark );
1173 }
1174 
1175 /*! \reimp
1176 */
1177 void SecTQLineEdit::mouseMoveEvent( TQMouseEvent * e )
1178 {
1179 
1180 #ifndef QT_NO_CURSOR
1181     if ( ( e->state() & MouseButtonMask ) == 0 ) {
1182 	if ( !d->readOnly )
1183 	  setCursor( ( d->inSelection( e->pos().x() ) ? arrowCursor : ibeamCursor ) );
1184     }
1185 #endif
1186 
1187     if ( e->state() & LeftButton ) {
1188       d->moveCursor( d->xToPos( e->pos().x() ), TRUE );
1189     }
1190 }
1191 
1192 /*! \reimp
1193 */
1194 void SecTQLineEdit::mouseReleaseEvent( TQMouseEvent* e )
1195 {
1196 #ifndef QT_NO_CLIPBOARD
1197     if (TQApplication::clipboard()->supportsSelection() ) {
1198 	if ( e->button() == LeftButton ) {
1199 	    d->copy( FALSE );
1200 	} else if ( !d->readOnly && e->button() == MidButton ) {
1201 	    d->deselect();
1202 	    insert( TQApplication::clipboard()->text( TQClipboard::Selection ) );
1203 	}
1204     }
1205 #endif
1206 }
1207 
1208 /*! \reimp
1209 */
1210 void SecTQLineEdit::mouseDoubleClickEvent( TQMouseEvent* e )
1211 {
1212     if ( e->button() == TQt::LeftButton ) {
1213 	deselect();
1214 	d->cursor = d->xToPos( e->pos().x() );
1215 	d->cursor = d->textLayout.previousCursorPosition( d->cursor, TQTextLayout::SkipWords );
1216 	// ## text layout should support end of words.
1217 	int end = d->textLayout.nextCursorPosition( d->cursor, TQTextLayout::SkipWords );
1218 	while ( end > d->cursor && d->text[end-1].isSpace() )
1219 	    --end;
1220 	d->moveCursor( end, TRUE );
1221 	d->tripleClickTimer = startTimer( TQApplication::doubleClickInterval() );
1222 	d->tripleClick = e->pos();
1223     }
1224 }
1225 
1226 /*!
1227     \fn void  SecTQLineEdit::returnPressed()
1228 
1229     This signal is emitted when the Return or Enter key is pressed.
1230 */
1231 
1232 /*!
1233     Converts key press event \a e into a line edit action.
1234 
1235     If Return or Enter is pressed the signal returnPressed() is
1236     emitted.
1237 
1238     The default key bindings are listed in the \link #desc detailed
1239     description.\endlink
1240 */
1241 
1242 void SecTQLineEdit::keyPressEvent( TQKeyEvent * e )
1243 {
1244     d->setCursorVisible( TRUE );
1245     if ( e->key() == Key_Enter || e->key() == Key_Return ) {
1246 	emit returnPressed();
1247 	e->ignore();
1248 	return;
1249     }
1250     if ( !d->readOnly ) {
1251 	TQString t = e->text();
1252 	if ( !t.isEmpty() && (!e->ascii() || e->ascii()>=32) &&
1253 	     e->key() != Key_Delete &&
1254 	     e->key() != Key_Backspace ) {
1255 #ifdef Q_WS_X11
1256 	    extern bool tqt_hebrew_keyboard_hack;
1257 	    if ( tqt_hebrew_keyboard_hack ) {
1258 		// the X11 keyboard layout is broken and does not reverse
1259 		// braces correctly. This is a hack to get halfway correct
1260 		// behaviour
1261 		if ( d->isRightToLeft() ) {
1262 		    TQChar *c = (TQChar *)t.unicode();
1263 		    int l = t.length();
1264 		    while( l-- ) {
1265 			if ( c->mirrored() )
1266 			    *c = c->mirroredChar();
1267 			c++;
1268 		    }
1269 		}
1270 	    }
1271 #endif
1272 	    insert( t );
1273 	    return;
1274 	}
1275     }
1276     bool unknown = FALSE;
1277     if ( e->state() & ControlButton ) {
1278 	switch ( e->key() ) {
1279 	case Key_A:
1280 #if defined(Q_WS_X11)
1281 	    home( e->state() & ShiftButton );
1282 #else
1283 	    selectAll();
1284 #endif
1285 	    break;
1286 	case Key_B:
1287 	    cursorForward( e->state() & ShiftButton, -1 );
1288 	    break;
1289 #ifndef QT_NO_CLIPBOARD
1290 	case Key_C:
1291 	    copy();
1292 	    break;
1293 #endif
1294 	case Key_D:
1295 	    if ( !d->readOnly ) {
1296 		del();
1297 	    }
1298 	    break;
1299 	case Key_E:
1300 	    end( e->state() & ShiftButton );
1301 	    break;
1302 	case Key_F:
1303 	    cursorForward( e->state() & ShiftButton, 1 );
1304 	    break;
1305 	case Key_H:
1306 	    if ( !d->readOnly ) {
1307 		backspace();
1308 	    }
1309 	    break;
1310 	case Key_K:
1311 	    if ( !d->readOnly ) {
1312 		int priorState = d->undoState;
1313 		d->deselect();
1314 		while ( d->cursor < (int) d->text.length() )
1315 		    d->del();
1316 		d->finishChange( priorState );
1317 	    }
1318 	    break;
1319 #if defined(Q_WS_X11)
1320         case Key_U:
1321 	    if ( !d->readOnly )
1322 		clear();
1323 	    break;
1324 #endif
1325 #ifndef QT_NO_CLIPBOARD
1326 	case Key_V:
1327 	    if ( !d->readOnly )
1328 		paste();
1329 	    break;
1330 	case Key_X:
1331 	    if ( !d->readOnly && d->hasSelectedText() && echoMode() == Normal ) {
1332 		copy();
1333 		del();
1334 	    }
1335 	    break;
1336 #if defined (Q_WS_WIN)
1337 	case Key_Insert:
1338 	    copy();
1339 	    break;
1340 #endif
1341 #endif
1342 	case Key_Delete:
1343 	    if ( !d->readOnly ) {
1344 		cursorWordForward( TRUE );
1345 		del();
1346 	    }
1347 	    break;
1348 	case Key_Backspace:
1349 	    if ( !d->readOnly ) {
1350 		cursorWordBackward( TRUE );
1351 		del();
1352 	    }
1353 	    break;
1354 	case Key_Right:
1355 	case Key_Left:
1356 	    if ( d->isRightToLeft() == (e->key() == Key_Right) ) {
1357 	        if ( echoMode() == Normal )
1358 		    cursorWordBackward( e->state() & ShiftButton );
1359 		else
1360 		    home( e->state() & ShiftButton );
1361 	    } else {
1362 		if ( echoMode() == Normal )
1363 		    cursorWordForward( e->state() & ShiftButton );
1364 		else
1365 		    end( e->state() & ShiftButton );
1366 	    }
1367 	    break;
1368 	case Key_Z:
1369 	    if ( !d->readOnly ) {
1370 		if(e->state() & ShiftButton)
1371 		    redo();
1372 		else
1373 		    undo();
1374 	    }
1375 	    break;
1376 	case Key_Y:
1377 	    if ( !d->readOnly )
1378 		redo();
1379 	    break;
1380 	default:
1381 	    unknown = TRUE;
1382 	}
1383     } else { // ### check for *no* modifier
1384 	switch ( e->key() ) {
1385 	case Key_Shift:
1386 	    // ### TODO
1387 	    break;
1388 	case Key_Left:
1389 	case Key_Right: {
1390 	    int step =  (d->isRightToLeft() == (e->key() == Key_Right)) ? -1 : 1;
1391 	    cursorForward( e->state() & ShiftButton, step );
1392 	}
1393 	break;
1394 	case Key_Backspace:
1395 	    if ( !d->readOnly ) {
1396 		backspace();
1397 	    }
1398 	    break;
1399 	case Key_Home:
1400 #ifdef Q_WS_MACX
1401 	case Key_Up:
1402 #endif
1403 	    home( e->state() & ShiftButton );
1404 	    break;
1405 	case Key_End:
1406 #ifdef Q_WS_MACX
1407 	case Key_Down:
1408 #endif
1409 	    end( e->state() & ShiftButton );
1410 	    break;
1411 	case Key_Delete:
1412 	    if ( !d->readOnly ) {
1413 #if defined (Q_WS_WIN)
1414 		if ( e->state() & ShiftButton ) {
1415 		    cut();
1416 		    break;
1417 		}
1418 #endif
1419 		del();
1420 	    }
1421 	    break;
1422 #if defined (Q_WS_WIN)
1423 	case Key_Insert:
1424 	    if ( !d->readOnly && e->state() & ShiftButton )
1425 		paste();
1426 	    else
1427 		unknown = TRUE;
1428 	    break;
1429 #endif
1430 	case Key_F14: // Undo key on Sun keyboards
1431 	    if ( !d->readOnly )
1432 		undo();
1433 	    break;
1434 #ifndef QT_NO_CLIPBOARD
1435 	case Key_F16: // Copy key on Sun keyboards
1436 	    copy();
1437 	    break;
1438 	case Key_F18: // Paste key on Sun keyboards
1439 	    if ( !d->readOnly )
1440 		paste();
1441 	    break;
1442 	case Key_F20: // Cut key on Sun keyboards
1443 	    if ( !d->readOnly && hasSelectedText() && echoMode() == Normal ) {
1444 		copy();
1445 		del();
1446 	    }
1447 	    break;
1448 #endif
1449 	default:
1450 	    unknown = TRUE;
1451 	}
1452     }
1453     if ( e->key() == Key_Direction_L )
1454 	d->direction = TQChar::DirL;
1455     else if ( e->key() == Key_Direction_R )
1456 	d->direction = TQChar::DirR;
1457 
1458     if ( unknown )
1459 	e->ignore();
1460 }
1461 
1462 /*! \reimp
1463  */
1464 void SecTQLineEdit::imStartEvent( TQIMEvent *e )
1465 {
1466     if ( d->readOnly ) {
1467 	e->ignore();
1468 	return;
1469     }
1470     d->removeSelectedText();
1471     d->updateMicroFocusHint();
1472     d->imstart = d->imend = d->imselstart = d->imselend = d->cursor;
1473 }
1474 
1475 /*! \reimp
1476  */
1477 void SecTQLineEdit::imComposeEvent( TQIMEvent *e )
1478 {
1479     if ( d->readOnly ) {
1480 	e->ignore();
1481     } else {
1482 	d->text.replace( d->imstart, d->imend - d->imstart, e->text() );
1483 	d->imend = d->imstart + e->text().length();
1484 	d->imselstart = d->imstart + e->cursorPos();
1485 	d->imselend = d->imselstart + e->selectionLength();
1486 	d->cursor = e->selectionLength() ? d->imend : d->imselend;
1487 	d->updateTextLayout();
1488 	update();
1489     }
1490 }
1491 
1492 /*! \reimp
1493  */
1494 void SecTQLineEdit::imEndEvent( TQIMEvent *e )
1495 {
1496     if ( d->readOnly ) {
1497 	e->ignore();
1498     } else {
1499 	d->text.remove( d->imstart, d->imend - d->imstart );
1500 	d->cursor = d->imselstart = d->imselend = d->imend = d->imstart;
1501 	d->textDirty = TRUE;
1502 	insert( e->text() );
1503     }
1504 }
1505 
1506 /*!\reimp
1507 */
1508 
1509 void SecTQLineEdit::focusInEvent( TQFocusEvent* e )
1510 {
1511     if ( e->reason() == TQFocusEvent::Tab ||
1512 	 e->reason() == TQFocusEvent::Backtab  ||
1513 	 e->reason() == TQFocusEvent::Shortcut )
1514 	selectAll();
1515     if ( !d->cursorTimer ) {
1516 	int cft = TQApplication::cursorFlashTime();
1517 	d->cursorTimer = cft ? startTimer( cft/2 ) : -1;
1518     }
1519     d->updateMicroFocusHint();
1520 }
1521 
1522 /*!\reimp
1523 */
1524 
1525 void SecTQLineEdit::focusOutEvent( TQFocusEvent* e )
1526 {
1527     if ( e->reason() != TQFocusEvent::ActiveWindow &&
1528 	 e->reason() != TQFocusEvent::Popup )
1529 	deselect();
1530     d->setCursorVisible( FALSE );
1531     if ( d->cursorTimer > 0 )
1532 	killTimer( d->cursorTimer );
1533     d->cursorTimer = 0;
1534     emit lostFocus();
1535 }
1536 
1537 /*!\reimp
1538 */
1539 void SecTQLineEdit::drawContents( TQPainter *p )
1540 {
1541     const TQColorGroup& cg = colorGroup();
1542     TQRect cr = contentsRect();
1543     TQFontMetrics fm = fontMetrics();
1544     TQRect lineRect( cr.x() + innerMargin, cr.y() + (cr.height() - fm.height() + 1) / 2,
1545 		    cr.width() - 2*innerMargin, fm.height() );
1546     TQBrush bg = TQBrush( paletteBackgroundColor() );
1547     if ( paletteBackgroundPixmap() )
1548 	bg = TQBrush( cg.background(), *paletteBackgroundPixmap() );
1549     else if ( !isEnabled() )
1550 	bg = cg.brush( TQColorGroup::Background );
1551     p->save();
1552     p->setClipRegion( TQRegion(cr) - lineRect );
1553     p->fillRect( cr, bg );
1554     p->restore();
1555     SecTQSharedDoubleBuffer buffer( p, lineRect.x(), lineRect.y(),
1556 				lineRect.width(), lineRect.height(),
1557 				hasFocus() ? SecTQSharedDoubleBuffer::Force : 0 );
1558     p = buffer.painter();
1559     p->fillRect( lineRect, bg );
1560 
1561     // locate cursor position
1562     int cix = 0;
1563     TQTextItem ci = d->textLayout.findItem( d->cursor );
1564     if ( ci.isValid() ) {
1565 	if ( d->cursor != (int)d->text.length() && d->cursor == ci.from() + ci.length()
1566 	     && ci.isRightToLeft() != d->isRightToLeft() )
1567 	    ci = d->textLayout.findItem( d->cursor + 1 );
1568 	cix = ci.x() + ci.cursorToX( d->cursor - ci.from() );
1569     }
1570 
1571     // horizontal scrolling
1572     int minLB = TQMAX( 0, -fm.minLeftBearing() );
1573     int minRB = TQMAX( 0, -fm.minRightBearing() );
1574     int widthUsed = d->textLayout.widthUsed() + 1 + minRB;
1575     if ( (minLB + widthUsed) <=  lineRect.width() ) {
1576 	switch ( d->visualAlignment() ) {
1577 	case AlignRight:
1578 	    d->hscroll = widthUsed - lineRect.width();
1579 	    break;
1580 	case AlignHCenter:
1581 	    d->hscroll = ( widthUsed - lineRect.width() ) / 2;
1582 	    break;
1583 	default:
1584 	    d->hscroll = 0;
1585 	    break;
1586 	}
1587 	d->hscroll -= minLB;
1588     } else if ( cix - d->hscroll >= lineRect.width() ) {
1589 	d->hscroll = cix - lineRect.width() + 1;
1590     } else if ( cix - d->hscroll < 0 ) {
1591 	d->hscroll = cix;
1592     } else if ( widthUsed - d->hscroll < lineRect.width() ) {
1593 	d->hscroll = widthUsed - lineRect.width() + 1;
1594     }
1595     // the y offset is there to keep the baseline constant in case we have script changes in the text.
1596     TQPoint topLeft = lineRect.topLeft() - TQPoint(d->hscroll, d->ascent-fm.ascent());
1597 
1598     // draw text, selections and cursors
1599     p->setPen( cg.text() );
1600     bool supressCursor = d->readOnly, hasRightToLeft = d->isRightToLeft();
1601     int textflags = 0;
1602     if ( font().underline() )
1603 	textflags |= TQt::Underline;
1604     if ( font().strikeOut() )
1605 	textflags |= TQt::StrikeOut;
1606     if ( font().overline() )
1607 	textflags |= TQt::Overline;
1608 
1609     for ( int i = 0; i < d->textLayout.numItems(); i++ ) {
1610 	TQTextItem ti = d->textLayout.itemAt( i );
1611 	hasRightToLeft |= ti.isRightToLeft();
1612 	int tix = topLeft.x() + ti.x();
1613 	int first = ti.from();
1614 	int last = ti.from() + ti.length() - 1;
1615 
1616 	// text and selection
1617 	if ( d->selstart < d->selend && (last >= d->selstart && first < d->selend ) ) {
1618 	    TQRect highlight = TQRect( TQPoint( tix + ti.cursorToX( TQMAX( d->selstart - first, 0 ) ),
1619 					     lineRect.top() ),
1620 				     TQPoint( tix + ti.cursorToX( TQMIN( d->selend - first, last - first + 1 ) ) - 1,
1621 					     lineRect.bottom() ) ).normalize();
1622 	    p->save();
1623 	    p->setClipRegion( TQRegion( lineRect ) - highlight, TQPainter::CoordPainter );
1624 	    p->drawTextItem( topLeft, ti, textflags );
1625 	    p->setClipRect( lineRect & highlight, TQPainter::CoordPainter );
1626 	    p->fillRect( highlight, cg.highlight() );
1627 	    p->setPen( cg.highlightedText() );
1628 	    p->drawTextItem( topLeft, ti, textflags );
1629 	    p->restore();
1630 	} else {
1631 	    p->drawTextItem( topLeft, ti, textflags );
1632 	}
1633 
1634 	// input method edit area
1635 	if ( d->imstart < d->imend && (last >= d->imstart && first < d->imend ) ) {
1636 	    TQRect highlight = TQRect( TQPoint( tix + ti.cursorToX( TQMAX( d->imstart - first, 0 ) ), lineRect.top() ),
1637 			      TQPoint( tix + ti.cursorToX( TQMIN( d->imend - first, last - first + 1 ) )-1, lineRect.bottom() ) ).normalize();
1638 	    p->save();
1639 	    p->setClipRect( lineRect & highlight, TQPainter::CoordPainter );
1640 
1641 	    int h1, s1, v1, h2, s2, v2;
1642 	    cg.color( TQColorGroup::Base ).hsv( &h1, &s1, &v1 );
1643 	    cg.color( TQColorGroup::Background ).hsv( &h2, &s2, &v2 );
1644 	    TQColor imCol;
1645 	    imCol.setHsv( h1, s1, ( v1 + v2 ) / 2 );
1646 	    p->fillRect( highlight, imCol );
1647 	    p->drawTextItem( topLeft, ti, textflags );
1648 	    p->restore();
1649 	}
1650 
1651 	// input method selection
1652 	if ( d->imselstart < d->imselend && (last >= d->imselstart && first < d->imselend ) ) {
1653 	    TQRect highlight = TQRect( TQPoint( tix + ti.cursorToX( TQMAX( d->imselstart - first, 0 ) ), lineRect.top() ),
1654 			      TQPoint( tix + ti.cursorToX( TQMIN( d->imselend - first, last - first + 1 ) )-1, lineRect.bottom() ) ).normalize();
1655 	    p->save();
1656 	    p->setClipRect( lineRect & highlight, TQPainter::CoordPainter );
1657 	    p->fillRect( highlight, cg.text() );
1658 	    p->setPen( paletteBackgroundColor() );
1659 	    p->drawTextItem( topLeft, ti, textflags );
1660 	    p->restore();
1661 	}
1662     }
1663 
1664     // draw cursor
1665     if ( d->cursorVisible && !supressCursor ) {
1666 	TQPoint from( topLeft.x() + cix, lineRect.top() );
1667 	TQPoint to = from + TQPoint( 0, lineRect.height() );
1668 	p->drawLine( from, to );
1669 	if ( hasRightToLeft ) {
1670 	    to = from + TQPoint( (ci.isRightToLeft()?-2:2), 2 );
1671 	    p->drawLine( from, to );
1672 	    from.ry() += 4;
1673 	    p->drawLine( from, to );
1674 	}
1675     }
1676     buffer.end();
1677 }
1678 
1679 
1680 enum { IdUndo, IdRedo, IdSep1, IdCut, IdCopy, IdPaste, IdClear, IdSep2, IdSelectAll };
1681 
1682 
1683 /*! \reimp */
1684 void SecTQLineEdit::windowActivationChange( bool b )
1685 {
1686     //### remove me with WHighlightSelection attribute
1687     if ( palette().active() != palette().inactive() )
1688 	update();
1689     TQWidget::windowActivationChange( b );
1690 }
1691 
1692 /*! \reimp */
1693 
1694 void SecTQLineEdit::setPalette( const TQPalette & p )
1695 {
1696     //### remove me with WHighlightSelection attribute
1697     TQWidget::setPalette( p );
1698     update();
1699 }
1700 
1701 /*!
1702   \obsolete
1703   \fn void SecTQLineEdit::repaintArea( int from, int to )
1704   Repaints all characters from \a from to \a to. If cursorPos is
1705   between from and to, ensures that cursorPos is visible.
1706 */
1707 
1708 /*! \reimp
1709  */
1710 void SecTQLineEdit::setFont( const TQFont & f )
1711 {
1712     TQWidget::setFont( f );
1713     d->updateTextLayout();
1714 }
1715 
1716 
1717 void SecTQLineEdit::clipboardChanged()
1718 {
1719 }
1720 
1721 void SecTQLineEditPrivate::init( const SecTQString& txt )
1722 {
1723 #ifndef QT_NO_CURSOR
1724     q->setCursor( readOnly ? arrowCursor : ibeamCursor );
1725 #endif
1726     q->setFocusPolicy( TQWidget::StrongFocus );
1727     q->setInputMethodEnabled( TRUE );
1728     //   Specifies that this widget can use more, but is able to survive on
1729     //   less, horizontal space; and is fixed vertically.
1730     q->setSizePolicy( TQSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Fixed ) );
1731     q->setBackgroundMode( PaletteBase );
1732     q->setKeyCompression( TRUE );
1733     q->setMouseTracking( TRUE );
1734     q->setAcceptDrops( TRUE );
1735     q->setFrame( TRUE );
1736     text = txt;
1737     updateTextLayout();
1738     cursor = text.length();
1739 }
1740 
1741 void SecTQLineEditPrivate::updateTextLayout()
1742 {
1743     // replace all non-printable characters with spaces (to avoid
1744     // drawing boxes when using fonts that don't have glyphs for such
1745     // characters)
1746     const TQString &displayText = q->displayText();
1747     TQString str(displayText.unicode(), displayText.length());
1748     TQChar* uc = (TQChar*)str.unicode();
1749     for (int i = 0; i < (int)str.length(); ++i) {
1750 	if (! uc[i].isPrint())
1751 	    uc[i] = TQChar(0x0020);
1752     }
1753     textLayout.setText( str, q->font() );
1754     // ### want to do textLayout.setRightToLeft( text.isRightToLeft() );
1755     textLayout.beginLayout( TQTextLayout::SingleLine );
1756     textLayout.beginLine( INT_MAX );
1757     while ( !textLayout.atEnd() )
1758 	textLayout.addCurrentItem();
1759     ascent = 0;
1760     textLayout.endLine(0, 0, TQt::AlignLeft, &ascent);
1761 }
1762 
1763 int SecTQLineEditPrivate::xToPos( int x, TQTextItem::CursorPosition betweenOrOn ) const
1764 {
1765     x-= q->contentsRect().x() - hscroll + innerMargin;
1766     for ( int i = 0; i < textLayout.numItems(); ++i ) {
1767 	TQTextItem ti = textLayout.itemAt( i );
1768 	TQRect tir = ti.rect();
1769 	if ( x >= tir.left() && x <= tir.right() )
1770 	    return ti.xToCursor( x - tir.x(), betweenOrOn ) + ti.from();
1771     }
1772     return x < 0 ? 0 : text.length();
1773 }
1774 
1775 
1776 TQRect SecTQLineEditPrivate::cursorRect() const
1777 {
1778     TQRect cr = q->contentsRect();
1779     int cix = cr.x() - hscroll + innerMargin;
1780     TQTextItem ci = textLayout.findItem( cursor );
1781     if ( ci.isValid() ) {
1782 	if ( cursor != (int)text.length() && cursor == ci.from() + ci.length()
1783 	     && ci.isRightToLeft() != isRightToLeft() )
1784 	    ci = textLayout.findItem( cursor + 1 );
1785 	cix += ci.x() + ci.cursorToX( cursor - ci.from() );
1786     }
1787     int ch = q->fontMetrics().height();
1788     return TQRect( cix-4, cr.y() + ( cr.height() -  ch + 1) / 2, 8, ch + 1 );
1789 }
1790 
1791 void SecTQLineEditPrivate::updateMicroFocusHint()
1792 {
1793     if ( q->hasFocus() ) {
1794 	TQRect r = cursorRect();
1795 	q->setMicroFocusHint( r.x(), r.y(), r.width(), r.height() );
1796     }
1797 }
1798 
1799 void SecTQLineEditPrivate::moveCursor( int pos, bool mark )
1800 {
1801     if ( pos != cursor )
1802 	separate();
1803     bool fullUpdate = mark || hasSelectedText();
1804     if ( mark ) {
1805 	int anchor;
1806 	if ( selend > selstart && cursor == selstart )
1807 	    anchor = selend;
1808 	else if ( selend > selstart && cursor == selend )
1809 	    anchor = selstart;
1810 	else
1811 	    anchor = cursor;
1812 	selstart = TQMIN( anchor, pos );
1813 	selend = TQMAX( anchor, pos );
1814     } else {
1815 	selstart = selend = 0;
1816     }
1817     if ( fullUpdate ) {
1818 	cursor = pos;
1819 	q->update();
1820     } else {
1821 	setCursorVisible( FALSE );
1822 	cursor = pos;
1823 	setCursorVisible( TRUE );
1824     }
1825     updateMicroFocusHint();
1826     if ( mark ) {
1827 	if( !q->style().styleHint( TQStyle::SH_BlinkCursorWhenTextSelected ))
1828 	    setCursorVisible( FALSE );
1829 	emit q->selectionChanged();
1830     }
1831 }
1832 
1833 void SecTQLineEditPrivate::finishChange( int validateFromState, bool setModified )
1834 {
1835     bool lineDirty = selDirty;
1836     if ( textDirty ) {
1837 	if ( validateFromState >= 0 ) {
1838 #ifndef SECURE_NO_UNDO
1839 	    undo( validateFromState );
1840 #endif /* SECURE_NO_UNDO */
1841 	    history.resize( undoState );
1842 	    textDirty = setModified = FALSE;
1843 	}
1844 	updateTextLayout();
1845 	updateMicroFocusHint();
1846 	lineDirty |= textDirty;
1847 	if ( setModified )
1848 	    modified = TRUE;
1849 	if ( textDirty ) {
1850 	    textDirty = FALSE;
1851 	    emit q->textChanged( text );
1852 	}
1853         emit q->textModified( text );
1854 #if defined(QT_ACCESSIBILITY_SUPPORT)
1855 	TQAccessible::updateAccessibility( q, 0, TQAccessible::ValueChanged );
1856 #endif
1857     }
1858     if ( selDirty ) {
1859 	selDirty = FALSE;
1860 	emit q->selectionChanged();
1861     }
1862     if ( lineDirty || !setModified )
1863 	q->update();
1864 }
1865 
1866 void SecTQLineEditPrivate::setText( const SecTQString& txt )
1867 {
1868     deselect();
1869     SecTQString oldText = text;
1870     text = txt.isEmpty() ? SecTQString ("") : txt.left( maxLength );
1871     history.clear();
1872     undoState = 0;
1873     cursor = text.length();
1874     textDirty = 1; // Err on safe side.
1875 }
1876 
1877 
1878 void SecTQLineEditPrivate::setCursorVisible( bool visible )
1879 {
1880     if ( (bool)cursorVisible == visible )
1881 	return;
1882     if ( cursorTimer )
1883 	cursorVisible = visible;
1884     TQRect r = cursorRect();
1885     if ( !q->contentsRect().contains( r ) )
1886 	q->update();
1887     else
1888 	q->update( r );
1889 }
1890 
1891 #ifndef SECURE_NO_UNDO
1892 
1893 void SecTQLineEditPrivate::addCommand( const Command& cmd )
1894 {
1895     if ( separator && undoState && history[undoState-1].type != Separator ) {
1896 	history.resize( undoState + 2 );
1897 	history[undoState++] = Command( Separator, 0, 0 );
1898     } else {
1899 	history.resize( undoState + 1);
1900     }
1901     separator = FALSE;
1902     history[ undoState++ ] = cmd;
1903 }
1904 #endif /* SECURE_NO_UNDO */
1905 
1906 void SecTQLineEditPrivate::insert( const SecTQString& s )
1907 {
1908   int remaining = maxLength - text.length();
1909   text.insert( cursor, s.left(remaining) );
1910   for ( int i = 0; i < (int) s.left(remaining).length(); ++i )
1911     {
1912 #ifndef SECURE_NO_UNDO
1913       addCommand( Command( Insert, cursor, s.at(i) ) );
1914 #endif /* SECURE_NO_UNDO */
1915       cursor++;
1916     }
1917   textDirty = TRUE;
1918 }
1919 
1920 void SecTQLineEditPrivate::del( bool wasBackspace )
1921 {
1922     if ( cursor < (int) text.length() ) {
1923 #ifndef SECURE_NO_UNDO
1924 	addCommand ( Command( (CommandType)(wasBackspace?Remove:Delete), cursor, text.at(cursor) ) );
1925 #endif /* SECURE_NO_UNDO */
1926 	text.remove( cursor, 1 );
1927 	textDirty = TRUE;
1928     }
1929 }
1930 
1931 void SecTQLineEditPrivate::removeSelectedText()
1932 {
1933     if ( selstart < selend && selend <= (int) text.length() ) {
1934 	separate();
1935 #ifndef SECURE_NO_UNDO
1936 	int i ;
1937 	if ( selstart <= cursor && cursor < selend ) {
1938 	    // cursor is within the selection. Split up the commands
1939 	    // to be able to restore the correct cursor position
1940 	    for ( i = cursor; i >= selstart; --i )
1941 		addCommand ( Command( DeleteSelection, i, text.at(i) ) );
1942 	    for ( i = selend - 1; i > cursor; --i )
1943 		addCommand ( Command( DeleteSelection, i - cursor + selstart - 1, text.at(i) ) );
1944 	} else {
1945 	    for ( i = selend-1; i >= selstart; --i )
1946 		addCommand ( Command( RemoveSelection, i, text.at(i) ) );
1947 	}
1948 #endif /* SECURE_NO_UNDO */
1949 	text.remove( selstart, selend - selstart );
1950 	if ( cursor > selstart )
1951 	    cursor -= TQMIN( cursor, selend ) - selstart;
1952 	deselect();
1953 	textDirty = TRUE;
1954     }
1955 }
1956 
1957 #include "secqlineedit.moc"
1958