src/declarative/graphicsitems/qdeclarativetextedit.cpp
changeset 30 5dc02b23752f
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "private/qdeclarativetextedit_p.h"
       
    43 #include "private/qdeclarativetextedit_p_p.h"
       
    44 
       
    45 #include "private/qdeclarativeevents_p_p.h"
       
    46 #include <private/qdeclarativeglobal_p.h>
       
    47 #include <qdeclarativeinfo.h>
       
    48 
       
    49 #include <QtCore/qmath.h>
       
    50 
       
    51 #include <QTextLayout>
       
    52 #include <QTextLine>
       
    53 #include <QTextDocument>
       
    54 #include <QGraphicsSceneMouseEvent>
       
    55 #include <QDebug>
       
    56 #include <QPainter>
       
    57 
       
    58 #include <private/qtextcontrol_p.h>
       
    59 
       
    60 QT_BEGIN_NAMESPACE
       
    61 
       
    62 /*!
       
    63     \qmlclass TextEdit QDeclarativeTextEdit
       
    64   \since 4.7
       
    65     \brief The TextEdit item allows you to add editable formatted text to a scene.
       
    66 
       
    67     It can display both plain and rich text. For example:
       
    68 
       
    69     \qml
       
    70 TextEdit {
       
    71     id: edit
       
    72     text: "<b>Hello</b> <i>World!</i>"
       
    73     focus: true
       
    74     font.family: "Helvetica"
       
    75     font.pointSize: 20
       
    76     color: "blue"
       
    77     width: 240
       
    78 }
       
    79     \endqml
       
    80 
       
    81     \image declarative-textedit.gif
       
    82 
       
    83     \sa Text
       
    84 */
       
    85 
       
    86 /*!
       
    87     \internal
       
    88     \class QDeclarativeTextEdit
       
    89     \qmlclass TextEdit
       
    90 
       
    91     \brief The QDeclarativeTextEdit class provides an editable formatted text item that you can add to a QDeclarativeView.
       
    92 
       
    93     It can display both plain and rich text.
       
    94 
       
    95     \image declarative-textedit.png
       
    96 
       
    97     A QDeclarativeTextEdit object can be instantiated in Qml using the tag \c &lt;TextEdit&gt;.
       
    98 */
       
    99 
       
   100 /*!
       
   101     Constructs a new QDeclarativeTextEdit.
       
   102 */
       
   103 QDeclarativeTextEdit::QDeclarativeTextEdit(QDeclarativeItem *parent)
       
   104 : QDeclarativePaintedItem(*(new QDeclarativeTextEditPrivate), parent)
       
   105 {
       
   106     Q_D(QDeclarativeTextEdit);
       
   107     d->init();
       
   108 }
       
   109 
       
   110 QString QDeclarativeTextEdit::text() const
       
   111 {
       
   112     Q_D(const QDeclarativeTextEdit);
       
   113 
       
   114     if (d->richText)
       
   115         return d->document->toHtml();
       
   116     else
       
   117         return d->document->toPlainText();
       
   118 }
       
   119 
       
   120 /*!
       
   121     \qmlproperty string TextEdit::font.family
       
   122 
       
   123     Sets the family name of the font.
       
   124 
       
   125     The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
       
   126     If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
       
   127     If the family isn't available a family will be set using the font matching algorithm.
       
   128 */
       
   129 
       
   130 /*!
       
   131     \qmlproperty bool TextEdit::font.bold
       
   132 
       
   133     Sets whether the font weight is bold.
       
   134 */
       
   135 
       
   136 /*!
       
   137     \qmlproperty enumeration TextEdit::font.weight
       
   138 
       
   139     Sets the font's weight.
       
   140 
       
   141     The weight can be one of:
       
   142     \list
       
   143     \o Font.Light
       
   144     \o Font.Normal - the default
       
   145     \o Font.DemiBold
       
   146     \o Font.Bold
       
   147     \o Font.Black
       
   148     \endlist
       
   149 
       
   150     \qml
       
   151     TextEdit { text: "Hello"; font.weight: Font.DemiBold }
       
   152     \endqml
       
   153 */
       
   154 
       
   155 /*!
       
   156     \qmlproperty bool TextEdit::font.italic
       
   157 
       
   158     Sets whether the font has an italic style.
       
   159 */
       
   160 
       
   161 /*!
       
   162     \qmlproperty bool TextEdit::font.underline
       
   163 
       
   164     Sets whether the text is underlined.
       
   165 */
       
   166 
       
   167 /*!
       
   168     \qmlproperty bool TextEdit::font.outline
       
   169 
       
   170     Sets whether the font has an outline style.
       
   171 */
       
   172 
       
   173 /*!
       
   174     \qmlproperty bool TextEdit::font.strikeout
       
   175 
       
   176     Sets whether the font has a strikeout style.
       
   177 */
       
   178 
       
   179 /*!
       
   180     \qmlproperty real TextEdit::font.pointSize
       
   181 
       
   182     Sets the font size in points. The point size must be greater than zero.
       
   183 */
       
   184 
       
   185 /*!
       
   186     \qmlproperty int TextEdit::font.pixelSize
       
   187 
       
   188     Sets the font size in pixels.
       
   189 
       
   190     Using this function makes the font device dependent.
       
   191     Use \c pointSize to set the size of the font in a device independent manner.
       
   192 */
       
   193 
       
   194 /*!
       
   195     \qmlproperty real TextEdit::font.letterSpacing
       
   196 
       
   197     Sets the letter spacing for the font.
       
   198 
       
   199     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
       
   201     the width of the character itself.
       
   202 */
       
   203 
       
   204 /*!
       
   205     \qmlproperty real TextEdit::font.wordSpacing
       
   206 
       
   207     Sets the word spacing for the font.
       
   208 
       
   209     Word spacing changes the default spacing between individual words.
       
   210     A positive value increases the word spacing by a corresponding amount of pixels,
       
   211     while a negative value decreases the inter-word spacing accordingly.
       
   212 */
       
   213 
       
   214 /*!
       
   215     \qmlproperty enumeration TextEdit::font.capitalization
       
   216 
       
   217     Sets the capitalization for the text.
       
   218 
       
   219     \list
       
   220     \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
       
   221     \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
       
   222     \o Font.AllLowercase	 - This alters the text to be rendered in all lowercase type.
       
   223     \o Font.SmallCaps -	This alters the text to be rendered in small-caps type.
       
   224     \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
       
   225     \endlist
       
   226 
       
   227     \qml
       
   228     TextEdit { text: "Hello"; font.capitalization: Font.AllLowercase }
       
   229     \endqml
       
   230 */
       
   231 
       
   232 /*!
       
   233     \qmlproperty string TextEdit::text
       
   234 
       
   235     The text to display.  If the text format is AutoText the text edit will
       
   236     automatically determine whether the text should be treated as
       
   237     rich text.  This determination is made using Qt::mightBeRichText().
       
   238 */
       
   239 void QDeclarativeTextEdit::setText(const QString &text)
       
   240 {
       
   241     Q_D(QDeclarativeTextEdit);
       
   242     if (QDeclarativeTextEdit::text() == text)
       
   243         return;
       
   244     d->text = text;
       
   245     d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
       
   246     if (d->richText) {
       
   247         d->control->setHtml(text);
       
   248     } else {
       
   249         d->control->setPlainText(text);
       
   250     }
       
   251     q_textChanged();
       
   252 }
       
   253 
       
   254 /*!
       
   255     \qmlproperty enumeration TextEdit::textFormat
       
   256 
       
   257     The way the text property should be displayed.
       
   258 
       
   259     \list
       
   260     \o TextEdit.AutoText
       
   261     \o TextEdit.PlainText
       
   262     \o TextEdit.RichText
       
   263     \o TextEdit.StyledText
       
   264     \endlist
       
   265 
       
   266     The default is TextEdit.AutoText.  If the text format is TextEdit.AutoText the text edit
       
   267     will automatically determine whether the text should be treated as
       
   268     rich text.  This determination is made using Qt::mightBeRichText().
       
   269 
       
   270     \table
       
   271     \row
       
   272     \o
       
   273     \qml
       
   274 Column {
       
   275     TextEdit {
       
   276         font.pointSize: 24
       
   277         text: "<b>Hello</b> <i>World!</i>"
       
   278     }
       
   279     TextEdit {
       
   280         font.pointSize: 24
       
   281         textFormat: TextEdit.RichText
       
   282         text: "<b>Hello</b> <i>World!</i>"
       
   283     }
       
   284     TextEdit {
       
   285         font.pointSize: 24
       
   286         textFormat: TextEdit.PlainText
       
   287         text: "<b>Hello</b> <i>World!</i>"
       
   288     }
       
   289 }
       
   290     \endqml
       
   291     \o \image declarative-textformat.png
       
   292     \endtable
       
   293 */
       
   294 QDeclarativeTextEdit::TextFormat QDeclarativeTextEdit::textFormat() const
       
   295 {
       
   296     Q_D(const QDeclarativeTextEdit);
       
   297     return d->format;
       
   298 }
       
   299 
       
   300 void QDeclarativeTextEdit::setTextFormat(TextFormat format)
       
   301 {
       
   302     Q_D(QDeclarativeTextEdit);
       
   303     if (format == d->format)
       
   304         return;
       
   305     bool wasRich = d->richText;
       
   306     d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
       
   307 
       
   308     if (wasRich && !d->richText) {
       
   309         d->control->setPlainText(d->text);
       
   310         updateSize();
       
   311     } else if (!wasRich && d->richText) {
       
   312         d->control->setHtml(d->text);
       
   313         updateSize();
       
   314     }
       
   315     d->format = format;
       
   316     emit textFormatChanged(d->format);
       
   317 }
       
   318 
       
   319 QFont QDeclarativeTextEdit::font() const
       
   320 {
       
   321     Q_D(const QDeclarativeTextEdit);
       
   322     return d->font;
       
   323 }
       
   324 
       
   325 void QDeclarativeTextEdit::setFont(const QFont &font)
       
   326 {
       
   327     Q_D(QDeclarativeTextEdit);
       
   328     d->font = font;
       
   329 
       
   330     clearCache();
       
   331     d->document->setDefaultFont(d->font);
       
   332     if(d->cursor){
       
   333         d->cursor->setHeight(QFontMetrics(d->font).height());
       
   334         moveCursorDelegate();
       
   335     }
       
   336     updateSize();
       
   337     update();
       
   338 }
       
   339 
       
   340 /*!
       
   341     \qmlproperty color TextEdit::color
       
   342 
       
   343     The text color.
       
   344 
       
   345     \qml
       
   346 // green text using hexadecimal notation
       
   347 TextEdit { color: "#00FF00"; ...  }
       
   348 
       
   349 // steelblue text using SVG color name
       
   350 TextEdit { color: "steelblue"; ...  }
       
   351     \endqml
       
   352 */
       
   353 QColor QDeclarativeTextEdit::color() const
       
   354 {
       
   355     Q_D(const QDeclarativeTextEdit);
       
   356     return d->color;
       
   357 }
       
   358 
       
   359 void QDeclarativeTextEdit::setColor(const QColor &color)
       
   360 {
       
   361     Q_D(QDeclarativeTextEdit);
       
   362     if (d->color == color)
       
   363         return;
       
   364 
       
   365     clearCache();
       
   366     d->color = color;
       
   367     QPalette pal = d->control->palette();
       
   368     pal.setColor(QPalette::Text, color);
       
   369     d->control->setPalette(pal);
       
   370     update();
       
   371     emit colorChanged(d->color);
       
   372 }
       
   373 
       
   374 /*!
       
   375     \qmlproperty color TextEdit::selectionColor
       
   376 
       
   377     The text highlight color, used behind selections.
       
   378 */
       
   379 QColor QDeclarativeTextEdit::selectionColor() const
       
   380 {
       
   381     Q_D(const QDeclarativeTextEdit);
       
   382     return d->selectionColor;
       
   383 }
       
   384 
       
   385 void QDeclarativeTextEdit::setSelectionColor(const QColor &color)
       
   386 {
       
   387     Q_D(QDeclarativeTextEdit);
       
   388     if (d->selectionColor == color)
       
   389         return;
       
   390 
       
   391     clearCache();
       
   392     d->selectionColor = color;
       
   393     QPalette pal = d->control->palette();
       
   394     pal.setColor(QPalette::Highlight, color);
       
   395     d->control->setPalette(pal);
       
   396     update();
       
   397     emit selectionColorChanged(d->selectionColor);
       
   398 }
       
   399 
       
   400 /*!
       
   401     \qmlproperty color TextEdit::selectedTextColor
       
   402 
       
   403     The selected text color, used in selections.
       
   404 */
       
   405 QColor QDeclarativeTextEdit::selectedTextColor() const
       
   406 {
       
   407     Q_D(const QDeclarativeTextEdit);
       
   408     return d->selectedTextColor;
       
   409 }
       
   410 
       
   411 void QDeclarativeTextEdit::setSelectedTextColor(const QColor &color)
       
   412 {
       
   413     Q_D(QDeclarativeTextEdit);
       
   414     if (d->selectedTextColor == color)
       
   415         return;
       
   416 
       
   417     clearCache();
       
   418     d->selectedTextColor = color;
       
   419     QPalette pal = d->control->palette();
       
   420     pal.setColor(QPalette::HighlightedText, color);
       
   421     d->control->setPalette(pal);
       
   422     update();
       
   423     emit selectedTextColorChanged(d->selectedTextColor);
       
   424 }
       
   425 
       
   426 /*!
       
   427     \qmlproperty enumeration TextEdit::horizontalAlignment
       
   428     \qmlproperty enumeration TextEdit::verticalAlignment
       
   429 
       
   430     Sets the horizontal and vertical alignment of the text within the TextEdit items
       
   431     width and height.  By default, the text is top-left aligned.
       
   432 
       
   433     The valid values for \c horizontalAlignment are \c TextEdit.AlignLeft, \c TextEdit.AlignRight and
       
   434     \c TextEdit.AlignHCenter.  The valid values for \c verticalAlignment are \c TextEdit.AlignTop, \c TextEdit.AlignBottom
       
   435     and \c TextEdit.AlignVCenter.
       
   436 */
       
   437 QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::hAlign() const
       
   438 {
       
   439     Q_D(const QDeclarativeTextEdit);
       
   440     return d->hAlign;
       
   441 }
       
   442 
       
   443 void QDeclarativeTextEdit::setHAlign(QDeclarativeTextEdit::HAlignment alignment)
       
   444 {
       
   445     Q_D(QDeclarativeTextEdit);
       
   446     if (alignment == d->hAlign)
       
   447         return;
       
   448     d->hAlign = alignment;
       
   449     d->updateDefaultTextOption();
       
   450     updateSize();
       
   451     emit horizontalAlignmentChanged(d->hAlign);
       
   452 }
       
   453 
       
   454 QDeclarativeTextEdit::VAlignment QDeclarativeTextEdit::vAlign() const
       
   455 {
       
   456     Q_D(const QDeclarativeTextEdit);
       
   457     return d->vAlign;
       
   458 }
       
   459 
       
   460 void QDeclarativeTextEdit::setVAlign(QDeclarativeTextEdit::VAlignment alignment)
       
   461 {
       
   462     Q_D(QDeclarativeTextEdit);
       
   463     if (alignment == d->vAlign)
       
   464         return;
       
   465     d->vAlign = alignment;
       
   466     d->updateDefaultTextOption();
       
   467     updateSize();
       
   468     emit verticalAlignmentChanged(d->vAlign);
       
   469 }
       
   470 
       
   471 /*!
       
   472     \qmlproperty enumeration TextEdit::wrapMode
       
   473 
       
   474     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.
       
   476 
       
   477     \list
       
   478     \o TextEdit.NoWrap - no wrapping will be performed.
       
   479     \o TextEdit.WordWrap - wrapping is done on word boundaries.
       
   480     \o TextEdit.WrapAnywhere - Text can be wrapped 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
       
   482        will occur at the appropriate point on the line, even in the middle of a word.
       
   483     \endlist
       
   484 
       
   485     The default is TextEdit.NoWrap.
       
   486 */
       
   487 QDeclarativeTextEdit::WrapMode QDeclarativeTextEdit::wrapMode() const
       
   488 {
       
   489     Q_D(const QDeclarativeTextEdit);
       
   490     return d->wrapMode;
       
   491 }
       
   492 
       
   493 void QDeclarativeTextEdit::setWrapMode(WrapMode mode)
       
   494 {
       
   495     Q_D(QDeclarativeTextEdit);
       
   496     if (mode == d->wrapMode)
       
   497         return;
       
   498     d->wrapMode = mode;
       
   499     d->updateDefaultTextOption();
       
   500     updateSize();
       
   501     emit wrapModeChanged();
       
   502 }
       
   503 
       
   504 /*!
       
   505     \qmlproperty bool TextEdit::cursorVisible
       
   506     If true the text edit shows a cursor.
       
   507 
       
   508     This property is set and unset when the text edit gets focus, but it can also
       
   509     be set directly (useful, for example, if a KeyProxy might forward keys to it).
       
   510 */
       
   511 bool QDeclarativeTextEdit::isCursorVisible() const
       
   512 {
       
   513     Q_D(const QDeclarativeTextEdit);
       
   514     return d->cursorVisible;
       
   515 }
       
   516 
       
   517 void QDeclarativeTextEdit::setCursorVisible(bool on)
       
   518 {
       
   519     Q_D(QDeclarativeTextEdit);
       
   520     if (d->cursorVisible == on)
       
   521         return;
       
   522     d->cursorVisible = on;
       
   523     QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
       
   524     if (!on && !d->persistentSelection)
       
   525         d->control->setCursorIsFocusIndicator(true);
       
   526     d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
       
   527     emit cursorVisibleChanged(d->cursorVisible);
       
   528 }
       
   529 
       
   530 /*!
       
   531     \qmlproperty int TextEdit::cursorPosition
       
   532     The position of the cursor in the TextEdit.
       
   533 */
       
   534 int QDeclarativeTextEdit::cursorPosition() const
       
   535 {
       
   536     Q_D(const QDeclarativeTextEdit);
       
   537     return d->control->textCursor().position();
       
   538 }
       
   539 
       
   540 void QDeclarativeTextEdit::setCursorPosition(int pos)
       
   541 {
       
   542     Q_D(QDeclarativeTextEdit);
       
   543     QTextCursor cursor = d->control->textCursor();
       
   544     if (cursor.position() == pos)
       
   545         return;
       
   546     cursor.setPosition(pos);
       
   547     d->control->setTextCursor(cursor);
       
   548 }
       
   549 
       
   550 /*!
       
   551     \qmlproperty Component TextEdit::cursorDelegate
       
   552     The delegate for the cursor in the TextEdit.
       
   553 
       
   554     If you set a cursorDelegate for a TextEdit, this delegate will be used for
       
   555     drawing the cursor instead of the standard cursor. An instance of the
       
   556     delegate will be created and managed by the text edit when a cursor is
       
   557     needed, and the x and y properties of delegate instance will be set so as
       
   558     to be one pixel before the top left of the current character.
       
   559 
       
   560     Note that the root item of the delegate component must be a QDeclarativeItem or
       
   561     QDeclarativeItem derived item.
       
   562 */
       
   563 QDeclarativeComponent* QDeclarativeTextEdit::cursorDelegate() const
       
   564 {
       
   565     Q_D(const QDeclarativeTextEdit);
       
   566     return d->cursorComponent;
       
   567 }
       
   568 
       
   569 void QDeclarativeTextEdit::setCursorDelegate(QDeclarativeComponent* c)
       
   570 {
       
   571     Q_D(QDeclarativeTextEdit);
       
   572     if(d->cursorComponent){
       
   573         if(d->cursor){
       
   574             disconnect(d->control, SIGNAL(cursorPositionChanged()),
       
   575                     this, SLOT(moveCursorDelegate()));
       
   576             d->control->setCursorWidth(-1);
       
   577             dirtyCache(cursorRect());
       
   578             delete d->cursor;
       
   579             d->cursor = 0;
       
   580         }
       
   581     }
       
   582     d->cursorComponent = c;
       
   583     if(c && c->isReady()){
       
   584         loadCursorDelegate();
       
   585     }else{
       
   586         if(c)
       
   587             connect(c, SIGNAL(statusChanged()),
       
   588                     this, SLOT(loadCursorDelegate()));
       
   589     }
       
   590 
       
   591     emit cursorDelegateChanged();
       
   592 }
       
   593 
       
   594 void QDeclarativeTextEdit::loadCursorDelegate()
       
   595 {
       
   596     Q_D(QDeclarativeTextEdit);
       
   597     if(d->cursorComponent->isLoading())
       
   598         return;
       
   599     d->cursor = qobject_cast<QDeclarativeItem*>(d->cursorComponent->create(qmlContext(this)));
       
   600     if(d->cursor){
       
   601         connect(d->control, SIGNAL(cursorPositionChanged()),
       
   602                 this, SLOT(moveCursorDelegate()));
       
   603         d->control->setCursorWidth(0);
       
   604         dirtyCache(cursorRect());
       
   605         QDeclarative_setParent_noEvent(d->cursor, this);
       
   606         d->cursor->setParentItem(this);
       
   607         d->cursor->setHeight(QFontMetrics(d->font).height());
       
   608         moveCursorDelegate();
       
   609     }else{
       
   610         qmlInfo(this) << "Error loading cursor delegate.";
       
   611     }
       
   612 }
       
   613 
       
   614 /*!
       
   615     \qmlproperty int TextEdit::selectionStart
       
   616 
       
   617     The cursor position before the first character in the current selection.
       
   618     Setting this and selectionEnd allows you to specify a selection in the
       
   619     text edit.
       
   620 
       
   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 
       
   625     \sa selectionEnd, cursorPosition, selectedText
       
   626 */
       
   627 int QDeclarativeTextEdit::selectionStart() const
       
   628 {
       
   629     Q_D(const QDeclarativeTextEdit);
       
   630     return d->control->textCursor().selectionStart();
       
   631 }
       
   632 
       
   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 /*!
       
   643     \qmlproperty int TextEdit::selectionEnd
       
   644 
       
   645     The cursor position after the last character in the current selection.
       
   646     Setting this and selectionStart allows you to specify a selection in the
       
   647     text edit.
       
   648 
       
   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 
       
   653     \sa selectionStart, cursorPosition, selectedText
       
   654 */
       
   655 int QDeclarativeTextEdit::selectionEnd() const
       
   656 {
       
   657     Q_D(const QDeclarativeTextEdit);
       
   658     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 }
       
   669 
       
   670 /*!
       
   671     \qmlproperty string TextEdit::selectedText
       
   672 
       
   673     This read-only property provides the text currently selected in the
       
   674     text edit.
       
   675 
       
   676     It is equivalent to the following snippet, but is faster and easier
       
   677     to use.
       
   678     \code
       
   679     //myTextEdit is the id of the TextEdit
       
   680     myTextEdit.text.toString().substring(myTextEdit.selectionStart,
       
   681             myTextEdit.selectionEnd);
       
   682     \endcode
       
   683 */
       
   684 QString QDeclarativeTextEdit::selectedText() const
       
   685 {
       
   686     Q_D(const QDeclarativeTextEdit);
       
   687     return d->control->textCursor().selectedText();
       
   688 }
       
   689 
       
   690 /*!
       
   691     \qmlproperty bool TextEdit::focusOnPress
       
   692 
       
   693     Whether the TextEdit should gain focus on a mouse press. By default this is
       
   694     set to true.
       
   695 */
       
   696 bool QDeclarativeTextEdit::focusOnPress() const
       
   697 {
       
   698     Q_D(const QDeclarativeTextEdit);
       
   699     return d->focusOnPress;
       
   700 }
       
   701 
       
   702 void QDeclarativeTextEdit::setFocusOnPress(bool on)
       
   703 {
       
   704     Q_D(QDeclarativeTextEdit);
       
   705     if (d->focusOnPress == on)
       
   706         return;
       
   707     d->focusOnPress = on;
       
   708     emit focusOnPressChanged(d->focusOnPress);
       
   709 }
       
   710 
       
   711 /*!
       
   712     \qmlproperty bool TextEdit::persistentSelection
       
   713 
       
   714     Whether the TextEdit should keep the selection visible when it loses focus to another
       
   715     item in the scene. By default this is set to true;
       
   716 */
       
   717 bool QDeclarativeTextEdit::persistentSelection() const
       
   718 {
       
   719     Q_D(const QDeclarativeTextEdit);
       
   720     return d->persistentSelection;
       
   721 }
       
   722 
       
   723 void QDeclarativeTextEdit::setPersistentSelection(bool on)
       
   724 {
       
   725     Q_D(QDeclarativeTextEdit);
       
   726     if (d->persistentSelection == on)
       
   727         return;
       
   728     d->persistentSelection = on;
       
   729     emit persistentSelectionChanged(d->persistentSelection);
       
   730 }
       
   731 
       
   732 /*
       
   733    \qmlproperty real TextEdit::textMargin
       
   734 
       
   735    The margin, in pixels, around the text in the TextEdit.
       
   736 */
       
   737 qreal QDeclarativeTextEdit::textMargin() const
       
   738 {
       
   739     Q_D(const QDeclarativeTextEdit);
       
   740     return d->textMargin;
       
   741 }
       
   742 
       
   743 void QDeclarativeTextEdit::setTextMargin(qreal margin)
       
   744 {
       
   745     Q_D(QDeclarativeTextEdit);
       
   746     if (d->textMargin == margin)
       
   747         return;
       
   748     d->textMargin = margin;
       
   749     d->document->setDocumentMargin(d->textMargin);
       
   750     emit textMarginChanged(d->textMargin);
       
   751 }
       
   752 
       
   753 void QDeclarativeTextEdit::geometryChanged(const QRectF &newGeometry,
       
   754                                   const QRectF &oldGeometry)
       
   755 {
       
   756     if (newGeometry.width() != oldGeometry.width())
       
   757         updateSize();
       
   758     QDeclarativePaintedItem::geometryChanged(newGeometry, oldGeometry);
       
   759 }
       
   760 
       
   761 /*!
       
   762     Ensures any delayed caching or data loading the class
       
   763     needs to performed is complete.
       
   764 */
       
   765 void QDeclarativeTextEdit::componentComplete()
       
   766 {
       
   767     Q_D(QDeclarativeTextEdit);
       
   768     QDeclarativePaintedItem::componentComplete();
       
   769     if (d->dirty) {
       
   770         updateSize();
       
   771         d->dirty = false;
       
   772     }
       
   773 }
       
   774 
       
   775 /*!
       
   776     \qmlproperty string TextEdit::selectByMouse
       
   777 
       
   778     Defaults to false.
       
   779 
       
   780     If true, the user can use the mouse to select text in some
       
   781     platform-specific way. Note that for some platforms this may
       
   782     not be an appropriate interaction (eg. may conflict with how
       
   783     the text needs to behave inside a Flickable.
       
   784 */
       
   785 bool QDeclarativeTextEdit::selectByMouse() const
       
   786 {
       
   787     Q_D(const QDeclarativeTextEdit);
       
   788     return d->selectByMouse;
       
   789 }
       
   790 
       
   791 void QDeclarativeTextEdit::setSelectByMouse(bool on)
       
   792 {
       
   793     Q_D(QDeclarativeTextEdit);
       
   794     if (d->selectByMouse != on) {
       
   795         d->selectByMouse = on;
       
   796         emit selectByMouseChanged(on);
       
   797     }
       
   798 }
       
   799 
       
   800 
       
   801 
       
   802 /*!
       
   803     \qmlproperty bool TextEdit::readOnly
       
   804 
       
   805     Whether the user an interact with the TextEdit item. If this
       
   806     property is set to true the text cannot be edited by user interaction.
       
   807 
       
   808     By default this property is false.
       
   809 */
       
   810 void QDeclarativeTextEdit::setReadOnly(bool r)
       
   811 {
       
   812     Q_D(QDeclarativeTextEdit);
       
   813     if (r == isReadOnly())
       
   814         return;
       
   815 
       
   816 
       
   817     Qt::TextInteractionFlags flags = Qt::NoTextInteraction;
       
   818     if (r) {
       
   819         flags = Qt::TextSelectableByMouse;
       
   820     } else {
       
   821         flags = Qt::TextEditorInteraction;
       
   822     }
       
   823     d->control->setTextInteractionFlags(flags);
       
   824     if (!r)
       
   825         d->control->moveCursor(QTextCursor::End);
       
   826 
       
   827     emit readOnlyChanged(r);
       
   828 }
       
   829 
       
   830 bool QDeclarativeTextEdit::isReadOnly() const
       
   831 {
       
   832     Q_D(const QDeclarativeTextEdit);
       
   833     return !(d->control->textInteractionFlags() & Qt::TextEditable);
       
   834 }
       
   835 
       
   836 /*!
       
   837     Sets how the text edit should interact with user input to the given
       
   838     \a flags.
       
   839 */
       
   840 void QDeclarativeTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
       
   841 {
       
   842     Q_D(QDeclarativeTextEdit);
       
   843     d->control->setTextInteractionFlags(flags);
       
   844 }
       
   845 
       
   846 /*!
       
   847     Returns the flags specifying how the text edit should interact
       
   848     with user input.
       
   849 */
       
   850 Qt::TextInteractionFlags QDeclarativeTextEdit::textInteractionFlags() const
       
   851 {
       
   852     Q_D(const QDeclarativeTextEdit);
       
   853     return d->control->textInteractionFlags();
       
   854 }
       
   855 
       
   856 /*!
       
   857     Returns the rectangle where the text cursor is rendered
       
   858     within the text edit.
       
   859 */
       
   860 QRect QDeclarativeTextEdit::cursorRect() const
       
   861 {
       
   862     Q_D(const QDeclarativeTextEdit);
       
   863     return d->control->cursorRect().toRect().translated(0,-d->yoff);
       
   864 }
       
   865 
       
   866 
       
   867 /*!
       
   868 \overload
       
   869 Handles the given \a event.
       
   870 */
       
   871 bool QDeclarativeTextEdit::event(QEvent *event)
       
   872 {
       
   873     Q_D(QDeclarativeTextEdit);
       
   874     if (event->type() == QEvent::ShortcutOverride) {
       
   875         d->control->processEvent(event, QPointF(0, -d->yoff));
       
   876         return event->isAccepted();
       
   877     }
       
   878     return QDeclarativePaintedItem::event(event);
       
   879 }
       
   880 
       
   881 /*!
       
   882 \overload
       
   883 Handles the given key \a event.
       
   884 */
       
   885 void QDeclarativeTextEdit::keyPressEvent(QKeyEvent *event)
       
   886 {
       
   887     Q_D(QDeclarativeTextEdit);
       
   888     keyPressPreHandler(event);
       
   889     if (!event->isAccepted())
       
   890         d->control->processEvent(event, QPointF(0, -d->yoff));
       
   891     if (!event->isAccepted())
       
   892         QDeclarativePaintedItem::keyPressEvent(event);
       
   893 }
       
   894 
       
   895 /*!
       
   896 \overload
       
   897 Handles the given key \a event.
       
   898 */
       
   899 void QDeclarativeTextEdit::keyReleaseEvent(QKeyEvent *event)
       
   900 {
       
   901     Q_D(QDeclarativeTextEdit);
       
   902     keyReleasePreHandler(event);
       
   903     if (!event->isAccepted())
       
   904         d->control->processEvent(event, QPointF(0, -d->yoff));
       
   905     if (!event->isAccepted())
       
   906         QDeclarativePaintedItem::keyReleaseEvent(event);
       
   907 }
       
   908 
       
   909 void QDeclarativeTextEditPrivate::focusChanged(bool hasFocus)
       
   910 {
       
   911     Q_Q(QDeclarativeTextEdit);
       
   912     q->setCursorVisible(hasFocus);
       
   913     QDeclarativeItemPrivate::focusChanged(hasFocus);
       
   914 }
       
   915 
       
   916 /*!
       
   917     Causes all text to be selected.
       
   918 */
       
   919 void QDeclarativeTextEdit::selectAll()
       
   920 {
       
   921     Q_D(QDeclarativeTextEdit);
       
   922     d->control->selectAll();
       
   923 }
       
   924 
       
   925 /*!
       
   926 \overload
       
   927 Handles the given mouse \a event.
       
   928 */
       
   929 void QDeclarativeTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
       
   930 {
       
   931     Q_D(QDeclarativeTextEdit);
       
   932     bool hadFocus = hasFocus();
       
   933     if (d->focusOnPress){
       
   934         QGraphicsItem *p = parentItem();//###Is there a better way to find my focus scope?
       
   935         while(p) {
       
   936             if (p->flags() & QGraphicsItem::ItemIsFocusScope)
       
   937                 p->setFocus();
       
   938             p = p->parentItem();
       
   939         }
       
   940         setFocus(true);
       
   941     }
       
   942     if (!hadFocus && hasFocus())
       
   943         d->clickCausedFocus = true;
       
   944     if (event->type() != QEvent::GraphicsSceneMouseDoubleClick || d->selectByMouse)
       
   945         d->control->processEvent(event, QPointF(0, -d->yoff));
       
   946     if (!event->isAccepted())
       
   947         QDeclarativePaintedItem::mousePressEvent(event);
       
   948 }
       
   949 
       
   950 /*!
       
   951 \overload
       
   952 Handles the given mouse \a event.
       
   953 */
       
   954 void QDeclarativeTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
       
   955 {
       
   956     Q_D(QDeclarativeTextEdit);
       
   957     QWidget *widget = event->widget();
       
   958     if (widget && (d->control->textInteractionFlags() & Qt::TextEditable) && boundingRect().contains(event->pos()))
       
   959         qt_widget_private(widget)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
       
   960     d->clickCausedFocus = false;
       
   961 
       
   962     d->control->processEvent(event, QPointF(0, -d->yoff));
       
   963     if (!event->isAccepted())
       
   964         QDeclarativePaintedItem::mouseReleaseEvent(event);
       
   965 }
       
   966 
       
   967 /*!
       
   968 \overload
       
   969 Handles the given mouse \a event.
       
   970 */
       
   971 void QDeclarativeTextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
       
   972 {
       
   973     Q_D(QDeclarativeTextEdit);
       
   974     if (d->selectByMouse) {
       
   975         d->control->processEvent(event, QPointF(0, -d->yoff));
       
   976         if (!event->isAccepted())
       
   977             QDeclarativePaintedItem::mouseDoubleClickEvent(event);
       
   978     } else {
       
   979         QDeclarativePaintedItem::mouseDoubleClickEvent(event);
       
   980     }
       
   981 }
       
   982 
       
   983 /*!
       
   984 \overload
       
   985 Handles the given mouse \a event.
       
   986 */
       
   987 void QDeclarativeTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
       
   988 {
       
   989     Q_D(QDeclarativeTextEdit);
       
   990     if (d->selectByMouse) {
       
   991         d->control->processEvent(event, QPointF(0, -d->yoff));
       
   992         if (!event->isAccepted())
       
   993             QDeclarativePaintedItem::mouseMoveEvent(event);
       
   994         event->setAccepted(true);
       
   995     } else {
       
   996         QDeclarativePaintedItem::mouseMoveEvent(event);
       
   997     }
       
   998 }
       
   999 
       
  1000 /*!
       
  1001 \overload
       
  1002 Handles the given input method \a event.
       
  1003 */
       
  1004 void QDeclarativeTextEdit::inputMethodEvent(QInputMethodEvent *event)
       
  1005 {
       
  1006     Q_D(QDeclarativeTextEdit);
       
  1007     d->control->processEvent(event, QPointF(0, -d->yoff));
       
  1008 }
       
  1009 
       
  1010 /*!
       
  1011 \overload
       
  1012 Returns the value of the given \a property.
       
  1013 */
       
  1014 QVariant QDeclarativeTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
       
  1015 {
       
  1016     Q_D(const QDeclarativeTextEdit);
       
  1017     return d->control->inputMethodQuery(property);
       
  1018 }
       
  1019 
       
  1020 /*!
       
  1021 Draws the contents of the text edit using the given \a painter within
       
  1022 the given \a bounds.
       
  1023 */
       
  1024 void QDeclarativeTextEdit::drawContents(QPainter *painter, const QRect &bounds)
       
  1025 {
       
  1026     Q_D(QDeclarativeTextEdit);
       
  1027 
       
  1028     painter->setRenderHint(QPainter::TextAntialiasing, true);
       
  1029     painter->translate(0,d->yoff);
       
  1030 
       
  1031     d->control->drawContents(painter, bounds.translated(0,-d->yoff));
       
  1032 
       
  1033     painter->translate(0,-d->yoff);
       
  1034 }
       
  1035 
       
  1036 void QDeclarativeTextEdit::updateImgCache(const QRectF &rf)
       
  1037 {
       
  1038     Q_D(const QDeclarativeTextEdit);
       
  1039     QRect r = rf.toRect();
       
  1040     if (r != QRect(0,0,INT_MAX,INT_MAX)) // Don't translate "everything"
       
  1041         r = r.translated(0,d->yoff);
       
  1042     dirtyCache(r);
       
  1043     emit update();
       
  1044 }
       
  1045 
       
  1046 /*!
       
  1047     \qmlproperty bool TextEdit::smooth
       
  1048 
       
  1049     This property holds whether the text is smoothly scaled or transformed.
       
  1050 
       
  1051     Smooth filtering gives better visual quality, but is slower.  If
       
  1052     the item is displayed at its natural size, this property has no visual or
       
  1053     performance effect.
       
  1054 
       
  1055     \note Generally scaling artifacts are only visible if the item is stationary on
       
  1056     the screen.  A common pattern when animating an item is to disable smooth
       
  1057     filtering at the beginning of the animation and reenable it at the conclusion.
       
  1058 */
       
  1059 
       
  1060 void QDeclarativeTextEditPrivate::init()
       
  1061 {
       
  1062     Q_Q(QDeclarativeTextEdit);
       
  1063 
       
  1064     q->setSmooth(smooth);
       
  1065     q->setAcceptedMouseButtons(Qt::LeftButton);
       
  1066     q->setFlag(QGraphicsItem::ItemHasNoContents, false);
       
  1067     q->setFlag(QGraphicsItem::ItemAcceptsInputMethod);
       
  1068 
       
  1069     control = new QTextControl(q);
       
  1070     control->setIgnoreUnusedNavigationEvents(true);
       
  1071 
       
  1072     QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF)));
       
  1073 
       
  1074     QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
       
  1075     QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
       
  1076     QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
       
  1077     QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
       
  1078     QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
       
  1079 
       
  1080     document = control->document();
       
  1081     document->setDefaultFont(font);
       
  1082     document->setDocumentMargin(textMargin);
       
  1083     document->setUndoRedoEnabled(false); // flush undo buffer.
       
  1084     document->setUndoRedoEnabled(true);
       
  1085     updateDefaultTextOption();
       
  1086 }
       
  1087 
       
  1088 void QDeclarativeTextEdit::q_textChanged()
       
  1089 {
       
  1090     updateSize();
       
  1091     emit textChanged(text());
       
  1092 }
       
  1093 
       
  1094 void QDeclarativeTextEdit::moveCursorDelegate()
       
  1095 {
       
  1096     Q_D(QDeclarativeTextEdit);
       
  1097     if(!d->cursor)
       
  1098         return;
       
  1099     QRectF cursorRect = d->control->cursorRect();
       
  1100     d->cursor->setX(cursorRect.x());
       
  1101     d->cursor->setY(cursorRect.y());
       
  1102 }
       
  1103 
       
  1104 void QDeclarativeTextEditPrivate::updateSelection()
       
  1105 {
       
  1106     Q_Q(QDeclarativeTextEdit);
       
  1107     QTextCursor cursor = control->textCursor();
       
  1108     bool startChange = (lastSelectionStart != cursor.selectionStart());
       
  1109     bool endChange = (lastSelectionEnd != cursor.selectionEnd());
       
  1110     //### Is it worth calculating a more minimal set of movements?
       
  1111     cursor.beginEditBlock();
       
  1112     cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor);
       
  1113     cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor);
       
  1114     cursor.endEditBlock();
       
  1115     control->setTextCursor(cursor);
       
  1116     if(startChange)
       
  1117         q->selectionStartChanged();
       
  1118     if(endChange)
       
  1119         q->selectionEndChanged();
       
  1120     startChange = (lastSelectionStart != control->textCursor().selectionStart());
       
  1121     endChange = (lastSelectionEnd != control->textCursor().selectionEnd());
       
  1122 }
       
  1123 
       
  1124 void QDeclarativeTextEdit::updateSelectionMarkers()
       
  1125 {
       
  1126     Q_D(QDeclarativeTextEdit);
       
  1127     if(d->lastSelectionStart != d->control->textCursor().selectionStart()){
       
  1128         d->lastSelectionStart = d->control->textCursor().selectionStart();
       
  1129         emit selectionStartChanged();
       
  1130     }
       
  1131     if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){
       
  1132         d->lastSelectionEnd = d->control->textCursor().selectionEnd();
       
  1133         emit selectionEndChanged();
       
  1134     }
       
  1135 }
       
  1136 
       
  1137 //### 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
       
  1139 void QDeclarativeTextEdit::updateSize()
       
  1140 {
       
  1141     Q_D(QDeclarativeTextEdit);
       
  1142     if (isComponentComplete()) {
       
  1143         QFontMetrics fm = QFontMetrics(d->font);
       
  1144         int dy = height();
       
  1145         // ### assumes that if the width is set, the text will fill to edges
       
  1146         // ### (unless wrap is false, then clipping will occur)
       
  1147         if (widthValid())
       
  1148             d->document->setTextWidth(width());
       
  1149         dy -= (int)d->document->size().height();
       
  1150 
       
  1151         if (heightValid()) {
       
  1152             if (d->vAlign == AlignBottom)
       
  1153                 d->yoff = dy;
       
  1154             else if (d->vAlign == AlignVCenter)
       
  1155                 d->yoff = dy/2;
       
  1156         } else {
       
  1157             d->yoff = 0;
       
  1158         }
       
  1159         setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
       
  1160 
       
  1161         //### need to comfirm cost of always setting these
       
  1162         int newWidth = qCeil(d->document->idealWidth());
       
  1163         if (!widthValid())
       
  1164             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.
       
  1172         setImplicitWidth(newWidth);
       
  1173         setImplicitHeight(d->text.isEmpty() ? fm.height() : (int)d->document->size().height());
       
  1174 
       
  1175         setContentsSize(QSize(width(), height()));
       
  1176     } else {
       
  1177         d->dirty = true;
       
  1178     }
       
  1179     emit update();
       
  1180 }
       
  1181 
       
  1182 void QDeclarativeTextEditPrivate::updateDefaultTextOption()
       
  1183 {
       
  1184     QTextOption opt = document->defaultTextOption();
       
  1185     int oldAlignment = opt.alignment();
       
  1186     opt.setAlignment((Qt::Alignment)(int)(hAlign | vAlign));
       
  1187 
       
  1188     QTextOption::WrapMode oldWrapMode = opt.wrapMode();
       
  1189     opt.setWrapMode(QTextOption::WrapMode(wrapMode));
       
  1190 
       
  1191     if (oldWrapMode == opt.wrapMode() && oldAlignment == opt.alignment())
       
  1192         return;
       
  1193     document->setDefaultTextOption(opt);
       
  1194 }
       
  1195 
       
  1196 QT_END_NAMESPACE