/****************************************************************************+ −
**+ −
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).+ −
** All rights reserved.+ −
** Contact: Nokia Corporation (qt-info@nokia.com)+ −
**+ −
** This file is part of the QtGui module of the Qt Toolkit.+ −
**+ −
** $QT_BEGIN_LICENSE:LGPL$+ −
** No Commercial Usage+ −
** This file contains pre-release code and may not be distributed.+ −
** You may use this file in accordance with the terms and conditions+ −
** contained in the Technology Preview License Agreement accompanying+ −
** this package.+ −
**+ −
** GNU Lesser General Public License Usage+ −
** Alternatively, this file may be used under the terms of the GNU Lesser+ −
** General Public License version 2.1 as published by the Free Software+ −
** Foundation and appearing in the file LICENSE.LGPL included in the+ −
** packaging of this file. Please review the following information to+ −
** ensure the GNU Lesser General Public License version 2.1 requirements+ −
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.+ −
**+ −
** In addition, as a special exception, Nokia gives you certain additional+ −
** rights. These rights are described in the Nokia Qt LGPL Exception+ −
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.+ −
**+ −
** If you have questions regarding the use of this file, please contact+ −
** Nokia at qt-info@nokia.com.+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
** $QT_END_LICENSE$+ −
**+ −
****************************************************************************/+ −
+ −
#include "qplaintextedit_p.h"+ −
+ −
+ −
#include <qfont.h>+ −
#include <qpainter.h>+ −
#include <qevent.h>+ −
#include <qdebug.h>+ −
#include <qmime.h>+ −
#include <qdrag.h>+ −
#include <qclipboard.h>+ −
#include <qmenu.h>+ −
#include <qstyle.h>+ −
#include <qtimer.h>+ −
#include "private/qtextdocumentlayout_p.h"+ −
#include "private/qabstracttextdocumentlayout_p.h"+ −
#include "qtextdocument.h"+ −
#include "private/qtextdocument_p.h"+ −
#include "qtextlist.h"+ −
#include "private/qtextcontrol_p.h"+ −
+ −
#include <qtextformat.h>+ −
#include <qdatetime.h>+ −
#include <qapplication.h>+ −
#include <limits.h>+ −
#include <qtexttable.h>+ −
#include <qvariant.h>+ −
#include <qinputcontext.h>+ −
+ −
#ifndef QT_NO_TEXTEDIT+ −
+ −
QT_BEGIN_NAMESPACE+ −
+ −
static inline bool shouldEnableInputMethod(QPlainTextEdit *plaintextedit)+ −
{+ −
return !plaintextedit->isReadOnly();+ −
}+ −
+ −
class QPlainTextDocumentLayoutPrivate : public QAbstractTextDocumentLayoutPrivate+ −
{+ −
Q_DECLARE_PUBLIC(QPlainTextDocumentLayout)+ −
public:+ −
QPlainTextDocumentLayoutPrivate() {+ −
mainViewPrivate = 0;+ −
width = 0;+ −
maximumWidth = 0;+ −
maximumWidthBlockNumber = 0;+ −
blockCount = 1;+ −
blockUpdate = blockDocumentSizeChanged = false;+ −
cursorWidth = 1;+ −
textLayoutFlags = 0;+ −
}+ −
+ −
qreal width;+ −
qreal maximumWidth;+ −
int maximumWidthBlockNumber;+ −
int blockCount;+ −
QPlainTextEditPrivate *mainViewPrivate;+ −
bool blockUpdate;+ −
bool blockDocumentSizeChanged;+ −
int cursorWidth;+ −
int textLayoutFlags;+ −
+ −
void layoutBlock(const QTextBlock &block);+ −
qreal blockWidth(const QTextBlock &block);+ −
+ −
void relayout();+ −
};+ −
+ −
+ −
+ −
/*! \class QPlainTextDocumentLayout+ −
\since 4.4+ −
\brief The QPlainTextDocumentLayout class implements a plain text layout for QTextDocument+ −
+ −
\ingroup richtext-processing+ −
+ −
A QPlainTextDocumentLayout is required for text documents that can+ −
be display or edited in a QPlainTextEdit. See+ −
QTextDocument::setDocumentLayout().+ −
+ −
QPlainTextDocumentLayout uses the QAbstractTextDocumentLayout API+ −
that QTextDocument requires, but redefines it partially in order to+ −
support plain text better. For instances, it does not operate on+ −
vertical pixels, but on paragraphs (called blocks) instead. The+ −
height of a document is identical to the number of paragraphs it+ −
contains. The layout also doesn't support tables or nested frames,+ −
or any sort of advanced text layout that goes beyond a list of+ −
paragraphs with syntax highlighting.+ −
+ −
*/+ −
+ −
+ −
+ −
/*!+ −
Constructs a plain text document layout for the text \a document.+ −
*/+ −
QPlainTextDocumentLayout::QPlainTextDocumentLayout(QTextDocument *document)+ −
:QAbstractTextDocumentLayout(* new QPlainTextDocumentLayoutPrivate, document) {+ −
}+ −
/*!+ −
Destructs a plain text document layout.+ −
*/+ −
QPlainTextDocumentLayout::~QPlainTextDocumentLayout() {}+ −
+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void QPlainTextDocumentLayout::draw(QPainter *, const PaintContext &)+ −
{+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
int QPlainTextDocumentLayout::hitTest(const QPointF &, Qt::HitTestAccuracy ) const+ −
{+ −
// this function is used from+ −
// QAbstractTextDocumentLayout::anchorAt(), but is not+ −
// implementable in a plain text document layout, because the+ −
// layout depends on the top block and top line which depends on+ −
// the view+ −
return -1;+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
int QPlainTextDocumentLayout::pageCount() const+ −
{ return 1; }+ −
+ −
/*!+ −
\reimp+ −
*/+ −
QSizeF QPlainTextDocumentLayout::documentSize() const+ −
{+ −
Q_D(const QPlainTextDocumentLayout);+ −
return QSizeF(d->maximumWidth, document()->lineCount());+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
QRectF QPlainTextDocumentLayout::frameBoundingRect(QTextFrame *) const+ −
{+ −
Q_D(const QPlainTextDocumentLayout);+ −
return QRectF(0, 0, qMax(d->width, d->maximumWidth), qreal(INT_MAX));+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
QRectF QPlainTextDocumentLayout::blockBoundingRect(const QTextBlock &block) const+ −
{+ −
if (!block.isValid()) { return QRectF(); }+ −
QTextLayout *tl = block.layout();+ −
if (!tl->lineCount())+ −
const_cast<QPlainTextDocumentLayout*>(this)->layoutBlock(block);+ −
QRectF br;+ −
if (block.isVisible()) {+ −
br = QRectF(QPointF(0, 0), tl->boundingRect().bottomRight());+ −
if (tl->lineCount() == 1)+ −
br.setWidth(qMax(br.width(), tl->lineAt(0).naturalTextWidth()));+ −
qreal margin = document()->documentMargin();+ −
br.adjust(0, 0, margin, 0);+ −
if (!block.next().isValid())+ −
br.adjust(0, 0, 0, margin);+ −
}+ −
return br;+ −
+ −
}+ −
+ −
/*!+ −
Ensures that \a block has a valid layout+ −
*/+ −
void QPlainTextDocumentLayout::ensureBlockLayout(const QTextBlock &block) const+ −
{+ −
if (!block.isValid())+ −
return;+ −
QTextLayout *tl = block.layout();+ −
if (!tl->lineCount())+ −
const_cast<QPlainTextDocumentLayout*>(this)->layoutBlock(block);+ −
}+ −
+ −
+ −
/*! \property QPlainTextDocumentLayout::cursorWidth+ −
+ −
This property specifies the width of the cursor in pixels. The default value is 1.+ −
*/+ −
void QPlainTextDocumentLayout::setCursorWidth(int width)+ −
{+ −
Q_D(QPlainTextDocumentLayout);+ −
d->cursorWidth = width;+ −
}+ −
+ −
int QPlainTextDocumentLayout::cursorWidth() const+ −
{+ −
Q_D(const QPlainTextDocumentLayout);+ −
return d->cursorWidth;+ −
}+ −
+ −
QPlainTextDocumentLayoutPrivate *QPlainTextDocumentLayout::priv() const+ −
{+ −
Q_D(const QPlainTextDocumentLayout);+ −
return const_cast<QPlainTextDocumentLayoutPrivate*>(d);+ −
}+ −
+ −
+ −
/*!+ −
+ −
Requests a complete update on all views.+ −
*/+ −
void QPlainTextDocumentLayout::requestUpdate()+ −
{+ −
emit update(QRectF(0., -document()->documentMargin(), 1000000000., 1000000000.));+ −
}+ −
+ −
+ −
void QPlainTextDocumentLayout::setTextWidth(qreal newWidth)+ −
{+ −
Q_D(QPlainTextDocumentLayout);+ −
d->width = d->maximumWidth = newWidth;+ −
d->relayout();+ −
}+ −
+ −
qreal QPlainTextDocumentLayout::textWidth() const+ −
{+ −
Q_D(const QPlainTextDocumentLayout);+ −
return d->width;+ −
}+ −
+ −
void QPlainTextDocumentLayoutPrivate::relayout()+ −
{+ −
Q_Q(QPlainTextDocumentLayout);+ −
QTextBlock block = q->document()->firstBlock();+ −
while (block.isValid()) {+ −
block.layout()->clearLayout();+ −
block.setLineCount(block.isVisible() ? 1 : 0);+ −
block = block.next();+ −
}+ −
emit q->update();+ −
}+ −
+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextDocumentLayout::documentChanged(int from, int /*charsRemoved*/, int charsAdded)+ −
{+ −
Q_D(QPlainTextDocumentLayout);+ −
QTextDocument *doc = document();+ −
int newBlockCount = doc->blockCount();+ −
+ −
QTextBlock changeStartBlock = doc->findBlock(from);+ −
QTextBlock changeEndBlock = doc->findBlock(qMax(0, from + charsAdded - 1));+ −
+ −
if (changeStartBlock == changeEndBlock && newBlockCount == d->blockCount) {+ −
QTextBlock block = changeStartBlock;+ −
int blockLineCount = block.layout()->lineCount();+ −
if (block.isValid() && blockLineCount) {+ −
QRectF oldBr = blockBoundingRect(block);+ −
layoutBlock(block);+ −
QRectF newBr = blockBoundingRect(block);+ −
if (newBr.height() == oldBr.height()) {+ −
if (!d->blockUpdate)+ −
emit updateBlock(block);+ −
return;+ −
}+ −
}+ −
} else {+ −
QTextBlock block = changeStartBlock;+ −
do {+ −
block.clearLayout();+ −
if (block == changeEndBlock)+ −
break;+ −
block = block.next();+ −
} while(block.isValid());+ −
}+ −
+ −
if (newBlockCount != d->blockCount) {+ −
+ −
int changeEnd = changeEndBlock.blockNumber();+ −
int blockDiff = newBlockCount - d->blockCount;+ −
int oldChangeEnd = changeEnd - blockDiff;+ −
+ −
if (d->maximumWidthBlockNumber > oldChangeEnd)+ −
d->maximumWidthBlockNumber += blockDiff;+ −
+ −
d->blockCount = newBlockCount;+ −
if (d->blockCount == 1)+ −
d->maximumWidth = blockWidth(doc->firstBlock());+ −
+ −
if (!d->blockDocumentSizeChanged)+ −
emit documentSizeChanged(documentSize());+ −
+ −
if (blockDiff == 1 && changeEnd == newBlockCount -1 ) {+ −
if (!d->blockUpdate) {+ −
QTextBlock b = changeStartBlock;+ −
for(;;) {+ −
emit updateBlock(b);+ −
if (b == changeEndBlock)+ −
break;+ −
b = b.next();+ −
}+ −
}+ −
return;+ −
}+ −
}+ −
+ −
if (!d->blockUpdate)+ −
emit update(QRectF(0., -doc->documentMargin(), 1000000000., 1000000000.)); // optimization potential+ −
}+ −
+ −
+ −
void QPlainTextDocumentLayout::layoutBlock(const QTextBlock &block)+ −
{+ −
Q_D(QPlainTextDocumentLayout);+ −
QTextDocument *doc = document();+ −
qreal margin = doc->documentMargin();+ −
qreal blockMaximumWidth = 0;+ −
+ −
qreal height = 0;+ −
QTextLayout *tl = block.layout();+ −
QTextOption option = doc->defaultTextOption();+ −
tl->setTextOption(option);+ −
+ −
int extraMargin = 0;+ −
if (option.flags() & QTextOption::AddSpaceForLineAndParagraphSeparators) {+ −
QFontMetrics fm(block.charFormat().font());+ −
extraMargin += fm.width(QChar(0x21B5));+ −
}+ −
tl->beginLayout();+ −
qreal availableWidth = d->width;+ −
if (availableWidth <= 0) {+ −
availableWidth = qreal(INT_MAX); // similar to text edit with pageSize.width == 0+ −
}+ −
availableWidth -= 2*margin + extraMargin;+ −
while (1) {+ −
QTextLine line = tl->createLine();+ −
if (!line.isValid())+ −
break;+ −
line.setLeadingIncluded(true);+ −
line.setLineWidth(availableWidth);+ −
line.setPosition(QPointF(margin, height));+ −
height += line.height();+ −
blockMaximumWidth = qMax(blockMaximumWidth, line.naturalTextWidth() + 2*margin);+ −
}+ −
tl->endLayout();+ −
+ −
int previousLineCount = doc->lineCount();+ −
const_cast<QTextBlock&>(block).setLineCount(block.isVisible() ? tl->lineCount() : 0);+ −
int lineCount = doc->lineCount();+ −
+ −
bool emitDocumentSizeChanged = previousLineCount != lineCount;+ −
if (blockMaximumWidth > d->maximumWidth) {+ −
// new longest line+ −
d->maximumWidth = blockMaximumWidth;+ −
d->maximumWidthBlockNumber = block.blockNumber();+ −
emitDocumentSizeChanged = true;+ −
} else if (block.blockNumber() == d->maximumWidthBlockNumber && blockMaximumWidth < d->maximumWidth) {+ −
// longest line shrinking+ −
QTextBlock b = doc->firstBlock();+ −
d->maximumWidth = 0;+ −
QTextBlock maximumBlock;+ −
while (b.isValid()) {+ −
qreal blockMaximumWidth = blockWidth(b);+ −
if (blockMaximumWidth > d->maximumWidth) {+ −
d->maximumWidth = blockMaximumWidth;+ −
maximumBlock = b;+ −
}+ −
b = b.next();+ −
}+ −
if (maximumBlock.isValid()) {+ −
d->maximumWidthBlockNumber = maximumBlock.blockNumber();+ −
emitDocumentSizeChanged = true;+ −
}+ −
}+ −
if (emitDocumentSizeChanged && !d->blockDocumentSizeChanged)+ −
emit documentSizeChanged(documentSize());+ −
}+ −
+ −
qreal QPlainTextDocumentLayout::blockWidth(const QTextBlock &block)+ −
{+ −
QTextLayout *layout = block.layout();+ −
if (!layout->lineCount())+ −
return 0; // only for layouted blocks+ −
qreal blockWidth = 0;+ −
for (int i = 0; i < layout->lineCount(); ++i) {+ −
QTextLine line = layout->lineAt(i);+ −
blockWidth = qMax(line.naturalTextWidth() + 8, blockWidth);+ −
}+ −
return blockWidth;+ −
}+ −
+ −
+ −
QPlainTextEditControl::QPlainTextEditControl(QPlainTextEdit *parent)+ −
: QTextControl(parent), textEdit(parent),+ −
topBlock(0)+ −
{+ −
setAcceptRichText(false);+ −
}+ −
+ −
void QPlainTextEditPrivate::_q_cursorPositionChanged()+ −
{+ −
pageUpDownLastCursorYIsValid = false;+ −
}+ −
+ −
void QPlainTextEditPrivate::_q_verticalScrollbarActionTriggered(int action) {+ −
if (action == QAbstractSlider::SliderPageStepAdd) {+ −
pageUpDown(QTextCursor::Down, QTextCursor::MoveAnchor, false);+ −
} else if (action == QAbstractSlider::SliderPageStepSub) {+ −
pageUpDown(QTextCursor::Up, QTextCursor::MoveAnchor, false);+ −
}+ −
}+ −
+ −
QMimeData *QPlainTextEditControl::createMimeDataFromSelection() const {+ −
QPlainTextEdit *ed = qobject_cast<QPlainTextEdit *>(parent());+ −
if (!ed)+ −
return QTextControl::createMimeDataFromSelection();+ −
return ed->createMimeDataFromSelection();+ −
}+ −
bool QPlainTextEditControl::canInsertFromMimeData(const QMimeData *source) const {+ −
QPlainTextEdit *ed = qobject_cast<QPlainTextEdit *>(parent());+ −
if (!ed)+ −
return QTextControl::canInsertFromMimeData(source);+ −
return ed->canInsertFromMimeData(source);+ −
}+ −
void QPlainTextEditControl::insertFromMimeData(const QMimeData *source) {+ −
QPlainTextEdit *ed = qobject_cast<QPlainTextEdit *>(parent());+ −
if (!ed)+ −
QTextControl::insertFromMimeData(source);+ −
else+ −
ed->insertFromMimeData(source);+ −
}+ −
+ −
int QPlainTextEditPrivate::verticalOffset(int topBlock, int topLine) const+ −
{+ −
qreal offset = 0;+ −
QTextDocument *doc = control->document();+ −
+ −
if (topLine) {+ −
QTextBlock currentBlock = doc->findBlockByNumber(topBlock);+ −
QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout());+ −
Q_ASSERT(documentLayout);+ −
QRectF r = documentLayout->blockBoundingRect(currentBlock);+ −
QTextLayout *layout = currentBlock.layout();+ −
if (layout && topLine <= layout->lineCount()) {+ −
QTextLine line = layout->lineAt(topLine - 1);+ −
const QRectF lr = line.naturalTextRect();+ −
offset = lr.bottom();+ −
}+ −
}+ −
if (topBlock == 0 && topLine == 0)+ −
offset -= doc->documentMargin(); // top margin+ −
return (int)offset;+ −
}+ −
+ −
+ −
int QPlainTextEditPrivate::verticalOffset() const {+ −
return verticalOffset(control->topBlock, topLine);+ −
}+ −
+ −
+ −
QTextBlock QPlainTextEditControl::firstVisibleBlock() const+ −
{+ −
return document()->findBlockByNumber(topBlock);+ −
}+ −
+ −
+ −
+ −
int QPlainTextEditControl::hitTest(const QPointF &point, Qt::HitTestAccuracy ) const {+ −
int currentBlockNumber = topBlock;+ −
QTextBlock currentBlock = document()->findBlockByNumber(currentBlockNumber);+ −
if (!currentBlock.isValid())+ −
return -1;+ −
+ −
QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document()->documentLayout());+ −
Q_ASSERT(documentLayout);+ −
+ −
QPointF offset;+ −
QRectF r = documentLayout->blockBoundingRect(currentBlock);+ −
while (currentBlock.next().isValid() && r.bottom() + offset.y() <= point.y()) {+ −
offset.ry() += r.height();+ −
currentBlock = currentBlock.next();+ −
++currentBlockNumber;+ −
r = documentLayout->blockBoundingRect(currentBlock);+ −
}+ −
while (currentBlock.previous().isValid() && r.top() + offset.y() > point.y()) {+ −
offset.ry() -= r.height();+ −
currentBlock = currentBlock.previous();+ −
--currentBlockNumber;+ −
r = documentLayout->blockBoundingRect(currentBlock);+ −
}+ −
+ −
+ −
if (!currentBlock.isValid())+ −
return -1;+ −
QTextLayout *layout = currentBlock.layout();+ −
int off = 0;+ −
QPointF pos = point - offset;+ −
for (int i = 0; i < layout->lineCount(); ++i) {+ −
QTextLine line = layout->lineAt(i);+ −
const QRectF lr = line.naturalTextRect();+ −
if (lr.top() > pos.y()) {+ −
off = qMin(off, line.textStart());+ −
} else if (lr.bottom() <= pos.y()) {+ −
off = qMax(off, line.textStart() + line.textLength());+ −
} else {+ −
off = line.xToCursor(pos.x(), overwriteMode() ?+ −
QTextLine::CursorOnCharacter : QTextLine::CursorBetweenCharacters);+ −
break;+ −
}+ −
}+ −
+ −
return currentBlock.position() + off;+ −
}+ −
+ −
QRectF QPlainTextEditControl::blockBoundingRect(const QTextBlock &block) const {+ −
int currentBlockNumber = topBlock;+ −
int blockNumber = block.blockNumber();+ −
QTextBlock currentBlock = document()->findBlockByNumber(currentBlockNumber);+ −
if (!currentBlock.isValid())+ −
return QRectF();+ −
Q_ASSERT(currentBlock.blockNumber() == currentBlockNumber);+ −
QTextDocument *doc = document();+ −
QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout());+ −
Q_ASSERT(documentLayout);+ −
+ −
QPointF offset;+ −
if (!block.isValid())+ −
return QRectF();+ −
QRectF r = documentLayout->blockBoundingRect(currentBlock);+ −
int maxVerticalOffset = r.height();+ −
while (currentBlockNumber < blockNumber && offset.y() - maxVerticalOffset <= 2* textEdit->viewport()->height()) {+ −
offset.ry() += r.height();+ −
currentBlock = currentBlock.next();+ −
++currentBlockNumber;+ −
if (!currentBlock.isVisible()) {+ −
currentBlock = doc->findBlockByLineNumber(currentBlock.firstLineNumber());+ −
currentBlockNumber = currentBlock.blockNumber();+ −
}+ −
r = documentLayout->blockBoundingRect(currentBlock);+ −
}+ −
while (currentBlockNumber > blockNumber && offset.y() + maxVerticalOffset >= -textEdit->viewport()->height()) {+ −
currentBlock = currentBlock.previous();+ −
--currentBlockNumber;+ −
while (!currentBlock.isVisible()) {+ −
currentBlock = currentBlock.previous();+ −
--currentBlockNumber;+ −
}+ −
if (!currentBlock.isValid())+ −
break;+ −
+ −
r = documentLayout->blockBoundingRect(currentBlock);+ −
offset.ry() -= r.height();+ −
}+ −
+ −
if (currentBlockNumber != blockNumber) {+ −
// fallback for blocks out of reach. Give it some geometry at+ −
// least, and ensure the layout is up to date.+ −
r = documentLayout->blockBoundingRect(block);+ −
if (currentBlockNumber > blockNumber)+ −
offset.ry() -= r.height();+ −
}+ −
r.translate(offset);+ −
return r;+ −
}+ −
+ −
+ −
void QPlainTextEditPrivate::setTopLine(int visualTopLine, int dx)+ −
{+ −
QTextDocument *doc = control->document();+ −
QTextBlock block = doc->findBlockByLineNumber(visualTopLine);+ −
int blockNumber = block.blockNumber();+ −
int lineNumber = visualTopLine - block.firstLineNumber();+ −
setTopBlock(blockNumber, lineNumber, dx);+ −
}+ −
+ −
void QPlainTextEditPrivate::setTopBlock(int blockNumber, int lineNumber, int dx)+ −
{+ −
Q_Q(QPlainTextEdit);+ −
blockNumber = qMax(0, blockNumber);+ −
lineNumber = qMax(0, lineNumber);+ −
QTextDocument *doc = control->document();+ −
QTextBlock block = doc->findBlockByNumber(blockNumber);+ −
+ −
int newTopLine = block.firstLineNumber() + lineNumber;+ −
int maxTopLine = vbar->maximum();+ −
+ −
if (newTopLine > maxTopLine) {+ −
block = doc->findBlockByLineNumber(maxTopLine);+ −
blockNumber = block.blockNumber();+ −
lineNumber = maxTopLine - block.firstLineNumber();+ −
}+ −
+ −
bool vbarSignalsBlocked = vbar->blockSignals(true);+ −
vbar->setValue(newTopLine);+ −
vbar->blockSignals(vbarSignalsBlocked);+ −
+ −
if (!dx && blockNumber == control->topBlock && lineNumber == topLine)+ −
return;+ −
+ −
if (viewport->updatesEnabled() && viewport->isVisible()) {+ −
int dy = 0;+ −
if (doc->findBlockByNumber(control->topBlock).isValid()) {+ −
dy = (int)(-q->blockBoundingGeometry(block).y())+ −
+ verticalOffset() - verticalOffset(blockNumber, lineNumber);+ −
}+ −
control->topBlock = blockNumber;+ −
topLine = lineNumber;+ −
if (dx || dy)+ −
viewport->scroll(q->isRightToLeft() ? -dx : dx, dy);+ −
else+ −
viewport->update();+ −
emit q->updateRequest(viewport->rect(), dy);+ −
} else {+ −
control->topBlock = blockNumber;+ −
topLine = lineNumber;+ −
}+ −
+ −
}+ −
+ −
+ −
+ −
void QPlainTextEditPrivate::ensureVisible(int position, bool center, bool forceCenter) {+ −
Q_Q(QPlainTextEdit);+ −
QRectF visible = QRectF(viewport->rect()).translated(-q->contentOffset());+ −
QTextBlock block = control->document()->findBlock(position);+ −
if (!block.isValid())+ −
return;+ −
QRectF br = control->blockBoundingRect(block);+ −
if (!br.isValid())+ −
return;+ −
QRectF lr = br;+ −
QTextLine line = block.layout()->lineForTextPosition(position - block.position());+ −
Q_ASSERT(line.isValid());+ −
lr = line.naturalTextRect().translated(br.topLeft());+ −
+ −
if (lr.bottom() >= visible.bottom() || (center && lr.top() < visible.top()) || forceCenter){+ −
+ −
qreal height = visible.height();+ −
if (center)+ −
height /= 2;+ −
+ −
qreal h = center ? line.naturalTextRect().center().y() : line.naturalTextRect().bottom();+ −
+ −
QTextBlock previousVisibleBlock = block;+ −
while (h < height && block.previous().isValid()) {+ −
previousVisibleBlock = block;+ −
do {+ −
block = block.previous();+ −
} while (!block.isVisible() && block.previous().isValid());+ −
h += q->blockBoundingRect(block).height();+ −
}+ −
+ −
int l = 0;+ −
int lineCount = block.layout()->lineCount();+ −
int voffset = verticalOffset(block.blockNumber(), 0);+ −
while (l < lineCount) {+ −
QRectF lineRect = block.layout()->lineAt(l).naturalTextRect();+ −
if (h - voffset - lineRect.top() <= height)+ −
break;+ −
++l;+ −
}+ −
+ −
if (l >= lineCount) {+ −
block = previousVisibleBlock;+ −
l = 0;+ −
}+ −
setTopBlock(block.blockNumber(), l);+ −
} else if (lr.top() < visible.top()) {+ −
setTopBlock(block.blockNumber(), line.lineNumber());+ −
}+ −
+ −
}+ −
+ −
+ −
void QPlainTextEditPrivate::updateViewport()+ −
{+ −
Q_Q(QPlainTextEdit);+ −
viewport->update();+ −
emit q->updateRequest(viewport->rect(), 0);+ −
}+ −
+ −
QPlainTextEditPrivate::QPlainTextEditPrivate()+ −
: control(0),+ −
tabChangesFocus(false),+ −
lineWrap(QPlainTextEdit::WidgetWidth),+ −
wordWrap(QTextOption::WrapAtWordBoundaryOrAnywhere),+ −
clickCausedFocus(0),topLine(0), + −
pageUpDownLastCursorYIsValid(false)+ −
{+ −
showCursorOnInitialShow = true;+ −
backgroundVisible = false;+ −
centerOnScroll = false;+ −
inDrag = false;+ −
}+ −
+ −
+ −
void QPlainTextEditPrivate::init(const QString &txt)+ −
{+ −
Q_Q(QPlainTextEdit);+ −
control = new QPlainTextEditControl(q);+ −
+ −
QTextDocument *doc = new QTextDocument(control);+ −
QAbstractTextDocumentLayout *layout = new QPlainTextDocumentLayout(doc);+ −
doc->setDocumentLayout(layout);+ −
control->setDocument(doc);+ −
+ −
control->setPalette(q->palette());+ −
+ −
QObject::connect(vbar, SIGNAL(actionTriggered(int)), q, SLOT(_q_verticalScrollbarActionTriggered(int)));+ −
+ −
QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(updateMicroFocus()));+ −
QObject::connect(control, SIGNAL(documentSizeChanged(QSizeF)), q, SLOT(_q_adjustScrollbars()));+ −
QObject::connect(control, SIGNAL(blockCountChanged(int)), q, SIGNAL(blockCountChanged(int)));+ −
QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(_q_repaintContents(QRectF)));+ −
QObject::connect(control, SIGNAL(modificationChanged(bool)), q, SIGNAL(modificationChanged(bool)));+ −
+ −
QObject::connect(control, SIGNAL(textChanged()), q, SIGNAL(textChanged()));+ −
QObject::connect(control, SIGNAL(undoAvailable(bool)), q, SIGNAL(undoAvailable(bool)));+ −
QObject::connect(control, SIGNAL(redoAvailable(bool)), q, SIGNAL(redoAvailable(bool)));+ −
QObject::connect(control, SIGNAL(copyAvailable(bool)), q, SIGNAL(copyAvailable(bool)));+ −
QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));+ −
QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(_q_cursorPositionChanged()));+ −
QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));+ −
+ −
QObject::connect(control, SIGNAL(textChanged()), q, SLOT(updateMicroFocus()));+ −
+ −
// set a null page size initially to avoid any relayouting until the textedit+ −
// is shown. relayoutDocument() will take care of setting the page size to the+ −
// viewport dimensions later.+ −
doc->setTextWidth(-1);+ −
doc->documentLayout()->setPaintDevice(viewport);+ −
doc->setDefaultFont(q->font());+ −
+ −
+ −
if (!txt.isEmpty())+ −
control->setPlainText(txt);+ −
+ −
hbar->setSingleStep(20);+ −
vbar->setSingleStep(1);+ −
+ −
viewport->setBackgroundRole(QPalette::Base);+ −
q->setAcceptDrops(true);+ −
q->setFocusPolicy(Qt::WheelFocus);+ −
q->setAttribute(Qt::WA_KeyCompression);+ −
q->setAttribute(Qt::WA_InputMethodEnabled);+ −
+ −
#ifndef QT_NO_CURSOR+ −
viewport->setCursor(Qt::IBeamCursor);+ −
#endif+ −
originalOffsetY = 0;+ −
#ifdef Q_WS_WIN+ −
setSingleFingerPanEnabled(true);+ −
#endif+ −
}+ −
+ −
void QPlainTextEditPrivate::_q_repaintContents(const QRectF &contentsRect)+ −
{+ −
Q_Q(QPlainTextEdit);+ −
if (!contentsRect.isValid()) {+ −
updateViewport();+ −
return;+ −
}+ −
const int xOffset = horizontalOffset();+ −
const int yOffset = verticalOffset();+ −
const QRect visibleRect(xOffset, yOffset, viewport->width(), viewport->height());+ −
+ −
QRect r = contentsRect.adjusted(-1, -1, 1, 1).intersected(visibleRect).toAlignedRect();+ −
if (r.isEmpty())+ −
return;+ −
+ −
r.translate(-xOffset, -yOffset);+ −
viewport->update(r);+ −
emit q->updateRequest(r, 0);+ −
}+ −
+ −
void QPlainTextEditPrivate::pageUpDown(QTextCursor::MoveOperation op, QTextCursor::MoveMode moveMode, bool moveCursor)+ −
{+ −
+ −
Q_Q(QPlainTextEdit);+ −
+ −
QTextCursor cursor = control->textCursor();+ −
if (moveCursor) {+ −
ensureCursorVisible();+ −
if (!pageUpDownLastCursorYIsValid)+ −
pageUpDownLastCursorY = control->cursorRect(cursor).top() - verticalOffset();+ −
}+ −
+ −
qreal lastY = pageUpDownLastCursorY;+ −
+ −
+ −
if (op == QTextCursor::Down) {+ −
QRectF visible = QRectF(viewport->rect()).translated(-q->contentOffset());+ −
QTextBlock firstVisibleBlock = q->firstVisibleBlock();+ −
QTextBlock block = firstVisibleBlock;+ −
QRectF br = q->blockBoundingRect(block);+ −
qreal h = 0;+ −
int atEnd = false;+ −
while (h + br.height() <= visible.bottom()) {+ −
if (!block.next().isValid()) {+ −
atEnd = true;+ −
lastY = visible.bottom(); // set cursor to last line+ −
break;+ −
}+ −
h += br.height();+ −
block = block.next();+ −
br = q->blockBoundingRect(block);+ −
}+ −
+ −
if (!atEnd) {+ −
int line = 0;+ −
qreal diff = visible.bottom() - h;+ −
int lineCount = block.layout()->lineCount();+ −
while (line < lineCount - 1) {+ −
if (block.layout()->lineAt(line).naturalTextRect().bottom() > diff) {+ −
// the first line that did not completely fit the screen+ −
break;+ −
}+ −
++line;+ −
}+ −
setTopBlock(block.blockNumber(), line);+ −
}+ −
+ −
if (moveCursor) {+ −
// move using movePosition to keep the cursor's x+ −
lastY += verticalOffset();+ −
bool moved = false;+ −
do {+ −
moved = cursor.movePosition(op, moveMode);+ −
} while (moved && control->cursorRect(cursor).top() < lastY);+ −
}+ −
+ −
} else if (op == QTextCursor::Up) {+ −
+ −
QRectF visible = QRectF(viewport->rect()).translated(-q->contentOffset());+ −
visible.translate(0, -visible.height()); // previous page+ −
QTextBlock block = q->firstVisibleBlock();+ −
qreal h = 0;+ −
while (h >= visible.top()) {+ −
if (!block.previous().isValid()) {+ −
if (control->topBlock == 0 && topLine == 0) {+ −
lastY = 0; // set cursor to first line+ −
}+ −
break;+ −
}+ −
block = block.previous();+ −
QRectF br = q->blockBoundingRect(block);+ −
h -= br.height();+ −
}+ −
+ −
int line = 0;+ −
if (block.isValid()) {+ −
qreal diff = visible.top() - h;+ −
int lineCount = block.layout()->lineCount();+ −
while (line < lineCount) {+ −
if (block.layout()->lineAt(line).naturalTextRect().top() >= diff)+ −
break;+ −
++line;+ −
}+ −
if (line == lineCount) {+ −
if (block.next().isValid() && block.next() != q->firstVisibleBlock()) {+ −
block = block.next();+ −
line = 0;+ −
} else {+ −
--line;+ −
}+ −
}+ −
}+ −
setTopBlock(block.blockNumber(), line);+ −
+ −
if (moveCursor) {+ −
// move using movePosition to keep the cursor's x+ −
lastY += verticalOffset();+ −
bool moved = false;+ −
do {+ −
moved = cursor.movePosition(op, moveMode);+ −
} while (moved && control->cursorRect(cursor).top() > lastY);+ −
}+ −
}+ −
+ −
if (moveCursor) {+ −
control->setTextCursor(cursor);+ −
pageUpDownLastCursorYIsValid = true;+ −
}+ −
}+ −
+ −
#ifndef QT_NO_SCROLLBAR+ −
+ −
void QPlainTextEditPrivate::_q_adjustScrollbars()+ −
{+ −
Q_Q(QPlainTextEdit);+ −
QTextDocument *doc = control->document();+ −
QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout());+ −
Q_ASSERT(documentLayout);+ −
bool documentSizeChangedBlocked = documentLayout->priv()->blockDocumentSizeChanged;+ −
documentLayout->priv()->blockDocumentSizeChanged = true;+ −
qreal margin = doc->documentMargin();+ −
+ −
int vmax = 0;+ −
+ −
int vSliderLength = 0;+ −
if (!centerOnScroll && q->isVisible()) {+ −
QTextBlock block = doc->lastBlock();+ −
const int visible = static_cast<int>(viewport->rect().height() - margin - 1);+ −
int y = 0;+ −
int visibleFromBottom = 0;+ −
+ −
while (block.isValid()) {+ −
if (!block.isVisible()) {+ −
block = block.previous();+ −
continue;+ −
}+ −
y += int(documentLayout->blockBoundingRect(block).height());+ −
+ −
QTextLayout *layout = block.layout();+ −
int layoutLineCount = layout->lineCount();+ −
if (y > visible) {+ −
int lineNumber = 0;+ −
while (lineNumber < layoutLineCount) {+ −
QTextLine line = layout->lineAt(lineNumber);+ −
const QRectF lr = line.naturalTextRect();+ −
if (int(lr.top()) >= y - visible)+ −
break;+ −
++lineNumber;+ −
}+ −
if (lineNumber < layoutLineCount)+ −
visibleFromBottom += (layoutLineCount - lineNumber - 1);+ −
break;+ −
+ −
}+ −
visibleFromBottom += layoutLineCount;+ −
block = block.previous();+ −
}+ −
vmax = qMax(0, doc->lineCount() - visibleFromBottom);+ −
vSliderLength = visibleFromBottom;+ −
+ −
} else {+ −
vmax = qMax(0, doc->lineCount() - 1);+ −
vSliderLength = viewport->height() / q->fontMetrics().lineSpacing();+ −
}+ −
+ −
+ −
+ −
QSizeF documentSize = documentLayout->documentSize();+ −
vbar->setRange(0, qMax(0, vmax));+ −
vbar->setPageStep(vSliderLength);+ −
int visualTopLine = vmax;+ −
QTextBlock firstVisibleBlock = q->firstVisibleBlock();+ −
if (firstVisibleBlock.isValid())+ −
visualTopLine = firstVisibleBlock.firstLineNumber() + topLine;+ −
bool vbarSignalsBlocked = vbar->blockSignals(true);+ −
vbar->setValue(visualTopLine);+ −
vbar->blockSignals(vbarSignalsBlocked);+ −
+ −
hbar->setRange(0, (int)documentSize.width() - viewport->width());+ −
hbar->setPageStep(viewport->width());+ −
documentLayout->priv()->blockDocumentSizeChanged = documentSizeChangedBlocked;+ −
setTopLine(vbar->value());+ −
}+ −
+ −
#endif+ −
+ −
+ −
void QPlainTextEditPrivate::ensureViewportLayouted()+ −
{+ −
}+ −
+ −
/*!+ −
\class QPlainTextEdit+ −
\since 4.4+ −
\brief The QPlainTextEdit class provides a widget that is used to edit and display+ −
plain text.+ −
+ −
\ingroup richtext-processing+ −
+ −
+ −
\tableofcontents+ −
+ −
\section1 Introduction and Concepts+ −
+ −
QPlainTextEdit is an advanced viewer/editor supporting plain+ −
text. It is optimized to handle large documents and to respond+ −
quickly to user input.+ −
+ −
QPlainText uses very much the same technology and concepts as+ −
QTextEdit, but is optimized for plain text handling.+ −
+ −
QPlainTextEdit works on paragraphs and characters. A paragraph is+ −
a formatted string which is word-wrapped to fit into the width of+ −
the widget. By default when reading plain text, one newline+ −
signifies a paragraph. A document consists of zero or more+ −
paragraphs. Paragraphs are separated by hard line breaks. Each+ −
character within a paragraph has its own attributes, for example,+ −
font and color.+ −
+ −
The shape of the mouse cursor on a QPlainTextEdit is+ −
Qt::IBeamCursor by default. It can be changed through the+ −
viewport()'s cursor property.+ −
+ −
\section1 Using QPlainTextEdit as a Display Widget+ −
+ −
The text is set or replaced using setPlainText() which deletes the+ −
existing text and replaces it with the text passed to setPlainText().+ −
+ −
Text can be inserted using the QTextCursor class or using the+ −
convenience functions insertPlainText(), appendPlainText() or+ −
paste().+ −
+ −
By default, the text edit wraps words at whitespace to fit within+ −
the text edit widget. The setLineWrapMode() function is used to+ −
specify the kind of line wrap you want, \l WidgetWidth or \l+ −
NoWrap if you don't want any wrapping. If you use word wrap to+ −
the widget's width \l WidgetWidth, you can specify whether to+ −
break on whitespace or anywhere with setWordWrapMode().+ −
+ −
The find() function can be used to find and select a given string+ −
within the text.+ −
+ −
If you want to limit the total number of paragraphs in a+ −
QPlainTextEdit, as it is for example useful in a log viewer, then+ −
you can use the maximumBlockCount property. The combination of+ −
setMaximumBlockCount() and appendPlainText() turns QPlainTextEdit+ −
into an efficient viewer for log text. The scrolling can be+ −
reduced with the centerOnScroll() property, making the log viewer+ −
even faster. Text can be formatted in a limited way, either using+ −
a syntax highlighter (see below), or by appending html-formatted+ −
text with appendHtml(). While QPlainTextEdit does not support+ −
complex rich text rendering with tables and floats, it does+ −
support limited paragraph-based formatting that you may need in a+ −
log viewer.+ −
+ −
\section2 Read-only Key Bindings+ −
+ −
When QPlainTextEdit is used read-only the key bindings are limited to+ −
navigation, and text may only be selected with the mouse:+ −
\table+ −
\header \i Keypresses \i Action+ −
\row \i Qt::UpArrow \i Moves one line up.+ −
\row \i Qt::DownArrow \i Moves one line down.+ −
\row \i Qt::LeftArrow \i Moves one character to the left.+ −
\row \i Qt::RightArrow \i Moves one character to the right.+ −
\row \i PageUp \i Moves one (viewport) page up.+ −
\row \i PageDown \i Moves one (viewport) page down.+ −
\row \i Home \i Moves to the beginning of the text.+ −
\row \i End \i Moves to the end of the text.+ −
\row \i Alt+Wheel+ −
\i Scrolls the page horizontally (the Wheel is the mouse wheel).+ −
\row \i Ctrl+Wheel \i Zooms the text.+ −
\row \i Ctrl+A \i Selects all text.+ −
\endtable+ −
+ −
+ −
\section1 Using QPlainTextEdit as an Editor+ −
+ −
All the information about using QPlainTextEdit as a display widget also+ −
applies here.+ −
+ −
Selection of text is handled by the QTextCursor class, which provides+ −
functionality for creating selections, retrieving the text contents or+ −
deleting selections. You can retrieve the object that corresponds with+ −
the user-visible cursor using the textCursor() method. If you want to set+ −
a selection in QPlainTextEdit just create one on a QTextCursor object and+ −
then make that cursor the visible cursor using setCursor(). The selection+ −
can be copied to the clipboard with copy(), or cut to the clipboard with+ −
cut(). The entire text can be selected using selectAll().+ −
+ −
QPlainTextEdit holds a QTextDocument object which can be retrieved using the+ −
document() method. You can also set your own document object using setDocument().+ −
QTextDocument emits a textChanged() signal if the text changes and it also+ −
provides a isModified() function which will return true if the text has been+ −
modified since it was either loaded or since the last call to setModified+ −
with false as argument. In addition it provides methods for undo and redo.+ −
+ −
\section2 Syntax Highlighting+ −
+ −
Just like QTextEdit, QPlainTextEdit works together with+ −
QSyntaxHighlighter.+ −
+ −
\section2 Editing Key Bindings+ −
+ −
The list of key bindings which are implemented for editing:+ −
\table+ −
\header \i Keypresses \i Action+ −
\row \i Backspace \i Deletes the character to the left of the cursor.+ −
\row \i Delete \i Deletes the character to the right of the cursor.+ −
\row \i Ctrl+C \i Copy the selected text to the clipboard.+ −
\row \i Ctrl+Insert \i Copy the selected text to the clipboard.+ −
\row \i Ctrl+K \i Deletes to the end of the line.+ −
\row \i Ctrl+V \i Pastes the clipboard text into text edit.+ −
\row \i Shift+Insert \i Pastes the clipboard text into text edit.+ −
\row \i Ctrl+X \i Deletes the selected text and copies it to the clipboard.+ −
\row \i Shift+Delete \i Deletes the selected text and copies it to the clipboard.+ −
\row \i Ctrl+Z \i Undoes the last operation.+ −
\row \i Ctrl+Y \i Redoes the last operation.+ −
\row \i LeftArrow \i Moves the cursor one character to the left.+ −
\row \i Ctrl+LeftArrow \i Moves the cursor one word to the left.+ −
\row \i RightArrow \i Moves the cursor one character to the right.+ −
\row \i Ctrl+RightArrow \i Moves the cursor one word to the right.+ −
\row \i UpArrow \i Moves the cursor one line up.+ −
\row \i Ctrl+UpArrow \i Moves the cursor one word up.+ −
\row \i DownArrow \i Moves the cursor one line down.+ −
\row \i Ctrl+Down Arrow \i Moves the cursor one word down.+ −
\row \i PageUp \i Moves the cursor one page up.+ −
\row \i PageDown \i Moves the cursor one page down.+ −
\row \i Home \i Moves the cursor to the beginning of the line.+ −
\row \i Ctrl+Home \i Moves the cursor to the beginning of the text.+ −
\row \i End \i Moves the cursor to the end of the line.+ −
\row \i Ctrl+End \i Moves the cursor to the end of the text.+ −
\row \i Alt+Wheel \i Scrolls the page horizontally (the Wheel is the mouse wheel).+ −
\row \i Ctrl+Wheel \i Zooms the text.+ −
\endtable+ −
+ −
To select (mark) text hold down the Shift key whilst pressing one+ −
of the movement keystrokes, for example, \e{Shift+Right Arrow}+ −
will select the character to the right, and \e{Shift+Ctrl+Right+ −
Arrow} will select the word to the right, etc.+ −
+ −
\section1 Differences to QTextEdit+ −
+ −
QPlainTextEdit is a thin class, implemented by using most of the+ −
technology that is behind QTextEdit and QTextDocument. Its+ −
performance benefits over QTextEdit stem mostly from using a+ −
different and simplified text layout called+ −
QPlainTextDocumentLayout on the text document (see+ −
QTextDocument::setDocumentLayout()). The plain text document layout+ −
does not support tables nor embedded frames, and \e{replaces a+ −
pixel-exact height calculation with a line-by-line respectively+ −
paragraph-by-paragraph scrolling approach}. This makes it possible+ −
to handle significantly larger documents, and still resize the+ −
editor with line wrap enabled in real time. It also makes for a+ −
fast log viewer (see setMaximumBlockCount()).+ −
+ −
+ −
\sa QTextDocument, QTextCursor, {Application Example},+ −
{Code Editor Example}, {Syntax Highlighter Example},+ −
{Rich Text Processing}+ −
+ −
*/+ −
+ −
/*!+ −
\property QPlainTextEdit::plainText+ −
+ −
This property gets and sets the plain text editor's contents. The previous+ −
contents are removed and undo/redo history is reset when this property is set.+ −
+ −
By default, for an editor with no contents, this property contains an empty string.+ −
*/+ −
+ −
/*!+ −
\property QPlainTextEdit::undoRedoEnabled+ −
\brief whether undo and redo are enabled+ −
+ −
Users are only able to undo or redo actions if this property is+ −
true, and if there is an action that can be undone (or redone).+ −
+ −
By default, this property is true.+ −
*/+ −
+ −
/*!+ −
\enum QPlainTextEdit::LineWrapMode+ −
+ −
\value NoWrap+ −
\value WidgetWidth+ −
*/+ −
+ −
+ −
/*!+ −
Constructs an empty QPlainTextEdit with parent \a+ −
parent.+ −
*/+ −
QPlainTextEdit::QPlainTextEdit(QWidget *parent)+ −
: QAbstractScrollArea(*new QPlainTextEditPrivate, parent)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->init();+ −
}+ −
+ −
/*!+ −
\internal+ −
*/+ −
QPlainTextEdit::QPlainTextEdit(QPlainTextEditPrivate &dd, QWidget *parent)+ −
: QAbstractScrollArea(dd, parent)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->init();+ −
}+ −
+ −
/*!+ −
Constructs a QPlainTextEdit with parent \a parent. The text edit will display+ −
the plain text \a text.+ −
*/+ −
QPlainTextEdit::QPlainTextEdit(const QString &text, QWidget *parent)+ −
: QAbstractScrollArea(*new QPlainTextEditPrivate, parent)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->init(text);+ −
}+ −
+ −
+ −
/*!+ −
Destructor.+ −
*/+ −
QPlainTextEdit::~QPlainTextEdit()+ −
{+ −
Q_D(QPlainTextEdit);+ −
if (d->documentLayoutPtr) {+ −
if (d->documentLayoutPtr->priv()->mainViewPrivate == d)+ −
d->documentLayoutPtr->priv()->mainViewPrivate = 0;+ −
}+ −
}+ −
+ −
/*!+ −
Makes \a document the new document of the text editor.+ −
+ −
The parent QObject of the provided document remains the owner+ −
of the object. If the current document is a child of the text+ −
editor, then it is deleted.+ −
+ −
The document must have a document layout that inherits+ −
QPlainTextDocumentLayout (see QTextDocument::setDocumentLayout()).+ −
+ −
\sa document()+ −
*/+ −
void QPlainTextEdit::setDocument(QTextDocument *document)+ −
{+ −
Q_D(QPlainTextEdit);+ −
QPlainTextDocumentLayout *documentLayout = 0;+ −
+ −
if (!document) {+ −
document = new QTextDocument(d->control);+ −
documentLayout = new QPlainTextDocumentLayout(document);+ −
document->setDocumentLayout(documentLayout);+ −
} else {+ −
documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document->documentLayout());+ −
if (!documentLayout) {+ −
qWarning("QPlainTextEdit::setDocument: Document set does not support QPlainTextDocumentLayout");+ −
return;+ −
}+ −
}+ −
d->control->setDocument(document);+ −
if (!documentLayout->priv()->mainViewPrivate)+ −
documentLayout->priv()->mainViewPrivate = d;+ −
d->documentLayoutPtr = documentLayout;+ −
d->updateDefaultTextOption();+ −
d->relayoutDocument();+ −
d->_q_adjustScrollbars();+ −
}+ −
+ −
/*!+ −
Returns a pointer to the underlying document.+ −
+ −
\sa setDocument()+ −
*/+ −
QTextDocument *QPlainTextEdit::document() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->control->document();+ −
}+ −
+ −
/*!+ −
Sets the visible \a cursor.+ −
*/+ −
void QPlainTextEdit::setTextCursor(const QTextCursor &cursor)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->setTextCursor(cursor);+ −
}+ −
+ −
/*!+ −
Returns a copy of the QTextCursor that represents the currently visible cursor.+ −
Note that changes on the returned cursor do not affect QPlainTextEdit's cursor; use+ −
setTextCursor() to update the visible cursor.+ −
*/+ −
QTextCursor QPlainTextEdit::textCursor() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->control->textCursor();+ −
}+ −
+ −
+ −
/*!+ −
Undoes the last operation.+ −
+ −
If there is no operation to undo, i.e. there is no undo step in+ −
the undo/redo history, nothing happens.+ −
+ −
\sa redo()+ −
*/+ −
void QPlainTextEdit::undo()+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->undo();+ −
}+ −
+ −
void QPlainTextEdit::redo()+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->redo();+ −
}+ −
+ −
/*!+ −
\fn void QPlainTextEdit::redo()+ −
+ −
Redoes the last operation.+ −
+ −
If there is no operation to redo, i.e. there is no redo step in+ −
the undo/redo history, nothing happens.+ −
+ −
\sa undo()+ −
*/+ −
+ −
#ifndef QT_NO_CLIPBOARD+ −
/*!+ −
Copies the selected text to the clipboard and deletes it from+ −
the text edit.+ −
+ −
If there is no selected text nothing happens.+ −
+ −
\sa copy() paste()+ −
*/+ −
+ −
void QPlainTextEdit::cut()+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->cut();+ −
}+ −
+ −
/*!+ −
Copies any selected text to the clipboard.+ −
+ −
\sa copyAvailable()+ −
*/+ −
+ −
void QPlainTextEdit::copy()+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->copy();+ −
}+ −
+ −
/*!+ −
Pastes the text from the clipboard into the text edit at the+ −
current cursor position.+ −
+ −
If there is no text in the clipboard nothing happens.+ −
+ −
To change the behavior of this function, i.e. to modify what+ −
QPlainTextEdit can paste and how it is being pasted, reimplement the+ −
virtual canInsertFromMimeData() and insertFromMimeData()+ −
functions.+ −
+ −
\sa cut() copy()+ −
*/+ −
+ −
void QPlainTextEdit::paste()+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->paste();+ −
}+ −
#endif+ −
+ −
/*!+ −
Deletes all the text in the text edit.+ −
+ −
Note that the undo/redo history is cleared by this function.+ −
+ −
\sa cut() setPlainText()+ −
*/+ −
void QPlainTextEdit::clear()+ −
{+ −
Q_D(QPlainTextEdit);+ −
// clears and sets empty content+ −
d->control->topBlock = d->topLine = 0;+ −
d->control->clear();+ −
}+ −
+ −
+ −
/*!+ −
Selects all text.+ −
+ −
\sa copy() cut() textCursor()+ −
*/+ −
void QPlainTextEdit::selectAll()+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->selectAll();+ −
}+ −
+ −
/*! \internal+ −
*/+ −
bool QPlainTextEdit::event(QEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
+ −
#ifndef QT_NO_CONTEXTMENU+ −
if (e->type() == QEvent::ContextMenu+ −
&& static_cast<QContextMenuEvent *>(e)->reason() == QContextMenuEvent::Keyboard) {+ −
ensureCursorVisible();+ −
const QPoint cursorPos = cursorRect().center();+ −
QContextMenuEvent ce(QContextMenuEvent::Keyboard, cursorPos, d->viewport->mapToGlobal(cursorPos));+ −
ce.setAccepted(e->isAccepted());+ −
const bool result = QAbstractScrollArea::event(&ce);+ −
e->setAccepted(ce.isAccepted());+ −
return result;+ −
}+ −
#endif // QT_NO_CONTEXTMENU+ −
if (e->type() == QEvent::ShortcutOverride+ −
|| e->type() == QEvent::ToolTip) {+ −
d->sendControlEvent(e);+ −
}+ −
#ifdef QT_KEYPAD_NAVIGATION+ −
else if (e->type() == QEvent::EnterEditFocus || e->type() == QEvent::LeaveEditFocus) {+ −
if (QApplication::keypadNavigationEnabled())+ −
d->sendControlEvent(e);+ −
}+ −
#endif+ −
else if (e->type() == QEvent::Gesture) {+ −
QGestureEvent *ge = static_cast<QGestureEvent *>(e);+ −
QPanGesture *g = static_cast<QPanGesture *>(ge->gesture(Qt::PanGesture));+ −
if (g) {+ −
QScrollBar *hBar = horizontalScrollBar();+ −
QScrollBar *vBar = verticalScrollBar();+ −
if (g->state() == Qt::GestureStarted)+ −
d->originalOffsetY = vBar->value();+ −
QPointF offset = g->offset();+ −
if (!offset.isNull()) {+ −
if (QApplication::isRightToLeft())+ −
offset.rx() *= -1;+ −
// QPlainTextEdit scrolls by lines only in vertical direction+ −
QFontMetrics fm(document()->defaultFont());+ −
int lineHeight = fm.height();+ −
int newX = hBar->value() - g->delta().x();+ −
int newY = d->originalOffsetY - offset.y()/lineHeight;+ −
hBar->setValue(newX);+ −
vBar->setValue(newY);+ −
}+ −
}+ −
return true;+ −
}+ −
return QAbstractScrollArea::event(e);+ −
}+ −
+ −
/*! \internal+ −
*/+ −
+ −
void QPlainTextEdit::timerEvent(QTimerEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
if (e->timerId() == d->autoScrollTimer.timerId()) {+ −
QRect visible = d->viewport->rect();+ −
QPoint pos;+ −
if (d->inDrag) {+ −
pos = d->autoScrollDragPos;+ −
visible.adjust(qMin(visible.width()/3,20), qMin(visible.height()/3,20),+ −
-qMin(visible.width()/3,20), -qMin(visible.height()/3,20));+ −
} else {+ −
const QPoint globalPos = QCursor::pos();+ −
pos = d->viewport->mapFromGlobal(globalPos);+ −
QMouseEvent ev(QEvent::MouseMove, pos, globalPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);+ −
mouseMoveEvent(&ev);+ −
}+ −
int deltaY = qMax(pos.y() - visible.top(), visible.bottom() - pos.y()) - visible.height();+ −
int deltaX = qMax(pos.x() - visible.left(), visible.right() - pos.x()) - visible.width();+ −
int delta = qMax(deltaX, deltaY);+ −
if (delta >= 0) {+ −
if (delta < 7)+ −
delta = 7;+ −
int timeout = 4900 / (delta * delta);+ −
d->autoScrollTimer.start(timeout, this);+ −
+ −
if (deltaY > 0)+ −
d->vbar->triggerAction(pos.y() < visible.center().y() ?+ −
QAbstractSlider::SliderSingleStepSub+ −
: QAbstractSlider::SliderSingleStepAdd);+ −
if (deltaX > 0)+ −
d->hbar->triggerAction(pos.x() < visible.center().x() ?+ −
QAbstractSlider::SliderSingleStepSub+ −
: QAbstractSlider::SliderSingleStepAdd);+ −
}+ −
}+ −
#ifdef QT_KEYPAD_NAVIGATION+ −
else if (e->timerId() == d->deleteAllTimer.timerId()) {+ −
d->deleteAllTimer.stop();+ −
clear();+ −
}+ −
#endif+ −
}+ −
+ −
/*!+ −
Changes the text of the text edit to the string \a text.+ −
Any previous text is removed.+ −
+ −
\a text is interpreted as plain text.+ −
+ −
Note that the undo/redo history is cleared by this function.+ −
+ −
\sa toText()+ −
*/+ −
+ −
void QPlainTextEdit::setPlainText(const QString &text)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->setPlainText(text);+ −
}+ −
+ −
/*!+ −
\fn QString QPlainTextEdit::toPlainText() const+ −
+ −
Returns the text of the text edit as plain text.+ −
+ −
\sa QPlainTextEdit::setPlainText()+ −
*/+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::keyPressEvent(QKeyEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
+ −
#ifdef QT_KEYPAD_NAVIGATION+ −
switch (e->key()) {+ −
case Qt::Key_Select:+ −
if (QApplication::keypadNavigationEnabled()) {+ −
if (!(d->control->textInteractionFlags() & Qt::LinksAccessibleByKeyboard))+ −
setEditFocus(!hasEditFocus());+ −
else {+ −
if (!hasEditFocus())+ −
setEditFocus(true);+ −
else {+ −
QTextCursor cursor = d->control->textCursor();+ −
QTextCharFormat charFmt = cursor.charFormat();+ −
if (!cursor.hasSelection() || charFmt.anchorHref().isEmpty()) {+ −
setEditFocus(false);+ −
}+ −
}+ −
}+ −
}+ −
break;+ −
case Qt::Key_Back:+ −
case Qt::Key_No:+ −
if (!QApplication::keypadNavigationEnabled()+ −
|| (QApplication::keypadNavigationEnabled() && !hasEditFocus())) {+ −
e->ignore();+ −
return;+ −
}+ −
break;+ −
default:+ −
if (QApplication::keypadNavigationEnabled()) {+ −
if (!hasEditFocus() && !(e->modifiers() & Qt::ControlModifier)) {+ −
if (e->text()[0].isPrint()) {+ −
setEditFocus(true);+ −
clear();+ −
} else {+ −
e->ignore();+ −
return;+ −
}+ −
}+ −
}+ −
break;+ −
}+ −
#endif+ −
+ −
#ifndef QT_NO_SHORTCUT+ −
+ −
Qt::TextInteractionFlags tif = d->control->textInteractionFlags();+ −
+ −
if (tif & Qt::TextSelectableByKeyboard){+ −
if (e == QKeySequence::SelectPreviousPage) {+ −
e->accept();+ −
d->pageUpDown(QTextCursor::Up, QTextCursor::KeepAnchor);+ −
return;+ −
} else if (e ==QKeySequence::SelectNextPage) {+ −
e->accept();+ −
d->pageUpDown(QTextCursor::Down, QTextCursor::KeepAnchor);+ −
return;+ −
}+ −
}+ −
if (tif & (Qt::TextSelectableByKeyboard | Qt::TextEditable)) {+ −
if (e == QKeySequence::MoveToPreviousPage) {+ −
e->accept();+ −
d->pageUpDown(QTextCursor::Up, QTextCursor::MoveAnchor);+ −
return;+ −
} else if (e == QKeySequence::MoveToNextPage) {+ −
e->accept();+ −
d->pageUpDown(QTextCursor::Down, QTextCursor::MoveAnchor);+ −
return;+ −
}+ −
}+ −
+ −
if (!(tif & Qt::TextEditable)) {+ −
switch (e->key()) {+ −
case Qt::Key_Space:+ −
e->accept();+ −
if (e->modifiers() & Qt::ShiftModifier)+ −
d->vbar->triggerAction(QAbstractSlider::SliderPageStepSub);+ −
else+ −
d->vbar->triggerAction(QAbstractSlider::SliderPageStepAdd);+ −
break;+ −
default:+ −
d->sendControlEvent(e);+ −
if (!e->isAccepted() && e->modifiers() == Qt::NoModifier) {+ −
if (e->key() == Qt::Key_Home) {+ −
d->vbar->triggerAction(QAbstractSlider::SliderToMinimum);+ −
e->accept();+ −
} else if (e->key() == Qt::Key_End) {+ −
d->vbar->triggerAction(QAbstractSlider::SliderToMaximum);+ −
e->accept();+ −
}+ −
}+ −
if (!e->isAccepted()) {+ −
QAbstractScrollArea::keyPressEvent(e);+ −
}+ −
}+ −
return;+ −
}+ −
#endif // QT_NO_SHORTCUT+ −
+ −
d->sendControlEvent(e);+ −
#ifdef QT_KEYPAD_NAVIGATION+ −
if (!e->isAccepted()) {+ −
switch (e->key()) {+ −
case Qt::Key_Up:+ −
case Qt::Key_Down:+ −
if (QApplication::keypadNavigationEnabled()) {+ −
// Cursor position didn't change, so we want to leave+ −
// these keys to change focus.+ −
e->ignore();+ −
return;+ −
}+ −
break;+ −
case Qt::Key_Left:+ −
case Qt::Key_Right:+ −
if (QApplication::keypadNavigationEnabled()+ −
&& QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) {+ −
// Same as for Key_Up and Key_Down.+ −
e->ignore();+ −
return;+ −
}+ −
break;+ −
case Qt::Key_Back:+ −
if (!e->isAutoRepeat()) {+ −
if (QApplication::keypadNavigationEnabled()) {+ −
if (document()->isEmpty()) {+ −
setEditFocus(false);+ −
e->accept();+ −
} else if (!d->deleteAllTimer.isActive()) {+ −
e->accept();+ −
d->deleteAllTimer.start(750, this);+ −
}+ −
} else {+ −
e->ignore();+ −
return;+ −
}+ −
}+ −
break;+ −
default: break;+ −
}+ −
}+ −
#endif+ −
}+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::keyReleaseEvent(QKeyEvent *e)+ −
{+ −
#ifdef QT_KEYPAD_NAVIGATION+ −
Q_D(QPlainTextEdit);+ −
if (QApplication::keypadNavigationEnabled()) {+ −
if (!e->isAutoRepeat() && e->key() == Qt::Key_Back+ −
&& d->deleteAllTimer.isActive()) {+ −
d->deleteAllTimer.stop();+ −
QTextCursor cursor = d->control->textCursor();+ −
QTextBlockFormat blockFmt = cursor.blockFormat();+ −
+ −
QTextList *list = cursor.currentList();+ −
if (list && cursor.atBlockStart()) {+ −
list->remove(cursor.block());+ −
} else if (cursor.atBlockStart() && blockFmt.indent() > 0) {+ −
blockFmt.setIndent(blockFmt.indent() - 1);+ −
cursor.setBlockFormat(blockFmt);+ −
} else {+ −
cursor.deletePreviousChar();+ −
}+ −
setTextCursor(cursor);+ −
}+ −
}+ −
#else+ −
Q_UNUSED(e);+ −
#endif+ −
}+ −
+ −
/*!+ −
Loads the resource specified by the given \a type and \a name.+ −
+ −
This function is an extension of QTextDocument::loadResource().+ −
+ −
\sa QTextDocument::loadResource()+ −
*/+ −
QVariant QPlainTextEdit::loadResource(int type, const QUrl &name)+ −
{+ −
Q_UNUSED(type);+ −
Q_UNUSED(name);+ −
return QVariant();+ −
}+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::resizeEvent(QResizeEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
if (e->oldSize().width() != e->size().width())+ −
d->relayoutDocument();+ −
d->_q_adjustScrollbars();+ −
}+ −
+ −
void QPlainTextEditPrivate::relayoutDocument()+ −
{+ −
QTextDocument *doc = control->document();+ −
QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout());+ −
Q_ASSERT(documentLayout);+ −
documentLayoutPtr = documentLayout;+ −
+ −
int width = viewport->width();+ −
+ −
if (documentLayout->priv()->mainViewPrivate == 0+ −
|| documentLayout->priv()->mainViewPrivate == this+ −
|| width > documentLayout->textWidth()) {+ −
documentLayout->priv()->mainViewPrivate = this;+ −
documentLayout->setTextWidth(width);+ −
}+ −
}+ −
+ −
static void fillBackground(QPainter *p, const QRectF &rect, QBrush brush, QRectF gradientRect = QRectF())+ −
{+ −
p->save();+ −
if (brush.style() >= Qt::LinearGradientPattern && brush.style() <= Qt::ConicalGradientPattern) {+ −
if (!gradientRect.isNull()) {+ −
QTransform m = QTransform::fromTranslate(gradientRect.left(), gradientRect.top());+ −
m.scale(gradientRect.width(), gradientRect.height());+ −
brush.setTransform(m);+ −
const_cast<QGradient *>(brush.gradient())->setCoordinateMode(QGradient::LogicalMode);+ −
}+ −
} else {+ −
p->setBrushOrigin(rect.topLeft());+ −
}+ −
p->fillRect(rect, brush);+ −
p->restore();+ −
}+ −
+ −
+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::paintEvent(QPaintEvent *e)+ −
{+ −
QPainter painter(viewport());+ −
Q_ASSERT(qobject_cast<QPlainTextDocumentLayout*>(document()->documentLayout()));+ −
+ −
QPointF offset(contentOffset());+ −
+ −
QRect er = e->rect();+ −
QRect viewportRect = viewport()->rect();+ −
+ −
bool editable = !isReadOnly();+ −
+ −
QTextBlock block = firstVisibleBlock();+ −
qreal maximumWidth = document()->documentLayout()->documentSize().width();+ −
+ −
// Set a brush origin so that the WaveUnderline knows where the wave started+ −
painter.setBrushOrigin(offset);+ −
+ −
// keep right margin clean from full-width selection+ −
int maxX = offset.x() + qMax((qreal)viewportRect.width(), maximumWidth)+ −
- document()->documentMargin();+ −
er.setRight(qMin(er.right(), maxX));+ −
painter.setClipRect(er);+ −
+ −
+ −
QAbstractTextDocumentLayout::PaintContext context = getPaintContext();+ −
+ −
while (block.isValid()) {+ −
+ −
QRectF r = blockBoundingRect(block).translated(offset);+ −
QTextLayout *layout = block.layout();+ −
+ −
if (!block.isVisible()) {+ −
offset.ry() += r.height();+ −
block = block.next();+ −
continue;+ −
}+ −
+ −
if (r.bottom() >= er.top() && r.top() <= er.bottom()) {+ −
+ −
QTextBlockFormat blockFormat = block.blockFormat();+ −
+ −
QBrush bg = blockFormat.background();+ −
if (bg != Qt::NoBrush) {+ −
QRectF contentsRect = r;+ −
contentsRect.setWidth(qMax(r.width(), maximumWidth));+ −
fillBackground(&painter, contentsRect, bg);+ −
}+ −
+ −
+ −
QVector<QTextLayout::FormatRange> selections;+ −
int blpos = block.position();+ −
int bllen = block.length();+ −
for (int i = 0; i < context.selections.size(); ++i) {+ −
const QAbstractTextDocumentLayout::Selection &range = context.selections.at(i);+ −
const int selStart = range.cursor.selectionStart() - blpos;+ −
const int selEnd = range.cursor.selectionEnd() - blpos;+ −
if (selStart < bllen && selEnd > 0+ −
&& selEnd > selStart) {+ −
QTextLayout::FormatRange o;+ −
o.start = selStart;+ −
o.length = selEnd - selStart;+ −
o.format = range.format;+ −
selections.append(o);+ −
} else if (!range.cursor.hasSelection() && range.format.hasProperty(QTextFormat::FullWidthSelection)+ −
&& block.contains(range.cursor.position())) {+ −
// for full width selections we don't require an actual selection, just+ −
// a position to specify the line. that's more convenience in usage.+ −
QTextLayout::FormatRange o;+ −
QTextLine l = layout->lineForTextPosition(range.cursor.position() - blpos);+ −
o.start = l.textStart();+ −
o.length = l.textLength();+ −
if (o.start + o.length == bllen - 1)+ −
++o.length; // include newline+ −
o.format = range.format;+ −
selections.append(o);+ −
}+ −
}+ −
+ −
bool drawCursor = (editable+ −
&& context.cursorPosition >= blpos+ −
&& context.cursorPosition < blpos + bllen);+ −
+ −
bool drawCursorAsBlock = drawCursor && overwriteMode() ;+ −
+ −
if (drawCursorAsBlock) {+ −
if (context.cursorPosition == blpos + bllen - 1) {+ −
drawCursorAsBlock = false;+ −
} else {+ −
QTextLayout::FormatRange o;+ −
o.start = context.cursorPosition - blpos;+ −
o.length = 1;+ −
o.format.setForeground(palette().base());+ −
o.format.setBackground(palette().text());+ −
selections.append(o);+ −
}+ −
}+ −
+ −
+ −
layout->draw(&painter, offset, selections, er);+ −
if ((drawCursor && !drawCursorAsBlock)+ −
|| (editable && context.cursorPosition < -1+ −
&& !layout->preeditAreaText().isEmpty())) {+ −
int cpos = context.cursorPosition;+ −
if (cpos < -1)+ −
cpos = layout->preeditAreaPosition() - (cpos + 2);+ −
else+ −
cpos -= blpos;+ −
layout->drawCursor(&painter, offset, cpos, cursorWidth());+ −
}+ −
}+ −
+ −
offset.ry() += r.height();+ −
if (offset.y() > viewportRect.height())+ −
break;+ −
block = block.next();+ −
}+ −
+ −
if (backgroundVisible() && !block.isValid() && offset.y() <= er.bottom()+ −
&& (centerOnScroll() || verticalScrollBar()->maximum() == verticalScrollBar()->minimum())) {+ −
painter.fillRect(QRect(QPoint((int)er.left(), (int)offset.y()), er.bottomRight()), palette().background());+ −
}+ −
}+ −
+ −
+ −
void QPlainTextEditPrivate::updateDefaultTextOption()+ −
{+ −
QTextDocument *doc = control->document();+ −
+ −
QTextOption opt = doc->defaultTextOption();+ −
QTextOption::WrapMode oldWrapMode = opt.wrapMode();+ −
+ −
if (lineWrap == QPlainTextEdit::NoWrap)+ −
opt.setWrapMode(QTextOption::NoWrap);+ −
else+ −
opt.setWrapMode(wordWrap);+ −
+ −
if (opt.wrapMode() != oldWrapMode)+ −
doc->setDefaultTextOption(opt);+ −
}+ −
+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::mousePressEvent(QMouseEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
#ifdef QT_KEYPAD_NAVIGATION+ −
if (QApplication::keypadNavigationEnabled() && !hasEditFocus())+ −
setEditFocus(true);+ −
#endif+ −
d->sendControlEvent(e);+ −
}+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::mouseMoveEvent(QMouseEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->inDrag = false; // paranoia+ −
const QPoint pos = e->pos();+ −
d->sendControlEvent(e);+ −
if (!(e->buttons() & Qt::LeftButton))+ −
return;+ −
QRect visible = d->viewport->rect();+ −
if (visible.contains(pos))+ −
d->autoScrollTimer.stop();+ −
else if (!d->autoScrollTimer.isActive())+ −
d->autoScrollTimer.start(100, this);+ −
}+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::mouseReleaseEvent(QMouseEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->sendControlEvent(e);+ −
if (d->autoScrollTimer.isActive()) {+ −
d->autoScrollTimer.stop();+ −
d->ensureCursorVisible();+ −
}+ −
+ −
if (!isReadOnly() && rect().contains(e->pos()))+ −
d->handleSoftwareInputPanel(e->button(), d->clickCausedFocus);+ −
d->clickCausedFocus = 0;+ −
}+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::mouseDoubleClickEvent(QMouseEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->sendControlEvent(e);+ −
}+ −
+ −
/*! \reimp+ −
*/+ −
bool QPlainTextEdit::focusNextPrevChild(bool next)+ −
{+ −
Q_D(const QPlainTextEdit);+ −
if (!d->tabChangesFocus && d->control->textInteractionFlags() & Qt::TextEditable)+ −
return false;+ −
return QAbstractScrollArea::focusNextPrevChild(next);+ −
}+ −
+ −
#ifndef QT_NO_CONTEXTMENU+ −
/*!+ −
\fn void QPlainTextEdit::contextMenuEvent(QContextMenuEvent *event)+ −
+ −
Shows the standard context menu created with createStandardContextMenu().+ −
+ −
If you do not want the text edit to have a context menu, you can set+ −
its \l contextMenuPolicy to Qt::NoContextMenu. If you want to+ −
customize the context menu, reimplement this function. If you want+ −
to extend the standard context menu, reimplement this function, call+ −
createStandardContextMenu() and extend the menu returned.+ −
+ −
Information about the event is passed in the \a event object.+ −
+ −
\snippet doc/src/snippets/code/src_gui_widgets_qplaintextedit.cpp 0+ −
*/+ −
void QPlainTextEdit::contextMenuEvent(QContextMenuEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->sendControlEvent(e);+ −
}+ −
#endif // QT_NO_CONTEXTMENU+ −
+ −
#ifndef QT_NO_DRAGANDDROP+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::dragEnterEvent(QDragEnterEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->inDrag = true;+ −
d->sendControlEvent(e);+ −
}+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::dragLeaveEvent(QDragLeaveEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->inDrag = false;+ −
d->autoScrollTimer.stop();+ −
d->sendControlEvent(e);+ −
}+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::dragMoveEvent(QDragMoveEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->autoScrollDragPos = e->pos();+ −
if (!d->autoScrollTimer.isActive())+ −
d->autoScrollTimer.start(100, this);+ −
d->sendControlEvent(e);+ −
}+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::dropEvent(QDropEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->inDrag = false;+ −
d->autoScrollTimer.stop();+ −
d->sendControlEvent(e);+ −
}+ −
+ −
#endif // QT_NO_DRAGANDDROP+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::inputMethodEvent(QInputMethodEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
#ifdef QT_KEYPAD_NAVIGATION+ −
if (d->control->textInteractionFlags() & Qt::TextEditable+ −
&& QApplication::keypadNavigationEnabled()+ −
&& !hasEditFocus()) {+ −
setEditFocus(true);+ −
selectAll(); // so text is replaced rather than appended to+ −
}+ −
#endif+ −
d->sendControlEvent(e);+ −
ensureCursorVisible();+ −
}+ −
+ −
/*!\reimp+ −
*/+ −
void QPlainTextEdit::scrollContentsBy(int dx, int /*dy*/)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->setTopLine(d->vbar->value(), dx);+ −
}+ −
+ −
/*!\reimp+ −
*/+ −
QVariant QPlainTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
QVariant v = d->control->inputMethodQuery(property);+ −
const QPoint offset(-d->horizontalOffset(), -0);+ −
if (v.type() == QVariant::RectF)+ −
v = v.toRectF().toRect().translated(offset);+ −
else if (v.type() == QVariant::PointF)+ −
v = v.toPointF().toPoint() + offset;+ −
else if (v.type() == QVariant::Rect)+ −
v = v.toRect().translated(offset);+ −
else if (v.type() == QVariant::Point)+ −
v = v.toPoint() + offset;+ −
return v;+ −
}+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::focusInEvent(QFocusEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
if (e->reason() == Qt::MouseFocusReason) {+ −
d->clickCausedFocus = 1;+ −
}+ −
QAbstractScrollArea::focusInEvent(e);+ −
d->sendControlEvent(e);+ −
}+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::focusOutEvent(QFocusEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
QAbstractScrollArea::focusOutEvent(e);+ −
d->sendControlEvent(e);+ −
}+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::showEvent(QShowEvent *)+ −
{+ −
Q_D(QPlainTextEdit);+ −
if (d->showCursorOnInitialShow) {+ −
d->showCursorOnInitialShow = false;+ −
ensureCursorVisible();+ −
}+ −
}+ −
+ −
/*! \reimp+ −
*/+ −
void QPlainTextEdit::changeEvent(QEvent *e)+ −
{+ −
Q_D(QPlainTextEdit);+ −
QAbstractScrollArea::changeEvent(e);+ −
if (e->type() == QEvent::ApplicationFontChange+ −
|| e->type() == QEvent::FontChange) {+ −
d->control->document()->setDefaultFont(font());+ −
} else if(e->type() == QEvent::ActivationChange) {+ −
if (!isActiveWindow())+ −
d->autoScrollTimer.stop();+ −
} else if (e->type() == QEvent::EnabledChange) {+ −
e->setAccepted(isEnabled());+ −
d->sendControlEvent(e);+ −
} else if (e->type() == QEvent::PaletteChange) {+ −
d->control->setPalette(palette());+ −
} else if (e->type() == QEvent::LayoutDirectionChange) {+ −
d->sendControlEvent(e);+ −
}+ −
}+ −
+ −
/*! \reimp+ −
*/+ −
#ifndef QT_NO_WHEELEVENT+ −
void QPlainTextEdit::wheelEvent(QWheelEvent *e)+ −
{+ −
QAbstractScrollArea::wheelEvent(e);+ −
updateMicroFocus();+ −
}+ −
#endif+ −
+ −
#ifndef QT_NO_CONTEXTMENU+ −
/*! This function creates the standard context menu which is shown+ −
when the user clicks on the line edit with the right mouse+ −
button. It is called from the default contextMenuEvent() handler.+ −
The popup menu's ownership is transferred to the caller.+ −
*/+ −
+ −
QMenu *QPlainTextEdit::createStandardContextMenu()+ −
{+ −
Q_D(QPlainTextEdit);+ −
return d->control->createStandardContextMenu(QPointF(), this);+ −
}+ −
#endif // QT_NO_CONTEXTMENU+ −
+ −
/*!+ −
returns a QTextCursor at position \a pos (in viewport coordinates).+ −
*/+ −
QTextCursor QPlainTextEdit::cursorForPosition(const QPoint &pos) const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->control->cursorForPosition(d->mapToContents(pos));+ −
}+ −
+ −
/*!+ −
returns a rectangle (in viewport coordinates) that includes the+ −
\a cursor.+ −
*/+ −
QRect QPlainTextEdit::cursorRect(const QTextCursor &cursor) const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
if (cursor.isNull())+ −
return QRect();+ −
+ −
QRect r = d->control->cursorRect(cursor).toRect();+ −
r.translate(-d->horizontalOffset(),-d->verticalOffset());+ −
return r;+ −
}+ −
+ −
/*!+ −
returns a rectangle (in viewport coordinates) that includes the+ −
cursor of the text edit.+ −
*/+ −
QRect QPlainTextEdit::cursorRect() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
QRect r = d->control->cursorRect().toRect();+ −
r.translate(-d->horizontalOffset(),-d->verticalOffset());+ −
return r;+ −
}+ −
+ −
+ −
/*!+ −
\property QPlainTextEdit::overwriteMode+ −
\brief whether text entered by the user will overwrite existing text+ −
+ −
As with many text editors, the plain text editor widget can be configured+ −
to insert or overwrite existing text with new text entered by the user.+ −
+ −
If this property is true, existing text is overwritten, character-for-character+ −
by new text; otherwise, text is inserted at the cursor position, displacing+ −
existing text.+ −
+ −
By default, this property is false (new text does not overwrite existing text).+ −
*/+ −
+ −
bool QPlainTextEdit::overwriteMode() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->control->overwriteMode();+ −
}+ −
+ −
void QPlainTextEdit::setOverwriteMode(bool overwrite)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->setOverwriteMode(overwrite);+ −
}+ −
+ −
/*!+ −
\property QPlainTextEdit::tabStopWidth+ −
\brief the tab stop width in pixels+ −
+ −
By default, this property contains a value of 80.+ −
*/+ −
+ −
int QPlainTextEdit::tabStopWidth() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return qRound(d->control->document()->defaultTextOption().tabStop());+ −
}+ −
+ −
void QPlainTextEdit::setTabStopWidth(int width)+ −
{+ −
Q_D(QPlainTextEdit);+ −
QTextOption opt = d->control->document()->defaultTextOption();+ −
if (opt.tabStop() == width || width < 0)+ −
return;+ −
opt.setTabStop(width);+ −
d->control->document()->setDefaultTextOption(opt);+ −
}+ −
+ −
/*!+ −
\property QPlainTextEdit::cursorWidth+ −
+ −
This property specifies the width of the cursor in pixels. The default value is 1.+ −
*/+ −
int QPlainTextEdit::cursorWidth() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->control->cursorWidth();+ −
}+ −
+ −
void QPlainTextEdit::setCursorWidth(int width)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->setCursorWidth(width);+ −
}+ −
+ −
+ −
+ −
/*!+ −
This function allows temporarily marking certain regions in the document+ −
with a given color, specified as \a selections. This can be useful for+ −
example in a programming editor to mark a whole line of text with a given+ −
background color to indicate the existence of a breakpoint.+ −
+ −
\sa QTextEdit::ExtraSelection, extraSelections()+ −
*/+ −
void QPlainTextEdit::setExtraSelections(const QList<QTextEdit::ExtraSelection> &selections)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->setExtraSelections(selections);+ −
}+ −
+ −
/*!+ −
Returns previously set extra selections.+ −
+ −
\sa setExtraSelections()+ −
*/+ −
QList<QTextEdit::ExtraSelection> QPlainTextEdit::extraSelections() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->control->extraSelections();+ −
}+ −
+ −
/*!+ −
This function returns a new MIME data object to represent the contents+ −
of the text edit's current selection. It is called when the selection needs+ −
to be encapsulated into a new QMimeData object; for example, when a drag+ −
and drop operation is started, or when data is copied to the clipboard.+ −
+ −
If you reimplement this function, note that the ownership of the returned+ −
QMimeData object is passed to the caller. The selection can be retrieved+ −
by using the textCursor() function.+ −
*/+ −
QMimeData *QPlainTextEdit::createMimeDataFromSelection() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->control->QTextControl::createMimeDataFromSelection();+ −
}+ −
+ −
/*!+ −
This function returns true if the contents of the MIME data object, specified+ −
by \a source, can be decoded and inserted into the document. It is called+ −
for example when during a drag operation the mouse enters this widget and it+ −
is necessary to determine whether it is possible to accept the drag.+ −
*/+ −
bool QPlainTextEdit::canInsertFromMimeData(const QMimeData *source) const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->control->QTextControl::canInsertFromMimeData(source);+ −
}+ −
+ −
/*!+ −
This function inserts the contents of the MIME data object, specified+ −
by \a source, into the text edit at the current cursor position. It is+ −
called whenever text is inserted as the result of a clipboard paste+ −
operation, or when the text edit accepts data from a drag and drop+ −
operation.+ −
*/+ −
void QPlainTextEdit::insertFromMimeData(const QMimeData *source)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->QTextControl::insertFromMimeData(source);+ −
}+ −
+ −
/*!+ −
\property QPlainTextEdit::readOnly+ −
\brief whether the text edit is read-only+ −
+ −
In a read-only text edit the user can only navigate through the+ −
text and select text; modifying the text is not possible.+ −
+ −
This property's default is false.+ −
*/+ −
+ −
bool QPlainTextEdit::isReadOnly() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return !(d->control->textInteractionFlags() & Qt::TextEditable);+ −
}+ −
+ −
void QPlainTextEdit::setReadOnly(bool ro)+ −
{+ −
Q_D(QPlainTextEdit);+ −
Qt::TextInteractionFlags flags = Qt::NoTextInteraction;+ −
if (ro) {+ −
flags = Qt::TextSelectableByMouse;+ −
} else {+ −
flags = Qt::TextEditorInteraction;+ −
}+ −
setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this));+ −
d->control->setTextInteractionFlags(flags);+ −
}+ −
+ −
/*!+ −
\property QPlainTextEdit::textInteractionFlags+ −
+ −
Specifies how the label should interact with user input if it displays text.+ −
+ −
If the flags contain either Qt::LinksAccessibleByKeyboard or Qt::TextSelectableByKeyboard+ −
then the focus policy is also automatically set to Qt::ClickFocus.+ −
+ −
The default value depends on whether the QPlainTextEdit is read-only+ −
or editable, and whether it is a QTextBrowser or not.+ −
*/+ −
+ −
void QPlainTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->setTextInteractionFlags(flags);+ −
}+ −
+ −
Qt::TextInteractionFlags QPlainTextEdit::textInteractionFlags() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->control->textInteractionFlags();+ −
}+ −
+ −
/*!+ −
Merges the properties specified in \a modifier into the current character+ −
format by calling QTextCursor::mergeCharFormat on the editor's cursor.+ −
If the editor has a selection then the properties of \a modifier are+ −
directly applied to the selection.+ −
+ −
\sa QTextCursor::mergeCharFormat()+ −
*/+ −
void QPlainTextEdit::mergeCurrentCharFormat(const QTextCharFormat &modifier)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->mergeCurrentCharFormat(modifier);+ −
}+ −
+ −
/*!+ −
Sets the char format that is be used when inserting new text to \a+ −
format by calling QTextCursor::setCharFormat() on the editor's+ −
cursor. If the editor has a selection then the char format is+ −
directly applied to the selection.+ −
*/+ −
void QPlainTextEdit::setCurrentCharFormat(const QTextCharFormat &format)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->setCurrentCharFormat(format);+ −
}+ −
+ −
/*!+ −
Returns the char format that is used when inserting new text.+ −
*/+ −
QTextCharFormat QPlainTextEdit::currentCharFormat() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->control->currentCharFormat();+ −
}+ −
+ −
+ −
+ −
/*!+ −
Convenience slot that inserts \a text at the current+ −
cursor position.+ −
+ −
It is equivalent to+ −
+ −
\snippet doc/src/snippets/code/src_gui_widgets_qplaintextedit.cpp 1+ −
*/+ −
void QPlainTextEdit::insertPlainText(const QString &text)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->insertPlainText(text);+ −
}+ −
+ −
+ −
/*!+ −
Moves the cursor by performing the given \a operation.+ −
+ −
If \a mode is QTextCursor::KeepAnchor, the cursor selects the text it moves over.+ −
This is the same effect that the user achieves when they hold down the Shift key+ −
and move the cursor with the cursor keys.+ −
+ −
\sa QTextCursor::movePosition()+ −
*/+ −
void QPlainTextEdit::moveCursor(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->control->moveCursor(operation, mode);+ −
}+ −
+ −
/*!+ −
Returns whether text can be pasted from the clipboard into the textedit.+ −
*/+ −
bool QPlainTextEdit::canPaste() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->control->canPaste();+ −
}+ −
+ −
#ifndef QT_NO_PRINTER+ −
/*!+ −
Convenience function to print the text edit's document to the given \a printer. This+ −
is equivalent to calling the print method on the document directly except that this+ −
function also supports QPrinter::Selection as print range.+ −
+ −
\sa QTextDocument::print()+ −
*/+ −
void QPlainTextEdit::print(QPrinter *printer) const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
d->control->print(printer);+ −
}+ −
#endif // QT _NO_PRINTER+ −
+ −
/*! \property QPlainTextEdit::tabChangesFocus+ −
\brief whether \gui Tab changes focus or is accepted as input+ −
+ −
In some occasions text edits should not allow the user to input+ −
tabulators or change indentation using the \gui Tab key, as this breaks+ −
the focus chain. The default is false.+ −
+ −
*/+ −
+ −
bool QPlainTextEdit::tabChangesFocus() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->tabChangesFocus;+ −
}+ −
+ −
void QPlainTextEdit::setTabChangesFocus(bool b)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->tabChangesFocus = b;+ −
}+ −
+ −
/*!+ −
\property QPlainTextEdit::documentTitle+ −
\brief the title of the document parsed from the text.+ −
+ −
By default, this property contains an empty string.+ −
*/+ −
+ −
/*!+ −
\property QPlainTextEdit::lineWrapMode+ −
\brief the line wrap mode+ −
+ −
The default mode is WidgetWidth which causes words to be+ −
wrapped at the right edge of the text edit. Wrapping occurs at+ −
whitespace, keeping whole words intact. If you want wrapping to+ −
occur within words use setWordWrapMode().+ −
*/+ −
+ −
QPlainTextEdit::LineWrapMode QPlainTextEdit::lineWrapMode() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->lineWrap;+ −
}+ −
+ −
void QPlainTextEdit::setLineWrapMode(LineWrapMode wrap)+ −
{+ −
Q_D(QPlainTextEdit);+ −
if (d->lineWrap == wrap)+ −
return;+ −
d->lineWrap = wrap;+ −
d->updateDefaultTextOption();+ −
d->relayoutDocument();+ −
d->_q_adjustScrollbars();+ −
ensureCursorVisible();+ −
}+ −
+ −
/*!+ −
\property QPlainTextEdit::wordWrapMode+ −
\brief the mode QPlainTextEdit will use when wrapping text by words+ −
+ −
By default, this property is set to QTextOption::WrapAtWordBoundaryOrAnywhere.+ −
+ −
\sa QTextOption::WrapMode+ −
*/+ −
+ −
QTextOption::WrapMode QPlainTextEdit::wordWrapMode() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->wordWrap;+ −
}+ −
+ −
void QPlainTextEdit::setWordWrapMode(QTextOption::WrapMode mode)+ −
{+ −
Q_D(QPlainTextEdit);+ −
if (mode == d->wordWrap)+ −
return;+ −
d->wordWrap = mode;+ −
d->updateDefaultTextOption();+ −
}+ −
+ −
/*!+ −
\property QPlainTextEdit::backgroundVisible+ −
\brief whether the palette background is visible outside the document area+ −
+ −
If set to true, the plain text edit paints the palette background+ −
on the viewport area not covered by the text document. Otherwise,+ −
if set to false, it won't. The feature makes it possible for+ −
the user to visually distinguish between the area of the document,+ −
painted with the base color of the palette, and the empty+ −
area not covered by any document.+ −
+ −
The default is false.+ −
*/+ −
+ −
bool QPlainTextEdit::backgroundVisible() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->backgroundVisible;+ −
}+ −
+ −
void QPlainTextEdit::setBackgroundVisible(bool visible)+ −
{+ −
Q_D(QPlainTextEdit);+ −
if (visible == d->backgroundVisible)+ −
return;+ −
d->backgroundVisible = visible;+ −
d->updateViewport();+ −
}+ −
+ −
/*!+ −
\property QPlainTextEdit::centerOnScroll+ −
\brief whether the cursor should be centered on screen+ −
+ −
If set to true, the plain text edit scrolls the document+ −
vertically to make the cursor visible at the center of the+ −
viewport. This also allows the text edit to scroll below the end+ −
of the document. Otherwise, if set to false, the plain text edit+ −
scrolls the smallest amount possible to ensure the cursor is+ −
visible. The same algorithm is applied to any new line appended+ −
through appendPlainText().+ −
+ −
The default is false.+ −
+ −
\sa centerCursor(), ensureCursorVisible()+ −
*/+ −
+ −
bool QPlainTextEdit::centerOnScroll() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->centerOnScroll;+ −
}+ −
+ −
void QPlainTextEdit::setCenterOnScroll(bool enabled)+ −
{+ −
Q_D(QPlainTextEdit);+ −
if (enabled == d->centerOnScroll)+ −
return;+ −
d->centerOnScroll = enabled;+ −
}+ −
+ −
+ −
+ −
/*!+ −
Finds the next occurrence of the string, \a exp, using the given+ −
\a options. Returns true if \a exp was found and changes the+ −
cursor to select the match; otherwise returns false.+ −
*/+ −
bool QPlainTextEdit::find(const QString &exp, QTextDocument::FindFlags options)+ −
{+ −
Q_D(QPlainTextEdit);+ −
return d->control->find(exp, options);+ −
}+ −
+ −
/*!+ −
\fn void QPlainTextEdit::copyAvailable(bool yes)+ −
+ −
This signal is emitted when text is selected or de-selected in the+ −
text edit.+ −
+ −
When text is selected this signal will be emitted with \a yes set+ −
to true. If no text has been selected or if the selected text is+ −
de-selected this signal is emitted with \a yes set to false.+ −
+ −
If \a yes is true then copy() can be used to copy the selection to+ −
the clipboard. If \a yes is false then copy() does nothing.+ −
+ −
\sa selectionChanged()+ −
*/+ −
+ −
+ −
/*!+ −
\fn void QPlainTextEdit::selectionChanged()+ −
+ −
This signal is emitted whenever the selection changes.+ −
+ −
\sa copyAvailable()+ −
*/+ −
+ −
/*!+ −
\fn void QPlainTextEdit::cursorPositionChanged()+ −
+ −
This signal is emitted whenever the position of the+ −
cursor changed.+ −
*/+ −
+ −
+ −
+ −
/*!+ −
\fn void QPlainTextEdit::updateRequest(const QRect &rect, int dy)+ −
+ −
This signal is emitted when the text document needs an update of+ −
the specified \a rect. If the text is scrolled, \a rect will cover+ −
the entire viewport area. If the text is scrolled vertically, \a+ −
dy carries the amount of pixels the viewport was scrolled.+ −
+ −
The purpose of the signal is to support extra widgets in plain+ −
text edit subclasses that e.g. show line numbers, breakpoints, or+ −
other extra information.+ −
*/+ −
+ −
/*! \fn void QPlainTextEdit::blockCountChanged(int newBlockCount);+ −
+ −
This signal is emitted whenever the block count changes. The new+ −
block count is passed in \a newBlockCount.+ −
*/+ −
+ −
/*! \fn void QPlainTextEdit::modificationChanged(bool changed);+ −
+ −
This signal is emitted whenever the content of the document+ −
changes in a way that affects the modification state. If \a+ −
changed is true, the document has been modified; otherwise it is+ −
false.+ −
+ −
For example, calling setModified(false) on a document and then+ −
inserting text causes the signal to get emitted. If you undo that+ −
operation, causing the document to return to its original+ −
unmodified state, the signal will get emitted again.+ −
*/+ −
+ −
+ −
+ −
+ −
void QPlainTextEditPrivate::append(const QString &text, Qt::TextFormat format)+ −
{+ −
Q_Q(QPlainTextEdit);+ −
+ −
QTextDocument *document = control->document();+ −
QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document->documentLayout());+ −
Q_ASSERT(documentLayout);+ −
+ −
int maximumBlockCount = document->maximumBlockCount();+ −
if (maximumBlockCount)+ −
document->setMaximumBlockCount(0);+ −
+ −
const bool atBottom = q->isVisible()+ −
&& (control->blockBoundingRect(document->lastBlock()).bottom() - verticalOffset()+ −
<= viewport->rect().bottom());+ −
+ −
if (!q->isVisible())+ −
showCursorOnInitialShow = true;+ −
+ −
bool documentSizeChangedBlocked = documentLayout->priv()->blockDocumentSizeChanged;+ −
documentLayout->priv()->blockDocumentSizeChanged = true;+ −
+ −
if (format == Qt::RichText)+ −
control->appendHtml(text);+ −
else if (format == Qt::PlainText)+ −
control->appendPlainText(text);+ −
else+ −
control->append(text);+ −
+ −
if (maximumBlockCount > 0) {+ −
if (document->blockCount() > maximumBlockCount) {+ −
bool blockUpdate = false;+ −
if (control->topBlock) {+ −
control->topBlock--;+ −
blockUpdate = true;+ −
emit q->updateRequest(viewport->rect(), 0);+ −
}+ −
+ −
bool updatesBlocked = documentLayout->priv()->blockUpdate;+ −
documentLayout->priv()->blockUpdate = blockUpdate;+ −
QTextCursor cursor(document);+ −
cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor);+ −
cursor.removeSelectedText();+ −
documentLayout->priv()->blockUpdate = updatesBlocked;+ −
}+ −
document->setMaximumBlockCount(maximumBlockCount);+ −
}+ −
+ −
documentLayout->priv()->blockDocumentSizeChanged = documentSizeChangedBlocked;+ −
_q_adjustScrollbars();+ −
+ −
+ −
if (atBottom) {+ −
const bool needScroll = !centerOnScroll+ −
|| control->blockBoundingRect(document->lastBlock()).bottom() - verticalOffset()+ −
> viewport->rect().bottom();+ −
if (needScroll)+ −
vbar->setValue(vbar->maximum());+ −
}+ −
}+ −
+ −
+ −
/*!+ −
Appends a new paragraph with \a text to the end of the text edit.+ −
+ −
\sa appendHtml()+ −
*/+ −
+ −
void QPlainTextEdit::appendPlainText(const QString &text)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->append(text, Qt::PlainText);+ −
}+ −
+ −
/*!+ −
Appends a new paragraph with \a html to the end of the text edit.+ −
+ −
appendPlainText()+ −
*/+ −
+ −
void QPlainTextEdit::appendHtml(const QString &html)+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->append(html, Qt::RichText);+ −
}+ −
+ −
void QPlainTextEditPrivate::ensureCursorVisible(bool center)+ −
{+ −
Q_Q(QPlainTextEdit);+ −
QRect visible = viewport->rect();+ −
QRect cr = q->cursorRect();+ −
if (cr.top() < visible.top() || cr.bottom() > visible.bottom()) {+ −
ensureVisible(control->textCursor().position(), center);+ −
}+ −
+ −
const bool rtl = q->isRightToLeft();+ −
if (cr.left() < visible.left() || cr.right() > visible.right()) {+ −
int x = cr.center().x() + horizontalOffset() - visible.width()/2;+ −
hbar->setValue(rtl ? hbar->maximum() - x : x);+ −
}+ −
}+ −
+ −
/*!+ −
Ensures that the cursor is visible by scrolling the text edit if+ −
necessary.+ −
+ −
\sa centerCursor(), centerOnScroll+ −
*/+ −
void QPlainTextEdit::ensureCursorVisible()+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->ensureCursorVisible(d->centerOnScroll);+ −
}+ −
+ −
+ −
/*! Scrolls the document in order to center the cursor vertically.+ −
+ −
\sa ensureCursorVisible(), centerOnScroll+ −
*/+ −
void QPlainTextEdit::centerCursor()+ −
{+ −
Q_D(QPlainTextEdit);+ −
d->ensureVisible(textCursor().position(), true, true);+ −
}+ −
+ −
/*!+ −
Returns the first visible block.+ −
+ −
\sa blockBoundingRect()+ −
*/+ −
QTextBlock QPlainTextEdit::firstVisibleBlock() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->control->firstVisibleBlock();+ −
}+ −
+ −
/*! Returns the content's origin in viewport coordinates.+ −
+ −
The origin of the content of a plain text edit is always the top+ −
left corner of the first visible text block. The content offset+ −
is different from (0,0) when the text has been scrolled+ −
horizontally, or when the first visible block has been scrolled+ −
partially off the screen, i.e. the visible text does not start+ −
with the first line of the first visible block, or when the first+ −
visible block is the very first block and the editor displays a+ −
margin.+ −
+ −
\sa firstVisibleBlock(), horizontalScrollBar(), verticalScrollBar()+ −
*/+ −
QPointF QPlainTextEdit::contentOffset() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return QPointF(-d->horizontalOffset(), -d->verticalOffset());+ −
}+ −
+ −
+ −
/*! Returns the bounding rectangle of the text \a block in content+ −
coordinates. Translate the rectangle with the contentOffset() to get+ −
visual coordinates on the viewport.+ −
+ −
\sa firstVisibleBlock(), blockBoundingRect()+ −
*/+ −
QRectF QPlainTextEdit::blockBoundingGeometry(const QTextBlock &block) const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->control->blockBoundingRect(block);+ −
}+ −
+ −
/*!+ −
Returns the bounding rectangle of the text \a block in the block's own coordinates.+ −
+ −
\sa blockBoundingGeometry()+ −
*/+ −
QRectF QPlainTextEdit::blockBoundingRect(const QTextBlock &block) const+ −
{+ −
QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(document()->documentLayout());+ −
Q_ASSERT(documentLayout);+ −
return documentLayout->blockBoundingRect(block);+ −
}+ −
+ −
/*!+ −
\property QPlainTextEdit::blockCount+ −
\brief the number of text blocks in the document.+ −
+ −
By default, in an empty document, this property contains a value of 1.+ −
*/+ −
int QPlainTextEdit::blockCount() const+ −
{+ −
return document()->blockCount();+ −
}+ −
+ −
/*! Returns the paint context for the viewport(), useful only when+ −
reimplementing paintEvent().+ −
*/+ −
QAbstractTextDocumentLayout::PaintContext QPlainTextEdit::getPaintContext() const+ −
{+ −
Q_D(const QPlainTextEdit);+ −
return d->control->getPaintContext(d->viewport);+ −
}+ −
+ −
/*!+ −
\property QPlainTextEdit::maximumBlockCount+ −
\brief the limit for blocks in the document.+ −
+ −
Specifies the maximum number of blocks the document may have. If there are+ −
more blocks in the document that specified with this property blocks are removed+ −
from the beginning of the document.+ −
+ −
A negative or zero value specifies that the document may contain an unlimited+ −
amount of blocks.+ −
+ −
The default value is 0.+ −
+ −
Note that setting this property will apply the limit immediately to the document+ −
contents. Setting this property also disables the undo redo history.+ −
+ −
*/+ −
+ −
+ −
/*!+ −
\fn void QPlainTextEdit::textChanged()+ −
+ −
This signal is emitted whenever the document's content changes; for+ −
example, when text is inserted or deleted, or when formatting is applied.+ −
*/+ −
+ −
/*!+ −
\fn void QPlainTextEdit::undoAvailable(bool available)+ −
+ −
This signal is emitted whenever undo operations become available+ −
(\a available is true) or unavailable (\a available is false).+ −
*/+ −
+ −
/*!+ −
\fn void QPlainTextEdit::redoAvailable(bool available)+ −
+ −
This signal is emitted whenever redo operations become available+ −
(\a available is true) or unavailable (\a available is false).+ −
*/+ −
+ −
QT_END_NAMESPACE+ −
+ −
#include "moc_qplaintextedit.cpp"+ −
#include "moc_qplaintextedit_p.cpp"+ −
+ −
#endif // QT_NO_TEXTEDIT+ −