87void QTextTableCell::setFormat(
const QTextCharFormat &format)
89 QTextCharFormat fmt = format;
90 fmt.clearProperty(QTextFormat::ObjectIndex);
91 fmt.setObjectType(QTextFormat::TableCellObject);
92 QTextDocumentPrivate *p =
const_cast<QTextDocumentPrivate *>(QTextDocumentPrivate::get(table));
93 QTextDocumentPrivate::FragmentIterator frag(&p->fragmentMap(), fragment);
95 QTextFormatCollection *c = p->formatCollection();
96 QTextCharFormat oldFormat = c->charFormat(frag->format);
97 fmt.setTableCellRowSpan(oldFormat.tableCellRowSpan());
98 fmt.setTableCellColumnSpan(oldFormat.tableCellColumnSpan());
100 p->setCharFormat(frag.position(), 1, fmt, QTextDocumentPrivate::SetFormatAndPreserveObjectIndices);
289QTextTable *QTextTablePrivate::createTable(QTextDocumentPrivate *pieceTable,
int pos,
int rows,
int cols,
const QTextTableFormat &tableFormat)
291 QTextTableFormat fmt = tableFormat;
292 fmt.setColumns(cols);
293 QTextTable *table = qobject_cast<QTextTable *>(pieceTable->createObject(fmt));
296 pieceTable->beginEditBlock();
300 QTextCharFormat charFmt;
301 charFmt.setObjectIndex(table->objectIndex());
302 charFmt.setObjectType(QTextFormat::TableCellObject);
305 int charIdx = pieceTable->formatCollection()->indexForFormat(charFmt);
306 int cellIdx = pieceTable->formatCollection()->indexForFormat(QTextBlockFormat());
308 QTextTablePrivate *d = table->d_func();
309 d->blockFragmentUpdates =
true;
312 d->cells.append(d->fragment_start);
315 for (
int i = 1; i < rows*cols; ++i) {
321 d->fragment_end = pieceTable->insertBlock(
QTextEndOfFrame, pos, cellIdx, charIdx);
325 d->blockFragmentUpdates =
false;
328 pieceTable->endEditBlock();
401void QTextTablePrivate::update()
const
403 Q_Q(
const QTextTable);
404 nCols = q->format().columns();
405 nRows = (cells.size() + nCols-1)/nCols;
408 grid.assign(nRows * nCols, 0);
410 QTextDocumentPrivate *p = pieceTable;
411 QTextFormatCollection *c = p->formatCollection();
413 cellIndices.resize(cells.size());
416 for (
int i = 0; i < cells.size(); ++i) {
417 int fragment = cells.at(i);
418 QTextCharFormat fmt = c->charFormat(QTextDocumentPrivate::FragmentIterator(&p->fragmentMap(), fragment)->format);
419 int rowspan = fmt.tableCellRowSpan();
420 int colspan = fmt.tableCellColumnSpan();
423 while (cell < nRows*nCols && grid[cell])
428 cellIndices[i] = cell;
430 if (r + rowspan > nRows) {
431 grid.resize((r + rowspan) * nCols, 0);
435 Q_ASSERT(c + colspan <= nCols);
436 for (
int ii = 0; ii < rowspan; ++ii) {
437 for (
int jj = 0; jj < colspan; ++jj) {
438 Q_ASSERT(grid[(r+ii)*nCols + c+jj] == 0);
439 grid[(r+ii)*nCols + c+jj] = fragment;
636void QTextTable::insertRows(
int pos,
int num)
645 if (pos > d->nRows || pos < 0)
649 QTextDocumentPrivate *p = d->pieceTable;
650 QTextFormatCollection *c = p->formatCollection();
654 int insert_before = 0;
655 if (pos > 0 && pos < d->nRows) {
657 for (
int i = 0; i < d->nCols; ++i) {
658 int cell = d->grid[pos*d->nCols + i];
659 if (cell == d->grid[(pos-1)*d->nCols+i]) {
661 if (cell != lastCell) {
662 QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
663 QTextCharFormat fmt = c->charFormat(it->format);
664 fmt.setTableCellRowSpan(fmt.tableCellRowSpan() + num);
665 p->setCharFormat(it.position(), 1, fmt);
668 }
else if (!insert_before) {
669 insert_before = cell;
674 insert_before = (pos == 0 ? d->grid[0] : d->fragment_end);
676 if (extended < d->nCols) {
677 Q_ASSERT(insert_before);
678 QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), insert_before);
679 QTextCharFormat fmt = c->charFormat(it->format);
680 fmt.setTableCellRowSpan(1);
681 fmt.setTableCellColumnSpan(1);
682 Q_ASSERT(fmt.objectIndex() == objectIndex());
683 int pos = it.position();
684 int cfmt = p->formatCollection()->indexForFormat(fmt);
685 int bfmt = p->formatCollection()->indexForFormat(QTextBlockFormat());
687 for (
int i = 0; i < num*(d->nCols-extended); ++i)
702void QTextTable::insertColumns(
int pos,
int num)
711 if (pos > d->nCols || pos < 0)
715 QTextDocumentPrivate *p = d->pieceTable;
716 QTextFormatCollection *c = p->formatCollection();
719 QList<
int> extendedSpans;
720 for (
int i = 0; i < d->nRows; ++i) {
722 if (i == d->nRows - 1 && pos == d->nCols) {
723 cell = d->fragment_end;
725 int logicalGridIndexBeforePosition = pos > 0 || i > 0
726 ? d->findCellIndex(d->grid[i*d->nCols + pos - 1])
732 int logicalGridIndex;
733 int gridArrayOffset = i*d->nCols + pos;
735 cell = d->grid[gridArrayOffset];
736 logicalGridIndex = d->findCellIndex(cell);
738 }
while (logicalGridIndex < logicalGridIndexBeforePosition
739 && gridArrayOffset < d->nRows*d->nCols);
741 if (logicalGridIndex < logicalGridIndexBeforePosition
742 && gridArrayOffset == d->nRows*d->nCols)
743 cell = d->fragment_end;
746 if (pos > 0 && pos < d->nCols && cell == d->grid[i*d->nCols + pos - 1]) {
748 if (!extendedSpans.contains(cell)) {
749 QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
750 QTextCharFormat fmt = c->charFormat(it->format);
751 fmt.setTableCellColumnSpan(fmt.tableCellColumnSpan() + num);
752 p->setCharFormat(it.position(), 1, fmt);
754 extendedSpans << cell;
758
759 if (i > 0 && pos < d->nCols && cell == d->grid[(i-1) * d->nCols + pos]) {
760 int gridIndex = i*d->nCols + pos;
761 const int gridEnd = d->nRows * d->nCols - 1;
762 while (gridIndex < gridEnd && cell == d->grid[gridIndex]) {
765 if (gridIndex == gridEnd)
766 cell = d->fragment_end;
768 cell = d->grid[gridIndex];
770 QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
771 QTextCharFormat fmt = c->charFormat(it->format);
772 fmt.setTableCellRowSpan(1);
773 fmt.setTableCellColumnSpan(1);
774 Q_ASSERT(fmt.objectIndex() == objectIndex());
775 int position = it.position();
776 int cfmt = p->formatCollection()->indexForFormat(fmt);
777 int bfmt = p->formatCollection()->indexForFormat(QTextBlockFormat());
778 for (
int i = 0; i < num; ++i)
783 QTextTableFormat tfmt = format();
784 tfmt.setColumns(tfmt.columns()+num);
785 QList<QTextLength> columnWidths = tfmt.columnWidthConstraints();
786 if (! columnWidths.isEmpty()) {
787 for (
int i = num; i > 0; --i)
788 columnWidths.insert(pos, columnWidths.at(qMax(0, pos - 1)));
790 tfmt.setColumnWidthConstraints (columnWidths);
791 QTextObject::setFormat(tfmt);
826void QTextTable::removeRows(
int pos,
int num)
831 if (num <= 0 || pos < 0)
837 if (pos+num > d->nRows)
838 num = d->nRows - pos;
840 QTextDocumentPrivate *p = d->pieceTable;
841 QTextFormatCollection *collection = p->formatCollection();
845 if (pos == 0 && num == d->nRows) {
846 const int pos = p->fragmentMap().position(d->fragment_start);
847 p->remove(pos, p->fragmentMap().position(d->fragment_end) - pos + 1);
852 p->aboutToRemoveCell(cellAt(pos, 0).firstPosition(), cellAt(pos + num - 1, d->nCols - 1).lastPosition());
854 QList<
int> touchedCells;
855 for (
int r = pos; r < pos + num; ++r) {
856 for (
int c = 0; c < d->nCols; ++c) {
857 int cell = d->grid[r*d->nCols + c];
858 if (touchedCells.contains(cell))
860 touchedCells << cell;
861 QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
862 QTextCharFormat fmt = collection->charFormat(it->format);
863 int span = fmt.tableCellRowSpan();
865 fmt.setTableCellRowSpan(span - 1);
866 p->setCharFormat(it.position(), 1, fmt);
869 int index = d->cells.indexOf(cell) + 1;
870 int f_end = index < d->cells.size() ? d->cells.at(index) : d->fragment_end;
871 p->remove(it.position(), p->fragmentMap().position(f_end) - it.position());
888void QTextTable::removeColumns(
int pos,
int num)
893 if (num <= 0 || pos < 0)
899 if (pos + num > d->nCols)
900 pos = d->nCols - num;
902 QTextDocumentPrivate *p = d->pieceTable;
903 QTextFormatCollection *collection = p->formatCollection();
907 if (pos == 0 && num == d->nCols) {
908 const int pos = p->fragmentMap().position(d->fragment_start);
909 p->remove(pos, p->fragmentMap().position(d->fragment_end) - pos + 1);
914 p->aboutToRemoveCell(cellAt(0, pos).firstPosition(), cellAt(d->nRows - 1, pos + num - 1).lastPosition());
916 QList<
int> touchedCells;
917 for (
int r = 0; r < d->nRows; ++r) {
918 for (
int c = pos; c < pos + num; ++c) {
919 int cell = d->grid[r*d->nCols + c];
920 QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
921 QTextCharFormat fmt = collection->charFormat(it->format);
922 int span = fmt.tableCellColumnSpan();
923 if (touchedCells.contains(cell) && span <= 1)
925 touchedCells << cell;
928 fmt.setTableCellColumnSpan(span - 1);
929 p->setCharFormat(it.position(), 1, fmt);
932 int index = d->cells.indexOf(cell) + 1;
933 int f_end = index < d->cells.size() ? d->cells.at(index) : d->fragment_end;
934 p->remove(it.position(), p->fragmentMap().position(f_end) - it.position());
939 QTextTableFormat tfmt = format();
940 tfmt.setColumns(tfmt.columns()-num);
941 QList<QTextLength> columnWidths = tfmt.columnWidthConstraints();
942 if (columnWidths.size() > pos) {
943 columnWidths.remove(pos, num);
944 tfmt.setColumnWidthConstraints (columnWidths);
946 QTextObject::setFormat(tfmt);
962void QTextTable::mergeCells(
int row,
int column,
int numRows,
int numCols)
969 QTextDocumentPrivate *p = d->pieceTable;
970 QTextFormatCollection *fc = p->formatCollection();
972 const QTextTableCell cell = cellAt(row, column);
973 if (!cell.isValid() || row != cell.row() || column != cell.column())
976 QTextCharFormat fmt = cell.format();
977 const int rowSpan = fmt.tableCellRowSpan();
978 const int colSpan = fmt.tableCellColumnSpan();
980 numRows = qMin(numRows, rows() - cell.row());
981 numCols = qMin(numCols, columns() - cell.column());
984 if (numRows < rowSpan || numCols < colSpan)
988 for (
int r = row; r < row + numRows; ++r) {
989 if (cellAt(r, column) == cellAt(r, column - 1))
991 if (cellAt(r, column + numCols) == cellAt(r, column + numCols - 1))
995 for (
int c = column; c < column + numCols; ++c) {
996 if (cellAt(row, c) == cellAt(row - 1, c))
998 if (cellAt(row + numRows, c) == cellAt(row + numRows - 1, c))
1002 p->beginEditBlock();
1004 const int origCellPosition = cell.firstPosition() - 1;
1006 const int cellFragment = d->grid[row * d->nCols + column];
1009 QFragmentFindHelper helper(origCellPosition, p->fragmentMap());
1010 const auto begin = d->cells.cbegin();
1011 const auto it = std::lower_bound(begin, d->cells.cend(), helper);
1012 Q_ASSERT(it != d->cells.cend());
1013 Q_ASSERT(!(helper < *it));
1014 Q_ASSERT(*it == cellFragment);
1015 const int insertCellIndex = it - begin;
1016 int insertFragment = d->cells.value(insertCellIndex + 1, d->fragment_end);
1017 uint insertPos = p->fragmentMap().position(insertFragment);
1019 d->blockFragmentUpdates =
true;
1021 bool rowHasText = cell.firstCursorPosition().block().length();
1022 bool needsParagraph = rowHasText && colSpan == numCols;
1025 for (
int r = row; r < row + numRows; ++r) {
1026 int firstColumn = r < row + rowSpan ? column + colSpan : column;
1029 int firstCellIndex = r == row ? insertCellIndex + 1 : -1;
1030 int cellIndex = firstCellIndex;
1032 for (
int c = firstColumn; c < column + numCols; ++c) {
1033 const int fragment = d->grid[r * d->nCols + c];
1036 if (fragment == cellFragment)
1039 QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), fragment);
1040 uint pos = it.position();
1042 if (firstCellIndex == -1) {
1043 QFragmentFindHelper helper(pos, p->fragmentMap());
1044 const auto begin = d->cells.cbegin();
1045 const auto it = std::lower_bound(begin, d->cells.cend(), helper);
1046 Q_ASSERT(it != d->cells.cend());
1047 Q_ASSERT(!(helper < *it));
1048 Q_ASSERT(*it == fragment);
1049 firstCellIndex = cellIndex = it - begin;
1054 QTextCharFormat fmt = fc->charFormat(it->format);
1056 const int cellRowSpan = fmt.tableCellRowSpan();
1057 const int cellColSpan = fmt.tableCellColumnSpan();
1060 for (
int i = r; i < r + cellRowSpan; ++i)
1061 for (
int j = c; j < c + cellColSpan; ++j)
1062 d->grid[i * d->nCols + j] = cellFragment;
1067 const int nextFragment = d->cells.value(cellIndex, d->fragment_end);
1068 const uint nextPos = p->fragmentMap().position(nextFragment);
1070 Q_ASSERT(nextPos >= pos);
1073 if (nextPos > pos) {
1074 if (needsParagraph) {
1075 needsParagraph =
false;
1076 QTextCursorPrivate::fromPosition(p, insertPos++).insertBlock();
1077 p->move(pos + 1, insertPos, nextPos - pos);
1078 }
else if (rowHasText) {
1079 QTextCursorPrivate::fromPosition(p, insertPos++).insertText(
" "_L1);
1080 p->move(pos + 1, insertPos, nextPos - pos);
1082 p->move(pos, insertPos, nextPos - pos);
1085 insertPos += nextPos - pos;
1091 needsParagraph =
true;
1096 if (firstCellIndex >= 0) {
1097 d->cellIndices.remove(firstCellIndex, cellIndex - firstCellIndex);
1098 d->cells.erase(d->cells.begin() + firstCellIndex, d->cells.begin() + cellIndex);
1102 d->fragment_start = d->cells.constFirst();
1104 fmt.setTableCellRowSpan(numRows);
1105 fmt.setTableCellColumnSpan(numCols);
1106 p->setCharFormat(origCellPosition, 1, fmt);
1108 d->blockFragmentUpdates =
false;
1143void QTextTable::splitCell(
int row,
int column,
int numRows,
int numCols)
1150 QTextDocumentPrivate *p = d->pieceTable;
1151 QTextFormatCollection *c = p->formatCollection();
1153 const QTextTableCell cell = cellAt(row, column);
1154 if (!cell.isValid())
1157 column = cell.column();
1159 QTextCharFormat fmt = cell.format();
1160 const int rowSpan = fmt.tableCellRowSpan();
1161 const int colSpan = fmt.tableCellColumnSpan();
1164 if (numRows > rowSpan || numCols > colSpan)
1167 p->beginEditBlock();
1169 const int origCellPosition = cell.firstPosition() - 1;
1171 QVarLengthArray<
int> rowPositions(rowSpan);
1173 rowPositions[0] = cell.lastPosition();
1175 for (
int r = row + 1; r < row + rowSpan; ++r) {
1177 int gridIndex = r * d->nCols + column;
1178 const auto begin = d->cellIndices.cbegin();
1179 const auto it = std::upper_bound(begin, d->cellIndices.cend(), gridIndex);
1180 int fragment = d->cells.value(it - begin, d->fragment_end);
1181 rowPositions[r - row] = p->fragmentMap().position(fragment);
1184 fmt.setTableCellColumnSpan(1);
1185 fmt.setTableCellRowSpan(1);
1186 const int fmtIndex = c->indexForFormat(fmt);
1187 const int blockIndex = p->blockMap().find(cell.lastPosition())->format;
1189 int insertAdjustement = 0;
1190 for (
int i = 0; i < numRows; ++i) {
1191 for (
int c = 0; c < colSpan - numCols; ++c)
1192 p->insertBlock(
QTextBeginningOfFrame, rowPositions[i] + insertAdjustement + c, blockIndex, fmtIndex);
1193 insertAdjustement += colSpan - numCols;
1196 for (
int i = numRows; i < rowSpan; ++i) {
1197 for (
int c = 0; c < colSpan; ++c)
1198 p->insertBlock(
QTextBeginningOfFrame, rowPositions[i] + insertAdjustement + c, blockIndex, fmtIndex);
1199 insertAdjustement += colSpan;
1202 fmt.setTableCellRowSpan(numRows);
1203 fmt.setTableCellColumnSpan(numCols);
1204 p->setCharFormat(origCellPosition, 1, fmt);
static bool operator<(int fragment, const QFragmentFindHelper &helper)
static bool operator<(const QFragmentFindHelper &helper, int fragment)