Example #1
0
static void calculateBoundingRect( QTextDocument *document, int startPosition, int endPosition,
                                   QRectF &rect )
{
    const QTextBlock startBlock = document->findBlock( startPosition );
    const QRectF startBoundingRect = document->documentLayout()->blockBoundingRect( startBlock );

    const QTextBlock endBlock = document->findBlock( endPosition );
    const QRectF endBoundingRect = document->documentLayout()->blockBoundingRect( endBlock );

    QTextLayout *startLayout = startBlock.layout();
    QTextLayout *endLayout = endBlock.layout();

    int startPos = startPosition - startBlock.position();
    int endPos = endPosition - endBlock.position();
    const QTextLine startLine = startLayout->lineForTextPosition( startPos );
    const QTextLine endLine = endLayout->lineForTextPosition( endPos );

    double x = startBoundingRect.x() + startLine.cursorToX( startPos );
    double y = startBoundingRect.y() + startLine.y();
    double r = endBoundingRect.x() + endLine.cursorToX( endPos );
    double b = endBoundingRect.y() + endLine.y() + endLine.height();

    const QSizeF size = document->size();
    rect = QRectF( x / size.width(), y / size.height(),
                   (r - x) / size.width(), (b - y) / size.height() );
}
Example #2
0
void MainWindow::UpdateStatusBar()
{
    int col = m_ui->txtedit->textCursor().positionInBlock();
    QTextLayout * pLayout = m_ui->txtedit->textCursor().block().layout();
    int nCurpos = m_ui->txtedit->textCursor().position() - m_ui->txtedit->textCursor().block().position();
    int line = pLayout->lineForTextPosition(nCurpos).lineNumber() + m_ui->txtedit->textCursor().block().firstLineNumber() + 1;

    QString title = "fake ide ";
    title += QFileInfo(m_file_name).fileName();
    if (m_saved != m_ui->txtedit->toPlainText())
    {
        title += " *";
    }
    setWindowTitle(title);

    char buff[1024];
    sprintf(buff, "line %d, col %d, total %d", line, col, m_ui->txtedit->toPlainText().size());
    QString msg = buff;
    m_ui->statusBar->showMessage(msg);
}
void History::on_plainTextEdit_cursorPositionChanged()
{
    if(!plainTextEdit->toPlainText().isEmpty())
    {
        QList<QTextEdit::ExtraSelection> extraSelections;
        QTextEdit::ExtraSelection selection;

        QColor lineColor = QColor(0,0,170).lighter(160);

        selection.format.setBackground(lineColor);
        selection.format.setProperty(QTextFormat::FullWidthSelection, true);
        selection.cursor =plainTextEdit->textCursor();
        selection.cursor.clearSelection();
        extraSelections.append(selection);

        //暂时标记指定的文档中的一部分,用指定的颜色
        plainTextEdit->setExtraSelections(extraSelections);

        usePushButton->setEnabled(true);
        deletePushButton->setEnabled(true);
        copyPushButton->setEnabled(true);
        clearPushButton->setEnabled(true);

        //获取光标所在行数
        QTextCursor tc = plainTextEdit->textCursor();
        QTextLayout* lo = tc.block().layout();
        int pos = tc.positionInBlock();
        int rowIndex = lo->lineForTextPosition(pos).lineNumber() + tc.block().firstLineNumber();

        lineEdit->setText(plainTextEdit->document()->findBlockByLineNumber(rowIndex).text());
        //plainTextEdit->document()->findBlockByLineNumber(rowIndex).text() 获取指定行的内容
    }
    else
    {
        usePushButton->setEnabled(false);
        deletePushButton->setEnabled(false);
        copyPushButton->setEnabled(false);
        clearPushButton->setEnabled(false);
        lineEdit->clear();
    }
}
Example #4
0
void TestDocumentLayout::placeAnchoredFrame2()
{
    QFETCH(int, horizontalAlignment);
    QFETCH(int, verticalAlignment);
    QFETCH(QPointF, startPosition);
    QFETCH(QPointF, imagePosition);

    initForNewTest(QString(loremIpsum));
    MockShape *picture = new MockShape();
    picture->setSize(QSizeF(198, 400));
    KTextAnchor *anchor = new KTextAnchor(picture);
    anchor->setAlignment(KTextAnchor::AnchorHorizontal(horizontalAlignment));
    anchor->setAlignment(KTextAnchor::AnchorVertical(verticalAlignment));
    picture->setPosition(startPosition);
    QTextCursor cursor(doc);

    KInlineTextObjectManager *manager = new KInlineTextObjectManager();
    layout->setInlineTextObjectManager(manager);
    MockLayoutState *state = new MockLayoutState(doc);
    layout->setLayout(state);
    state->shape = shape1;
    manager->insertInlineObject(cursor, anchor);
    QCOMPARE(cursor.position(), 1);
    layout->layout();

    QCOMPARE(picture->parent(), shape1);
    QCOMPARE(picture->position(), imagePosition);

    // test if rest of text is below picture.
    QTextLayout *lay = doc->begin().layout();
    QVERIFY(lay->lineCount() >= 1);
    QTextLine line = lay->lineForTextPosition(1); // the first char of real text.
    QVERIFY(line.isValid());
    // qDebug() << line.y() << line.height();
    QVERIFY(line.y() + line.height() >= 412); // test that text is below image
}
QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, const QTextCursor &end,
                                                    const QRect &clip)
{
    if (begin.isNull() || end.isNull() || begin.position() > end.position())
        return QPainterPath();

    QPointF offset = m_editor->contentOffset();
    QRect viewportRect = rect();
    QTextDocument *document = m_editor->document();

    if (m_editor->blockBoundingGeometry(begin.block()).translated(offset).top() > clip.bottom() + 10
        || m_editor->blockBoundingGeometry(end.block()).translated(offset).bottom() < clip.top() - 10
        )
        return QPainterPath(); // nothing of the selection is visible


    QTextBlock block = begin.block();

    if (block.blockNumber() < m_editor->firstVisibleBlock().blockNumber() - 4)
        block = m_editor->document()->findBlockByNumber(m_editor->firstVisibleBlock().blockNumber() - 4);

    bool inSelection = false;

    QVector<QRectF> selection;

    if (begin.position() == end.position()) {
        // special case empty selections
        const QRectF blockGeometry = m_editor->blockBoundingGeometry(block);
        QTextLayout *blockLayout = block.layout();
        int pos = begin.position() - begin.block().position();
        QTextLine line = blockLayout->lineForTextPosition(pos);
        QRectF lineRect = line.naturalTextRect();
        int x = line.cursorToX(pos);
        lineRect.setLeft(x - m_borderWidth);
        lineRect.setRight(x + m_borderWidth);
        selection += lineRect.translated(blockGeometry.topLeft());
    } else {
        for (; block.isValid() && block.blockNumber() <= end.blockNumber(); block = block.next()) {
            if (! block.isVisible())
                continue;

            const QRectF blockGeometry = m_editor->blockBoundingGeometry(block);
            QTextLayout *blockLayout = block.layout();

            QTextLine line = blockLayout->lineAt(0);
            bool firstOrLastBlock = false;

            int beginChar = 0;
            if (!inSelection) {
                if (block == begin.block()) {
                    beginChar = begin.positionInBlock();
                    line = blockLayout->lineForTextPosition(beginChar);
                    firstOrLastBlock = true;
                }
                inSelection = true;
            } else {
//                while (beginChar < block.length() && document->characterAt(block.position() + beginChar).isSpace())
//                    ++beginChar;
//                if (beginChar == block.length())
//                    beginChar = 0;
            }

            int lastLine = blockLayout->lineCount()-1;
            int endChar = -1;
            if (block == end.block()) {
                endChar = end.positionInBlock();
                lastLine = blockLayout->lineForTextPosition(endChar).lineNumber();
                inSelection = false;
                firstOrLastBlock = true;
            } else {
                endChar = block.length();
                while (endChar > beginChar && document->characterAt(block.position() + endChar - 1).isSpace())
                    --endChar;
            }

            QRectF lineRect = line.naturalTextRect();
            if (beginChar < endChar) {
                lineRect.setLeft(line.cursorToX(beginChar));
                if (line.lineNumber() == lastLine)
                    lineRect.setRight(line.cursorToX(endChar));
                selection += lineRect.translated(blockGeometry.topLeft());

                for (int lineIndex = line.lineNumber()+1; lineIndex <= lastLine; ++lineIndex) {
                    line = blockLayout->lineAt(lineIndex);
                    lineRect = line.naturalTextRect();
                    if (lineIndex == lastLine)
                        lineRect.setRight(line.cursorToX(endChar));
                    selection += lineRect.translated(blockGeometry.topLeft());
                }
            } else { // empty lines
                const int emptyLineSelectionSize = 16;
                if (!firstOrLastBlock && !selection.isEmpty()) { // middle
                    lineRect.setLeft(selection.last().left());
                } else if (inSelection) { // first line
                    lineRect.setLeft(line.cursorToX(beginChar));
                } else { // last line
                    if (endChar == 0)
                        break;
                    lineRect.setLeft(line.cursorToX(endChar) - emptyLineSelectionSize);
                }
                lineRect.setRight(lineRect.left() + emptyLineSelectionSize);
                selection += lineRect.translated(blockGeometry.topLeft());
            }

            if (!inSelection)
                break;

            if (blockGeometry.translated(offset).y() > 2*viewportRect.height())
                break;
        }
    }


    if (selection.isEmpty())
        return QPainterPath();

    QVector<QPointF> points;

    const int margin = m_borderWidth/2;
    const int extra = 0;

    const QRectF &firstSelection = selection.at(0);
    points += (firstSelection.topLeft() + firstSelection.topRight()) / 2 + QPointF(0, -margin);
    points += firstSelection.topRight() + QPointF(margin+1, -margin);
    points += firstSelection.bottomRight() + QPointF(margin+1, 0);

    const int count = selection.count();
    for (int i = 1; i < count-1; ++i) {
#define MAX3(a,b,c) qMax(a, qMax(b,c))
        qreal x = MAX3(selection.at(i-1).right(),
                       selection.at(i).right(),
                       selection.at(i+1).right()) + margin;

        points += QPointF(x+1, selection.at(i).top());
        points += QPointF(x+1, selection.at(i).bottom());
    }

    const QRectF &lastSelection = selection.at(count-1);
    points += lastSelection.topRight() + QPointF(margin+1, 0);
    points += lastSelection.bottomRight() + QPointF(margin+1, margin+extra);
    points += lastSelection.bottomLeft() + QPointF(-margin, margin+extra);
    points += lastSelection.topLeft() + QPointF(-margin, 0);

    for (int i = count-2; i > 0; --i) {
#define MIN3(a,b,c) qMin(a, qMin(b,c))
        qreal x = MIN3(selection.at(i-1).left(),
                       selection.at(i).left(),
                       selection.at(i+1).left()) - margin;

        points += QPointF(x, selection.at(i).bottom()+extra);
        points += QPointF(x, selection.at(i).top());
    }

    points += firstSelection.bottomLeft() + QPointF(-margin, extra);
    points += firstSelection.topLeft() + QPointF(-margin, -margin);


    QPainterPath path;
    const int corner = 4;
    path.moveTo(points.at(0));
    points += points.at(0);
    QPointF previous = points.at(0);
    for (int i = 1; i < points.size(); ++i) {
        QPointF point = points.at(i);
        if (point.y() == previous.y() && qAbs(point.x() - previous.x()) > 2*corner) {
            QPointF tmp = QPointF(previous.x() + corner * ((point.x() > previous.x())?1:-1), previous.y());
            path.quadTo(previous, tmp);
            previous = tmp;
            i--;
            continue;
        } else if (point.x() == previous.x() && qAbs(point.y() - previous.y()) > 2*corner) {
            QPointF tmp = QPointF(previous.x(), previous.y() + corner * ((point.y() > previous.y())?1:-1));
            path.quadTo(previous, tmp);
            previous = tmp;
            i--;
            continue;
        }


        QPointF target = (previous + point) / 2;
        path.quadTo(previous, target);
        previous = points.at(i);
    }
    path.closeSubpath();
    path.translate(offset);
    return path;
}
Example #6
0
void KoTextShapeContainerModel::proposeMove(KoShape *child, QPointF &move)
{
    Relation *relation = d->children.value(child);
    if (relation == 0 || relation->anchor == 0)
        return;

    QPointF newPosition = child->position() + move;
    QRectF parentShapeRect(QPointF(0, 0), child->parent()->size());
//kDebug(32500) <<"proposeMove:" << move <<" |" << newPosition <<" |" << parentShapeRect;

    if (qAbs(newPosition.x()) < 10) // align left
        relation->anchor->setAlignment(KoTextAnchor::Left);
    else if (qAbs(parentShapeRect.width() - newPosition.x()) < 10.0)
        relation->anchor->setAlignment(KoTextAnchor::Right);
    else if (qAbs(parentShapeRect.width() / 2.0 - newPosition.x()) < 10.0)
        relation->anchor->setAlignment(KoTextAnchor::Center);
    /*else {
        relation->anchor->setAlignment(KoTextAnchor::HorizontalOffset);
        // TODO
        //QPointF offset = relation->anchor->offset();
        //offset.setX(offset.x() + move.x());
        //relation->anchor->setOffset(offset);
    } */

    if (qAbs(newPosition.y()) < 10.0) // TopOfFrame
    {
        kDebug(32500) <<"  TopOfFrame";
        relation->anchor->setAlignment(KoTextAnchor::TopOfFrame);
    } else if (qAbs(parentShapeRect.height() - newPosition.y()) < 10.0) {
        kDebug(32500) <<"  BottomOfFrame";
        relation->anchor->setAlignment(KoTextAnchor::BottomOfFrame); // TODO
    } else { // need layout info..
        QTextBlock block = relation->anchor->document()->findBlock(relation->anchor->positionInDocument());
        QTextLayout *layout = block.layout();
        if (layout->lineCount() > 0) {
            KoTextShapeData *data = dynamic_cast<KoTextShapeData*>(child->parent()->userData());
            Q_ASSERT(data);
            QTextLine tl = layout->lineAt(0);
            qreal y = tl.y() - data->documentOffset() - newPosition.y();
            if (y >= 0 && y < 10) {
                kDebug(32500) <<"  TopOfParagraph" << y <<"";
                relation->anchor->setAlignment(KoTextAnchor::TopOfParagraph);
            } else {
                tl = layout->lineAt(layout->lineCount() - 1);
                y = newPosition.y() - tl.y() - data->documentOffset() - tl.ascent();
                if (y >= 0 && y < 10) {
                    kDebug(32500) <<"  BottomOfParagraph" << y;
                    relation->anchor->setAlignment(KoTextAnchor::BottomOfParagraph); // TODO
                } else {
                    tl = layout->lineForTextPosition(relation->anchor->positionInDocument() - block.position());
                    y = tl.y() - data->documentOffset() - newPosition.y();
                    if (y >= 0 && y < 10) {
                        kDebug(32500) <<"  AboveCurrentLine";
                        relation->anchor->setAlignment(KoTextAnchor::AboveCurrentLine);
                    }
                    //else  do VerticalOffset here as well?
                }
            }
        }
    }

    move.setX(0); // let the text layout move it.
    move.setY(0);
}
Example #7
0
void BaseEditor::paintEvent(QPaintEvent *e)
{
    //copy from QPlainTextEditor
    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();

    //margin
    qreal lineX = 0;
    if (conf->isDisplayRightColumnMargin()) {
        // Don't use QFontMetricsF::averageCharWidth here, due to it returning
        // a fractional size even when this is not supported by the platform.
        lineX = QFontMetricsF(document()->defaultFont()).width(QLatin1Char('X')) * conf->getRightMarginColumn() + offset.x() + 4;

        if (lineX < viewportRect.width()) {
            const QBrush background = QBrush(QColor(239, 239, 239));
            painter.fillRect(QRectF(lineX, er.top(), viewportRect.width() - lineX, er.height()),
                             background);

            const QColor col = (palette().base().color().value() > 128) ? Qt::black : Qt::white;
            const QPen pen = painter.pen();
            painter.setPen(blendColors(background.isOpaque() ? background.color() : palette().base().color(),
                                       col, 32));
            painter.drawLine(QPointF(lineX, er.top()), QPointF(lineX, er.bottom()));
            painter.setPen(pen);
        }
    }

    // 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 || (textInteractionFlags() & Qt::TextSelectableByKeyboard))
                               && 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());
    }
}