source: trunk/src/gui/widgets/qlinecontrol.cpp@ 769

Last change on this file since 769 was 769, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

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