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