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

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

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 55.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
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 [email protected].
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()
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)
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();
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 o.start = m_cursor;
514 o.length = 1;
515 o.format.setBackground(m_palette.brush(QPalette::Text));
516 o.format.setForeground(m_palette.brush(QPalette::Window));
517 }
518 selections.append(o);
519 }
520
521 if (flags & DrawText)
522 m_textLayout.draw(painter, offset, selections, clip);
523
524 if (flags & DrawCursor){
525 if(!m_blinkPeriod || m_blinkStatus)
526 m_textLayout.drawCursor(painter, offset, m_cursor, m_cursorWidth);
527 }
528}
529
530/*!
531 \internal
532
533 Sets the selection to cover the word at the given cursor position.
534 The word boundries is defined by the behavior of QTextLayout::SkipWords
535 cursor mode.
536*/
537void QLineControl::selectWordAtPos(int cursor)
538{
539 int c = m_textLayout.previousCursorPosition(cursor, QTextLayout::SkipWords);
540 moveCursor(c, false);
541 // ## text layout should support end of words.
542 int end = m_textLayout.nextCursorPosition(cursor, QTextLayout::SkipWords);
543 while (end > cursor && m_text[end-1].isSpace())
544 --end;
545 moveCursor(end, true);
546}
547
548/*!
549 \internal
550
551 Completes a change to the line control text. If the change is not valid
552 will undo the line control state back to the given \a validateFromState.
553
554 If \a edited is true and the change is valid, will emit textEdited() in
555 addition to textChanged(). Otherwise only emits textChanged() on a valid
556 change.
557
558 The \a update value is currently unused.
559*/
560bool QLineControl::finishChange(int validateFromState, bool update, bool edited)
561{
562 Q_UNUSED(update)
563 bool lineDirty = m_selDirty;
564 if (m_textDirty) {
565 // do validation
566 bool wasValidInput = m_validInput;
567 m_validInput = true;
568#ifndef QT_NO_VALIDATOR
569 if (m_validator) {
570 m_validInput = false;
571 QString textCopy = m_text;
572 int cursorCopy = m_cursor;
573 m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
574 if (m_validInput) {
575 if (m_text != textCopy) {
576 internalSetText(textCopy, cursorCopy);
577 return true;
578 }
579 m_cursor = cursorCopy;
580 }
581 }
582#endif
583 if (validateFromState >= 0 && wasValidInput && !m_validInput) {
584 if (m_transactions.count())
585 return false;
586 internalUndo(validateFromState);
587 m_history.resize(m_undoState);
588 if (m_modifiedState > m_undoState)
589 m_modifiedState = -1;
590 m_validInput = true;
591 m_textDirty = false;
592 }
593 updateDisplayText();
594 lineDirty |= m_textDirty;
595 if (m_textDirty) {
596 m_textDirty = false;
597 QString actualText = text();
598 if (edited)
599 emit textEdited(actualText);
600 emit textChanged(actualText);
601 }
602 }
603 if (m_selDirty) {
604 m_selDirty = false;
605 emit selectionChanged();
606 }
607 emitCursorPositionChanged();
608 return true;
609}
610
611/*!
612 \internal
613
614 An internal function for setting the text of the line control.
615*/
616void QLineControl::internalSetText(const QString &txt, int pos, bool edited)
617{
618 internalDeselect();
619 emit resetInputContext();
620 QString oldText = m_text;
621 if (m_maskData) {
622 m_text = maskString(0, txt, true);
623 m_text += clearString(m_text.length(), m_maxLength - m_text.length());
624 } else {
625 m_text = txt.isEmpty() ? txt : txt.left(m_maxLength);
626 }
627 m_history.clear();
628 m_modifiedState = m_undoState = 0;
629 m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos;
630 m_textDirty = (oldText != m_text);
631 finishChange(-1, true, edited);
632}
633
634
635/*!
636 \internal
637
638 Adds the given \a command to the undo history
639 of the line control. Does not apply the command.
640*/
641void QLineControl::addCommand(const Command &cmd)
642{
643 if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) {
644 m_history.resize(m_undoState + 2);
645 m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend);
646 } else {
647 m_history.resize(m_undoState + 1);
648 }
649 m_separator = false;
650 m_history[m_undoState++] = cmd;
651}
652
653/*!
654 \internal
655
656 Inserts the given string \a s into the line
657 control.
658
659 Also adds the appropriate commands into the undo history.
660 This function does not call finishChange(), and may leave the text
661 in an invalid state.
662*/
663void QLineControl::internalInsert(const QString &s)
664{
665 if (hasSelectedText())
666 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
667 if (m_maskData) {
668 QString ms = maskString(m_cursor, s);
669 for (int i = 0; i < (int) ms.length(); ++i) {
670 addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1));
671 addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1));
672 }
673 m_text.replace(m_cursor, ms.length(), ms);
674 m_cursor += ms.length();
675 m_cursor = nextMaskBlank(m_cursor);
676 m_textDirty = true;
677 } else {
678 int remaining = m_maxLength - m_text.length();
679 if (remaining != 0) {
680 m_text.insert(m_cursor, s.left(remaining));
681 for (int i = 0; i < (int) s.left(remaining).length(); ++i)
682 addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1));
683 m_textDirty = true;
684 }
685 }
686}
687
688/*!
689 \internal
690
691 deletes a single character from the current text. If \a wasBackspace,
692 the character prior to the cursor is removed. Otherwise the character
693 after the cursor is removed.
694
695 Also adds the appropriate commands into the undo history.
696 This function does not call finishChange(), and may leave the text
697 in an invalid state.
698*/
699void QLineControl::internalDelete(bool wasBackspace)
700{
701 if (m_cursor < (int) m_text.length()) {
702 if (hasSelectedText())
703 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
704 addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)),
705 m_cursor, m_text.at(m_cursor), -1, -1));
706 if (m_maskData) {
707 m_text.replace(m_cursor, 1, clearString(m_cursor, 1));
708 addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1));
709 } else {
710 m_text.remove(m_cursor, 1);
711 }
712 m_textDirty = true;
713 }
714}
715
716/*!
717 \internal
718
719 removes the currently selected text from the line control.
720
721 Also adds the appropriate commands into the undo history.
722 This function does not call finishChange(), and may leave the text
723 in an invalid state.
724*/
725void QLineControl::removeSelectedText()
726{
727 if (m_selstart < m_selend && m_selend <= (int) m_text.length()) {
728 separate();
729 int i ;
730 addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
731 if (m_selstart <= m_cursor && m_cursor < m_selend) {
732 // cursor is within the selection. Split up the commands
733 // to be able to restore the correct cursor position
734 for (i = m_cursor; i >= m_selstart; --i)
735 addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1));
736 for (i = m_selend - 1; i > m_cursor; --i)
737 addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1));
738 } else {
739 for (i = m_selend-1; i >= m_selstart; --i)
740 addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1));
741 }
742 if (m_maskData) {
743 m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart));
744 for (int i = 0; i < m_selend - m_selstart; ++i)
745 addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1));
746 } else {
747 m_text.remove(m_selstart, m_selend - m_selstart);
748 }
749 if (m_cursor > m_selstart)
750 m_cursor -= qMin(m_cursor, m_selend) - m_selstart;
751 internalDeselect();
752 m_textDirty = true;
753 }
754}
755
756/*!
757 \internal
758
759 Parses the input mask specified by \a maskFields to generate
760 the mask data used to handle input masks.
761*/
762void QLineControl::parseInputMask(const QString &maskFields)
763{
764 int delimiter = maskFields.indexOf(QLatin1Char(';'));
765 if (maskFields.isEmpty() || delimiter == 0) {
766 if (m_maskData) {
767 delete [] m_maskData;
768 m_maskData = 0;
769 m_maxLength = 32767;
770 internalSetText(QString());
771 }
772 return;
773 }
774
775 if (delimiter == -1) {
776 m_blank = QLatin1Char(' ');
777 m_inputMask = maskFields;
778 } else {
779 m_inputMask = maskFields.left(delimiter);
780 m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' ');
781 }
782
783 // calculate m_maxLength / m_maskData length
784 m_maxLength = 0;
785 QChar c = 0;
786 for (int i=0; i<m_inputMask.length(); i++) {
787 c = m_inputMask.at(i);
788 if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) {
789 m_maxLength++;
790 continue;
791 }
792 if (c != QLatin1Char('\\') && c != QLatin1Char('!') &&
793 c != QLatin1Char('<') && c != QLatin1Char('>') &&
794 c != QLatin1Char('{') && c != QLatin1Char('}') &&
795 c != QLatin1Char('[') && c != QLatin1Char(']'))
796 m_maxLength++;
797 }
798
799 delete [] m_maskData;
800 m_maskData = new MaskInputData[m_maxLength];
801
802 MaskInputData::Casemode m = MaskInputData::NoCaseMode;
803 c = 0;
804 bool s;
805 bool escape = false;
806 int index = 0;
807 for (int i = 0; i < m_inputMask.length(); i++) {
808 c = m_inputMask.at(i);
809 if (escape) {
810 s = true;
811 m_maskData[index].maskChar = c;
812 m_maskData[index].separator = s;
813 m_maskData[index].caseMode = m;
814 index++;
815 escape = false;
816 } else if (c == QLatin1Char('<')) {
817 m = MaskInputData::Lower;
818 } else if (c == QLatin1Char('>')) {
819 m = MaskInputData::Upper;
820 } else if (c == QLatin1Char('!')) {
821 m = MaskInputData::NoCaseMode;
822 } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) {
823 switch (c.unicode()) {
824 case 'A':
825 case 'a':
826 case 'N':
827 case 'n':
828 case 'X':
829 case 'x':
830 case '9':
831 case '0':
832 case 'D':
833 case 'd':
834 case '#':
835 case 'H':
836 case 'h':
837 case 'B':
838 case 'b':
839 s = false;
840 break;
841 case '\\':
842 escape = true;
843 default:
844 s = true;
845 break;
846 }
847
848 if (!escape) {
849 m_maskData[index].maskChar = c;
850 m_maskData[index].separator = s;
851 m_maskData[index].caseMode = m;
852 index++;
853 }
854 }
855 }
856 internalSetText(m_text);
857}
858
859
860/*!
861 \internal
862
863 checks if the key is valid compared to the inputMask
864*/
865bool QLineControl::isValidInput(QChar key, QChar mask) const
866{
867 switch (mask.unicode()) {
868 case 'A':
869 if (key.isLetter())
870 return true;
871 break;
872 case 'a':
873 if (key.isLetter() || key == m_blank)
874 return true;
875 break;
876 case 'N':
877 if (key.isLetterOrNumber())
878 return true;
879 break;
880 case 'n':
881 if (key.isLetterOrNumber() || key == m_blank)
882 return true;
883 break;
884 case 'X':
885 if (key.isPrint())
886 return true;
887 break;
888 case 'x':
889 if (key.isPrint() || key == m_blank)
890 return true;
891 break;
892 case '9':
893 if (key.isNumber())
894 return true;
895 break;
896 case '0':
897 if (key.isNumber() || key == m_blank)
898 return true;
899 break;
900 case 'D':
901 if (key.isNumber() && key.digitValue() > 0)
902 return true;
903 break;
904 case 'd':
905 if ((key.isNumber() && key.digitValue() > 0) || key == m_blank)
906 return true;
907 break;
908 case '#':
909 if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank)
910 return true;
911 break;
912 case 'B':
913 if (key == QLatin1Char('0') || key == QLatin1Char('1'))
914 return true;
915 break;
916 case 'b':
917 if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank)
918 return true;
919 break;
920 case 'H':
921 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')))
922 return true;
923 break;
924 case 'h':
925 if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank)
926 return true;
927 break;
928 default:
929 break;
930 }
931 return false;
932}
933
934/*!
935 \internal
936
937 Returns true if the given text \a str is valid for any
938 validator or input mask set for the line control.
939
940 Otherwise returns false
941*/
942bool QLineControl::hasAcceptableInput(const QString &str) const
943{
944#ifndef QT_NO_VALIDATOR
945 QString textCopy = str;
946 int cursorCopy = m_cursor;
947 if (m_validator && m_validator->validate(textCopy, cursorCopy)
948 != QValidator::Acceptable)
949 return false;
950#endif
951
952 if (!m_maskData)
953 return true;
954
955 if (str.length() != m_maxLength)
956 return false;
957
958 for (int i=0; i < m_maxLength; ++i) {
959 if (m_maskData[i].separator) {
960 if (str.at(i) != m_maskData[i].maskChar)
961 return false;
962 } else {
963 if (!isValidInput(str.at(i), m_maskData[i].maskChar))
964 return false;
965 }
966 }
967 return true;
968}
969
970/*!
971 \internal
972
973 Applies the inputMask on \a str starting from position \a pos in the mask. \a clear
974 specifies from where characters should be gotten when a separator is met in \a str - true means
975 that blanks will be used, false that previous input is used.
976 Calling this when no inputMask is set is undefined.
977*/
978QString QLineControl::maskString(uint pos, const QString &str, bool clear) const
979{
980 if (pos >= (uint)m_maxLength)
981 return QString::fromLatin1("");
982
983 QString fill;
984 fill = clear ? clearString(0, m_maxLength) : m_text;
985
986 int strIndex = 0;
987 QString s = QString::fromLatin1("");
988 int i = pos;
989 while (i < m_maxLength) {
990 if (strIndex < str.length()) {
991 if (m_maskData[i].separator) {
992 s += m_maskData[i].maskChar;
993 if (str[(int)strIndex] == m_maskData[i].maskChar)
994 strIndex++;
995 ++i;
996 } else {
997 if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) {
998 switch (m_maskData[i].caseMode) {
999 case MaskInputData::Upper:
1000 s += str[(int)strIndex].toUpper();
1001 break;
1002 case MaskInputData::Lower:
1003 s += str[(int)strIndex].toLower();
1004 break;
1005 default:
1006 s += str[(int)strIndex];
1007 }
1008 ++i;
1009 } else {
1010 // search for separator first
1011 int n = findInMask(i, true, true, str[(int)strIndex]);
1012 if (n != -1) {
1013 if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) {
1014 s += fill.mid(i, n-i+1);
1015 i = n + 1; // update i to find + 1
1016 }
1017 } else {
1018 // search for valid m_blank if not
1019 n = findInMask(i, true, false, str[(int)strIndex]);
1020 if (n != -1) {
1021 s += fill.mid(i, n-i);
1022 switch (m_maskData[n].caseMode) {
1023 case MaskInputData::Upper:
1024 s += str[(int)strIndex].toUpper();
1025 break;
1026 case MaskInputData::Lower:
1027 s += str[(int)strIndex].toLower();
1028 break;
1029 default:
1030 s += str[(int)strIndex];
1031 }
1032 i = n + 1; // updates i to find + 1
1033 }
1034 }
1035 }
1036 ++strIndex;
1037 }
1038 } else
1039 break;
1040 }
1041
1042 return s;
1043}
1044
1045
1046
1047/*!
1048 \internal
1049
1050 Returns a "cleared" string with only separators and blank chars.
1051 Calling this when no inputMask is set is undefined.
1052*/
1053QString QLineControl::clearString(uint pos, uint len) const
1054{
1055 if (pos >= (uint)m_maxLength)
1056 return QString();
1057
1058 QString s;
1059 int end = qMin((uint)m_maxLength, pos + len);
1060 for (int i = pos; i < end; ++i)
1061 if (m_maskData[i].separator)
1062 s += m_maskData[i].maskChar;
1063 else
1064 s += m_blank;
1065
1066 return s;
1067}
1068
1069/*!
1070 \internal
1071
1072 Strips blank parts of the input in a QLineControl when an inputMask is set,
1073 separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1".
1074*/
1075QString QLineControl::stripString(const QString &str) const
1076{
1077 if (!m_maskData)
1078 return str;
1079
1080 QString s;
1081 int end = qMin(m_maxLength, (int)str.length());
1082 for (int i = 0; i < end; ++i)
1083 if (m_maskData[i].separator)
1084 s += m_maskData[i].maskChar;
1085 else
1086 if (str[i] != m_blank)
1087 s += str[i];
1088
1089 return s;
1090}
1091
1092/*!
1093 \internal
1094 searches forward/backward in m_maskData for either a separator or a m_blank
1095*/
1096int QLineControl::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const
1097{
1098 if (pos >= m_maxLength || pos < 0)
1099 return -1;
1100
1101 int end = forward ? m_maxLength : -1;
1102 int step = forward ? 1 : -1;
1103 int i = pos;
1104
1105 while (i != end) {
1106 if (findSeparator) {
1107 if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar)
1108 return i;
1109 } else {
1110 if (!m_maskData[i].separator) {
1111 if (searchChar.isNull())
1112 return i;
1113 else if (isValidInput(searchChar, m_maskData[i].maskChar))
1114 return i;
1115 }
1116 }
1117 i += step;
1118 }
1119 return -1;
1120}
1121
1122void QLineControl::internalUndo(int until)
1123{
1124 if (!isUndoAvailable())
1125 return;
1126 internalDeselect();
1127 while (m_undoState && m_undoState > until) {
1128 Command& cmd = m_history[--m_undoState];
1129 switch (cmd.type) {
1130 case Insert:
1131 m_text.remove(cmd.pos, 1);
1132 m_cursor = cmd.pos;
1133 break;
1134 case SetSelection:
1135 m_selstart = cmd.selStart;
1136 m_selend = cmd.selEnd;
1137 m_cursor = cmd.pos;
1138 break;
1139 case Remove:
1140 case RemoveSelection:
1141 m_text.insert(cmd.pos, cmd.uc);
1142 m_cursor = cmd.pos + 1;
1143 break;
1144 case Delete:
1145 case DeleteSelection:
1146 m_text.insert(cmd.pos, cmd.uc);
1147 m_cursor = cmd.pos;
1148 break;
1149 case Separator:
1150 continue;
1151 }
1152 if (until < 0 && m_undoState) {
1153 Command& next = m_history[m_undoState-1];
1154 if (next.type != cmd.type && next.type < RemoveSelection
1155 && (cmd.type < RemoveSelection || next.type == Separator))
1156 break;
1157 }
1158 }
1159 m_textDirty = true;
1160 emitCursorPositionChanged();
1161}
1162
1163void QLineControl::internalRedo()
1164{
1165 if (!isRedoAvailable())
1166 return;
1167 internalDeselect();
1168 while (m_undoState < (int)m_history.size()) {
1169 Command& cmd = m_history[m_undoState++];
1170 switch (cmd.type) {
1171 case Insert:
1172 m_text.insert(cmd.pos, cmd.uc);
1173 m_cursor = cmd.pos + 1;
1174 break;
1175 case SetSelection:
1176 m_selstart = cmd.selStart;
1177 m_selend = cmd.selEnd;
1178 m_cursor = cmd.pos;
1179 break;
1180 case Remove:
1181 case Delete:
1182 case RemoveSelection:
1183 case DeleteSelection:
1184 m_text.remove(cmd.pos, 1);
1185 m_selstart = cmd.selStart;
1186 m_selend = cmd.selEnd;
1187 m_cursor = cmd.pos;
1188 break;
1189 case Separator:
1190 m_selstart = cmd.selStart;
1191 m_selend = cmd.selEnd;
1192 m_cursor = cmd.pos;
1193 break;
1194 }
1195 if (m_undoState < (int)m_history.size()) {
1196 Command& next = m_history[m_undoState];
1197 if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator
1198 && (next.type < RemoveSelection || cmd.type == Separator))
1199 break;
1200 }
1201 }
1202 m_textDirty = true;
1203 emitCursorPositionChanged();
1204}
1205
1206/*!
1207 \internal
1208
1209 If the current cursor position differs from the last emited cursor
1210 position, emits cursorPositionChanged().
1211*/
1212void QLineControl::emitCursorPositionChanged()
1213{
1214 if (m_cursor != m_lastCursorPos) {
1215 const int oldLast = m_lastCursorPos;
1216 m_lastCursorPos = m_cursor;
1217 cursorPositionChanged(oldLast, m_cursor);
1218 }
1219}
1220
1221#ifndef QT_NO_COMPLETER
1222// iterating forward(dir=1)/backward(dir=-1) from the
1223// current row based. dir=0 indicates a new completion prefix was set.
1224bool QLineControl::advanceToEnabledItem(int dir)
1225{
1226 int start = m_completer->currentRow();
1227 if (start == -1)
1228 return false;
1229 int i = start + dir;
1230 if (dir == 0) dir = 1;
1231 do {
1232 if (!m_completer->setCurrentRow(i)) {
1233 if (!m_completer->wrapAround())
1234 break;
1235 i = i > 0 ? 0 : m_completer->completionCount() - 1;
1236 } else {
1237 QModelIndex currentIndex = m_completer->currentIndex();
1238 if (m_completer->completionModel()->flags(currentIndex) & Qt::ItemIsEnabled)
1239 return true;
1240 i += dir;
1241 }
1242 } while (i != start);
1243
1244 m_completer->setCurrentRow(start); // restore
1245 return false;
1246}
1247
1248void QLineControl::complete(int key)
1249{
1250 if (!m_completer || isReadOnly() || echoMode() != QLineEdit::Normal)
1251 return;
1252
1253 QString text = this->text();
1254 if (m_completer->completionMode() == QCompleter::InlineCompletion) {
1255 if (key == Qt::Key_Backspace)
1256 return;
1257 int n = 0;
1258 if (key == Qt::Key_Up || key == Qt::Key_Down) {
1259 if (textAfterSelection().length())
1260 return;
1261 QString prefix = hasSelectedText() ? textBeforeSelection()
1262 : text;
1263 if (text.compare(m_completer->currentCompletion(), m_completer->caseSensitivity()) != 0
1264 || prefix.compare(m_completer->completionPrefix(), m_completer->caseSensitivity()) != 0) {
1265 m_completer->setCompletionPrefix(prefix);
1266 } else {
1267 n = (key == Qt::Key_Up) ? -1 : +1;
1268 }
1269 } else {
1270 m_completer->setCompletionPrefix(text);
1271 }
1272 if (!advanceToEnabledItem(n))
1273 return;
1274 } else {
1275#ifndef QT_KEYPAD_NAVIGATION
1276 if (text.isEmpty()) {
1277 m_completer->popup()->hide();
1278 return;
1279 }
1280#endif
1281 m_completer->setCompletionPrefix(text);
1282 }
1283
1284 m_completer->complete();
1285}
1286#endif
1287
1288void QLineControl::setCursorBlinkPeriod(int msec)
1289{
1290 if (msec == m_blinkPeriod)
1291 return;
1292 if (m_blinkTimer) {
1293 killTimer(m_blinkTimer);
1294 }
1295 if (msec) {
1296 m_blinkTimer = startTimer(msec / 2);
1297 m_blinkStatus = 1;
1298 } else {
1299 m_blinkTimer = 0;
1300 if (m_blinkStatus == 1)
1301 emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect());
1302 }
1303 m_blinkPeriod = msec;
1304}
1305
1306void QLineControl::timerEvent(QTimerEvent *event)
1307{
1308 if (event->timerId() == m_blinkTimer) {
1309 m_blinkStatus = !m_blinkStatus;
1310 emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect());
1311 } else if (event->timerId() == m_deleteAllTimer) {
1312 killTimer(m_deleteAllTimer);
1313 m_deleteAllTimer = 0;
1314 clear();
1315 } else if (event->timerId() == m_tripleClickTimer) {
1316 killTimer(m_tripleClickTimer);
1317 m_tripleClickTimer = 0;
1318 }
1319}
1320
1321bool QLineControl::processEvent(QEvent* ev)
1322{
1323#ifdef QT_KEYPAD_NAVIGATION
1324 if (QApplication::keypadNavigationEnabled()) {
1325 if ((ev->type() == QEvent::KeyPress) || (ev->type() == QEvent::KeyRelease)) {
1326 QKeyEvent *ke = (QKeyEvent *)ev;
1327 if (ke->key() == Qt::Key_Back) {
1328 if (ke->isAutoRepeat()) {
1329 // Swallow it. We don't want back keys running amok.
1330 ke->accept();
1331 return true;
1332 }
1333 if ((ev->type() == QEvent::KeyRelease)
1334 && !isReadOnly()
1335 && m_deleteAllTimer) {
1336 killTimer(m_deleteAllTimer);
1337 m_deleteAllTimer = 0;
1338 backspace();
1339 ke->accept();
1340 return true;
1341 }
1342 }
1343 }
1344 }
1345#endif
1346 switch(ev->type()){
1347#ifndef QT_NO_GRAPHICSVIEW
1348 case QEvent::GraphicsSceneMouseMove:
1349 case QEvent::GraphicsSceneMouseRelease:
1350 case QEvent::GraphicsSceneMousePress:{
1351 QGraphicsSceneMouseEvent *gvEv = static_cast<QGraphicsSceneMouseEvent*>(ev);
1352 QMouseEvent* mouse = new QMouseEvent(ev->type(),
1353 gvEv->pos().toPoint(), gvEv->button(), gvEv->buttons(), gvEv->modifiers());
1354 processMouseEvent(mouse); break;
1355 }
1356#endif
1357 case QEvent::MouseButtonPress:
1358 case QEvent::MouseButtonRelease:
1359 case QEvent::MouseButtonDblClick:
1360 case QEvent::MouseMove:
1361 processMouseEvent(static_cast<QMouseEvent*>(ev)); break;
1362 case QEvent::KeyPress:
1363 case QEvent::KeyRelease:
1364 processKeyEvent(static_cast<QKeyEvent*>(ev)); break;
1365 case QEvent::InputMethod:
1366 processInputMethodEvent(static_cast<QInputMethodEvent*>(ev)); break;
1367#ifndef QT_NO_SHORTCUT
1368 case QEvent::ShortcutOverride:{
1369 QKeyEvent* ke = static_cast<QKeyEvent*>(ev);
1370 if (ke == QKeySequence::Copy
1371 || ke == QKeySequence::Paste
1372 || ke == QKeySequence::Cut
1373 || ke == QKeySequence::Redo
1374 || ke == QKeySequence::Undo
1375 || ke == QKeySequence::MoveToNextWord
1376 || ke == QKeySequence::MoveToPreviousWord
1377 || ke == QKeySequence::MoveToStartOfDocument
1378 || ke == QKeySequence::MoveToEndOfDocument
1379 || ke == QKeySequence::SelectNextWord
1380 || ke == QKeySequence::SelectPreviousWord
1381 || ke == QKeySequence::SelectStartOfLine
1382 || ke == QKeySequence::SelectEndOfLine
1383 || ke == QKeySequence::SelectStartOfBlock
1384 || ke == QKeySequence::SelectEndOfBlock
1385 || ke == QKeySequence::SelectStartOfDocument
1386 || ke == QKeySequence::SelectAll
1387 || ke == QKeySequence::SelectEndOfDocument) {
1388 ke->accept();
1389 } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
1390 || ke->modifiers() == Qt::KeypadModifier) {
1391 if (ke->key() < Qt::Key_Escape) {
1392 ke->accept();
1393 } else {
1394 switch (ke->key()) {
1395 case Qt::Key_Delete:
1396 case Qt::Key_Home:
1397 case Qt::Key_End:
1398 case Qt::Key_Backspace:
1399 case Qt::Key_Left:
1400 case Qt::Key_Right:
1401 ke->accept();
1402 default:
1403 break;
1404 }
1405 }
1406 }
1407 }
1408#endif
1409 default:
1410 return false;
1411 }
1412 return true;
1413}
1414
1415void QLineControl::processMouseEvent(QMouseEvent* ev)
1416{
1417
1418 switch (ev->type()) {
1419 case QEvent::GraphicsSceneMousePress:
1420 case QEvent::MouseButtonPress:{
1421 if (m_tripleClickTimer
1422 && (ev->pos() - m_tripleClick).manhattanLength()
1423 < QApplication::startDragDistance()) {
1424 selectAll();
1425 return;
1426 }
1427 if (ev->button() == Qt::RightButton)
1428 return;
1429
1430 bool mark = ev->modifiers() & Qt::ShiftModifier;
1431 int cursor = xToPos(ev->pos().x());
1432 moveCursor(cursor, mark);
1433 break;
1434 }
1435 case QEvent::MouseButtonDblClick:
1436 if (ev->button() == Qt::LeftButton) {
1437 selectWordAtPos(xToPos(ev->pos().x()));
1438 if (m_tripleClickTimer)
1439 killTimer(m_tripleClickTimer);
1440 m_tripleClickTimer = startTimer(QApplication::doubleClickInterval());
1441 m_tripleClick = ev->pos();
1442 }
1443 break;
1444 case QEvent::GraphicsSceneMouseRelease:
1445 case QEvent::MouseButtonRelease:
1446#ifndef QT_NO_CLIPBOARD
1447 if (QApplication::clipboard()->supportsSelection()) {
1448 if (ev->button() == Qt::LeftButton) {
1449 copy(QClipboard::Selection);
1450 } else if (!isReadOnly() && ev->button() == Qt::MidButton) {
1451 deselect();
1452 insert(QApplication::clipboard()->text(QClipboard::Selection));
1453 }
1454 }
1455#endif
1456 break;
1457 case QEvent::GraphicsSceneMouseMove:
1458 case QEvent::MouseMove:
1459 if (ev->buttons() & Qt::LeftButton) {
1460 moveCursor(xToPos(ev->pos().x()), true);
1461 }
1462 break;
1463 default:
1464 break;
1465 }
1466}
1467
1468void QLineControl::processKeyEvent(QKeyEvent* event)
1469{
1470 bool inlineCompletionAccepted = false;
1471
1472#ifndef QT_NO_COMPLETER
1473 if (m_completer) {
1474 QCompleter::CompletionMode completionMode = m_completer->completionMode();
1475 if ((completionMode == QCompleter::PopupCompletion
1476 || completionMode == QCompleter::UnfilteredPopupCompletion)
1477 && m_completer->popup()
1478 && m_completer->popup()->isVisible()) {
1479 // The following keys are forwarded by the completer to the widget
1480 // Ignoring the events lets the completer provide suitable default behavior
1481 switch (event->key()) {
1482 case Qt::Key_Escape:
1483 event->ignore();
1484 return;
1485 case Qt::Key_Enter:
1486 case Qt::Key_Return:
1487 case Qt::Key_F4:
1488#ifdef QT_KEYPAD_NAVIGATION
1489 case Qt::Key_Select:
1490 if (!QApplication::keypadNavigationEnabled())
1491 break;
1492#endif
1493 m_completer->popup()->hide(); // just hide. will end up propagating to parent
1494 default:
1495 break; // normal key processing
1496 }
1497 } else if (completionMode == QCompleter::InlineCompletion) {
1498 switch (event->key()) {
1499 case Qt::Key_Enter:
1500 case Qt::Key_Return:
1501 case Qt::Key_F4:
1502#ifdef QT_KEYPAD_NAVIGATION
1503 case Qt::Key_Select:
1504 if (!QApplication::keypadNavigationEnabled())
1505 break;
1506#endif
1507 if (!m_completer->currentCompletion().isEmpty() && hasSelectedText()
1508 && textAfterSelection().isEmpty()) {
1509 setText(m_completer->currentCompletion());
1510 inlineCompletionAccepted = true;
1511 }
1512 default:
1513 break; // normal key processing
1514 }
1515 }
1516 }
1517#endif // QT_NO_COMPLETER
1518
1519 if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
1520 if (hasAcceptableInput() || fixup()) {
1521 emit accepted();
1522 emit editingFinished();
1523 }
1524 if (inlineCompletionAccepted)
1525 event->accept();
1526 else
1527 event->ignore();
1528 return;
1529 }
1530
1531 if (echoMode() == QLineEdit::PasswordEchoOnEdit
1532 && !passwordEchoEditing()
1533 && !isReadOnly()
1534 && !event->text().isEmpty()
1535#ifdef QT_KEYPAD_NAVIGATION
1536 && event->key() != Qt::Key_Select
1537 && event->key() != Qt::Key_Up
1538 && event->key() != Qt::Key_Down
1539 && event->key() != Qt::Key_Back
1540#endif
1541 && !(event->modifiers() & Qt::ControlModifier)) {
1542 // Clear the edit and reset to normal echo mode while editing; the
1543 // echo mode switches back when the edit loses focus
1544 // ### resets current content. dubious code; you can
1545 // navigate with keys up, down, back, and select(?), but if you press
1546 // "left" or "right" it clears?
1547 updatePasswordEchoEditing(true);
1548 clear();
1549 }
1550
1551 bool unknown = false;
1552
1553 if (false) {
1554 }
1555#ifndef QT_NO_SHORTCUT
1556 else if (event == QKeySequence::Undo) {
1557 if (!isReadOnly())
1558 undo();
1559 }
1560 else if (event == QKeySequence::Redo) {
1561 if (!isReadOnly())
1562 redo();
1563 }
1564 else if (event == QKeySequence::SelectAll) {
1565 selectAll();
1566 }
1567#ifndef QT_NO_CLIPBOARD
1568 else if (event == QKeySequence::Copy) {
1569 copy();
1570 }
1571 else if (event == QKeySequence::Paste) {
1572 if (!isReadOnly())
1573 paste();
1574 }
1575 else if (event == QKeySequence::Cut) {
1576 if (!isReadOnly()) {
1577 copy();
1578 del();
1579 }
1580 }
1581 else if (event == QKeySequence::DeleteEndOfLine) {
1582 if (!isReadOnly()) {
1583 setSelection(cursor(), end());
1584 copy();
1585 del();
1586 }
1587 }
1588#endif //QT_NO_CLIPBOARD
1589 else if (event == QKeySequence::MoveToStartOfLine || event == QKeySequence::MoveToStartOfBlock) {
1590 home(0);
1591 }
1592 else if (event == QKeySequence::MoveToEndOfLine || event == QKeySequence::MoveToEndOfBlock) {
1593 end(0);
1594 }
1595 else if (event == QKeySequence::SelectStartOfLine || event == QKeySequence::SelectStartOfBlock) {
1596 home(1);
1597 }
1598 else if (event == QKeySequence::SelectEndOfLine || event == QKeySequence::SelectEndOfBlock) {
1599 end(1);
1600 }
1601 else if (event == QKeySequence::MoveToNextChar) {
1602#if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER)
1603 if (hasSelectedText()) {
1604#else
1605 if (hasSelectedText() && m_completer
1606 && m_completer->completionMode() == QCompleter::InlineCompletion) {
1607#endif
1608 moveCursor(selectionEnd(), false);
1609 } else {
1610 cursorForward(0, layoutDirection() == Qt::LeftToRight ? 1 : -1);
1611 }
1612 }
1613 else if (event == QKeySequence::SelectNextChar) {
1614 cursorForward(1, layoutDirection() == Qt::LeftToRight ? 1 : -1);
1615 }
1616 else if (event == QKeySequence::MoveToPreviousChar) {
1617#if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER)
1618 if (hasSelectedText()) {
1619#else
1620 if (hasSelectedText() && m_completer
1621 && m_completer->completionMode() == QCompleter::InlineCompletion) {
1622#endif
1623 moveCursor(selectionStart(), false);
1624 } else {
1625 cursorForward(0, layoutDirection() == Qt::LeftToRight ? -1 : 1);
1626 }
1627 }
1628 else if (event == QKeySequence::SelectPreviousChar) {
1629 cursorForward(1, layoutDirection() == Qt::LeftToRight ? -1 : 1);
1630 }
1631 else if (event == QKeySequence::MoveToNextWord) {
1632 if (echoMode() == QLineEdit::Normal)
1633 layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0);
1634 else
1635 layoutDirection() == Qt::LeftToRight ? end(0) : home(0);
1636 }
1637 else if (event == QKeySequence::MoveToPreviousWord) {
1638 if (echoMode() == QLineEdit::Normal)
1639 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0);
1640 else if (!isReadOnly()) {
1641 layoutDirection() == Qt::LeftToRight ? home(0) : end(0);
1642 }
1643 }
1644 else if (event == QKeySequence::SelectNextWord) {
1645 if (echoMode() == QLineEdit::Normal)
1646 layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1);
1647 else
1648 layoutDirection() == Qt::LeftToRight ? end(1) : home(1);
1649 }
1650 else if (event == QKeySequence::SelectPreviousWord) {
1651 if (echoMode() == QLineEdit::Normal)
1652 layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1);
1653 else
1654 layoutDirection() == Qt::LeftToRight ? home(1) : end(1);
1655 }
1656 else if (event == QKeySequence::Delete) {
1657 if (!isReadOnly())
1658 del();
1659 }
1660 else if (event == QKeySequence::DeleteEndOfWord) {
1661 if (!isReadOnly()) {
1662 cursorWordForward(true);
1663 del();
1664 }
1665 }
1666 else if (event == QKeySequence::DeleteStartOfWord) {
1667 if (!isReadOnly()) {
1668 cursorWordBackward(true);
1669 del();
1670 }
1671 }
1672#endif // QT_NO_SHORTCUT
1673 else {
1674 bool handled = false;
1675#ifdef Q_WS_MAC
1676 if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down) {
1677 Qt::KeyboardModifiers myModifiers = (event->modifiers() & ~Qt::KeypadModifier);
1678 if (myModifiers & Qt::ShiftModifier) {
1679 if (myModifiers == (Qt::ControlModifier|Qt::ShiftModifier)
1680 || myModifiers == (Qt::AltModifier|Qt::ShiftModifier)
1681 || myModifiers == Qt::ShiftModifier) {
1682
1683 event->key() == Qt::Key_Up ? home(1) : end(1);
1684 }
1685 } else {
1686 if ((myModifiers == Qt::ControlModifier
1687 || myModifiers == Qt::AltModifier
1688 || myModifiers == Qt::NoModifier)) {
1689 event->key() == Qt::Key_Up ? home(0) : end(0);
1690 }
1691 }
1692 handled = true;
1693 }
1694#endif
1695 if (event->modifiers() & Qt::ControlModifier) {
1696 switch (event->key()) {
1697 case Qt::Key_Backspace:
1698 if (!isReadOnly()) {
1699 cursorWordBackward(true);
1700 del();
1701 }
1702 break;
1703#ifndef QT_NO_COMPLETER
1704 case Qt::Key_Up:
1705 case Qt::Key_Down:
1706 complete(event->key());
1707 break;
1708#endif
1709#if defined(Q_WS_X11)
1710 case Qt::Key_E:
1711 end(0);
1712 break;
1713
1714 case Qt::Key_U:
1715 if (!isReadOnly()) {
1716 setSelection(0, text().size());
1717#ifndef QT_NO_CLIPBOARD
1718 copy();
1719#endif
1720 del();
1721 }
1722 break;
1723#endif
1724 default:
1725 if (!handled)
1726 unknown = true;
1727 }
1728 } else { // ### check for *no* modifier
1729 switch (event->key()) {
1730 case Qt::Key_Backspace:
1731 if (!isReadOnly()) {
1732 backspace();
1733#ifndef QT_NO_COMPLETER
1734 complete(Qt::Key_Backspace);
1735#endif
1736 }
1737 break;
1738#ifdef QT_KEYPAD_NAVIGATION
1739 case Qt::Key_Back:
1740 if (QApplication::keypadNavigationEnabled() && !event->isAutoRepeat()
1741 && !isReadOnly()) {
1742 if (text().length() == 0) {
1743 setText(m_cancelText);
1744
1745 if (passwordEchoEditing())
1746 updatePasswordEchoEditing(false);
1747
1748 emit editFocusChange(false);
1749 } else if (!m_deleteAllTimer) {
1750 m_deleteAllTimer = startTimer(750);
1751 }
1752 } else {
1753 unknown = true;
1754 }
1755 break;
1756#endif
1757
1758 default:
1759 if (!handled)
1760 unknown = true;
1761 }
1762 }
1763 }
1764
1765 if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) {
1766 setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
1767 unknown = false;
1768 }
1769
1770 if (unknown && !isReadOnly()) {
1771 QString t = event->text();
1772 if (!t.isEmpty() && t.at(0).isPrint()) {
1773 insert(t);
1774#ifndef QT_NO_COMPLETER
1775 complete(event->key());
1776#endif
1777 event->accept();
1778 return;
1779 }
1780 }
1781
1782 if (unknown)
1783 event->ignore();
1784 else
1785 event->accept();
1786}
1787
1788
1789QT_END_NAMESPACE
1790
1791#endif
Note: See TracBrowser for help on using the repository browser.