diff options
author | Serge Krot <Serge.Krot@cib.de> | 2018-01-12 13:55:59 +0100 |
---|---|---|
committer | Thorsten Behrens <Thorsten.Behrens@CIB.de> | 2018-01-15 22:22:45 +0100 |
commit | 311ea730cb225bca167af2e4111445608a14a263 (patch) | |
tree | 1ea98e52980d82e8566466b552c4c4c0a3c28a6d /sw | |
parent | 8f28db9515e049fa7e0aa26fe32513e3486dcfaf (diff) |
tdf#113877 Insert document: merge two lists into one
When inserting a new document into current position we need to
concat to lists into one only when they have the same list
properties.
Added unit test.
Change-Id: I66a8090fdeacd3a630700113d6a26a1cad75dc41
Reviewed-on: https://gerrit.libreoffice.org/47814
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
Diffstat (limited to 'sw')
-rwxr-xr-x | sw/qa/extras/uiwriter/data/tdf113877_insert_numbered_list_abcd.odt | bin | 0 -> 8518 bytes | |||
-rw-r--r-- | sw/qa/extras/uiwriter/uiwriter.cxx | 51 | ||||
-rw-r--r-- | sw/source/filter/xml/xmlimp.cxx | 239 | ||||
-rw-r--r-- | sw/source/filter/xml/xmlimp.hxx | 1 |
4 files changed, 227 insertions, 64 deletions
diff --git a/sw/qa/extras/uiwriter/data/tdf113877_insert_numbered_list_abcd.odt b/sw/qa/extras/uiwriter/data/tdf113877_insert_numbered_list_abcd.odt Binary files differnew file mode 100755 index 000000000000..47fe7e0760fe --- /dev/null +++ b/sw/qa/extras/uiwriter/data/tdf113877_insert_numbered_list_abcd.odt diff --git a/sw/qa/extras/uiwriter/uiwriter.cxx b/sw/qa/extras/uiwriter/uiwriter.cxx index 7d39895f39bd..1bfb252c4899 100644 --- a/sw/qa/extras/uiwriter/uiwriter.cxx +++ b/sw/qa/extras/uiwriter/uiwriter.cxx @@ -264,6 +264,7 @@ public: void testTdf58604(); void testTdf112025(); void testTdf113877(); + void testTdf113877NoMerge(); void testMsWordCompTrailingBlanks(); void testCreateDocxAnnotation(); void testTdf107976(); @@ -437,6 +438,7 @@ public: CPPUNIT_TEST(testTdf58604); CPPUNIT_TEST(testTdf112025); CPPUNIT_TEST(testTdf113877); + CPPUNIT_TEST(testTdf113877NoMerge); CPPUNIT_TEST(testMsWordCompTrailingBlanks); CPPUNIT_TEST(testCreateDocxAnnotation); CPPUNIT_TEST(testTdf107976); @@ -5281,6 +5283,8 @@ void SwUiWriterTest::testTdf114306() assertXPath(pXmlDoc, "/root/page[2]/body/tab[1]/row[1]/cell[1]/txt", 1); } +// During insert of the document with list inside into the main document inside the list +// we should merge both lists into one, when they have the same list properties void SwUiWriterTest::testTdf113877() { load(DATA_DIRECTORY, "tdf113877_insert_numbered_list.odt"); @@ -5298,13 +5302,52 @@ void SwUiWriterTest::testTdf113877() lcl_dispatchCommand(mxComponent, ".uno:InsertDoc", aPropertyValues); } + const OUString listId1 = getProperty<OUString>(getParagraph(1), "ListId"); + const OUString listId4 = getProperty<OUString>(getParagraph(4), "ListId"); + const OUString listId5 = getProperty<OUString>(getParagraph(5), "ListId"); + const OUString listId6 = getProperty<OUString>(getParagraph(6), "ListId"); + const OUString listId7 = getProperty<OUString>(getParagraph(7), "ListId"); + + // the initial list with 4 list items + CPPUNIT_ASSERT_EQUAL(listId1, listId4); + + // the last of the first list, and the first of the inserted list + CPPUNIT_ASSERT_EQUAL(listId4, listId5); + CPPUNIT_ASSERT_EQUAL(listId5, listId6); + CPPUNIT_ASSERT_EQUAL(listId6, listId7); +} + +// The same test as testTdf113877() but merging of two list should not be performed. +void SwUiWriterTest::testTdf113877NoMerge() +{ + load(DATA_DIRECTORY, "tdf113877_insert_numbered_list.odt"); + + // set a page cursor into the end of the document + uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(xModel->getCurrentController(), uno::UNO_QUERY); + uno::Reference<text::XPageCursor> xCursor(xTextViewCursorSupplier->getViewCursor(), uno::UNO_QUERY); + xCursor->jumpToEndOfPage(); + + // insert the same document at current cursor position + { + const OUString insertFileid = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf113877_insert_numbered_list_abcd.odt"; + uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence({ { "Name", uno::makeAny(insertFileid) } })); + lcl_dispatchCommand(mxComponent, ".uno:InsertDoc", aPropertyValues); + } + + const OUString listId1 = getProperty<OUString>(getParagraph(1), "ListId"); + const OUString listId4 = getProperty<OUString>(getParagraph(4), "ListId"); + const OUString listId5 = getProperty<OUString>(getParagraph(5), "ListId"); + const OUString listId6 = getProperty<OUString>(getParagraph(6), "ListId"); + const OUString listId7 = getProperty<OUString>(getParagraph(7), "ListId"); + // the initial list with 4 list items - CPPUNIT_ASSERT_EQUAL(getProperty<OUString>(getParagraph(1), "ListId"), getProperty<OUString>(getParagraph(4), "ListId")); + CPPUNIT_ASSERT_EQUAL(listId1, listId4); // the last of the first list, and the first of the inserted list - CPPUNIT_ASSERT_EQUAL(getProperty<OUString>(getParagraph(4), "ListId"), getProperty<OUString>(getParagraph(5), "ListId")); - CPPUNIT_ASSERT_EQUAL(getProperty<OUString>(getParagraph(5), "ListId"), getProperty<OUString>(getParagraph(6), "ListId")); - CPPUNIT_ASSERT_EQUAL(getProperty<OUString>(getParagraph(6), "ListId"), getProperty<OUString>(getParagraph(7), "ListId")); + CPPUNIT_ASSERT(listId4 != listId5); + CPPUNIT_ASSERT_EQUAL(listId5, listId6); + CPPUNIT_ASSERT(listId6 != listId7); } void SwUiWriterTest::testTdf108524() diff --git a/sw/source/filter/xml/xmlimp.cxx b/sw/source/filter/xml/xmlimp.cxx index 29d4a6e64c7b..6bead78a5484 100644 --- a/sw/source/filter/xml/xmlimp.cxx +++ b/sw/source/filter/xml/xmlimp.cxx @@ -45,6 +45,7 @@ #include <drawdoc.hxx> #include <IDocumentSettingAccess.hxx> #include <IDocumentDeviceAccess.hxx> +#include <IDocumentListsAccess.hxx> #include <IDocumentStylePoolAccess.hxx> #include <IDocumentDrawModelAccess.hxx> #include <unofreg.hxx> @@ -56,8 +57,10 @@ #include <ndtxt.hxx> #include <editsh.hxx> #include <strings.hrc> +#include <svl/stritem.hxx> #include "xmlimp.hxx" #include "xmltexti.hxx" +#include <list.hxx> #include <swdll.hxx> #include <xmloff/DocumentSettingsContext.hxx> #include <docsh.hxx> @@ -829,7 +832,7 @@ void SwXMLImport::endDocument() // tdf#113877 // when we insert one document with list inside into another one with list at the insert position, - // the resulting numbering in these lists are not consequent. + // the resulting numbering in these lists is not consequent. // // Main document: // 1. One @@ -852,65 +855,7 @@ void SwXMLImport::endDocument() // 6. Three // 7. // - if (IsInsertMode() && m_pSttNdIdx->GetIndex()) - { - sal_uLong index = 1; - - // the last node of the main document where we have inserted a document - SwNode * p1 = pDoc->GetNodes()[m_pSttNdIdx->GetIndex() + 0]; - - // the first node of the inserted document - SwNode * p2 = pDoc->GetNodes()[m_pSttNdIdx->GetIndex() + index]; - - // the first node of the inserted document, - // which will be used to detect if inside inserted document a new list was started - const SfxPoolItem* listId2Initial = nullptr; - - while ( - p1 && p2 - && (p1->GetNodeType() == p2->GetNodeType()) - && (p1->IsTextNode() == p2->IsTextNode()) - ) - { - SwContentNode * c1 = static_cast<SwContentNode *>(p1); - SwContentNode * c2 = static_cast<SwContentNode *>(p2); - - const SfxPoolItem* listId1 = c1->GetNoCondAttr(RES_PARATR_LIST_ID, false); - const SfxPoolItem* listId2 = c2->GetNoCondAttr(RES_PARATR_LIST_ID, false); - - if (!listId2Initial) - { - listId2Initial = listId2; - } - - if (! (listId2Initial && listId2 && (*listId2Initial == *listId2)) ) - { - // no more list items of the first list inside inserted document - break; - } - - if (listId1 && listId2) - { - c2->SetAttr(*listId1); - } - else - { - // no more appropriate list items - break; - } - - // get next item - index++; - if (index >= pDoc->GetNodes().Count()) - { - // no more items - break; - } - - p2 = pDoc->GetNodes()[m_pSttNdIdx->GetIndex() + index]; - } - } - + MergeListsAtDocumentInsertPosition(pDoc); } } @@ -985,6 +930,180 @@ void SwXMLImport::endDocument() ClearTextImport(); } +// tdf#113877 +// when we insert one document with list inside into another one with list at the insert position, +// the resulting numbering in these lists is not consequent. +// +// CASE-1: Main document: +// 1. One +// 2. Two +// 3. Three +// 4. <-- insert position +// +// Inserted document: +// 1. One +// 2. Two +// 3. Three +// 4. +// +// Expected result +// 1. One +// 2. Two +// 3. Three +// 4. One +// 5. Two +// 6. Three +// 7. +// +// CASE-2: Main document: +// 1. One +// 2. Two +// 3. Three +// 4. <-- insert position +// +// Inserted document: +// A) One +// B) Two +// C) Three +// D) +// +// Expected result +// 1. One +// 2. Two +// 3. Three +// 4. One +// A) Two +// B) Three +// 5. +// +void SwXMLImport::MergeListsAtDocumentInsertPosition(SwDoc *pDoc) +{ + // 1. check enviroment + if (! pDoc) + return; + + if (! IsInsertMode() || ! m_pSttNdIdx->GetIndex()) + return; + + sal_uLong index = 1; + + // the last node of the main document where we have inserted a document + const SwNodePtr node1 = pDoc->GetNodes()[m_pSttNdIdx->GetIndex() + 0]; + + // the first node of the inserted document + SwNodePtr node2 = pDoc->GetNodes()[m_pSttNdIdx->GetIndex() + index]; + + if (! (node1 && node2 + && (node1->GetNodeType() == node2->GetNodeType()) + && (node1->IsTextNode() == node2->IsTextNode()) + )) + { + // not a text node at insert position + return; + } + + // 2. get the first node of the inserted document, + // which will be used to detect if inside inserted document a new list was started after the first list + const SfxPoolItem* pListId2Initial = nullptr; + { + SwContentNode* contentNode1 = static_cast<SwContentNode *>(node1); + SwContentNode* contentNode2 = static_cast<SwContentNode *>(node2); + + // check if both lists have the same list properties + const SfxPoolItem* pListId1 = contentNode1->GetNoCondAttr( RES_PARATR_LIST_ID, false ); + const SfxPoolItem* pListId2 = contentNode2->GetNoCondAttr( RES_PARATR_LIST_ID, false ); + + if (! pListId1) + return; + if (! pListId2) + return; + + const OUString& sListId1 = dynamic_cast<const SfxStringItem*>(pListId1)->GetValue(); + const OUString& sListId2 = dynamic_cast<const SfxStringItem*>(pListId2)->GetValue(); + + const SwList* pList1 = pDoc->getIDocumentListsAccess().getListByName( sListId1 ); + const SwList* pList2 = pDoc->getIDocumentListsAccess().getListByName( sListId2 ); + + if (! pList1) + return; + if (! pList2) + return; + + const OUString& sDefaultListStyleName1 = pList1->GetDefaultListStyleName(); + const OUString& sDefaultListStyleName2 = pList2->GetDefaultListStyleName(); + + if (sDefaultListStyleName1 != sDefaultListStyleName2) + { + const SwNumRule* pNumRule1 = pDoc->FindNumRulePtr( sDefaultListStyleName1 ); + const SwNumRule* pNumRule2 = pDoc->FindNumRulePtr( sDefaultListStyleName2 ); + + if (pNumRule1 && pNumRule2) + { + // check style of the each list level + for( sal_uInt8 n = 0; n < MAXLEVEL; ++n ) + { + if( !( pNumRule1->Get( n ) == pNumRule2->Get( n ) )) + { + return; + } + } + + // our list should be merged + pListId2Initial = pListId2; + } + } + else + { + // our list should be merged + pListId2Initial = pListId2; + } + } + + if (! pListId2Initial) + { + // two lists have different styles => they should not be merged + return; + } + + // 3. merge two lists + while ( + node1 && node2 + && (node1->GetNodeType() == node2->GetNodeType()) + && (node1->IsTextNode() == node2->IsTextNode()) + ) + { + SwContentNode* contentNode1 = static_cast<SwContentNode *>( node1 ); + SwContentNode* contentNode2 = static_cast<SwContentNode *>( node2 ); + + const SfxPoolItem* pListId1 = contentNode1->GetNoCondAttr( RES_PARATR_LIST_ID, false ); + const SfxPoolItem* pListId2 = contentNode2->GetNoCondAttr( RES_PARATR_LIST_ID, false ); + + if (! pListId1) + return; + if (! pListId2) + return; + + if (*pListId2Initial != *pListId2) + { + // no more list items of the first list inside inserted document + return; + } + + // set list style to this list element + contentNode2->SetAttr(*pListId1); + + // get next item + index++; + if (index >= pDoc->GetNodes().Count()) + { + // no more items + return; + } + + node2 = pDoc->GetNodes()[m_pSttNdIdx->GetIndex() + index]; + } +} + // Locally derive XMLTextShapeImportHelper, so we can take care of the // form import This is Writer, but not text specific, so it should go // here! diff --git a/sw/source/filter/xml/xmlimp.hxx b/sw/source/filter/xml/xmlimp.hxx index aa7ad833e356..8907970b62e9 100644 --- a/sw/source/filter/xml/xmlimp.hxx +++ b/sw/source/filter/xml/xmlimp.hxx @@ -168,6 +168,7 @@ public: bool FindAutomaticStyle( sal_uInt16 nFamily, const OUString& rName, const SfxItemSet **ppItemSet ) const; + void MergeListsAtDocumentInsertPosition(SwDoc *pDoc); virtual void SetStatistics( const css::uno::Sequence< css::beans::NamedValue> & i_rStats) override; |