1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtDeclarative module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "private/qdeclarativetextinput_p.h"
43#include "private/qdeclarativetextinput_p_p.h"
44
45#include <private/qdeclarativeglobal_p.h>
46#include <qdeclarativeinfo.h>
47
48#include <QValidator>
49#include <QTextCursor>
50#include <QApplication>
51#include <QFontMetrics>
52#include <QPainter>
53#include <QTextBoundaryFinder>
54#include <QInputContext>
55#include <qstyle.h>
56
57#ifndef QT_NO_LINEEDIT
58
59QT_BEGIN_NAMESPACE
60
61/*!
62 \qmlclass TextInput QDeclarativeTextInput
63 \ingroup qml-basic-visual-elements
64 \since 4.7
65 \brief The TextInput item displays an editable line of text.
66 \inherits Item
67
68 The TextInput element displays a single line of editable plain text.
69
70 TextInput is used to accept a line of text input. Input constraints
71 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
72 and setting \l echoMode to an appropriate value enables TextInput to be used for
73 a password input field.
74
75 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
76 If you want such bindings (on any platform), you will need to construct them in QML.
77
78 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
79*/
80QDeclarativeTextInput::QDeclarativeTextInput(QDeclarativeItem* parent)
81 : QDeclarativeImplicitSizePaintedItem(*(new QDeclarativeTextInputPrivate), parent)
82{
83 Q_D(QDeclarativeTextInput);
84 d->init();
85}
86
87QDeclarativeTextInput::~QDeclarativeTextInput()
88{
89}
90
91/*!
92 \qmlproperty string TextInput::text
93
94 The text in the TextInput.
95*/
96
97QString QDeclarativeTextInput::text() const
98{
99 Q_D(const QDeclarativeTextInput);
100 return d->control->text();
101}
102
103void QDeclarativeTextInput::setText(const QString &s)
104{
105 Q_D(QDeclarativeTextInput);
106 if(s == text())
107 return;
108 d->control->setText(s);
109}
110
111/*!
112 \qmlproperty string TextInput::font.family
113
114 Sets the family name of the font.
115
116 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
117 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
118 If the family isn't available a family will be set using the font matching algorithm.
119*/
120
121/*!
122 \qmlproperty bool TextInput::font.bold
123
124 Sets whether the font weight is bold.
125*/
126
127/*!
128 \qmlproperty enumeration TextInput::font.weight
129
130 Sets the font's weight.
131
132 The weight can be one of:
133 \list
134 \o Font.Light
135 \o Font.Normal - the default
136 \o Font.DemiBold
137 \o Font.Bold
138 \o Font.Black
139 \endlist
140
141 \qml
142 TextInput { text: "Hello"; font.weight: Font.DemiBold }
143 \endqml
144*/
145
146/*!
147 \qmlproperty bool TextInput::font.italic
148
149 Sets whether the font has an italic style.
150*/
151
152/*!
153 \qmlproperty bool TextInput::font.underline
154
155 Sets whether the text is underlined.
156*/
157
158/*!
159 \qmlproperty bool TextInput::font.strikeout
160
161 Sets whether the font has a strikeout style.
162*/
163
164/*!
165 \qmlproperty real TextInput::font.pointSize
166
167 Sets the font size in points. The point size must be greater than zero.
168*/
169
170/*!
171 \qmlproperty int TextInput::font.pixelSize
172
173 Sets the font size in pixels.
174
175 Using this function makes the font device dependent.
176 Use \c pointSize to set the size of the font in a device independent manner.
177*/
178
179/*!
180 \qmlproperty real TextInput::font.letterSpacing
181
182 Sets the letter spacing for the font.
183
184 Letter spacing changes the default spacing between individual letters in the font.
185 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
186*/
187
188/*!
189 \qmlproperty real TextInput::font.wordSpacing
190
191 Sets the word spacing for the font.
192
193 Word spacing changes the default spacing between individual words.
194 A positive value increases the word spacing by a corresponding amount of pixels,
195 while a negative value decreases the inter-word spacing accordingly.
196*/
197
198/*!
199 \qmlproperty enumeration TextInput::font.capitalization
200
201 Sets the capitalization for the text.
202
203 \list
204 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
205 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
206 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
207 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
208 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
209 \endlist
210
211 \qml
212 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
213 \endqml
214*/
215
216QFont QDeclarativeTextInput::font() const
217{
218 Q_D(const QDeclarativeTextInput);
219 return d->sourceFont;
220}
221
222void QDeclarativeTextInput::setFont(const QFont &font)
223{
224 Q_D(QDeclarativeTextInput);
225 if (d->sourceFont == font)
226 return;
227
228 d->sourceFont = font;
229 QFont oldFont = d->font;
230 d->font = font;
231 if (d->font.pointSizeF() != -1) {
232 // 0.5pt resolution
233 qreal size = qRound(d->font.pointSizeF()*2.0);
234 d->font.setPointSizeF(size/2.0);
235 }
236
237 if (oldFont != d->font) {
238 d->control->setFont(d->font);
239 updateSize();
240 updateCursorRectangle();
241 if(d->cursorItem){
242 d->cursorItem->setHeight(QFontMetrics(d->font).height());
243 }
244 }
245 emit fontChanged(d->sourceFont);
246}
247
248/*!
249 \qmlproperty color TextInput::color
250
251 The text color.
252*/
253QColor QDeclarativeTextInput::color() const
254{
255 Q_D(const QDeclarativeTextInput);
256 return d->color;
257}
258
259void QDeclarativeTextInput::setColor(const QColor &c)
260{
261 Q_D(QDeclarativeTextInput);
262 if (c != d->color) {
263 d->color = c;
264 clearCache();
265 update();
266 emit colorChanged(c);
267 }
268}
269
270
271/*!
272 \qmlproperty color TextInput::selectionColor
273
274 The text highlight color, used behind selections.
275*/
276QColor QDeclarativeTextInput::selectionColor() const
277{
278 Q_D(const QDeclarativeTextInput);
279 return d->selectionColor;
280}
281
282void QDeclarativeTextInput::setSelectionColor(const QColor &color)
283{
284 Q_D(QDeclarativeTextInput);
285 if (d->selectionColor == color)
286 return;
287
288 d->selectionColor = color;
289 QPalette p = d->control->palette();
290 p.setColor(QPalette::Highlight, d->selectionColor);
291 d->control->setPalette(p);
292 if (d->control->hasSelectedText()) {
293 clearCache();
294 update();
295 }
296 emit selectionColorChanged(color);
297}
298
299/*!
300 \qmlproperty color TextInput::selectedTextColor
301
302 The highlighted text color, used in selections.
303*/
304QColor QDeclarativeTextInput::selectedTextColor() const
305{
306 Q_D(const QDeclarativeTextInput);
307 return d->selectedTextColor;
308}
309
310void QDeclarativeTextInput::setSelectedTextColor(const QColor &color)
311{
312 Q_D(QDeclarativeTextInput);
313 if (d->selectedTextColor == color)
314 return;
315
316 d->selectedTextColor = color;
317 QPalette p = d->control->palette();
318 p.setColor(QPalette::HighlightedText, d->selectedTextColor);
319 d->control->setPalette(p);
320 if (d->control->hasSelectedText()) {
321 clearCache();
322 update();
323 }
324 emit selectedTextColorChanged(color);
325}
326
327/*!
328 \qmlproperty enumeration TextInput::horizontalAlignment
329
330 Sets the horizontal alignment of the text within the TextInput item's
331 width and height. By default, the text alignment follows the natural alignment
332 of the text, for example text that is read from left to right will be aligned to
333 the left.
334
335 TextInput does not have vertical alignment, as the natural height is
336 exactly the height of the single line of text. If you set the height
337 manually to something larger, TextInput will always be top aligned
338 vertically. You can use anchors to align it however you want within
339 another item.
340
341 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
342 \c TextInput.AlignHCenter.
343
344 When using the attached property \l {LayoutMirroring::enabled} to mirror application
345 layouts, the horizontal alignment of text will also be mirrored. However, the property
346 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
347 of TextInput, use the property \l {LayoutMirroring::enabled}.
348*/
349QDeclarativeTextInput::HAlignment QDeclarativeTextInput::hAlign() const
350{
351 Q_D(const QDeclarativeTextInput);
352 return d->hAlign;
353}
354
355void QDeclarativeTextInput::setHAlign(HAlignment align)
356{
357 Q_D(QDeclarativeTextInput);
358 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
359 d->hAlignImplicit = false;
360 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
361 updateCursorRectangle();
362 }
363}
364
365void QDeclarativeTextInput::resetHAlign()
366{
367 Q_D(QDeclarativeTextInput);
368 d->hAlignImplicit = true;
369 if (d->determineHorizontalAlignment() && isComponentComplete()) {
370 updateCursorRectangle();
371 }
372}
373
374QDeclarativeTextInput::HAlignment QDeclarativeTextInput::effectiveHAlign() const
375{
376 Q_D(const QDeclarativeTextInput);
377 QDeclarativeTextInput::HAlignment effectiveAlignment = d->hAlign;
378 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
379 switch (d->hAlign) {
380 case QDeclarativeTextInput::AlignLeft:
381 effectiveAlignment = QDeclarativeTextInput::AlignRight;
382 break;
383 case QDeclarativeTextInput::AlignRight:
384 effectiveAlignment = QDeclarativeTextInput::AlignLeft;
385 break;
386 default:
387 break;
388 }
389 }
390 return effectiveAlignment;
391}
392
393bool QDeclarativeTextInputPrivate::setHAlign(QDeclarativeTextInput::HAlignment alignment, bool forceAlign)
394{
395 Q_Q(QDeclarativeTextInput);
396 if ((hAlign != alignment || forceAlign) && alignment <= QDeclarativeTextInput::AlignHCenter) { // justify not supported
397 hAlign = alignment;
398 emit q->horizontalAlignmentChanged(alignment);
399 return true;
400 }
401 return false;
402}
403
404bool QDeclarativeTextInputPrivate::determineHorizontalAlignment()
405{
406 if (hAlignImplicit) {
407 // if no explicit alignment has been set, follow the natural layout direction of the text
408 QString text = control->text();
409 if (text.isEmpty())
410 text = control->preeditAreaText();
411 bool isRightToLeft = text.isEmpty()
412 ? QApplication::keyboardInputDirection() == Qt::RightToLeft
413 : text.isRightToLeft();
414 return setHAlign(isRightToLeft ? QDeclarativeTextInput::AlignRight : QDeclarativeTextInput::AlignLeft);
415 }
416 return false;
417}
418
419void QDeclarativeTextInputPrivate::mirrorChange()
420{
421 Q_Q(QDeclarativeTextInput);
422 if (q->isComponentComplete()) {
423 if (!hAlignImplicit && (hAlign == QDeclarativeTextInput::AlignRight || hAlign == QDeclarativeTextInput::AlignLeft)) {
424 q->updateCursorRectangle();
425 updateHorizontalScroll();
426 }
427 }
428}
429
430/*!
431 \qmlproperty bool TextInput::readOnly
432
433 Sets whether user input can modify the contents of the TextInput.
434
435 If readOnly is set to true, then user input will not affect the text
436 property. Any bindings or attempts to set the text property will still
437 work.
438*/
439
440bool QDeclarativeTextInput::isReadOnly() const
441{
442 Q_D(const QDeclarativeTextInput);
443 return d->control->isReadOnly();
444}
445
446void QDeclarativeTextInput::setReadOnly(bool ro)
447{
448 Q_D(QDeclarativeTextInput);
449 if (d->control->isReadOnly() == ro)
450 return;
451
452 setFlag(QGraphicsItem::ItemAcceptsInputMethod, !ro);
453 d->control->setReadOnly(ro);
454
455 emit readOnlyChanged(ro);
456}
457
458/*!
459 \qmlproperty int TextInput::maximumLength
460 The maximum permitted length of the text in the TextInput.
461
462 If the text is too long, it is truncated at the limit.
463
464 By default, this property contains a value of 32767.
465*/
466int QDeclarativeTextInput::maxLength() const
467{
468 Q_D(const QDeclarativeTextInput);
469 return d->control->maxLength();
470}
471
472void QDeclarativeTextInput::setMaxLength(int ml)
473{
474 Q_D(QDeclarativeTextInput);
475 if (d->control->maxLength() == ml)
476 return;
477
478 d->control->setMaxLength(ml);
479
480 emit maximumLengthChanged(ml);
481}
482
483/*!
484 \qmlproperty bool TextInput::cursorVisible
485 Set to true when the TextInput shows a cursor.
486
487 This property is set and unset when the TextInput gets active focus, so that other
488 properties can be bound to whether the cursor is currently showing. As it
489 gets set and unset automatically, when you set the value yourself you must
490 keep in mind that your value may be overwritten.
491
492 It can be set directly in script, for example if a KeyProxy might
493 forward keys to it and you desire it to look active when this happens
494 (but without actually giving it active focus).
495
496 It should not be set directly on the element, like in the below QML,
497 as the specified value will be overridden an lost on focus changes.
498
499 \code
500 TextInput {
501 text: "Text"
502 cursorVisible: false
503 }
504 \endcode
505
506 In the above snippet the cursor will still become visible when the
507 TextInput gains active focus.
508*/
509bool QDeclarativeTextInput::isCursorVisible() const
510{
511 Q_D(const QDeclarativeTextInput);
512 return d->cursorVisible;
513}
514
515void QDeclarativeTextInput::setCursorVisible(bool on)
516{
517 Q_D(QDeclarativeTextInput);
518 if (d->cursorVisible == on)
519 return;
520 d->cursorVisible = on;
521 d->control->setCursorBlinkPeriod(on?QApplication::cursorFlashTime():0);
522 QRect r = d->control->cursorRect();
523 if (d->control->inputMask().isEmpty())
524 updateRect(r);
525 else
526 updateRect();
527 emit cursorVisibleChanged(d->cursorVisible);
528}
529
530/*!
531 \qmlproperty int TextInput::cursorPosition
532 The position of the cursor in the TextInput.
533*/
534int QDeclarativeTextInput::cursorPosition() const
535{
536 Q_D(const QDeclarativeTextInput);
537 return d->control->cursor();
538}
539void QDeclarativeTextInput::setCursorPosition(int cp)
540{
541 Q_D(QDeclarativeTextInput);
542 if (cp < 0 || cp > d->control->text().length())
543 return;
544 d->control->moveCursor(cp);
545}
546
547/*!
548 Returns a Rect which encompasses the cursor, but which may be larger than is
549 required. Ignores custom cursor delegates.
550*/
551QRect QDeclarativeTextInput::cursorRectangle() const
552{
553 Q_D(const QDeclarativeTextInput);
554 QRect r = d->control->cursorRect();
555 // Scroll and make consistent with TextEdit
556 // QLineControl inexplicably adds 1 to the height and horizontal padding
557 // for unicode direction markers.
558 r.adjust(5 - d->hscroll, 0, -4 - d->hscroll, -1);
559 return r;
560}
561
562/*!
563 \qmlproperty int TextInput::selectionStart
564
565 The cursor position before the first character in the current selection.
566
567 This property is read-only. To change the selection, use select(start,end),
568 selectAll(), or selectWord().
569
570 \sa selectionEnd, cursorPosition, selectedText
571*/
572int QDeclarativeTextInput::selectionStart() const
573{
574 Q_D(const QDeclarativeTextInput);
575 return d->lastSelectionStart;
576}
577
578/*!
579 \qmlproperty int TextInput::selectionEnd
580
581 The cursor position after the last character in the current selection.
582
583 This property is read-only. To change the selection, use select(start,end),
584 selectAll(), or selectWord().
585
586 \sa selectionStart, cursorPosition, selectedText
587*/
588int QDeclarativeTextInput::selectionEnd() const
589{
590 Q_D(const QDeclarativeTextInput);
591 return d->lastSelectionEnd;
592}
593
594/*!
595 \qmlmethod void TextInput::select(int start, int end)
596
597 Causes the text from \a start to \a end to be selected.
598
599 If either start or end is out of range, the selection is not changed.
600
601 After calling this, selectionStart will become the lesser
602 and selectionEnd will become the greater (regardless of the order passed
603 to this method).
604
605 \sa selectionStart, selectionEnd
606*/
607void QDeclarativeTextInput::select(int start, int end)
608{
609 Q_D(QDeclarativeTextInput);
610 if (start < 0 || end < 0 || start > d->control->text().length() || end > d->control->text().length())
611 return;
612 d->control->setSelection(start, end-start);
613}
614
615/*!
616 \qmlproperty string TextInput::selectedText
617
618 This read-only property provides the text currently selected in the
619 text input.
620
621 It is equivalent to the following snippet, but is faster and easier
622 to use.
623
624 \js
625 myTextInput.text.toString().substring(myTextInput.selectionStart,
626 myTextInput.selectionEnd);
627 \endjs
628*/
629QString QDeclarativeTextInput::selectedText() const
630{
631 Q_D(const QDeclarativeTextInput);
632 return d->control->selectedText();
633}
634
635/*!
636 \qmlproperty bool TextInput::activeFocusOnPress
637
638 Whether the TextInput should gain active focus on a mouse press. By default this is
639 set to true.
640*/
641bool QDeclarativeTextInput::focusOnPress() const
642{
643 Q_D(const QDeclarativeTextInput);
644 return d->focusOnPress;
645}
646
647void QDeclarativeTextInput::setFocusOnPress(bool b)
648{
649 Q_D(QDeclarativeTextInput);
650 if (d->focusOnPress == b)
651 return;
652
653 d->focusOnPress = b;
654
655 emit activeFocusOnPressChanged(d->focusOnPress);
656}
657
658/*!
659 \qmlproperty bool TextInput::autoScroll
660
661 Whether the TextInput should scroll when the text is longer than the width. By default this is
662 set to true.
663*/
664bool QDeclarativeTextInput::autoScroll() const
665{
666 Q_D(const QDeclarativeTextInput);
667 return d->autoScroll;
668}
669
670void QDeclarativeTextInput::setAutoScroll(bool b)
671{
672 Q_D(QDeclarativeTextInput);
673 if (d->autoScroll == b)
674 return;
675
676 d->autoScroll = b;
677 //We need to repaint so that the scrolling is taking into account.
678 updateSize(true);
679 updateCursorRectangle();
680 emit autoScrollChanged(d->autoScroll);
681}
682
683/*!
684 \qmlclass IntValidator QIntValidator
685 \ingroup qml-basic-visual-elements
686
687 This element provides a validator for integer values.
688
689 IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
690 will accept locale specific digits, group separators, and positive and negative signs. In
691 addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
692 locale.
693*/
694/*!
695 \qmlproperty int IntValidator::top
696
697 This property holds the validator's highest acceptable value.
698 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
699*/
700/*!
701 \qmlproperty int IntValidator::bottom
702
703 This property holds the validator's lowest acceptable value.
704 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
705*/
706
707/*!
708 \qmlclass DoubleValidator QDoubleValidator
709 \ingroup qml-basic-visual-elements
710
711 This element provides a validator for non-integer numbers.
712*/
713
714/*!
715 \qmlproperty real DoubleValidator::top
716
717 This property holds the validator's maximum acceptable value.
718 By default, this property contains a value of infinity.
719*/
720/*!
721 \qmlproperty real DoubleValidator::bottom
722
723 This property holds the validator's minimum acceptable value.
724 By default, this property contains a value of -infinity.
725*/
726/*!
727 \qmlproperty int DoubleValidator::decimals
728
729 This property holds the validator's maximum number of digits after the decimal point.
730 By default, this property contains a value of 1000.
731*/
732/*!
733 \qmlproperty enumeration DoubleValidator::notation
734 This property holds the notation of how a string can describe a number.
735
736 The possible values for this property are:
737
738 \list
739 \o DoubleValidator.StandardNotation
740 \o DoubleValidator.ScientificNotation (default)
741 \endlist
742
743 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
744*/
745
746/*!
747 \qmlclass RegExpValidator QRegExpValidator
748 \ingroup qml-basic-visual-elements
749
750 This element provides a validator, which counts as valid any string which
751 matches a specified regular expression.
752*/
753/*!
754 \qmlproperty regExp RegExpValidator::regExp
755
756 This property holds the regular expression used for validation.
757
758 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
759 matching "a".
760
761 By default, this property contains a regular expression with the pattern .* that matches any string.
762*/
763
764/*!
765 \qmlproperty Validator TextInput::validator
766
767 Allows you to set a validator on the TextInput. When a validator is set
768 the TextInput will only accept input which leaves the text property in
769 an acceptable or intermediate state. The accepted signal will only be sent
770 if the text is in an acceptable state when enter is pressed.
771
772 Currently supported validators are IntValidator, DoubleValidator and
773 RegExpValidator. An example of using validators is shown below, which allows
774 input of integers between 11 and 31 into the text input:
775
776 \code
777 import QtQuick 1.0
778 TextInput{
779 validator: IntValidator{bottom: 11; top: 31;}
780 focus: true
781 }
782 \endcode
783
784 \sa acceptableInput, inputMask
785*/
786#ifndef QT_NO_VALIDATOR
787QValidator* QDeclarativeTextInput::validator() const
788{
789 Q_D(const QDeclarativeTextInput);
790 //###const cast isn't good, but needed for property system?
791 return const_cast<QValidator*>(d->control->validator());
792}
793
794void QDeclarativeTextInput::setValidator(QValidator* v)
795{
796 Q_D(QDeclarativeTextInput);
797 if (d->control->validator() == v)
798 return;
799
800 d->control->setValidator(v);
801 if(!d->control->hasAcceptableInput()){
802 d->oldValidity = false;
803 emit acceptableInputChanged();
804 }
805
806 emit validatorChanged();
807}
808#endif // QT_NO_VALIDATOR
809
810/*!
811 \qmlproperty string TextInput::inputMask
812
813 Allows you to set an input mask on the TextInput, restricting the allowable
814 text inputs. See QLineEdit::inputMask for further details, as the exact
815 same mask strings are used by TextInput.
816
817 \sa acceptableInput, validator
818*/
819QString QDeclarativeTextInput::inputMask() const
820{
821 Q_D(const QDeclarativeTextInput);
822 return d->control->inputMask();
823}
824
825void QDeclarativeTextInput::setInputMask(const QString &im)
826{
827 Q_D(QDeclarativeTextInput);
828 if (d->control->inputMask() == im)
829 return;
830
831 d->control->setInputMask(im);
832 emit inputMaskChanged(d->control->inputMask());
833}
834
835/*!
836 \qmlproperty bool TextInput::acceptableInput
837
838 This property is always true unless a validator or input mask has been set.
839 If a validator or input mask has been set, this property will only be true
840 if the current text is acceptable to the validator or input mask as a final
841 string (not as an intermediate string).
842*/
843bool QDeclarativeTextInput::hasAcceptableInput() const
844{
845 Q_D(const QDeclarativeTextInput);
846 return d->control->hasAcceptableInput();
847}
848
849/*!
850 \qmlsignal TextInput::onAccepted()
851
852 This handler is called when the Return or Enter key is pressed.
853 Note that if there is a \l validator or \l inputMask set on the text
854 input, the handler will only be emitted if the input is in an acceptable
855 state.
856*/
857
858void QDeclarativeTextInputPrivate::updateInputMethodHints()
859{
860 Q_Q(QDeclarativeTextInput);
861 Qt::InputMethodHints hints = inputMethodHints;
862 uint echo = control->echoMode();
863 if (echo == QDeclarativeTextInput::Password || echo == QDeclarativeTextInput::NoEcho)
864 hints |= Qt::ImhHiddenText;
865 else if (echo == QDeclarativeTextInput::PasswordEchoOnEdit)
866 hints &= ~Qt::ImhHiddenText;
867 if (echo != QDeclarativeTextInput::Normal)
868 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
869 q->setInputMethodHints(hints);
870}
871
872/*!
873 \qmlproperty enumeration TextInput::echoMode
874
875 Specifies how the text should be displayed in the TextInput.
876 \list
877 \o TextInput.Normal - Displays the text as it is. (Default)
878 \o TextInput.Password - Displays asterixes instead of characters.
879 \o TextInput.NoEcho - Displays nothing.
880 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
881 while editing, otherwise displays asterisks.
882 \endlist
883*/
884QDeclarativeTextInput::EchoMode QDeclarativeTextInput::echoMode() const
885{
886 Q_D(const QDeclarativeTextInput);
887 return (QDeclarativeTextInput::EchoMode)d->control->echoMode();
888}
889
890void QDeclarativeTextInput::setEchoMode(QDeclarativeTextInput::EchoMode echo)
891{
892 Q_D(QDeclarativeTextInput);
893 if (echoMode() == echo)
894 return;
895 d->control->setEchoMode((uint)echo);
896 d->updateInputMethodHints();
897 q_textChanged();
898 emit echoModeChanged(echoMode());
899}
900
901Qt::InputMethodHints QDeclarativeTextInput::imHints() const
902{
903 Q_D(const QDeclarativeTextInput);
904 return d->inputMethodHints;
905}
906
907void QDeclarativeTextInput::setIMHints(Qt::InputMethodHints hints)
908{
909 Q_D(QDeclarativeTextInput);
910 if (d->inputMethodHints == hints)
911 return;
912 d->inputMethodHints = hints;
913 d->updateInputMethodHints();
914}
915
916/*!
917 \qmlproperty Component TextInput::cursorDelegate
918 The delegate for the cursor in the TextInput.
919
920 If you set a cursorDelegate for a TextInput, this delegate will be used for
921 drawing the cursor instead of the standard cursor. An instance of the
922 delegate will be created and managed by the TextInput when a cursor is
923 needed, and the x property of delegate instance will be set so as
924 to be one pixel before the top left of the current character.
925
926 Note that the root item of the delegate component must be a QDeclarativeItem or
927 QDeclarativeItem derived item.
928*/
929QDeclarativeComponent* QDeclarativeTextInput::cursorDelegate() const
930{
931 Q_D(const QDeclarativeTextInput);
932 return d->cursorComponent;
933}
934
935void QDeclarativeTextInput::setCursorDelegate(QDeclarativeComponent* c)
936{
937 Q_D(QDeclarativeTextInput);
938 if (d->cursorComponent == c)
939 return;
940
941 d->cursorComponent = c;
942 if(!c){
943 //note that the components are owned by something else
944 delete d->cursorItem;
945 }else{
946 d->startCreatingCursor();
947 }
948
949 emit cursorDelegateChanged();
950}
951
952void QDeclarativeTextInputPrivate::startCreatingCursor()
953{
954 Q_Q(QDeclarativeTextInput);
955 if(cursorComponent->isReady()){
956 q->createCursor();
957 }else if(cursorComponent->isLoading()){
958 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
959 q, SLOT(createCursor()));
960 }else {//isError
961 qmlInfo(q, cursorComponent->errors()) << QDeclarativeTextInput::tr("Could not load cursor delegate");
962 }
963}
964
965void QDeclarativeTextInput::createCursor()
966{
967 Q_D(QDeclarativeTextInput);
968 if(d->cursorComponent->isError()){
969 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
970 return;
971 }
972
973 if(!d->cursorComponent->isReady())
974 return;
975
976 if(d->cursorItem)
977 delete d->cursorItem;
978 d->cursorItem = qobject_cast<QDeclarativeItem*>(d->cursorComponent->create());
979 if(!d->cursorItem){
980 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
981 return;
982 }
983
984 QDeclarative_setParent_noEvent(d->cursorItem, this);
985 d->cursorItem->setParentItem(this);
986 d->cursorItem->setX(d->control->cursorToX());
987 d->cursorItem->setHeight(d->control->height()-1); // -1 to counter QLineControl's +1 which is not consistent with Text.
988}
989
990/*!
991 \qmlmethod rect TextInput::positionToRectangle(int pos)
992
993 This function takes a character position and returns the rectangle that the
994 cursor would occupy, if it was placed at that character position.
995
996 This is similar to setting the cursorPosition, and then querying the cursor
997 rectangle, but the cursorPosition is not changed.
998*/
999QRectF QDeclarativeTextInput::positionToRectangle(int pos) const
1000{
1001 Q_D(const QDeclarativeTextInput);
1002 if (pos > d->control->cursorPosition())
1003 pos += d->control->preeditAreaText().length();
1004 return QRectF(d->control->cursorToX(pos)-d->hscroll,
1005 0.0,
1006 d->control->cursorWidth(),
1007 cursorRectangle().height());
1008}
1009
1010int QDeclarativeTextInput::positionAt(int x) const
1011{
1012 return positionAt(x, CursorBetweenCharacters);
1013}
1014
1015/*!
1016 \qmlmethod int TextInput::positionAt(int x, CursorPosition position = CursorBetweenCharacters)
1017 \since QtQuick 1.1
1018
1019 This function returns the character position at
1020 x pixels from the left of the textInput. Position 0 is before the
1021 first character, position 1 is after the first character but before the second,
1022 and so on until position text.length, which is after all characters.
1023
1024 This means that for all x values before the first character this function returns 0,
1025 and for all x values after the last character this function returns text.length.
1026
1027 The cursor position type specifies how the cursor position should be resolved.
1028
1029 \list
1030 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1031 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1032 \endlist
1033*/
1034int QDeclarativeTextInput::positionAt(int x, CursorPosition position) const
1035{
1036 Q_D(const QDeclarativeTextInput);
1037 int pos = d->control->xToPos(x + d->hscroll, QTextLine::CursorPosition(position));
1038 const int cursor = d->control->cursor();
1039 if (pos > cursor) {
1040 const int preeditLength = d->control->preeditAreaText().length();
1041 pos = pos > cursor + preeditLength
1042 ? pos - preeditLength
1043 : cursor;
1044 }
1045 return pos;
1046}
1047
1048void QDeclarativeTextInputPrivate::focusChanged(bool hasFocus)
1049{
1050 Q_Q(QDeclarativeTextInput);
1051 focused = hasFocus;
1052 q->setCursorVisible(hasFocus && scene && scene->hasFocus());
1053 if(!hasFocus && control->passwordEchoEditing())
1054 control->updatePasswordEchoEditing(false);//QLineControl sets it on key events, but doesn't deal with focus events
1055 if (!hasFocus)
1056 control->deselect();
1057 QDeclarativeItemPrivate::focusChanged(hasFocus);
1058}
1059
1060void QDeclarativeTextInput::keyPressEvent(QKeyEvent* ev)
1061{
1062 Q_D(QDeclarativeTextInput);
1063 keyPressPreHandler(ev);
1064 if (ev->isAccepted())
1065 return;
1066
1067 // Don't allow MacOSX up/down support, and we don't allow a completer.
1068 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1069 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1070 // Ignore when moving off the end unless there is a selection,
1071 // because then moving will do something (deselect).
1072 int cursorPosition = d->control->cursor();
1073 if (cursorPosition == 0)
1074 ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1075 if (!ignore && cursorPosition == d->control->text().length())
1076 ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1077 }
1078 if (ignore) {
1079 ev->ignore();
1080 } else {
1081 d->control->processKeyEvent(ev);
1082 }
1083 if (!ev->isAccepted())
1084 QDeclarativePaintedItem::keyPressEvent(ev);
1085}
1086
1087void QDeclarativeTextInput::inputMethodEvent(QInputMethodEvent *ev)
1088{
1089 Q_D(QDeclarativeTextInput);
1090 ev->ignore();
1091 const bool wasComposing = d->control->preeditAreaText().length() > 0;
1092 inputMethodPreHandler(ev);
1093 if (!ev->isAccepted()) {
1094 if (d->control->isReadOnly()) {
1095 ev->ignore();
1096 } else {
1097 d->control->processInputMethodEvent(ev);
1098 }
1099 }
1100 if (!ev->isAccepted())
1101 QDeclarativePaintedItem::inputMethodEvent(ev);
1102
1103 if (wasComposing != (d->control->preeditAreaText().length() > 0))
1104 emit inputMethodComposingChanged();
1105}
1106
1107/*!
1108\overload
1109Handles the given mouse \a event.
1110*/
1111void QDeclarativeTextInput::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1112{
1113 Q_D(QDeclarativeTextInput);
1114 if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonDblClick))
1115 return;
1116 if (d->selectByMouse) {
1117 int cursor = d->xToPos(event->pos().x());
1118 d->control->selectWordAtPos(cursor);
1119 event->setAccepted(true);
1120 } else {
1121 QDeclarativePaintedItem::mouseDoubleClickEvent(event);
1122 }
1123}
1124
1125void QDeclarativeTextInput::mousePressEvent(QGraphicsSceneMouseEvent *event)
1126{
1127 Q_D(QDeclarativeTextInput);
1128 if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonPress))
1129 return;
1130 if(d->focusOnPress){
1131 bool hadActiveFocus = hasActiveFocus();
1132 forceActiveFocus();
1133 if (d->showInputPanelOnFocus) {
1134 if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) {
1135 // re-open input panel on press if already focused
1136 openSoftwareInputPanel();
1137 }
1138 } else { // show input panel on click
1139 if (hasActiveFocus() && !hadActiveFocus) {
1140 d->clickCausedFocus = true;
1141 }
1142 }
1143 }
1144 if (d->selectByMouse) {
1145 setKeepMouseGrab(false);
1146 d->selectPressed = true;
1147 d->pressPos = event->pos();
1148 }
1149 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1150 int cursor = d->xToPos(event->pos().x());
1151 d->control->moveCursor(cursor, mark);
1152 event->setAccepted(true);
1153}
1154
1155void QDeclarativeTextInput::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1156{
1157 Q_D(QDeclarativeTextInput);
1158 if (d->sendMouseEventToInputContext(event, QEvent::MouseMove))
1159 return;
1160 if (d->selectPressed) {
1161 if (qAbs(int(event->pos().x() - d->pressPos.x())) > QApplication::startDragDistance())
1162 setKeepMouseGrab(true);
1163 moveCursorSelection(d->xToPos(event->pos().x()), d->mouseSelectionMode);
1164 event->setAccepted(true);
1165 } else {
1166 QDeclarativePaintedItem::mouseMoveEvent(event);
1167 }
1168}
1169
1170/*!
1171\overload
1172Handles the given mouse \a event.
1173*/
1174void QDeclarativeTextInput::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1175{
1176 Q_D(QDeclarativeTextInput);
1177 if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonRelease))
1178 return;
1179 if (d->selectPressed) {
1180 d->selectPressed = false;
1181 setKeepMouseGrab(false);
1182 }
1183 if (!d->showInputPanelOnFocus) { // input panel on click
1184 if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
1185 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1186 if (view->scene() && view->scene() == scene()) {
1187 qt_widget_private(view)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
1188 }
1189 }
1190 }
1191 }
1192 d->clickCausedFocus = false;
1193 d->control->processEvent(event);
1194 if (!event->isAccepted())
1195 QDeclarativePaintedItem::mouseReleaseEvent(event);
1196}
1197
1198bool QDeclarativeTextInputPrivate::sendMouseEventToInputContext(
1199 QGraphicsSceneMouseEvent *event, QEvent::Type eventType)
1200{
1201#if !defined QT_NO_IM
1202 Q_Q(QDeclarativeTextInput);
1203
1204 QWidget *widget = event->widget();
1205 // event->widget() is null, if this is delayed event from QDeclarativeFlickable.
1206 if (!widget && qApp) {
1207 QGraphicsView *view = qobject_cast<QGraphicsView*>(qApp->focusWidget());
1208 if (view && view->scene() && view->scene() == q->scene())
1209 widget = view->viewport();
1210 }
1211
1212 if (widget && control->composeMode()) {
1213 int tmp_cursor = xToPos(event->pos().x());
1214 int mousePos = tmp_cursor - control->cursor();
1215 if (mousePos < 0 || mousePos > control->preeditAreaText().length()) {
1216 mousePos = -1;
1217 // don't send move events outside the preedit area
1218 if (eventType == QEvent::MouseMove)
1219 return true;
1220 }
1221
1222 QInputContext *qic = widget->inputContext();
1223 if (qic) {
1224 QMouseEvent mouseEvent(
1225 eventType,
1226 widget->mapFromGlobal(event->screenPos()),
1227 event->screenPos(),
1228 event->button(),
1229 event->buttons(),
1230 event->modifiers());
1231 // may be causing reset() in some input methods
1232 qic->mouseHandler(mousePos, &mouseEvent);
1233 event->setAccepted(mouseEvent.isAccepted());
1234 }
1235 if (!control->preeditAreaText().isEmpty())
1236 return true;
1237 }
1238#else
1239 Q_UNUSED(event);
1240 Q_UNUSED(eventType)
1241#endif
1242
1243 return false;
1244}
1245
1246bool QDeclarativeTextInput::sceneEvent(QEvent *event)
1247{
1248 Q_D(QDeclarativeTextInput);
1249 bool rv = QDeclarativeItem::sceneEvent(event);
1250 if (event->type() == QEvent::UngrabMouse) {
1251 d->selectPressed = false;
1252 setKeepMouseGrab(false);
1253 }
1254 return rv;
1255}
1256
1257bool QDeclarativeTextInput::event(QEvent* ev)
1258{
1259 Q_D(QDeclarativeTextInput);
1260 //Anything we don't deal with ourselves, pass to the control
1261 bool handled = false;
1262 switch(ev->type()){
1263 case QEvent::KeyPress:
1264 case QEvent::KeyRelease://###Should the control be doing anything with release?
1265 case QEvent::InputMethod:
1266 case QEvent::GraphicsSceneMousePress:
1267 case QEvent::GraphicsSceneMouseMove:
1268 case QEvent::GraphicsSceneMouseRelease:
1269 case QEvent::GraphicsSceneMouseDoubleClick:
1270 break;
1271 default:
1272 handled = d->control->processEvent(ev);
1273 }
1274 if(!handled)
1275 handled = QDeclarativePaintedItem::event(ev);
1276 return handled;
1277}
1278
1279void QDeclarativeTextInput::geometryChanged(const QRectF &newGeometry,
1280 const QRectF &oldGeometry)
1281{
1282 if (newGeometry.width() != oldGeometry.width()) {
1283 updateSize();
1284 updateCursorRectangle();
1285 }
1286 QDeclarativePaintedItem::geometryChanged(newGeometry, oldGeometry);
1287}
1288
1289int QDeclarativeTextInputPrivate::calculateTextWidth()
1290{
1291 return qRound(control->naturalTextWidth());
1292}
1293
1294void QDeclarativeTextInputPrivate::updateHorizontalScroll()
1295{
1296 Q_Q(QDeclarativeTextInput);
1297 const int preeditLength = control->preeditAreaText().length();
1298 int cix = qRound(control->cursorToX(control->cursor() + preeditLength));
1299 QRect br(q->boundingRect().toRect());
1300 int widthUsed = calculateTextWidth();
1301
1302 QDeclarativeTextInput::HAlignment effectiveHAlign = q->effectiveHAlign();
1303 if (autoScroll) {
1304 if (widthUsed <= br.width()) {
1305 // text fits in br; use hscroll for alignment
1306 switch (effectiveHAlign & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) {
1307 case Qt::AlignRight:
1308 hscroll = widthUsed - br.width() - 1;
1309 break;
1310 case Qt::AlignHCenter:
1311 hscroll = (widthUsed - br.width()) / 2;
1312 break;
1313 default:
1314 // Left
1315 hscroll = 0;
1316 break;
1317 }
1318 } else if (cix - hscroll >= br.width()) {
1319 // text doesn't fit, cursor is to the right of br (scroll right)
1320 hscroll = cix - br.width() + 1;
1321 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1322 // text doesn't fit, cursor is to the left of br (scroll left)
1323 hscroll = cix;
1324 } else if (widthUsed - hscroll < br.width()) {
1325 // text doesn't fit, text document is to the left of br; align
1326 // right
1327 hscroll = widthUsed - br.width() + 1;
1328 }
1329 if (preeditLength > 0) {
1330 // check to ensure long pre-edit text doesn't push the cursor
1331 // off to the left
1332 cix = qRound(control->cursorToX(
1333 control->cursor() + qMax(0, control->preeditCursor() - 1)));
1334 if (cix < hscroll)
1335 hscroll = cix;
1336 }
1337 } else {
1338 switch (effectiveHAlign) {
1339 case QDeclarativeTextInput::AlignRight:
1340 hscroll = q->width() - widthUsed;
1341 break;
1342 case QDeclarativeTextInput::AlignHCenter:
1343 hscroll = (q->width() - widthUsed) / 2;
1344 break;
1345 default:
1346 // Left
1347 hscroll = 0;
1348 break;
1349 }
1350 }
1351}
1352
1353void QDeclarativeTextInput::drawContents(QPainter *p, const QRect &r)
1354{
1355 Q_D(QDeclarativeTextInput);
1356 p->setRenderHint(QPainter::TextAntialiasing, true);
1357 p->save();
1358 p->setPen(QPen(d->color));
1359 int flags = QLineControl::DrawText;
1360 if(!isReadOnly() && d->cursorVisible && !d->cursorItem)
1361 flags |= QLineControl::DrawCursor;
1362 if (d->control->hasSelectedText())
1363 flags |= QLineControl::DrawSelections;
1364 QPoint offset = QPoint(0,0);
1365 QFontMetrics fm = QFontMetrics(d->font);
1366 QRect br(boundingRect().toRect());
1367 if (d->autoScroll) {
1368 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1369 offset = br.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent());
1370 } else {
1371 offset = QPoint(d->hscroll, 0);
1372 }
1373 d->control->draw(p, offset, r, flags);
1374 p->restore();
1375}
1376
1377/*!
1378\overload
1379Returns the value of the given \a property.
1380*/
1381QVariant QDeclarativeTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1382{
1383 Q_D(const QDeclarativeTextInput);
1384 switch(property) {
1385 case Qt::ImMicroFocus:
1386 return cursorRectangle();
1387 case Qt::ImFont:
1388 return font();
1389 case Qt::ImCursorPosition:
1390 return QVariant(d->control->cursor());
1391 case Qt::ImSurroundingText:
1392 if (d->control->echoMode() == PasswordEchoOnEdit && !d->control->passwordEchoEditing())
1393 return QVariant(displayText());
1394 else
1395 return QVariant(text());
1396 case Qt::ImCurrentSelection:
1397 return QVariant(selectedText());
1398 case Qt::ImMaximumTextLength:
1399 return QVariant(maxLength());
1400 case Qt::ImAnchorPosition:
1401 if (d->control->selectionStart() == d->control->selectionEnd())
1402 return QVariant(d->control->cursor());
1403 else if (d->control->selectionStart() == d->control->cursor())
1404 return QVariant(d->control->selectionEnd());
1405 else
1406 return QVariant(d->control->selectionStart());
1407 default:
1408 return QVariant();
1409 }
1410}
1411
1412/*!
1413 \qmlmethod void TextInput::deselect()
1414 \since QtQuick 1.1
1415
1416 Removes active text selection.
1417*/
1418void QDeclarativeTextInput::deselect()
1419{
1420 Q_D(QDeclarativeTextInput);
1421 d->control->deselect();
1422}
1423
1424/*!
1425 \qmlmethod void TextInput::selectAll()
1426
1427 Causes all text to be selected.
1428*/
1429void QDeclarativeTextInput::selectAll()
1430{
1431 Q_D(QDeclarativeTextInput);
1432 d->control->setSelection(0, d->control->text().length());
1433}
1434
1435/*!
1436 \qmlmethod void TextInput::isRightToLeft(int start, int end)
1437
1438 Returns true if the natural reading direction of the editor text
1439 found between positions \a start and \a end is right to left.
1440*/
1441bool QDeclarativeTextInput::isRightToLeft(int start, int end)
1442{
1443 Q_D(QDeclarativeTextInput);
1444 if (start > end) {
1445 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1446 return false;
1447 } else {
1448 return d->control->text().mid(start, end - start).isRightToLeft();
1449 }
1450}
1451
1452#ifndef QT_NO_CLIPBOARD
1453/*!
1454 \qmlmethod TextInput::cut()
1455
1456 Moves the currently selected text to the system clipboard.
1457*/
1458void QDeclarativeTextInput::cut()
1459{
1460 Q_D(QDeclarativeTextInput);
1461 d->control->copy();
1462 d->control->del();
1463}
1464
1465/*!
1466 \qmlmethod TextInput::copy()
1467
1468 Copies the currently selected text to the system clipboard.
1469*/
1470void QDeclarativeTextInput::copy()
1471{
1472 Q_D(QDeclarativeTextInput);
1473 d->control->copy();
1474}
1475
1476/*!
1477 \qmlmethod TextInput::paste()
1478
1479 Replaces the currently selected text by the contents of the system clipboard.
1480*/
1481void QDeclarativeTextInput::paste()
1482{
1483 Q_D(QDeclarativeTextInput);
1484 if(!d->control->isReadOnly())
1485 d->control->paste();
1486}
1487#endif // QT_NO_CLIPBOARD
1488
1489/*!
1490 \qmlmethod void TextInput::selectWord()
1491
1492 Causes the word closest to the current cursor position to be selected.
1493*/
1494void QDeclarativeTextInput::selectWord()
1495{
1496 Q_D(QDeclarativeTextInput);
1497 d->control->selectWordAtPos(d->control->cursor());
1498}
1499
1500/*!
1501 \qmlproperty bool TextInput::smooth
1502
1503 This property holds whether the text is smoothly scaled or transformed.
1504
1505 Smooth filtering gives better visual quality, but is slower. If
1506 the item is displayed at its natural size, this property has no visual or
1507 performance effect.
1508
1509 \note Generally scaling artifacts are only visible if the item is stationary on
1510 the screen. A common pattern when animating an item is to disable smooth
1511 filtering at the beginning of the animation and reenable it at the conclusion.
1512*/
1513
1514/*!
1515 \qmlproperty string TextInput::passwordCharacter
1516
1517 This is the character displayed when echoMode is set to Password or
1518 PasswordEchoOnEdit. By default it is an asterisk.
1519
1520 If this property is set to a string with more than one character,
1521 the first character is used. If the string is empty, the value
1522 is ignored and the property is not set.
1523*/
1524QString QDeclarativeTextInput::passwordCharacter() const
1525{
1526 Q_D(const QDeclarativeTextInput);
1527 return QString(d->control->passwordCharacter());
1528}
1529
1530void QDeclarativeTextInput::setPasswordCharacter(const QString &str)
1531{
1532 Q_D(QDeclarativeTextInput);
1533 if(str.length() < 1)
1534 return;
1535 d->control->setPasswordCharacter(str.constData()[0]);
1536 EchoMode echoMode_ = echoMode();
1537 if (echoMode_ == Password || echoMode_ == PasswordEchoOnEdit) {
1538 updateSize();
1539 }
1540 emit passwordCharacterChanged();
1541}
1542
1543/*!
1544 \qmlproperty string TextInput::displayText
1545
1546 This is the text displayed in the TextInput.
1547
1548 If \l echoMode is set to TextInput::Normal, this holds the
1549 same value as the TextInput::text property. Otherwise,
1550 this property holds the text visible to the user, while
1551 the \l text property holds the actual entered text.
1552*/
1553QString QDeclarativeTextInput::displayText() const
1554{
1555 Q_D(const QDeclarativeTextInput);
1556 return d->control->displayText();
1557}
1558
1559/*!
1560 \qmlproperty bool TextInput::selectByMouse
1561
1562 Defaults to false.
1563
1564 If true, the user can use the mouse to select text in some
1565 platform-specific way. Note that for some platforms this may
1566 not be an appropriate interaction (eg. may conflict with how
1567 the text needs to behave inside a Flickable.
1568*/
1569bool QDeclarativeTextInput::selectByMouse() const
1570{
1571 Q_D(const QDeclarativeTextInput);
1572 return d->selectByMouse;
1573}
1574
1575void QDeclarativeTextInput::setSelectByMouse(bool on)
1576{
1577 Q_D(QDeclarativeTextInput);
1578 if (d->selectByMouse != on) {
1579 d->selectByMouse = on;
1580 emit selectByMouseChanged(on);
1581 }
1582}
1583
1584/*!
1585 \qmlproperty enum TextInput::mouseSelectionMode
1586 \since QtQuick 1.1
1587
1588 Specifies how text should be selected using a mouse.
1589
1590 \list
1591 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
1592 \o TextInput.SelectWords - The selection is updated with whole words.
1593 \endlist
1594
1595 This property only applies when \l selectByMouse is true.
1596*/
1597
1598QDeclarativeTextInput::SelectionMode QDeclarativeTextInput::mouseSelectionMode() const
1599{
1600 Q_D(const QDeclarativeTextInput);
1601 return d->mouseSelectionMode;
1602}
1603
1604void QDeclarativeTextInput::setMouseSelectionMode(SelectionMode mode)
1605{
1606 Q_D(QDeclarativeTextInput);
1607 if (d->mouseSelectionMode != mode) {
1608 d->mouseSelectionMode = mode;
1609 emit mouseSelectionModeChanged(mode);
1610 }
1611}
1612
1613/*!
1614 \qmlproperty bool TextInput::canPaste
1615 \since QtQuick 1.1
1616
1617 Returns true if the TextInput is writable and the content of the clipboard is
1618 suitable for pasting into the TextEdit.
1619*/
1620bool QDeclarativeTextInput::canPaste() const
1621{
1622 Q_D(const QDeclarativeTextInput);
1623 return d->canPaste;
1624}
1625
1626void QDeclarativeTextInput::moveCursorSelection(int position)
1627{
1628 Q_D(QDeclarativeTextInput);
1629 d->control->moveCursor(position, true);
1630}
1631
1632/*!
1633 \qmlmethod void TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
1634 \since QtQuick 1.1
1635
1636 Moves the cursor to \a position and updates the selection according to the optional \a mode
1637 parameter. (To only move the cursor, set the \l cursorPosition property.)
1638
1639 When this method is called it additionally sets either the
1640 selectionStart or the selectionEnd (whichever was at the previous cursor position)
1641 to the specified position. This allows you to easily extend and contract the selected
1642 text range.
1643
1644 The selection mode specifies whether the selection is updated on a per character or a per word
1645 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
1646
1647 \list
1648 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
1649 the previous cursor position) to the specified position.
1650 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
1651 words between the specified postion and the previous cursor position. Words partially in the
1652 range are included.
1653 \endlist
1654
1655 For example, take this sequence of calls:
1656
1657 \code
1658 cursorPosition = 5
1659 moveCursorSelection(9, TextInput.SelectCharacters)
1660 moveCursorSelection(7, TextInput.SelectCharacters)
1661 \endcode
1662
1663 This moves the cursor to position 5, extend the selection end from 5 to 9
1664 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
1665 selected (the 6th and 7th characters).
1666
1667 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
1668 before or on position 5 and extend the selection end to a word boundary on or past position 9.
1669*/
1670void QDeclarativeTextInput::moveCursorSelection(int pos, SelectionMode mode)
1671{
1672 Q_D(QDeclarativeTextInput);
1673
1674 if (mode == SelectCharacters) {
1675 d->control->moveCursor(pos, true);
1676 } else if (pos != d->control->cursor()){
1677 const int cursor = d->control->cursor();
1678 int anchor;
1679 if (!d->control->hasSelectedText())
1680 anchor = d->control->cursor();
1681 else if (d->control->selectionStart() == d->control->cursor())
1682 anchor = d->control->selectionEnd();
1683 else
1684 anchor = d->control->selectionStart();
1685
1686 if (anchor < pos || (anchor == pos && cursor < pos)) {
1687 const QString text = d->control->text();
1688 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1689 finder.setPosition(anchor);
1690
1691 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1692 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
1693 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
1694 finder.toPreviousBoundary();
1695 }
1696 anchor = finder.position() != -1 ? finder.position() : 0;
1697
1698 finder.setPosition(pos);
1699 if (pos > 0 && !finder.boundaryReasons())
1700 finder.toNextBoundary();
1701 const int cursor = finder.position() != -1 ? finder.position() : text.length();
1702
1703 d->control->setSelection(anchor, cursor - anchor);
1704 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
1705 const QString text = d->control->text();
1706 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1707 finder.setPosition(anchor);
1708
1709 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1710 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
1711 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
1712 finder.toNextBoundary();
1713 }
1714 anchor = finder.position() != -1 ? finder.position() : text.length();
1715
1716 finder.setPosition(pos);
1717 if (pos < text.length() && !finder.boundaryReasons())
1718 finder.toPreviousBoundary();
1719 const int cursor = finder.position() != -1 ? finder.position() : 0;
1720
1721 d->control->setSelection(anchor, cursor - anchor);
1722 }
1723 }
1724}
1725
1726/*!
1727 \qmlmethod void TextInput::openSoftwareInputPanel()
1728
1729 Opens software input panels like virtual keyboards for typing, useful for
1730 customizing when you want the input keyboard to be shown and hidden in
1731 your application.
1732
1733 By default the opening of input panels follows the platform style. On Symbian^1 and
1734 Symbian^3 -based devices the panels are opened by clicking TextInput. On other platforms
1735 the panels are automatically opened when TextInput element gains active focus. Input panels are
1736 always closed if no editor has active focus.
1737
1738 . You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1739 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1740 the behavior you want.
1741
1742 Only relevant on platforms, which provide virtual keyboards.
1743
1744 \qml
1745 import QtQuick 1.0
1746 TextInput {
1747 id: textInput
1748 text: "Hello world!"
1749 activeFocusOnPress: false
1750 MouseArea {
1751 anchors.fill: parent
1752 onClicked: {
1753 if (!textInput.activeFocus) {
1754 textInput.forceActiveFocus()
1755 textInput.openSoftwareInputPanel();
1756 } else {
1757 textInput.focus = false;
1758 }
1759 }
1760 onPressAndHold: textInput.closeSoftwareInputPanel();
1761 }
1762 }
1763 \endqml
1764*/
1765void QDeclarativeTextInput::openSoftwareInputPanel()
1766{
1767 QEvent event(QEvent::RequestSoftwareInputPanel);
1768 if (qApp) {
1769 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1770 if (view->scene() && view->scene() == scene()) {
1771 QApplication::sendEvent(view, &event);
1772 }
1773 }
1774 }
1775}
1776
1777/*!
1778 \qmlmethod void TextInput::closeSoftwareInputPanel()
1779
1780 Closes a software input panel like a virtual keyboard shown on the screen, useful
1781 for customizing when you want the input keyboard to be shown and hidden in
1782 your application.
1783
1784 By default the opening of input panels follows the platform style. On Symbian^1 and
1785 Symbian^3 -based devices the panels are opened by clicking TextInput. On other platforms
1786 the panels are automatically opened when TextInput element gains active focus. Input panels are
1787 always closed if no editor has active focus.
1788
1789 . You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1790 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1791 the behavior you want.
1792
1793 Only relevant on platforms, which provide virtual keyboards.
1794
1795 \qml
1796 import QtQuick 1.0
1797 TextInput {
1798 id: textInput
1799 text: "Hello world!"
1800 activeFocusOnPress: false
1801 MouseArea {
1802 anchors.fill: parent
1803 onClicked: {
1804 if (!textInput.activeFocus) {
1805 textInput.forceActiveFocus();
1806 textInput.openSoftwareInputPanel();
1807 } else {
1808 textInput.focus = false;
1809 }
1810 }
1811 onPressAndHold: textInput.closeSoftwareInputPanel();
1812 }
1813 }
1814 \endqml
1815*/
1816void QDeclarativeTextInput::closeSoftwareInputPanel()
1817{
1818 QEvent event(QEvent::CloseSoftwareInputPanel);
1819 if (qApp) {
1820 QEvent event(QEvent::CloseSoftwareInputPanel);
1821 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1822 if (view->scene() && view->scene() == scene()) {
1823 QApplication::sendEvent(view, &event);
1824 }
1825 }
1826 }
1827}
1828
1829void QDeclarativeTextInput::focusInEvent(QFocusEvent *event)
1830{
1831 Q_D(const QDeclarativeTextInput);
1832 if (d->showInputPanelOnFocus) {
1833 if (d->focusOnPress && !isReadOnly()) {
1834 openSoftwareInputPanel();
1835 }
1836 }
1837 QDeclarativePaintedItem::focusInEvent(event);
1838}
1839
1840/*!
1841 \qmlproperty bool TextInput::inputMethodComposing
1842
1843 \since QtQuick 1.1
1844
1845 This property holds whether the TextInput has partial text input from an
1846 input method.
1847
1848 While it is composing an input method may rely on mouse or key events from
1849 the TextInput to edit or commit the partial text. This property can be
1850 used to determine when to disable events handlers that may interfere with
1851 the correct operation of an input method.
1852*/
1853bool QDeclarativeTextInput::isInputMethodComposing() const
1854{
1855 Q_D(const QDeclarativeTextInput);
1856 return d->control->preeditAreaText().length() > 0;
1857}
1858
1859void QDeclarativeTextInputPrivate::init()
1860{
1861 Q_Q(QDeclarativeTextInput);
1862 control->setParent(q);
1863 control->setCursorWidth(1);
1864 control->setPasswordCharacter(QLatin1Char('*'));
1865 q->setSmooth(smooth);
1866 q->setAcceptedMouseButtons(Qt::LeftButton);
1867 q->setFlag(QGraphicsItem::ItemHasNoContents, false);
1868 q->setFlag(QGraphicsItem::ItemAcceptsInputMethod);
1869 q->connect(control, SIGNAL(cursorPositionChanged(int,int)),
1870 q, SLOT(cursorPosChanged()));
1871 q->connect(control, SIGNAL(selectionChanged()),
1872 q, SLOT(selectionChanged()));
1873 q->connect(control, SIGNAL(textChanged(QString)),
1874 q, SLOT(q_textChanged()));
1875 q->connect(control, SIGNAL(accepted()),
1876 q, SIGNAL(accepted()));
1877 q->connect(control, SIGNAL(updateNeeded(QRect)),
1878 q, SLOT(updateRect(QRect)));
1879#ifndef QT_NO_CLIPBOARD
1880 q->connect(q, SIGNAL(readOnlyChanged(bool)),
1881 q, SLOT(q_canPasteChanged()));
1882 q->connect(QApplication::clipboard(), SIGNAL(dataChanged()),
1883 q, SLOT(q_canPasteChanged()));
1884 canPaste = !control->isReadOnly() && QApplication::clipboard()->text().length() != 0;
1885#endif // QT_NO_CLIPBOARD
1886 q->connect(control, SIGNAL(updateMicroFocus()),
1887 q, SLOT(updateCursorRectangle()));
1888 q->connect(control, SIGNAL(displayTextChanged(QString)),
1889 q, SLOT(updateRect()));
1890 q->updateSize();
1891 oldValidity = control->hasAcceptableInput();
1892 lastSelectionStart = 0;
1893 lastSelectionEnd = 0;
1894 QPalette p = control->palette();
1895 selectedTextColor = p.color(QPalette::HighlightedText);
1896 selectionColor = p.color(QPalette::Highlight);
1897 determineHorizontalAlignment();
1898}
1899
1900void QDeclarativeTextInput::cursorPosChanged()
1901{
1902 Q_D(QDeclarativeTextInput);
1903 updateCursorRectangle();
1904 emit cursorPositionChanged();
1905 d->control->resetCursorBlinkTimer();
1906
1907 if(!d->control->hasSelectedText()){
1908 if(d->lastSelectionStart != d->control->cursor()){
1909 d->lastSelectionStart = d->control->cursor();
1910 emit selectionStartChanged();
1911 }
1912 if(d->lastSelectionEnd != d->control->cursor()){
1913 d->lastSelectionEnd = d->control->cursor();
1914 emit selectionEndChanged();
1915 }
1916 }
1917}
1918
1919void QDeclarativeTextInput::updateCursorRectangle()
1920{
1921 Q_D(QDeclarativeTextInput);
1922 d->determineHorizontalAlignment();
1923 d->updateHorizontalScroll();
1924 updateRect();//TODO: Only update rect between pos's
1925 updateMicroFocus();
1926 emit cursorRectangleChanged();
1927 if (d->cursorItem)
1928 d->cursorItem->setX(d->control->cursorToX() - d->hscroll);
1929}
1930
1931void QDeclarativeTextInput::selectionChanged()
1932{
1933 Q_D(QDeclarativeTextInput);
1934 updateRect();//TODO: Only update rect in selection
1935 emit selectedTextChanged();
1936
1937 if(d->lastSelectionStart != d->control->selectionStart()){
1938 d->lastSelectionStart = d->control->selectionStart();
1939 if(d->lastSelectionStart == -1)
1940 d->lastSelectionStart = d->control->cursor();
1941 emit selectionStartChanged();
1942 }
1943 if(d->lastSelectionEnd != d->control->selectionEnd()){
1944 d->lastSelectionEnd = d->control->selectionEnd();
1945 if(d->lastSelectionEnd == -1)
1946 d->lastSelectionEnd = d->control->cursor();
1947 emit selectionEndChanged();
1948 }
1949}
1950
1951void QDeclarativeTextInput::q_textChanged()
1952{
1953 Q_D(QDeclarativeTextInput);
1954 emit textChanged();
1955 emit displayTextChanged();
1956 updateSize();
1957 d->determineHorizontalAlignment();
1958 d->updateHorizontalScroll();
1959 updateMicroFocus();
1960 if(hasAcceptableInput() != d->oldValidity){
1961 d->oldValidity = hasAcceptableInput();
1962 emit acceptableInputChanged();
1963 }
1964}
1965
1966void QDeclarativeTextInput::updateRect(const QRect &r)
1967{
1968 Q_D(QDeclarativeTextInput);
1969 if(r == QRect())
1970 clearCache();
1971 else
1972 dirtyCache(QRect(r.x() - d->hscroll, r.y(), r.width(), r.height()));
1973 update();
1974}
1975
1976QRectF QDeclarativeTextInput::boundingRect() const
1977{
1978 Q_D(const QDeclarativeTextInput);
1979 QRectF r = QDeclarativePaintedItem::boundingRect();
1980
1981 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->control->cursorWidth();
1982
1983 // Could include font max left/right bearings to either side of rectangle.
1984
1985 r.setRight(r.right() + cursorWidth);
1986 return r;
1987}
1988
1989void QDeclarativeTextInput::updateSize(bool needsRedraw)
1990{
1991 Q_D(QDeclarativeTextInput);
1992 int w = width();
1993 int h = height();
1994 setImplicitHeight(d->control->height()-1); // -1 to counter QLineControl's +1 which is not consistent with Text.
1995 setImplicitWidth(d->calculateTextWidth());
1996 setContentsSize(QSize(width(), height()));//Repaints if changed
1997 if(w==width() && h==height() && needsRedraw){
1998 clearCache();
1999 update();
2000 }
2001}
2002
2003void QDeclarativeTextInput::q_canPasteChanged()
2004{
2005 Q_D(QDeclarativeTextInput);
2006 bool old = d->canPaste;
2007#ifndef QT_NO_CLIPBOARD
2008 d->canPaste = !d->control->isReadOnly() && QApplication::clipboard()->text().length() != 0;
2009#endif
2010 if(d->canPaste != old)
2011 emit canPasteChanged();
2012}
2013
2014QT_END_NAMESPACE
2015
2016#endif // QT_NO_LINEEDIT
2017
2018