source: trunk/src/gui/widgets/qplaintextedit.cpp@ 332

Last change on this file since 332 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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