59 |
59 |
60 QT_BEGIN_NAMESPACE |
60 QT_BEGIN_NAMESPACE |
61 |
61 |
62 /*! |
62 /*! |
63 \qmlclass TextEdit QDeclarativeTextEdit |
63 \qmlclass TextEdit QDeclarativeTextEdit |
64 \since 4.7 |
64 \since 4.7 |
65 \brief The TextEdit item allows you to add editable formatted text to a scene. |
65 \brief The TextEdit item displays multiple lines of editable formatted text. |
|
66 \inherits Item |
|
67 |
|
68 The TextEdit item displays a block of editable, formatted text. |
66 |
69 |
67 It can display both plain and rich text. For example: |
70 It can display both plain and rich text. For example: |
68 |
71 |
69 \qml |
72 \qml |
70 TextEdit { |
73 TextEdit { |
71 id: edit |
74 width: 240 |
72 text: "<b>Hello</b> <i>World!</i>" |
75 text: "<b>Hello</b> <i>World!</i>" |
73 focus: true |
|
74 font.family: "Helvetica" |
76 font.family: "Helvetica" |
75 font.pointSize: 20 |
77 font.pointSize: 20 |
76 color: "blue" |
78 color: "blue" |
77 width: 240 |
79 focus: true |
78 } |
80 } |
79 \endqml |
81 \endqml |
80 |
82 |
81 \image declarative-textedit.gif |
83 \image declarative-textedit.gif |
82 |
84 |
83 \sa Text |
85 Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus. |
|
86 |
|
87 Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific |
|
88 to a look-and-feel. For example, to add flickable scrolling that follows the cursor: |
|
89 |
|
90 \snippet snippets/declarative/texteditor.qml 0 |
|
91 |
|
92 A particular look-and-feel might use smooth scrolling (eg. using SmoothedFollow), might have a visible |
|
93 scrollbar, or a scrollbar that fades in to show location, etc. |
|
94 |
|
95 Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can |
|
96 be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely |
|
97 from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord(). |
|
98 |
|
99 You can translate between cursor positions (characters from the start of the document) and pixel |
|
100 points using positionAt() and positionToRectangle(). |
|
101 |
|
102 \sa Text, TextInput, {declarative/text/textselection}{Text Selection example} |
84 */ |
103 */ |
85 |
104 |
86 /*! |
105 /*! |
87 \internal |
106 \internal |
88 \class QDeclarativeTextEdit |
107 \class QDeclarativeTextEdit |
185 /*! |
200 /*! |
186 \qmlproperty int TextEdit::font.pixelSize |
201 \qmlproperty int TextEdit::font.pixelSize |
187 |
202 |
188 Sets the font size in pixels. |
203 Sets the font size in pixels. |
189 |
204 |
190 Using this function makes the font device dependent. |
205 Using this function makes the font device dependent. Use |
191 Use \c pointSize to set the size of the font in a device independent manner. |
206 \l{TextEdit::font.pointSize} to set the size of the font in a |
|
207 device independent manner. |
192 */ |
208 */ |
193 |
209 |
194 /*! |
210 /*! |
195 \qmlproperty real TextEdit::font.letterSpacing |
211 \qmlproperty real TextEdit::font.letterSpacing |
196 |
212 |
197 Sets the letter spacing for the font. |
213 Sets the letter spacing for the font. |
198 |
214 |
199 Letter spacing changes the default spacing between individual letters in the font. |
215 Letter spacing changes the default spacing between individual letters in the font. |
200 A value of 100 will keep the spacing unchanged; a value of 200 will enlarge the spacing after a character by |
216 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing. |
201 the width of the character itself. |
|
202 */ |
217 */ |
203 |
218 |
204 /*! |
219 /*! |
205 \qmlproperty real TextEdit::font.wordSpacing |
220 \qmlproperty real TextEdit::font.wordSpacing |
206 |
221 |
425 |
447 |
426 /*! |
448 /*! |
427 \qmlproperty enumeration TextEdit::horizontalAlignment |
449 \qmlproperty enumeration TextEdit::horizontalAlignment |
428 \qmlproperty enumeration TextEdit::verticalAlignment |
450 \qmlproperty enumeration TextEdit::verticalAlignment |
429 |
451 |
430 Sets the horizontal and vertical alignment of the text within the TextEdit items |
452 Sets the horizontal and vertical alignment of the text within the TextEdit item's |
431 width and height. By default, the text is top-left aligned. |
453 width and height. By default, the text is top-left aligned. |
432 |
454 |
433 The valid values for \c horizontalAlignment are \c TextEdit.AlignLeft, \c TextEdit.AlignRight and |
455 Valid values for \c horizontalAlignment are: |
434 \c TextEdit.AlignHCenter. The valid values for \c verticalAlignment are \c TextEdit.AlignTop, \c TextEdit.AlignBottom |
456 \list |
435 and \c TextEdit.AlignVCenter. |
457 \o TextEdit.AlignLeft (default) |
|
458 \o TextEdit.AlignRight |
|
459 \o TextEdit.AlignHCenter |
|
460 \endlist |
|
461 |
|
462 Valid values for \c verticalAlignment are: |
|
463 \list |
|
464 \o TextEdit.AlignTop (default) |
|
465 \o TextEdit.AlignBottom |
|
466 \c TextEdit.AlignVCenter |
|
467 \endlist |
436 */ |
468 */ |
437 QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::hAlign() const |
469 QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::hAlign() const |
438 { |
470 { |
439 Q_D(const QDeclarativeTextEdit); |
471 Q_D(const QDeclarativeTextEdit); |
440 return d->hAlign; |
472 return d->hAlign; |
473 |
505 |
474 Set this property to wrap the text to the TextEdit item's width. |
506 Set this property to wrap the text to the TextEdit item's width. |
475 The text will only wrap if an explicit width has been set. |
507 The text will only wrap if an explicit width has been set. |
476 |
508 |
477 \list |
509 \list |
478 \o TextEdit.NoWrap - no wrapping will be performed. |
510 \o TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width. |
479 \o TextEdit.WordWrap - wrapping is done on word boundaries. |
511 \o TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width. |
480 \o TextEdit.WrapAnywhere - Text can be wrapped at any point on a line, even if it occurs in the middle of a word. |
512 \o TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word. |
481 \o TextEdit.WrapAtWordBoundaryOrAnywhere - If possible, wrapping occurs at a word boundary; otherwise it |
513 \o TextEdit.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word. |
482 will occur at the appropriate point on the line, even in the middle of a word. |
|
483 \endlist |
514 \endlist |
484 |
515 |
485 The default is TextEdit.NoWrap. |
516 The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap. |
486 */ |
517 */ |
487 QDeclarativeTextEdit::WrapMode QDeclarativeTextEdit::wrapMode() const |
518 QDeclarativeTextEdit::WrapMode QDeclarativeTextEdit::wrapMode() const |
488 { |
519 { |
489 Q_D(const QDeclarativeTextEdit); |
520 Q_D(const QDeclarativeTextEdit); |
490 return d->wrapMode; |
521 return d->wrapMode; |
500 updateSize(); |
531 updateSize(); |
501 emit wrapModeChanged(); |
532 emit wrapModeChanged(); |
502 } |
533 } |
503 |
534 |
504 /*! |
535 /*! |
|
536 \qmlproperty real TextEdit::paintedWidth |
|
537 |
|
538 Returns the width of the text, including the width past the width |
|
539 which is covered due to insufficient wrapping if \l wrapMode is set. |
|
540 */ |
|
541 qreal QDeclarativeTextEdit::paintedWidth() const |
|
542 { |
|
543 return implicitWidth(); |
|
544 } |
|
545 |
|
546 /*! |
|
547 \qmlproperty real TextEdit::paintedHeight |
|
548 |
|
549 Returns the height of the text, including the height past the height |
|
550 that is covered if the text does not fit within the set height. |
|
551 */ |
|
552 qreal QDeclarativeTextEdit::paintedHeight() const |
|
553 { |
|
554 return implicitHeight(); |
|
555 } |
|
556 |
|
557 /*! |
|
558 \qmlmethod rectangle TextEdit::positionToRectangle(position) |
|
559 |
|
560 Returns the rectangle at the given \a position in the text. The x, y, |
|
561 and height properties correspond to the cursor that would describe |
|
562 that position. |
|
563 */ |
|
564 QRectF QDeclarativeTextEdit::positionToRectangle(int pos) const |
|
565 { |
|
566 Q_D(const QDeclarativeTextEdit); |
|
567 QTextCursor c(d->document); |
|
568 c.setPosition(pos); |
|
569 return d->control->cursorRect(c); |
|
570 |
|
571 } |
|
572 |
|
573 /*! |
|
574 \qmlmethod int TextEdit::positionAt(x,y) |
|
575 |
|
576 Returns the text position closest to pixel position (\a x, \a y). |
|
577 |
|
578 Position 0 is before the first character, position 1 is after the first character |
|
579 but before the second, and so on until position \l {text}.length, which is after all characters. |
|
580 */ |
|
581 int QDeclarativeTextEdit::positionAt(int x, int y) const |
|
582 { |
|
583 Q_D(const QDeclarativeTextEdit); |
|
584 int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit); |
|
585 return r; |
|
586 } |
|
587 |
|
588 /*! |
|
589 \qmlmethod int TextEdit::moveCursorSelection(int pos) |
|
590 |
|
591 Moves the cursor to \a position and updates the selection accordingly. |
|
592 (To only move the cursor, set the \l cursorPosition property.) |
|
593 |
|
594 When this method is called it additionally sets either the |
|
595 selectionStart or the selectionEnd (whichever was at the previous cursor position) |
|
596 to the specified position. This allows you to easily extend and contract the selected |
|
597 text range. |
|
598 |
|
599 For example, take this sequence of calls: |
|
600 |
|
601 \code |
|
602 cursorPosition = 5 |
|
603 moveCursorSelection(9) |
|
604 moveCursorSelection(7) |
|
605 \endcode |
|
606 |
|
607 This moves the cursor to position 5, extend the selection end from 5 to 9 |
|
608 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7 |
|
609 selected (the 6th and 7th characters). |
|
610 */ |
|
611 void QDeclarativeTextEdit::moveCursorSelection(int pos) |
|
612 { |
|
613 //Note that this is the same as setCursorPosition but with the KeepAnchor flag set |
|
614 Q_D(QDeclarativeTextEdit); |
|
615 QTextCursor cursor = d->control->textCursor(); |
|
616 if (cursor.position() == pos) |
|
617 return; |
|
618 cursor.setPosition(pos, QTextCursor::KeepAnchor); |
|
619 d->control->setTextCursor(cursor); |
|
620 } |
|
621 |
|
622 /*! |
505 \qmlproperty bool TextEdit::cursorVisible |
623 \qmlproperty bool TextEdit::cursorVisible |
506 If true the text edit shows a cursor. |
624 If true the text edit shows a cursor. |
507 |
625 |
508 This property is set and unset when the text edit gets focus, but it can also |
626 This property is set and unset when the text edit gets active focus, but it can also |
509 be set directly (useful, for example, if a KeyProxy might forward keys to it). |
627 be set directly (useful, for example, if a KeyProxy might forward keys to it). |
510 */ |
628 */ |
511 bool QDeclarativeTextEdit::isCursorVisible() const |
629 bool QDeclarativeTextEdit::isCursorVisible() const |
512 { |
630 { |
513 Q_D(const QDeclarativeTextEdit); |
631 Q_D(const QDeclarativeTextEdit); |
599 d->cursor = qobject_cast<QDeclarativeItem*>(d->cursorComponent->create(qmlContext(this))); |
717 d->cursor = qobject_cast<QDeclarativeItem*>(d->cursorComponent->create(qmlContext(this))); |
600 if(d->cursor){ |
718 if(d->cursor){ |
601 connect(d->control, SIGNAL(cursorPositionChanged()), |
719 connect(d->control, SIGNAL(cursorPositionChanged()), |
602 this, SLOT(moveCursorDelegate())); |
720 this, SLOT(moveCursorDelegate())); |
603 d->control->setCursorWidth(0); |
721 d->control->setCursorWidth(0); |
604 dirtyCache(cursorRect()); |
722 dirtyCache(cursorRectangle()); |
605 QDeclarative_setParent_noEvent(d->cursor, this); |
723 QDeclarative_setParent_noEvent(d->cursor, this); |
606 d->cursor->setParentItem(this); |
724 d->cursor->setParentItem(this); |
607 d->cursor->setHeight(QFontMetrics(d->font).height()); |
725 d->cursor->setHeight(QFontMetrics(d->font).height()); |
608 moveCursorDelegate(); |
726 moveCursorDelegate(); |
609 }else{ |
727 }else{ |
613 |
731 |
614 /*! |
732 /*! |
615 \qmlproperty int TextEdit::selectionStart |
733 \qmlproperty int TextEdit::selectionStart |
616 |
734 |
617 The cursor position before the first character in the current selection. |
735 The cursor position before the first character in the current selection. |
618 Setting this and selectionEnd allows you to specify a selection in the |
736 |
619 text edit. |
737 This property is read-only. To change the selection, use select(start,end), |
620 |
738 selectAll(), or selectWord(). |
621 Note that if selectionStart == selectionEnd then there is no current |
|
622 selection. If you attempt to set selectionStart to a value outside of |
|
623 the current text, selectionStart will not be changed. |
|
624 |
739 |
625 \sa selectionEnd, cursorPosition, selectedText |
740 \sa selectionEnd, cursorPosition, selectedText |
626 */ |
741 */ |
627 int QDeclarativeTextEdit::selectionStart() const |
742 int QDeclarativeTextEdit::selectionStart() const |
628 { |
743 { |
629 Q_D(const QDeclarativeTextEdit); |
744 Q_D(const QDeclarativeTextEdit); |
630 return d->control->textCursor().selectionStart(); |
745 return d->control->textCursor().selectionStart(); |
631 } |
746 } |
632 |
747 |
633 void QDeclarativeTextEdit::setSelectionStart(int s) |
|
634 { |
|
635 Q_D(QDeclarativeTextEdit); |
|
636 if(d->lastSelectionStart == s || s < 0 || s > text().length()) |
|
637 return; |
|
638 d->lastSelectionStart = s; |
|
639 d->updateSelection();// Will emit the relevant signals |
|
640 } |
|
641 |
|
642 /*! |
748 /*! |
643 \qmlproperty int TextEdit::selectionEnd |
749 \qmlproperty int TextEdit::selectionEnd |
644 |
750 |
645 The cursor position after the last character in the current selection. |
751 The cursor position after the last character in the current selection. |
646 Setting this and selectionStart allows you to specify a selection in the |
752 |
647 text edit. |
753 This property is read-only. To change the selection, use select(start,end), |
648 |
754 selectAll(), or selectWord(). |
649 Note that if selectionStart == selectionEnd then there is no current |
|
650 selection. If you attempt to set selectionEnd to a value outside of |
|
651 the current text, selectionEnd will not be changed. |
|
652 |
755 |
653 \sa selectionStart, cursorPosition, selectedText |
756 \sa selectionStart, cursorPosition, selectedText |
654 */ |
757 */ |
655 int QDeclarativeTextEdit::selectionEnd() const |
758 int QDeclarativeTextEdit::selectionEnd() const |
656 { |
759 { |
657 Q_D(const QDeclarativeTextEdit); |
760 Q_D(const QDeclarativeTextEdit); |
658 return d->control->textCursor().selectionEnd(); |
761 return d->control->textCursor().selectionEnd(); |
659 } |
|
660 |
|
661 void QDeclarativeTextEdit::setSelectionEnd(int s) |
|
662 { |
|
663 Q_D(QDeclarativeTextEdit); |
|
664 if(d->lastSelectionEnd == s || s < 0 || s > text().length()) |
|
665 return; |
|
666 d->lastSelectionEnd = s; |
|
667 d->updateSelection();// Will emit the relevant signals |
|
668 } |
762 } |
669 |
763 |
670 /*! |
764 /*! |
671 \qmlproperty string TextEdit::selectedText |
765 \qmlproperty string TextEdit::selectedText |
672 |
766 |
703 { |
797 { |
704 Q_D(QDeclarativeTextEdit); |
798 Q_D(QDeclarativeTextEdit); |
705 if (d->focusOnPress == on) |
799 if (d->focusOnPress == on) |
706 return; |
800 return; |
707 d->focusOnPress = on; |
801 d->focusOnPress = on; |
708 emit focusOnPressChanged(d->focusOnPress); |
802 emit activeFocusOnPressChanged(d->focusOnPress); |
709 } |
803 } |
710 |
804 |
711 /*! |
805 /*! |
712 \qmlproperty bool TextEdit::persistentSelection |
806 \qmlproperty bool TextEdit::persistentSelection |
713 |
807 |
714 Whether the TextEdit should keep the selection visible when it loses focus to another |
808 Whether the TextEdit should keep the selection visible when it loses active focus to another |
715 item in the scene. By default this is set to true; |
809 item in the scene. By default this is set to true; |
716 */ |
810 */ |
717 bool QDeclarativeTextEdit::persistentSelection() const |
811 bool QDeclarativeTextEdit::persistentSelection() const |
718 { |
812 { |
719 Q_D(const QDeclarativeTextEdit); |
813 Q_D(const QDeclarativeTextEdit); |
912 q->setCursorVisible(hasFocus); |
1008 q->setCursorVisible(hasFocus); |
913 QDeclarativeItemPrivate::focusChanged(hasFocus); |
1009 QDeclarativeItemPrivate::focusChanged(hasFocus); |
914 } |
1010 } |
915 |
1011 |
916 /*! |
1012 /*! |
|
1013 \qmlmethod void TextEdit::selectAll() |
|
1014 |
917 Causes all text to be selected. |
1015 Causes all text to be selected. |
918 */ |
1016 */ |
919 void QDeclarativeTextEdit::selectAll() |
1017 void QDeclarativeTextEdit::selectAll() |
920 { |
1018 { |
921 Q_D(QDeclarativeTextEdit); |
1019 Q_D(QDeclarativeTextEdit); |
922 d->control->selectAll(); |
1020 d->control->selectAll(); |
923 } |
1021 } |
|
1022 |
|
1023 /*! |
|
1024 \qmlmethod void TextEdit::selectWord() |
|
1025 |
|
1026 Causes the word closest to the current cursor position to be selected. |
|
1027 */ |
|
1028 void QDeclarativeTextEdit::selectWord() |
|
1029 { |
|
1030 Q_D(QDeclarativeTextEdit); |
|
1031 QTextCursor c = d->control->textCursor(); |
|
1032 c.select(QTextCursor::WordUnderCursor); |
|
1033 d->control->setTextCursor(c); |
|
1034 } |
|
1035 |
|
1036 /*! |
|
1037 \qmlmethod void TextEdit::select(start,end) |
|
1038 |
|
1039 Causes the text from \a start to \a end to be selected. |
|
1040 |
|
1041 If either start or end is out of range, the selection is not changed. |
|
1042 |
|
1043 After calling this, selectionStart will become the lesser |
|
1044 and selectionEnd will become the greater (regardless of the order passed |
|
1045 to this method). |
|
1046 |
|
1047 \sa selectionStart, selectionEnd |
|
1048 */ |
|
1049 void QDeclarativeTextEdit::select(int start, int end) |
|
1050 { |
|
1051 Q_D(QDeclarativeTextEdit); |
|
1052 if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length()) |
|
1053 return; |
|
1054 QTextCursor cursor = d->control->textCursor(); |
|
1055 cursor.beginEditBlock(); |
|
1056 cursor.setPosition(start, QTextCursor::MoveAnchor); |
|
1057 cursor.setPosition(end, QTextCursor::KeepAnchor); |
|
1058 cursor.endEditBlock(); |
|
1059 d->control->setTextCursor(cursor); |
|
1060 |
|
1061 // QTBUG-11100 |
|
1062 updateSelectionMarkers(); |
|
1063 } |
|
1064 |
|
1065 #ifndef QT_NO_CLIPBOARD |
|
1066 /*! |
|
1067 \qmlmethod TextEdit::cut() |
|
1068 |
|
1069 Moves the currently selected text to the system clipboard. |
|
1070 */ |
|
1071 void QDeclarativeTextEdit::cut() |
|
1072 { |
|
1073 Q_D(QDeclarativeTextEdit); |
|
1074 d->control->cut(); |
|
1075 } |
|
1076 |
|
1077 /*! |
|
1078 \qmlmethod TextEdit::copy() |
|
1079 |
|
1080 Copies the currently selected text to the system clipboard. |
|
1081 */ |
|
1082 void QDeclarativeTextEdit::copy() |
|
1083 { |
|
1084 Q_D(QDeclarativeTextEdit); |
|
1085 d->control->copy(); |
|
1086 } |
|
1087 |
|
1088 /*! |
|
1089 \qmlmethod TextEdit::paste() |
|
1090 |
|
1091 Replaces the currently selected text by the contents of the system clipboard. |
|
1092 */ |
|
1093 void QDeclarativeTextEdit::paste() |
|
1094 { |
|
1095 Q_D(QDeclarativeTextEdit); |
|
1096 d->control->paste(); |
|
1097 } |
|
1098 #endif // QT_NO_CLIPBOARD |
924 |
1099 |
925 /*! |
1100 /*! |
926 \overload |
1101 \overload |
927 Handles the given mouse \a event. |
1102 Handles the given mouse \a event. |
928 */ |
1103 */ |
929 void QDeclarativeTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event) |
1104 void QDeclarativeTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event) |
930 { |
1105 { |
931 Q_D(QDeclarativeTextEdit); |
1106 Q_D(QDeclarativeTextEdit); |
932 bool hadFocus = hasFocus(); |
|
933 if (d->focusOnPress){ |
1107 if (d->focusOnPress){ |
934 QGraphicsItem *p = parentItem();//###Is there a better way to find my focus scope? |
1108 bool hadActiveFocus = hasActiveFocus(); |
935 while(p) { |
1109 forceActiveFocus(); |
936 if (p->flags() & QGraphicsItem::ItemIsFocusScope) |
1110 if (d->showInputPanelOnFocus) { |
937 p->setFocus(); |
1111 if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) { |
938 p = p->parentItem(); |
1112 // re-open input panel on press if already focused |
|
1113 openSoftwareInputPanel(); |
|
1114 } |
|
1115 } else { // show input panel on click |
|
1116 if (hasActiveFocus() && !hadActiveFocus) { |
|
1117 d->clickCausedFocus = true; |
|
1118 } |
939 } |
1119 } |
940 setFocus(true); |
1120 } |
941 } |
|
942 if (!hadFocus && hasFocus()) |
|
943 d->clickCausedFocus = true; |
|
944 if (event->type() != QEvent::GraphicsSceneMouseDoubleClick || d->selectByMouse) |
1121 if (event->type() != QEvent::GraphicsSceneMouseDoubleClick || d->selectByMouse) |
945 d->control->processEvent(event, QPointF(0, -d->yoff)); |
1122 d->control->processEvent(event, QPointF(0, -d->yoff)); |
946 if (!event->isAccepted()) |
1123 if (!event->isAccepted()) |
947 QDeclarativePaintedItem::mousePressEvent(event); |
1124 QDeclarativePaintedItem::mousePressEvent(event); |
948 } |
1125 } |
952 Handles the given mouse \a event. |
1129 Handles the given mouse \a event. |
953 */ |
1130 */ |
954 void QDeclarativeTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) |
1131 void QDeclarativeTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) |
955 { |
1132 { |
956 Q_D(QDeclarativeTextEdit); |
1133 Q_D(QDeclarativeTextEdit); |
957 QWidget *widget = event->widget(); |
1134 d->control->processEvent(event, QPointF(0, -d->yoff)); |
958 if (widget && (d->control->textInteractionFlags() & Qt::TextEditable) && boundingRect().contains(event->pos())) |
1135 if (!d->showInputPanelOnFocus) { // input panel on click |
959 qt_widget_private(widget)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus); |
1136 if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) { |
|
1137 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) { |
|
1138 if (view->scene() && view->scene() == scene()) { |
|
1139 qt_widget_private(view)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus); |
|
1140 } |
|
1141 } |
|
1142 } |
|
1143 } |
960 d->clickCausedFocus = false; |
1144 d->clickCausedFocus = false; |
961 |
1145 |
962 d->control->processEvent(event, QPointF(0, -d->yoff)); |
|
963 if (!event->isAccepted()) |
1146 if (!event->isAccepted()) |
964 QDeclarativePaintedItem::mouseReleaseEvent(event); |
1147 QDeclarativePaintedItem::mouseReleaseEvent(event); |
965 } |
1148 } |
966 |
1149 |
967 /*! |
1150 /*! |
1066 q->setFlag(QGraphicsItem::ItemHasNoContents, false); |
1259 q->setFlag(QGraphicsItem::ItemHasNoContents, false); |
1067 q->setFlag(QGraphicsItem::ItemAcceptsInputMethod); |
1260 q->setFlag(QGraphicsItem::ItemAcceptsInputMethod); |
1068 |
1261 |
1069 control = new QTextControl(q); |
1262 control = new QTextControl(q); |
1070 control->setIgnoreUnusedNavigationEvents(true); |
1263 control->setIgnoreUnusedNavigationEvents(true); |
|
1264 |
|
1265 // QTextControl follows the default text color |
|
1266 // defined by the platform, declarative text |
|
1267 // should be black by default |
|
1268 QPalette pal = control->palette(); |
|
1269 if (pal.color(QPalette::Text) != color) { |
|
1270 pal.setColor(QPalette::Text, color); |
|
1271 control->setPalette(pal); |
|
1272 } |
1071 |
1273 |
1072 QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF))); |
1274 QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF))); |
1073 |
1275 |
1074 QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged())); |
1276 QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged())); |
1075 QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged())); |
1277 QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged())); |
1076 QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers())); |
1278 QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers())); |
1077 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers())); |
1279 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers())); |
1078 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged())); |
1280 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged())); |
|
1281 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorRectangleChanged())); |
1079 |
1282 |
1080 document = control->document(); |
1283 document = control->document(); |
1081 document->setDefaultFont(font); |
1284 document->setDefaultFont(font); |
1082 document->setDocumentMargin(textMargin); |
1285 document->setDocumentMargin(textMargin); |
1083 document->setUndoRedoEnabled(false); // flush undo buffer. |
1286 document->setUndoRedoEnabled(false); // flush undo buffer. |
1105 { |
1311 { |
1106 Q_Q(QDeclarativeTextEdit); |
1312 Q_Q(QDeclarativeTextEdit); |
1107 QTextCursor cursor = control->textCursor(); |
1313 QTextCursor cursor = control->textCursor(); |
1108 bool startChange = (lastSelectionStart != cursor.selectionStart()); |
1314 bool startChange = (lastSelectionStart != cursor.selectionStart()); |
1109 bool endChange = (lastSelectionEnd != cursor.selectionEnd()); |
1315 bool endChange = (lastSelectionEnd != cursor.selectionEnd()); |
1110 //### Is it worth calculating a more minimal set of movements? |
|
1111 cursor.beginEditBlock(); |
1316 cursor.beginEditBlock(); |
1112 cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor); |
1317 cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor); |
1113 cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor); |
1318 cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor); |
1114 cursor.endEditBlock(); |
1319 cursor.endEditBlock(); |
1115 control->setTextCursor(cursor); |
1320 control->setTextCursor(cursor); |
1116 if(startChange) |
1321 if(startChange) |
1117 q->selectionStartChanged(); |
1322 q->selectionStartChanged(); |
1118 if(endChange) |
1323 if(endChange) |
1119 q->selectionEndChanged(); |
1324 q->selectionEndChanged(); |
1120 startChange = (lastSelectionStart != control->textCursor().selectionStart()); |
|
1121 endChange = (lastSelectionEnd != control->textCursor().selectionEnd()); |
|
1122 } |
1325 } |
1123 |
1326 |
1124 void QDeclarativeTextEdit::updateSelectionMarkers() |
1327 void QDeclarativeTextEdit::updateSelectionMarkers() |
1125 { |
1328 { |
1126 Q_D(QDeclarativeTextEdit); |
1329 Q_D(QDeclarativeTextEdit); |
1130 } |
1333 } |
1131 if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){ |
1334 if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){ |
1132 d->lastSelectionEnd = d->control->textCursor().selectionEnd(); |
1335 d->lastSelectionEnd = d->control->textCursor().selectionEnd(); |
1133 emit selectionEndChanged(); |
1336 emit selectionEndChanged(); |
1134 } |
1337 } |
1135 } |
1338 updateMicroFocus(); |
|
1339 } |
|
1340 |
|
1341 QRectF QDeclarativeTextEdit::boundingRect() const |
|
1342 { |
|
1343 Q_D(const QDeclarativeTextEdit); |
|
1344 QRectF r = QDeclarativePaintedItem::boundingRect(); |
|
1345 int cursorWidth = 1; |
|
1346 if(d->cursor) |
|
1347 cursorWidth = d->cursor->width(); |
|
1348 if(!d->document->isEmpty()) |
|
1349 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor |
|
1350 |
|
1351 // Could include font max left/right bearings to either side of rectangle. |
|
1352 |
|
1353 r.setRight(r.right() + cursorWidth); |
|
1354 return r.translated(0,d->yoff); |
|
1355 } |
|
1356 |
1136 |
1357 |
1137 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't |
1358 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't |
1138 // need to do all the calculations each time |
1359 // need to do all the calculations each time |
1139 void QDeclarativeTextEdit::updateSize() |
1360 void QDeclarativeTextEdit::updateSize() |
1140 { |
1361 { |
1142 if (isComponentComplete()) { |
1363 if (isComponentComplete()) { |
1143 QFontMetrics fm = QFontMetrics(d->font); |
1364 QFontMetrics fm = QFontMetrics(d->font); |
1144 int dy = height(); |
1365 int dy = height(); |
1145 // ### assumes that if the width is set, the text will fill to edges |
1366 // ### assumes that if the width is set, the text will fill to edges |
1146 // ### (unless wrap is false, then clipping will occur) |
1367 // ### (unless wrap is false, then clipping will occur) |
1147 if (widthValid()) |
1368 if (widthValid() && d->document->textWidth() != width()) |
1148 d->document->setTextWidth(width()); |
1369 d->document->setTextWidth(width()); |
1149 dy -= (int)d->document->size().height(); |
1370 dy -= (int)d->document->size().height(); |
1150 |
1371 |
|
1372 int nyoff; |
1151 if (heightValid()) { |
1373 if (heightValid()) { |
1152 if (d->vAlign == AlignBottom) |
1374 if (d->vAlign == AlignBottom) |
1153 d->yoff = dy; |
1375 nyoff = dy; |
1154 else if (d->vAlign == AlignVCenter) |
1376 else if (d->vAlign == AlignVCenter) |
1155 d->yoff = dy/2; |
1377 nyoff = dy/2; |
|
1378 else |
|
1379 nyoff = 0; |
1156 } else { |
1380 } else { |
1157 d->yoff = 0; |
1381 nyoff = 0; |
|
1382 } |
|
1383 if (nyoff != d->yoff) { |
|
1384 prepareGeometryChange(); |
|
1385 d->yoff = nyoff; |
1158 } |
1386 } |
1159 setBaselineOffset(fm.ascent() + d->yoff + d->textMargin); |
1387 setBaselineOffset(fm.ascent() + d->yoff + d->textMargin); |
1160 |
1388 |
1161 //### need to comfirm cost of always setting these |
1389 //### need to comfirm cost of always setting these |
1162 int newWidth = qCeil(d->document->idealWidth()); |
1390 int newWidth = qCeil(d->document->idealWidth()); |
1163 if (!widthValid()) |
1391 if (!widthValid() && d->document->textWidth() != newWidth) |
1164 d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug) |
1392 d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug) |
1165 int cursorWidth = 1; |
|
1166 if(d->cursor) |
|
1167 cursorWidth = d->cursor->width(); |
|
1168 newWidth += cursorWidth; |
|
1169 if(!d->document->isEmpty()) |
|
1170 newWidth += 3;// ### Need a better way of accounting for space between char and cursor |
|
1171 // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed. |
1393 // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed. |
1172 setImplicitWidth(newWidth); |
1394 setImplicitWidth(newWidth); |
1173 setImplicitHeight(d->text.isEmpty() ? fm.height() : (int)d->document->size().height()); |
1395 qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height(); |
1174 |
1396 setImplicitHeight(newHeight); |
1175 setContentsSize(QSize(width(), height())); |
1397 |
|
1398 setContentsSize(QSize(newWidth, newHeight)); |
|
1399 |
|
1400 emit paintedSizeChanged(); |
1176 } else { |
1401 } else { |
1177 d->dirty = true; |
1402 d->dirty = true; |
1178 } |
1403 } |
1179 emit update(); |
1404 emit update(); |
1180 } |
1405 } |
1191 if (oldWrapMode == opt.wrapMode() && oldAlignment == opt.alignment()) |
1416 if (oldWrapMode == opt.wrapMode() && oldAlignment == opt.alignment()) |
1192 return; |
1417 return; |
1193 document->setDefaultTextOption(opt); |
1418 document->setDefaultTextOption(opt); |
1194 } |
1419 } |
1195 |
1420 |
|
1421 |
|
1422 /*! |
|
1423 \qmlmethod void TextEdit::openSoftwareInputPanel() |
|
1424 |
|
1425 Opens software input panels like virtual keyboards for typing, useful for |
|
1426 customizing when you want the input keyboard to be shown and hidden in |
|
1427 your application. |
|
1428 |
|
1429 By default the opening of input panels follows the platform style. On Symbian^1 and |
|
1430 Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms |
|
1431 the panels are automatically opened when TextEdit element gains active focus. Input panels are |
|
1432 always closed if no editor has active focus. |
|
1433 |
|
1434 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false |
|
1435 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement |
|
1436 the behavior you want. |
|
1437 |
|
1438 Only relevant on platforms, which provide virtual keyboards. |
|
1439 |
|
1440 \code |
|
1441 import Qt 4.7 |
|
1442 TextEdit { |
|
1443 id: textEdit |
|
1444 text: "Hello world!" |
|
1445 activeFocusOnPress: false |
|
1446 MouseArea { |
|
1447 anchors.fill: parent |
|
1448 onClicked: { |
|
1449 if (!textEdit.activeFocus) { |
|
1450 textEdit.forceActiveFocus(); |
|
1451 textEdit.openSoftwareInputPanel(); |
|
1452 } else { |
|
1453 textEdit.focus = false; |
|
1454 } |
|
1455 } |
|
1456 onPressAndHold: textEdit.closeSoftwareInputPanel(); |
|
1457 } |
|
1458 } |
|
1459 \endcode |
|
1460 */ |
|
1461 void QDeclarativeTextEdit::openSoftwareInputPanel() |
|
1462 { |
|
1463 QEvent event(QEvent::RequestSoftwareInputPanel); |
|
1464 if (qApp) { |
|
1465 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) { |
|
1466 if (view->scene() && view->scene() == scene()) { |
|
1467 QApplication::sendEvent(view, &event); |
|
1468 } |
|
1469 } |
|
1470 } |
|
1471 } |
|
1472 |
|
1473 /*! |
|
1474 \qmlmethod void TextEdit::closeSoftwareInputPanel() |
|
1475 |
|
1476 Closes a software input panel like a virtual keyboard shown on the screen, useful |
|
1477 for customizing when you want the input keyboard to be shown and hidden in |
|
1478 your application. |
|
1479 |
|
1480 By default the opening of input panels follows the platform style. On Symbian^1 and |
|
1481 Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms |
|
1482 the panels are automatically opened when TextEdit element gains active focus. Input panels are |
|
1483 always closed if no editor has active focus. |
|
1484 |
|
1485 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false |
|
1486 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement |
|
1487 the behavior you want. |
|
1488 |
|
1489 Only relevant on platforms, which provide virtual keyboards. |
|
1490 |
|
1491 \code |
|
1492 import Qt 4.7 |
|
1493 TextEdit { |
|
1494 id: textEdit |
|
1495 text: "Hello world!" |
|
1496 activeFocusOnPress: false |
|
1497 MouseArea { |
|
1498 anchors.fill: parent |
|
1499 onClicked: { |
|
1500 if (!textEdit.activeFocus) { |
|
1501 textEdit.forceActiveFocus(); |
|
1502 textEdit.openSoftwareInputPanel(); |
|
1503 } else { |
|
1504 textEdit.focus = false; |
|
1505 } |
|
1506 } |
|
1507 onPressAndHold: textEdit.closeSoftwareInputPanel(); |
|
1508 } |
|
1509 } |
|
1510 \endcode |
|
1511 */ |
|
1512 void QDeclarativeTextEdit::closeSoftwareInputPanel() |
|
1513 { |
|
1514 QEvent event(QEvent::CloseSoftwareInputPanel); |
|
1515 if (qApp) { |
|
1516 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) { |
|
1517 if (view->scene() && view->scene() == scene()) { |
|
1518 QApplication::sendEvent(view, &event); |
|
1519 } |
|
1520 } |
|
1521 } |
|
1522 } |
|
1523 |
|
1524 void QDeclarativeTextEdit::focusInEvent(QFocusEvent *event) |
|
1525 { |
|
1526 Q_D(const QDeclarativeTextEdit); |
|
1527 if (d->showInputPanelOnFocus) { |
|
1528 if (d->focusOnPress && !isReadOnly()) { |
|
1529 openSoftwareInputPanel(); |
|
1530 } |
|
1531 } |
|
1532 QDeclarativePaintedItem::focusInEvent(event); |
|
1533 } |
|
1534 |
1196 QT_END_NAMESPACE |
1535 QT_END_NAMESPACE |