int KTextDocumentLayout::hitTestIterated(QTextFrame::iterator begin, QTextFrame::iterator end, const QPointF &point, Qt::HitTestAccuracy accuracy) const { int position = -1; QTextFrame::iterator it = begin; for (it = begin; it != end; ++it) { QTextBlock block = it.currentBlock(); QTextTable *table = qobject_cast<QTextTable*>(it.currentFrame()); QTextFrame *subFrame = it.currentFrame(); if (table) { QTextTableCell cell = m_state->hitTestTable(table, point); if (cell.isValid()) { position = hitTestIterated(cell.begin(), cell.end(), point, accuracy); if (position == -1) position = cell.lastPosition(); return position; } continue; } else if (subFrame) { position = hitTestIterated(subFrame->begin(), subFrame->end(), point, accuracy); if (position != -1) return position; continue; } else { if (!block.isValid()) continue; } // kDebug(32500) <<"hitTest[" << point.x() <<"," << point.y() <<"]"; QTextLayout *layout = block.layout(); if (point.y() > layout->boundingRect().bottom()) { // just skip this block. position = block.position() + block.length() - 1; continue; } for (int i = 0; i < layout->lineCount(); i++) { QTextLine line = layout->lineAt(i); // kDebug(32500) <<" + line[" << line.textStart() <<"]:" << line.y() <<"-" << line.height(); if (point.y() > line.y() + line.height()) { position = line.textStart() + line.textLength(); continue; } if (accuracy == Qt::ExactHit && point.y() < line.y()) // between lines return -1; if (accuracy == Qt::ExactHit && // left or right of line (point.x() < line.x() || point.x() > line.x() + line.width())) return -1; if (point.x() > line.width() && layout->textOption().textDirection() == Qt::RightToLeft) { // totally right of RTL text means the position is the start of the text. return block.position() + line.textStart(); } return block.position() + line.xToCursor(point.x()); } } return -1; }
void TestDocumentLayout::testRightToLeftList() { initForNewTest("a\nb\nc"); KoParagraphStyle h1; h1.setTextProgressionDirection(KoText::RightLeftTopBottom); m_styleManager->add(&h1); KoListStyle listStyle; KoListLevelProperties llp = listStyle.levelProperties(1); llp.setStyle(KoListStyle::DecimalItem); listStyle.setLevelProperties(llp); h1.setListStyle(&listStyle); QTextBlock block = m_doc->begin(); h1.applyStyle(block); block = block.next(); h1.applyStyle(block); block = block.next(); h1.applyStyle(block); block = block.next(); m_layout->layout(); block = m_doc->begin(); while (block.isValid()) { KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData()); QVERIFY(data); QVERIFY(data->counterWidth() > 2); QVERIFY(data->counterPosition().x() > 100); QTextLine line = block.layout()->lineAt(0); QVERIFY(line.isValid()); QCOMPARE(line.x(), (qreal)0); QCOMPARE(line.width() + data->counterWidth() + data->counterSpacing(), (qreal)200); block = block.next(); } }
QRect StyleHelper::drawText(QPainter* p, const QRect& rc, QString& str, int nLines, int nFlags, const QColor& color, const QFont& font, bool bElided) { if (str.isEmpty()) { qDebug() << "[WARNING]: the text should not be empty when drawing!"; return QRect(); } QFontMetrics fm(font); if (rc.height() < (fm.height() + fm.leading()) * nLines) { qDebug() << "[WARNING]: space is not enough for drawing! text: " << str.left(30) << "..."; } //if (rc.width() * nLines < fm.width(str)) { // qDebug() << "[WARNING]: width should bigger than font metrics when drawing! text:" << str.left(30) << "..."; //} p->save(); p->setPen(color); p->setFont(font); int nWidth = 0; int nHeight = 0; int nHeightLine = p->fontMetrics().height() + leading(); QRect rcRet(rc.x(), rc.y(), rc.width(), nHeightLine); rcRet.adjust(margin(), 0, -margin(), 0); QTextLayout textLayout(str, p->font()); QTextOption opt = textLayout.textOption(); opt.setWrapMode(QTextOption::WrapAnywhere); textLayout.setTextOption(opt); textLayout.beginLayout(); while (nLines) { QTextLine line = textLayout.createLine(); if (!line.isValid()) { break; } line.setLineWidth(rcRet.width()); QString lineText; if (nLines == 1 && bElided) { // the last line lineText = p->fontMetrics().elidedText(str, Qt::ElideRight, rcRet.width()); nWidth = qMax<int>(p->fontMetrics().width(lineText), nWidth); } else { lineText = str.left(line.textLength()); nWidth = qMax<int>(line.width(), nWidth); } str.remove(0, line.textLength()); p->drawText(rcRet, nFlags, lineText); nHeight += nHeightLine; rcRet.setRect(rc.x(), rc.y() + nHeight, nWidth, nHeightLine); rcRet.adjust(margin(), 0, -margin(), 0); nLines--; } textLayout.endLayout(); rcRet.setRect(rc.x() + margin(), rc.y(), nWidth + margin(), nHeight); //rcRet.adjust(margin(), 0, -margin(), 0); p->restore(); return rcRet; }
void TestTableLayout::testBasicLayout() { QList<KoTableColumnStyle *> columnStyles; QList<KoTableRowStyle *> rowStyles; QMap<QPair<int, int>, KoTableCellStyle *> cellStyles; QMap<QPair<int, int>, QString> cellTexts; cellTexts.insert(qMakePair(0, 0), "Cell 1"); cellTexts.insert(qMakePair(0, 1), "Cell 2"); cellTexts.insert(qMakePair(1, 0), "Cell 3"); cellTexts.insert(qMakePair(1, 1), "Cell 4"); initTest(2, 2, 0, columnStyles, rowStyles, cellStyles, cellTexts); m_layout->layout(); // Check that the table and layout data was correctly added to the table data map. QVERIFY(m_textLayout->m_tableLayout.m_tableLayoutDataMap.contains(m_table)); TableLayoutData *tableLayoutData = m_textLayout->m_tableLayout.m_tableLayoutDataMap.value(m_table); QVERIFY(tableLayoutData); // Check table dimensions are correct. QCOMPARE(tableLayoutData->m_rowPositions.size(), 2); QCOMPARE(tableLayoutData->m_rowHeights.size(), 2); QCOMPARE(tableLayoutData->m_tableRects.last().columnPositions.size(), 2); QCOMPARE(tableLayoutData->m_tableRects.last().columnWidths.size(), 2); // Check cell bounding rectangles. /* * Cell 0, 0 rules: * x = 0 (no borders/margins/paddings) * y = 0 (no borders/margins/paddings) * width = 200/2 = 100 (table width/column count) * height = 1 * 14.4 = 14.4 (number of lines * line height) */ QTextTableCell cell1 = m_table->cellAt(0, 0); QCOMPARE(m_textLayout->m_tableLayout.cellBoundingRect(cell1), QRectF(0, 0, 100, 14.4)); /* * Cell 0, 1 rules: * x = 100 (table width/column count) * y = 0 (no borders/margins/paddings) * width = 200/2 = 100 (table width/column count) * height = 1 * 14.4 = 14.4 (number of lines * line height) */ QTextTableCell cell2 = m_table->cellAt(0, 1); QCOMPARE(m_textLayout->m_tableLayout.cellBoundingRect(cell2), QRectF(100, 0, 100, 14.4)); /* * Cell 1, 0 rules: * x = 0 (no borders/margins/paddings) * y = 14.4 (line height) * width = 200/2 = 100 (table width/column count) * height = 1 * 14.4 = 14.4 (number of lines * line height) */ QTextTableCell cell3 = m_table->cellAt(1, 0); QCOMPARE(m_textLayout->m_tableLayout.cellBoundingRect(cell3), QRectF(0, 14.4, 100, 14.4)); /* * Cell 1, 1 rules: * x = 100 (table width/column count) * y = 14.4 (line height) * width = 200/2 = 100 (table width/column count) * height = 1 * 14.4 = 14.4 (number of lines * line height) */ QTextTableCell cell4 = m_table->cellAt(1, 1); QCOMPARE(m_textLayout->m_tableLayout.cellBoundingRect(cell4), QRectF(100, 14.4, 100, 14.4)); // Check position of blocks in cells. QTextBlock block1 = cell1.firstCursorPosition().block(); QCOMPARE(block1.position(), 1); QVERIFY(block1.layout()); QCOMPARE(block1.layout()->lineCount(), 1); QTextLine line = block1.layout()->lineAt(0); QCOMPARE(line.width(), 100.); QCOMPARE(line.position(), QPointF()); /* * Blocks in cell 0,1 rules: * Position Content Layout bounding rect * 8 "Cell 2" 100, 0 100x? */ QTextBlock block2 = cell2.firstCursorPosition().block(); QCOMPARE(block2.position(), 8); QVERIFY(block2.layout()); QCOMPARE(block2.layout()->lineCount(), 1); line = block2.layout()->lineAt(0); QCOMPARE(line.width(), 100.); QCOMPARE(line.position(), QPointF(100, 0)); /* * Blocks in cell 1,0 rules: * Position Content Layout bounding rect * 15 "Cell 3" 0, 14.4 100x? */ QTextBlock block3 = cell3.firstCursorPosition().block(); QCOMPARE(block3.position(), 15); QVERIFY(block3.layout()); QCOMPARE(block3.layout()->lineCount(), 1); line = block3.layout()->lineAt(0); QCOMPARE(line.width(), 100.); QCOMPARE(line.position().x(), 0.); QVERIFY(qAbs(line.position().y() - 14.4) < 0.156); /* * Blocks in cell 1,1 rules: * Position Content Layout bounding rect * 22 "Cell 4" 100, 14.4 100x? */ QTextBlock block4 = cell4.firstCursorPosition().block(); QCOMPARE(block4.position(), 22); QVERIFY(block4.layout()); QCOMPARE(block4.layout()->lineCount(), 1); line = block4.layout()->lineAt(0); QCOMPARE(line.width(), 100.); QCOMPARE(line.position().x(), 100.); QVERIFY(qAbs(line.position().y() - 14.4) < 0.156); /* * TODO: Insert/remove rows/columns. */ cleanupTest(); }