summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerge Krot <Serge.Krot@cib.de>2018-01-12 13:55:59 +0100
committerThorsten Behrens <Thorsten.Behrens@CIB.de>2018-01-15 22:22:45 +0100
commit311ea730cb225bca167af2e4111445608a14a263 (patch)
tree1ea98e52980d82e8566466b552c4c4c0a3c28a6d
parent8f28db9515e049fa7e0aa26fe32513e3486dcfaf (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>
-rwxr-xr-xsw/qa/extras/uiwriter/data/tdf113877_insert_numbered_list_abcd.odtbin0 -> 8518 bytes
-rw-r--r--sw/qa/extras/uiwriter/uiwriter.cxx51
-rw-r--r--sw/source/filter/xml/xmlimp.cxx239
-rw-r--r--sw/source/filter/xml/xmlimp.hxx1
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
new file mode 100755
index 000000000000..47fe7e0760fe
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data/tdf113877_insert_numbered_list_abcd.odt
Binary files differ
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;