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();
403void QTextTablePrivate::update()
const
405 Q_Q(
const QTextTable);
406 nCols = q->format().columns();
407 nRows = (cells.size() + nCols-1)/nCols;
410 grid.assign(nRows * nCols, 0);
412 QTextDocumentPrivate *p = pieceTable;
413 QTextFormatCollection *c = p->formatCollection();
415 cellIndices.resize(cells.size());
418 for (
int i = 0; i < cells.size(); ++i) {
419 int fragment = cells.at(i);
420 QTextCharFormat fmt = c->charFormat(QTextDocumentPrivate::FragmentIterator(&p->fragmentMap(), fragment)->format);
421 int rowspan = fmt.tableCellRowSpan();
422 int colspan = fmt.tableCellColumnSpan();
425 while (cell < nRows*nCols && grid[cell])
430 cellIndices[i] = cell;
432 if (r + rowspan > nRows) {
433 grid.resize((r + rowspan) * nCols, 0);
437 Q_ASSERT(c + colspan <= nCols);
438 for (
int ii = 0; ii < rowspan; ++ii) {
439 for (
int jj = 0; jj < colspan; ++jj) {
440 Q_ASSERT(grid[(r+ii)*nCols + c+jj] == 0);
441 grid[(r+ii)*nCols + c+jj] = fragment;
638void QTextTable::insertRows(
int pos,
int num)
647 if (pos > d->nRows || pos < 0)
651 QTextDocumentPrivate *p = d->pieceTable;
652 QTextFormatCollection *c = p->formatCollection();
656 int insert_before = 0;
657 if (pos > 0 && pos < d->nRows) {
659 for (
int i = 0; i < d->nCols; ++i) {
660 int cell = d->grid[pos*d->nCols + i];
661 if (cell == d->grid[(pos-1)*d->nCols+i]) {
663 if (cell != lastCell) {
664 QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
665 QTextCharFormat fmt = c->charFormat(it->format);
666 fmt.setTableCellRowSpan(fmt.tableCellRowSpan() + num);
667 p->setCharFormat(it.position(), 1, fmt);
670 }
else if (!insert_before) {
671 insert_before = cell;
676 insert_before = (pos == 0 ? d->grid[0] : d->fragment_end);
678 if (extended < d->nCols) {
679 Q_ASSERT(insert_before);
680 QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), insert_before);
681 QTextCharFormat fmt = c->charFormat(it->format);
682 fmt.setTableCellRowSpan(1);
683 fmt.setTableCellColumnSpan(1);
684 Q_ASSERT(fmt.objectIndex() == objectIndex());
685 int pos = it.position();
686 int cfmt = p->formatCollection()->indexForFormat(fmt);
687 int bfmt = p->formatCollection()->indexForFormat(QTextBlockFormat());
689 for (
int i = 0; i < num*(d->nCols-extended); ++i)
704void QTextTable::insertColumns(
int pos,
int num)
713 if (pos > d->nCols || pos < 0)
717 QTextDocumentPrivate *p = d->pieceTable;
718 QTextFormatCollection *c = p->formatCollection();
721 QList<
int> extendedSpans;
722 for (
int i = 0; i < d->nRows; ++i) {
724 if (i == d->nRows - 1 && pos == d->nCols) {
725 cell = d->fragment_end;
727 int logicalGridIndexBeforePosition = pos > 0 || i > 0
728 ? d->findCellIndex(d->grid[i*d->nCols + pos - 1])
734 int logicalGridIndex;
735 int gridArrayOffset = i*d->nCols + pos;
737 cell = d->grid[gridArrayOffset];
738 logicalGridIndex = d->findCellIndex(cell);
740 }
while (logicalGridIndex < logicalGridIndexBeforePosition
741 && gridArrayOffset < d->nRows*d->nCols);
743 if (logicalGridIndex < logicalGridIndexBeforePosition
744 && gridArrayOffset == d->nRows*d->nCols)
745 cell = d->fragment_end;
748 if (pos > 0 && pos < d->nCols && cell == d->grid[i*d->nCols + pos - 1]) {
750 if (!extendedSpans.contains(cell)) {
751 QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
752 QTextCharFormat fmt = c->charFormat(it->format);
753 fmt.setTableCellColumnSpan(fmt.tableCellColumnSpan() + num);
754 p->setCharFormat(it.position(), 1, fmt);
756 extendedSpans << cell;
760
761 if (i > 0 && pos < d->nCols && cell == d->grid[(i-1) * d->nCols + pos]) {
762 int gridIndex = i*d->nCols + pos;
763 const int gridEnd = d->nRows * d->nCols - 1;
764 while (gridIndex < gridEnd && cell == d->grid[gridIndex]) {
767 if (gridIndex == gridEnd)
768 cell = d->fragment_end;
770 cell = d->grid[gridIndex];
772 QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
773 QTextCharFormat fmt = c->charFormat(it->format);
774 fmt.setTableCellRowSpan(1);
775 fmt.setTableCellColumnSpan(1);
776 Q_ASSERT(fmt.objectIndex() == objectIndex());
777 int position = it.position();
778 int cfmt = p->formatCollection()->indexForFormat(fmt);
779 int bfmt = p->formatCollection()->indexForFormat(QTextBlockFormat());
780 for (
int i = 0; i < num; ++i)
785 QTextTableFormat tfmt = format();
786 tfmt.setColumns(tfmt.columns()+num);
787 QList<QTextLength> columnWidths = tfmt.columnWidthConstraints();
788 if (! columnWidths.isEmpty()) {
789 for (
int i = num; i > 0; --i)
790 columnWidths.insert(pos, columnWidths.at(qMax(0, pos - 1)));
792 tfmt.setColumnWidthConstraints (columnWidths);
793 QTextObject::setFormat(tfmt);
828void QTextTable::removeRows(
int pos,
int num)
833 if (num <= 0 || pos < 0)
839 if (pos+num > d->nRows)
840 num = d->nRows - pos;
842 QTextDocumentPrivate *p = d->pieceTable;
843 QTextFormatCollection *collection = p->formatCollection();
847 if (pos == 0 && num == d->nRows) {
848 const int pos = p->fragmentMap().position(d->fragment_start);
849 p->remove(pos, p->fragmentMap().position(d->fragment_end) - pos + 1);
854 p->aboutToRemoveCell(cellAt(pos, 0).firstPosition(), cellAt(pos + num - 1, d->nCols - 1).lastPosition());
856 QList<
int> touchedCells;
857 for (
int r = pos; r < pos + num; ++r) {
858 for (
int c = 0; c < d->nCols; ++c) {
859 int cell = d->grid[r*d->nCols + c];
860 if (touchedCells.contains(cell))
862 touchedCells << cell;
863 QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
864 QTextCharFormat fmt = collection->charFormat(it->format);
865 int span = fmt.tableCellRowSpan();
867 fmt.setTableCellRowSpan(span - 1);
868 p->setCharFormat(it.position(), 1, fmt);
871 int index = d->cells.indexOf(cell) + 1;
872 int f_end = index < d->cells.size() ? d->cells.at(index) : d->fragment_end;
873 p->remove(it.position(), p->fragmentMap().position(f_end) - it.position());
890void QTextTable::removeColumns(
int pos,
int num)
895 if (num <= 0 || pos < 0)
901 if (pos + num > d->nCols)
902 pos = d->nCols - num;
904 QTextDocumentPrivate *p = d->pieceTable;
905 QTextFormatCollection *collection = p->formatCollection();
909 if (pos == 0 && num == d->nCols) {
910 const int pos = p->fragmentMap().position(d->fragment_start);
911 p->remove(pos, p->fragmentMap().position(d->fragment_end) - pos + 1);
916 p->aboutToRemoveCell(cellAt(0, pos).firstPosition(), cellAt(d->nRows - 1, pos + num - 1).lastPosition());
918 QList<
int> touchedCells;
919 for (
int r = 0; r < d->nRows; ++r) {
920 for (
int c = pos; c < pos + num; ++c) {
921 int cell = d->grid[r*d->nCols + c];
922 QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
923 QTextCharFormat fmt = collection->charFormat(it->format);
924 int span = fmt.tableCellColumnSpan();
925 if (touchedCells.contains(cell) && span <= 1)
927 touchedCells << cell;
930 fmt.setTableCellColumnSpan(span - 1);
931 p->setCharFormat(it.position(), 1, fmt);
934 int index = d->cells.indexOf(cell) + 1;
935 int f_end = index < d->cells.size() ? d->cells.at(index) : d->fragment_end;
936 p->remove(it.position(), p->fragmentMap().position(f_end) - it.position());
941 QTextTableFormat tfmt = format();
942 tfmt.setColumns(tfmt.columns()-num);
943 QList<QTextLength> columnWidths = tfmt.columnWidthConstraints();
944 if (columnWidths.size() > pos) {
945 columnWidths.remove(pos, num);
946 tfmt.setColumnWidthConstraints (columnWidths);
948 QTextObject::setFormat(tfmt);
964void QTextTable::mergeCells(
int row,
int column,
int numRows,
int numCols)
971 QTextDocumentPrivate *p = d->pieceTable;
972 QTextFormatCollection *fc = p->formatCollection();
974 const QTextTableCell cell = cellAt(row, column);
975 if (!cell.isValid() || row != cell.row() || column != cell.column())
978 QTextCharFormat fmt = cell.format();
979 const int rowSpan = fmt.tableCellRowSpan();
980 const int colSpan = fmt.tableCellColumnSpan();
982 numRows = qMin(numRows, rows() - cell.row());
983 numCols = qMin(numCols, columns() - cell.column());
986 if (numRows < rowSpan || numCols < colSpan)
990 for (
int r = row; r < row + numRows; ++r) {
991 if (cellAt(r, column) == cellAt(r, column - 1))
993 if (cellAt(r, column + numCols) == cellAt(r, column + numCols - 1))
997 for (
int c = column; c < column + numCols; ++c) {
998 if (cellAt(row, c) == cellAt(row - 1, c))
1000 if (cellAt(row + numRows, c) == cellAt(row + numRows - 1, c))
1004 p->beginEditBlock();
1006 const int origCellPosition = cell.firstPosition() - 1;
1008 const int cellFragment = d->grid[row * d->nCols + column];
1011 QFragmentFindHelper helper(origCellPosition, p->fragmentMap());
1012 const auto begin = d->cells.cbegin();
1013 const auto it = std::lower_bound(begin, d->cells.cend(), helper);
1014 Q_ASSERT(it != d->cells.cend());
1015 Q_ASSERT(!(helper < *it));
1016 Q_ASSERT(*it == cellFragment);
1017 const int insertCellIndex = it - begin;
1018 int insertFragment = d->cells.value(insertCellIndex + 1, d->fragment_end);
1019 uint insertPos = p->fragmentMap().position(insertFragment);
1021 d->blockFragmentUpdates =
true;
1023 bool rowHasText = cell.firstCursorPosition().block().length();
1024 bool needsParagraph = rowHasText && colSpan == numCols;
1027 for (
int r = row; r < row + numRows; ++r) {
1028 int firstColumn = r < row + rowSpan ? column + colSpan : column;
1031 int firstCellIndex = r == row ? insertCellIndex + 1 : -1;
1032 int cellIndex = firstCellIndex;
1034 for (
int c = firstColumn; c < column + numCols; ++c) {
1035 const int fragment = d->grid[r * d->nCols + c];
1038 if (fragment == cellFragment)
1041 QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), fragment);
1042 uint pos = it.position();
1044 if (firstCellIndex == -1) {
1045 QFragmentFindHelper helper(pos, p->fragmentMap());
1046 const auto begin = d->cells.cbegin();
1047 const auto it = std::lower_bound(begin, d->cells.cend(), helper);
1048 Q_ASSERT(it != d->cells.cend());
1049 Q_ASSERT(!(helper < *it));
1050 Q_ASSERT(*it == fragment);
1051 firstCellIndex = cellIndex = it - begin;
1056 QTextCharFormat fmt = fc->charFormat(it->format);
1058 const int cellRowSpan = fmt.tableCellRowSpan();
1059 const int cellColSpan = fmt.tableCellColumnSpan();
1062 for (
int i = r; i < r + cellRowSpan; ++i)
1063 for (
int j = c; j < c + cellColSpan; ++j)
1064 d->grid[i * d->nCols + j] = cellFragment;
1069 const int nextFragment = d->cells.value(cellIndex, d->fragment_end);
1070 const uint nextPos = p->fragmentMap().position(nextFragment);
1072 Q_ASSERT(nextPos >= pos);
1075 if (nextPos > pos) {
1076 if (needsParagraph) {
1077 needsParagraph =
false;
1078 QTextCursorPrivate::fromPosition(p, insertPos++).insertBlock();
1079 p->move(pos + 1, insertPos, nextPos - pos);
1080 }
else if (rowHasText) {
1081 QTextCursorPrivate::fromPosition(p, insertPos++).insertText(
" "_L1);
1082 p->move(pos + 1, insertPos, nextPos - pos);
1084 p->move(pos, insertPos, nextPos - pos);
1087 insertPos += nextPos - pos;
1093 needsParagraph =
true;
1098 if (firstCellIndex >= 0) {
1099 d->cellIndices.remove(firstCellIndex, cellIndex - firstCellIndex);
1100 d->cells.erase(d->cells.begin() + firstCellIndex, d->cells.begin() + cellIndex);
1104 d->fragment_start = d->cells.constFirst();
1106 fmt.setTableCellRowSpan(numRows);
1107 fmt.setTableCellColumnSpan(numCols);
1108 p->setCharFormat(origCellPosition, 1, fmt);
1110 d->blockFragmentUpdates =
false;
1145void QTextTable::splitCell(
int row,
int column,
int numRows,
int numCols)
1152 QTextDocumentPrivate *p = d->pieceTable;
1153 QTextFormatCollection *c = p->formatCollection();
1155 const QTextTableCell cell = cellAt(row, column);
1156 if (!cell.isValid())
1159 column = cell.column();
1161 QTextCharFormat fmt = cell.format();
1162 const int rowSpan = fmt.tableCellRowSpan();
1163 const int colSpan = fmt.tableCellColumnSpan();
1166 if (numRows > rowSpan || numCols > colSpan)
1169 p->beginEditBlock();
1171 const int origCellPosition = cell.firstPosition() - 1;
1173 QVarLengthArray<
int> rowPositions(rowSpan);
1175 rowPositions[0] = cell.lastPosition();
1177 for (
int r = row + 1; r < row + rowSpan; ++r) {
1179 int gridIndex = r * d->nCols + column;
1180 const auto begin = d->cellIndices.cbegin();
1181 const auto it = std::upper_bound(begin, d->cellIndices.cend(), gridIndex);
1182 int fragment = d->cells.value(it - begin, d->fragment_end);
1183 rowPositions[r - row] = p->fragmentMap().position(fragment);
1186 fmt.setTableCellColumnSpan(1);
1187 fmt.setTableCellRowSpan(1);
1188 const int fmtIndex = c->indexForFormat(fmt);
1189 const int blockIndex = p->blockMap().find(cell.lastPosition())->format;
1191 int insertAdjustement = 0;
1192 for (
int i = 0; i < numRows; ++i) {
1193 for (
int c = 0; c < colSpan - numCols; ++c)
1194 p->insertBlock(
QTextBeginningOfFrame, rowPositions[i] + insertAdjustement + c, blockIndex, fmtIndex);
1195 insertAdjustement += colSpan - numCols;
1198 for (
int i = numRows; i < rowSpan; ++i) {
1199 for (
int c = 0; c < colSpan; ++c)
1200 p->insertBlock(
QTextBeginningOfFrame, rowPositions[i] + insertAdjustement + c, blockIndex, fmtIndex);
1201 insertAdjustement += colSpan;
1204 fmt.setTableCellRowSpan(numRows);
1205 fmt.setTableCellColumnSpan(numCols);
1206 p->setCharFormat(origCellPosition, 1, fmt);
static bool operator<(int fragment, const QFragmentFindHelper &helper)
static bool operator<(const QFragmentFindHelper &helper, int fragment)