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