1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29
30#include <QtTest/QtTest>
31
32#include <qbuffer.h>
33#include <qtextdocument.h>
34#include <qtextdocumentfragment.h>
35#include <qtexttable.h>
36#include <qdebug.h>
37#include <qtextcursor.h>
38#include <qtextdocument.h>
39#ifndef QT_NO_WIDGETS
40#include <qtextedit.h>
41#endif
42#ifndef QT_NO_PRINTER
43#include <QPagedPaintDevice>
44#include <QPainter>
45#include <QPaintEngine>
46#endif
47#include <private/qtextdocumentlayout_p.h>
48#include <private/qpagedpaintdevice_p.h>
49
50typedef QList<int> IntList;
51
52QT_FORWARD_DECLARE_CLASS(QTextDocument)
53
54Q_DECLARE_METATYPE(QTextFrameFormat::BorderStyle);
55
56class tst_QTextTable : public QObject
57{
58 Q_OBJECT
59
60private slots:
61 void init();
62 void cleanup();
63 void cursorPositioning();
64 void variousTableModifications();
65 void tableShrinking();
66 void spans();
67 void variousModifications2();
68 void tableManager_undo();
69 void tableManager_removeCell();
70 void rowAt();
71 void rowAtWithSpans();
72 void multiBlockCells();
73 void insertRows();
74 void deleteInTable();
75 void mergeCells();
76 void mergeAndInsert();
77 void splitCells();
78 void blocksForTableShouldHaveEmptyFormat();
79 void removeTableByRemoveRows();
80 void removeTableByRemoveColumns();
81 void setCellFormat();
82 void removeRows1();
83 void removeRows2();
84 void removeRows3();
85 void removeRows4();
86 void removeRows5();
87 void removeColumns1();
88 void removeColumns2();
89 void removeColumns3();
90 void removeColumns4();
91 void removeColumns5();
92 void removeColumnsInTableWithMergedRows();
93#ifndef QT_NO_WIDGETS
94 void QTBUG11282_insertBeforeMergedEnding_data();
95 void QTBUG11282_insertBeforeMergedEnding();
96#endif
97 void QTBUG22011_insertBeforeRowSpan();
98#if !defined(QT_NO_PRINTER) && defined(QT_BUILD_INTERNAL)
99 void QTBUG31330_renderBackground();
100#endif
101 void checkBorderAttributes_data();
102 void checkBorderAttributes();
103
104#ifndef QT_NO_WIDGETS
105 void columnWidthWithSpans();
106
107 void columnWidthWithImage_data();
108 void columnWidthWithImage();
109#endif
110
111private:
112 QTextTable *create2x2Table();
113 QTextTable *create4x4Table();
114
115 QTextTable *createTable(int rows, int cols);
116
117 QTextDocument *doc;
118 QTextCursor cursor;
119};
120
121void tst_QTextTable::init()
122{
123 doc = new QTextDocument;
124 cursor = QTextCursor(doc);
125}
126
127void tst_QTextTable::cleanup()
128{
129 cursor = QTextCursor();
130 delete doc;
131 doc = 0;
132}
133
134void tst_QTextTable::cursorPositioning()
135{
136 // ensure the cursor is placed at the beginning of the first cell upon
137 // table creation
138 QTextTable *table = cursor.insertTable(rows: 2, cols: 2);
139
140 QVERIFY(cursor == table->cellAt(0, 0).firstCursorPosition());
141 QVERIFY(table->cellAt(0, 0).firstPosition() == table->firstPosition());
142}
143
144void tst_QTextTable::variousTableModifications()
145{
146 QTextTableFormat tableFmt;
147
148 QTextTable *tab = cursor.insertTable(rows: 2, cols: 2, format: tableFmt);
149 QCOMPARE(doc->toPlainText().length(), 5);
150 QCOMPARE(tab, cursor.currentTable());
151 QCOMPARE(tab->columns(), 2);
152 QCOMPARE(tab->rows(), 2);
153
154 QCOMPARE(cursor.position(), 1);
155 QTextCharFormat fmt = cursor.charFormat();
156 QCOMPARE(fmt.objectIndex(), -1);
157 QTextTableCell cell = tab->cellAt(c: cursor);
158 QVERIFY(cell.isValid());
159 QCOMPARE(cell.row(), 0);
160 QCOMPARE(cell.column(), 0);
161
162 cursor.movePosition(op: QTextCursor::NextBlock);
163 QCOMPARE(cursor.position(), 2);
164 fmt = cursor.charFormat();
165 QCOMPARE(fmt.objectIndex(), -1);
166 cell = tab->cellAt(c: cursor);
167 QVERIFY(cell.isValid());
168 QCOMPARE(cell.row(), 0);
169 QCOMPARE(cell.column(), 1);
170
171 cursor.movePosition(op: QTextCursor::NextBlock);
172 QCOMPARE(cursor.position(), 3);
173 fmt = cursor.charFormat();
174 QCOMPARE(fmt.objectIndex(), -1);
175 cell = tab->cellAt(c: cursor);
176 QVERIFY(cell.isValid());
177 QCOMPARE(cell.row(), 1);
178 QCOMPARE(cell.column(), 0);
179
180 cursor.movePosition(op: QTextCursor::NextBlock);
181 QCOMPARE(cursor.position(), 4);
182 fmt = cursor.charFormat();
183 QCOMPARE(fmt.objectIndex(), -1);
184 cell = tab->cellAt(c: cursor);
185 QVERIFY(cell.isValid());
186 QCOMPARE(cell.row(), 1);
187 QCOMPARE(cell.column(), 1);
188
189 cursor.movePosition(op: QTextCursor::NextBlock);
190 QCOMPARE(cursor.position(), 5);
191 fmt = cursor.charFormat();
192 QCOMPARE(fmt.objectIndex(), -1);
193 cell = tab->cellAt(c: cursor);
194 QVERIFY(!cell.isValid());
195
196 cursor.movePosition(op: QTextCursor::NextBlock);
197 QCOMPARE(cursor.position(), 5);
198
199 // check we can't delete the cells with the cursor
200 cursor.movePosition(op: QTextCursor::Start);
201 cursor.movePosition(op: QTextCursor::NextBlock);
202 QCOMPARE(cursor.position(), 1);
203 cursor.deleteChar();
204 QCOMPARE(doc->toPlainText().length(), 5);
205 cursor.movePosition(op: QTextCursor::NextBlock);
206 QCOMPARE(cursor.position(), 2);
207 cursor.deleteChar();
208 QCOMPARE(doc->toPlainText().length(), 5);
209 cursor.deletePreviousChar();
210 QCOMPARE(cursor.position(), 2);
211 QCOMPARE(doc->toPlainText().length(), 5);
212
213 QTextTable *table = cursor.currentTable();
214 QCOMPARE(table->rows(), 2);
215 QCOMPARE(table->columns(), 2);
216
217 table->insertRows(pos: 2, num: 1);
218 QCOMPARE(table->rows(), 3);
219 QCOMPARE(table->columns(), 2);
220 QCOMPARE(doc->toPlainText().length(), 7);
221 table->insertColumns(pos: 2, num: 2);
222 QCOMPARE(table->rows(), 3);
223 QCOMPARE(table->columns(), 4);
224 QCOMPARE(doc->toPlainText().length(), 13);
225
226 table->resize(rows: 4, cols: 5);
227 QCOMPARE(table->rows(), 4);
228 QCOMPARE(table->columns(), 5);
229 QCOMPARE(doc->toPlainText().length(), 21);
230}
231
232void tst_QTextTable::tableShrinking()
233{
234 QTextTableFormat tableFmt;
235
236 cursor.insertTable(rows: 3, cols: 4, format: tableFmt);
237 QCOMPARE(doc->toPlainText().length(), 13);
238
239 QTextTable *table = cursor.currentTable();
240 QCOMPARE(table->rows(), 3);
241 QCOMPARE(table->columns(), 4);
242
243 table->removeRows(pos: 1, num: 1);
244 QCOMPARE(table->rows(), 2);
245 QCOMPARE(table->columns(), 4);
246 QCOMPARE(doc->toPlainText().length(), 9);
247 table->removeColumns(pos: 1, num: 2);
248 QCOMPARE(table->rows(), 2);
249 QCOMPARE(table->columns(), 2);
250 QCOMPARE(doc->toPlainText().length(), 5);
251
252 table->resize(rows: 1, cols: 1);
253 QCOMPARE(table->rows(), 1);
254 QCOMPARE(table->columns(), 1);
255 QCOMPARE(doc->toPlainText().length(), 2);
256}
257
258void tst_QTextTable::spans()
259{
260 QTextTableFormat tableFmt;
261
262 cursor.insertTable(rows: 2, cols: 2, format: tableFmt);
263
264 QTextTable *table = cursor.currentTable();
265 QVERIFY(table->cellAt(0, 0) != table->cellAt(0, 1));
266 table->mergeCells(row: 0, col: 0, numRows: 1, numCols: 2);
267 QCOMPARE(table->rows(), 2);
268 QCOMPARE(table->columns(), 2);
269 QVERIFY(table->cellAt(0, 0) == table->cellAt(0, 1));
270 table->mergeCells(row: 0, col: 0, numRows: 2, numCols: 2);
271 QCOMPARE(table->rows(), 2);
272 QCOMPARE(table->columns(), 2);
273}
274
275void tst_QTextTable::variousModifications2()
276{
277 QTextTableFormat tableFmt;
278
279 cursor.insertTable(rows: 2, cols: 5, format: tableFmt);
280 QCOMPARE(doc->toPlainText().length(), 11);
281 QTextTable *table = cursor.currentTable();
282 QCOMPARE(cursor.position(), 1);
283 QCOMPARE(table->rows(), 2);
284 QCOMPARE(table->columns(), 5);
285
286 table->insertColumns(pos: 0, num: 1);
287 QCOMPARE(table->rows(), 2);
288 QCOMPARE(table->columns(), 6);
289 table->insertColumns(pos: 6, num: 1);
290 QCOMPARE(table->rows(), 2);
291 QCOMPARE(table->columns(), 7);
292
293 table->insertRows(pos: 0, num: 1);
294 QCOMPARE(table->rows(), 3);
295 QCOMPARE(table->columns(), 7);
296 table->insertRows(pos: 3, num: 1);
297 QCOMPARE(table->rows(), 4);
298 QCOMPARE(table->columns(), 7);
299
300 table->removeRows(pos: 0, num: 1);
301 QCOMPARE(table->rows(), 3);
302 QCOMPARE(table->columns(), 7);
303 table->removeRows(pos: 2, num: 1);
304 QCOMPARE(table->rows(), 2);
305 QCOMPARE(table->columns(), 7);
306
307 table->removeColumns(pos: 0, num: 1);
308 QCOMPARE(table->rows(), 2);
309 QCOMPARE(table->columns(), 6);
310 table->removeColumns(pos: 5, num: 1);
311 QCOMPARE(table->rows(), 2);
312 QCOMPARE(table->columns(), 5);
313
314 tableFmt = table->format();
315 table->insertColumns(pos: 2, num: 1);
316 table->setFormat(tableFmt);
317 table->insertColumns(pos: 2, num: 1);
318 QCOMPARE(table->columns(), 7);
319}
320
321void tst_QTextTable::tableManager_undo()
322{
323 QTextTableFormat fmt;
324 fmt.setBorder(10);
325 QTextTable *table = cursor.insertTable(rows: 2, cols: 2, format: fmt);
326 QVERIFY(table);
327
328 QCOMPARE(table->format().border(), qreal(10));
329
330 fmt.setBorder(20);
331 table->setFormat(fmt);
332
333 QCOMPARE(table->format().border(), qreal(20));
334
335 doc->undo();
336
337 QCOMPARE(table->format().border(), qreal(10));
338}
339
340void tst_QTextTable::tableManager_removeCell()
341{
342 // essentially a test for TableManager::removeCell, in particular to remove empty items from the rowlist.
343 // If it fails it'll triger assertions inside TableManager. Yeah, not pretty, should VERIFY here ;(
344 cursor.insertTable(rows: 2, cols: 2, format: QTextTableFormat());
345 doc->undo();
346 // ###
347 QVERIFY(true);
348}
349
350void tst_QTextTable::rowAt()
351{
352 // test TablePrivate::rowAt
353 QTextTable *table = cursor.insertTable(rows: 4, cols: 2);
354
355 QCOMPARE(table->rows(), 4);
356 QCOMPARE(table->columns(), 2);
357
358 QTextCursor cell00Cursor = table->cellAt(row: 0, col: 0).firstCursorPosition();
359 QTextCursor cell10Cursor = table->cellAt(row: 1, col: 0).firstCursorPosition();
360 QTextCursor cell20Cursor = table->cellAt(row: 2, col: 0).firstCursorPosition();
361 QTextCursor cell21Cursor = table->cellAt(row: 2, col: 1).firstCursorPosition();
362 QTextCursor cell30Cursor = table->cellAt(row: 3, col: 0).firstCursorPosition();
363 QCOMPARE(table->cellAt(cell00Cursor).firstCursorPosition(), cell00Cursor);
364 QCOMPARE(table->cellAt(cell10Cursor).firstCursorPosition(), cell10Cursor);
365 QCOMPARE(table->cellAt(cell20Cursor).firstCursorPosition(), cell20Cursor);
366 QCOMPARE(table->cellAt(cell30Cursor).firstCursorPosition(), cell30Cursor);
367
368 table->mergeCells(row: 1, col: 0, numRows: 2, numCols: 1);
369
370 QCOMPARE(table->rows(), 4);
371 QCOMPARE(table->columns(), 2);
372
373 QVERIFY(cell00Cursor == table->cellAt(0, 0).firstCursorPosition());
374 QVERIFY(cell10Cursor == table->cellAt(1, 0).firstCursorPosition());
375 QVERIFY(cell10Cursor == table->cellAt(2, 0).firstCursorPosition());
376 QVERIFY(cell21Cursor == table->cellAt(2, 1).firstCursorPosition());
377 QVERIFY(cell30Cursor == table->cellAt(3, 0).firstCursorPosition());
378
379 table->mergeCells(row: 1, col: 0, numRows: 2, numCols: 2);
380
381 QCOMPARE(table->rows(), 4);
382 QCOMPARE(table->columns(), 2);
383
384 QVERIFY(cell00Cursor == table->cellAt(0, 0).firstCursorPosition());
385 QVERIFY(cell00Cursor == table->cellAt(0, 0).firstCursorPosition());
386 QVERIFY(cell10Cursor == table->cellAt(1, 0).firstCursorPosition());
387 QVERIFY(cell10Cursor == table->cellAt(1, 1).firstCursorPosition());
388 QVERIFY(cell10Cursor == table->cellAt(2, 0).firstCursorPosition());
389 QVERIFY(cell10Cursor == table->cellAt(2, 1).firstCursorPosition());
390 QVERIFY(cell30Cursor == table->cellAt(3, 0).firstCursorPosition());
391}
392
393void tst_QTextTable::rowAtWithSpans()
394{
395 QTextTable *table = cursor.insertTable(rows: 2, cols: 2);
396
397 QCOMPARE(table->rows(), 2);
398 QCOMPARE(table->columns(), 2);
399
400 table->mergeCells(row: 0, col: 0, numRows: 2, numCols: 1);
401 QVERIFY(table->cellAt(0, 0).rowSpan() == 2);
402
403 QCOMPARE(table->rows(), 2);
404 QCOMPARE(table->columns(), 2);
405
406 table->mergeCells(row: 0, col: 0, numRows: 2, numCols: 2);
407 QVERIFY(table->cellAt(0, 0).columnSpan() == 2);
408
409 QCOMPARE(table->rows(), 2);
410 QCOMPARE(table->columns(), 2);
411}
412
413void tst_QTextTable::multiBlockCells()
414{
415 // little testcase for multi-block cells
416 QTextTable *table = cursor.insertTable(rows: 2, cols: 2);
417
418 QVERIFY(cursor == table->cellAt(0, 0).firstCursorPosition());
419
420 cursor.insertText(text: "Hello");
421 cursor.insertBlock(format: QTextBlockFormat());
422 cursor.insertText(text: "World");
423
424 cursor.movePosition(op: QTextCursor::Left);
425 QVERIFY(table->cellAt(0, 0) == table->cellAt(cursor));
426}
427
428void tst_QTextTable::insertRows()
429{
430 // little testcase for multi-block cells
431 QTextTable *table = cursor.insertTable(rows: 2, cols: 2);
432
433 QVERIFY(cursor == table->cellAt(0, 0).firstCursorPosition());
434
435 table->insertRows(pos: 0, num: 1);
436 QCOMPARE(table->rows(), 3);
437
438 table->insertRows(pos: 1, num: 1);
439 QCOMPARE(table->rows(), 4);
440
441 table->insertRows(pos: -1, num: 1);
442 QCOMPARE(table->rows(), 5);
443
444 table->insertRows(pos: 5, num: 2);
445 QCOMPARE(table->rows(), 7);
446
447 table = cursor.insertTable(rows: 5,cols: 5);
448 table->mergeCells(row: 0,col: 0,numRows: 3,numCols: 3);
449 table->insertRows(pos: 2,num: 1);
450
451 QCOMPARE(table->rows(), 6);
452
453}
454
455void tst_QTextTable::deleteInTable()
456{
457 QTextTable *table = cursor.insertTable(rows: 2, cols: 2);
458 table->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "Blah");
459 table->cellAt(row: 0, col: 1).firstCursorPosition().insertText(text: "Foo");
460 table->cellAt(row: 1, col: 0).firstCursorPosition().insertText(text: "Bar");
461 table->cellAt(row: 1, col: 1).firstCursorPosition().insertText(text: "Hah");
462
463 cursor = table->cellAt(row: 1, col: 1).firstCursorPosition();
464 cursor.movePosition(op: QTextCursor::PreviousBlock, QTextCursor::KeepAnchor);
465
466 QCOMPARE(table->cellAt(cursor.position()).row(), 1);
467 QCOMPARE(table->cellAt(cursor.position()).column(), 0);
468
469 cursor.removeSelectedText();
470
471 QCOMPARE(table->columns(), 2);
472 QCOMPARE(table->rows(), 2);
473
474 // verify table is still all in shape. Only the text inside should get deleted
475 for (int row = 0; row < table->rows(); ++row)
476 for (int col = 0; col < table->columns(); ++col) {
477 const QTextTableCell cell = table->cellAt(row, col);
478 QVERIFY(cell.isValid());
479 QCOMPARE(cell.rowSpan(), 1);
480 QCOMPARE(cell.columnSpan(), 1);
481 }
482}
483
484QTextTable *tst_QTextTable::create2x2Table()
485{
486 cleanup();
487 init();
488 QTextTable *table = cursor.insertTable(rows: 2, cols: 2);
489 table->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "Blah");
490 table->cellAt(row: 0, col: 1).firstCursorPosition().insertText(text: "Foo");
491 table->cellAt(row: 1, col: 0).firstCursorPosition().insertText(text: "Bar");
492 table->cellAt(row: 1, col: 1).firstCursorPosition().insertText(text: "Hah");
493 return table;
494}
495
496QTextTable *tst_QTextTable::create4x4Table()
497{
498 cleanup();
499 init();
500 QTextTable *table = cursor.insertTable(rows: 4, cols: 4);
501 table->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "Blah");
502 table->cellAt(row: 0, col: 1).firstCursorPosition().insertText(text: "Foo");
503 table->cellAt(row: 1, col: 0).firstCursorPosition().insertText(text: "Bar");
504 table->cellAt(row: 1, col: 1).firstCursorPosition().insertText(text: "Hah");
505 return table;
506}
507
508QTextTable *tst_QTextTable::createTable(int rows, int cols)
509{
510 cleanup();
511 init();
512 QTextTable *table = cursor.insertTable(rows, cols);
513 return table;
514}
515
516void tst_QTextTable::mergeCells()
517{
518 QTextTable *table = create4x4Table();
519
520 table->mergeCells(row: 1, col: 1, numRows: 1, numCols: 2);
521 QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2));
522
523 table->mergeCells(row: 1, col: 1, numRows: 2, numCols: 2);
524 QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2));
525 QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1));
526 QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2));
527
528 table = create4x4Table();
529
530 table->mergeCells(row: 1, col: 1, numRows: 2, numCols: 1);
531 QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1));
532
533 table->mergeCells(row: 1, col: 1, numRows: 2, numCols: 2);
534 QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2));
535 QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1));
536 QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2));
537
538 table = create4x4Table();
539
540 table->mergeCells(row: 1, col: 1, numRows: 2, numCols: 2);
541 QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2));
542 QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1));
543 QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2));
544
545 // should do nothing
546 table->mergeCells(row: 1, col: 1, numRows: 1, numCols: 1);
547 QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2));
548 QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1));
549 QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2));
550
551 table = create2x2Table();
552
553 table->mergeCells(row: 0, col: 1, numRows: 2, numCols: 1);
554 table->mergeCells(row: 0, col: 0, numRows: 2, numCols: 2);
555 QVERIFY(table->cellAt(0, 0) == table->cellAt(0, 1));
556 QVERIFY(table->cellAt(0, 0) == table->cellAt(1, 0));
557 QVERIFY(table->cellAt(0, 0) == table->cellAt(1, 1));
558
559 QTextBlock block = table->cellAt(row: 0, col: 0).firstCursorPosition().block();
560
561 QCOMPARE(block.text(), QLatin1String("Blah Foo"));
562 QCOMPARE(block.next().text(), QLatin1String("Hah"));
563 QCOMPARE(block.next().next().text(), QLatin1String("Bar"));
564
565 table = create4x4Table();
566
567 QTextCursor cursor = table->cellAt(row: 3, col: 3).firstCursorPosition();
568 QTextTable *t2 = cursor.insertTable(rows: 2, cols: 2);
569 t2->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "Test");
570
571 table->mergeCells(row: 2, col: 2, numRows: 2, numCols: 2);
572 cursor = table->cellAt(row: 2, col: 2).firstCursorPosition();
573
574 QTextFrame *frame = cursor.currentFrame();
575
576 QTextFrame::iterator it = frame->begin();
577
578 // find the embedded table
579 while (it != frame->end() && !it.currentFrame())
580 ++it;
581
582 table = qobject_cast<QTextTable *>(object: it.currentFrame());
583
584 QVERIFY(table);
585
586 if (table) {
587 cursor = table->cellAt(row: 0, col: 0).firstCursorPosition();
588
589 QCOMPARE(cursor.block().text(), QLatin1String("Test"));
590 }
591
592 table = create2x2Table();
593
594 table->mergeCells(row: 0, col: 1, numRows: 2, numCols: 1);
595
596 QVERIFY(table->cellAt(0, 0) != table->cellAt(0, 1));
597 QVERIFY(table->cellAt(0, 1) == table->cellAt(1, 1));
598
599 // should do nothing
600 table->mergeCells(row: 0, col: 0, numRows: 1, numCols: 2);
601
602 QVERIFY(table->cellAt(0, 0) != table->cellAt(0, 1));
603 QVERIFY(table->cellAt(0, 1) == table->cellAt(1, 1));
604}
605
606void tst_QTextTable::mergeAndInsert()
607{
608 QTextTable *table = cursor.insertTable(rows: 4,cols: 3);
609 table->mergeCells(row: 0,col: 1,numRows: 3,numCols: 2);
610 table->mergeCells(row: 3,col: 0,numRows: 1,numCols: 3);
611 //Don't crash !
612 table->insertColumns(pos: 1,num: 2);
613 QCOMPARE(table->columns(), 5);
614}
615
616void tst_QTextTable::splitCells()
617{
618 QTextTable *table = create4x4Table();
619 table->mergeCells(row: 1, col: 1, numRows: 2, numCols: 2);
620 QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2));
621 QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1));
622 QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2));
623
624 table->splitCell(row: 1, col: 1, numRows: 1, numCols: 2);
625 QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2));
626 QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 1));
627 QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 2));
628
629 table->splitCell(row: 1, col: 1, numRows: 1, numCols: 1);
630 QVERIFY(table->cellAt(1, 1) != table->cellAt(1, 2));
631 QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 1));
632 QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 2));
633
634
635 table = create4x4Table();
636 table->mergeCells(row: 1, col: 1, numRows: 2, numCols: 2);
637 QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2));
638 QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1));
639 QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2));
640
641 table->splitCell(row: 1, col: 1, numRows: 2, numCols: 1);
642 QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1));
643 QVERIFY(table->cellAt(1, 1) != table->cellAt(1, 2));
644 QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 2));
645
646 table->splitCell(row: 1, col: 1, numRows: 1, numCols: 1);
647 QVERIFY(table->cellAt(1, 1) != table->cellAt(1, 2));
648 QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 1));
649 QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 2));
650
651
652 table = create4x4Table();
653 table->mergeCells(row: 1, col: 1, numRows: 2, numCols: 2);
654 QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2));
655 QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1));
656 QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2));
657
658 table->splitCell(row: 1, col: 1, numRows: 1, numCols: 1);
659 QVERIFY(table->cellAt(1, 1) != table->cellAt(1, 2));
660 QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 1));
661 QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 2));
662
663 table = createTable(rows: 2, cols: 5);
664 table->mergeCells(row: 0, col: 0, numRows: 2, numCols: 1);
665 table->mergeCells(row: 0, col: 1, numRows: 2, numCols: 1);
666 QVERIFY(table->cellAt(0, 0) == table->cellAt(1, 0));
667 QVERIFY(table->cellAt(0, 1) == table->cellAt(1, 1));
668 table->splitCell(row: 0, col: 0, numRows: 1, numCols: 1);
669 QVERIFY(table->cellAt(0, 0) != table->cellAt(1, 0));
670 QVERIFY(table->cellAt(0, 1) == table->cellAt(1, 1));
671
672 table = createTable(rows: 2, cols: 5);
673 table->mergeCells(row: 0, col: 4, numRows: 2, numCols: 1);
674 QVERIFY(table->cellAt(0, 4) == table->cellAt(1, 4));
675
676 table->splitCell(row: 0, col: 4, numRows: 1, numCols: 1);
677 QVERIFY(table->cellAt(0, 4) != table->cellAt(1, 4));
678}
679
680void tst_QTextTable::blocksForTableShouldHaveEmptyFormat()
681{
682 QTextBlockFormat fmt;
683 fmt.setProperty(propertyId: QTextFormat::UserProperty, value: true);
684 cursor.insertBlock(format: fmt);
685 QVERIFY(cursor.blockFormat().hasProperty(QTextFormat::UserProperty));
686
687 QTextTable *table = cursor.insertTable(rows: 1, cols: 1);
688 QVERIFY(!table->cellAt(0, 0).firstCursorPosition().blockFormat().hasProperty(QTextFormat::UserProperty));
689
690 int userPropCount = 0;
691 for (QTextBlock block = doc->begin();
692 block.isValid(); block = block.next()) {
693 if (block.blockFormat().hasProperty(propertyId: QTextFormat::UserProperty))
694 userPropCount++;
695 }
696 QCOMPARE(userPropCount, 1);
697}
698
699void tst_QTextTable::removeTableByRemoveRows()
700{
701 QPointer<QTextTable> table1 = QTextCursor(cursor).insertTable(rows: 4, cols: 4);
702 QPointer<QTextTable> table2 = QTextCursor(cursor).insertTable(rows: 4, cols: 4);
703 QPointer<QTextTable> table3 = QTextCursor(cursor).insertTable(rows: 4, cols: 4);
704
705 QVERIFY(table1);
706 QVERIFY(table2);
707 QVERIFY(table3);
708
709 table2->removeRows(pos: 1, num: 1);
710
711 QVERIFY(table1);
712 QVERIFY(table2);
713 QVERIFY(table3);
714
715 table2->removeRows(pos: 0, num: table2->rows());
716
717 QVERIFY(table1);
718 QVERIFY(!table2);
719 QVERIFY(table3);
720}
721
722void tst_QTextTable::removeTableByRemoveColumns()
723{
724 QPointer<QTextTable> table1 = QTextCursor(cursor).insertTable(rows: 4, cols: 4);
725 QPointer<QTextTable> table2 = QTextCursor(cursor).insertTable(rows: 4, cols: 4);
726 QPointer<QTextTable> table3 = QTextCursor(cursor).insertTable(rows: 4, cols: 4);
727
728 QVERIFY(table1);
729 QVERIFY(table2);
730 QVERIFY(table3);
731
732 table2->removeColumns(pos: 1, num: 1);
733
734 QVERIFY(table1);
735 QVERIFY(table2);
736 QVERIFY(table3);
737
738 table2->removeColumns(pos: 0, num: table2->columns());
739
740 QVERIFY(table1);
741 QVERIFY(!table2);
742 QVERIFY(table3);
743}
744
745void tst_QTextTable::setCellFormat()
746{
747 QTextTable *table = cursor.insertTable(rows: 2, cols: 2);
748 table->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "First");
749 table->cellAt(row: 0, col: 1).firstCursorPosition().insertText(text: "Second");
750 table->cellAt(row: 1, col: 0).firstCursorPosition().insertText(text: "Third");
751 table->cellAt(row: 1, col: 1).firstCursorPosition().insertText(text: "Fourth");
752 QTextTableCell cell = table->cellAt(row: 0, col: 0);
753 QTextCharFormat fmt;
754 fmt.setObjectIndex(23);
755 fmt.setBackground(Qt::blue);
756 fmt.setTableCellColumnSpan(25);
757 fmt.setTableCellRowSpan(42);
758 cell.setFormat(fmt);
759 QCOMPARE(cell.format().background().color(), QColor(Qt::blue));
760 QCOMPARE(cell.format().tableCellColumnSpan(), 1);
761 QCOMPARE(cell.format().tableCellRowSpan(), 1);
762}
763
764void tst_QTextTable::removeRows1()
765{
766 QTextTable *table = cursor.insertTable(rows: 2, cols: 2);
767 table->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "First");
768 table->cellAt(row: 0, col: 1).firstCursorPosition().insertText(text: "Second");
769 table->cellAt(row: 1, col: 0).firstCursorPosition().insertText(text: "Third");
770 table->cellAt(row: 1, col: 1).firstCursorPosition().insertText(text: "Fourth");
771 table->removeRows(pos: 0, num: 1);
772 QCOMPARE(table->rows(), 1);
773 QCOMPARE(table->columns(), 2);
774 QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Third"));
775 QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Fourth"));
776}
777
778void tst_QTextTable::removeRows2()
779{
780 QTextTable *table = cursor.insertTable(rows: 2, cols: 2);
781 table->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "First");
782 table->cellAt(row: 0, col: 1).firstCursorPosition().insertText(text: "Second");
783 table->cellAt(row: 1, col: 0).firstCursorPosition().insertText(text: "Third");
784 table->cellAt(row: 1, col: 1).firstCursorPosition().insertText(text: "Fourth");
785 table->removeRows(pos: 1, num: 1);
786 QCOMPARE(table->rows(), 1);
787 QCOMPARE(table->columns(), 2);
788 QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First"));
789 QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Second"));
790}
791
792void tst_QTextTable::removeRows3()
793{
794 QTextTable *table = cursor.insertTable(rows: 3, cols: 2);
795 table->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "First");
796 table->cellAt(row: 0, col: 1).firstCursorPosition().insertText(text: "Second");
797 table->cellAt(row: 1, col: 0).firstCursorPosition().insertText(text: "Third");
798 table->cellAt(row: 1, col: 1).firstCursorPosition().insertText(text: "Fourth");
799 table->cellAt(row: 2, col: 0).firstCursorPosition().insertText(text: "Fifth");
800 table->cellAt(row: 2, col: 1).firstCursorPosition().insertText(text: "Sixth");
801 table->removeRows(pos: 1, num: 1);
802 QCOMPARE(table->rows(), 2);
803 QCOMPARE(table->columns(), 2);
804 QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First"));
805 QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Second"));
806 QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Fifth"));
807 QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Sixth"));
808}
809
810void tst_QTextTable::removeRows4()
811{
812 QTextTable *table = cursor.insertTable(rows: 4, cols: 2);
813 table->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "First");
814 table->cellAt(row: 0, col: 1).firstCursorPosition().insertText(text: "Second");
815 table->cellAt(row: 1, col: 0).firstCursorPosition().insertText(text: "Third");
816 table->cellAt(row: 1, col: 1).firstCursorPosition().insertText(text: "Fourth");
817 table->cellAt(row: 2, col: 0).firstCursorPosition().insertText(text: "Fifth");
818 table->cellAt(row: 2, col: 1).firstCursorPosition().insertText(text: "Sixth");
819 table->cellAt(row: 3, col: 0).firstCursorPosition().insertText(text: "Seventh");
820 table->cellAt(row: 3, col: 1).firstCursorPosition().insertText(text: "Eighth");
821 table->removeRows(pos: 1, num: 2);
822 QCOMPARE(table->rows(), 2);
823 QCOMPARE(table->columns(), 2);
824 QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First"));
825 QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Second"));
826 QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Seventh"));
827 QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Eighth"));
828}
829
830void tst_QTextTable::removeRows5()
831{
832 QTextTable *table = cursor.insertTable(rows: 2,cols: 2);
833 table->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "First");
834 table->cellAt(row: 0, col: 1).firstCursorPosition().insertText(text: "Second");
835 table->cellAt(row: 1, col: 0).firstCursorPosition().insertText(text: "Third");
836 table->cellAt(row: 1, col: 1).firstCursorPosition().insertText(text: "Fourth");
837 table->insertRows(pos: 1,num: 1);
838 table->mergeCells(row: 1,col: 0,numRows: 1,numCols: 2);
839 table->removeRows(pos: 1,num: 1);
840 QCOMPARE(table->rows(), 2);
841 QCOMPARE(table->columns(), 2);
842 QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First"));
843 QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Second"));
844 QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Third"));
845 QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Fourth"));
846}
847
848void tst_QTextTable::removeColumns1()
849{
850 QTextTable *table = cursor.insertTable(rows: 2, cols: 2);
851 table->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "First");
852 table->cellAt(row: 0, col: 1).firstCursorPosition().insertText(text: "Second");
853 table->cellAt(row: 1, col: 0).firstCursorPosition().insertText(text: "Third");
854 table->cellAt(row: 1, col: 1).firstCursorPosition().insertText(text: "Fourth");
855 table->removeColumns(pos: 0, num: 1);
856 QCOMPARE(table->rows(), 2);
857 QCOMPARE(table->columns(), 1);
858 QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Second"));
859 QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Fourth"));
860}
861
862void tst_QTextTable::removeColumns2()
863{
864 QTextTable *table = cursor.insertTable(rows: 2, cols: 2);
865 table->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "First");
866 table->cellAt(row: 0, col: 1).firstCursorPosition().insertText(text: "Second");
867 table->cellAt(row: 1, col: 0).firstCursorPosition().insertText(text: "Third");
868 table->cellAt(row: 1, col: 1).firstCursorPosition().insertText(text: "Fourth");
869 table->removeColumns(pos: 1, num: 1);
870 QCOMPARE(table->rows(), 2);
871 QCOMPARE(table->columns(), 1);
872 QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First"));
873 QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Third"));
874}
875
876void tst_QTextTable::removeColumns3()
877{
878 QTextTable *table = cursor.insertTable(rows: 2, cols: 3);
879 table->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "First");
880 table->cellAt(row: 0, col: 1).firstCursorPosition().insertText(text: "Second");
881 table->cellAt(row: 0, col: 2).firstCursorPosition().insertText(text: "Third");
882 table->cellAt(row: 1, col: 0).firstCursorPosition().insertText(text: "Fourth");
883 table->cellAt(row: 1, col: 1).firstCursorPosition().insertText(text: "Fifth");
884 table->cellAt(row: 1, col: 2).firstCursorPosition().insertText(text: "Sixth");
885 table->removeColumns(pos: 1, num: 1);
886 QCOMPARE(table->rows(), 2);
887 QCOMPARE(table->columns(), 2);
888 QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First"));
889 QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Third"));
890 QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Fourth"));
891 QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Sixth"));
892}
893
894void tst_QTextTable::removeColumns4()
895{
896 QTextTable *table = cursor.insertTable(rows: 2, cols: 4);
897 table->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "First");
898 table->cellAt(row: 0, col: 1).firstCursorPosition().insertText(text: "Second");
899 table->cellAt(row: 0, col: 2).firstCursorPosition().insertText(text: "Third");
900 table->cellAt(row: 0, col: 3).firstCursorPosition().insertText(text: "Fourth");
901 table->cellAt(row: 1, col: 0).firstCursorPosition().insertText(text: "Fifth");
902 table->cellAt(row: 1, col: 1).firstCursorPosition().insertText(text: "Sixth");
903 table->cellAt(row: 1, col: 2).firstCursorPosition().insertText(text: "Seventh");
904 table->cellAt(row: 1, col: 3).firstCursorPosition().insertText(text: "Eighth");
905 table->removeColumns(pos: 1, num: 2);
906 QCOMPARE(table->rows(), 2);
907 QCOMPARE(table->columns(), 2);
908 QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First"));
909 QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Fourth"));
910 QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Fifth"));
911 QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Eighth"));
912}
913
914void tst_QTextTable::removeColumns5()
915{
916 QTextTable *table = cursor.insertTable(rows: 4, cols: 4);
917 QTextCursor tc (doc);
918 tc.setPosition(pos: table->cellAt(row: 2,col: 0).firstPosition());
919 tc.setPosition(pos: table->cellAt(row: 3,col: 1).firstPosition(), mode: QTextCursor::KeepAnchor);
920 table->mergeCells(cursor: tc);
921 QCOMPARE(table->rows(), 4);
922 QCOMPARE(table->columns(), 4);
923 QCOMPARE(table->cellAt(0, 0).firstPosition(), 1);
924 QCOMPARE(table->cellAt(0, 1).firstPosition(), 2);
925 QCOMPARE(table->cellAt(0, 2).firstPosition(), 3);
926 QCOMPARE(table->cellAt(0, 3).firstPosition(), 4);
927 QCOMPARE(table->cellAt(1, 0).firstPosition(), 5);
928 QCOMPARE(table->cellAt(1, 1).firstPosition(), 6);
929 QCOMPARE(table->cellAt(1, 2).firstPosition(), 7);
930 QCOMPARE(table->cellAt(1, 3).firstPosition(), 8);
931 QCOMPARE(table->cellAt(2, 0).firstPosition(), 9);
932 QCOMPARE(table->cellAt(2, 0).rowSpan(), 2);
933 QCOMPARE(table->cellAt(2, 0).columnSpan(), 2);
934 QCOMPARE(table->cellAt(2, 1).firstPosition(), 9);
935 QCOMPARE(table->cellAt(2, 2).firstPosition(), 10);
936 QCOMPARE(table->cellAt(2, 3).firstPosition(), 11);
937 QCOMPARE(table->cellAt(3, 0).firstPosition(), 9);
938 QCOMPARE(table->cellAt(3, 1).firstPosition(), 9);
939 QCOMPARE(table->cellAt(3, 2).firstPosition(), 12);
940 QCOMPARE(table->cellAt(3, 3).firstPosition(), 13);
941
942 table->removeColumns(pos: 1, num: 1);
943 QCOMPARE(table->rows(), 4);
944 QCOMPARE(table->columns(), 3);
945 QCOMPARE(table->cellAt(0, 0).firstPosition(), 1);
946 QCOMPARE(table->cellAt(0, 1).firstPosition(), 2);
947 QCOMPARE(table->cellAt(0, 2).firstPosition(), 3);
948 QCOMPARE(table->cellAt(1, 0).firstPosition(), 4);
949 QCOMPARE(table->cellAt(1, 1).firstPosition(), 5);
950 QCOMPARE(table->cellAt(1, 2).firstPosition(), 6);
951 QCOMPARE(table->cellAt(2, 0).firstPosition(), 7);
952 QCOMPARE(table->cellAt(2, 0).rowSpan(), 2);
953 QCOMPARE(table->cellAt(2, 0).columnSpan(), 1);
954 QCOMPARE(table->cellAt(2, 1).firstPosition(), 8);
955 QCOMPARE(table->cellAt(2, 2).firstPosition(), 9);
956 QCOMPARE(table->cellAt(3, 0).firstPosition(), 7);
957 QCOMPARE(table->cellAt(3, 1).firstPosition(), 10);
958 QCOMPARE(table->cellAt(3, 2).firstPosition(), 11);
959}
960
961void tst_QTextTable::removeColumnsInTableWithMergedRows()
962{
963 QTextTable *table = cursor.insertTable(rows: 3, cols: 4);
964 table->mergeCells(row: 0, col: 0, numRows: 1, numCols: 4);
965 QCOMPARE(table->rows(), 3);
966 QCOMPARE(table->columns(), 4);
967
968 table->removeColumns(pos: 0, num: table->columns() - 1);
969
970 QCOMPARE(table->rows(), 3);
971 QCOMPARE(table->columns(), 1);
972}
973
974#ifndef QT_NO_WIDGETS
975void tst_QTextTable::QTBUG11282_insertBeforeMergedEnding_data()
976{
977 QTest::addColumn<int>(name: "rows");
978 QTest::addColumn<int>(name: "columns");
979 QTest::addColumn<QList<int> >(name: "merge");
980 QTest::addColumn<QList<int> >(name: "insert");
981
982 QTest::newRow(dataTag: "2x3, merge two, insert one") << 2 << 3 << (QList<int>() << 1 << 2 << 2)
983 << (QList<int>() << 1 << 1) ;
984 QTest::newRow(dataTag: "3x4, merge three, insert one") << 3 << 4 << (QList<int>() << 1 << 3 << 3)
985 << (QList<int>() << 1 << 1) ;
986 QTest::newRow(dataTag: "4x3, merge two, insert two") << 4 << 3 << (QList<int>() << 1 << 4 << 2)
987 << (QList<int>() << 1 << 2) ;
988 QTest::newRow(dataTag: "4x4, merge middle two, insert one") << 4 << 4 << (QList<int>() << 1 << 4 << 2)
989 << (QList<int>() << 1 << 1) ;
990}
991
992void tst_QTextTable::QTBUG11282_insertBeforeMergedEnding()
993{
994 QFETCH(int, rows);
995 QFETCH(int, columns);
996 QFETCH(QList<int>, merge);
997 QFETCH(QList<int>, insert);
998 QTextTable *table = cursor.insertTable(rows, cols: columns);
999 QTextEdit *textEdit = new QTextEdit;
1000 textEdit->setDocument(doc);
1001 textEdit->show();
1002 QVERIFY(QTest::qWaitForWindowExposed(textEdit));
1003 table->mergeCells(row: 0,col: merge.at(i: 0), numRows: merge.at(i: 1), numCols: merge.at(i: 2));
1004 //Don't crash !
1005 table->insertColumns(pos: insert.at(i: 0), num: insert.at(i: 1));
1006 //Check that the final size is what we expected
1007 QCOMPARE(table->rows(), rows);
1008 QCOMPARE(table->columns(), columns + insert.at(1));
1009 delete textEdit;
1010}
1011#endif
1012
1013void tst_QTextTable::QTBUG22011_insertBeforeRowSpan()
1014{
1015 QTextDocument doc;
1016 QTextCursor cursor(&doc);
1017 QTextTable *table = cursor.insertTable(rows: 1,cols: 1); // 1x1
1018
1019 table->appendColumns(count: 1); // 1x2
1020 table->appendRows(count: 1); // 2x2
1021 table->mergeCells(row: 0, col: 0, numRows: 2, numCols: 1); // 2x2
1022 table->insertColumns(pos: 1, num: 1); // 2x3
1023 table->mergeCells(row: 0, col: 1, numRows: 1, numCols: 2); // 2x3
1024 table->appendRows(count: 1); // 3x3
1025 table->mergeCells(row: 0, col: 0, numRows: 3, numCols: 1); // 3x3
1026 table->appendRows(count: 1); // 4x3
1027 table->insertColumns(pos: 1, num: 1); // 4x4
1028 table->mergeCells(row: 0, col: 1, numRows: 1, numCols: 3);
1029 table->mergeCells(row: 1, col: 1, numRows: 1, numCols: 2);
1030 table->mergeCells(row: 2, col: 1, numRows: 1, numCols: 2);
1031 table->mergeCells(row: 3, col: 0, numRows: 1, numCols: 2);
1032 table->insertColumns(pos: 3, num: 1); // 4x5
1033 table->mergeCells(row: 0, col: 1, numRows: 1, numCols: 4);
1034
1035 table->appendColumns(count: 1); // 4x6
1036
1037 QCOMPARE(table->rows(), 4);
1038 QCOMPARE(table->columns(), 6);
1039}
1040
1041#if !defined(QT_NO_PRINTER) && defined(QT_BUILD_INTERNAL)
1042namespace {
1043class QTBUG31330_PaintDevice : public QPagedPaintDevice
1044{
1045public:
1046 class PaintEngine : public QPaintEngine
1047 {
1048 public:
1049 QList<QRectF> rects;
1050
1051 PaintEngine()
1052 : QPaintEngine(QPaintEngine::PaintEngineFeatures{ })
1053 {}
1054 virtual Type type() const
1055 {
1056 return User;
1057 }
1058 virtual bool begin(QPaintDevice *)
1059 {
1060 return true;
1061 }
1062 virtual bool end()
1063 {
1064 return true;
1065 }
1066 virtual void updateState(const QPaintEngineState &)
1067 {}
1068 virtual void drawRects(const QRect *, int)
1069 {}
1070 virtual void drawRects(const QRectF *r, int)
1071 {
1072 if (painter()->brush() == QBrush(Qt::green))
1073 {
1074 rects.append(t: *r);
1075 }
1076 }
1077 virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &)
1078 {}
1079 };
1080
1081 class QDummyPagedPaintDevicePrivate : public QPagedPaintDevicePrivate
1082 {
1083 bool setPageLayout(const QPageLayout &newPageLayout) override
1084 {
1085 m_pageLayout = newPageLayout;
1086 return m_pageLayout.isEquivalentTo(other: newPageLayout);
1087 }
1088
1089 bool setPageSize(const QPageSize &pageSize) override
1090 {
1091 m_pageLayout.setPageSize(pageSize);
1092 return m_pageLayout.pageSize().isEquivalentTo(other: pageSize);
1093 }
1094
1095 bool setPageOrientation(QPageLayout::Orientation orientation) override
1096 {
1097 m_pageLayout.setOrientation(orientation);
1098 return m_pageLayout.orientation() == orientation;
1099 }
1100
1101 bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units) override
1102 {
1103 m_pageLayout.setUnits(units);
1104 m_pageLayout.setMargins(margins);
1105 return m_pageLayout.margins() == margins && m_pageLayout.units() == units;
1106 }
1107
1108 QPageLayout pageLayout() const override
1109 {
1110 return m_pageLayout;
1111 }
1112
1113 QPageLayout m_pageLayout;
1114 };
1115
1116 int pages;
1117 QPaintEngine* engine;
1118
1119 QTBUG31330_PaintDevice(QPaintEngine* engine)
1120 : QPagedPaintDevice(new QDummyPagedPaintDevicePrivate), pages(1), engine(engine)
1121 {
1122 QPageLayout layout = pageLayout();
1123 layout.setUnits(QPageLayout::Point);
1124 setPageLayout(layout);
1125 }
1126 virtual int metric(PaintDeviceMetric metric) const
1127 {
1128 if (PdmDevicePixelRatio == metric)
1129 return 1;
1130 if (PdmDevicePixelRatioScaled == metric)
1131 return 1 * QPaintDevice::devicePixelRatioFScale();
1132 if (PdmDpiY == metric)
1133 return 96;
1134 if (PdmDpiX == metric)
1135 return 96;
1136 if (PdmHeight == metric)
1137 return 1000;
1138 if (PdmWidth == metric)
1139 return 700;
1140 return 900;
1141 }
1142 virtual QPaintEngine *paintEngine() const
1143 {
1144 return engine;
1145 }
1146 bool newPage()
1147 {
1148 ++pages;
1149 return true;
1150 }
1151};
1152}
1153
1154void tst_QTextTable::QTBUG31330_renderBackground()
1155{
1156 QTextDocument doc;
1157 QTextCursor cursor(&doc);
1158 QTextTable* table = cursor.insertTable(rows: 4, cols: 2);
1159
1160 QTextTableCell cell = table->cellAt(row: 3, col: 0);
1161
1162 QTextCharFormat cellFormat = cell.format();
1163 cellFormat.setBackground(QBrush(Qt::green));
1164 cell.setFormat(cellFormat);
1165
1166 QTextCursor tc = cell.firstCursorPosition();
1167 for (int i = 0; i < 60; ++i) {
1168 tc.insertBlock();
1169 }
1170 QTBUG31330_PaintDevice::PaintEngine engine;
1171 QTBUG31330_PaintDevice paintDevice(&engine);
1172 paintDevice.setPageSize(QPagedPaintDevice::A4);
1173 doc.print(printer: &paintDevice);
1174
1175 QVERIFY(paintDevice.pages >= 2);
1176 QCOMPARE(engine.rects.count(), paintDevice.pages);
1177 for (int i = 0; i < engine.rects.count(); ++i) {
1178 QRectF rect = engine.rects[i];
1179 QVERIFY(rect.top() > 0);
1180 QVERIFY(rect.bottom() < 1000);
1181 }
1182}
1183#endif
1184
1185void tst_QTextTable::checkBorderAttributes_data()
1186{
1187 QTest::addColumn<QString>(name: "html");
1188 QTest::addColumn<qreal>(name: "topBorderWidth");
1189 QTest::addColumn<qreal>(name: "bottomBorderWidth");
1190 QTest::addColumn<qreal>(name: "leftBorderWidth");
1191 QTest::addColumn<qreal>(name: "rightBorderWidth");
1192 QTest::addColumn<QTextFrameFormat::BorderStyle>(name: "topBorderStyle");
1193 QTest::addColumn<QTextFrameFormat::BorderStyle>(name: "bottomBorderStyle");
1194 QTest::addColumn<QTextFrameFormat::BorderStyle>(name: "leftBorderStyle");
1195 QTest::addColumn<QTextFrameFormat::BorderStyle>(name: "rightBorderStyle");
1196 QTest::addColumn<QBrush>(name: "topBorderBrush");
1197 QTest::addColumn<QBrush>(name: "bottomBorderBrush");
1198 QTest::addColumn<QBrush>(name: "leftBorderBrush");
1199 QTest::addColumn<QBrush>(name: "rightBorderBrush");
1200
1201 const QString tableHtmlStart = QStringLiteral("<html><head><style>");
1202 const QString tableHtmlEnd = QStringLiteral("</style></head><body>"
1203 "<table border=\"1\"><tr><td>One</td><td>Two</td></tr>"
1204 "<tr><td>Three</td><td>Four</td></tr></table></body></html>");
1205 QTest::newRow(dataTag: "1px-solid-colors")
1206 << QString("%1"
1207 "td {"
1208 "border-top: 1px solid red;"
1209 "border-bottom: 1px solid blue;"
1210 "border-left: 1px solid green;"
1211 "border-right: 1px solid yellow;"
1212 "}"
1213 "%2").arg(a: tableHtmlStart).arg(a: tableHtmlEnd)
1214 << 1.0 << 1.0 << 1.0 << 1.0
1215 << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid
1216 << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid
1217 << QBrush(Qt::red) << QBrush(Qt::blue) << QBrush(Qt::darkGreen) << QBrush(Qt::yellow);
1218 QTest::newRow(dataTag: "MixedWidth-solid-colors")
1219 << QString("%1"
1220 "td {"
1221 "border-top: 1px solid red;"
1222 "border-bottom: 2px solid blue;"
1223 "border-left: 3px solid green;"
1224 "border-right: 4px solid yellow;"
1225 "}"
1226 "%2").arg(a: tableHtmlStart).arg(a: tableHtmlEnd)
1227 << 1.0 << 2.0 << 3.0 << 4.0
1228 << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid
1229 << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid
1230 << QBrush(Qt::red) << QBrush(Qt::blue) << QBrush(Qt::darkGreen) << QBrush(Qt::yellow);
1231 QTest::newRow(dataTag: "MixedWidth-MixedStyle-colors")
1232 << QString("%1"
1233 "td {"
1234 "border-top: 1px solid red;"
1235 "border-bottom: 2px dotted blue;"
1236 "border-left: 3px dashed green;"
1237 "border-right: 4px inset yellow;"
1238 "}"
1239 "%2").arg(a: tableHtmlStart).arg(a: tableHtmlEnd)
1240 << 1.0 << 2.0 << 3.0 << 4.0
1241 << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Dotted
1242 << QTextFrameFormat::BorderStyle_Dashed << QTextFrameFormat::BorderStyle_Inset
1243 << QBrush(Qt::red) << QBrush(Qt::blue) << QBrush(Qt::darkGreen) << QBrush(Qt::yellow);
1244}
1245
1246void tst_QTextTable::checkBorderAttributes()
1247{
1248 QFETCH(QString, html);
1249 QFETCH(qreal, topBorderWidth);
1250 QFETCH(qreal, bottomBorderWidth);
1251 QFETCH(qreal, leftBorderWidth);
1252 QFETCH(qreal, rightBorderWidth);
1253 QFETCH(QTextFrameFormat::BorderStyle, topBorderStyle);
1254 QFETCH(QTextFrameFormat::BorderStyle, bottomBorderStyle);
1255 QFETCH(QTextFrameFormat::BorderStyle, leftBorderStyle);
1256 QFETCH(QTextFrameFormat::BorderStyle, rightBorderStyle);
1257 QFETCH(QBrush, topBorderBrush);
1258 QFETCH(QBrush, bottomBorderBrush);
1259 QFETCH(QBrush, leftBorderBrush);
1260 QFETCH(QBrush, rightBorderBrush);
1261
1262 QTextDocument doc;
1263 doc.setHtml(html);
1264 QTextCursor cursor(doc.firstBlock());
1265 cursor.movePosition(op: QTextCursor::Right);
1266
1267 QTextTable *currentTable = cursor.currentTable();
1268 QVERIFY(currentTable);
1269 for (int row = 0; row < 2; row++) {
1270 for (int column = 0; column < 2; column++) {
1271 QTextTableCell cell = currentTable->cellAt(row, col: column);
1272 QTextCharFormat cellFormat = cell.format();
1273 QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellTopBorder), topBorderWidth);
1274 QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellBottomBorder), bottomBorderWidth);
1275 QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellLeftBorder), leftBorderWidth);
1276 QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellRightBorder), rightBorderWidth);
1277 QCOMPARE(cellFormat.property(QTextFormat::TableCellTopBorderStyle), topBorderStyle);
1278 QCOMPARE(cellFormat.property(QTextFormat::TableCellBottomBorderStyle), bottomBorderStyle);
1279 QCOMPARE(cellFormat.property(QTextFormat::TableCellLeftBorderStyle), leftBorderStyle);
1280 QCOMPARE(cellFormat.property(QTextFormat::TableCellRightBorderStyle), rightBorderStyle);
1281 QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellTopBorderBrush), topBorderBrush);
1282 QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellBottomBorderBrush), bottomBorderBrush);
1283 QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellLeftBorderBrush), leftBorderBrush);
1284 QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellRightBorderBrush), rightBorderBrush);
1285 }
1286 }
1287}
1288
1289#ifndef QT_NO_WIDGETS
1290void tst_QTextTable::columnWidthWithSpans()
1291{
1292 cleanup();
1293 init();
1294 QTextTable *table = cursor.insertTable(rows: 4, cols: 4);
1295 QTextEdit textEdit;
1296 textEdit.setDocument(doc);
1297 textEdit.show();
1298 QVERIFY(QTest::qWaitForWindowExposed(&textEdit));
1299
1300 for (int i = 0; i < table->columns(); ++i)
1301 table->cellAt(row: 0, col: i).firstCursorPosition().insertText(text: QString("Header %1").arg(a: i));
1302
1303 QTextBlock block = table->cellAt(row: 0, col: 0).firstCursorPosition().block();
1304 const QRectF beforeRect = table->document()->documentLayout()->blockBoundingRect(block);
1305 table->mergeCells(row: 1, col: 0, numRows: 1, numCols: table->columns());
1306 block = table->cellAt(row: 0, col: 0).firstCursorPosition().block();
1307 const QRectF afterRect = table->document()->documentLayout()->blockBoundingRect(block);
1308 QCOMPARE(afterRect, beforeRect);
1309}
1310
1311void tst_QTextTable::columnWidthWithImage_data()
1312{
1313 const auto imageHtml = [](int width, int height) {
1314 QImage image(width, height, QImage::Format_RGB32);
1315 image.fill(color: Qt::red);
1316 QByteArray imageBytes;
1317 QBuffer buffer(&imageBytes);
1318 buffer.open(openMode: QIODevice::WriteOnly);
1319 image.save(device: &buffer, format: "png");
1320 return QString("<td><img src='data:image/png;base64,%1'/></td>")
1321 .arg(a: QString::fromLatin1(str: imageBytes.toBase64()));
1322 };
1323
1324 QTest::addColumn<QString>(name: "leftHtml");
1325 QTest::addColumn<QString>(name: "rightHtml");
1326 QTest::addColumn<QSize>(name: "imageSize");
1327 QTest::addRow(format: "image")
1328 << imageHtml(500, 32) << "<td></td>" << QSize(500, 32);
1329 QTest::addRow(format: "image, text")
1330 << imageHtml(32, 32) << "<td>abc</td>" << QSize(32, 32);
1331 QTest::addRow(format: "image, 100%% text")
1332 << imageHtml(32, 32) << "<td style='background-color: grey' width='100%'>abc</td>"
1333 << QSize(32, 32);
1334 QTest::addRow(format: "image, image")
1335 << imageHtml(256, 32) << imageHtml(256, 32) << QSize(256, 32);
1336}
1337
1338void tst_QTextTable::columnWidthWithImage()
1339{
1340 const QString tableTemplate = "<table><tr>%1 %2</tr></table>";
1341
1342 QFETCH(QString, leftHtml);
1343 QFETCH(QString, rightHtml);
1344 QFETCH(QSize, imageSize);
1345
1346 QTextDocument doc;
1347 doc.setHtml(tableTemplate.arg(a: leftHtml).arg(a: rightHtml));
1348 QTextEdit textEdit;
1349 textEdit.setDocument(&doc);
1350 textEdit.show();
1351 QVERIFY(QTest::qWaitForWindowExposed(&textEdit));
1352
1353 QTextCursor cursor(doc.firstBlock());
1354 cursor.movePosition(op: QTextCursor::Right);
1355
1356 QTextTable *currentTable = cursor.currentTable();
1357 QVERIFY(currentTable);
1358
1359 QTextBlock block = currentTable->cellAt(row: 0, col: 0).firstCursorPosition().block();
1360 const QRectF leftRect = currentTable->document()->documentLayout()->blockBoundingRect(block);
1361 block = currentTable->cellAt(row: 0, col: 1).firstCursorPosition().block();
1362 const QRectF rightRect = currentTable->document()->documentLayout()->blockBoundingRect(block);
1363 QCOMPARE(leftRect.size().toSize(), imageSize);
1364 QVERIFY(rightRect.left() > leftRect.right());
1365}
1366#endif
1367
1368QTEST_MAIN(tst_QTextTable)
1369#include "tst_qtexttable.moc"
1370

source code of qtbase/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp