util/src/gui/widgets/qplaintextedit.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** 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 "qplaintextedit_p.h"
       
    43 
       
    44 
       
    45 #include <qfont.h>
       
    46 #include <qpainter.h>
       
    47 #include <qevent.h>
       
    48 #include <qdebug.h>
       
    49 #include <qmime.h>
       
    50 #include <qdrag.h>
       
    51 #include <qclipboard.h>
       
    52 #include <qmenu.h>
       
    53 #include <qstyle.h>
       
    54 #include <qtimer.h>
       
    55 #include "private/qtextdocumentlayout_p.h"
       
    56 #include "private/qabstracttextdocumentlayout_p.h"
       
    57 #include "qtextdocument.h"
       
    58 #include "private/qtextdocument_p.h"
       
    59 #include "qtextlist.h"
       
    60 #include "private/qtextcontrol_p.h"
       
    61 
       
    62 #include <qtextformat.h>
       
    63 #include <qdatetime.h>
       
    64 #include <qapplication.h>
       
    65 #include <limits.h>
       
    66 #include <qtexttable.h>
       
    67 #include <qvariant.h>
       
    68 #include <qinputcontext.h>
       
    69 
       
    70 #ifndef QT_NO_TEXTEDIT
       
    71 
       
    72 QT_BEGIN_NAMESPACE
       
    73 
       
    74 static inline bool shouldEnableInputMethod(QPlainTextEdit *plaintextedit)
       
    75 {
       
    76     return !plaintextedit->isReadOnly();
       
    77 }
       
    78 
       
    79 class QPlainTextDocumentLayoutPrivate : public QAbstractTextDocumentLayoutPrivate
       
    80 {
       
    81     Q_DECLARE_PUBLIC(QPlainTextDocumentLayout)
       
    82 public:
       
    83     QPlainTextDocumentLayoutPrivate() {
       
    84         mainViewPrivate = 0;
       
    85         width = 0;
       
    86         maximumWidth = 0;
       
    87         maximumWidthBlockNumber = 0;
       
    88         blockCount = 1;
       
    89         blockUpdate = blockDocumentSizeChanged = false;
       
    90         cursorWidth = 1;
       
    91         textLayoutFlags = 0;
       
    92     }
       
    93 
       
    94     qreal width;
       
    95     qreal maximumWidth;
       
    96     int maximumWidthBlockNumber;
       
    97     int blockCount;
       
    98     QPlainTextEditPrivate *mainViewPrivate;
       
    99     bool blockUpdate;
       
   100     bool blockDocumentSizeChanged;
       
   101     int cursorWidth;
       
   102     int textLayoutFlags;
       
   103 
       
   104     void layoutBlock(const QTextBlock &block);
       
   105     qreal blockWidth(const QTextBlock &block);
       
   106 
       
   107     void relayout();
       
   108 };
       
   109 
       
   110 
       
   111 
       
   112 /*! \class QPlainTextDocumentLayout
       
   113     \since 4.4
       
   114     \brief The QPlainTextDocumentLayout class implements a plain text layout for QTextDocument
       
   115 
       
   116     \ingroup richtext-processing
       
   117 
       
   118    A QPlainTextDocumentLayout is required for text documents that can
       
   119    be display or edited in a QPlainTextEdit. See
       
   120    QTextDocument::setDocumentLayout().
       
   121 
       
   122    QPlainTextDocumentLayout uses the QAbstractTextDocumentLayout API
       
   123    that QTextDocument requires, but redefines it partially in order to
       
   124    support plain text better. For instances, it does not operate on
       
   125    vertical pixels, but on paragraphs (called blocks) instead. The
       
   126    height of a document is identical to the number of paragraphs it
       
   127    contains. The layout also doesn't support tables or nested frames,
       
   128    or any sort of advanced text layout that goes beyond a list of
       
   129    paragraphs with syntax highlighting.
       
   130 
       
   131 */
       
   132 
       
   133 
       
   134 
       
   135 /*!
       
   136   Constructs a plain text document layout for the text \a document.
       
   137  */
       
   138 QPlainTextDocumentLayout::QPlainTextDocumentLayout(QTextDocument *document)
       
   139     :QAbstractTextDocumentLayout(* new QPlainTextDocumentLayoutPrivate, document) {
       
   140 }
       
   141 /*!
       
   142   Destructs a plain text document layout.
       
   143  */
       
   144 QPlainTextDocumentLayout::~QPlainTextDocumentLayout() {}
       
   145 
       
   146 
       
   147 /*!
       
   148   \reimp
       
   149  */
       
   150 void QPlainTextDocumentLayout::draw(QPainter *, const PaintContext &)
       
   151 {
       
   152 }
       
   153 
       
   154 /*!
       
   155   \reimp
       
   156  */
       
   157 int QPlainTextDocumentLayout::hitTest(const QPointF &, Qt::HitTestAccuracy ) const
       
   158 {
       
   159 //     this function is used from
       
   160 //     QAbstractTextDocumentLayout::anchorAt(), but is not
       
   161 //     implementable in a plain text document layout, because the
       
   162 //     layout depends on the top block and top line which depends on
       
   163 //     the view
       
   164     return -1;
       
   165 }
       
   166 
       
   167 /*!
       
   168   \reimp
       
   169  */
       
   170 int QPlainTextDocumentLayout::pageCount() const
       
   171 { return 1; }
       
   172 
       
   173 /*!
       
   174   \reimp
       
   175  */
       
   176 QSizeF QPlainTextDocumentLayout::documentSize() const
       
   177 {
       
   178     Q_D(const QPlainTextDocumentLayout);
       
   179     return QSizeF(d->maximumWidth, document()->lineCount());
       
   180 }
       
   181 
       
   182 /*!
       
   183   \reimp
       
   184  */
       
   185 QRectF QPlainTextDocumentLayout::frameBoundingRect(QTextFrame *) const
       
   186 {
       
   187     Q_D(const QPlainTextDocumentLayout);
       
   188     return QRectF(0, 0, qMax(d->width, d->maximumWidth), qreal(INT_MAX));
       
   189 }
       
   190 
       
   191 /*!
       
   192   \reimp
       
   193  */
       
   194 QRectF QPlainTextDocumentLayout::blockBoundingRect(const QTextBlock &block) const
       
   195 {
       
   196     if (!block.isValid()) { return QRectF(); }
       
   197     QTextLayout *tl = block.layout();
       
   198     if (!tl->lineCount())
       
   199         const_cast<QPlainTextDocumentLayout*>(this)->layoutBlock(block);
       
   200     QRectF br;
       
   201     if (block.isVisible()) {
       
   202         br = QRectF(QPointF(0, 0), tl->boundingRect().bottomRight());
       
   203         if (tl->lineCount() == 1)
       
   204             br.setWidth(qMax(br.width(), tl->lineAt(0).naturalTextWidth()));
       
   205         qreal margin = document()->documentMargin();
       
   206         br.adjust(0, 0, margin, 0);
       
   207         if (!block.next().isValid())
       
   208             br.adjust(0, 0, 0, margin);
       
   209     }
       
   210     return br;
       
   211 
       
   212 }
       
   213 
       
   214 /*!
       
   215   Ensures that \a block has a valid layout
       
   216  */
       
   217 void QPlainTextDocumentLayout::ensureBlockLayout(const QTextBlock &block) const
       
   218 {
       
   219     if (!block.isValid())
       
   220         return;
       
   221     QTextLayout *tl = block.layout();
       
   222     if (!tl->lineCount())
       
   223         const_cast<QPlainTextDocumentLayout*>(this)->layoutBlock(block);
       
   224 }
       
   225 
       
   226 
       
   227 /*! \property QPlainTextDocumentLayout::cursorWidth
       
   228 
       
   229     This property specifies the width of the cursor in pixels. The default value is 1.
       
   230 */
       
   231 void QPlainTextDocumentLayout::setCursorWidth(int width)
       
   232 {
       
   233     Q_D(QPlainTextDocumentLayout);
       
   234     d->cursorWidth = width;
       
   235 }
       
   236 
       
   237 int QPlainTextDocumentLayout::cursorWidth() const
       
   238 {
       
   239     Q_D(const QPlainTextDocumentLayout);
       
   240     return d->cursorWidth;
       
   241 }
       
   242 
       
   243 QPlainTextDocumentLayoutPrivate *QPlainTextDocumentLayout::priv() const
       
   244 {
       
   245     Q_D(const QPlainTextDocumentLayout);
       
   246     return const_cast<QPlainTextDocumentLayoutPrivate*>(d);
       
   247 }
       
   248 
       
   249 
       
   250 /*!
       
   251 
       
   252    Requests a complete update on all views.
       
   253  */
       
   254 void QPlainTextDocumentLayout::requestUpdate()
       
   255 {
       
   256     emit update(QRectF(0., -document()->documentMargin(), 1000000000., 1000000000.));
       
   257 }
       
   258 
       
   259 
       
   260 void QPlainTextDocumentLayout::setTextWidth(qreal newWidth)
       
   261 {
       
   262     Q_D(QPlainTextDocumentLayout);
       
   263     d->width = d->maximumWidth = newWidth;
       
   264     d->relayout();
       
   265 }
       
   266 
       
   267 qreal QPlainTextDocumentLayout::textWidth() const
       
   268 {
       
   269     Q_D(const QPlainTextDocumentLayout);
       
   270     return d->width;
       
   271 }
       
   272 
       
   273 void QPlainTextDocumentLayoutPrivate::relayout()
       
   274 {
       
   275     Q_Q(QPlainTextDocumentLayout);
       
   276     QTextBlock block = q->document()->firstBlock();
       
   277     while (block.isValid()) {
       
   278         block.layout()->clearLayout();
       
   279         block.setLineCount(block.isVisible() ? 1 : 0);
       
   280         block = block.next();
       
   281     }
       
   282     emit q->update();
       
   283 }
       
   284 
       
   285 
       
   286 /*! \reimp
       
   287  */
       
   288 void QPlainTextDocumentLayout::documentChanged(int from, int /*charsRemoved*/, int charsAdded)
       
   289 {
       
   290     Q_D(QPlainTextDocumentLayout);
       
   291     QTextDocument *doc = document();
       
   292     int newBlockCount = doc->blockCount();
       
   293 
       
   294     QTextBlock changeStartBlock = doc->findBlock(from);
       
   295     QTextBlock changeEndBlock = doc->findBlock(qMax(0, from + charsAdded - 1));
       
   296 
       
   297     if (changeStartBlock == changeEndBlock && newBlockCount == d->blockCount) {
       
   298         QTextBlock block = changeStartBlock;
       
   299         int blockLineCount = block.layout()->lineCount();
       
   300         if (block.isValid() && blockLineCount) {
       
   301             QRectF oldBr = blockBoundingRect(block);
       
   302             layoutBlock(block);
       
   303             QRectF newBr = blockBoundingRect(block);
       
   304             if (newBr.height() == oldBr.height()) {
       
   305                 if (!d->blockUpdate)
       
   306                     emit updateBlock(block);
       
   307                 return;
       
   308             }
       
   309         }
       
   310     } else {
       
   311         QTextBlock block = changeStartBlock;
       
   312         do {
       
   313             block.clearLayout();
       
   314             if (block == changeEndBlock)
       
   315                 break;
       
   316             block = block.next();
       
   317         } while(block.isValid());
       
   318     }
       
   319 
       
   320     if (newBlockCount != d->blockCount) {
       
   321 
       
   322         int changeEnd = changeEndBlock.blockNumber();
       
   323         int blockDiff = newBlockCount - d->blockCount;
       
   324         int oldChangeEnd = changeEnd - blockDiff;
       
   325 
       
   326         if (d->maximumWidthBlockNumber > oldChangeEnd)
       
   327             d->maximumWidthBlockNumber += blockDiff;
       
   328 
       
   329         d->blockCount = newBlockCount;
       
   330         if (d->blockCount == 1)
       
   331             d->maximumWidth = blockWidth(doc->firstBlock());
       
   332 
       
   333         if (!d->blockDocumentSizeChanged)
       
   334             emit documentSizeChanged(documentSize());
       
   335 
       
   336         if (blockDiff == 1 && changeEnd == newBlockCount -1 ) {
       
   337             if (!d->blockUpdate) {
       
   338                 QTextBlock b = changeStartBlock;
       
   339                 for(;;) {
       
   340                     emit updateBlock(b);
       
   341                     if (b == changeEndBlock)
       
   342                         break;
       
   343                     b = b.next();
       
   344                 }
       
   345             }
       
   346             return;
       
   347         }
       
   348     }
       
   349 
       
   350     if (!d->blockUpdate)
       
   351 	emit update(QRectF(0., -doc->documentMargin(), 1000000000., 1000000000.)); // optimization potential
       
   352 }
       
   353 
       
   354 
       
   355 void QPlainTextDocumentLayout::layoutBlock(const QTextBlock &block)
       
   356 {
       
   357     Q_D(QPlainTextDocumentLayout);
       
   358     QTextDocument *doc = document();
       
   359     qreal margin = doc->documentMargin();
       
   360     qreal blockMaximumWidth = 0;
       
   361 
       
   362     qreal height = 0;
       
   363     QTextLayout *tl = block.layout();
       
   364     QTextOption option = doc->defaultTextOption();
       
   365     tl->setTextOption(option);
       
   366 
       
   367     int extraMargin = 0;
       
   368     if (option.flags() & QTextOption::AddSpaceForLineAndParagraphSeparators) {
       
   369         QFontMetrics fm(block.charFormat().font());
       
   370         extraMargin += fm.width(QChar(0x21B5));
       
   371     }
       
   372     tl->beginLayout();
       
   373     qreal availableWidth = d->width;
       
   374     if (availableWidth <= 0) {
       
   375         availableWidth = qreal(INT_MAX); // similar to text edit with pageSize.width == 0
       
   376     }
       
   377     availableWidth -= 2*margin + extraMargin;
       
   378     while (1) {
       
   379         QTextLine line = tl->createLine();
       
   380         if (!line.isValid())
       
   381             break;
       
   382         line.setLeadingIncluded(true);
       
   383         line.setLineWidth(availableWidth);
       
   384         line.setPosition(QPointF(margin, height));
       
   385         height += line.height();
       
   386         blockMaximumWidth = qMax(blockMaximumWidth, line.naturalTextWidth() + 2*margin);
       
   387     }
       
   388     tl->endLayout();
       
   389 
       
   390     int previousLineCount = doc->lineCount();
       
   391     const_cast<QTextBlock&>(block).setLineCount(block.isVisible() ? tl->lineCount() : 0);
       
   392     int lineCount = doc->lineCount();
       
   393 
       
   394     bool emitDocumentSizeChanged = previousLineCount != lineCount;
       
   395     if (blockMaximumWidth > d->maximumWidth) {
       
   396         // new longest line
       
   397         d->maximumWidth = blockMaximumWidth;
       
   398         d->maximumWidthBlockNumber = block.blockNumber();
       
   399         emitDocumentSizeChanged = true;
       
   400     } else if (block.blockNumber() == d->maximumWidthBlockNumber && blockMaximumWidth < d->maximumWidth) {
       
   401         // longest line shrinking
       
   402         QTextBlock b = doc->firstBlock();
       
   403         d->maximumWidth = 0;
       
   404         QTextBlock maximumBlock;
       
   405         while (b.isValid()) {
       
   406             qreal blockMaximumWidth = blockWidth(b);
       
   407             if (blockMaximumWidth > d->maximumWidth) {
       
   408                 d->maximumWidth = blockMaximumWidth;
       
   409                 maximumBlock = b;
       
   410             }
       
   411             b = b.next();
       
   412         }
       
   413         if (maximumBlock.isValid()) {
       
   414             d->maximumWidthBlockNumber = maximumBlock.blockNumber();
       
   415             emitDocumentSizeChanged = true;
       
   416         }
       
   417     }
       
   418     if (emitDocumentSizeChanged && !d->blockDocumentSizeChanged)
       
   419         emit documentSizeChanged(documentSize());
       
   420 }
       
   421 
       
   422 qreal QPlainTextDocumentLayout::blockWidth(const QTextBlock &block)
       
   423 {
       
   424     QTextLayout *layout = block.layout();
       
   425     if (!layout->lineCount())
       
   426         return 0; // only for layouted blocks
       
   427     qreal blockWidth = 0;
       
   428     for (int i = 0; i < layout->lineCount(); ++i) {
       
   429         QTextLine line = layout->lineAt(i);
       
   430         blockWidth = qMax(line.naturalTextWidth() + 8, blockWidth);
       
   431     }
       
   432     return blockWidth;
       
   433 }
       
   434 
       
   435 
       
   436 QPlainTextEditControl::QPlainTextEditControl(QPlainTextEdit *parent)
       
   437     : QTextControl(parent), textEdit(parent),
       
   438       topBlock(0)
       
   439 {
       
   440     setAcceptRichText(false);
       
   441 }
       
   442 
       
   443 void QPlainTextEditPrivate::_q_cursorPositionChanged()
       
   444 {
       
   445     pageUpDownLastCursorYIsValid = false;
       
   446 }
       
   447 
       
   448 void QPlainTextEditPrivate::_q_verticalScrollbarActionTriggered(int action) {
       
   449     if (action == QAbstractSlider::SliderPageStepAdd) {
       
   450         pageUpDown(QTextCursor::Down, QTextCursor::MoveAnchor, false);
       
   451     } else if (action == QAbstractSlider::SliderPageStepSub) {
       
   452         pageUpDown(QTextCursor::Up, QTextCursor::MoveAnchor, false);
       
   453     }
       
   454 }
       
   455 
       
   456 QMimeData *QPlainTextEditControl::createMimeDataFromSelection() const {
       
   457         QPlainTextEdit *ed = qobject_cast<QPlainTextEdit *>(parent());
       
   458         if (!ed)
       
   459             return QTextControl::createMimeDataFromSelection();
       
   460         return ed->createMimeDataFromSelection();
       
   461     }
       
   462 bool QPlainTextEditControl::canInsertFromMimeData(const QMimeData *source) const {
       
   463     QPlainTextEdit *ed = qobject_cast<QPlainTextEdit *>(parent());
       
   464     if (!ed)
       
   465         return QTextControl::canInsertFromMimeData(source);
       
   466     return ed->canInsertFromMimeData(source);
       
   467 }
       
   468 void QPlainTextEditControl::insertFromMimeData(const QMimeData *source) {
       
   469     QPlainTextEdit *ed = qobject_cast<QPlainTextEdit *>(parent());
       
   470     if (!ed)
       
   471         QTextControl::insertFromMimeData(source);
       
   472     else
       
   473         ed->insertFromMimeData(source);
       
   474 }
       
   475 
       
   476 int QPlainTextEditPrivate::verticalOffset(int topBlock, int topLine) const
       
   477 {
       
   478     qreal offset = 0;
       
   479     QTextDocument *doc = control->document();
       
   480 
       
   481     if (topLine) {
       
   482         QTextBlock currentBlock = doc->findBlockByNumber(topBlock);
       
   483         QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout());
       
   484         Q_ASSERT(documentLayout);
       
   485         QRectF r = documentLayout->blockBoundingRect(currentBlock);
       
   486         QTextLayout *layout = currentBlock.layout();
       
   487         if (layout && topLine <= layout->lineCount()) {
       
   488             QTextLine line = layout->lineAt(topLine - 1);
       
   489             const QRectF lr = line.naturalTextRect();
       
   490             offset = lr.bottom();
       
   491         }
       
   492     }
       
   493     if (topBlock == 0 && topLine == 0)
       
   494         offset -= doc->documentMargin(); // top margin
       
   495     return (int)offset;
       
   496 }
       
   497 
       
   498 
       
   499 int QPlainTextEditPrivate::verticalOffset() const {
       
   500     return verticalOffset(control->topBlock, topLine);
       
   501 }
       
   502 
       
   503 
       
   504 QTextBlock QPlainTextEditControl::firstVisibleBlock() const
       
   505 {
       
   506     return document()->findBlockByNumber(topBlock);
       
   507 }
       
   508 
       
   509 
       
   510 
       
   511 int QPlainTextEditControl::hitTest(const QPointF &point, Qt::HitTestAccuracy ) const {
       
   512     int currentBlockNumber = topBlock;
       
   513     QTextBlock currentBlock = document()->findBlockByNumber(currentBlockNumber);
       
   514     if (!currentBlock.isValid())
       
   515         return -1;
       
   516 
       
   517     QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document()->documentLayout());
       
   518     Q_ASSERT(documentLayout);
       
   519 
       
   520     QPointF offset;
       
   521     QRectF r = documentLayout->blockBoundingRect(currentBlock);
       
   522     while (currentBlock.next().isValid() && r.bottom() + offset.y() <= point.y()) {
       
   523         offset.ry() += r.height();
       
   524         currentBlock = currentBlock.next();
       
   525         ++currentBlockNumber;
       
   526         r = documentLayout->blockBoundingRect(currentBlock);
       
   527     }
       
   528     while (currentBlock.previous().isValid() && r.top() + offset.y() > point.y()) {
       
   529         offset.ry() -= r.height();
       
   530         currentBlock = currentBlock.previous();
       
   531         --currentBlockNumber;
       
   532         r = documentLayout->blockBoundingRect(currentBlock);
       
   533     }
       
   534 
       
   535 
       
   536     if (!currentBlock.isValid())
       
   537         return -1;
       
   538     QTextLayout *layout = currentBlock.layout();
       
   539     int off = 0;
       
   540     QPointF pos = point - offset;
       
   541     for (int i = 0; i < layout->lineCount(); ++i) {
       
   542         QTextLine line = layout->lineAt(i);
       
   543         const QRectF lr = line.naturalTextRect();
       
   544         if (lr.top() > pos.y()) {
       
   545             off = qMin(off, line.textStart());
       
   546         } else if (lr.bottom() <= pos.y()) {
       
   547             off = qMax(off, line.textStart() + line.textLength());
       
   548         } else {
       
   549             off = line.xToCursor(pos.x(), overwriteMode() ?
       
   550                                  QTextLine::CursorOnCharacter : QTextLine::CursorBetweenCharacters);
       
   551             break;
       
   552         }
       
   553     }
       
   554 
       
   555     return currentBlock.position() + off;
       
   556 }
       
   557 
       
   558 QRectF QPlainTextEditControl::blockBoundingRect(const QTextBlock &block) const {
       
   559     int currentBlockNumber = topBlock;
       
   560     int blockNumber = block.blockNumber();
       
   561     QTextBlock currentBlock = document()->findBlockByNumber(currentBlockNumber);
       
   562     if (!currentBlock.isValid())
       
   563         return QRectF();
       
   564     Q_ASSERT(currentBlock.blockNumber() == currentBlockNumber);
       
   565     QTextDocument *doc = document();
       
   566     QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout());
       
   567     Q_ASSERT(documentLayout);
       
   568 
       
   569     QPointF offset;
       
   570     if (!block.isValid())
       
   571         return QRectF();
       
   572     QRectF r = documentLayout->blockBoundingRect(currentBlock);
       
   573     int maxVerticalOffset = r.height();
       
   574     while (currentBlockNumber < blockNumber && offset.y() - maxVerticalOffset <= 2* textEdit->viewport()->height()) {
       
   575         offset.ry() += r.height();
       
   576         currentBlock = currentBlock.next();
       
   577         ++currentBlockNumber;
       
   578         if (!currentBlock.isVisible()) {
       
   579             currentBlock = doc->findBlockByLineNumber(currentBlock.firstLineNumber());
       
   580             currentBlockNumber = currentBlock.blockNumber();
       
   581         }
       
   582         r = documentLayout->blockBoundingRect(currentBlock);
       
   583     }
       
   584     while (currentBlockNumber > blockNumber && offset.y() + maxVerticalOffset >= -textEdit->viewport()->height()) {
       
   585         currentBlock = currentBlock.previous();
       
   586         --currentBlockNumber;
       
   587         while (!currentBlock.isVisible()) {
       
   588             currentBlock = currentBlock.previous();
       
   589             --currentBlockNumber;
       
   590         }
       
   591         if (!currentBlock.isValid())
       
   592             break;
       
   593 
       
   594         r = documentLayout->blockBoundingRect(currentBlock);
       
   595         offset.ry() -= r.height();
       
   596     }
       
   597 
       
   598     if (currentBlockNumber != blockNumber) {
       
   599         // fallback for blocks out of reach. Give it some geometry at
       
   600         // least, and ensure the layout is up to date.
       
   601         r = documentLayout->blockBoundingRect(block);
       
   602         if (currentBlockNumber > blockNumber)
       
   603             offset.ry() -= r.height();
       
   604     }
       
   605     r.translate(offset);
       
   606     return r;
       
   607 }
       
   608 
       
   609 
       
   610 void QPlainTextEditPrivate::setTopLine(int visualTopLine, int dx)
       
   611 {
       
   612     QTextDocument *doc = control->document();
       
   613     QTextBlock block = doc->findBlockByLineNumber(visualTopLine);
       
   614     int blockNumber = block.blockNumber();
       
   615     int lineNumber = visualTopLine - block.firstLineNumber();
       
   616     setTopBlock(blockNumber, lineNumber, dx);
       
   617 }
       
   618 
       
   619 void QPlainTextEditPrivate::setTopBlock(int blockNumber, int lineNumber, int dx)
       
   620 {
       
   621     Q_Q(QPlainTextEdit);
       
   622     blockNumber = qMax(0, blockNumber);
       
   623     lineNumber = qMax(0, lineNumber);
       
   624     QTextDocument *doc = control->document();
       
   625     QTextBlock block = doc->findBlockByNumber(blockNumber);
       
   626 
       
   627     int newTopLine = block.firstLineNumber() + lineNumber;
       
   628     int maxTopLine = vbar->maximum();
       
   629 
       
   630     if (newTopLine > maxTopLine) {
       
   631         block = doc->findBlockByLineNumber(maxTopLine);
       
   632         blockNumber = block.blockNumber();
       
   633         lineNumber = maxTopLine - block.firstLineNumber();
       
   634     }
       
   635 
       
   636     bool vbarSignalsBlocked = vbar->blockSignals(true);
       
   637     vbar->setValue(newTopLine);
       
   638     vbar->blockSignals(vbarSignalsBlocked);
       
   639 
       
   640     if (!dx && blockNumber == control->topBlock && lineNumber == topLine)
       
   641         return;
       
   642 
       
   643     if (viewport->updatesEnabled() && viewport->isVisible()) {
       
   644         int dy = 0;
       
   645         if (doc->findBlockByNumber(control->topBlock).isValid()) {
       
   646             dy = (int)(-q->blockBoundingGeometry(block).y())
       
   647                  + verticalOffset() - verticalOffset(blockNumber, lineNumber);
       
   648         }
       
   649         control->topBlock = blockNumber;
       
   650         topLine = lineNumber;
       
   651         if (dx || dy)
       
   652             viewport->scroll(q->isRightToLeft() ? -dx : dx, dy);
       
   653         else
       
   654             viewport->update();
       
   655         emit q->updateRequest(viewport->rect(), dy);
       
   656     } else {
       
   657         control->topBlock = blockNumber;
       
   658         topLine = lineNumber;
       
   659     }
       
   660 
       
   661 }
       
   662 
       
   663 
       
   664 
       
   665 void QPlainTextEditPrivate::ensureVisible(int position, bool center, bool forceCenter) {
       
   666     Q_Q(QPlainTextEdit);
       
   667     QRectF visible = QRectF(viewport->rect()).translated(-q->contentOffset());
       
   668     QTextBlock block = control->document()->findBlock(position);
       
   669     if (!block.isValid())
       
   670         return;
       
   671     QRectF br = control->blockBoundingRect(block);
       
   672     if (!br.isValid())
       
   673         return;
       
   674     QRectF lr = br;
       
   675     QTextLine line = block.layout()->lineForTextPosition(position - block.position());
       
   676     Q_ASSERT(line.isValid());
       
   677     lr = line.naturalTextRect().translated(br.topLeft());
       
   678 
       
   679     if (lr.bottom() >= visible.bottom() || (center && lr.top() < visible.top()) || forceCenter){
       
   680 
       
   681         qreal height = visible.height();
       
   682         if (center)
       
   683             height /= 2;
       
   684 
       
   685         qreal h = center ? line.naturalTextRect().center().y() : line.naturalTextRect().bottom();
       
   686 
       
   687         QTextBlock previousVisibleBlock = block;
       
   688         while (h < height && block.previous().isValid()) {
       
   689             previousVisibleBlock = block;
       
   690             do {
       
   691                 block = block.previous();
       
   692             } while (!block.isVisible() && block.previous().isValid());
       
   693             h += q->blockBoundingRect(block).height();
       
   694         }
       
   695 
       
   696         int l = 0;
       
   697         int lineCount = block.layout()->lineCount();
       
   698         int voffset = verticalOffset(block.blockNumber(), 0);
       
   699         while (l < lineCount) {
       
   700             QRectF lineRect = block.layout()->lineAt(l).naturalTextRect();
       
   701             if (h - voffset - lineRect.top() <= height)
       
   702                 break;
       
   703             ++l;
       
   704         }
       
   705 
       
   706         if (l >= lineCount) {
       
   707             block = previousVisibleBlock;
       
   708             l = 0;
       
   709         }
       
   710         setTopBlock(block.blockNumber(), l);
       
   711     } else if (lr.top() < visible.top()) {
       
   712         setTopBlock(block.blockNumber(), line.lineNumber());
       
   713     }
       
   714 
       
   715 }
       
   716 
       
   717 
       
   718 void QPlainTextEditPrivate::updateViewport()
       
   719 {
       
   720     Q_Q(QPlainTextEdit);
       
   721     viewport->update();
       
   722     emit q->updateRequest(viewport->rect(), 0);
       
   723 }
       
   724 
       
   725 QPlainTextEditPrivate::QPlainTextEditPrivate()
       
   726     : control(0),
       
   727       tabChangesFocus(false),
       
   728       lineWrap(QPlainTextEdit::WidgetWidth),
       
   729       wordWrap(QTextOption::WrapAtWordBoundaryOrAnywhere),
       
   730       clickCausedFocus(0),topLine(0), 
       
   731       pageUpDownLastCursorYIsValid(false)
       
   732 {
       
   733     showCursorOnInitialShow = true;
       
   734     backgroundVisible = false;
       
   735     centerOnScroll = false;
       
   736     inDrag = false;
       
   737 }
       
   738 
       
   739 
       
   740 void QPlainTextEditPrivate::init(const QString &txt)
       
   741 {
       
   742     Q_Q(QPlainTextEdit);
       
   743     control = new QPlainTextEditControl(q);
       
   744 
       
   745     QTextDocument *doc = new QTextDocument(control);
       
   746     QAbstractTextDocumentLayout *layout = new QPlainTextDocumentLayout(doc);
       
   747     doc->setDocumentLayout(layout);
       
   748     control->setDocument(doc);
       
   749 
       
   750     control->setPalette(q->palette());
       
   751 
       
   752     QObject::connect(vbar, SIGNAL(actionTriggered(int)), q, SLOT(_q_verticalScrollbarActionTriggered(int)));
       
   753 
       
   754     QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(updateMicroFocus()));
       
   755     QObject::connect(control, SIGNAL(documentSizeChanged(QSizeF)), q, SLOT(_q_adjustScrollbars()));
       
   756     QObject::connect(control, SIGNAL(blockCountChanged(int)), q, SIGNAL(blockCountChanged(int)));
       
   757     QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(_q_repaintContents(QRectF)));
       
   758     QObject::connect(control, SIGNAL(modificationChanged(bool)), q, SIGNAL(modificationChanged(bool)));
       
   759 
       
   760     QObject::connect(control, SIGNAL(textChanged()), q, SIGNAL(textChanged()));
       
   761     QObject::connect(control, SIGNAL(undoAvailable(bool)), q, SIGNAL(undoAvailable(bool)));
       
   762     QObject::connect(control, SIGNAL(redoAvailable(bool)), q, SIGNAL(redoAvailable(bool)));
       
   763     QObject::connect(control, SIGNAL(copyAvailable(bool)), q, SIGNAL(copyAvailable(bool)));
       
   764     QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
       
   765     QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(_q_cursorPositionChanged()));
       
   766     QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
       
   767 
       
   768     QObject::connect(control, SIGNAL(textChanged()), q, SLOT(updateMicroFocus()));
       
   769 
       
   770     // set a null page size initially to avoid any relayouting until the textedit
       
   771     // is shown. relayoutDocument() will take care of setting the page size to the
       
   772     // viewport dimensions later.
       
   773     doc->setTextWidth(-1);
       
   774     doc->documentLayout()->setPaintDevice(viewport);
       
   775     doc->setDefaultFont(q->font());
       
   776 
       
   777 
       
   778     if (!txt.isEmpty())
       
   779         control->setPlainText(txt);
       
   780 
       
   781     hbar->setSingleStep(20);
       
   782     vbar->setSingleStep(1);
       
   783 
       
   784     viewport->setBackgroundRole(QPalette::Base);
       
   785     q->setAcceptDrops(true);
       
   786     q->setFocusPolicy(Qt::WheelFocus);
       
   787     q->setAttribute(Qt::WA_KeyCompression);
       
   788     q->setAttribute(Qt::WA_InputMethodEnabled);
       
   789 
       
   790 #ifndef QT_NO_CURSOR
       
   791     viewport->setCursor(Qt::IBeamCursor);
       
   792 #endif
       
   793     originalOffsetY = 0;
       
   794 #ifdef Q_WS_WIN
       
   795     setSingleFingerPanEnabled(true);
       
   796 #endif
       
   797 }
       
   798 
       
   799 void QPlainTextEditPrivate::_q_repaintContents(const QRectF &contentsRect)
       
   800 {
       
   801     Q_Q(QPlainTextEdit);
       
   802     if (!contentsRect.isValid()) {
       
   803         updateViewport();
       
   804         return;
       
   805     }
       
   806     const int xOffset = horizontalOffset();
       
   807     const int yOffset = verticalOffset();
       
   808     const QRect visibleRect(xOffset, yOffset, viewport->width(), viewport->height());
       
   809 
       
   810     QRect r = contentsRect.adjusted(-1, -1, 1, 1).intersected(visibleRect).toAlignedRect();
       
   811     if (r.isEmpty())
       
   812         return;
       
   813 
       
   814     r.translate(-xOffset, -yOffset);
       
   815     viewport->update(r);
       
   816     emit q->updateRequest(r, 0);
       
   817 }
       
   818 
       
   819 void QPlainTextEditPrivate::pageUpDown(QTextCursor::MoveOperation op, QTextCursor::MoveMode moveMode, bool moveCursor)
       
   820 {
       
   821 
       
   822     Q_Q(QPlainTextEdit);
       
   823 
       
   824     QTextCursor cursor = control->textCursor();
       
   825     if (moveCursor) {
       
   826         ensureCursorVisible();
       
   827         if (!pageUpDownLastCursorYIsValid)
       
   828             pageUpDownLastCursorY = control->cursorRect(cursor).top() - verticalOffset();
       
   829     }
       
   830 
       
   831     qreal lastY = pageUpDownLastCursorY;
       
   832 
       
   833 
       
   834     if (op == QTextCursor::Down) {
       
   835         QRectF visible = QRectF(viewport->rect()).translated(-q->contentOffset());
       
   836         QTextBlock firstVisibleBlock = q->firstVisibleBlock();
       
   837         QTextBlock block = firstVisibleBlock;
       
   838         QRectF br = q->blockBoundingRect(block);
       
   839         qreal h = 0;
       
   840         int atEnd = false;
       
   841         while (h + br.height() <= visible.bottom()) {
       
   842             if (!block.next().isValid()) {
       
   843                 atEnd = true;
       
   844                 lastY = visible.bottom(); // set cursor to last line
       
   845                 break;
       
   846             }
       
   847             h += br.height();
       
   848             block = block.next();
       
   849             br = q->blockBoundingRect(block);
       
   850         }
       
   851 
       
   852         if (!atEnd) {
       
   853             int line = 0;
       
   854             qreal diff = visible.bottom() - h;
       
   855             int lineCount = block.layout()->lineCount();
       
   856             while (line < lineCount - 1) {
       
   857                 if (block.layout()->lineAt(line).naturalTextRect().bottom() > diff) {
       
   858                     // the first line that did not completely fit the screen
       
   859                     break;
       
   860                 }
       
   861                 ++line;
       
   862             }
       
   863             setTopBlock(block.blockNumber(), line);
       
   864         }
       
   865 
       
   866         if (moveCursor) {
       
   867             // move using movePosition to keep the cursor's x
       
   868             lastY += verticalOffset();
       
   869             bool moved = false;
       
   870             do {
       
   871                 moved = cursor.movePosition(op, moveMode);
       
   872             } while (moved && control->cursorRect(cursor).top() < lastY);
       
   873         }
       
   874 
       
   875     } else if (op == QTextCursor::Up) {
       
   876 
       
   877         QRectF visible = QRectF(viewport->rect()).translated(-q->contentOffset());
       
   878         visible.translate(0, -visible.height()); // previous page
       
   879         QTextBlock block = q->firstVisibleBlock();
       
   880         qreal h = 0;
       
   881         while (h >= visible.top()) {
       
   882             if (!block.previous().isValid()) {
       
   883                 if (control->topBlock == 0 && topLine == 0) {
       
   884                     lastY = 0; // set cursor to first line
       
   885                 }
       
   886                 break;
       
   887             }
       
   888             block = block.previous();
       
   889             QRectF br = q->blockBoundingRect(block);
       
   890             h -= br.height();
       
   891         }
       
   892 
       
   893         int line = 0;
       
   894         if (block.isValid()) {
       
   895             qreal diff = visible.top() - h;
       
   896             int lineCount = block.layout()->lineCount();
       
   897             while (line < lineCount) {
       
   898                 if (block.layout()->lineAt(line).naturalTextRect().top() >= diff)
       
   899                     break;
       
   900                 ++line;
       
   901             }
       
   902             if (line == lineCount) {
       
   903                 if (block.next().isValid() && block.next() != q->firstVisibleBlock()) {
       
   904                     block = block.next();
       
   905                     line = 0;
       
   906                 } else {
       
   907                     --line;
       
   908                 }
       
   909             }
       
   910         }
       
   911         setTopBlock(block.blockNumber(), line);
       
   912 
       
   913         if (moveCursor) {
       
   914             // move using movePosition to keep the cursor's x
       
   915             lastY += verticalOffset();
       
   916             bool moved = false;
       
   917             do {
       
   918                 moved = cursor.movePosition(op, moveMode);
       
   919             } while (moved && control->cursorRect(cursor).top() > lastY);
       
   920         }
       
   921     }
       
   922 
       
   923     if (moveCursor) {
       
   924         control->setTextCursor(cursor);
       
   925         pageUpDownLastCursorYIsValid = true;
       
   926     }
       
   927 }
       
   928 
       
   929 #ifndef QT_NO_SCROLLBAR
       
   930 
       
   931 void QPlainTextEditPrivate::_q_adjustScrollbars()
       
   932 {
       
   933     Q_Q(QPlainTextEdit);
       
   934     QTextDocument *doc = control->document();
       
   935     QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout());
       
   936     Q_ASSERT(documentLayout);
       
   937     bool documentSizeChangedBlocked = documentLayout->priv()->blockDocumentSizeChanged;
       
   938     documentLayout->priv()->blockDocumentSizeChanged = true;
       
   939     qreal margin = doc->documentMargin();
       
   940 
       
   941     int vmax = 0;
       
   942 
       
   943     int vSliderLength = 0;
       
   944     if (!centerOnScroll && q->isVisible()) {
       
   945         QTextBlock block = doc->lastBlock();
       
   946         const int visible = static_cast<int>(viewport->rect().height() - margin - 1);
       
   947         int y = 0;
       
   948         int visibleFromBottom = 0;
       
   949 
       
   950         while (block.isValid()) {
       
   951             if (!block.isVisible()) {
       
   952                 block = block.previous();
       
   953                 continue;
       
   954             }
       
   955             y += int(documentLayout->blockBoundingRect(block).height());
       
   956 
       
   957             QTextLayout *layout = block.layout();
       
   958             int layoutLineCount = layout->lineCount();
       
   959             if (y > visible) {
       
   960                 int lineNumber = 0;
       
   961                 while (lineNumber < layoutLineCount) {
       
   962                     QTextLine line = layout->lineAt(lineNumber);
       
   963                     const QRectF lr = line.naturalTextRect();
       
   964                     if (int(lr.top()) >= y - visible)
       
   965                         break;
       
   966                     ++lineNumber;
       
   967                 }
       
   968                 if (lineNumber < layoutLineCount)
       
   969                     visibleFromBottom += (layoutLineCount - lineNumber - 1);
       
   970                 break;
       
   971 
       
   972             }
       
   973             visibleFromBottom += layoutLineCount;
       
   974             block = block.previous();
       
   975         }
       
   976         vmax = qMax(0, doc->lineCount() - visibleFromBottom);
       
   977         vSliderLength = visibleFromBottom;
       
   978 
       
   979     } else {
       
   980         vmax = qMax(0, doc->lineCount() - 1);
       
   981         vSliderLength = viewport->height() / q->fontMetrics().lineSpacing();
       
   982     }
       
   983 
       
   984 
       
   985 
       
   986     QSizeF documentSize = documentLayout->documentSize();
       
   987     vbar->setRange(0, qMax(0, vmax));
       
   988     vbar->setPageStep(vSliderLength);
       
   989     int visualTopLine = vmax;
       
   990     QTextBlock firstVisibleBlock = q->firstVisibleBlock();
       
   991     if (firstVisibleBlock.isValid())
       
   992         visualTopLine = firstVisibleBlock.firstLineNumber() + topLine;
       
   993     bool vbarSignalsBlocked = vbar->blockSignals(true);
       
   994     vbar->setValue(visualTopLine);
       
   995     vbar->blockSignals(vbarSignalsBlocked);
       
   996 
       
   997     hbar->setRange(0, (int)documentSize.width() - viewport->width());
       
   998     hbar->setPageStep(viewport->width());
       
   999     documentLayout->priv()->blockDocumentSizeChanged = documentSizeChangedBlocked;
       
  1000     setTopLine(vbar->value());
       
  1001 }
       
  1002 
       
  1003 #endif
       
  1004 
       
  1005 
       
  1006 void QPlainTextEditPrivate::ensureViewportLayouted()
       
  1007 {
       
  1008 }
       
  1009 
       
  1010 /*!
       
  1011     \class QPlainTextEdit
       
  1012     \since 4.4
       
  1013     \brief The QPlainTextEdit class provides a widget that is used to edit and display
       
  1014     plain text.
       
  1015 
       
  1016     \ingroup richtext-processing
       
  1017 
       
  1018 
       
  1019     \tableofcontents
       
  1020 
       
  1021     \section1 Introduction and Concepts
       
  1022 
       
  1023     QPlainTextEdit is an advanced viewer/editor supporting plain
       
  1024     text. It is optimized to handle large documents and to respond
       
  1025     quickly to user input.
       
  1026 
       
  1027     QPlainText uses very much the same technology and concepts as
       
  1028     QTextEdit, but is optimized for plain text handling.
       
  1029 
       
  1030     QPlainTextEdit works on paragraphs and characters. A paragraph is
       
  1031     a formatted string which is word-wrapped to fit into the width of
       
  1032     the widget. By default when reading plain text, one newline
       
  1033     signifies a paragraph. A document consists of zero or more
       
  1034     paragraphs. Paragraphs are separated by hard line breaks. Each
       
  1035     character within a paragraph has its own attributes, for example,
       
  1036     font and color.
       
  1037 
       
  1038     The shape of the mouse cursor on a QPlainTextEdit is
       
  1039     Qt::IBeamCursor by default.  It can be changed through the
       
  1040     viewport()'s cursor property.
       
  1041 
       
  1042     \section1 Using QPlainTextEdit as a Display Widget
       
  1043 
       
  1044     The text is set or replaced using setPlainText() which deletes the
       
  1045     existing text and replaces it with the text passed to setPlainText().
       
  1046 
       
  1047     Text can be inserted using the QTextCursor class or using the
       
  1048     convenience functions insertPlainText(), appendPlainText() or
       
  1049     paste().
       
  1050 
       
  1051     By default, the text edit wraps words at whitespace to fit within
       
  1052     the text edit widget. The setLineWrapMode() function is used to
       
  1053     specify the kind of line wrap you want, \l WidgetWidth or \l
       
  1054     NoWrap if you don't want any wrapping.  If you use word wrap to
       
  1055     the widget's width \l WidgetWidth, you can specify whether to
       
  1056     break on whitespace or anywhere with setWordWrapMode().
       
  1057 
       
  1058     The find() function can be used to find and select a given string
       
  1059     within the text.
       
  1060 
       
  1061     If you want to limit the total number of paragraphs in a
       
  1062     QPlainTextEdit, as it is for example useful in a log viewer, then
       
  1063     you can use the maximumBlockCount property. The combination of
       
  1064     setMaximumBlockCount() and appendPlainText() turns QPlainTextEdit
       
  1065     into an efficient viewer for log text. The scrolling can be
       
  1066     reduced with the centerOnScroll() property, making the log viewer
       
  1067     even faster. Text can be formatted in a limited way, either using
       
  1068     a syntax highlighter (see below), or by appending html-formatted
       
  1069     text with appendHtml(). While QPlainTextEdit does not support
       
  1070     complex rich text rendering with tables and floats, it does
       
  1071     support limited paragraph-based formatting that you may need in a
       
  1072     log viewer.
       
  1073 
       
  1074     \section2 Read-only Key Bindings
       
  1075 
       
  1076     When QPlainTextEdit is used read-only the key bindings are limited to
       
  1077     navigation, and text may only be selected with the mouse:
       
  1078     \table
       
  1079     \header \i Keypresses \i Action
       
  1080     \row \i Qt::UpArrow        \i Moves one line up.
       
  1081     \row \i Qt::DownArrow        \i Moves one line down.
       
  1082     \row \i Qt::LeftArrow        \i Moves one character to the left.
       
  1083     \row \i Qt::RightArrow        \i Moves one character to the right.
       
  1084     \row \i PageUp        \i Moves one (viewport) page up.
       
  1085     \row \i PageDown        \i Moves one (viewport) page down.
       
  1086     \row \i Home        \i Moves to the beginning of the text.
       
  1087     \row \i End                \i Moves to the end of the text.
       
  1088     \row \i Alt+Wheel
       
  1089          \i Scrolls the page horizontally (the Wheel is the mouse wheel).
       
  1090     \row \i Ctrl+Wheel        \i Zooms the text.
       
  1091     \row \i Ctrl+A            \i Selects all text.
       
  1092     \endtable
       
  1093 
       
  1094 
       
  1095     \section1 Using QPlainTextEdit as an Editor
       
  1096 
       
  1097     All the information about using QPlainTextEdit as a display widget also
       
  1098     applies here.
       
  1099 
       
  1100     Selection of text is handled by the QTextCursor class, which provides
       
  1101     functionality for creating selections, retrieving the text contents or
       
  1102     deleting selections. You can retrieve the object that corresponds with
       
  1103     the user-visible cursor using the textCursor() method. If you want to set
       
  1104     a selection in QPlainTextEdit just create one on a QTextCursor object and
       
  1105     then make that cursor the visible cursor using setCursor(). The selection
       
  1106     can be copied to the clipboard with copy(), or cut to the clipboard with
       
  1107     cut(). The entire text can be selected using selectAll().
       
  1108 
       
  1109     QPlainTextEdit holds a QTextDocument object which can be retrieved using the
       
  1110     document() method. You can also set your own document object using setDocument().
       
  1111     QTextDocument emits a textChanged() signal if the text changes and it also
       
  1112     provides a isModified() function which will return true if the text has been
       
  1113     modified since it was either loaded or since the last call to setModified
       
  1114     with false as argument. In addition it provides methods for undo and redo.
       
  1115 
       
  1116     \section2 Syntax Highlighting
       
  1117 
       
  1118     Just like QTextEdit, QPlainTextEdit works together with
       
  1119     QSyntaxHighlighter.
       
  1120 
       
  1121     \section2 Editing Key Bindings
       
  1122 
       
  1123     The list of key bindings which are implemented for editing:
       
  1124     \table
       
  1125     \header \i Keypresses \i Action
       
  1126     \row \i Backspace \i Deletes the character to the left of the cursor.
       
  1127     \row \i Delete \i Deletes the character to the right of the cursor.
       
  1128     \row \i Ctrl+C \i Copy the selected text to the clipboard.
       
  1129     \row \i Ctrl+Insert \i Copy the selected text to the clipboard.
       
  1130     \row \i Ctrl+K \i Deletes to the end of the line.
       
  1131     \row \i Ctrl+V \i Pastes the clipboard text into text edit.
       
  1132     \row \i Shift+Insert \i Pastes the clipboard text into text edit.
       
  1133     \row \i Ctrl+X \i Deletes the selected text and copies it to the clipboard.
       
  1134     \row \i Shift+Delete \i Deletes the selected text and copies it to the clipboard.
       
  1135     \row \i Ctrl+Z \i Undoes the last operation.
       
  1136     \row \i Ctrl+Y \i Redoes the last operation.
       
  1137     \row \i LeftArrow \i Moves the cursor one character to the left.
       
  1138     \row \i Ctrl+LeftArrow \i Moves the cursor one word to the left.
       
  1139     \row \i RightArrow \i Moves the cursor one character to the right.
       
  1140     \row \i Ctrl+RightArrow \i Moves the cursor one word to the right.
       
  1141     \row \i UpArrow \i Moves the cursor one line up.
       
  1142     \row \i Ctrl+UpArrow \i Moves the cursor one word up.
       
  1143     \row \i DownArrow \i Moves the cursor one line down.
       
  1144     \row \i Ctrl+Down Arrow \i Moves the cursor one word down.
       
  1145     \row \i PageUp \i Moves the cursor one page up.
       
  1146     \row \i PageDown \i Moves the cursor one page down.
       
  1147     \row \i Home \i Moves the cursor to the beginning of the line.
       
  1148     \row \i Ctrl+Home \i Moves the cursor to the beginning of the text.
       
  1149     \row \i End \i Moves the cursor to the end of the line.
       
  1150     \row \i Ctrl+End \i Moves the cursor to the end of the text.
       
  1151     \row \i Alt+Wheel \i Scrolls the page horizontally (the Wheel is the mouse wheel).
       
  1152     \row \i Ctrl+Wheel \i Zooms the text.
       
  1153     \endtable
       
  1154 
       
  1155     To select (mark) text hold down the Shift key whilst pressing one
       
  1156     of the movement keystrokes, for example, \e{Shift+Right Arrow}
       
  1157     will select the character to the right, and \e{Shift+Ctrl+Right
       
  1158     Arrow} will select the word to the right, etc.
       
  1159 
       
  1160    \section1 Differences to QTextEdit
       
  1161 
       
  1162    QPlainTextEdit is a thin class, implemented by using most of the
       
  1163    technology that is behind QTextEdit and QTextDocument. Its
       
  1164    performance benefits over QTextEdit stem mostly from using a
       
  1165    different and simplified text layout called
       
  1166    QPlainTextDocumentLayout on the text document (see
       
  1167    QTextDocument::setDocumentLayout()). The plain text document layout
       
  1168    does not support tables nor embedded frames, and \e{replaces a
       
  1169    pixel-exact height calculation with a line-by-line respectively
       
  1170    paragraph-by-paragraph scrolling approach}. This makes it possible
       
  1171    to handle significantly larger documents, and still resize the
       
  1172    editor with line wrap enabled in real time. It also makes for a
       
  1173    fast log viewer (see setMaximumBlockCount()).
       
  1174 
       
  1175 
       
  1176     \sa QTextDocument, QTextCursor, {Application Example},
       
  1177         {Code Editor Example}, {Syntax Highlighter Example},
       
  1178         {Rich Text Processing}
       
  1179 
       
  1180 */
       
  1181 
       
  1182 /*!
       
  1183     \property QPlainTextEdit::plainText
       
  1184 
       
  1185     This property gets and sets the plain text editor's contents. The previous
       
  1186     contents are removed and undo/redo history is reset when this property is set.
       
  1187 
       
  1188     By default, for an editor with no contents, this property contains an empty string.
       
  1189 */
       
  1190 
       
  1191 /*!
       
  1192     \property QPlainTextEdit::undoRedoEnabled
       
  1193     \brief whether undo and redo are enabled
       
  1194 
       
  1195     Users are only able to undo or redo actions if this property is
       
  1196     true, and if there is an action that can be undone (or redone).
       
  1197 
       
  1198     By default, this property is true.
       
  1199 */
       
  1200 
       
  1201 /*!
       
  1202     \enum QPlainTextEdit::LineWrapMode
       
  1203 
       
  1204     \value NoWrap
       
  1205     \value WidgetWidth
       
  1206 */
       
  1207 
       
  1208 
       
  1209 /*!
       
  1210     Constructs an empty QPlainTextEdit with parent \a
       
  1211     parent.
       
  1212 */
       
  1213 QPlainTextEdit::QPlainTextEdit(QWidget *parent)
       
  1214     : QAbstractScrollArea(*new QPlainTextEditPrivate, parent)
       
  1215 {
       
  1216     Q_D(QPlainTextEdit);
       
  1217     d->init();
       
  1218 }
       
  1219 
       
  1220 /*!
       
  1221     \internal
       
  1222 */
       
  1223 QPlainTextEdit::QPlainTextEdit(QPlainTextEditPrivate &dd, QWidget *parent)
       
  1224     : QAbstractScrollArea(dd, parent)
       
  1225 {
       
  1226     Q_D(QPlainTextEdit);
       
  1227     d->init();
       
  1228 }
       
  1229 
       
  1230 /*!
       
  1231     Constructs a QPlainTextEdit with parent \a parent. The text edit will display
       
  1232     the plain text \a text.
       
  1233 */
       
  1234 QPlainTextEdit::QPlainTextEdit(const QString &text, QWidget *parent)
       
  1235     : QAbstractScrollArea(*new QPlainTextEditPrivate, parent)
       
  1236 {
       
  1237     Q_D(QPlainTextEdit);
       
  1238     d->init(text);
       
  1239 }
       
  1240 
       
  1241 
       
  1242 /*!
       
  1243     Destructor.
       
  1244 */
       
  1245 QPlainTextEdit::~QPlainTextEdit()
       
  1246 {
       
  1247     Q_D(QPlainTextEdit);
       
  1248     if (d->documentLayoutPtr) {
       
  1249         if (d->documentLayoutPtr->priv()->mainViewPrivate == d)
       
  1250             d->documentLayoutPtr->priv()->mainViewPrivate = 0;
       
  1251     }
       
  1252 }
       
  1253 
       
  1254 /*!
       
  1255     Makes \a document the new document of the text editor.
       
  1256 
       
  1257     The parent QObject of the provided document remains the owner
       
  1258     of the object. If the current document is a child of the text
       
  1259     editor, then it is deleted.
       
  1260 
       
  1261     The document must have a document layout that inherits
       
  1262     QPlainTextDocumentLayout (see QTextDocument::setDocumentLayout()).
       
  1263 
       
  1264     \sa document()
       
  1265 */
       
  1266 void QPlainTextEdit::setDocument(QTextDocument *document)
       
  1267 {
       
  1268     Q_D(QPlainTextEdit);
       
  1269     QPlainTextDocumentLayout *documentLayout = 0;
       
  1270 
       
  1271     if (!document) {
       
  1272         document = new QTextDocument(d->control);
       
  1273         documentLayout = new QPlainTextDocumentLayout(document);
       
  1274         document->setDocumentLayout(documentLayout);
       
  1275     } else {
       
  1276         documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document->documentLayout());
       
  1277         if (!documentLayout) {
       
  1278             qWarning("QPlainTextEdit::setDocument: Document set does not support QPlainTextDocumentLayout");
       
  1279             return;
       
  1280         }
       
  1281     }
       
  1282     d->control->setDocument(document);
       
  1283     if (!documentLayout->priv()->mainViewPrivate)
       
  1284         documentLayout->priv()->mainViewPrivate = d;
       
  1285     d->documentLayoutPtr = documentLayout;
       
  1286     d->updateDefaultTextOption();
       
  1287     d->relayoutDocument();
       
  1288     d->_q_adjustScrollbars();
       
  1289 }
       
  1290 
       
  1291 /*!
       
  1292     Returns a pointer to the underlying document.
       
  1293 
       
  1294     \sa setDocument()
       
  1295 */
       
  1296 QTextDocument *QPlainTextEdit::document() const
       
  1297 {
       
  1298     Q_D(const QPlainTextEdit);
       
  1299     return d->control->document();
       
  1300 }
       
  1301 
       
  1302 /*!
       
  1303     Sets the visible \a cursor.
       
  1304 */
       
  1305 void QPlainTextEdit::setTextCursor(const QTextCursor &cursor)
       
  1306 {
       
  1307     Q_D(QPlainTextEdit);
       
  1308     d->control->setTextCursor(cursor);
       
  1309 }
       
  1310 
       
  1311 /*!
       
  1312     Returns a copy of the QTextCursor that represents the currently visible cursor.
       
  1313     Note that changes on the returned cursor do not affect QPlainTextEdit's cursor; use
       
  1314     setTextCursor() to update the visible cursor.
       
  1315  */
       
  1316 QTextCursor QPlainTextEdit::textCursor() const
       
  1317 {
       
  1318     Q_D(const QPlainTextEdit);
       
  1319     return d->control->textCursor();
       
  1320 }
       
  1321 
       
  1322 
       
  1323 /*!
       
  1324     Undoes the last operation.
       
  1325 
       
  1326     If there is no operation to undo, i.e. there is no undo step in
       
  1327     the undo/redo history, nothing happens.
       
  1328 
       
  1329     \sa redo()
       
  1330 */
       
  1331 void QPlainTextEdit::undo()
       
  1332 {
       
  1333     Q_D(QPlainTextEdit);
       
  1334     d->control->undo();
       
  1335 }
       
  1336 
       
  1337 void QPlainTextEdit::redo()
       
  1338 {
       
  1339     Q_D(QPlainTextEdit);
       
  1340     d->control->redo();
       
  1341 }
       
  1342 
       
  1343 /*!
       
  1344     \fn void QPlainTextEdit::redo()
       
  1345 
       
  1346     Redoes the last operation.
       
  1347 
       
  1348     If there is no operation to redo, i.e. there is no redo step in
       
  1349     the undo/redo history, nothing happens.
       
  1350 
       
  1351     \sa undo()
       
  1352 */
       
  1353 
       
  1354 #ifndef QT_NO_CLIPBOARD
       
  1355 /*!
       
  1356     Copies the selected text to the clipboard and deletes it from
       
  1357     the text edit.
       
  1358 
       
  1359     If there is no selected text nothing happens.
       
  1360 
       
  1361     \sa copy() paste()
       
  1362 */
       
  1363 
       
  1364 void QPlainTextEdit::cut()
       
  1365 {
       
  1366     Q_D(QPlainTextEdit);
       
  1367     d->control->cut();
       
  1368 }
       
  1369 
       
  1370 /*!
       
  1371     Copies any selected text to the clipboard.
       
  1372 
       
  1373     \sa copyAvailable()
       
  1374 */
       
  1375 
       
  1376 void QPlainTextEdit::copy()
       
  1377 {
       
  1378     Q_D(QPlainTextEdit);
       
  1379     d->control->copy();
       
  1380 }
       
  1381 
       
  1382 /*!
       
  1383     Pastes the text from the clipboard into the text edit at the
       
  1384     current cursor position.
       
  1385 
       
  1386     If there is no text in the clipboard nothing happens.
       
  1387 
       
  1388     To change the behavior of this function, i.e. to modify what
       
  1389     QPlainTextEdit can paste and how it is being pasted, reimplement the
       
  1390     virtual canInsertFromMimeData() and insertFromMimeData()
       
  1391     functions.
       
  1392 
       
  1393     \sa cut() copy()
       
  1394 */
       
  1395 
       
  1396 void QPlainTextEdit::paste()
       
  1397 {
       
  1398     Q_D(QPlainTextEdit);
       
  1399     d->control->paste();
       
  1400 }
       
  1401 #endif
       
  1402 
       
  1403 /*!
       
  1404     Deletes all the text in the text edit.
       
  1405 
       
  1406     Note that the undo/redo history is cleared by this function.
       
  1407 
       
  1408     \sa cut() setPlainText()
       
  1409 */
       
  1410 void QPlainTextEdit::clear()
       
  1411 {
       
  1412     Q_D(QPlainTextEdit);
       
  1413     // clears and sets empty content
       
  1414     d->control->topBlock = d->topLine = 0;
       
  1415     d->control->clear();
       
  1416 }
       
  1417 
       
  1418 
       
  1419 /*!
       
  1420     Selects all text.
       
  1421 
       
  1422     \sa copy() cut() textCursor()
       
  1423  */
       
  1424 void QPlainTextEdit::selectAll()
       
  1425 {
       
  1426     Q_D(QPlainTextEdit);
       
  1427     d->control->selectAll();
       
  1428 }
       
  1429 
       
  1430 /*! \internal
       
  1431 */
       
  1432 bool QPlainTextEdit::event(QEvent *e)
       
  1433 {
       
  1434     Q_D(QPlainTextEdit);
       
  1435 
       
  1436 #ifndef QT_NO_CONTEXTMENU
       
  1437     if (e->type() == QEvent::ContextMenu
       
  1438         && static_cast<QContextMenuEvent *>(e)->reason() == QContextMenuEvent::Keyboard) {
       
  1439         ensureCursorVisible();
       
  1440         const QPoint cursorPos = cursorRect().center();
       
  1441         QContextMenuEvent ce(QContextMenuEvent::Keyboard, cursorPos, d->viewport->mapToGlobal(cursorPos));
       
  1442         ce.setAccepted(e->isAccepted());
       
  1443         const bool result = QAbstractScrollArea::event(&ce);
       
  1444         e->setAccepted(ce.isAccepted());
       
  1445         return result;
       
  1446     }
       
  1447 #endif // QT_NO_CONTEXTMENU
       
  1448     if (e->type() == QEvent::ShortcutOverride
       
  1449                || e->type() == QEvent::ToolTip) {
       
  1450         d->sendControlEvent(e);
       
  1451     }
       
  1452 #ifdef QT_KEYPAD_NAVIGATION
       
  1453     else if (e->type() == QEvent::EnterEditFocus || e->type() == QEvent::LeaveEditFocus) {
       
  1454         if (QApplication::keypadNavigationEnabled())
       
  1455             d->sendControlEvent(e);
       
  1456     }
       
  1457 #endif
       
  1458     else if (e->type() == QEvent::Gesture) {
       
  1459         QGestureEvent *ge = static_cast<QGestureEvent *>(e);
       
  1460         QPanGesture *g = static_cast<QPanGesture *>(ge->gesture(Qt::PanGesture));
       
  1461         if (g) {
       
  1462             QScrollBar *hBar = horizontalScrollBar();
       
  1463             QScrollBar *vBar = verticalScrollBar();
       
  1464             if (g->state() == Qt::GestureStarted)
       
  1465                 d->originalOffsetY = vBar->value();
       
  1466             QPointF offset = g->offset();
       
  1467             if (!offset.isNull()) {
       
  1468                 if (QApplication::isRightToLeft())
       
  1469                     offset.rx() *= -1;
       
  1470                 // QPlainTextEdit scrolls by lines only in vertical direction
       
  1471                 QFontMetrics fm(document()->defaultFont());
       
  1472                 int lineHeight = fm.height();
       
  1473                 int newX = hBar->value() - g->delta().x();
       
  1474                 int newY = d->originalOffsetY - offset.y()/lineHeight;
       
  1475                 hBar->setValue(newX);
       
  1476                 vBar->setValue(newY);
       
  1477             }
       
  1478         }
       
  1479         return true;
       
  1480     }
       
  1481     return QAbstractScrollArea::event(e);
       
  1482 }
       
  1483 
       
  1484 /*! \internal
       
  1485 */
       
  1486 
       
  1487 void QPlainTextEdit::timerEvent(QTimerEvent *e)
       
  1488 {
       
  1489     Q_D(QPlainTextEdit);
       
  1490     if (e->timerId() == d->autoScrollTimer.timerId()) {
       
  1491         QRect visible = d->viewport->rect();
       
  1492         QPoint pos;
       
  1493         if (d->inDrag) {
       
  1494             pos = d->autoScrollDragPos;
       
  1495             visible.adjust(qMin(visible.width()/3,20), qMin(visible.height()/3,20),
       
  1496                            -qMin(visible.width()/3,20), -qMin(visible.height()/3,20));
       
  1497         } else {
       
  1498             const QPoint globalPos = QCursor::pos();
       
  1499             pos = d->viewport->mapFromGlobal(globalPos);
       
  1500             QMouseEvent ev(QEvent::MouseMove, pos, globalPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
       
  1501             mouseMoveEvent(&ev);
       
  1502         }
       
  1503         int deltaY = qMax(pos.y() - visible.top(), visible.bottom() - pos.y()) - visible.height();
       
  1504         int deltaX = qMax(pos.x() - visible.left(), visible.right() - pos.x()) - visible.width();
       
  1505         int delta = qMax(deltaX, deltaY);
       
  1506         if (delta >= 0) {
       
  1507             if (delta < 7)
       
  1508                 delta = 7;
       
  1509             int timeout = 4900 / (delta * delta);
       
  1510             d->autoScrollTimer.start(timeout, this);
       
  1511 
       
  1512             if (deltaY > 0)
       
  1513                 d->vbar->triggerAction(pos.y() < visible.center().y() ?
       
  1514                                        QAbstractSlider::SliderSingleStepSub
       
  1515                                        : QAbstractSlider::SliderSingleStepAdd);
       
  1516             if (deltaX > 0)
       
  1517                 d->hbar->triggerAction(pos.x() < visible.center().x() ?
       
  1518                                        QAbstractSlider::SliderSingleStepSub
       
  1519                                        : QAbstractSlider::SliderSingleStepAdd);
       
  1520         }
       
  1521     }
       
  1522 #ifdef QT_KEYPAD_NAVIGATION
       
  1523     else if (e->timerId() == d->deleteAllTimer.timerId()) {
       
  1524         d->deleteAllTimer.stop();
       
  1525         clear();
       
  1526     }
       
  1527 #endif
       
  1528 }
       
  1529 
       
  1530 /*!
       
  1531     Changes the text of the text edit to the string \a text.
       
  1532     Any previous text is removed.
       
  1533 
       
  1534     \a text is interpreted as plain text.
       
  1535 
       
  1536     Note that the undo/redo history is cleared by this function.
       
  1537 
       
  1538     \sa toText()
       
  1539 */
       
  1540 
       
  1541 void QPlainTextEdit::setPlainText(const QString &text)
       
  1542 {
       
  1543     Q_D(QPlainTextEdit);
       
  1544     d->control->setPlainText(text);
       
  1545 }
       
  1546 
       
  1547 /*!
       
  1548     \fn QString QPlainTextEdit::toPlainText() const
       
  1549 
       
  1550     Returns the text of the text edit as plain text.
       
  1551 
       
  1552     \sa QPlainTextEdit::setPlainText()
       
  1553  */
       
  1554 
       
  1555 /*! \reimp
       
  1556 */
       
  1557 void QPlainTextEdit::keyPressEvent(QKeyEvent *e)
       
  1558 {
       
  1559     Q_D(QPlainTextEdit);
       
  1560 
       
  1561 #ifdef QT_KEYPAD_NAVIGATION
       
  1562     switch (e->key()) {
       
  1563         case Qt::Key_Select:
       
  1564             if (QApplication::keypadNavigationEnabled()) {
       
  1565                 if (!(d->control->textInteractionFlags() & Qt::LinksAccessibleByKeyboard))
       
  1566                     setEditFocus(!hasEditFocus());
       
  1567                 else {
       
  1568                     if (!hasEditFocus())
       
  1569                         setEditFocus(true);
       
  1570                     else {
       
  1571                         QTextCursor cursor = d->control->textCursor();
       
  1572                         QTextCharFormat charFmt = cursor.charFormat();
       
  1573                         if (!cursor.hasSelection() || charFmt.anchorHref().isEmpty()) {
       
  1574                             setEditFocus(false);
       
  1575                         }
       
  1576                     }
       
  1577                 }
       
  1578             }
       
  1579             break;
       
  1580         case Qt::Key_Back:
       
  1581         case Qt::Key_No:
       
  1582             if (!QApplication::keypadNavigationEnabled()
       
  1583                     || (QApplication::keypadNavigationEnabled() && !hasEditFocus())) {
       
  1584                 e->ignore();
       
  1585                 return;
       
  1586             }
       
  1587             break;
       
  1588         default:
       
  1589             if (QApplication::keypadNavigationEnabled()) {
       
  1590                 if (!hasEditFocus() && !(e->modifiers() & Qt::ControlModifier)) {
       
  1591                     if (e->text()[0].isPrint()) {
       
  1592                         setEditFocus(true);
       
  1593                         clear();
       
  1594                     } else {
       
  1595                         e->ignore();
       
  1596                         return;
       
  1597                     }
       
  1598                 }
       
  1599             }
       
  1600             break;
       
  1601     }
       
  1602 #endif
       
  1603 
       
  1604 #ifndef QT_NO_SHORTCUT
       
  1605 
       
  1606     Qt::TextInteractionFlags tif = d->control->textInteractionFlags();
       
  1607 
       
  1608     if (tif & Qt::TextSelectableByKeyboard){
       
  1609         if (e == QKeySequence::SelectPreviousPage) {
       
  1610             e->accept();
       
  1611             d->pageUpDown(QTextCursor::Up, QTextCursor::KeepAnchor);
       
  1612             return;
       
  1613         } else if (e ==QKeySequence::SelectNextPage) {
       
  1614             e->accept();
       
  1615             d->pageUpDown(QTextCursor::Down, QTextCursor::KeepAnchor);
       
  1616             return;
       
  1617         }
       
  1618     }
       
  1619     if (tif & (Qt::TextSelectableByKeyboard | Qt::TextEditable)) {
       
  1620         if (e == QKeySequence::MoveToPreviousPage) {
       
  1621             e->accept();
       
  1622             d->pageUpDown(QTextCursor::Up, QTextCursor::MoveAnchor);
       
  1623             return;
       
  1624         } else if (e == QKeySequence::MoveToNextPage) {
       
  1625             e->accept();
       
  1626             d->pageUpDown(QTextCursor::Down, QTextCursor::MoveAnchor);
       
  1627             return;
       
  1628         }
       
  1629     }
       
  1630 
       
  1631     if (!(tif & Qt::TextEditable)) {
       
  1632         switch (e->key()) {
       
  1633             case Qt::Key_Space:
       
  1634                 e->accept();
       
  1635                 if (e->modifiers() & Qt::ShiftModifier)
       
  1636                     d->vbar->triggerAction(QAbstractSlider::SliderPageStepSub);
       
  1637                 else
       
  1638                     d->vbar->triggerAction(QAbstractSlider::SliderPageStepAdd);
       
  1639                 break;
       
  1640             default:
       
  1641                 d->sendControlEvent(e);
       
  1642                 if (!e->isAccepted() && e->modifiers() == Qt::NoModifier) {
       
  1643                     if (e->key() == Qt::Key_Home) {
       
  1644                         d->vbar->triggerAction(QAbstractSlider::SliderToMinimum);
       
  1645                         e->accept();
       
  1646                     } else if (e->key() == Qt::Key_End) {
       
  1647                         d->vbar->triggerAction(QAbstractSlider::SliderToMaximum);
       
  1648                         e->accept();
       
  1649                     }
       
  1650                 }
       
  1651                 if (!e->isAccepted()) {
       
  1652                     QAbstractScrollArea::keyPressEvent(e);
       
  1653                 }
       
  1654         }
       
  1655         return;
       
  1656     }
       
  1657 #endif // QT_NO_SHORTCUT
       
  1658 
       
  1659     d->sendControlEvent(e);
       
  1660 #ifdef QT_KEYPAD_NAVIGATION
       
  1661     if (!e->isAccepted()) {
       
  1662         switch (e->key()) {
       
  1663             case Qt::Key_Up:
       
  1664             case Qt::Key_Down:
       
  1665                 if (QApplication::keypadNavigationEnabled()) {
       
  1666                     // Cursor position didn't change, so we want to leave
       
  1667                     // these keys to change focus.
       
  1668                     e->ignore();
       
  1669                     return;
       
  1670                 }
       
  1671                 break;
       
  1672             case Qt::Key_Left:
       
  1673             case Qt::Key_Right:
       
  1674                 if (QApplication::keypadNavigationEnabled()
       
  1675                         && QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) {
       
  1676                     // Same as for Key_Up and Key_Down.
       
  1677                     e->ignore();
       
  1678                     return;
       
  1679                 }
       
  1680                 break;
       
  1681             case Qt::Key_Back:
       
  1682                 if (!e->isAutoRepeat()) {
       
  1683                     if (QApplication::keypadNavigationEnabled()) {
       
  1684                         if (document()->isEmpty()) {
       
  1685                             setEditFocus(false);
       
  1686                             e->accept();
       
  1687                         } else if (!d->deleteAllTimer.isActive()) {
       
  1688                             e->accept();
       
  1689                             d->deleteAllTimer.start(750, this);
       
  1690                         }
       
  1691                     } else {
       
  1692                         e->ignore();
       
  1693                         return;
       
  1694                     }
       
  1695                 }
       
  1696                 break;
       
  1697             default: break;
       
  1698         }
       
  1699     }
       
  1700 #endif
       
  1701 }
       
  1702 
       
  1703 /*! \reimp
       
  1704 */
       
  1705 void QPlainTextEdit::keyReleaseEvent(QKeyEvent *e)
       
  1706 {
       
  1707 #ifdef QT_KEYPAD_NAVIGATION
       
  1708     Q_D(QPlainTextEdit);
       
  1709     if (QApplication::keypadNavigationEnabled()) {
       
  1710         if (!e->isAutoRepeat() && e->key() == Qt::Key_Back
       
  1711             && d->deleteAllTimer.isActive()) {
       
  1712             d->deleteAllTimer.stop();
       
  1713             QTextCursor cursor = d->control->textCursor();
       
  1714             QTextBlockFormat blockFmt = cursor.blockFormat();
       
  1715 
       
  1716             QTextList *list = cursor.currentList();
       
  1717             if (list && cursor.atBlockStart()) {
       
  1718                 list->remove(cursor.block());
       
  1719             } else if (cursor.atBlockStart() && blockFmt.indent() > 0) {
       
  1720                 blockFmt.setIndent(blockFmt.indent() - 1);
       
  1721                 cursor.setBlockFormat(blockFmt);
       
  1722             } else {
       
  1723                 cursor.deletePreviousChar();
       
  1724             }
       
  1725             setTextCursor(cursor);
       
  1726         }
       
  1727     }
       
  1728 #else
       
  1729     Q_UNUSED(e);
       
  1730 #endif
       
  1731 }
       
  1732 
       
  1733 /*!
       
  1734     Loads the resource specified by the given \a type and \a name.
       
  1735 
       
  1736     This function is an extension of QTextDocument::loadResource().
       
  1737 
       
  1738     \sa QTextDocument::loadResource()
       
  1739 */
       
  1740 QVariant QPlainTextEdit::loadResource(int type, const QUrl &name)
       
  1741 {
       
  1742     Q_UNUSED(type);
       
  1743     Q_UNUSED(name);
       
  1744     return QVariant();
       
  1745 }
       
  1746 
       
  1747 /*! \reimp
       
  1748 */
       
  1749 void QPlainTextEdit::resizeEvent(QResizeEvent *e)
       
  1750 {
       
  1751     Q_D(QPlainTextEdit);
       
  1752     if (e->oldSize().width() != e->size().width())
       
  1753         d->relayoutDocument();
       
  1754     d->_q_adjustScrollbars();
       
  1755 }
       
  1756 
       
  1757 void QPlainTextEditPrivate::relayoutDocument()
       
  1758 {
       
  1759     QTextDocument *doc = control->document();
       
  1760     QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout());
       
  1761     Q_ASSERT(documentLayout);
       
  1762     documentLayoutPtr = documentLayout;
       
  1763 
       
  1764     int width = viewport->width();
       
  1765 
       
  1766     if (documentLayout->priv()->mainViewPrivate == 0
       
  1767         || documentLayout->priv()->mainViewPrivate == this
       
  1768         || width > documentLayout->textWidth()) {
       
  1769         documentLayout->priv()->mainViewPrivate = this;
       
  1770         documentLayout->setTextWidth(width);
       
  1771     }
       
  1772 }
       
  1773 
       
  1774 static void fillBackground(QPainter *p, const QRectF &rect, QBrush brush, QRectF gradientRect = QRectF())
       
  1775 {
       
  1776     p->save();
       
  1777     if (brush.style() >= Qt::LinearGradientPattern && brush.style() <= Qt::ConicalGradientPattern) {
       
  1778         if (!gradientRect.isNull()) {
       
  1779             QTransform m = QTransform::fromTranslate(gradientRect.left(), gradientRect.top());
       
  1780             m.scale(gradientRect.width(), gradientRect.height());
       
  1781             brush.setTransform(m);
       
  1782             const_cast<QGradient *>(brush.gradient())->setCoordinateMode(QGradient::LogicalMode);
       
  1783         }
       
  1784     } else {
       
  1785         p->setBrushOrigin(rect.topLeft());
       
  1786     }
       
  1787     p->fillRect(rect, brush);
       
  1788     p->restore();
       
  1789 }
       
  1790 
       
  1791 
       
  1792 
       
  1793 /*! \reimp
       
  1794 */
       
  1795 void QPlainTextEdit::paintEvent(QPaintEvent *e)
       
  1796 {
       
  1797     QPainter painter(viewport());
       
  1798     Q_ASSERT(qobject_cast<QPlainTextDocumentLayout*>(document()->documentLayout()));
       
  1799 
       
  1800     QPointF offset(contentOffset());
       
  1801 
       
  1802     QRect er = e->rect();
       
  1803     QRect viewportRect = viewport()->rect();
       
  1804 
       
  1805     bool editable = !isReadOnly();
       
  1806 
       
  1807     QTextBlock block = firstVisibleBlock();
       
  1808     qreal maximumWidth = document()->documentLayout()->documentSize().width();
       
  1809 
       
  1810     // Set a brush origin so that the WaveUnderline knows where the wave started
       
  1811     painter.setBrushOrigin(offset);
       
  1812 
       
  1813     // keep right margin clean from full-width selection
       
  1814     int maxX = offset.x() + qMax((qreal)viewportRect.width(), maximumWidth)
       
  1815                - document()->documentMargin();
       
  1816     er.setRight(qMin(er.right(), maxX));
       
  1817     painter.setClipRect(er);
       
  1818 
       
  1819 
       
  1820     QAbstractTextDocumentLayout::PaintContext context = getPaintContext();
       
  1821 
       
  1822     while (block.isValid()) {
       
  1823 
       
  1824         QRectF r = blockBoundingRect(block).translated(offset);
       
  1825         QTextLayout *layout = block.layout();
       
  1826 
       
  1827         if (!block.isVisible()) {
       
  1828             offset.ry() += r.height();
       
  1829             block = block.next();
       
  1830             continue;
       
  1831         }
       
  1832 
       
  1833         if (r.bottom() >= er.top() && r.top() <= er.bottom()) {
       
  1834 
       
  1835             QTextBlockFormat blockFormat = block.blockFormat();
       
  1836 
       
  1837             QBrush bg = blockFormat.background();
       
  1838             if (bg != Qt::NoBrush) {
       
  1839                 QRectF contentsRect = r;
       
  1840                 contentsRect.setWidth(qMax(r.width(), maximumWidth));
       
  1841                 fillBackground(&painter, contentsRect, bg);
       
  1842             }
       
  1843 
       
  1844 
       
  1845             QVector<QTextLayout::FormatRange> selections;
       
  1846             int blpos = block.position();
       
  1847             int bllen = block.length();
       
  1848             for (int i = 0; i < context.selections.size(); ++i) {
       
  1849                 const QAbstractTextDocumentLayout::Selection &range = context.selections.at(i);
       
  1850                 const int selStart = range.cursor.selectionStart() - blpos;
       
  1851                 const int selEnd = range.cursor.selectionEnd() - blpos;
       
  1852                 if (selStart < bllen && selEnd > 0
       
  1853                     && selEnd > selStart) {
       
  1854                     QTextLayout::FormatRange o;
       
  1855                     o.start = selStart;
       
  1856                     o.length = selEnd - selStart;
       
  1857                     o.format = range.format;
       
  1858                     selections.append(o);
       
  1859                 } else if (!range.cursor.hasSelection() && range.format.hasProperty(QTextFormat::FullWidthSelection)
       
  1860                            && block.contains(range.cursor.position())) {
       
  1861                     // for full width selections we don't require an actual selection, just
       
  1862                     // a position to specify the line. that's more convenience in usage.
       
  1863                     QTextLayout::FormatRange o;
       
  1864                     QTextLine l = layout->lineForTextPosition(range.cursor.position() - blpos);
       
  1865                     o.start = l.textStart();
       
  1866                     o.length = l.textLength();
       
  1867                     if (o.start + o.length == bllen - 1)
       
  1868                         ++o.length; // include newline
       
  1869                     o.format = range.format;
       
  1870                     selections.append(o);
       
  1871                 }
       
  1872             }
       
  1873 
       
  1874             bool drawCursor = (editable
       
  1875                                && context.cursorPosition >= blpos
       
  1876                                && context.cursorPosition < blpos + bllen);
       
  1877 
       
  1878             bool drawCursorAsBlock = drawCursor && overwriteMode() ;
       
  1879 
       
  1880             if (drawCursorAsBlock) {
       
  1881                 if (context.cursorPosition == blpos + bllen - 1) {
       
  1882                     drawCursorAsBlock = false;
       
  1883                 } else {
       
  1884                     QTextLayout::FormatRange o;
       
  1885                     o.start = context.cursorPosition - blpos;
       
  1886                     o.length = 1;
       
  1887                     o.format.setForeground(palette().base());
       
  1888                     o.format.setBackground(palette().text());
       
  1889                     selections.append(o);
       
  1890                 }
       
  1891             }
       
  1892 
       
  1893 
       
  1894             layout->draw(&painter, offset, selections, er);
       
  1895             if ((drawCursor && !drawCursorAsBlock)
       
  1896                 || (editable && context.cursorPosition < -1
       
  1897                     && !layout->preeditAreaText().isEmpty())) {
       
  1898                 int cpos = context.cursorPosition;
       
  1899                 if (cpos < -1)
       
  1900                     cpos = layout->preeditAreaPosition() - (cpos + 2);
       
  1901                 else
       
  1902                     cpos -= blpos;
       
  1903                 layout->drawCursor(&painter, offset, cpos, cursorWidth());
       
  1904             }
       
  1905         }
       
  1906 
       
  1907         offset.ry() += r.height();
       
  1908         if (offset.y() > viewportRect.height())
       
  1909             break;
       
  1910         block = block.next();
       
  1911     }
       
  1912 
       
  1913     if (backgroundVisible() && !block.isValid() && offset.y() <= er.bottom()
       
  1914         && (centerOnScroll() || verticalScrollBar()->maximum() == verticalScrollBar()->minimum())) {
       
  1915         painter.fillRect(QRect(QPoint((int)er.left(), (int)offset.y()), er.bottomRight()), palette().background());
       
  1916     }
       
  1917 }
       
  1918 
       
  1919 
       
  1920 void QPlainTextEditPrivate::updateDefaultTextOption()
       
  1921 {
       
  1922     QTextDocument *doc = control->document();
       
  1923 
       
  1924     QTextOption opt = doc->defaultTextOption();
       
  1925     QTextOption::WrapMode oldWrapMode = opt.wrapMode();
       
  1926 
       
  1927     if (lineWrap == QPlainTextEdit::NoWrap)
       
  1928         opt.setWrapMode(QTextOption::NoWrap);
       
  1929     else
       
  1930         opt.setWrapMode(wordWrap);
       
  1931 
       
  1932     if (opt.wrapMode() != oldWrapMode)
       
  1933         doc->setDefaultTextOption(opt);
       
  1934 }
       
  1935 
       
  1936 
       
  1937 /*! \reimp
       
  1938 */
       
  1939 void QPlainTextEdit::mousePressEvent(QMouseEvent *e)
       
  1940 {
       
  1941     Q_D(QPlainTextEdit);
       
  1942 #ifdef QT_KEYPAD_NAVIGATION
       
  1943     if (QApplication::keypadNavigationEnabled() && !hasEditFocus())
       
  1944         setEditFocus(true);
       
  1945 #endif
       
  1946     d->sendControlEvent(e);
       
  1947 }
       
  1948 
       
  1949 /*! \reimp
       
  1950 */
       
  1951 void QPlainTextEdit::mouseMoveEvent(QMouseEvent *e)
       
  1952 {
       
  1953     Q_D(QPlainTextEdit);
       
  1954     d->inDrag = false; // paranoia
       
  1955     const QPoint pos = e->pos();
       
  1956     d->sendControlEvent(e);
       
  1957     if (!(e->buttons() & Qt::LeftButton))
       
  1958         return;
       
  1959     QRect visible = d->viewport->rect();
       
  1960     if (visible.contains(pos))
       
  1961         d->autoScrollTimer.stop();
       
  1962     else if (!d->autoScrollTimer.isActive())
       
  1963         d->autoScrollTimer.start(100, this);
       
  1964 }
       
  1965 
       
  1966 /*! \reimp
       
  1967 */
       
  1968 void QPlainTextEdit::mouseReleaseEvent(QMouseEvent *e)
       
  1969 {
       
  1970     Q_D(QPlainTextEdit);
       
  1971     d->sendControlEvent(e);
       
  1972     if (d->autoScrollTimer.isActive()) {
       
  1973         d->autoScrollTimer.stop();
       
  1974         d->ensureCursorVisible();
       
  1975     }
       
  1976 
       
  1977     if (!isReadOnly() && rect().contains(e->pos()))
       
  1978         d->handleSoftwareInputPanel(e->button(), d->clickCausedFocus);
       
  1979     d->clickCausedFocus = 0;
       
  1980 }
       
  1981 
       
  1982 /*! \reimp
       
  1983 */
       
  1984 void QPlainTextEdit::mouseDoubleClickEvent(QMouseEvent *e)
       
  1985 {
       
  1986     Q_D(QPlainTextEdit);
       
  1987     d->sendControlEvent(e);
       
  1988 }
       
  1989 
       
  1990 /*! \reimp
       
  1991 */
       
  1992 bool QPlainTextEdit::focusNextPrevChild(bool next)
       
  1993 {
       
  1994     Q_D(const QPlainTextEdit);
       
  1995     if (!d->tabChangesFocus && d->control->textInteractionFlags() & Qt::TextEditable)
       
  1996         return false;
       
  1997     return QAbstractScrollArea::focusNextPrevChild(next);
       
  1998 }
       
  1999 
       
  2000 #ifndef QT_NO_CONTEXTMENU
       
  2001 /*!
       
  2002   \fn void QPlainTextEdit::contextMenuEvent(QContextMenuEvent *event)
       
  2003 
       
  2004   Shows the standard context menu created with createStandardContextMenu().
       
  2005 
       
  2006   If you do not want the text edit to have a context menu, you can set
       
  2007   its \l contextMenuPolicy to Qt::NoContextMenu. If you want to
       
  2008   customize the context menu, reimplement this function. If you want
       
  2009   to extend the standard context menu, reimplement this function, call
       
  2010   createStandardContextMenu() and extend the menu returned.
       
  2011 
       
  2012   Information about the event is passed in the \a event object.
       
  2013 
       
  2014   \snippet doc/src/snippets/code/src_gui_widgets_qplaintextedit.cpp 0
       
  2015 */
       
  2016 void QPlainTextEdit::contextMenuEvent(QContextMenuEvent *e)
       
  2017 {
       
  2018     Q_D(QPlainTextEdit);
       
  2019     d->sendControlEvent(e);
       
  2020 }
       
  2021 #endif // QT_NO_CONTEXTMENU
       
  2022 
       
  2023 #ifndef QT_NO_DRAGANDDROP
       
  2024 /*! \reimp
       
  2025 */
       
  2026 void QPlainTextEdit::dragEnterEvent(QDragEnterEvent *e)
       
  2027 {
       
  2028     Q_D(QPlainTextEdit);
       
  2029     d->inDrag = true;
       
  2030     d->sendControlEvent(e);
       
  2031 }
       
  2032 
       
  2033 /*! \reimp
       
  2034 */
       
  2035 void QPlainTextEdit::dragLeaveEvent(QDragLeaveEvent *e)
       
  2036 {
       
  2037     Q_D(QPlainTextEdit);
       
  2038     d->inDrag = false;
       
  2039     d->autoScrollTimer.stop();
       
  2040     d->sendControlEvent(e);
       
  2041 }
       
  2042 
       
  2043 /*! \reimp
       
  2044 */
       
  2045 void QPlainTextEdit::dragMoveEvent(QDragMoveEvent *e)
       
  2046 {
       
  2047     Q_D(QPlainTextEdit);
       
  2048     d->autoScrollDragPos = e->pos();
       
  2049     if (!d->autoScrollTimer.isActive())
       
  2050         d->autoScrollTimer.start(100, this);
       
  2051     d->sendControlEvent(e);
       
  2052 }
       
  2053 
       
  2054 /*! \reimp
       
  2055 */
       
  2056 void QPlainTextEdit::dropEvent(QDropEvent *e)
       
  2057 {
       
  2058     Q_D(QPlainTextEdit);
       
  2059     d->inDrag = false;
       
  2060     d->autoScrollTimer.stop();
       
  2061     d->sendControlEvent(e);
       
  2062 }
       
  2063 
       
  2064 #endif // QT_NO_DRAGANDDROP
       
  2065 
       
  2066 /*! \reimp
       
  2067  */
       
  2068 void QPlainTextEdit::inputMethodEvent(QInputMethodEvent *e)
       
  2069 {
       
  2070     Q_D(QPlainTextEdit);
       
  2071 #ifdef QT_KEYPAD_NAVIGATION
       
  2072     if (d->control->textInteractionFlags() & Qt::TextEditable
       
  2073         && QApplication::keypadNavigationEnabled()
       
  2074         && !hasEditFocus()) {
       
  2075         setEditFocus(true);
       
  2076         selectAll();    // so text is replaced rather than appended to
       
  2077     }
       
  2078 #endif
       
  2079     d->sendControlEvent(e);
       
  2080     ensureCursorVisible();
       
  2081 }
       
  2082 
       
  2083 /*!\reimp
       
  2084 */
       
  2085 void QPlainTextEdit::scrollContentsBy(int dx, int /*dy*/)
       
  2086 {
       
  2087     Q_D(QPlainTextEdit);
       
  2088     d->setTopLine(d->vbar->value(), dx);
       
  2089 }
       
  2090 
       
  2091 /*!\reimp
       
  2092 */
       
  2093 QVariant QPlainTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
       
  2094 {
       
  2095     Q_D(const QPlainTextEdit);
       
  2096     QVariant v = d->control->inputMethodQuery(property);
       
  2097     const QPoint offset(-d->horizontalOffset(), -0);
       
  2098     if (v.type() == QVariant::RectF)
       
  2099         v = v.toRectF().toRect().translated(offset);
       
  2100     else if (v.type() == QVariant::PointF)
       
  2101         v = v.toPointF().toPoint() + offset;
       
  2102     else if (v.type() == QVariant::Rect)
       
  2103         v = v.toRect().translated(offset);
       
  2104     else if (v.type() == QVariant::Point)
       
  2105         v = v.toPoint() + offset;
       
  2106     return v;
       
  2107 }
       
  2108 
       
  2109 /*! \reimp
       
  2110 */
       
  2111 void QPlainTextEdit::focusInEvent(QFocusEvent *e)
       
  2112 {
       
  2113     Q_D(QPlainTextEdit);
       
  2114     if (e->reason() == Qt::MouseFocusReason) {
       
  2115         d->clickCausedFocus = 1;
       
  2116     }
       
  2117     QAbstractScrollArea::focusInEvent(e);
       
  2118     d->sendControlEvent(e);
       
  2119 }
       
  2120 
       
  2121 /*! \reimp
       
  2122 */
       
  2123 void QPlainTextEdit::focusOutEvent(QFocusEvent *e)
       
  2124 {
       
  2125     Q_D(QPlainTextEdit);
       
  2126     QAbstractScrollArea::focusOutEvent(e);
       
  2127     d->sendControlEvent(e);
       
  2128 }
       
  2129 
       
  2130 /*! \reimp
       
  2131 */
       
  2132 void QPlainTextEdit::showEvent(QShowEvent *)
       
  2133 {
       
  2134     Q_D(QPlainTextEdit);
       
  2135     if (d->showCursorOnInitialShow) {
       
  2136         d->showCursorOnInitialShow = false;
       
  2137         ensureCursorVisible();
       
  2138     }
       
  2139 }
       
  2140 
       
  2141 /*! \reimp
       
  2142 */
       
  2143 void QPlainTextEdit::changeEvent(QEvent *e)
       
  2144 {
       
  2145     Q_D(QPlainTextEdit);
       
  2146     QAbstractScrollArea::changeEvent(e);
       
  2147     if (e->type() == QEvent::ApplicationFontChange
       
  2148         || e->type() == QEvent::FontChange) {
       
  2149         d->control->document()->setDefaultFont(font());
       
  2150     }  else if(e->type() == QEvent::ActivationChange) {
       
  2151         if (!isActiveWindow())
       
  2152             d->autoScrollTimer.stop();
       
  2153     } else if (e->type() == QEvent::EnabledChange) {
       
  2154         e->setAccepted(isEnabled());
       
  2155         d->sendControlEvent(e);
       
  2156     } else if (e->type() == QEvent::PaletteChange) {
       
  2157         d->control->setPalette(palette());
       
  2158     } else if (e->type() == QEvent::LayoutDirectionChange) {
       
  2159         d->sendControlEvent(e);
       
  2160     }
       
  2161 }
       
  2162 
       
  2163 /*! \reimp
       
  2164 */
       
  2165 #ifndef QT_NO_WHEELEVENT
       
  2166 void QPlainTextEdit::wheelEvent(QWheelEvent *e)
       
  2167 {
       
  2168     QAbstractScrollArea::wheelEvent(e);
       
  2169     updateMicroFocus();
       
  2170 }
       
  2171 #endif
       
  2172 
       
  2173 #ifndef QT_NO_CONTEXTMENU
       
  2174 /*!  This function creates the standard context menu which is shown
       
  2175   when the user clicks on the line edit with the right mouse
       
  2176   button. It is called from the default contextMenuEvent() handler.
       
  2177   The popup menu's ownership is transferred to the caller.
       
  2178 */
       
  2179 
       
  2180 QMenu *QPlainTextEdit::createStandardContextMenu()
       
  2181 {
       
  2182     Q_D(QPlainTextEdit);
       
  2183     return d->control->createStandardContextMenu(QPointF(), this);
       
  2184 }
       
  2185 #endif // QT_NO_CONTEXTMENU
       
  2186 
       
  2187 /*!
       
  2188   returns a QTextCursor at position \a pos (in viewport coordinates).
       
  2189 */
       
  2190 QTextCursor QPlainTextEdit::cursorForPosition(const QPoint &pos) const
       
  2191 {
       
  2192     Q_D(const QPlainTextEdit);
       
  2193     return d->control->cursorForPosition(d->mapToContents(pos));
       
  2194 }
       
  2195 
       
  2196 /*!
       
  2197   returns a rectangle (in viewport coordinates) that includes the
       
  2198   \a cursor.
       
  2199  */
       
  2200 QRect QPlainTextEdit::cursorRect(const QTextCursor &cursor) const
       
  2201 {
       
  2202     Q_D(const QPlainTextEdit);
       
  2203     if (cursor.isNull())
       
  2204         return QRect();
       
  2205 
       
  2206     QRect r = d->control->cursorRect(cursor).toRect();
       
  2207     r.translate(-d->horizontalOffset(),-d->verticalOffset());
       
  2208     return r;
       
  2209 }
       
  2210 
       
  2211 /*!
       
  2212   returns a rectangle (in viewport coordinates) that includes the
       
  2213   cursor of the text edit.
       
  2214  */
       
  2215 QRect QPlainTextEdit::cursorRect() const
       
  2216 {
       
  2217     Q_D(const QPlainTextEdit);
       
  2218     QRect r = d->control->cursorRect().toRect();
       
  2219     r.translate(-d->horizontalOffset(),-d->verticalOffset());
       
  2220     return r;
       
  2221 }
       
  2222 
       
  2223 
       
  2224 /*!
       
  2225    \property QPlainTextEdit::overwriteMode
       
  2226    \brief whether text entered by the user will overwrite existing text
       
  2227 
       
  2228    As with many text editors, the plain text editor widget can be configured
       
  2229    to insert or overwrite existing text with new text entered by the user.
       
  2230 
       
  2231    If this property is true, existing text is overwritten, character-for-character
       
  2232    by new text; otherwise, text is inserted at the cursor position, displacing
       
  2233    existing text.
       
  2234 
       
  2235    By default, this property is false (new text does not overwrite existing text).
       
  2236 */
       
  2237 
       
  2238 bool QPlainTextEdit::overwriteMode() const
       
  2239 {
       
  2240     Q_D(const QPlainTextEdit);
       
  2241     return d->control->overwriteMode();
       
  2242 }
       
  2243 
       
  2244 void QPlainTextEdit::setOverwriteMode(bool overwrite)
       
  2245 {
       
  2246     Q_D(QPlainTextEdit);
       
  2247     d->control->setOverwriteMode(overwrite);
       
  2248 }
       
  2249 
       
  2250 /*!
       
  2251     \property QPlainTextEdit::tabStopWidth
       
  2252     \brief the tab stop width in pixels
       
  2253 
       
  2254     By default, this property contains a value of 80.
       
  2255 */
       
  2256 
       
  2257 int QPlainTextEdit::tabStopWidth() const
       
  2258 {
       
  2259     Q_D(const QPlainTextEdit);
       
  2260     return qRound(d->control->document()->defaultTextOption().tabStop());
       
  2261 }
       
  2262 
       
  2263 void QPlainTextEdit::setTabStopWidth(int width)
       
  2264 {
       
  2265     Q_D(QPlainTextEdit);
       
  2266     QTextOption opt = d->control->document()->defaultTextOption();
       
  2267     if (opt.tabStop() == width || width < 0)
       
  2268         return;
       
  2269     opt.setTabStop(width);
       
  2270     d->control->document()->setDefaultTextOption(opt);
       
  2271 }
       
  2272 
       
  2273 /*!
       
  2274     \property QPlainTextEdit::cursorWidth
       
  2275 
       
  2276     This property specifies the width of the cursor in pixels. The default value is 1.
       
  2277 */
       
  2278 int QPlainTextEdit::cursorWidth() const
       
  2279 {
       
  2280     Q_D(const QPlainTextEdit);
       
  2281     return d->control->cursorWidth();
       
  2282 }
       
  2283 
       
  2284 void QPlainTextEdit::setCursorWidth(int width)
       
  2285 {
       
  2286     Q_D(QPlainTextEdit);
       
  2287     d->control->setCursorWidth(width);
       
  2288 }
       
  2289 
       
  2290 
       
  2291 
       
  2292 /*!
       
  2293     This function allows temporarily marking certain regions in the document
       
  2294     with a given color, specified as \a selections. This can be useful for
       
  2295     example in a programming editor to mark a whole line of text with a given
       
  2296     background color to indicate the existence of a breakpoint.
       
  2297 
       
  2298     \sa QTextEdit::ExtraSelection, extraSelections()
       
  2299 */
       
  2300 void QPlainTextEdit::setExtraSelections(const QList<QTextEdit::ExtraSelection> &selections)
       
  2301 {
       
  2302     Q_D(QPlainTextEdit);
       
  2303     d->control->setExtraSelections(selections);
       
  2304 }
       
  2305 
       
  2306 /*!
       
  2307     Returns previously set extra selections.
       
  2308 
       
  2309     \sa setExtraSelections()
       
  2310 */
       
  2311 QList<QTextEdit::ExtraSelection> QPlainTextEdit::extraSelections() const
       
  2312 {
       
  2313     Q_D(const QPlainTextEdit);
       
  2314     return d->control->extraSelections();
       
  2315 }
       
  2316 
       
  2317 /*!
       
  2318     This function returns a new MIME data object to represent the contents
       
  2319     of the text edit's current selection. It is called when the selection needs
       
  2320     to be encapsulated into a new QMimeData object; for example, when a drag
       
  2321     and drop operation is started, or when data is copied to the clipboard.
       
  2322 
       
  2323     If you reimplement this function, note that the ownership of the returned
       
  2324     QMimeData object is passed to the caller. The selection can be retrieved
       
  2325     by using the textCursor() function.
       
  2326 */
       
  2327 QMimeData *QPlainTextEdit::createMimeDataFromSelection() const
       
  2328 {
       
  2329     Q_D(const QPlainTextEdit);
       
  2330     return d->control->QTextControl::createMimeDataFromSelection();
       
  2331 }
       
  2332 
       
  2333 /*!
       
  2334     This function returns true if the contents of the MIME data object, specified
       
  2335     by \a source, can be decoded and inserted into the document. It is called
       
  2336     for example when during a drag operation the mouse enters this widget and it
       
  2337     is necessary to determine whether it is possible to accept the drag.
       
  2338  */
       
  2339 bool QPlainTextEdit::canInsertFromMimeData(const QMimeData *source) const
       
  2340 {
       
  2341     Q_D(const QPlainTextEdit);
       
  2342     return d->control->QTextControl::canInsertFromMimeData(source);
       
  2343 }
       
  2344 
       
  2345 /*!
       
  2346     This function inserts the contents of the MIME data object, specified
       
  2347     by \a source, into the text edit at the current cursor position. It is
       
  2348     called whenever text is inserted as the result of a clipboard paste
       
  2349     operation, or when the text edit accepts data from a drag and drop
       
  2350     operation.
       
  2351 */
       
  2352 void QPlainTextEdit::insertFromMimeData(const QMimeData *source)
       
  2353 {
       
  2354     Q_D(QPlainTextEdit);
       
  2355     d->control->QTextControl::insertFromMimeData(source);
       
  2356 }
       
  2357 
       
  2358 /*!
       
  2359     \property QPlainTextEdit::readOnly
       
  2360     \brief whether the text edit is read-only
       
  2361 
       
  2362     In a read-only text edit the user can only navigate through the
       
  2363     text and select text; modifying the text is not possible.
       
  2364 
       
  2365     This property's default is false.
       
  2366 */
       
  2367 
       
  2368 bool QPlainTextEdit::isReadOnly() const
       
  2369 {
       
  2370     Q_D(const QPlainTextEdit);
       
  2371     return !(d->control->textInteractionFlags() & Qt::TextEditable);
       
  2372 }
       
  2373 
       
  2374 void QPlainTextEdit::setReadOnly(bool ro)
       
  2375 {
       
  2376     Q_D(QPlainTextEdit);
       
  2377     Qt::TextInteractionFlags flags = Qt::NoTextInteraction;
       
  2378     if (ro) {
       
  2379         flags = Qt::TextSelectableByMouse;
       
  2380     } else {
       
  2381         flags = Qt::TextEditorInteraction;
       
  2382     }
       
  2383     setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this));
       
  2384     d->control->setTextInteractionFlags(flags);
       
  2385 }
       
  2386 
       
  2387 /*!
       
  2388     \property QPlainTextEdit::textInteractionFlags
       
  2389 
       
  2390     Specifies how the label should interact with user input if it displays text.
       
  2391 
       
  2392     If the flags contain either Qt::LinksAccessibleByKeyboard or Qt::TextSelectableByKeyboard
       
  2393     then the focus policy is also automatically set to Qt::ClickFocus.
       
  2394 
       
  2395     The default value depends on whether the QPlainTextEdit is read-only
       
  2396     or editable, and whether it is a QTextBrowser or not.
       
  2397 */
       
  2398 
       
  2399 void QPlainTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
       
  2400 {
       
  2401     Q_D(QPlainTextEdit);
       
  2402     d->control->setTextInteractionFlags(flags);
       
  2403 }
       
  2404 
       
  2405 Qt::TextInteractionFlags QPlainTextEdit::textInteractionFlags() const
       
  2406 {
       
  2407     Q_D(const QPlainTextEdit);
       
  2408     return d->control->textInteractionFlags();
       
  2409 }
       
  2410 
       
  2411 /*!
       
  2412     Merges the properties specified in \a modifier into the current character
       
  2413     format by calling QTextCursor::mergeCharFormat on the editor's cursor.
       
  2414     If the editor has a selection then the properties of \a modifier are
       
  2415     directly applied to the selection.
       
  2416 
       
  2417     \sa QTextCursor::mergeCharFormat()
       
  2418  */
       
  2419 void QPlainTextEdit::mergeCurrentCharFormat(const QTextCharFormat &modifier)
       
  2420 {
       
  2421     Q_D(QPlainTextEdit);
       
  2422     d->control->mergeCurrentCharFormat(modifier);
       
  2423 }
       
  2424 
       
  2425 /*!
       
  2426     Sets the char format that is be used when inserting new text to \a
       
  2427     format by calling QTextCursor::setCharFormat() on the editor's
       
  2428     cursor.  If the editor has a selection then the char format is
       
  2429     directly applied to the selection.
       
  2430  */
       
  2431 void QPlainTextEdit::setCurrentCharFormat(const QTextCharFormat &format)
       
  2432 {
       
  2433     Q_D(QPlainTextEdit);
       
  2434     d->control->setCurrentCharFormat(format);
       
  2435 }
       
  2436 
       
  2437 /*!
       
  2438     Returns the char format that is used when inserting new text.
       
  2439  */
       
  2440 QTextCharFormat QPlainTextEdit::currentCharFormat() const
       
  2441 {
       
  2442     Q_D(const QPlainTextEdit);
       
  2443     return d->control->currentCharFormat();
       
  2444 }
       
  2445 
       
  2446 
       
  2447 
       
  2448 /*!
       
  2449     Convenience slot that inserts \a text at the current
       
  2450     cursor position.
       
  2451 
       
  2452     It is equivalent to
       
  2453 
       
  2454     \snippet doc/src/snippets/code/src_gui_widgets_qplaintextedit.cpp 1
       
  2455  */
       
  2456 void QPlainTextEdit::insertPlainText(const QString &text)
       
  2457 {
       
  2458     Q_D(QPlainTextEdit);
       
  2459     d->control->insertPlainText(text);
       
  2460 }
       
  2461 
       
  2462 
       
  2463 /*!
       
  2464     Moves the cursor by performing the given \a operation.
       
  2465 
       
  2466     If \a mode is QTextCursor::KeepAnchor, the cursor selects the text it moves over.
       
  2467     This is the same effect that the user achieves when they hold down the Shift key
       
  2468     and move the cursor with the cursor keys.
       
  2469 
       
  2470     \sa QTextCursor::movePosition()
       
  2471 */
       
  2472 void QPlainTextEdit::moveCursor(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode)
       
  2473 {
       
  2474     Q_D(QPlainTextEdit);
       
  2475     d->control->moveCursor(operation, mode);
       
  2476 }
       
  2477 
       
  2478 /*!
       
  2479     Returns whether text can be pasted from the clipboard into the textedit.
       
  2480 */
       
  2481 bool QPlainTextEdit::canPaste() const
       
  2482 {
       
  2483     Q_D(const QPlainTextEdit);
       
  2484     return d->control->canPaste();
       
  2485 }
       
  2486 
       
  2487 #ifndef QT_NO_PRINTER
       
  2488 /*!
       
  2489     Convenience function to print the text edit's document to the given \a printer. This
       
  2490     is equivalent to calling the print method on the document directly except that this
       
  2491     function also supports QPrinter::Selection as print range.
       
  2492 
       
  2493     \sa QTextDocument::print()
       
  2494 */
       
  2495 void QPlainTextEdit::print(QPrinter *printer) const
       
  2496 {
       
  2497     Q_D(const QPlainTextEdit);
       
  2498     d->control->print(printer);
       
  2499 }
       
  2500 #endif // QT _NO_PRINTER
       
  2501 
       
  2502 /*! \property QPlainTextEdit::tabChangesFocus
       
  2503   \brief whether \gui Tab changes focus or is accepted as input
       
  2504 
       
  2505   In some occasions text edits should not allow the user to input
       
  2506   tabulators or change indentation using the \gui Tab key, as this breaks
       
  2507   the focus chain. The default is false.
       
  2508 
       
  2509 */
       
  2510 
       
  2511 bool QPlainTextEdit::tabChangesFocus() const
       
  2512 {
       
  2513     Q_D(const QPlainTextEdit);
       
  2514     return d->tabChangesFocus;
       
  2515 }
       
  2516 
       
  2517 void QPlainTextEdit::setTabChangesFocus(bool b)
       
  2518 {
       
  2519     Q_D(QPlainTextEdit);
       
  2520     d->tabChangesFocus = b;
       
  2521 }
       
  2522 
       
  2523 /*!
       
  2524     \property QPlainTextEdit::documentTitle
       
  2525     \brief the title of the document parsed from the text.
       
  2526 
       
  2527     By default, this property contains an empty string.
       
  2528 */
       
  2529 
       
  2530 /*!
       
  2531     \property QPlainTextEdit::lineWrapMode
       
  2532     \brief the line wrap mode
       
  2533 
       
  2534     The default mode is WidgetWidth which causes words to be
       
  2535     wrapped at the right edge of the text edit. Wrapping occurs at
       
  2536     whitespace, keeping whole words intact. If you want wrapping to
       
  2537     occur within words use setWordWrapMode().
       
  2538 */
       
  2539 
       
  2540 QPlainTextEdit::LineWrapMode QPlainTextEdit::lineWrapMode() const
       
  2541 {
       
  2542     Q_D(const QPlainTextEdit);
       
  2543     return d->lineWrap;
       
  2544 }
       
  2545 
       
  2546 void QPlainTextEdit::setLineWrapMode(LineWrapMode wrap)
       
  2547 {
       
  2548     Q_D(QPlainTextEdit);
       
  2549     if (d->lineWrap == wrap)
       
  2550         return;
       
  2551     d->lineWrap = wrap;
       
  2552     d->updateDefaultTextOption();
       
  2553     d->relayoutDocument();
       
  2554     d->_q_adjustScrollbars();
       
  2555     ensureCursorVisible();
       
  2556 }
       
  2557 
       
  2558 /*!
       
  2559     \property QPlainTextEdit::wordWrapMode
       
  2560     \brief the mode QPlainTextEdit will use when wrapping text by words
       
  2561 
       
  2562     By default, this property is set to QTextOption::WrapAtWordBoundaryOrAnywhere.
       
  2563 
       
  2564     \sa QTextOption::WrapMode
       
  2565 */
       
  2566 
       
  2567 QTextOption::WrapMode QPlainTextEdit::wordWrapMode() const
       
  2568 {
       
  2569     Q_D(const QPlainTextEdit);
       
  2570     return d->wordWrap;
       
  2571 }
       
  2572 
       
  2573 void QPlainTextEdit::setWordWrapMode(QTextOption::WrapMode mode)
       
  2574 {
       
  2575     Q_D(QPlainTextEdit);
       
  2576     if (mode == d->wordWrap)
       
  2577         return;
       
  2578     d->wordWrap = mode;
       
  2579     d->updateDefaultTextOption();
       
  2580 }
       
  2581 
       
  2582 /*!
       
  2583     \property QPlainTextEdit::backgroundVisible
       
  2584     \brief whether the palette background is visible outside the document area
       
  2585 
       
  2586     If set to true, the plain text edit paints the palette background
       
  2587     on the viewport area not covered by the text document. Otherwise,
       
  2588     if set to false, it won't. The feature makes it possible for
       
  2589     the user to visually distinguish between the area of the document,
       
  2590     painted with the base color of the palette, and the empty
       
  2591     area not covered by any document.
       
  2592 
       
  2593     The default is false.
       
  2594 */
       
  2595 
       
  2596 bool QPlainTextEdit::backgroundVisible() const
       
  2597 {
       
  2598     Q_D(const QPlainTextEdit);
       
  2599     return d->backgroundVisible;
       
  2600 }
       
  2601 
       
  2602 void QPlainTextEdit::setBackgroundVisible(bool visible)
       
  2603 {
       
  2604     Q_D(QPlainTextEdit);
       
  2605     if (visible == d->backgroundVisible)
       
  2606         return;
       
  2607     d->backgroundVisible = visible;
       
  2608     d->updateViewport();
       
  2609 }
       
  2610 
       
  2611 /*!
       
  2612     \property QPlainTextEdit::centerOnScroll
       
  2613     \brief whether the cursor should be centered on screen
       
  2614 
       
  2615     If set to true, the plain text edit scrolls the document
       
  2616     vertically to make the cursor visible at the center of the
       
  2617     viewport. This also allows the text edit to scroll below the end
       
  2618     of the document. Otherwise, if set to false, the plain text edit
       
  2619     scrolls the smallest amount possible to ensure the cursor is
       
  2620     visible.  The same algorithm is applied to any new line appended
       
  2621     through appendPlainText().
       
  2622 
       
  2623     The default is false.
       
  2624 
       
  2625     \sa centerCursor(), ensureCursorVisible()
       
  2626 */
       
  2627 
       
  2628 bool QPlainTextEdit::centerOnScroll() const
       
  2629 {
       
  2630     Q_D(const QPlainTextEdit);
       
  2631     return d->centerOnScroll;
       
  2632 }
       
  2633 
       
  2634 void QPlainTextEdit::setCenterOnScroll(bool enabled)
       
  2635 {
       
  2636     Q_D(QPlainTextEdit);
       
  2637     if (enabled == d->centerOnScroll)
       
  2638         return;
       
  2639     d->centerOnScroll = enabled;
       
  2640 }
       
  2641 
       
  2642 
       
  2643 
       
  2644 /*!
       
  2645     Finds the next occurrence of the string, \a exp, using the given
       
  2646     \a options. Returns true if \a exp was found and changes the
       
  2647     cursor to select the match; otherwise returns false.
       
  2648 */
       
  2649 bool QPlainTextEdit::find(const QString &exp, QTextDocument::FindFlags options)
       
  2650 {
       
  2651     Q_D(QPlainTextEdit);
       
  2652     return d->control->find(exp, options);
       
  2653 }
       
  2654 
       
  2655 /*!
       
  2656     \fn void QPlainTextEdit::copyAvailable(bool yes)
       
  2657 
       
  2658     This signal is emitted when text is selected or de-selected in the
       
  2659     text edit.
       
  2660 
       
  2661     When text is selected this signal will be emitted with \a yes set
       
  2662     to true. If no text has been selected or if the selected text is
       
  2663     de-selected this signal is emitted with \a yes set to false.
       
  2664 
       
  2665     If \a yes is true then copy() can be used to copy the selection to
       
  2666     the clipboard. If \a yes is false then copy() does nothing.
       
  2667 
       
  2668     \sa selectionChanged()
       
  2669 */
       
  2670 
       
  2671 
       
  2672 /*!
       
  2673     \fn void QPlainTextEdit::selectionChanged()
       
  2674 
       
  2675     This signal is emitted whenever the selection changes.
       
  2676 
       
  2677     \sa copyAvailable()
       
  2678 */
       
  2679 
       
  2680 /*!
       
  2681     \fn void QPlainTextEdit::cursorPositionChanged()
       
  2682 
       
  2683     This signal is emitted whenever the position of the
       
  2684     cursor changed.
       
  2685 */
       
  2686 
       
  2687 
       
  2688 
       
  2689 /*!
       
  2690     \fn void QPlainTextEdit::updateRequest(const QRect &rect, int dy)
       
  2691 
       
  2692     This signal is emitted when the text document needs an update of
       
  2693     the specified \a rect. If the text is scrolled, \a rect will cover
       
  2694     the entire viewport area. If the text is scrolled vertically, \a
       
  2695     dy carries the amount of pixels the viewport was scrolled.
       
  2696 
       
  2697     The purpose of the signal is to support extra widgets in plain
       
  2698     text edit subclasses that e.g. show line numbers, breakpoints, or
       
  2699     other extra information.
       
  2700 */
       
  2701 
       
  2702 /*!  \fn void QPlainTextEdit::blockCountChanged(int newBlockCount);
       
  2703 
       
  2704     This signal is emitted whenever the block count changes. The new
       
  2705     block count is passed in \a newBlockCount.
       
  2706 */
       
  2707 
       
  2708 /*!  \fn void QPlainTextEdit::modificationChanged(bool changed);
       
  2709 
       
  2710     This signal is emitted whenever the content of the document
       
  2711     changes in a way that affects the modification state. If \a
       
  2712     changed is true, the document has been modified; otherwise it is
       
  2713     false.
       
  2714 
       
  2715     For example, calling setModified(false) on a document and then
       
  2716     inserting text causes the signal to get emitted. If you undo that
       
  2717     operation, causing the document to return to its original
       
  2718     unmodified state, the signal will get emitted again.
       
  2719 */
       
  2720 
       
  2721 
       
  2722 
       
  2723 
       
  2724 void QPlainTextEditPrivate::append(const QString &text, Qt::TextFormat format)
       
  2725 {
       
  2726     Q_Q(QPlainTextEdit);
       
  2727 
       
  2728     QTextDocument *document = control->document();
       
  2729     QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document->documentLayout());
       
  2730     Q_ASSERT(documentLayout);
       
  2731 
       
  2732     int maximumBlockCount = document->maximumBlockCount();
       
  2733     if (maximumBlockCount)
       
  2734         document->setMaximumBlockCount(0);
       
  2735 
       
  2736     const bool atBottom =  q->isVisible()
       
  2737                            && (control->blockBoundingRect(document->lastBlock()).bottom() - verticalOffset()
       
  2738                                <= viewport->rect().bottom());
       
  2739 
       
  2740     if (!q->isVisible())
       
  2741         showCursorOnInitialShow = true;
       
  2742 
       
  2743     bool documentSizeChangedBlocked = documentLayout->priv()->blockDocumentSizeChanged;
       
  2744     documentLayout->priv()->blockDocumentSizeChanged = true;
       
  2745 
       
  2746     if (format == Qt::RichText)
       
  2747         control->appendHtml(text);
       
  2748     else if (format == Qt::PlainText)
       
  2749         control->appendPlainText(text);
       
  2750     else
       
  2751         control->append(text);
       
  2752 
       
  2753     if (maximumBlockCount > 0) {
       
  2754         if (document->blockCount() > maximumBlockCount) {
       
  2755             bool blockUpdate = false;
       
  2756             if (control->topBlock) {
       
  2757                 control->topBlock--;
       
  2758                 blockUpdate = true;
       
  2759                 emit q->updateRequest(viewport->rect(), 0);
       
  2760             }
       
  2761 
       
  2762             bool updatesBlocked = documentLayout->priv()->blockUpdate;
       
  2763             documentLayout->priv()->blockUpdate = blockUpdate;
       
  2764             QTextCursor cursor(document);
       
  2765             cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor);
       
  2766             cursor.removeSelectedText();
       
  2767             documentLayout->priv()->blockUpdate = updatesBlocked;
       
  2768         }
       
  2769         document->setMaximumBlockCount(maximumBlockCount);
       
  2770     }
       
  2771 
       
  2772     documentLayout->priv()->blockDocumentSizeChanged = documentSizeChangedBlocked;
       
  2773     _q_adjustScrollbars();
       
  2774 
       
  2775 
       
  2776     if (atBottom) {
       
  2777         const bool needScroll =  !centerOnScroll
       
  2778                                  || control->blockBoundingRect(document->lastBlock()).bottom() - verticalOffset()
       
  2779                                  > viewport->rect().bottom();
       
  2780         if (needScroll)
       
  2781             vbar->setValue(vbar->maximum());
       
  2782     }
       
  2783 }
       
  2784 
       
  2785 
       
  2786 /*!
       
  2787     Appends a new paragraph with \a text to the end of the text edit.
       
  2788 
       
  2789     \sa appendHtml()
       
  2790 */
       
  2791 
       
  2792 void QPlainTextEdit::appendPlainText(const QString &text)
       
  2793 {
       
  2794     Q_D(QPlainTextEdit);
       
  2795     d->append(text, Qt::PlainText);
       
  2796 }
       
  2797 
       
  2798 /*!
       
  2799     Appends a new paragraph with \a html to the end of the text edit.
       
  2800 
       
  2801     appendPlainText()
       
  2802 */
       
  2803 
       
  2804 void QPlainTextEdit::appendHtml(const QString &html)
       
  2805 {
       
  2806     Q_D(QPlainTextEdit);
       
  2807     d->append(html, Qt::RichText);
       
  2808 }
       
  2809 
       
  2810 void QPlainTextEditPrivate::ensureCursorVisible(bool center)
       
  2811 {
       
  2812     Q_Q(QPlainTextEdit);
       
  2813     QRect visible = viewport->rect();
       
  2814     QRect cr = q->cursorRect();
       
  2815     if (cr.top() < visible.top() || cr.bottom() > visible.bottom()) {
       
  2816         ensureVisible(control->textCursor().position(), center);
       
  2817     }
       
  2818 
       
  2819     const bool rtl = q->isRightToLeft();
       
  2820     if (cr.left() < visible.left() || cr.right() > visible.right()) {
       
  2821         int x = cr.center().x() + horizontalOffset() - visible.width()/2;
       
  2822         hbar->setValue(rtl ? hbar->maximum() - x : x);
       
  2823     }
       
  2824 }
       
  2825 
       
  2826 /*!
       
  2827     Ensures that the cursor is visible by scrolling the text edit if
       
  2828     necessary.
       
  2829 
       
  2830     \sa centerCursor(), centerOnScroll
       
  2831 */
       
  2832 void QPlainTextEdit::ensureCursorVisible()
       
  2833 {
       
  2834     Q_D(QPlainTextEdit);
       
  2835     d->ensureCursorVisible(d->centerOnScroll);
       
  2836 }
       
  2837 
       
  2838 
       
  2839 /*!  Scrolls the document in order to center the cursor vertically.
       
  2840 
       
  2841 \sa ensureCursorVisible(), centerOnScroll
       
  2842  */
       
  2843 void QPlainTextEdit::centerCursor()
       
  2844 {
       
  2845     Q_D(QPlainTextEdit);
       
  2846     d->ensureVisible(textCursor().position(), true, true);
       
  2847 }
       
  2848 
       
  2849 /*!
       
  2850   Returns the first visible block.
       
  2851 
       
  2852   \sa blockBoundingRect()
       
  2853  */
       
  2854 QTextBlock QPlainTextEdit::firstVisibleBlock() const
       
  2855 {
       
  2856     Q_D(const QPlainTextEdit);
       
  2857     return d->control->firstVisibleBlock();
       
  2858 }
       
  2859 
       
  2860 /*!  Returns the content's origin in viewport coordinates.
       
  2861 
       
  2862      The origin of the content of a plain text edit is always the top
       
  2863      left corner of the first visible text block. The content offset
       
  2864      is different from (0,0) when the text has been scrolled
       
  2865      horizontally, or when the first visible block has been scrolled
       
  2866      partially off the screen, i.e. the visible text does not start
       
  2867      with the first line of the first visible block, or when the first
       
  2868      visible block is the very first block and the editor displays a
       
  2869      margin.
       
  2870 
       
  2871      \sa firstVisibleBlock(), horizontalScrollBar(), verticalScrollBar()
       
  2872  */
       
  2873 QPointF QPlainTextEdit::contentOffset() const
       
  2874 {
       
  2875     Q_D(const QPlainTextEdit);
       
  2876     return QPointF(-d->horizontalOffset(), -d->verticalOffset());
       
  2877 }
       
  2878 
       
  2879 
       
  2880 /*!  Returns the bounding rectangle of the text \a block in content
       
  2881   coordinates. Translate the rectangle with the contentOffset() to get
       
  2882   visual coordinates on the viewport.
       
  2883 
       
  2884   \sa firstVisibleBlock(), blockBoundingRect()
       
  2885  */
       
  2886 QRectF QPlainTextEdit::blockBoundingGeometry(const QTextBlock &block) const
       
  2887 {
       
  2888     Q_D(const QPlainTextEdit);
       
  2889     return d->control->blockBoundingRect(block);
       
  2890 }
       
  2891 
       
  2892 /*!
       
  2893   Returns the bounding rectangle of the text \a block in the block's own coordinates.
       
  2894 
       
  2895   \sa blockBoundingGeometry()
       
  2896  */
       
  2897 QRectF QPlainTextEdit::blockBoundingRect(const QTextBlock &block) const
       
  2898 {
       
  2899     QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document()->documentLayout());
       
  2900     Q_ASSERT(documentLayout);
       
  2901     return documentLayout->blockBoundingRect(block);
       
  2902 }
       
  2903 
       
  2904 /*!
       
  2905     \property QPlainTextEdit::blockCount
       
  2906     \brief the number of text blocks in the document.
       
  2907 
       
  2908     By default, in an empty document, this property contains a value of 1.
       
  2909 */
       
  2910 int QPlainTextEdit::blockCount() const
       
  2911 {
       
  2912     return document()->blockCount();
       
  2913 }
       
  2914 
       
  2915 /*!  Returns the paint context for the viewport(), useful only when
       
  2916   reimplementing paintEvent().
       
  2917  */
       
  2918 QAbstractTextDocumentLayout::PaintContext QPlainTextEdit::getPaintContext() const
       
  2919 {
       
  2920     Q_D(const QPlainTextEdit);
       
  2921     return d->control->getPaintContext(d->viewport);
       
  2922 }
       
  2923 
       
  2924 /*!
       
  2925     \property QPlainTextEdit::maximumBlockCount
       
  2926     \brief the limit for blocks in the document.
       
  2927 
       
  2928     Specifies the maximum number of blocks the document may have. If there are
       
  2929     more blocks in the document that specified with this property blocks are removed
       
  2930     from the beginning of the document.
       
  2931 
       
  2932     A negative or zero value specifies that the document may contain an unlimited
       
  2933     amount of blocks.
       
  2934 
       
  2935     The default value is 0.
       
  2936 
       
  2937     Note that setting this property will apply the limit immediately to the document
       
  2938     contents. Setting this property also disables the undo redo history.
       
  2939 
       
  2940 */
       
  2941 
       
  2942 
       
  2943 /*!
       
  2944     \fn void QPlainTextEdit::textChanged()
       
  2945 
       
  2946     This signal is emitted whenever the document's content changes; for
       
  2947     example, when text is inserted or deleted, or when formatting is applied.
       
  2948 */
       
  2949 
       
  2950 /*!
       
  2951     \fn void QPlainTextEdit::undoAvailable(bool available)
       
  2952 
       
  2953     This signal is emitted whenever undo operations become available
       
  2954     (\a available is true) or unavailable (\a available is false).
       
  2955 */
       
  2956 
       
  2957 /*!
       
  2958     \fn void QPlainTextEdit::redoAvailable(bool available)
       
  2959 
       
  2960     This signal is emitted whenever redo operations become available
       
  2961     (\a available is true) or unavailable (\a available is false).
       
  2962 */
       
  2963 
       
  2964 QT_END_NAMESPACE
       
  2965 
       
  2966 #include "moc_qplaintextedit.cpp"
       
  2967 #include "moc_qplaintextedit_p.cpp"
       
  2968 
       
  2969 #endif // QT_NO_TEXTEDIT