1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 
43 #include <QtTest/QtTest>
44 
45 
46 #include <qtextdocument.h>
47 #include <qtextdocumentfragment.h>
48 #include <qtexttable.h>
49 #include <qdebug.h>
50 #include <qtextcursor.h>
51 #include <qtextdocument.h>
52 #include <qtextedit.h>
53 
54 //TESTED_FILES=
55 
56 typedef QList<int> IntList;
57 Q_DECLARE_METATYPE(IntList)
58 
59 QT_FORWARD_DECLARE_CLASS(QTextDocument)
60 
61 class tst_QTextTable : public QObject
62 {
63     Q_OBJECT
64 
65 public:
66     tst_QTextTable();
67 
68 
69 public slots:
70     void init();
71     void cleanup();
72 private slots:
73     void cursorPositioning();
74     void variousTableModifications();
75     void tableShrinking();
76     void spans();
77     void variousModifications2();
78     void tableManager_undo();
79     void tableManager_removeCell();
80     void rowAt();
81     void rowAtWithSpans();
82     void multiBlockCells();
83     void insertRows();
84     void deleteInTable();
85     void mergeCells();
86     void mergeAndInsert();
87     void splitCells();
88     void blocksForTableShouldHaveEmptyFormat();
89     void removeTableByRemoveRows();
90     void removeTableByRemoveColumns();
91     void setCellFormat();
92     void removeRows1();
93     void removeRows2();
94     void removeRows3();
95     void removeRows4();
96     void removeRows5();
97     void removeColumns1();
98     void removeColumns2();
99     void removeColumns3();
100     void removeColumns4();
101     void removeColumns5();
102     void removeColumnsInTableWithMergedRows();
103     void QTBUG11282_insertBeforeMergedEnding_data();
104     void QTBUG11282_insertBeforeMergedEnding();
105     void QTBUG22011_insertBeforeRowSpan();
106 
107 private:
108     QTextTable *create2x2Table();
109     QTextTable *create4x4Table();
110 
111     QTextTable *createTable(int rows, int cols);
112 
113     QTextDocument *doc;
114     QTextCursor cursor;
115 };
116 
tst_QTextTable()117 tst_QTextTable::tst_QTextTable()
118 {}
119 
init()120 void tst_QTextTable::init()
121 {
122     doc = new QTextDocument;
123     cursor = QTextCursor(doc);
124 }
125 
cleanup()126 void tst_QTextTable::cleanup()
127 {
128     cursor = QTextCursor();
129     delete doc;
130     doc = 0;
131 }
132 
cursorPositioning()133 void tst_QTextTable::cursorPositioning()
134 {
135     // ensure the cursor is placed at the beginning of the first cell upon
136     // table creation
137     QTextTable *table = cursor.insertTable(2, 2);
138 
139     QVERIFY(cursor == table->cellAt(0, 0).firstCursorPosition());
140     QVERIFY(table->cellAt(0, 0).firstPosition() == table->firstPosition());
141 }
142 
variousTableModifications()143 void tst_QTextTable::variousTableModifications()
144 {
145     QTextTableFormat tableFmt;
146 
147     QTextTable *tab = cursor.insertTable(2, 2, tableFmt);
148     QVERIFY(doc->toPlainText().length() == 5);
149     QVERIFY(tab == cursor.currentTable());
150     QVERIFY(tab->columns() == 2);
151     QVERIFY(tab->rows() == 2);
152 
153     QVERIFY(cursor.position() == 1);
154     QTextCharFormat fmt = cursor.charFormat();
155     QVERIFY(fmt.objectIndex() == -1);
156     QTextTableCell cell = tab->cellAt(cursor);
157     QVERIFY(cell.isValid());
158     QVERIFY(cell.row() == 0);
159     QVERIFY(cell.column() == 0);
160 
161     cursor.movePosition(QTextCursor::NextBlock);
162     QVERIFY(cursor.position() == 2);
163     fmt = cursor.charFormat();
164     QVERIFY(fmt.objectIndex() == -1);
165     cell = tab->cellAt(cursor);
166     QVERIFY(cell.isValid());
167     QVERIFY(cell.row() == 0);
168     QVERIFY(cell.column() == 1);
169 
170     cursor.movePosition(QTextCursor::NextBlock);
171     QVERIFY(cursor.position() == 3);
172     fmt = cursor.charFormat();
173     QVERIFY(fmt.objectIndex() == -1);
174     cell = tab->cellAt(cursor);
175     QVERIFY(cell.isValid());
176     QVERIFY(cell.row() == 1);
177     QVERIFY(cell.column() == 0);
178 
179     cursor.movePosition(QTextCursor::NextBlock);
180     QVERIFY(cursor.position() == 4);
181     fmt = cursor.charFormat();
182     QVERIFY(fmt.objectIndex() == -1);
183     cell = tab->cellAt(cursor);
184     QVERIFY(cell.isValid());
185     QVERIFY(cell.row() == 1);
186     QVERIFY(cell.column() == 1);
187 
188     cursor.movePosition(QTextCursor::NextBlock);
189     QVERIFY(cursor.position() == 5);
190     fmt = cursor.charFormat();
191     QVERIFY(fmt.objectIndex() == -1);
192     cell = tab->cellAt(cursor);
193     QVERIFY(!cell.isValid());
194 
195     cursor.movePosition(QTextCursor::NextBlock);
196     QVERIFY(cursor.position() == 5);
197 
198     // check we can't delete the cells with the cursor
199     cursor.movePosition(QTextCursor::Start);
200     cursor.movePosition(QTextCursor::NextBlock);
201     QVERIFY(cursor.position() == 1);
202     cursor.deleteChar();
203     QVERIFY(doc->toPlainText().length() == 5);
204     cursor.movePosition(QTextCursor::NextBlock);
205     QVERIFY(cursor.position() == 2);
206     cursor.deleteChar();
207     QVERIFY(doc->toPlainText().length() == 5);
208     cursor.deletePreviousChar();
209     QVERIFY(cursor.position() == 2);
210     QVERIFY(doc->toPlainText().length() == 5);
211 
212     QTextTable *table = cursor.currentTable();
213     QVERIFY(table->rows() == 2);
214     QVERIFY(table->columns() == 2);
215 
216     table->insertRows(2, 1);
217     QVERIFY(table->rows() == 3);
218     QVERIFY(table->columns() == 2);
219     QVERIFY(doc->toPlainText().length() == 7);
220     table->insertColumns(2, 2);
221     QVERIFY(table->rows() == 3);
222     QVERIFY(table->columns() == 4);
223     QVERIFY(doc->toPlainText().length() == 13);
224 
225     table->resize(4, 5);
226     QVERIFY(table->rows() == 4);
227     QVERIFY(table->columns() == 5);
228     QVERIFY(doc->toPlainText().length() == 21);
229 }
230 
tableShrinking()231 void tst_QTextTable::tableShrinking()
232 {
233     QTextTableFormat tableFmt;
234 
235     cursor.insertTable(3, 4, tableFmt);
236     QVERIFY(doc->toPlainText().length() == 13);
237 
238     QTextTable *table = cursor.currentTable();
239     QVERIFY(table->rows() == 3);
240     QVERIFY(table->columns() == 4);
241 
242     table->removeRows(1, 1);
243     QVERIFY(table->rows() == 2);
244     QVERIFY(table->columns() == 4);
245     QVERIFY(doc->toPlainText().length() == 9);
246     table->removeColumns(1, 2);
247     QVERIFY(table->rows() == 2);
248     QVERIFY(table->columns() == 2);
249     QVERIFY(doc->toPlainText().length() == 5);
250 
251     table->resize(1, 1);
252     QVERIFY(table->rows() == 1);
253     QVERIFY(table->columns() == 1);
254     QVERIFY(doc->toPlainText().length() == 2);
255 }
256 
spans()257 void tst_QTextTable::spans()
258 {
259     QTextTableFormat tableFmt;
260 
261     cursor.insertTable(2, 2, tableFmt);
262 
263     QTextTable *table = cursor.currentTable();
264     QVERIFY(table->cellAt(0, 0) != table->cellAt(0, 1));
265     table->mergeCells(0, 0, 1, 2);
266     QVERIFY(table->rows() == 2);
267     QVERIFY(table->columns() == 2);
268     QVERIFY(table->cellAt(0, 0) == table->cellAt(0, 1));
269     table->mergeCells(0, 0, 2, 2);
270     QVERIFY(table->rows() == 2);
271     QVERIFY(table->columns() == 2);
272 }
273 
variousModifications2()274 void tst_QTextTable::variousModifications2()
275 {
276     QTextTableFormat tableFmt;
277 
278     cursor.insertTable(2, 5, tableFmt);
279     QVERIFY(doc->toPlainText().length() == 11);
280     QTextTable *table = cursor.currentTable();
281     QVERIFY(cursor.position() == 1);
282     QVERIFY(table->rows() == 2);
283     QVERIFY(table->columns() == 5);
284 
285     table->insertColumns(0, 1);
286     QVERIFY(table->rows() == 2);
287     QVERIFY(table->columns() == 6);
288     table->insertColumns(6, 1);
289     QVERIFY(table->rows() == 2);
290     QVERIFY(table->columns() == 7);
291 
292     table->insertRows(0, 1);
293     QVERIFY(table->rows() == 3);
294     QVERIFY(table->columns() == 7);
295     table->insertRows(3, 1);
296     QVERIFY(table->rows() == 4);
297     QVERIFY(table->columns() == 7);
298 
299     table->removeRows(0, 1);
300     QVERIFY(table->rows() == 3);
301     QVERIFY(table->columns() == 7);
302     table->removeRows(2, 1);
303     QVERIFY(table->rows() == 2);
304     QVERIFY(table->columns() == 7);
305 
306     table->removeColumns(0, 1);
307     QVERIFY(table->rows() == 2);
308     QVERIFY(table->columns() == 6);
309     table->removeColumns(5, 1);
310     QVERIFY(table->rows() == 2);
311     QVERIFY(table->columns() == 5);
312 
313     tableFmt = table->format();
314     table->insertColumns(2, 1);
315     table->setFormat(tableFmt);
316     table->insertColumns(2, 1);
317     QVERIFY(table->columns() == 7);
318 }
319 
tableManager_undo()320 void tst_QTextTable::tableManager_undo()
321 {
322     QTextTableFormat fmt;
323     fmt.setBorder(10);
324     QTextTable *table = cursor.insertTable(2, 2, fmt);
325     QVERIFY(table);
326 
327     QVERIFY(table->format().border() == 10);
328 
329     fmt.setBorder(20);
330     table->setFormat(fmt);
331 
332     QVERIFY(table->format().border() == 20);
333 
334     doc->undo();
335 
336     QVERIFY(table->format().border() == 10);
337 }
338 
tableManager_removeCell()339 void tst_QTextTable::tableManager_removeCell()
340 {
341     // essentially a test for TableManager::removeCell, in particular to remove empty items from the rowlist.
342     // If it fails it'll triger assertions inside TableManager. Yeah, not pretty, should VERIFY here ;(
343     cursor.insertTable(2, 2, QTextTableFormat());
344     doc->undo();
345     // ###
346     QVERIFY(true);
347 }
348 
rowAt()349 void tst_QTextTable::rowAt()
350 {
351     // test TablePrivate::rowAt
352     QTextTable *table = cursor.insertTable(4, 2);
353 
354     QCOMPARE(table->rows(), 4);
355     QCOMPARE(table->columns(), 2);
356 
357     QTextCursor cell00Cursor = table->cellAt(0, 0).firstCursorPosition();
358     QTextCursor cell10Cursor = table->cellAt(1, 0).firstCursorPosition();
359     QTextCursor cell20Cursor = table->cellAt(2, 0).firstCursorPosition();
360     QTextCursor cell21Cursor = table->cellAt(2, 1).firstCursorPosition();
361     QTextCursor cell30Cursor = table->cellAt(3, 0).firstCursorPosition();
362     QVERIFY(table->cellAt(cell00Cursor).firstCursorPosition() == cell00Cursor);
363     QVERIFY(table->cellAt(cell10Cursor).firstCursorPosition() == cell10Cursor);
364     QVERIFY(table->cellAt(cell20Cursor).firstCursorPosition() == cell20Cursor);
365     QVERIFY(table->cellAt(cell30Cursor).firstCursorPosition() == cell30Cursor);
366 
367     table->mergeCells(1, 0, 2, 1);
368 
369     QCOMPARE(table->rows(), 4);
370     QCOMPARE(table->columns(), 2);
371 
372     QVERIFY(cell00Cursor == table->cellAt(0, 0).firstCursorPosition());
373     QVERIFY(cell10Cursor == table->cellAt(1, 0).firstCursorPosition());
374     QVERIFY(cell10Cursor == table->cellAt(2, 0).firstCursorPosition());
375     QVERIFY(cell21Cursor == table->cellAt(2, 1).firstCursorPosition());
376     QVERIFY(cell30Cursor == table->cellAt(3, 0).firstCursorPosition());
377 
378     table->mergeCells(1, 0, 2, 2);
379 
380     QCOMPARE(table->rows(), 4);
381     QCOMPARE(table->columns(), 2);
382 
383     QVERIFY(cell00Cursor == table->cellAt(0, 0).firstCursorPosition());
384     QVERIFY(cell00Cursor == table->cellAt(0, 0).firstCursorPosition());
385     QVERIFY(cell10Cursor == table->cellAt(1, 0).firstCursorPosition());
386     QVERIFY(cell10Cursor == table->cellAt(1, 1).firstCursorPosition());
387     QVERIFY(cell10Cursor == table->cellAt(2, 0).firstCursorPosition());
388     QVERIFY(cell10Cursor == table->cellAt(2, 1).firstCursorPosition());
389     QVERIFY(cell30Cursor == table->cellAt(3, 0).firstCursorPosition());
390 }
391 
rowAtWithSpans()392 void tst_QTextTable::rowAtWithSpans()
393 {
394     QTextTable *table = cursor.insertTable(2, 2);
395 
396     QCOMPARE(table->rows(), 2);
397     QCOMPARE(table->columns(), 2);
398 
399     table->mergeCells(0, 0, 2, 1);
400     QVERIFY(table->cellAt(0, 0).rowSpan() == 2);
401 
402     QCOMPARE(table->rows(), 2);
403     QCOMPARE(table->columns(), 2);
404 
405     table->mergeCells(0, 0, 2, 2);
406     QVERIFY(table->cellAt(0, 0).columnSpan() == 2);
407 
408     QCOMPARE(table->rows(), 2);
409     QCOMPARE(table->columns(), 2);
410 }
411 
multiBlockCells()412 void tst_QTextTable::multiBlockCells()
413 {
414     // little testcase for multi-block cells
415     QTextTable *table = cursor.insertTable(2, 2);
416 
417     QVERIFY(cursor == table->cellAt(0, 0).firstCursorPosition());
418 
419     cursor.insertText("Hello");
420     cursor.insertBlock(QTextBlockFormat());
421     cursor.insertText("World");
422 
423     cursor.movePosition(QTextCursor::Left);
424     QVERIFY(table->cellAt(0, 0) == table->cellAt(cursor));
425 }
426 
insertRows()427 void tst_QTextTable::insertRows()
428 {
429     // little testcase for multi-block cells
430     QTextTable *table = cursor.insertTable(2, 2);
431 
432     QVERIFY(cursor == table->cellAt(0, 0).firstCursorPosition());
433 
434     table->insertRows(0, 1);
435     QVERIFY(table->rows() == 3);
436 
437     table->insertRows(1, 1);
438     QVERIFY(table->rows() == 4);
439 
440     table->insertRows(-1, 1);
441     QVERIFY(table->rows() == 5);
442 
443     table->insertRows(5, 2);
444     QVERIFY(table->rows() == 7);
445 
446 }
447 
deleteInTable()448 void tst_QTextTable::deleteInTable()
449 {
450     QTextTable *table = cursor.insertTable(2, 2);
451     table->cellAt(0, 0).firstCursorPosition().insertText("Blah");
452     table->cellAt(0, 1).firstCursorPosition().insertText("Foo");
453     table->cellAt(1, 0).firstCursorPosition().insertText("Bar");
454     table->cellAt(1, 1).firstCursorPosition().insertText("Hah");
455 
456     cursor = table->cellAt(1, 1).firstCursorPosition();
457     cursor.movePosition(QTextCursor::PreviousBlock, QTextCursor::KeepAnchor);
458 
459     QCOMPARE(table->cellAt(cursor.position()).row(), 1);
460     QCOMPARE(table->cellAt(cursor.position()).column(), 0);
461 
462     cursor.removeSelectedText();
463 
464     QCOMPARE(table->columns(), 2);
465     QCOMPARE(table->rows(), 2);
466 
467     // verify table is still all in shape. Only the text inside should get deleted
468     for (int row = 0; row < table->rows(); ++row)
469         for (int col = 0; col < table->columns(); ++col) {
470             const QTextTableCell cell = table->cellAt(row, col);
471             QVERIFY(cell.isValid());
472             QCOMPARE(cell.rowSpan(), 1);
473             QCOMPARE(cell.columnSpan(), 1);
474         }
475 }
476 
create2x2Table()477 QTextTable *tst_QTextTable::create2x2Table()
478 {
479     cleanup();
480     init();
481     QTextTable *table = cursor.insertTable(2, 2);
482     table->cellAt(0, 0).firstCursorPosition().insertText("Blah");
483     table->cellAt(0, 1).firstCursorPosition().insertText("Foo");
484     table->cellAt(1, 0).firstCursorPosition().insertText("Bar");
485     table->cellAt(1, 1).firstCursorPosition().insertText("Hah");
486     return table;
487 }
488 
create4x4Table()489 QTextTable *tst_QTextTable::create4x4Table()
490 {
491     cleanup();
492     init();
493     QTextTable *table = cursor.insertTable(4, 4);
494     table->cellAt(0, 0).firstCursorPosition().insertText("Blah");
495     table->cellAt(0, 1).firstCursorPosition().insertText("Foo");
496     table->cellAt(1, 0).firstCursorPosition().insertText("Bar");
497     table->cellAt(1, 1).firstCursorPosition().insertText("Hah");
498     return table;
499 }
500 
createTable(int rows,int cols)501 QTextTable *tst_QTextTable::createTable(int rows, int cols)
502 {
503     cleanup();
504     init();
505     QTextTable *table = cursor.insertTable(rows, cols);
506     return table;
507 }
508 
mergeCells()509 void tst_QTextTable::mergeCells()
510 {
511     QTextTable *table = create4x4Table();
512 
513     table->mergeCells(1, 1, 1, 2);
514     QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2));
515 
516     table->mergeCells(1, 1, 2, 2);
517     QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2));
518     QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1));
519     QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2));
520 
521     table = create4x4Table();
522 
523     table->mergeCells(1, 1, 2, 1);
524     QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1));
525 
526     table->mergeCells(1, 1, 2, 2);
527     QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2));
528     QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1));
529     QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2));
530 
531     table = create4x4Table();
532 
533     table->mergeCells(1, 1, 2, 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     // should do nothing
539     table->mergeCells(1, 1, 1, 1);
540     QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2));
541     QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1));
542     QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2));
543 
544     table = create2x2Table();
545 
546     table->mergeCells(0, 1, 2, 1);
547     table->mergeCells(0, 0, 2, 2);
548     QVERIFY(table->cellAt(0, 0) == table->cellAt(0, 1));
549     QVERIFY(table->cellAt(0, 0) == table->cellAt(1, 0));
550     QVERIFY(table->cellAt(0, 0) == table->cellAt(1, 1));
551 
552     QTextBlock block = table->cellAt(0, 0).firstCursorPosition().block();
553 
554     QVERIFY(block.text() == "Blah Foo");
555     QVERIFY(block.next().text() == "Hah");
556     QVERIFY(block.next().next().text() == "Bar");
557 
558     table = create4x4Table();
559 
560     QTextCursor cursor = table->cellAt(3, 3).firstCursorPosition();
561     QTextTable *t2 = cursor.insertTable(2, 2);
562     t2->cellAt(0, 0).firstCursorPosition().insertText("Test");
563 
564     table->mergeCells(2, 2, 2, 2);
565     cursor = table->cellAt(2, 2).firstCursorPosition();
566 
567     QTextFrame *frame = cursor.currentFrame();
568 
569     QTextFrame::iterator it = frame->begin();
570 
571     // find the embedded table
572     while (it != frame->end() && !it.currentFrame())
573         ++it;
574 
575     table = qobject_cast<QTextTable *>(it.currentFrame());
576 
577     QVERIFY(table);
578 
579     if (table) {
580         cursor = table->cellAt(0, 0).firstCursorPosition();
581 
582         QVERIFY(cursor.block().text() == "Test");
583     }
584 
585     table = create2x2Table();
586 
587     table->mergeCells(0, 1, 2, 1);
588 
589     QVERIFY(table->cellAt(0, 0) != table->cellAt(0, 1));
590     QVERIFY(table->cellAt(0, 1) == table->cellAt(1, 1));
591 
592     // should do nothing
593     table->mergeCells(0, 0, 1, 2);
594 
595     QVERIFY(table->cellAt(0, 0) != table->cellAt(0, 1));
596     QVERIFY(table->cellAt(0, 1) == table->cellAt(1, 1));
597 }
598 
mergeAndInsert()599 void tst_QTextTable::mergeAndInsert()
600 {
601     QTextTable *table = cursor.insertTable(4,3);
602     table->mergeCells(0,1,3,2);
603     table->mergeCells(3,0,1,3);
604     //Don't crash !
605     table->insertColumns(1,2);
606     QCOMPARE(table->columns(), 5);
607 }
608 
splitCells()609 void tst_QTextTable::splitCells()
610 {
611     QTextTable *table = create4x4Table();
612     table->mergeCells(1, 1, 2, 2);
613     QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2));
614     QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1));
615     QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2));
616 
617     table->splitCell(1, 1, 1, 2);
618     QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2));
619     QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 1));
620     QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 2));
621 
622     table->splitCell(1, 1, 1, 1);
623     QVERIFY(table->cellAt(1, 1) != table->cellAt(1, 2));
624     QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 1));
625     QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 2));
626 
627 
628     table = create4x4Table();
629     table->mergeCells(1, 1, 2, 2);
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     table->splitCell(1, 1, 2, 1);
635     QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1));
636     QVERIFY(table->cellAt(1, 1) != table->cellAt(1, 2));
637     QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 2));
638 
639     table->splitCell(1, 1, 1, 1);
640     QVERIFY(table->cellAt(1, 1) != table->cellAt(1, 2));
641     QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 1));
642     QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 2));
643 
644 
645     table = create4x4Table();
646     table->mergeCells(1, 1, 2, 2);
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     table->splitCell(1, 1, 1, 1);
652     QVERIFY(table->cellAt(1, 1) != table->cellAt(1, 2));
653     QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 1));
654     QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 2));
655 
656     table = createTable(2, 5);
657     table->mergeCells(0, 0, 2, 1);
658     table->mergeCells(0, 1, 2, 1);
659     QVERIFY(table->cellAt(0, 0) == table->cellAt(1, 0));
660     QVERIFY(table->cellAt(0, 1) == table->cellAt(1, 1));
661     table->splitCell(0, 0, 1, 1);
662     QVERIFY(table->cellAt(0, 0) != table->cellAt(1, 0));
663     QVERIFY(table->cellAt(0, 1) == table->cellAt(1, 1));
664 
665     table = createTable(2, 5);
666     table->mergeCells(0, 4, 2, 1);
667     QVERIFY(table->cellAt(0, 4) == table->cellAt(1, 4));
668 
669     table->splitCell(0, 4, 1, 1);
670     QVERIFY(table->cellAt(0, 4) != table->cellAt(1, 4));
671 }
672 
blocksForTableShouldHaveEmptyFormat()673 void tst_QTextTable::blocksForTableShouldHaveEmptyFormat()
674 {
675     QTextBlockFormat fmt;
676     fmt.setProperty(QTextFormat::UserProperty, true);
677     cursor.insertBlock(fmt);
678     QVERIFY(cursor.blockFormat().hasProperty(QTextFormat::UserProperty));
679 
680     QTextTable *table = cursor.insertTable(1, 1);
681     QVERIFY(!table->cellAt(0, 0).firstCursorPosition().blockFormat().hasProperty(QTextFormat::UserProperty));
682 
683     int userPropCount = 0;
684     for (QTextBlock block = doc->begin();
685          block.isValid(); block = block.next()) {
686         if (block.blockFormat().hasProperty(QTextFormat::UserProperty))
687             userPropCount++;
688     }
689     QCOMPARE(userPropCount, 1);
690 }
691 
removeTableByRemoveRows()692 void tst_QTextTable::removeTableByRemoveRows()
693 {
694     QPointer<QTextTable> table1 = QTextCursor(cursor).insertTable(4, 4);
695     QPointer<QTextTable> table2 = QTextCursor(cursor).insertTable(4, 4);
696     QPointer<QTextTable> table3 = QTextCursor(cursor).insertTable(4, 4);
697 
698     QVERIFY(table1);
699     QVERIFY(table2);
700     QVERIFY(table3);
701 
702     table2->removeRows(1, 1);
703 
704     QVERIFY(table1);
705     QVERIFY(table2);
706     QVERIFY(table3);
707 
708     table2->removeRows(0, table2->rows());
709 
710     QVERIFY(table1);
711     QVERIFY(!table2);
712     QVERIFY(table3);
713 }
714 
removeTableByRemoveColumns()715 void tst_QTextTable::removeTableByRemoveColumns()
716 {
717     QPointer<QTextTable> table1 = QTextCursor(cursor).insertTable(4, 4);
718     QPointer<QTextTable> table2 = QTextCursor(cursor).insertTable(4, 4);
719     QPointer<QTextTable> table3 = QTextCursor(cursor).insertTable(4, 4);
720 
721     QVERIFY(table1);
722     QVERIFY(table2);
723     QVERIFY(table3);
724 
725     table2->removeColumns(1, 1);
726 
727     QVERIFY(table1);
728     QVERIFY(table2);
729     QVERIFY(table3);
730 
731     table2->removeColumns(0, table2->columns());
732 
733     QVERIFY(table1);
734     QVERIFY(!table2);
735     QVERIFY(table3);
736 }
737 
setCellFormat()738 void tst_QTextTable::setCellFormat()
739 {
740     QTextTable *table = cursor.insertTable(2, 2);
741     table->cellAt(0, 0).firstCursorPosition().insertText("First");
742     table->cellAt(0, 1).firstCursorPosition().insertText("Second");
743     table->cellAt(1, 0).firstCursorPosition().insertText("Third");
744     table->cellAt(1, 1).firstCursorPosition().insertText("Fourth");
745     QTextTableCell cell = table->cellAt(0, 0);
746     QTextCharFormat fmt;
747     fmt.setObjectIndex(23);
748     fmt.setBackground(Qt::blue);
749     fmt.setTableCellColumnSpan(25);
750     fmt.setTableCellRowSpan(42);
751     cell.setFormat(fmt);
752     QVERIFY(cell.format().background().color() == QColor(Qt::blue));
753     QCOMPARE(cell.format().tableCellColumnSpan(), 1);
754     QCOMPARE(cell.format().tableCellRowSpan(), 1);
755 }
756 
removeRows1()757 void tst_QTextTable::removeRows1()
758 {
759     QTextTable *table = cursor.insertTable(2, 2);
760     table->cellAt(0, 0).firstCursorPosition().insertText("First");
761     table->cellAt(0, 1).firstCursorPosition().insertText("Second");
762     table->cellAt(1, 0).firstCursorPosition().insertText("Third");
763     table->cellAt(1, 1).firstCursorPosition().insertText("Fourth");
764     table->removeRows(0, 1);
765     QCOMPARE(table->rows(), 1);
766     QCOMPARE(table->columns(), 2);
767     QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Third"));
768     QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Fourth"));
769 }
770 
removeRows2()771 void tst_QTextTable::removeRows2()
772 {
773     QTextTable *table = cursor.insertTable(2, 2);
774     table->cellAt(0, 0).firstCursorPosition().insertText("First");
775     table->cellAt(0, 1).firstCursorPosition().insertText("Second");
776     table->cellAt(1, 0).firstCursorPosition().insertText("Third");
777     table->cellAt(1, 1).firstCursorPosition().insertText("Fourth");
778     table->removeRows(1, 1);
779     QCOMPARE(table->rows(), 1);
780     QCOMPARE(table->columns(), 2);
781     QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First"));
782     QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Second"));
783 }
784 
removeRows3()785 void tst_QTextTable::removeRows3()
786 {
787     QTextTable *table = cursor.insertTable(3, 2);
788     table->cellAt(0, 0).firstCursorPosition().insertText("First");
789     table->cellAt(0, 1).firstCursorPosition().insertText("Second");
790     table->cellAt(1, 0).firstCursorPosition().insertText("Third");
791     table->cellAt(1, 1).firstCursorPosition().insertText("Fourth");
792     table->cellAt(2, 0).firstCursorPosition().insertText("Fifth");
793     table->cellAt(2, 1).firstCursorPosition().insertText("Sixth");
794     table->removeRows(1, 1);
795     QCOMPARE(table->rows(), 2);
796     QCOMPARE(table->columns(), 2);
797     QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First"));
798     QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Second"));
799     QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Fifth"));
800     QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Sixth"));
801 }
802 
removeRows4()803 void tst_QTextTable::removeRows4()
804 {
805     QTextTable *table = cursor.insertTable(4, 2);
806     table->cellAt(0, 0).firstCursorPosition().insertText("First");
807     table->cellAt(0, 1).firstCursorPosition().insertText("Second");
808     table->cellAt(1, 0).firstCursorPosition().insertText("Third");
809     table->cellAt(1, 1).firstCursorPosition().insertText("Fourth");
810     table->cellAt(2, 0).firstCursorPosition().insertText("Fifth");
811     table->cellAt(2, 1).firstCursorPosition().insertText("Sixth");
812     table->cellAt(3, 0).firstCursorPosition().insertText("Seventh");
813     table->cellAt(3, 1).firstCursorPosition().insertText("Eighth");
814     table->removeRows(1, 2);
815     QCOMPARE(table->rows(), 2);
816     QCOMPARE(table->columns(), 2);
817     QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First"));
818     QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Second"));
819     QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Seventh"));
820     QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Eighth"));
821 }
822 
removeRows5()823 void tst_QTextTable::removeRows5()
824 {
825     QTextTable *table = cursor.insertTable(2,2);
826     table->cellAt(0, 0).firstCursorPosition().insertText("First");
827     table->cellAt(0, 1).firstCursorPosition().insertText("Second");
828     table->cellAt(1, 0).firstCursorPosition().insertText("Third");
829     table->cellAt(1, 1).firstCursorPosition().insertText("Fourth");
830     table->insertRows(1,1);
831     table->mergeCells(1,0,1,2);
832     table->removeRows(1,1);
833     QCOMPARE(table->rows(), 2);
834     QCOMPARE(table->columns(), 2);
835     QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First"));
836     QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Second"));
837     QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Third"));
838     QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Fourth"));
839 }
840 
removeColumns1()841 void tst_QTextTable::removeColumns1()
842 {
843     QTextTable *table = cursor.insertTable(2, 2);
844     table->cellAt(0, 0).firstCursorPosition().insertText("First");
845     table->cellAt(0, 1).firstCursorPosition().insertText("Second");
846     table->cellAt(1, 0).firstCursorPosition().insertText("Third");
847     table->cellAt(1, 1).firstCursorPosition().insertText("Fourth");
848     table->removeColumns(0, 1);
849     QCOMPARE(table->rows(), 2);
850     QCOMPARE(table->columns(), 1);
851     QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Second"));
852     QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Fourth"));
853 }
854 
removeColumns2()855 void tst_QTextTable::removeColumns2()
856 {
857     QTextTable *table = cursor.insertTable(2, 2);
858     table->cellAt(0, 0).firstCursorPosition().insertText("First");
859     table->cellAt(0, 1).firstCursorPosition().insertText("Second");
860     table->cellAt(1, 0).firstCursorPosition().insertText("Third");
861     table->cellAt(1, 1).firstCursorPosition().insertText("Fourth");
862     table->removeColumns(1, 1);
863     QCOMPARE(table->rows(), 2);
864     QCOMPARE(table->columns(), 1);
865     QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First"));
866     QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Third"));
867 }
868 
removeColumns3()869 void tst_QTextTable::removeColumns3()
870 {
871     QTextTable *table = cursor.insertTable(2, 3);
872     table->cellAt(0, 0).firstCursorPosition().insertText("First");
873     table->cellAt(0, 1).firstCursorPosition().insertText("Second");
874     table->cellAt(0, 2).firstCursorPosition().insertText("Third");
875     table->cellAt(1, 0).firstCursorPosition().insertText("Fourth");
876     table->cellAt(1, 1).firstCursorPosition().insertText("Fifth");
877     table->cellAt(1, 2).firstCursorPosition().insertText("Sixth");
878     table->removeColumns(1, 1);
879     QCOMPARE(table->rows(), 2);
880     QCOMPARE(table->columns(), 2);
881     QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First"));
882     QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Third"));
883     QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Fourth"));
884     QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Sixth"));
885 }
886 
removeColumns4()887 void tst_QTextTable::removeColumns4()
888 {
889     QTextTable *table = cursor.insertTable(2, 4);
890     table->cellAt(0, 0).firstCursorPosition().insertText("First");
891     table->cellAt(0, 1).firstCursorPosition().insertText("Second");
892     table->cellAt(0, 2).firstCursorPosition().insertText("Third");
893     table->cellAt(0, 3).firstCursorPosition().insertText("Fourth");
894     table->cellAt(1, 0).firstCursorPosition().insertText("Fifth");
895     table->cellAt(1, 1).firstCursorPosition().insertText("Sixth");
896     table->cellAt(1, 2).firstCursorPosition().insertText("Seventh");
897     table->cellAt(1, 3).firstCursorPosition().insertText("Eighth");
898     table->removeColumns(1, 2);
899     QCOMPARE(table->rows(), 2);
900     QCOMPARE(table->columns(), 2);
901     QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First"));
902     QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Fourth"));
903     QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Fifth"));
904     QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Eighth"));
905 }
906 
removeColumns5()907 void tst_QTextTable::removeColumns5()
908 {
909     QTextTable *table = cursor.insertTable(4, 4);
910     QTextCursor tc (doc);
911     tc.setPosition(table->cellAt(2,0).firstPosition());
912     tc.setPosition(table->cellAt(3,1).firstPosition(), QTextCursor::KeepAnchor);
913     table->mergeCells(tc);
914     QCOMPARE(table->rows(), 4);
915     QCOMPARE(table->columns(), 4);
916     QCOMPARE(table->cellAt(0, 0).firstPosition(), 1);
917     QCOMPARE(table->cellAt(0, 1).firstPosition(), 2);
918     QCOMPARE(table->cellAt(0, 2).firstPosition(), 3);
919     QCOMPARE(table->cellAt(0, 3).firstPosition(), 4);
920     QCOMPARE(table->cellAt(1, 0).firstPosition(), 5);
921     QCOMPARE(table->cellAt(1, 1).firstPosition(), 6);
922     QCOMPARE(table->cellAt(1, 2).firstPosition(), 7);
923     QCOMPARE(table->cellAt(1, 3).firstPosition(), 8);
924     QCOMPARE(table->cellAt(2, 0).firstPosition(), 9);
925     QCOMPARE(table->cellAt(2, 0).rowSpan(), 2);
926     QCOMPARE(table->cellAt(2, 0).columnSpan(), 2);
927     QCOMPARE(table->cellAt(2, 1).firstPosition(), 9);
928     QCOMPARE(table->cellAt(2, 2).firstPosition(), 10);
929     QCOMPARE(table->cellAt(2, 3).firstPosition(), 11);
930     QCOMPARE(table->cellAt(3, 0).firstPosition(), 9);
931     QCOMPARE(table->cellAt(3, 1).firstPosition(), 9);
932     QCOMPARE(table->cellAt(3, 2).firstPosition(), 12);
933     QCOMPARE(table->cellAt(3, 3).firstPosition(), 13);
934 
935     table->removeColumns(1, 1);
936     QCOMPARE(table->rows(), 4);
937     QCOMPARE(table->columns(), 3);
938     QCOMPARE(table->cellAt(0, 0).firstPosition(), 1);
939     QCOMPARE(table->cellAt(0, 1).firstPosition(), 2);
940     QCOMPARE(table->cellAt(0, 2).firstPosition(), 3);
941     QCOMPARE(table->cellAt(1, 0).firstPosition(), 4);
942     QCOMPARE(table->cellAt(1, 1).firstPosition(), 5);
943     QCOMPARE(table->cellAt(1, 2).firstPosition(), 6);
944     QCOMPARE(table->cellAt(2, 0).firstPosition(), 7);
945     QCOMPARE(table->cellAt(2, 0).rowSpan(), 2);
946     QCOMPARE(table->cellAt(2, 0).columnSpan(), 1);
947     QCOMPARE(table->cellAt(2, 1).firstPosition(), 8);
948     QCOMPARE(table->cellAt(2, 2).firstPosition(), 9);
949     QCOMPARE(table->cellAt(3, 0).firstPosition(), 7);
950     QCOMPARE(table->cellAt(3, 1).firstPosition(), 10);
951     QCOMPARE(table->cellAt(3, 2).firstPosition(), 11);
952 }
953 
removeColumnsInTableWithMergedRows()954 void tst_QTextTable::removeColumnsInTableWithMergedRows()
955 {
956     QTextTable *table = cursor.insertTable(3, 4);
957     table->mergeCells(0, 0, 1, 4);
958     QCOMPARE(table->rows(), 3);
959     QCOMPARE(table->columns(), 4);
960 
961     table->removeColumns(0, table->columns() - 1);
962 
963     QCOMPARE(table->rows(), 3);
964     QCOMPARE(table->columns(), 1);
965 }
966 
QTBUG11282_insertBeforeMergedEnding_data()967 void tst_QTextTable::QTBUG11282_insertBeforeMergedEnding_data()
968 {
969     QTest::addColumn<int>("rows");
970     QTest::addColumn<int>("columns");
971     QTest::addColumn<QList<int> >("merge");
972     QTest::addColumn<QList<int> >("insert");
973 
974     QTest::newRow("2x3, merge two, insert one") << 2 << 3 << (QList<int>() << 1 << 2 << 2)
975             << (QList<int>() << 1 << 1) ;
976     QTest::newRow("3x4, merge three, insert one") << 3 << 4 << (QList<int>() << 1 << 3 << 3)
977             << (QList<int>() << 1 << 1) ;
978     QTest::newRow("4x3, merge two, insert two") << 4 << 3 << (QList<int>() << 1 << 4 << 2)
979             << (QList<int>() << 1 << 2) ;
980     QTest::newRow("4x4, merge middle two, insert one") << 4 << 4 << (QList<int>() << 1 << 4 << 2)
981             << (QList<int>() << 1 << 1) ;
982 }
983 
QTBUG11282_insertBeforeMergedEnding()984 void tst_QTextTable::QTBUG11282_insertBeforeMergedEnding()
985 {
986     QFETCH(int, rows);
987     QFETCH(int, columns);
988     QFETCH(QList<int>, merge);
989     QFETCH(QList<int>, insert);
990     QTextTable *table = cursor.insertTable(rows, columns);
991     QTextEdit *textEdit = new QTextEdit;
992     textEdit->setDocument(doc);
993     textEdit->show();
994     QTest::qWaitForWindowShown(textEdit);
995     table->mergeCells(0,merge.at(0), merge.at(1), merge.at(2));
996     //Don't crash !
997     table->insertColumns(insert.at(0), insert.at(1));
998     //Check that the final size is what we expected
999     QCOMPARE(table->rows(), rows);
1000     QCOMPARE(table->columns(), columns + insert.at(1));
1001     delete textEdit;
1002 }
1003 
QTBUG22011_insertBeforeRowSpan()1004 void tst_QTextTable::QTBUG22011_insertBeforeRowSpan()
1005 {
1006     QTextDocument doc;
1007     QTextCursor cursor(&doc);
1008     QTextTable *table = cursor.insertTable(1,1); // 1x1
1009 
1010     table->appendColumns(1); // 1x2
1011     table->appendRows(1); // 2x2
1012     table->mergeCells(0, 0, 2, 1); // 2x2
1013     table->insertColumns(1, 1); // 2x3
1014     table->mergeCells(0, 1, 1, 2); // 2x3
1015     table->appendRows(1); // 3x3
1016     table->mergeCells(0, 0, 3, 1); // 3x3
1017     table->appendRows(1); // 4x3
1018     table->insertColumns(1, 1); // 4x4
1019     table->mergeCells(0, 1, 1, 3);
1020     table->mergeCells(1, 1, 1, 2);
1021     table->mergeCells(2, 1, 1, 2);
1022     table->mergeCells(3, 0, 1, 2);
1023     table->insertColumns(3, 1); // 4x5
1024     table->mergeCells(0, 1, 1, 4);
1025 
1026     table->appendColumns(1); // 4x6
1027 
1028     QCOMPARE(table->rows(), 4);
1029     QCOMPARE(table->columns(), 6);
1030 }
1031 
1032 QTEST_MAIN(tst_QTextTable)
1033 #include "tst_qtexttable.moc"
1034