void TestChangeTrackedDelete::testPrefixMerge() { TextTool *textTool = new TextTool(new MockCanvas); KoTextEditor *textEditor = textTool->textEditor(); QVERIFY(textEditor); QTextDocument *document = textEditor->document(); KoTextDocumentLayout *layout = qobject_cast<KoTextDocumentLayout *>(document->documentLayout()); QTextCursor *cursor = textEditor->cursor(); cursor->insertText("Hello World"); cursor->setPosition(3); ChangeTrackedDeleteCommand *delCommand = new ChangeTrackedDeleteCommand(ChangeTrackedDeleteCommand::NextChar, textTool); textEditor->addCommand(delCommand); QCOMPARE(document->characterAt(3).unicode(), (ushort)(QChar::ObjectReplacementCharacter)); cursor->setPosition(4); delCommand = new ChangeTrackedDeleteCommand(ChangeTrackedDeleteCommand::NextChar, textTool); textEditor->addCommand(delCommand); // This is weird. Without this loop present the succeeding call to inlineTextObject returs NULL. Why ?????? for (int i = 0; i < document->characterCount(); i++) { cursor->setPosition(i); } cursor->setPosition(4); KoDeleteChangeMarker *testMarker = dynamic_cast<KoDeleteChangeMarker *>(layout->inlineTextObjectManager()->inlineTextObject(*cursor)); QTextDocumentFragment deleteData = KoTextDocument(document).changeTracker()->elementById(testMarker->changeId())->getDeleteData(); QCOMPARE(deleteData.toPlainText(), QString("lo")); delete textTool; }
void TestChangeTrackedDelete::testListDelete() { TextTool *textTool = new TextTool(new MockCanvas); KoTextEditor *textEditor = textTool->textEditor(); QVERIFY(textEditor); QTextDocument *document = textEditor->document(); KoTextDocumentLayout *layout = qobject_cast<KoTextDocumentLayout *>(document->documentLayout()); QTextCursor *cursor = textEditor->cursor(); insertSampleList(document); cursor->setPosition(16); cursor->setPosition(152, QTextCursor::KeepAnchor); ChangeTrackedDeleteCommand *delCommand = new ChangeTrackedDeleteCommand(ChangeTrackedDeleteCommand::NextChar, textTool); textEditor->addCommand(delCommand); QCOMPARE(document->characterAt(16).unicode(), (ushort)(QChar::ObjectReplacementCharacter)); // This is weird. Without this loop present the succeeding call to inlineTextObject returs NULL. Why ?????? for (int i = 0; i < document->characterCount(); i++) { cursor->setPosition(i); } cursor->setPosition(17); KoDeleteChangeMarker *testMarker = dynamic_cast<KoDeleteChangeMarker *>(layout->inlineTextObjectManager()->inlineTextObject(*cursor)); QTextDocumentFragment deleteData = KoTextDocument(document).changeTracker()->elementById(testMarker->changeId())->getDeleteData(); QTextDocument deleteDocument; QTextCursor deleteCursor(&deleteDocument); deleteCursor.insertFragment(deleteData); bool listFound = false; for (int i = 0; i < deleteDocument.characterCount(); i++) { deleteCursor.setPosition(i); if (deleteCursor.currentList()) { listFound = true; continue; } } QVERIFY(listFound == true); QTextList *deletedList = deleteCursor.currentList(); bool deletedListStatus = deletedList->format().boolProperty(KoDeleteChangeMarker::DeletedList); QVERIFY(deletedListStatus == true); bool deletedListItemStatus; deletedListItemStatus = deletedList->item(0).blockFormat().boolProperty(KoDeleteChangeMarker::DeletedListItem); QVERIFY(deletedListItemStatus == true); deletedListItemStatus = deletedList->item(1).blockFormat().boolProperty(KoDeleteChangeMarker::DeletedListItem); QVERIFY(deletedListItemStatus == true); deletedListItemStatus = deletedList->item(2).blockFormat().boolProperty(KoDeleteChangeMarker::DeletedListItem); QVERIFY(deletedListItemStatus == true); deletedListItemStatus = deletedList->item(3).blockFormat().boolProperty(KoDeleteChangeMarker::DeletedListItem); QVERIFY(deletedListItemStatus == true); deletedListItemStatus = deletedList->item(4).blockFormat().boolProperty(KoDeleteChangeMarker::DeletedListItem); QVERIFY(deletedListItemStatus == true); delete textTool; }
void KoTextLoader::loadBody(const KoXmlElement &bodyElem, QTextCursor &cursor) { const QTextBlockFormat defaultBlockFormat = cursor.blockFormat(); const QTextCharFormat defaultCharFormat = cursor.charFormat(); const QTextDocument *document = cursor.block().document(); d->styleManager = KoTextDocument(document).styleManager(); Q_ASSERT(d->styleManager); d->changeTracker = KoTextDocument(document).changeTracker(); // if (!d->changeTracker) // d->changeTracker = dynamic_cast<KoChangeTracker *>(d->context.dataCenterMap().value("ChangeTracker")); // Q_ASSERT(d->changeTracker); kDebug(32500) << "text-style:" << KoTextDebug::textAttributes( cursor.blockCharFormat() ); #if 0 if ((document->isEmpty()) && (d->styleManager)) { QTextBlock block = cursor.block(); d->styleManager->defaultParagraphStyle()->applyStyle(block); } #endif startBody(KoXml::childNodesCount(bodyElem)); KoXmlElement tag; bool usedParagraph = false; // set to true if we found a tag that used the paragraph, indicating that the next round needs to start a new one. forEachElement(tag, bodyElem) { if (! tag.isNull()) { const QString localName = tag.localName(); if (tag.namespaceURI() == KoXmlNS::text) { if (usedParagraph) cursor.insertBlock(defaultBlockFormat, defaultCharFormat); usedParagraph = true; if (d->changeTracker && localName == "tracked-changes") { d->changeTracker->loadOdfChanges(tag); usedParagraph = false; } else if (d->changeTracker && localName == "change-start") { loadChangedRegion(tag, cursor); usedParagraph = false; } else if (d->changeTracker && localName == "change-end") { d->currentChangeId = 0; usedParagraph = false; } else if (localName == "p") { // text paragraph loadParagraph(tag, cursor); } else if (localName == "h") { // heading loadHeading(tag, cursor); } else if (localName == "unordered-list" || localName == "ordered-list" // OOo-1.1 || localName == "list" || localName == "numbered-paragraph") { // OASIS loadList(tag, cursor); } else if (localName == "section") { // Temporary support (###TODO) loadSection(tag, cursor); } else { KoVariable *var = KoVariableRegistry::instance()->createFromOdf(tag, d->context); if (var) { KoTextDocumentLayout *layout = dynamic_cast<KoTextDocumentLayout*>(cursor.block().document()->documentLayout()); if (layout) { KoInlineTextObjectManager *textObjectManager = layout->inlineTextObjectManager(); if (textObjectManager) { KoVariableManager *varManager = textObjectManager->variableManager(); if (varManager) { textObjectManager->insertInlineObject(cursor, var); } } } } else { usedParagraph = false; kWarning(32500) << "unhandled text:" << localName; } } } else if (tag.namespaceURI() == KoXmlNS::draw) { loadShape(tag, cursor); } else if (tag.namespaceURI() == KoXmlNS::table) { if (localName == "table") { loadTable(tag, cursor); } else { kWarning(32500) << "unhandled table:" << localName; } #if 0 // TODO commented out for now if (localName == "table") { cursor.insertText("\n"); cursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, 1); QTextTable *tbl = cursor.insertTable(1, 1); int rows = 0; int columns = 0; kDebug(32500) << "Table inserted"; KoXmlElement tblTag; forEachElement(tblTag, tag) { if (! tblTag.isNull()) { const QString tblLocalName = tblTag.localName(); if (tblTag.namespaceURI() == KoXmlNS::table) { if (tblLocalName == "table-column") { // Do some parsing with the column, see §8.2.1, ODF 1.1 spec int repeatColumn = tblTag.attributeNS(KoXmlNS::table, "number-columns-repeated", "1").toInt(); columns = columns + repeatColumn; if (rows > 0) tbl->resize(rows, columns); else tbl->resize(1, columns); } else if (tblLocalName == "table-row") { // Lot of work to do here... rows++; if (columns > 0) tbl->resize(rows, columns); else tbl->resize(rows, 1); // Added a row int currentCell = 0; KoXmlElement rowTag; forEachElement(rowTag, tblTag) { if (!rowTag.isNull()) { const QString rowLocalName = rowTag.localName(); if (rowTag.namespaceURI() == KoXmlNS::table) { if (rowLocalName == "table-cell") { // Ok, it's a cell... const int currentRow = tbl->rows() - 1; QTextTableCell cell = tbl->cellAt(currentRow, currentCell); if (cell.isValid()) { cursor = cell.firstCursorPosition(); loadBody(context, rowTag, cursor); } else kDebug(32500) << "Invalid table-cell row=" << currentRow << " column=" << currentCell; currentCell++; } } } } } } } } cursor = tbl->lastCursorPosition(); cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 1); } else { kWarning(32500) << "KoTextLoader::loadBody unhandled table::" << localName; } #endif }
void TestChangeTrackedDelete::testTableDelete() { TextTool *textTool = new TextTool(new MockCanvas); KoTextEditor *textEditor = textTool->textEditor(); QVERIFY(textEditor); QTextDocument *document = textEditor->document(); KoTextDocumentLayout *layout = qobject_cast<KoTextDocumentLayout *>(document->documentLayout()); QTextCursor *cursor = textEditor->cursor(); insertSampleTable(document); cursor->setPosition(13); cursor->setPosition(102, QTextCursor::KeepAnchor); ChangeTrackedDeleteCommand *delCommand = new ChangeTrackedDeleteCommand(ChangeTrackedDeleteCommand::NextChar, textTool); textEditor->addCommand(delCommand); QCOMPARE(document->characterAt(13).unicode(), (ushort)(QChar::ObjectReplacementCharacter)); // This is weird. Without this loop present the succeeding call to inlineTextObject returs NULL. Why ?????? for (int i = 0; i < document->characterCount(); i++) { cursor->setPosition(i); } cursor->setPosition(14); KoDeleteChangeMarker *testMarker = dynamic_cast<KoDeleteChangeMarker *>(layout->inlineTextObjectManager()->inlineTextObject(*cursor)); QTextDocumentFragment deleteData = KoTextDocument(document).changeTracker()->elementById(testMarker->changeId())->getDeleteData(); QTextDocument deleteDocument; QTextCursor deleteCursor(&deleteDocument); deleteCursor.insertFragment(deleteData); bool tableFound = false; for (int i = 0; i < deleteDocument.characterCount(); i++) { deleteCursor.setPosition(i); if (deleteCursor.currentTable()) { tableFound = true; break; } } QVERIFY(tableFound == true); QTextTable *table = deleteCursor.currentTable(); QVERIFY(table->rows() == 3); QVERIFY(table->columns() == 3); tableFound = false; for (int i = 0; i < document->characterCount(); i++) { deleteCursor.setPosition(i); if (deleteCursor.currentTable()) { tableFound = true; break; } } QVERIFY(tableFound == false); delCommand->undo(); tableFound = false; for (int i = 0; i < document->characterCount(); i++) { deleteCursor.setPosition(i); if (deleteCursor.currentTable()) { tableFound = true; break; } } QVERIFY(tableFound == true); delete textTool; }