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 QTextCopyHelper::copy() { if (cursor.hasComplexSelection()) { QTextTable *table = cursor.currentTable(); int row_start, col_start, num_rows, num_cols; cursor.selectedTableCells(&row_start, &num_rows, &col_start, &num_cols); QTextTableFormat tableFormat = table->format(); tableFormat.setColumns(num_cols); tableFormat.clearColumnWidthConstraints(); const int objectIndex = dst->formatCollection()->createObjectIndex(tableFormat); Q_ASSERT(row_start != -1); for (int r = row_start; r < row_start + num_rows; ++r) { for (int c = col_start; c < col_start + num_cols; ++c) { QTextTableCell cell = table->cellAt(r, c); const int rspan = cell.rowSpan(); const int cspan = cell.columnSpan(); if (rspan != 1) { int cr = cell.row(); if (cr != r) continue; } if (cspan != 1) { int cc = cell.column(); if (cc != c) continue; } // add the QTextBeginningOfFrame QTextCharFormat cellFormat = cell.format(); if (r + rspan >= row_start + num_rows) { cellFormat.setTableCellRowSpan(row_start + num_rows - r); } if (c + cspan >= col_start + num_cols) { cellFormat.setTableCellColumnSpan(col_start + num_cols - c); } const int charFormatIndex = convertFormatIndex(cellFormat, objectIndex); int blockIdx = -2; const int cellPos = cell.firstPosition(); QTextBlock block = src->blocksFind(cellPos); if (block.position() == cellPos) { blockIdx = convertFormatIndex(block.blockFormat()); } dst->insertBlock(QTextBeginningOfFrame, insertPos, blockIdx, charFormatIndex); ++insertPos; // nothing to add for empty cells if (cell.lastPosition() > cellPos) { // add the contents appendFragments(cellPos, cell.lastPosition()); } } } // add end of table int end = table->lastPosition(); appendFragment(end, end+1, objectIndex); } else { appendFragments(cursor.selectionStart(), cursor.selectionEnd()); } }
/*! \since 4.1 Splits the specified cell at \a row and \a column into an array of multiple cells with dimensions specified by \a numRows and \a numCols. \note It is only possible to split cells that span multiple rows or columns, such as rows that have been merged using mergeCells(). \sa mergeCells() */ void QTextTable::splitCell(int row, int column, int numRows, int numCols) { Q_D(QTextTable); if (d->dirty) d->update(); QTextDocumentPrivate *p = d->pieceTable; QTextFormatCollection *c = p->formatCollection(); const QTextTableCell cell = cellAt(row, column); if (!cell.isValid()) return; row = cell.row(); column = cell.column(); QTextCharFormat fmt = cell.format(); const int rowSpan = fmt.tableCellRowSpan(); const int colSpan = fmt.tableCellColumnSpan(); // nothing to split? if (numRows > rowSpan || numCols > colSpan) return; p->beginEditBlock(); const int origCellPosition = cell.firstPosition() - 1; QVarLengthArray<int> rowPositions(rowSpan); rowPositions[0] = cell.lastPosition(); for (int r = row + 1; r < row + rowSpan; ++r) { // find the cell before which to insert the new cell markers int gridIndex = r * d->nCols + column; QVector<int>::iterator it = qUpperBound(d->cellIndices.begin(), d->cellIndices.end(), gridIndex); int cellIndex = it - d->cellIndices.begin(); int fragment = d->cells.value(cellIndex, d->fragment_end); rowPositions[r - row] = p->fragmentMap().position(fragment); } fmt.setTableCellColumnSpan(1); fmt.setTableCellRowSpan(1); const int fmtIndex = c->indexForFormat(fmt); const int blockIndex = p->blockMap().find(cell.lastPosition())->format; int insertAdjustement = 0; for (int i = 0; i < numRows; ++i) { for (int c = 0; c < colSpan - numCols; ++c) p->insertBlock(QTextBeginningOfFrame, rowPositions[i] + insertAdjustement + c, blockIndex, fmtIndex); insertAdjustement += colSpan - numCols; } for (int i = numRows; i < rowSpan; ++i) { for (int c = 0; c < colSpan; ++c) p->insertBlock(QTextBeginningOfFrame, rowPositions[i] + insertAdjustement + c, blockIndex, fmtIndex); insertAdjustement += colSpan; } fmt.setTableCellRowSpan(numRows); fmt.setTableCellColumnSpan(numCols); p->setCharFormat(origCellPosition, 1, fmt); p->endEditBlock(); }