diff options
Diffstat (limited to 'src/gui/widgets/qplaintextedit.cpp')
-rw-r--r-- | src/gui/widgets/qplaintextedit.cpp | 2998 |
1 files changed, 0 insertions, 2998 deletions
diff --git a/src/gui/widgets/qplaintextedit.cpp b/src/gui/widgets/qplaintextedit.cpp deleted file mode 100644 index f2fca8fbdf..0000000000 --- a/src/gui/widgets/qplaintextedit.cpp +++ /dev/null @@ -1,2998 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 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$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $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); - Q_UNUSED(r); - 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; - - bool vbarSignalsBlocked = vbar->blockSignals(true); - vbar->setValue(block.firstLineNumber() + lineNumber); - vbar->blockSignals(vbarSignalsBlocked); - - 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) { - cursor.setVisualNavigation(true); - // 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 qreal visible = viewport->rect().height() - margin - 1; - qreal y = 0; - int visibleFromBottom = 0; - - while (block.isValid()) { - if (!block.isVisible()) { - block = block.previous(); - continue; - } - y += 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 (lr.top() >= y - visible) - break; - ++lineNumber; - } - if (lineNumber < layoutLineCount) - visibleFromBottom += (layoutLineCount - lineNumber); - 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(); -} - -/*! - Returns the reference of the anchor at position \a pos, or an - empty string if no anchor exists at that point. - - \since 4.7 - */ -QString QPlainTextEdit::anchorAt(const QPoint &pos) const -{ - Q_D(const QPlainTextEdit); - int cursorPos = d->control->hitTest(pos + QPoint(d->horizontalOffset(), - d->verticalOffset()), - Qt::ExactHit); - if (cursorPos < 0) - return QString(); - - QTextDocumentPrivate *pieceTable = document()->docHandle(); - QTextDocumentPrivate::FragmentIterator it = pieceTable->find(cursorPos); - QTextCharFormat fmt = pieceTable->formatCollection()->charFormat(it->format); - return fmt.anchorHref(); -} - -/*! - 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 -#ifndef QT_NO_GESTURES - 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; - } -#endif // QT_NO_GESTURES - 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. -*/ - -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 |