| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the test suite of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| |
| #include <QtTest/QtTest> |
| |
| #include <qtextdocument.h> |
| #include <qtextdocumentfragment.h> |
| #include <qtextlist.h> |
| #include <qabstracttextdocumentlayout.h> |
| #include <qtextcursor.h> |
| #include "../qtextdocument/common.h" |
| |
| class tst_QTextList : public QObject |
| { |
| Q_OBJECT |
| |
| private slots: |
| void init(); |
| void cleanup(); |
| void item(); |
| void autoNumbering(); |
| void autoNumberingRTL(); |
| void autoNumberingPrefixAndSuffix(); |
| void autoNumberingPrefixAndSuffixRTL(); |
| void autoNumberingPrefixAndSuffixHtmlExportImport(); |
| void romanNumbering(); |
| void romanNumberingLimit(); |
| void formatChange(); |
| void cursorNavigation(); |
| void partialRemoval(); |
| void formatReferenceChange(); |
| void ensureItemOrder(); |
| void add(); |
| void defaultIndent(); |
| void blockUpdate(); |
| void numbering_data(); |
| void numbering(); |
| |
| private: |
| QTextDocument *doc; |
| QTextCursor cursor; |
| QTestDocumentLayout *layout; |
| }; |
| |
| void tst_QTextList::init() |
| { |
| doc = new QTextDocument(); |
| layout = new QTestDocumentLayout(doc); |
| doc->setDocumentLayout(layout); |
| cursor = QTextCursor(doc); |
| } |
| |
| void tst_QTextList::cleanup() |
| { |
| cursor = QTextCursor(); |
| delete doc; |
| doc = 0; |
| } |
| |
| void tst_QTextList::item() |
| { |
| // this is basically a test for the key() + 1 in QTextList::item. |
| QTextList *list = cursor.createList(QTextListFormat()); |
| QVERIFY(list->item(0).blockFormat().objectIndex() != -1); |
| } |
| |
| void tst_QTextList::autoNumbering() |
| { |
| QTextListFormat fmt; |
| fmt.setStyle(QTextListFormat::ListLowerAlpha); |
| QTextList *list = cursor.createList(fmt); |
| QVERIFY(list); |
| |
| for (int i = 0; i < 27; ++i) |
| cursor.insertBlock(); |
| |
| QCOMPARE(list->count(), 28); |
| |
| QVERIFY(cursor.currentList()); |
| QCOMPARE(cursor.currentList()->itemNumber(cursor.block()), 27); |
| QCOMPARE(cursor.currentList()->itemText(cursor.block()), QLatin1String("ab.")); |
| } |
| |
| void tst_QTextList::autoNumberingPrefixAndSuffix() |
| { |
| QTextListFormat fmt; |
| fmt.setStyle(QTextListFormat::ListLowerAlpha); |
| fmt.setNumberPrefix("-"); |
| fmt.setNumberSuffix(")"); |
| QTextList *list = cursor.createList(fmt); |
| QVERIFY(list); |
| |
| for (int i = 0; i < 27; ++i) |
| cursor.insertBlock(); |
| |
| QCOMPARE(list->count(), 28); |
| |
| QVERIFY(cursor.currentList()); |
| QCOMPARE(cursor.currentList()->itemNumber(cursor.block()), 27); |
| QCOMPARE(cursor.currentList()->itemText(cursor.block()), QLatin1String("-ab)")); |
| } |
| |
| void tst_QTextList::autoNumberingPrefixAndSuffixRTL() |
| { |
| QTextBlockFormat bfmt; |
| bfmt.setLayoutDirection(Qt::RightToLeft); |
| cursor.setBlockFormat(bfmt); |
| |
| QTextListFormat fmt; |
| fmt.setStyle(QTextListFormat::ListUpperAlpha); |
| fmt.setNumberPrefix("-"); |
| fmt.setNumberSuffix("*"); |
| QTextList *list = cursor.createList(fmt); |
| QVERIFY(list); |
| |
| cursor.insertBlock(); |
| |
| QCOMPARE(list->count(), 2); |
| |
| QCOMPARE(cursor.currentList()->itemText(cursor.block()), QLatin1String("*B-")); |
| } |
| |
| void tst_QTextList::autoNumberingPrefixAndSuffixHtmlExportImport() |
| { |
| QTextListFormat fmt; |
| fmt.setStyle(QTextListFormat::ListLowerAlpha); |
| fmt.setNumberPrefix("\""); |
| fmt.setNumberSuffix("#"); |
| fmt.setIndent(10); |
| // FIXME: Would like to test "'" but there's a problem in the css parser (Scanner::preprocess |
| // is called before the values are being parsed), so the quoting does not work. |
| QTextList *list = cursor.createList(fmt); |
| QVERIFY(list); |
| |
| for (int i = 0; i < 27; ++i) |
| cursor.insertBlock(); |
| |
| QCOMPARE(list->count(), 28); |
| |
| QString htmlExport = doc->toHtml(); |
| QTextDocument importDoc; |
| importDoc.setHtml(htmlExport); |
| |
| QTextCursor importCursor(&importDoc); |
| for (int i = 0; i < 27; ++i) |
| importCursor.movePosition(QTextCursor::NextBlock); |
| |
| QVERIFY(importCursor.currentList()); |
| QCOMPARE(importCursor.currentList()->itemNumber(importCursor.block()), 27); |
| QCOMPARE(importCursor.currentList()->itemText(importCursor.block()), QLatin1String("\"ab#")); |
| QCOMPARE(importCursor.currentList()->format().indent(), 10); |
| } |
| |
| void tst_QTextList::autoNumberingRTL() |
| { |
| QTextBlockFormat bfmt; |
| bfmt.setLayoutDirection(Qt::RightToLeft); |
| cursor.setBlockFormat(bfmt); |
| |
| QTextListFormat fmt; |
| fmt.setStyle(QTextListFormat::ListUpperAlpha); |
| QTextList *list = cursor.createList(fmt); |
| QVERIFY(list); |
| |
| cursor.insertBlock(); |
| |
| QCOMPARE(list->count(), 2); |
| |
| QCOMPARE(cursor.currentList()->itemText(cursor.block()), QLatin1String(".B")); |
| } |
| |
| void tst_QTextList::romanNumbering() |
| { |
| QTextListFormat fmt; |
| fmt.setStyle(QTextListFormat::ListUpperRoman); |
| QTextList *list = cursor.createList(fmt); |
| QVERIFY(list); |
| |
| for (int i = 0; i < 4998; ++i) |
| cursor.insertBlock(); |
| |
| QCOMPARE(list->count(), 4999); |
| |
| QVERIFY(cursor.currentList()); |
| QCOMPARE(cursor.currentList()->itemNumber(cursor.block()), 4998); |
| QCOMPARE(cursor.currentList()->itemText(cursor.block()), QLatin1String("MMMMCMXCIX.")); |
| } |
| |
| void tst_QTextList::romanNumberingLimit() |
| { |
| QTextListFormat fmt; |
| fmt.setStyle(QTextListFormat::ListLowerRoman); |
| QTextList *list = cursor.createList(fmt); |
| QVERIFY(list); |
| |
| for (int i = 0; i < 4999; ++i) |
| cursor.insertBlock(); |
| |
| QCOMPARE(list->count(), 5000); |
| |
| QVERIFY(cursor.currentList()); |
| QCOMPARE(cursor.currentList()->itemNumber(cursor.block()), 4999); |
| QCOMPARE(cursor.currentList()->itemText(cursor.block()), QLatin1String("?.")); |
| } |
| |
| void tst_QTextList::formatChange() |
| { |
| // testing the formatChanged slot in QTextListManager |
| |
| /* <initial block> |
| * 1. |
| * 2. |
| */ |
| QTextList *list = cursor.insertList(QTextListFormat::ListDecimal); |
| QTextList *firstList = list; |
| cursor.insertBlock(); |
| |
| QVERIFY(list && list->count() == 2); |
| |
| QTextBlockFormat bfmt = cursor.blockFormat(); |
| // QCOMPARE(bfmt.object(), list); |
| |
| bfmt.setObjectIndex(-1); |
| cursor.setBlockFormat(bfmt); |
| |
| QCOMPARE(firstList->count(), 1); |
| } |
| |
| void tst_QTextList::cursorNavigation() |
| { |
| // testing some cursor list methods |
| |
| /* <initial block> |
| * 1. |
| * 2. |
| */ |
| cursor.insertList(QTextListFormat::ListDecimal); |
| cursor.insertBlock(); |
| |
| cursor.movePosition(QTextCursor::Start); |
| cursor.movePosition(QTextCursor::NextBlock); |
| cursor.movePosition(QTextCursor::NextBlock); |
| QVERIFY(cursor.currentList()); |
| cursor.movePosition(QTextCursor::PreviousBlock); |
| QVERIFY(cursor.currentList()); |
| QCOMPARE(cursor.currentList()->itemNumber(cursor.block()), 0); |
| } |
| |
| void tst_QTextList::partialRemoval() |
| { |
| /* this is essentially a test for PieceTable::removeBlock to not miss any |
| blocks with the blockChanged signal emission that actually get removed. |
| |
| It creates two lists, like this: |
| |
| 1. Hello World |
| a. Foobar |
| |
| and then removes from within the 'Hello World' into the 'Foobar' . |
| There used to be no emission for the removal of the second (a.) block, |
| causing list inconsistencies. |
| |
| */ |
| |
| QTextList *firstList = cursor.insertList(QTextListFormat::ListDecimal); |
| |
| QTextCursor selStart = cursor; |
| selStart.movePosition(QTextCursor::PreviousCharacter); |
| |
| cursor.insertText("Hello World"); |
| |
| // position it well into the 'hello world' text. |
| selStart.movePosition(QTextCursor::NextCharacter); |
| selStart.movePosition(QTextCursor::NextCharacter); |
| selStart.clearSelection(); |
| |
| QPointer<QTextList> secondList = cursor.insertList(QTextListFormat::ListCircle); |
| cursor.insertText("Foobar"); |
| |
| // position it into the 'foo bar' text. |
| cursor.movePosition(QTextCursor::PreviousCharacter); |
| QTextCursor selEnd = cursor; |
| |
| // this creates a selection that includes parts of both text-fragments and also the list item of the second list. |
| QTextCursor selection = selStart; |
| selection.setPosition(selEnd.position(), QTextCursor::KeepAnchor); |
| |
| selection.deleteChar(); // deletes the second list |
| |
| QVERIFY(!secondList); |
| QVERIFY(firstList->count() > 0); |
| |
| doc->undo(); |
| } |
| |
| void tst_QTextList::formatReferenceChange() |
| { |
| QTextList *list = cursor.insertList(QTextListFormat::ListDecimal); |
| cursor.insertText("Some Content..."); |
| cursor.insertBlock(QTextBlockFormat()); |
| |
| cursor.setPosition(list->item(0).position()); |
| int listItemStartPos = cursor.position(); |
| cursor.movePosition(QTextCursor::NextBlock); |
| int listItemLen = cursor.position() - listItemStartPos; |
| layout->expect(listItemStartPos, listItemLen, listItemLen); |
| |
| QTextListFormat fmt = list->format(); |
| fmt.setStyle(QTextListFormat::ListCircle); |
| list->setFormat(fmt); |
| |
| QVERIFY(layout->called); |
| QVERIFY(!layout->error); |
| } |
| |
| void tst_QTextList::ensureItemOrder() |
| { |
| /* |
| * Insert a new list item before the first one and verify the blocks |
| * are sorted after that. |
| */ |
| QTextList *list = cursor.insertList(QTextListFormat::ListDecimal); |
| |
| QTextBlockFormat fmt = cursor.blockFormat(); |
| cursor.movePosition(QTextCursor::Start); |
| cursor.insertBlock(fmt); |
| |
| QCOMPARE(list->item(0).position(), 1); |
| QCOMPARE(list->item(1).position(), 2); |
| } |
| |
| void tst_QTextList::add() |
| { |
| QTextList *list = cursor.insertList(QTextListFormat::ListDecimal); |
| cursor.insertBlock(QTextBlockFormat()); |
| QCOMPARE(list->count(), 1); |
| cursor.insertBlock(QTextBlockFormat()); |
| list->add(cursor.block()); |
| QCOMPARE(list->count(), 2); |
| } |
| |
| // Task #72036 |
| void tst_QTextList::defaultIndent() |
| { |
| QTextListFormat fmt; |
| QCOMPARE(fmt.indent(), 1); |
| } |
| |
| void tst_QTextList::blockUpdate() |
| { |
| // three items |
| QTextList *list = cursor.insertList(QTextListFormat::ListDecimal); |
| cursor.insertBlock(); |
| cursor.insertBlock(); |
| |
| // remove second, needs also update on the third |
| // since the numbering might have changed |
| const int len = cursor.position() + cursor.block().length() - 1; |
| layout->expect(1, len, len); |
| list->remove(list->item(1)); |
| QVERIFY(!layout->error); |
| } |
| |
| void tst_QTextList::numbering_data() |
| { |
| QTest::addColumn<int>("format"); |
| QTest::addColumn<int>("number"); |
| QTest::addColumn<QString>("result"); |
| |
| QTest::newRow("E.") << int(QTextListFormat::ListUpperAlpha) << 5 << "E."; |
| QTest::newRow("abc.") << int(QTextListFormat::ListLowerAlpha) << (26 + 2) * 26 + 3 << "abc."; |
| QTest::newRow("12.") << int(QTextListFormat::ListDecimal) << 12 << "12."; |
| QTest::newRow("XXIV.") << int(QTextListFormat::ListUpperRoman) << 24 << "XXIV."; |
| QTest::newRow("VIII.") << int(QTextListFormat::ListUpperRoman) << 8 << "VIII."; |
| QTest::newRow("xxx.") << int(QTextListFormat::ListLowerRoman) << 30 << "xxx."; |
| QTest::newRow("xxix.") << int(QTextListFormat::ListLowerRoman) << 29 << "xxix."; |
| // QTest::newRow("xxx. alpha") << int(QTextListFormat::ListLowerAlpha) << (24 * 26 + 24) * 26 + 24 << "xxx."; //Too slow |
| } |
| |
| void tst_QTextList::numbering() |
| { |
| QFETCH(int, format); |
| QFETCH(int, number); |
| QFETCH(QString, result); |
| |
| |
| QTextListFormat fmt; |
| fmt.setStyle(QTextListFormat::Style(format)); |
| QTextList *list = cursor.createList(fmt); |
| QVERIFY(list); |
| |
| for (int i = 1; i < number; ++i) |
| cursor.insertBlock(); |
| |
| QCOMPARE(list->count(), number); |
| |
| QVERIFY(cursor.currentList()); |
| QCOMPARE(cursor.currentList()->itemNumber(cursor.block()), number - 1); |
| QCOMPARE(cursor.currentList()->itemText(cursor.block()), result); |
| } |
| |
| QTEST_MAIN(tst_QTextList) |
| #include "tst_qtextlist.moc" |