Bump version to 24.04.3.4
[LibreOffice.git] / editeng / qa / unit / core-test.cxx
blobdf9fb6c8ca269f987e430f635631567d1aa3a59d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <config_fonts.h>
12 #include <test/bootstrapfixture.hxx>
14 #include <cppunit/extensions/HelperMacros.h>
16 #include <editdoc.hxx>
18 #include <sfx2/app.hxx>
19 #include <svl/itempool.hxx>
20 #include <editeng/editeng.hxx>
21 #include <editeng/eeitem.hxx>
22 #include <editeng/lspcitem.hxx>
23 #include <editeng/svxacorr.hxx>
24 #include <editeng/unofield.hxx>
25 #include <editeng/wghtitem.hxx>
26 #include <editeng/postitem.hxx>
27 #include <editeng/section.hxx>
28 #include <editeng/editobj.hxx>
29 #include <editeng/flditem.hxx>
30 #include <editeng/udlnitem.hxx>
31 #include <svl/srchitem.hxx>
32 #include <svl/voiditem.hxx>
33 #include <editeng/fontitem.hxx>
34 #include <editeng/fhgtitem.hxx>
36 #include <com/sun/star/text/textfield/Type.hpp>
37 #include <com/sun/star/datatransfer/XTransferable.hpp>
39 #include <memory>
40 #include <editeng/outliner.hxx>
42 using namespace com::sun::star;
44 namespace {
46 class Test : public test::BootstrapFixture
48 public:
49 Test() {}
51 void setUp() override
53 test::BootstrapFixture::setUp();
54 mpItemPool = new EditEngineItemPool();
55 SfxApplication::GetOrCreate();
58 void tearDown() override
60 mpItemPool.clear();
61 test::BootstrapFixture::tearDown();
64 #if HAVE_MORE_FONTS
65 /// Test text portions position when percentage line spacing is set
66 void testLineSpacing();
67 #endif
69 void testConstruction();
71 /// Test UNO service class that implements text field items.
72 void testUnoTextFields();
74 /// AutoCorrect tests
75 void testAutocorrect();
77 /// Test Copy/Paste with hyperlinks in text using Legacy Format
78 void testHyperlinkCopyPaste();
80 /// Test Copy/Paste using Legacy Format
81 void testCopyPaste();
83 /// Test Paste using HTML
84 void testHTMLPaste();
86 /// Test Paste using an HTML fragment
87 void testHTMLFragmentPaste();
89 /// Test Copy/Paste with selective selection over multiple paragraphs
90 void testMultiParaSelCopyPaste();
92 /// Test Copy/Paste with Tabs
93 void testTabsCopyPaste();
95 /// Test hyperlinks
96 void testHyperlinkSearch();
98 /// Test Copy/Paste with Bold/Italic text using Legacy Format
99 void testBoldItalicCopyPaste();
101 /// Test Copy/Paste with Underline text using Legacy Format
102 void testUnderlineCopyPaste();
104 /// Test Copy/Paste with multiple paragraphs
105 void testMultiParaCopyPaste();
107 /// Test Copy/Paste with multiple paragraphs having Bold/Italic text
108 void testParaBoldItalicCopyPaste();
110 void testParaStartCopyPaste();
112 void testSectionAttributes();
114 void testLargeParaCopyPaste();
116 void testTransliterate();
118 void testTdf147196();
120 void testTdf148148();
122 void testSingleLine();
124 DECL_STATIC_LINK( Test, CalcFieldValueHdl, EditFieldInfo*, void );
126 CPPUNIT_TEST_SUITE(Test);
127 #if HAVE_MORE_FONTS
128 CPPUNIT_TEST(testLineSpacing);
129 #endif
130 CPPUNIT_TEST(testConstruction);
131 CPPUNIT_TEST(testUnoTextFields);
132 CPPUNIT_TEST(testAutocorrect);
133 CPPUNIT_TEST(testHyperlinkCopyPaste);
134 CPPUNIT_TEST(testCopyPaste);
135 CPPUNIT_TEST(testHTMLPaste);
136 CPPUNIT_TEST(testHTMLFragmentPaste);
137 CPPUNIT_TEST(testMultiParaSelCopyPaste);
138 CPPUNIT_TEST(testTabsCopyPaste);
139 CPPUNIT_TEST(testHyperlinkSearch);
140 CPPUNIT_TEST(testBoldItalicCopyPaste);
141 CPPUNIT_TEST(testUnderlineCopyPaste);
142 CPPUNIT_TEST(testMultiParaCopyPaste);
143 CPPUNIT_TEST(testParaBoldItalicCopyPaste);
144 CPPUNIT_TEST(testParaStartCopyPaste);
145 CPPUNIT_TEST(testSectionAttributes);
146 CPPUNIT_TEST(testLargeParaCopyPaste);
147 CPPUNIT_TEST(testTransliterate);
148 CPPUNIT_TEST(testTdf147196);
149 CPPUNIT_TEST(testTdf148148);
150 CPPUNIT_TEST(testSingleLine);
151 CPPUNIT_TEST_SUITE_END();
153 private:
154 rtl::Reference<EditEngineItemPool> mpItemPool;
157 #if HAVE_MORE_FONTS
158 void Test::testLineSpacing()
160 // Create EditEngine's instance
161 EditEngine aEditEngine(mpItemPool.get());
163 if(aEditEngine.GetRefDevice()->GetDPIY() != 96
164 || aEditEngine.GetRefDevice()->GetDPIScaleFactor() != 1.0)
165 return;
167 // Get EditDoc for current EditEngine's instance
168 EditDoc &rDoc = aEditEngine.GetEditDoc();
170 // Initially no text should be there
171 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rDoc.GetTextLen());
172 CPPUNIT_ASSERT_EQUAL(OUString(), rDoc.GetParaAsString(sal_Int32(0)));
174 // Set initial text
175 OUString aText = "This is multi-line paragraph";
177 sal_Int32 aTextLen = aText.getLength();
178 aEditEngine.SetText(aText);
180 // Assert changes - text insertion
181 CPPUNIT_ASSERT_EQUAL(aTextLen, rDoc.GetTextLen());
182 CPPUNIT_ASSERT_EQUAL(aText, rDoc.GetParaAsString(sal_Int32(0)));
184 // Select all paragraphs
185 ESelection aSelection(0, 0, 0, aTextLen);
187 auto doTest = [&](sal_uInt16 nSpace, sal_uInt16 nExpMaxAscent, sal_uInt32 nExpLineHeight)
189 std::unique_ptr<SfxItemSet> pSet(new SfxItemSet(aEditEngine.GetEmptyItemSet()));
190 SvxLineSpacingItem aLineSpacing(LINE_SPACE_DEFAULT_HEIGHT, EE_PARA_SBL);
191 aLineSpacing.SetPropLineSpace(nSpace);
192 pSet->Put(aLineSpacing);
194 // Set font
195 SvxFontItem aFont(EE_CHAR_FONTINFO);
196 aFont.SetFamilyName("Liberation Sans");
197 pSet->Put(aFont);
198 SvxFontHeightItem aFontSize(240, 100, EE_CHAR_FONTHEIGHT);
199 pSet->Put(aFontSize);
201 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(3), pSet->Count());
203 aEditEngine.QuickSetAttribs(*pSet, aSelection);
205 // Assert changes
206 ParaPortion* pParaPortion = aEditEngine.GetParaPortions()[0];
207 ContentNode* const pNode = pParaPortion->GetNode();
208 const SvxLineSpacingItem& rLSItem = pNode->GetContentAttribs().GetItem(EE_PARA_SBL);
209 CPPUNIT_ASSERT_EQUAL(SvxInterLineSpaceRule::Prop, rLSItem.GetInterLineSpaceRule());
210 CPPUNIT_ASSERT_EQUAL(nSpace, rLSItem.GetPropLineSpace());
212 // Check the first line
213 ParagraphInfos aInfo = aEditEngine.GetParagraphInfos(0);
214 CPPUNIT_ASSERT_EQUAL(nExpMaxAscent, aInfo.nFirstLineMaxAscent);
215 CPPUNIT_ASSERT_EQUAL(nExpLineHeight, aEditEngine.GetLineHeight(0));
218 // Test first case - 60%
219 doTest(60, 122, 153);
221 // Force multiple lines
222 aEditEngine.SetPaperSize(Size(1000, 6000));
223 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), aEditEngine.GetLineCount(0));
225 // Test second case - 150%
226 doTest(150, 337, 382);
228 // Test lower Word limit - 6% (factor 0.06)
229 doTest(6, 12, 15);
231 // Test upper Word limit - 13200% (factor 132)
232 doTest(13200, 33615, 33660);
234 #endif
236 void Test::testConstruction()
238 EditEngine aEngine(mpItemPool.get());
240 aEngine.SetText("I am Edit Engine.");
243 bool includes(const uno::Sequence<OUString>& rSeq, std::u16string_view rVal)
245 for (OUString const & s : rSeq)
246 if (s == rVal)
247 return true;
249 return false;
252 void Test::testUnoTextFields()
255 // DATE
256 rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::DATE));
257 uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
258 bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.DateTime");
259 CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
263 // URL
264 rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::URL));
265 uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
266 bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.URL");
267 CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
271 // PAGE
272 rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::PAGE));
273 uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
274 bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.PageNumber");
275 CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
279 // PAGES
280 rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::PAGES));
281 uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
282 bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.PageCount");
283 CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
287 // TIME
288 rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::TIME));
289 uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
290 bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.DateTime");
291 CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
295 // FILE
296 rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::DOCINFO_TITLE));
297 uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
298 bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.docinfo.Title");
299 CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
303 // TABLE
304 rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::TABLE));
305 uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
306 bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.SheetName");
307 CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
311 // EXTENDED TIME
312 rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::EXTENDED_TIME));
313 uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
314 bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.DateTime");
315 CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
319 // EXTENDED FILE
320 rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::EXTENDED_FILE));
321 uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
322 bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.FileName");
323 CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
327 // AUTHOR
328 rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::AUTHOR));
329 uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
330 bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.Author");
331 CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
335 // MEASURE
336 rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::MEASURE));
337 uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
338 bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.Measure");
339 CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
343 // PRESENTATION HEADER
344 rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::PRESENTATION_HEADER));
345 uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
346 bool bGood = includes(aSvcs, u"com.sun.star.presentation.textfield.Header");
347 CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
351 // PRESENTATION FOOTER
352 rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::PRESENTATION_FOOTER));
353 uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
354 bool bGood = includes(aSvcs, u"com.sun.star.presentation.textfield.Footer");
355 CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
359 // PRESENTATION DATE TIME
360 rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::PRESENTATION_DATE_TIME));
361 uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
362 bool bGood = includes(aSvcs, u"com.sun.star.presentation.textfield.DateTime");
363 CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
367 class TestAutoCorrDoc : public SvxAutoCorrDoc
369 public:
370 /// just like the real thing, this dummy modifies the rText parameter :(
371 TestAutoCorrDoc(OUString &rText, LanguageType eLang)
372 : m_rText(rText)
373 , m_eLang(eLang)
376 OUString const& getResult() const
378 return m_rText;
380 private:
381 OUString & m_rText;
382 LanguageType m_eLang;
383 virtual bool Delete( sal_Int32 nStt, sal_Int32 nEnd ) override
385 //fprintf(stderr, "TestAutoCorrDoc::Delete\n");
386 m_rText = m_rText.replaceAt(nStt, nEnd-nStt, u"");
387 return true;
389 virtual bool Insert( sal_Int32 nPos, const OUString& rTxt ) override
391 //fprintf(stderr, "TestAutoCorrDoc::Insert\n");
392 m_rText = m_rText.replaceAt(nPos, 0, rTxt);
393 return true;
395 virtual bool Replace( sal_Int32 nPos, const OUString& rTxt ) override
397 //fprintf(stderr, "TestAutoCorrDoc::Replace\n");
398 return ReplaceRange( nPos, rTxt.getLength(), rTxt );
400 virtual bool ReplaceRange( sal_Int32 nPos, sal_Int32 nLen, const OUString& rTxt ) override
402 //fprintf(stderr, "TestAutoCorrDoc::ReplaceRange %d %d %s\n", nPos, nLen, OUStringToOString(rTxt, RTL_TEXTENCODING_UTF8).getStr());
403 m_rText = m_rText.replaceAt(nPos, nLen, rTxt);
404 return true;
406 virtual void SetAttr( sal_Int32, sal_Int32, sal_uInt16, SfxPoolItem& ) override
408 //fprintf(stderr, "TestAutoCorrDoc::SetAttr\n");
410 virtual bool SetINetAttr( sal_Int32, sal_Int32, const OUString& ) override
412 //fprintf(stderr, "TestAutoCorrDoc::SetINetAttr\n");
413 return true;
415 virtual OUString const* GetPrevPara(bool) override
417 //fprintf(stderr, "TestAutoCorrDoc::GetPrevPara\n");
418 return nullptr;
420 virtual bool ChgAutoCorrWord( sal_Int32& rSttPos,
421 sal_Int32 nEndPos, SvxAutoCorrect& rACorrect,
422 OUString* pPara ) override
424 //fprintf(stderr, "TestAutoCorrDoc::ChgAutoCorrWord\n");
426 if (m_rText.isEmpty())
427 return false;
429 LanguageTag aLanguageTag( m_eLang);
430 const SvxAutocorrWord* pFnd = rACorrect.SearchWordsInList(
431 m_rText, rSttPos, nEndPos, *this, aLanguageTag);
432 if (pFnd && pFnd->IsTextOnly())
434 m_rText = m_rText.replaceAt(rSttPos, nEndPos, pFnd->GetLong());
435 if( pPara )
436 pPara->clear(); // =&pCurNode->GetString();
437 return true;
440 return false;
442 virtual bool TransliterateRTLWord( sal_Int32& /*rSttPos*/,
443 sal_Int32 /*nEndPos*/, bool /*bApply*/ ) override
445 return false;
449 //https://bugs.libreoffice.org/show_bug.cgi?id=55693
450 //Two capitalized letters are not corrected if dash or slash are directly
451 //before the two letters
452 void Test::testAutocorrect()
454 SvxAutoCorrect aAutoCorrect((OUString()), (OUString()));
457 OUString sInput("TEst-TEst");
458 sal_Unicode const cNextChar(' ');
459 bool bNbspRunNext = false;
461 TestAutoCorrDoc aFoo(sInput, LANGUAGE_ENGLISH_US);
462 aAutoCorrect.DoAutoCorrect(aFoo, sInput, sInput.getLength(), cNextChar, true, bNbspRunNext);
464 CPPUNIT_ASSERT_EQUAL_MESSAGE("autocorrect", OUString("Test-Test "), aFoo.getResult());
468 OUString sInput("TEst/TEst");
469 sal_Unicode const cNextChar(' ');
470 bool bNbspRunNext = false;
472 TestAutoCorrDoc aFoo(sInput, LANGUAGE_ENGLISH_US);
473 aAutoCorrect.DoAutoCorrect(aFoo, sInput, sInput.getLength(), cNextChar, true, bNbspRunNext);
475 CPPUNIT_ASSERT_EQUAL_MESSAGE("autocorrect", OUString("Test/Test "), aFoo.getResult());
479 // test auto-bolding with '*'
480 OUString sInput("*foo");
481 sal_Unicode const cNextChar('*');
482 bool bNbspRunNext = false;
484 TestAutoCorrDoc aFoo(sInput, LANGUAGE_ENGLISH_US);
485 aAutoCorrect.DoAutoCorrect(aFoo, sInput, sInput.getLength(), cNextChar, true, bNbspRunNext);
487 CPPUNIT_ASSERT_EQUAL(OUString("foo"), aFoo.getResult());
491 OUString sInput("Test. test");
492 sal_Unicode const cNextChar(' ');
493 bool bNbspRunNext = false;
495 TestAutoCorrDoc aFoo(sInput, LANGUAGE_ENGLISH_US);
496 aAutoCorrect.DoAutoCorrect(aFoo, sInput, sInput.getLength(), cNextChar, true, bNbspRunNext);
498 CPPUNIT_ASSERT_EQUAL_MESSAGE("autocorrect", OUString("Test. Test "), aFoo.getResult());
501 // don't autocapitalize after a field mark
503 OUString sInput("Test. \x01 test");
504 sal_Unicode const cNextChar(' ');
505 bool bNbspRunNext = false;
507 TestAutoCorrDoc aFoo(sInput, LANGUAGE_ENGLISH_US);
508 aAutoCorrect.DoAutoCorrect(aFoo, sInput, sInput.getLength(), cNextChar, true, bNbspRunNext);
510 CPPUNIT_ASSERT_EQUAL_MESSAGE("autocorrect", OUString("Test. \x01 test "), aFoo.getResult());
513 // consider field contents as text for auto quotes
515 OUString sInput("T\x01");
516 sal_Unicode const cNextChar('"');
517 static constexpr OUStringLiteral sExpected = u"T\x01\u201d";
518 bool bNbspRunNext = false;
520 TestAutoCorrDoc aFoo(sInput, LANGUAGE_ENGLISH_US);
521 aAutoCorrect.SetAutoCorrFlag(ACFlags::ChgQuotes, true);
522 aAutoCorrect.DoAutoCorrect(aFoo, sInput, sInput.getLength(), cNextChar, true, bNbspRunNext);
523 fprintf(stderr, "text is %x\n", aFoo.getResult()[aFoo.getResult().getLength() - 1]);
525 CPPUNIT_ASSERT_EQUAL_MESSAGE("autocorrect", OUString(sExpected), aFoo.getResult());
530 IMPL_STATIC_LINK( Test, CalcFieldValueHdl, EditFieldInfo*, pInfo, void )
532 if (!pInfo)
533 return;
535 const SvxFieldItem& rField = pInfo->GetField();
536 const SvxFieldData* pField = rField.GetField();
537 if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
539 // URLField
540 OUString aURL = pURLField->GetURL();
541 switch ( pURLField->GetFormat() )
543 case SvxURLFormat::AppDefault:
544 case SvxURLFormat::Repr:
546 pInfo->SetRepresentation( pURLField->GetRepresentation() );
548 break;
550 case SvxURLFormat::Url:
552 pInfo->SetRepresentation( aURL );
554 break;
557 else
559 OSL_FAIL("Unknown Field");
560 pInfo->SetRepresentation(OUString('?'));
564 void Test::testHyperlinkCopyPaste()
566 // Create Outliner instance
567 Outliner aOutliner(mpItemPool.get(), OutlinerMode
568 ::TextObject);
569 aOutliner.SetCalcFieldValueHdl( LINK( nullptr, Test, CalcFieldValueHdl ) );
571 // Create EditEngine's instance
572 EditEngine& aEditEngine = const_cast<EditEngine&> (aOutliner.GetEditEngine());
574 // Get EditDoc for current EditEngine's instance
575 EditDoc &rDoc = aEditEngine.GetEditDoc();
577 // New instance must be empty - no initial text
578 CPPUNIT_ASSERT_EQUAL( sal_Int32(0), rDoc.GetTextLen() );
579 CPPUNIT_ASSERT_EQUAL( OUString(), rDoc.GetParaAsString(sal_Int32(0)) );
581 // Get corresponding Field Item for inserting URLs in text
582 // URL 1
583 OUString aURL1 = "mailto:///user@example.com";
584 OUString aRepres1 = "user@example.com";
585 SvxURLField aURLField1( aURL1, aRepres1, SvxURLFormat::Repr );
586 SvxFieldItem aField1( aURLField1, EE_FEATURE_FIELD );
587 // URL 2
588 OUString aURL2 = "mailto:///example@domain.com";
589 OUString aRepres2 = "example@domain.com";
590 SvxURLField aURLField2( aURL2, aRepres2, SvxURLFormat::Repr );
591 SvxFieldItem aField2( aURLField2, EE_FEATURE_FIELD );
593 // Insert initial text
594 OUString aParaText = "sampletextfortestingfeaturefields";
595 // Positions Ref .............*13....*20..........
596 sal_Int32 aTextLen = aParaText.getLength();
597 aEditEngine.SetText( aParaText );
599 // Assert changes
600 CPPUNIT_ASSERT_EQUAL( aTextLen, rDoc.GetTextLen() );
601 CPPUNIT_ASSERT_EQUAL( aParaText, rDoc.GetParaAsString(sal_Int32(0)) );
603 // Insert URL 1
604 ContentNode *pNode = rDoc.GetObject(0);
605 EditSelection aSel1( EditPaM(pNode, 13), EditPaM(pNode, 13) );
606 aEditEngine.InsertField( aSel1, aField1 );
608 // Assert Field Count
609 CPPUNIT_ASSERT_EQUAL( sal_uInt16(1), aEditEngine.GetFieldCount(0) );
611 // Insert URL 2
612 EditSelection aSel2( EditPaM(pNode, 20 + 1), EditPaM(pNode, 20 + 1) );
613 aEditEngine.InsertField( aSel2, aField2 );
615 // Assert Field Count
616 CPPUNIT_ASSERT_EQUAL( sal_uInt16(2), aEditEngine.GetFieldCount(0) );
618 // Assert URL Fields and text before copy
619 // Check text
620 CPPUNIT_ASSERT_EQUAL( aTextLen + aRepres1.getLength() + aRepres2.getLength(), rDoc.GetTextLen() );
621 CPPUNIT_ASSERT_EQUAL( OUString("sampletextforuser@example.comtestingexample@domain.comfeaturefields"), rDoc.GetParaAsString(sal_Int32(0)) );
623 // Check Field 1
624 EFieldInfo aURLFieldInfo1 = aEditEngine.GetFieldInfo( sal_Int32(0), sal_uInt16(0) );
625 CPPUNIT_ASSERT_EQUAL( sal_Int32(13), aURLFieldInfo1.aPosition.nIndex );
626 CPPUNIT_ASSERT_EQUAL( sal_uInt16(EE_FEATURE_FIELD), aURLFieldInfo1.pFieldItem->Which() );
627 SvxURLField* pURLField1 = dynamic_cast<SvxURLField*> ( const_cast<SvxFieldData*> (aURLFieldInfo1.pFieldItem->GetField()) );
628 CPPUNIT_ASSERT(pURLField1);
629 CPPUNIT_ASSERT_EQUAL( aURL1, pURLField1->GetURL() );
630 CPPUNIT_ASSERT_EQUAL( aRepres1, pURLField1->GetRepresentation() );
632 // Check Field 2
633 EFieldInfo aURLFieldInfo2 = aEditEngine.GetFieldInfo( sal_Int32(0), sal_uInt16(1) );
634 CPPUNIT_ASSERT_EQUAL( sal_Int32(21), aURLFieldInfo2.aPosition.nIndex );
635 CPPUNIT_ASSERT_EQUAL( sal_uInt16(EE_FEATURE_FIELD), aURLFieldInfo2.pFieldItem->Which() );
636 SvxURLField* pURLField2 = dynamic_cast<SvxURLField*> ( const_cast<SvxFieldData*> (aURLFieldInfo2.pFieldItem->GetField()) );
637 CPPUNIT_ASSERT(pURLField2);
638 CPPUNIT_ASSERT_EQUAL( aURL2, pURLField2->GetURL() );
639 CPPUNIT_ASSERT_EQUAL( aRepres2, pURLField2->GetRepresentation() );
641 // Copy text using legacy format
642 uno::Reference< datatransfer::XTransferable > xData = aEditEngine.CreateTransferable( ESelection(0,10,0,21) );
644 // Paste text at the end
645 aEditEngine.InsertText( xData, OUString(), rDoc.GetEndPaM(), true );
647 // Assert Changes ACP, ACP: after Copy/Paste
649 // Check the fields count
650 CPPUNIT_ASSERT_EQUAL( sal_uInt16(3), aEditEngine.GetFieldCount(0) );
652 // Check the updated text length
653 CPPUNIT_ASSERT_EQUAL( aTextLen + 10 + aRepres1.getLength()*2 + aRepres2.getLength(), rDoc.GetTextLen() );
655 // Check the updated text contents
656 CPPUNIT_ASSERT_EQUAL( OUString("sampletextforuser@example.comtestingexample@domain.comfeaturefieldsforuser@example.comtesting"), rDoc.GetParaAsString(sal_Int32(0)) );
658 // Check the Fields and their values
660 // Field 1
661 EFieldInfo aACPURLFieldInfo1 = aEditEngine.GetFieldInfo( sal_Int32(0), sal_uInt16(0) );
662 CPPUNIT_ASSERT_EQUAL( sal_Int32(13), aACPURLFieldInfo1.aPosition.nIndex );
663 CPPUNIT_ASSERT_EQUAL( sal_uInt16(EE_FEATURE_FIELD), aACPURLFieldInfo1.pFieldItem->Which() );
664 SvxURLField* pACPURLField1 = dynamic_cast<SvxURLField*> ( const_cast<SvxFieldData*> (aACPURLFieldInfo1.pFieldItem->GetField()) );
665 CPPUNIT_ASSERT(pACPURLField1);
666 CPPUNIT_ASSERT_EQUAL( aURL1, pACPURLField1->GetURL() );
667 CPPUNIT_ASSERT_EQUAL( aRepres1, pACPURLField1->GetRepresentation() );
669 // Field 2
670 EFieldInfo aACPURLFieldInfo2 = aEditEngine.GetFieldInfo( sal_Int32(0), sal_uInt16(1) );
671 CPPUNIT_ASSERT_EQUAL( sal_Int32(21), aACPURLFieldInfo2.aPosition.nIndex );
672 CPPUNIT_ASSERT_EQUAL( sal_uInt16(EE_FEATURE_FIELD), aACPURLFieldInfo2.pFieldItem->Which() );
673 SvxURLField* pACPURLField2 = dynamic_cast<SvxURLField*> ( const_cast<SvxFieldData*> (aACPURLFieldInfo2.pFieldItem->GetField()) );
674 CPPUNIT_ASSERT(pACPURLField2);
675 CPPUNIT_ASSERT_EQUAL( aURL2, pACPURLField2->GetURL() );
676 CPPUNIT_ASSERT_EQUAL( aRepres2, pACPURLField2->GetRepresentation() ) ;
678 // Field 3
679 EFieldInfo aACPURLFieldInfo3 = aEditEngine.GetFieldInfo( sal_Int32(0), sal_uInt16(2) );
680 CPPUNIT_ASSERT_EQUAL( sal_Int32(38), aACPURLFieldInfo3.aPosition.nIndex );
681 CPPUNIT_ASSERT_EQUAL( sal_uInt16(EE_FEATURE_FIELD), aACPURLFieldInfo3.pFieldItem->Which() );
682 SvxURLField* pACPURLField3 = dynamic_cast<SvxURLField*> ( const_cast<SvxFieldData*> (aACPURLFieldInfo3.pFieldItem->GetField()) );
683 CPPUNIT_ASSERT(pACPURLField3);
684 CPPUNIT_ASSERT_EQUAL( aURL1, pACPURLField3->GetURL() );
685 CPPUNIT_ASSERT_EQUAL( aRepres1, pACPURLField3->GetRepresentation() );
688 void Test::testCopyPaste()
690 // Create EditEngine's instance
691 EditEngine aEditEngine( mpItemPool.get() );
693 // Get EditDoc for current EditEngine's instance
694 EditDoc &rDoc = aEditEngine.GetEditDoc();
696 // Initially no text should be there
697 CPPUNIT_ASSERT_EQUAL( sal_Int32(0), rDoc.GetTextLen() );
698 CPPUNIT_ASSERT_EQUAL( OUString(), rDoc.GetParaAsString(sal_Int32(0)) );
700 // Set initial text
701 OUString aText = "This is custom initial text";
702 sal_Int32 aTextLen = aText.getLength();
703 aEditEngine.SetText( aText );
705 // Assert changes
706 CPPUNIT_ASSERT_EQUAL( aTextLen, rDoc.GetTextLen() );
707 CPPUNIT_ASSERT_EQUAL( aText, rDoc.GetParaAsString(sal_Int32(0)) );
709 // Copy initial text using legacy format
710 uno::Reference< datatransfer::XTransferable > xData = aEditEngine.CreateTransferable( ESelection(0,0,0,aTextLen) );
712 // Paste text at the end
713 aEditEngine.InsertText( xData, OUString(), rDoc.GetEndPaM(), true );
715 // Assert changes
716 CPPUNIT_ASSERT_EQUAL( aTextLen + aTextLen, rDoc.GetTextLen() );
717 CPPUNIT_ASSERT_EQUAL( OUString(aText + aText), rDoc.GetParaAsString(sal_Int32(0)) );
720 /// XTransferable implementation that provides simple HTML content.
721 class TestHTMLTransferable : public cppu::WeakImplHelper<datatransfer::XTransferable>
723 OString m_aHTML;
724 public:
725 TestHTMLTransferable(const OString& rHTML);
726 uno::Any SAL_CALL getTransferData(const datatransfer::DataFlavor& rFlavor) override;
727 uno::Sequence<datatransfer::DataFlavor> SAL_CALL getTransferDataFlavors() override;
728 sal_Bool SAL_CALL isDataFlavorSupported(const datatransfer::DataFlavor& rFlavor) override;
731 TestHTMLTransferable::TestHTMLTransferable(const OString& rHTML)
732 : m_aHTML(rHTML)
736 uno::Any TestHTMLTransferable::getTransferData(const datatransfer::DataFlavor& rFlavor)
738 if (rFlavor.MimeType != "text/html")
740 return {};
743 uno::Any aRet;
744 SvMemoryStream aStream;
745 aStream.WriteOString(m_aHTML);
746 aRet <<= uno::Sequence<sal_Int8>(static_cast<const sal_Int8*>(aStream.GetData()), aStream.GetSize());
747 return aRet;
750 uno::Sequence<datatransfer::DataFlavor> TestHTMLTransferable::getTransferDataFlavors()
752 datatransfer::DataFlavor aFlavor;
753 aFlavor.DataType = cppu::UnoType<uno::Sequence<sal_Int8>>::get();
754 aFlavor.MimeType = "text/html";
755 aFlavor.HumanPresentableName = aFlavor.MimeType;
756 return { aFlavor };
759 sal_Bool TestHTMLTransferable::isDataFlavorSupported(const datatransfer::DataFlavor& rFlavor)
761 return rFlavor.MimeType == "text/html"
762 && rFlavor.DataType == cppu::UnoType<uno::Sequence<sal_Int8>>::get();
765 void Test::testHTMLPaste()
767 // Given an empty editeng document:
768 EditEngine aEditEngine(mpItemPool.get());
769 EditDoc &rDoc = aEditEngine.GetEditDoc();
770 OString aHTML("<!DOCTYPE html>\n<html><body>test</body></html>"_ostr);
771 uno::Reference< datatransfer::XTransferable > xData(new TestHTMLTransferable(aHTML));
773 // When trying to paste HTML:
774 aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true);
776 // Then make sure the text gets pasted:
777 // Without the accompanying fix in place, this test would have failed with:
778 // - Expected: test
779 // - Actual :
780 // i.e. RTF and plain text paste worked, but not HTML.
781 CPPUNIT_ASSERT_EQUAL(OUString("test"), rDoc.GetParaAsString(static_cast<sal_Int32>(0)));
784 void Test::testHTMLFragmentPaste()
786 // Given an empty editeng document:
787 EditEngine aEditEngine(mpItemPool.get());
788 EditDoc &rDoc = aEditEngine.GetEditDoc();
789 OString aHTML("a<b>b</b>c"_ostr);
790 uno::Reference< datatransfer::XTransferable > xData(new TestHTMLTransferable(aHTML));
792 // When trying to paste an HTML fragment:
793 aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true);
795 // Then make sure the text gets pasted:
796 // Without the accompanying fix in place, this test would have failed with:
797 // - Expected: abc
798 // - Actual :
799 // i.e. a HTML fragment without a proper header was ignored on paste.
800 CPPUNIT_ASSERT_EQUAL(OUString("abc"), rDoc.GetParaAsString(static_cast<sal_Int32>(0)));
803 void Test::testMultiParaSelCopyPaste()
805 // Create EditEngine's instance
806 EditEngine aEditEngine( mpItemPool.get() );
808 // Get EditDoc for current EditEngine's instance
809 EditDoc &rDoc = aEditEngine.GetEditDoc();
811 // Initially no text should be there
812 CPPUNIT_ASSERT_EQUAL( sal_Int32(0), rDoc.GetTextLen() );
813 CPPUNIT_ASSERT_EQUAL( OUString(), rDoc.GetParaAsString(sal_Int32(0)) );
815 // Insert initial text
816 OUString aFirstPara = "This is first paragraph";
817 // Selection Ref ........8..............
818 OUString aSecondPara = "This is second paragraph";
819 // Selection Ref .............14.........
820 OUString aThirdPara = "This is third paragraph";
821 OUString aText = aFirstPara + "\n" + aSecondPara + "\n" + aThirdPara;
822 sal_Int32 aTextLen = aFirstPara.getLength() + aSecondPara.getLength() + aThirdPara.getLength();
823 aEditEngine.SetText( aText );
824 OUString aCopyText = "first paragraphThis is second";
825 sal_Int32 aCopyTextLen = aCopyText.getLength();
827 // Assert changes
828 CPPUNIT_ASSERT_EQUAL( aTextLen, rDoc.GetTextLen() );
829 CPPUNIT_ASSERT_EQUAL( aFirstPara, rDoc.GetParaAsString(sal_Int32(0)) );
830 CPPUNIT_ASSERT_EQUAL( aSecondPara, rDoc.GetParaAsString(sal_Int32(1)) );
831 CPPUNIT_ASSERT_EQUAL( aThirdPara, rDoc.GetParaAsString(sal_Int32(2)) );
833 // Copy initial text using legacy format
834 uno::Reference< datatransfer::XTransferable > xData = aEditEngine.CreateTransferable( ESelection(0,8,1,14) );
836 // Paste text at the end
837 aEditEngine.InsertText( xData, OUString(), rDoc.GetEndPaM(), true );
839 // Assert changes
840 OUString aThirdParaAfterCopyPaste = aThirdPara + "first paragraph";
841 CPPUNIT_ASSERT_EQUAL( aTextLen + aCopyTextLen, rDoc.GetTextLen() );
842 CPPUNIT_ASSERT_EQUAL( aFirstPara, rDoc.GetParaAsString(sal_Int32(0)) );
843 CPPUNIT_ASSERT_EQUAL( aSecondPara, rDoc.GetParaAsString(sal_Int32(1)) );
844 CPPUNIT_ASSERT_EQUAL( aThirdParaAfterCopyPaste, rDoc.GetParaAsString(sal_Int32(2)) );
845 CPPUNIT_ASSERT_EQUAL( OUString("This is second"), rDoc.GetParaAsString(sal_Int32(3)) );
848 void Test::testTabsCopyPaste()
850 // Create EditEngine's instance
851 EditEngine aEditEngine( mpItemPool.get() );
853 // Get EditDoc for current EditEngine's instance
854 EditDoc &rDoc = aEditEngine.GetEditDoc();
856 // New instance must be empty - no initial text
857 CPPUNIT_ASSERT_EQUAL( sal_Int32(0), rDoc.GetTextLen() );
858 CPPUNIT_ASSERT_EQUAL( OUString(), rDoc.GetParaAsString(sal_Int32(0)) );
860 // Get corresponding Item for inserting tabs in the text
861 SfxVoidItem aTab( EE_FEATURE_TAB );
863 // Insert initial text
864 OUString aParaText = "sampletextfortestingtab";
865 // Positions Ref ......*6...............*23
866 sal_Int32 aTextLen = aParaText.getLength();
867 aEditEngine.SetText( aParaText );
869 // Assert changes
870 CPPUNIT_ASSERT_EQUAL( aTextLen, rDoc.GetTextLen() );
871 CPPUNIT_ASSERT_EQUAL( aParaText, rDoc.GetParaAsString(sal_Int32(0)) );
873 // Insert tab 1 at desired position
874 ContentNode *pNode = rDoc.GetObject(0);
875 EditSelection aSel1( EditPaM(pNode, 6), EditPaM(pNode, 6) );
876 aEditEngine.InsertFeature( aSel1, aTab );
878 // Assert changes
879 CPPUNIT_ASSERT_EQUAL( aTextLen + 1, rDoc.GetTextLen() );
880 CPPUNIT_ASSERT_EQUAL( OUString("sample\ttextfortestingtab"), rDoc.GetParaAsString(sal_Int32(0)) );
882 // Insert tab 2 at desired position
883 EditSelection aSel2( EditPaM(pNode, 23+1), EditPaM(pNode, 23+1) );
884 aEditEngine.InsertFeature( aSel2, aTab );
886 // Assert changes
887 CPPUNIT_ASSERT_EQUAL( aTextLen + 2, rDoc.GetTextLen() );
888 CPPUNIT_ASSERT_EQUAL( OUString("sample\ttextfortestingtab\t"), rDoc.GetParaAsString(sal_Int32(0)) );
890 // Copy text using legacy format
891 uno::Reference< datatransfer::XTransferable > xData = aEditEngine.CreateTransferable( ESelection(0,6,0,aTextLen+2) );
893 // Paste text at the end
894 aEditEngine.InsertText( xData, OUString(), rDoc.GetEndPaM(), true );
896 // Assert changes
897 CPPUNIT_ASSERT_EQUAL( aTextLen + aTextLen - 6 + 4, rDoc.GetTextLen() );
898 CPPUNIT_ASSERT_EQUAL( OUString("sample\ttextfortestingtab\t\ttextfortestingtab\t"), rDoc.GetParaAsString(sal_Int32(0)) );
901 class UrlEditEngine : public EditEngine
903 public:
904 explicit UrlEditEngine(SfxItemPool *pPool) : EditEngine(pPool) {}
906 virtual OUString CalcFieldValue( const SvxFieldItem&, sal_Int32, sal_Int32, std::optional<Color>&, std::optional<Color>&, std::optional<FontLineStyle>& ) override
908 return "jim@bob.com"; // a sophisticated view of value:
912 // Odd accounting for hyperlink position & size etc.
913 // https://bugzilla.novell.com/show_bug.cgi?id=467459
914 void Test::testHyperlinkSearch()
916 UrlEditEngine aEngine(mpItemPool.get());
917 EditDoc &rDoc = aEngine.GetEditDoc();
919 OUString aSampleText = "Please write email to . if you find a fish(not a dog).";
920 aEngine.SetText(aSampleText);
922 CPPUNIT_ASSERT_EQUAL_MESSAGE("set text", aSampleText, rDoc.GetParaAsString(sal_Int32(0)));
924 ContentNode *pNode = rDoc.GetObject(0);
925 EditSelection aSel(EditPaM(pNode, 22), EditPaM(pNode, 22));
926 SvxURLField aURLField("mailto:///jim@bob.com", "jim@bob.com",
927 SvxURLFormat::Repr);
928 SvxFieldItem aField(aURLField, EE_FEATURE_FIELD);
930 aEngine.InsertField(aSel, aField);
932 OUString aContent = pNode->GetExpandedText();
933 CPPUNIT_ASSERT_EQUAL_MESSAGE("get text", OUString("Please write email to jim@bob.com. if you find a fish(not a dog)."),
934 aContent);
935 CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong length", aContent.getLength(), rDoc.GetTextLen());
937 // Check expansion and positioning re-work
938 CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong length", aContent.getLength(),
939 pNode->GetExpandedLen());
940 for (sal_Int32 n = 0; n < aContent.getLength(); n++)
942 sal_Int32 nStart = n, nEnd = n;
943 pNode->UnExpandPositions(nStart,nEnd);
944 CPPUNIT_ASSERT_MESSAGE("out of bound start", nStart < pNode->Len());
945 CPPUNIT_ASSERT_MESSAGE("out of bound end", nEnd <= pNode->Len());
948 static const struct {
949 sal_Int32 mnStart, mnEnd;
950 sal_Int32 mnNewStart, mnNewEnd;
951 } aTrickyOnes[] = {
952 { 0, 1, /* -> */ 0, 1 },
953 { 21, 25, /* -> */ 21, 23 }, // the field is really just one char
954 { 25, 27, /* -> */ 22, 23 },
955 { 50, 56, /* -> */ 40, 46 }
957 for (size_t n = 0; n < SAL_N_ELEMENTS(aTrickyOnes); n++)
959 sal_Int32 nStart = aTrickyOnes[n].mnStart;
960 sal_Int32 nEnd = aTrickyOnes[n].mnEnd;
961 pNode->UnExpandPositions(nStart,nEnd);
963 CPPUNIT_ASSERT_EQUAL_MESSAGE(
964 OString("in row " + OString::number(n)).getStr(),
965 aTrickyOnes[n].mnNewStart, nStart);
966 CPPUNIT_ASSERT_EQUAL_MESSAGE(
967 OString("in row " + OString::number(n)).getStr(),
968 aTrickyOnes[n].mnNewEnd, nEnd);
971 SvxSearchItem aItem(1); //SID_SEARCH_ITEM);
972 aItem.SetBackward(false);
973 aItem.SetSelection(false);
974 aItem.SetSearchString("fish");
975 CPPUNIT_ASSERT_MESSAGE("no fish", aEngine.HasText(aItem));
976 aItem.SetSearchString("dog");
977 CPPUNIT_ASSERT_MESSAGE("no dog", aEngine.HasText(aItem));
980 bool hasBold(const editeng::Section& rSecAttr)
982 return std::any_of(rSecAttr.maAttributes.begin(), rSecAttr.maAttributes.end(),
983 [](const SfxPoolItem* p) {
984 return p->Which() == EE_CHAR_WEIGHT
985 && static_cast<const SvxWeightItem*>(p)->GetWeight() == WEIGHT_BOLD;
989 bool hasItalic(const editeng::Section& rSecAttr)
991 return std::any_of(rSecAttr.maAttributes.begin(), rSecAttr.maAttributes.end(),
992 [](const SfxPoolItem* p) {
993 return p->Which() == EE_CHAR_ITALIC
994 && static_cast<const SvxPostureItem*>(p)->GetPosture() == ITALIC_NORMAL;
998 void Test::testBoldItalicCopyPaste()
1000 // Create EditEngine's instance
1001 EditEngine aEditEngine( mpItemPool.get() );
1003 // Get EditDoc for current EditEngine's instance
1004 EditDoc &rDoc = aEditEngine.GetEditDoc();
1006 // New instance must be empty - no initial text
1007 CPPUNIT_ASSERT_EQUAL( sal_Int32(0), rDoc.GetTextLen() );
1008 CPPUNIT_ASSERT_EQUAL( OUString(), rDoc.GetParaAsString(sal_Int32(0)) );
1010 // Get corresponding ItemSet for inserting Bold/Italic text
1011 std::unique_ptr<SfxItemSet> pSet( new SfxItemSet(aEditEngine.GetEmptyItemSet()) );
1012 SvxWeightItem aBold( WEIGHT_BOLD, EE_CHAR_WEIGHT );
1013 SvxPostureItem aItalic( ITALIC_NORMAL, EE_CHAR_ITALIC );
1015 // Insert initial text
1016 OUString aParaText = "boldeditengineitalic";
1017 // Positions Ref ..*2....*8...*13.*17
1018 // Bold Ref ..[ BOLD ]......
1019 // Italic Ref ........[ ITALIC ]..
1020 sal_Int32 aTextLen = aParaText.getLength();
1021 aEditEngine.SetText( aParaText );
1023 // Assert changes - text insertion
1024 CPPUNIT_ASSERT_EQUAL( aTextLen, rDoc.GetTextLen() );
1025 CPPUNIT_ASSERT_EQUAL( aParaText, rDoc.GetParaAsString(sal_Int32(0)) );
1027 // Apply Bold to appropriate selection
1028 pSet->Put(aBold);
1029 CPPUNIT_ASSERT_EQUAL( static_cast<sal_uInt16>(1), pSet->Count() );
1030 aEditEngine.QuickSetAttribs( *pSet, ESelection(0,2,0,14) );
1032 // Assert changes
1033 std::unique_ptr<EditTextObject> pEditText1( aEditEngine.CreateTextObject() );
1034 std::vector<editeng::Section> aAttrs1;
1035 pEditText1->GetAllSections( aAttrs1 );
1036 // There should be 3 sections - woBold - wBold - woBold (w - with, wo - without)
1037 CPPUNIT_ASSERT_EQUAL( size_t(3), aAttrs1.size() );
1039 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[0].mnParagraph) );
1040 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[0].mnStart) );
1041 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs1[0].mnEnd) );
1042 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[0].maAttributes.size()) );
1044 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[1].mnParagraph) );
1045 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs1[1].mnStart) );
1046 CPPUNIT_ASSERT_EQUAL( 14, static_cast<int>(aAttrs1[1].mnEnd) );
1047 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs1[1].maAttributes.size()) );
1048 CPPUNIT_ASSERT_MESSAGE( "This section must be bold.", hasBold(aAttrs1[1]) );
1050 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[2].mnParagraph) );
1051 CPPUNIT_ASSERT_EQUAL( 14, static_cast<int>(aAttrs1[2].mnStart) );
1052 CPPUNIT_ASSERT_EQUAL( 20, static_cast<int>(aAttrs1[2].mnEnd) );
1053 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[2].maAttributes.size()) );
1055 // Apply Italic to appropriate selection
1056 pSet.reset( new SfxItemSet(aEditEngine.GetEmptyItemSet()) );
1057 pSet->Put(aItalic);
1058 CPPUNIT_ASSERT_EQUAL( static_cast<sal_uInt16>(1), pSet->Count() );
1059 aEditEngine.QuickSetAttribs( *pSet, ESelection(0,8,0,18) );
1061 // Assert changes
1062 std::unique_ptr<EditTextObject> pEditText2( aEditEngine.CreateTextObject() );
1063 std::vector<editeng::Section> aAttrs2;
1064 pEditText2->GetAllSections( aAttrs2 );
1065 // There should be 5 sections - woBold&woItalic - wBold&woItalic - wBold&wItalic - woBold&wItalic - woBold&woItalic (w - with, wo - without)
1066 CPPUNIT_ASSERT_EQUAL( size_t(5), aAttrs2.size() );
1068 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[0].mnParagraph) );
1069 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[0].mnStart) );
1070 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs2[0].mnEnd) );
1071 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[0].maAttributes.size()) );
1073 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[1].mnParagraph) );
1074 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs2[1].mnStart) );
1075 CPPUNIT_ASSERT_EQUAL( 8, static_cast<int>(aAttrs2[1].mnEnd) );
1076 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs2[1].maAttributes.size()) );
1077 CPPUNIT_ASSERT_MESSAGE( "This section must be bold.", hasBold(aAttrs2[1]) );
1079 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[2].mnParagraph) );
1080 CPPUNIT_ASSERT_EQUAL( 8, static_cast<int>(aAttrs2[2].mnStart) );
1081 CPPUNIT_ASSERT_EQUAL( 14, static_cast<int>(aAttrs2[2].mnEnd) );
1082 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs2[2].maAttributes.size()) );
1083 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasBold(aAttrs2[2]) );
1084 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasItalic(aAttrs2[2]) );
1086 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[3].mnParagraph) );
1087 CPPUNIT_ASSERT_EQUAL( 14, static_cast<int>(aAttrs2[3].mnStart) );
1088 CPPUNIT_ASSERT_EQUAL( 18, static_cast<int>(aAttrs2[3].mnEnd) );
1089 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs2[3].maAttributes.size()) );
1090 CPPUNIT_ASSERT_MESSAGE( "This section must be italic.", hasItalic(aAttrs2[3]) );
1092 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[4].mnParagraph) );
1093 CPPUNIT_ASSERT_EQUAL( 18, static_cast<int>(aAttrs2[4].mnStart) );
1094 CPPUNIT_ASSERT_EQUAL( 20, static_cast<int>(aAttrs2[4].mnEnd) );
1095 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[4].maAttributes.size()) );
1097 // Copy text using legacy format
1098 uno::Reference< datatransfer::XTransferable > xData = aEditEngine.CreateTransferable( ESelection(0,1,0,aTextLen-1) );
1100 // Paste text at the end
1101 aEditEngine.InsertText( xData, OUString(), rDoc.GetEndPaM(), true );
1103 // Assert changes
1104 CPPUNIT_ASSERT_EQUAL( aTextLen + aTextLen - 2, rDoc.GetTextLen() );
1105 CPPUNIT_ASSERT_EQUAL( OUString(aParaText + "oldeditengineitali" ), rDoc.GetParaAsString(sal_Int32(0)) );
1107 // Check updated text for appropriate Bold/Italics
1108 std::unique_ptr<EditTextObject> pEditText3( aEditEngine.CreateTextObject() );
1109 std::vector<editeng::Section> aAttrs3;
1110 pEditText3->GetAllSections( aAttrs3 );
1111 // There should be 9 sections - woBold&woItalic - wBold&woItalic - wBold&wItalic - woBold&wItalic - woBold&woItalic - wBold&woItalic
1112 // - wBold&wItalic - woBold&wItalic - woBold&woItalic(w - with, wo - without)
1113 CPPUNIT_ASSERT_EQUAL( size_t(9), aAttrs3.size() );
1115 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[0].mnParagraph) );
1116 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[0].mnStart) );
1117 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs3[0].mnEnd) );
1118 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[0].maAttributes.size()) );
1120 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[1].mnParagraph) );
1121 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs3[1].mnStart) );
1122 CPPUNIT_ASSERT_EQUAL( 8, static_cast<int>(aAttrs3[1].mnEnd) );
1123 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs3[1].maAttributes.size()) );
1124 CPPUNIT_ASSERT_MESSAGE( "This section must be bold.", hasBold(aAttrs3[1]) );
1126 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[2].mnParagraph) );
1127 CPPUNIT_ASSERT_EQUAL( 8, static_cast<int>(aAttrs3[2].mnStart) );
1128 CPPUNIT_ASSERT_EQUAL( 14, static_cast<int>(aAttrs3[2].mnEnd) );
1129 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs3[2].maAttributes.size()) );
1130 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasBold(aAttrs3[2]) );
1131 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasItalic(aAttrs3[2]) );
1133 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[3].mnParagraph) );
1134 CPPUNIT_ASSERT_EQUAL( 14, static_cast<int>(aAttrs3[3].mnStart) );
1135 CPPUNIT_ASSERT_EQUAL( 18, static_cast<int>(aAttrs3[3].mnEnd) );
1136 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs3[3].maAttributes.size()) );
1137 CPPUNIT_ASSERT_MESSAGE( "This section must be italic.", hasItalic(aAttrs3[3]) );
1139 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[4].mnParagraph) );
1140 CPPUNIT_ASSERT_EQUAL( 18, static_cast<int>(aAttrs3[4].mnStart) );
1141 CPPUNIT_ASSERT_EQUAL( 21, static_cast<int>(aAttrs3[4].mnEnd) );
1142 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[4].maAttributes.size()) );
1144 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[5].mnParagraph) );
1145 CPPUNIT_ASSERT_EQUAL( 21, static_cast<int>(aAttrs3[5].mnStart) );
1146 CPPUNIT_ASSERT_EQUAL( 27, static_cast<int>(aAttrs3[5].mnEnd) );
1147 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs3[5].maAttributes.size()) );
1148 CPPUNIT_ASSERT_MESSAGE( "This section must be bold.", hasBold(aAttrs3[5]) );
1150 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[6].mnParagraph) );
1151 CPPUNIT_ASSERT_EQUAL( 27, static_cast<int>(aAttrs3[6].mnStart) );
1152 CPPUNIT_ASSERT_EQUAL( 33, static_cast<int>(aAttrs3[6].mnEnd) );
1153 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs3[6].maAttributes.size()) );
1154 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasBold(aAttrs3[6]) );
1155 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasItalic(aAttrs3[6]) );
1157 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[7].mnParagraph) );
1158 CPPUNIT_ASSERT_EQUAL( 33, static_cast<int>(aAttrs3[7].mnStart) );
1159 CPPUNIT_ASSERT_EQUAL( 37, static_cast<int>(aAttrs3[7].mnEnd) );
1160 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs3[7].maAttributes.size()) );
1161 CPPUNIT_ASSERT_MESSAGE( "This section must be italic.", hasItalic(aAttrs3[7]) );
1163 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[8].mnParagraph) );
1164 CPPUNIT_ASSERT_EQUAL( 37, static_cast<int>(aAttrs3[8].mnStart) );
1165 CPPUNIT_ASSERT_EQUAL( 38, static_cast<int>(aAttrs3[8].mnEnd) );
1166 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[8].maAttributes.size()) );
1169 // Auxiliary function to test Underline text Copy/Paste using Legacy Format
1170 bool hasUnderline(const editeng::Section& rSecAttr)
1172 return std::any_of(rSecAttr.maAttributes.begin(), rSecAttr.maAttributes.end(),
1173 [](const SfxPoolItem* p) {
1174 return p->Which() == EE_CHAR_UNDERLINE
1175 && static_cast<const SvxUnderlineItem*>(p)->GetLineStyle() == LINESTYLE_SINGLE;
1179 void Test::testUnderlineCopyPaste()
1181 // Create EditEngine's instance
1182 EditEngine aEditEngine( mpItemPool.get() );
1184 // Get EditDoc for current EditEngine's instance
1185 EditDoc &rDoc = aEditEngine.GetEditDoc();
1187 // New instance must be empty - no initial text
1188 CPPUNIT_ASSERT_EQUAL( sal_Int32(0), rDoc.GetTextLen() );
1189 CPPUNIT_ASSERT_EQUAL( OUString(), rDoc.GetParaAsString(sal_Int32(0)) );
1191 // Get corresponding ItemSet for inserting Underline text
1192 std::unique_ptr<SfxItemSet> pSet( new SfxItemSet(aEditEngine.GetEmptyItemSet()) );
1193 SvxUnderlineItem aULine( LINESTYLE_SINGLE, EE_CHAR_UNDERLINE );
1195 // Insert initial text
1196 OUString aParaText = "sampletextforunderline";
1197 // Positions Ref ......*6.........*17..
1198 // Underline Ref ......[UNDERLINE ]....
1199 sal_Int32 aTextLen = aParaText.getLength();
1200 aEditEngine.SetText( aParaText );
1202 // Apply Underline style
1203 pSet->Put( aULine );
1204 CPPUNIT_ASSERT_EQUAL( static_cast<sal_uInt16>(1), pSet->Count() );
1205 aEditEngine.QuickSetAttribs( *pSet, ESelection(0,6,0,18) );
1207 // Assert changes
1208 std::unique_ptr<EditTextObject> pEditText1( aEditEngine.CreateTextObject() );
1209 std::vector<editeng::Section> aAttrs1;
1210 pEditText1->GetAllSections( aAttrs1 );
1212 // There should be 3 sections - woUnderline - wUnderline - woUnderline (w - with, wo - without)
1213 CPPUNIT_ASSERT_EQUAL( size_t(3), aAttrs1.size() );
1215 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[0].mnParagraph) );
1216 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[0].mnStart) );
1217 CPPUNIT_ASSERT_EQUAL( 6, static_cast<int>(aAttrs1[0].mnEnd) );
1218 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[0].maAttributes.size()) );
1220 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[1].mnParagraph) );
1221 CPPUNIT_ASSERT_EQUAL( 6, static_cast<int>(aAttrs1[1].mnStart) );
1222 CPPUNIT_ASSERT_EQUAL( 18, static_cast<int>(aAttrs1[1].mnEnd) );
1223 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs1[1].maAttributes.size()) );
1224 CPPUNIT_ASSERT_MESSAGE( "This section must be underlined.", hasUnderline(aAttrs1[1]) );
1226 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[2].mnParagraph) );
1227 CPPUNIT_ASSERT_EQUAL( 18, static_cast<int>(aAttrs1[2].mnStart) );
1228 CPPUNIT_ASSERT_EQUAL( 22, static_cast<int>(aAttrs1[2].mnEnd) );
1229 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[2].maAttributes.size()) );
1231 // Copy text using legacy format
1232 uno::Reference< datatransfer::XTransferable > xData = aEditEngine.CreateTransferable( ESelection(0,6,0,aTextLen-4) );
1234 // Paste text at the end
1235 aEditEngine.InsertText( xData, OUString(), rDoc.GetEndPaM(), true );
1237 // Assert changes
1238 CPPUNIT_ASSERT_EQUAL( static_cast<sal_Int32>(aTextLen + strlen("textforunder")), rDoc.GetTextLen() );
1239 CPPUNIT_ASSERT_EQUAL( OUString(aParaText + "textforunder" ), rDoc.GetParaAsString(sal_Int32(0)) );
1241 // Check updated text for appropriate Underline
1242 std::unique_ptr<EditTextObject> pEditText2( aEditEngine.CreateTextObject() );
1243 std::vector<editeng::Section> aAttrs2;
1244 pEditText2->GetAllSections( aAttrs2 );
1246 // There should be 4 sections - woUnderline - wUnderline - woUnderline - wUnderline (w - with, wo - without)
1247 CPPUNIT_ASSERT_EQUAL( size_t(4), aAttrs2.size() );
1249 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[0].mnParagraph) );
1250 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[0].mnStart) );
1251 CPPUNIT_ASSERT_EQUAL( 6, static_cast<int>(aAttrs2[0].mnEnd) );
1252 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[0].maAttributes.size()) );
1254 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[1].mnParagraph) );
1255 CPPUNIT_ASSERT_EQUAL( 6, static_cast<int>(aAttrs2[1].mnStart) );
1256 CPPUNIT_ASSERT_EQUAL( 18, static_cast<int>(aAttrs2[1].mnEnd) );
1257 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs2[1].maAttributes.size()) );
1258 CPPUNIT_ASSERT_MESSAGE( "This section must be underlined.", hasUnderline(aAttrs2[1]) );
1260 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[2].mnParagraph) );
1261 CPPUNIT_ASSERT_EQUAL( 18, static_cast<int>(aAttrs2[2].mnStart) );
1262 CPPUNIT_ASSERT_EQUAL( 22, static_cast<int>(aAttrs2[2].mnEnd) );
1263 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[2].maAttributes.size()) );
1265 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[3].mnParagraph) );
1266 CPPUNIT_ASSERT_EQUAL( 22, static_cast<int>(aAttrs2[3].mnStart) );
1267 CPPUNIT_ASSERT_EQUAL( 34, static_cast<int>(aAttrs2[3].mnEnd) );
1268 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs2[3].maAttributes.size()) );
1269 CPPUNIT_ASSERT_MESSAGE( "This section must be underlined.", hasUnderline(aAttrs2[3]) );
1272 void Test::testMultiParaCopyPaste()
1274 // Create EditEngine's instance
1275 EditEngine aEditEngine( mpItemPool.get() );
1277 // Get EditDoc for current EditEngine's instance
1278 EditDoc &rDoc = aEditEngine.GetEditDoc();
1280 // Initially no text should be there
1281 CPPUNIT_ASSERT_EQUAL( sal_Int32(0), rDoc.GetTextLen() );
1282 CPPUNIT_ASSERT_EQUAL( OUString(), rDoc.GetParaAsString(sal_Int32(0)) );
1284 // Insert initial text
1285 OUString aFirstPara = "This is first paragraph";
1286 OUString aSecondPara = "This is second paragraph";
1287 OUString aThirdPara = "This is third paragraph";
1288 OUString aText = aFirstPara + "\n" + aSecondPara + "\n" + aThirdPara;
1289 sal_Int32 aTextLen = aFirstPara.getLength() + aSecondPara.getLength() + aThirdPara.getLength();
1290 aEditEngine.SetText( aText );
1291 sal_Int32 aCopyTextLen = aFirstPara.getLength() + aSecondPara.getLength();
1293 // Assert changes
1294 CPPUNIT_ASSERT_EQUAL( aTextLen, rDoc.GetTextLen() );
1295 CPPUNIT_ASSERT_EQUAL( aFirstPara, rDoc.GetParaAsString(sal_Int32(0)) );
1296 CPPUNIT_ASSERT_EQUAL( aSecondPara, rDoc.GetParaAsString(sal_Int32(1)) );
1297 CPPUNIT_ASSERT_EQUAL( aThirdPara, rDoc.GetParaAsString(sal_Int32(2)) );
1299 // Copy initial text using legacy format
1300 uno::Reference< datatransfer::XTransferable > xData = aEditEngine.CreateTransferable( ESelection(0,0,1,aSecondPara.getLength()) );
1302 // Paste text at the end
1303 aEditEngine.InsertText( xData, OUString(), rDoc.GetEndPaM(), true );
1305 // Assert changes
1306 OUString aThirdParaAfterCopyPaste = aThirdPara + aFirstPara;
1307 CPPUNIT_ASSERT_EQUAL( aTextLen + aCopyTextLen, rDoc.GetTextLen() );
1308 CPPUNIT_ASSERT_EQUAL( aFirstPara, rDoc.GetParaAsString(sal_Int32(0)) );
1309 CPPUNIT_ASSERT_EQUAL( aSecondPara, rDoc.GetParaAsString(sal_Int32(1)) );
1310 CPPUNIT_ASSERT_EQUAL( aThirdParaAfterCopyPaste, rDoc.GetParaAsString(sal_Int32(2)) );
1311 CPPUNIT_ASSERT_EQUAL( aSecondPara, rDoc.GetParaAsString(sal_Int32(3)) );
1314 void Test::testParaBoldItalicCopyPaste()
1316 // Create EditEngine's instance
1317 EditEngine aEditEngine( mpItemPool.get() );
1319 // Get EditDoc for current EditEngine's instance
1320 EditDoc &rDoc = aEditEngine.GetEditDoc();
1322 // Initially no text should be there
1323 CPPUNIT_ASSERT_EQUAL( sal_Int32(0), rDoc.GetTextLen() );
1324 CPPUNIT_ASSERT_EQUAL( OUString(), rDoc.GetParaAsString(sal_Int32(0)) );
1326 // Get corresponding ItemSet for inserting Bold/Italic text
1327 std::unique_ptr<SfxItemSet> pSet( new SfxItemSet(aEditEngine.GetEmptyItemSet()) );
1328 SvxWeightItem aBold( WEIGHT_BOLD, EE_CHAR_WEIGHT );
1329 SvxPostureItem aItalic( ITALIC_NORMAL, EE_CHAR_ITALIC );
1331 // Insert initial text
1332 OUString aFirstPara = "This is first paragraph";
1333 // Positions Ref .....*5.*8....*14*17...
1334 // Bold Ref .....[ BOLD ].....
1335 // Italic Ref ..............[ ITA
1336 // Copy Ref ........[ Copy Sel
1337 OUString aSecondPara = "This is second paragraph";
1338 // Positions Ref .....*5.*8...*13..*18...
1339 // Bold Ref .....[ BOLD ].....
1340 // Italic Ref LIC ]...............
1341 // Copy Ref ection ]..........
1342 OUString aThirdPara = "This is third paragraph";
1343 OUString aText = aFirstPara + "\n" + aSecondPara + "\n" + aThirdPara;
1344 sal_Int32 aTextLen = aFirstPara.getLength() + aSecondPara.getLength() + aThirdPara.getLength();
1345 aEditEngine.SetText( aText );
1346 OUString aCopyText = "first paragraphThis is second";
1347 sal_Int32 aCopyTextLen = aCopyText.getLength();
1349 // Assert changes - text insertion
1350 CPPUNIT_ASSERT_EQUAL( aTextLen, rDoc.GetTextLen() );
1351 CPPUNIT_ASSERT_EQUAL( aFirstPara, rDoc.GetParaAsString(sal_Int32(0)) );
1352 CPPUNIT_ASSERT_EQUAL( aSecondPara, rDoc.GetParaAsString(sal_Int32(1)) );
1353 CPPUNIT_ASSERT_EQUAL( aThirdPara, rDoc.GetParaAsString(sal_Int32(2)) );
1355 // Apply Bold to appropriate selections
1356 pSet->Put(aBold);
1357 CPPUNIT_ASSERT_EQUAL( static_cast<sal_uInt16>(1), pSet->Count() );
1358 aEditEngine.QuickSetAttribs( *pSet, ESelection(0,5,0,18) );
1359 aEditEngine.QuickSetAttribs( *pSet, ESelection(1,5,1,19) );
1361 // Assert changes
1362 std::unique_ptr<EditTextObject> pEditText1( aEditEngine.CreateTextObject() );
1363 std::vector<editeng::Section> aAttrs1;
1364 pEditText1->GetAllSections( aAttrs1 );
1365 // There should be 7 sections - woB - wB - woB -woB -wB -woB -woB (w - with, wo - without, B - Bold, I - Italic)
1366 CPPUNIT_ASSERT_EQUAL( size_t(7), aAttrs1.size() );
1368 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[0].mnParagraph) );
1369 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[0].mnStart) );
1370 CPPUNIT_ASSERT_EQUAL( 5, static_cast<int>(aAttrs1[0].mnEnd) );
1371 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[0].maAttributes.size()) );
1373 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[1].mnParagraph) );
1374 CPPUNIT_ASSERT_EQUAL( 5, static_cast<int>(aAttrs1[1].mnStart) );
1375 CPPUNIT_ASSERT_EQUAL( 18, static_cast<int>(aAttrs1[1].mnEnd) );
1376 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs1[1].maAttributes.size()) );
1377 CPPUNIT_ASSERT_MESSAGE( "This section must be bold.", hasBold(aAttrs1[1]) );
1379 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[2].mnParagraph) );
1380 CPPUNIT_ASSERT_EQUAL( 18, static_cast<int>(aAttrs1[2].mnStart) );
1381 CPPUNIT_ASSERT_EQUAL( 23, static_cast<int>(aAttrs1[2].mnEnd) );
1382 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[2].maAttributes.size()) );
1384 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs1[3].mnParagraph) );
1385 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[3].mnStart) );
1386 CPPUNIT_ASSERT_EQUAL( 5, static_cast<int>(aAttrs1[3].mnEnd) );
1387 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[3].maAttributes.size()) );
1389 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs1[4].mnParagraph) );
1390 CPPUNIT_ASSERT_EQUAL( 5, static_cast<int>(aAttrs1[4].mnStart) );
1391 CPPUNIT_ASSERT_EQUAL( 19, static_cast<int>(aAttrs1[4].mnEnd) );
1392 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs1[4].maAttributes.size()) );
1393 CPPUNIT_ASSERT_MESSAGE( "This section must be bold.", hasBold(aAttrs1[4]) );
1395 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs1[5].mnParagraph) );
1396 CPPUNIT_ASSERT_EQUAL( 19, static_cast<int>(aAttrs1[5].mnStart) );
1397 CPPUNIT_ASSERT_EQUAL( 24, static_cast<int>(aAttrs1[5].mnEnd) );
1398 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[5].maAttributes.size()) );
1400 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs1[6].mnParagraph) );
1401 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[6].mnStart) );
1402 CPPUNIT_ASSERT_EQUAL( 23, static_cast<int>(aAttrs1[6].mnEnd) );
1403 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs1[6].maAttributes.size()) );
1405 // Apply Italic to appropriate selection
1406 pSet.reset( new SfxItemSet(aEditEngine.GetEmptyItemSet()) );
1407 pSet->Put(aItalic);
1408 CPPUNIT_ASSERT_EQUAL( static_cast<sal_uInt16>(1), pSet->Count() );
1409 aEditEngine.QuickSetAttribs( *pSet, ESelection(0,14,1,9) );
1411 // Assert changes
1412 std::unique_ptr<EditTextObject> pEditText2( aEditEngine.CreateTextObject() );
1413 std::vector<editeng::Section> aAttrs2;
1414 pEditText2->GetAllSections( aAttrs2 );
1415 // There should be 9 sections - woB&woI - wB&woI - wB&wI -woB&wI - woB&wI - wB&wI - wB&woI - woB&woI - woB&woI (w - with, wo - without, B - Bold, I - Italic)
1416 CPPUNIT_ASSERT_EQUAL( size_t(9), aAttrs2.size() );
1418 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[0].mnParagraph) );
1419 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[0].mnStart) );
1420 CPPUNIT_ASSERT_EQUAL( 5, static_cast<int>(aAttrs2[0].mnEnd) );
1421 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[0].maAttributes.size()) );
1423 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[1].mnParagraph) );
1424 CPPUNIT_ASSERT_EQUAL( 5, static_cast<int>(aAttrs2[1].mnStart) );
1425 CPPUNIT_ASSERT_EQUAL( 14, static_cast<int>(aAttrs2[1].mnEnd) );
1426 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs2[1].maAttributes.size()) );
1427 CPPUNIT_ASSERT_MESSAGE( "This section must be bold.", hasBold(aAttrs2[1]) );
1429 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[2].mnParagraph) );
1430 CPPUNIT_ASSERT_EQUAL( 14, static_cast<int>(aAttrs2[2].mnStart) );
1431 CPPUNIT_ASSERT_EQUAL( 18, static_cast<int>(aAttrs2[2].mnEnd) );
1432 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs2[2].maAttributes.size()) );
1433 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasBold(aAttrs2[2]) );
1434 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasItalic(aAttrs2[2]) );
1436 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[3].mnParagraph) );
1437 CPPUNIT_ASSERT_EQUAL( 18, static_cast<int>(aAttrs2[3].mnStart) );
1438 CPPUNIT_ASSERT_EQUAL( 23, static_cast<int>(aAttrs2[3].mnEnd) );
1439 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs2[3].maAttributes.size()) );
1440 CPPUNIT_ASSERT_MESSAGE( "This section must be italic.", hasItalic(aAttrs2[3]) );
1442 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs2[4].mnParagraph) );
1443 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[4].mnStart) );
1444 CPPUNIT_ASSERT_EQUAL( 5, static_cast<int>(aAttrs2[4].mnEnd) );
1445 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs2[4].maAttributes.size()) );
1446 CPPUNIT_ASSERT_MESSAGE( "This section must be italic.", hasItalic(aAttrs2[4]) );
1448 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs2[5].mnParagraph) );
1449 CPPUNIT_ASSERT_EQUAL( 5, static_cast<int>(aAttrs2[5].mnStart) );
1450 CPPUNIT_ASSERT_EQUAL( 9, static_cast<int>(aAttrs2[5].mnEnd) );
1451 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs2[5].maAttributes.size()) );
1452 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasBold(aAttrs2[5]) );
1453 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasItalic(aAttrs2[5]) );
1455 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs2[6].mnParagraph) );
1456 CPPUNIT_ASSERT_EQUAL( 9, static_cast<int>(aAttrs2[6].mnStart) );
1457 CPPUNIT_ASSERT_EQUAL( 19, static_cast<int>(aAttrs2[6].mnEnd) );
1458 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs2[6].maAttributes.size()) );
1459 CPPUNIT_ASSERT_MESSAGE( "This section must be bold.", hasBold(aAttrs2[6]) );
1461 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs2[7].mnParagraph) );
1462 CPPUNIT_ASSERT_EQUAL( 19, static_cast<int>(aAttrs2[7].mnStart) );
1463 CPPUNIT_ASSERT_EQUAL( 24, static_cast<int>(aAttrs2[7].mnEnd) );
1464 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[7].maAttributes.size()) );
1466 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs2[8].mnParagraph) );
1467 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[8].mnStart) );
1468 CPPUNIT_ASSERT_EQUAL( 23, static_cast<int>(aAttrs2[8].mnEnd) );
1469 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs2[8].maAttributes.size()) );
1471 // Copy text using legacy format
1472 uno::Reference< datatransfer::XTransferable > xData = aEditEngine.CreateTransferable( ESelection(0,8,1,14) );
1474 // Paste text at the end
1475 aEditEngine.InsertText( xData, OUString(), rDoc.GetEndPaM(), true );
1477 // Assert changes
1478 OUString aThirdParaAfterCopyPaste = aThirdPara + "first paragraph";
1479 CPPUNIT_ASSERT_EQUAL( aTextLen + aCopyTextLen, rDoc.GetTextLen() );
1480 CPPUNIT_ASSERT_EQUAL( aFirstPara, rDoc.GetParaAsString(sal_Int32(0)) );
1481 CPPUNIT_ASSERT_EQUAL( aSecondPara, rDoc.GetParaAsString(sal_Int32(1)) );
1482 CPPUNIT_ASSERT_EQUAL( aThirdParaAfterCopyPaste, rDoc.GetParaAsString(sal_Int32(2)) );
1483 CPPUNIT_ASSERT_EQUAL( OUString("This is second"), rDoc.GetParaAsString(sal_Int32(3)) );
1485 // Check updated text for appropriate Bold/Italics
1486 std::unique_ptr<EditTextObject> pEditText3( aEditEngine.CreateTextObject() );
1487 std::vector<editeng::Section> aAttrs3;
1488 pEditText3->GetAllSections( aAttrs3 );
1489 // There should be 15 sections - woB&woI - wB&woI - wB&wI -woB&wI - woB&wI - wB&wI - wB&woI - woB&woI - woB&woI
1490 // - wB&woI - wB&wI - woB&wI - -woB&wI - wB&wI - wB&woI (w - with, wo - without, B - Bold, I - Italic)
1491 CPPUNIT_ASSERT_EQUAL( size_t(15), aAttrs3.size() );
1493 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[0].mnParagraph) );
1494 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[0].mnStart) );
1495 CPPUNIT_ASSERT_EQUAL( 5, static_cast<int>(aAttrs3[0].mnEnd) );
1496 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[0].maAttributes.size()) );
1498 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[1].mnParagraph) );
1499 CPPUNIT_ASSERT_EQUAL( 5, static_cast<int>(aAttrs3[1].mnStart) );
1500 CPPUNIT_ASSERT_EQUAL( 14, static_cast<int>(aAttrs3[1].mnEnd) );
1501 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs3[1].maAttributes.size()) );
1502 CPPUNIT_ASSERT_MESSAGE( "This section must be bold.", hasBold(aAttrs3[1]) );
1504 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[2].mnParagraph) );
1505 CPPUNIT_ASSERT_EQUAL( 14, static_cast<int>(aAttrs3[2].mnStart) );
1506 CPPUNIT_ASSERT_EQUAL( 18, static_cast<int>(aAttrs3[2].mnEnd) );
1507 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs3[2].maAttributes.size()) );
1508 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasBold(aAttrs3[2]) );
1509 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasItalic(aAttrs3[2]) );
1511 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[3].mnParagraph) );
1512 CPPUNIT_ASSERT_EQUAL( 18, static_cast<int>(aAttrs3[3].mnStart) );
1513 CPPUNIT_ASSERT_EQUAL( 23, static_cast<int>(aAttrs3[3].mnEnd) );
1514 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs3[3].maAttributes.size()) );
1515 CPPUNIT_ASSERT_MESSAGE( "This section must be italic.", hasItalic(aAttrs3[3]) );
1517 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs3[4].mnParagraph) );
1518 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[4].mnStart) );
1519 CPPUNIT_ASSERT_EQUAL( 5, static_cast<int>(aAttrs3[4].mnEnd) );
1520 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs3[4].maAttributes.size()) );
1521 CPPUNIT_ASSERT_MESSAGE( "This section must be italic.", hasItalic(aAttrs3[4]) );
1523 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs3[5].mnParagraph) );
1524 CPPUNIT_ASSERT_EQUAL( 5, static_cast<int>(aAttrs3[5].mnStart) );
1525 CPPUNIT_ASSERT_EQUAL( 9, static_cast<int>(aAttrs3[5].mnEnd) );
1526 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs3[5].maAttributes.size()) );
1527 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasBold(aAttrs3[5]) );
1528 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasItalic(aAttrs3[5]) );
1530 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs3[6].mnParagraph) );
1531 CPPUNIT_ASSERT_EQUAL( 9, static_cast<int>(aAttrs3[6].mnStart) );
1532 CPPUNIT_ASSERT_EQUAL( 19, static_cast<int>(aAttrs3[6].mnEnd) );
1533 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs3[6].maAttributes.size()) );
1534 CPPUNIT_ASSERT_MESSAGE( "This section must be bold.", hasBold(aAttrs3[6]) );
1536 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs3[7].mnParagraph) );
1537 CPPUNIT_ASSERT_EQUAL( 19, static_cast<int>(aAttrs3[7].mnStart) );
1538 CPPUNIT_ASSERT_EQUAL( 24, static_cast<int>(aAttrs3[7].mnEnd) );
1539 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[7].maAttributes.size()) );
1541 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs3[8].mnParagraph) );
1542 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[8].mnStart) );
1543 CPPUNIT_ASSERT_EQUAL( 23, static_cast<int>(aAttrs3[8].mnEnd) );
1544 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[8].maAttributes.size()) );
1546 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs3[9].mnParagraph) );
1547 CPPUNIT_ASSERT_EQUAL( 23, static_cast<int>(aAttrs3[9].mnStart) );
1548 CPPUNIT_ASSERT_EQUAL( 29, static_cast<int>(aAttrs3[9].mnEnd) );
1549 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs3[9].maAttributes.size()) );
1550 CPPUNIT_ASSERT_MESSAGE( "This section must be bold.", hasBold(aAttrs3[9]) );
1552 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs3[10].mnParagraph) );
1553 CPPUNIT_ASSERT_EQUAL( 29, static_cast<int>(aAttrs3[10].mnStart) );
1554 CPPUNIT_ASSERT_EQUAL( 33, static_cast<int>(aAttrs3[10].mnEnd) );
1555 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs3[10].maAttributes.size()) );
1556 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasBold(aAttrs3[10]) );
1557 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasItalic(aAttrs3[10]) );
1559 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs3[11].mnParagraph) );
1560 CPPUNIT_ASSERT_EQUAL( 33, static_cast<int>(aAttrs3[11].mnStart) );
1561 CPPUNIT_ASSERT_EQUAL( 38, static_cast<int>(aAttrs3[11].mnEnd) );
1562 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs3[11].maAttributes.size()) );
1563 CPPUNIT_ASSERT_MESSAGE( "This section must be italic.", hasItalic(aAttrs3[11]) );
1565 CPPUNIT_ASSERT_EQUAL( 3, static_cast<int>(aAttrs3[12].mnParagraph) );
1566 CPPUNIT_ASSERT_EQUAL( 0, static_cast<int>(aAttrs3[12].mnStart) );
1567 CPPUNIT_ASSERT_EQUAL( 5, static_cast<int>(aAttrs3[12].mnEnd) );
1568 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs3[12].maAttributes.size()) );
1569 CPPUNIT_ASSERT_MESSAGE( "This section must be italic.", hasItalic(aAttrs3[12]) );
1571 CPPUNIT_ASSERT_EQUAL( 3, static_cast<int>(aAttrs3[13].mnParagraph) );
1572 CPPUNIT_ASSERT_EQUAL( 5, static_cast<int>(aAttrs3[13].mnStart) );
1573 CPPUNIT_ASSERT_EQUAL( 9, static_cast<int>(aAttrs3[13].mnEnd) );
1574 CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(aAttrs3[13].maAttributes.size()) );
1575 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasBold(aAttrs3[13]) );
1576 CPPUNIT_ASSERT_MESSAGE( "This section must be bold and italic.", hasItalic(aAttrs3[13]) );
1578 CPPUNIT_ASSERT_EQUAL( 3, static_cast<int>(aAttrs3[14].mnParagraph) );
1579 CPPUNIT_ASSERT_EQUAL( 9, static_cast<int>(aAttrs3[14].mnStart) );
1580 CPPUNIT_ASSERT_EQUAL( 14, static_cast<int>(aAttrs3[14].mnEnd) );
1581 CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(aAttrs3[14].maAttributes.size()) );
1582 CPPUNIT_ASSERT_MESSAGE( "This section must be bold.", hasBold(aAttrs3[14]) );
1585 void Test::testParaStartCopyPaste()
1587 // Create EditEngine's instance
1588 EditEngine aEditEngine( mpItemPool.get() );
1590 // Get EditDoc for current EditEngine's instance
1591 EditDoc &rDoc = aEditEngine.GetEditDoc();
1593 // Initially no text should be there
1594 CPPUNIT_ASSERT_EQUAL( sal_Int32(0), rDoc.GetTextLen() );
1595 CPPUNIT_ASSERT_EQUAL( OUString(), rDoc.GetParaAsString(sal_Int32(0)) );
1597 // Insert initial text
1598 OUString aFirstPara = "This is first paragraph";
1599 // Selection Ref ........8..............
1600 OUString aSecondPara = "This is second paragraph";
1601 // Selection Ref .............14.........
1602 OUString aThirdPara = "This is third paragraph";
1603 OUString aText = aFirstPara + "\n" + aSecondPara + "\n" + aThirdPara;
1604 sal_Int32 aTextLen = aFirstPara.getLength() + aSecondPara.getLength() + aThirdPara.getLength();
1605 aEditEngine.SetText( aText );
1606 OUString aCopyText = "first paragraphThis is second";
1607 sal_Int32 aCopyTextLen = aCopyText.getLength();
1609 // Assert changes
1610 CPPUNIT_ASSERT_EQUAL( aTextLen, rDoc.GetTextLen() );
1611 CPPUNIT_ASSERT_EQUAL( aFirstPara, rDoc.GetParaAsString(sal_Int32(0)) );
1612 CPPUNIT_ASSERT_EQUAL( aSecondPara, rDoc.GetParaAsString(sal_Int32(1)) );
1613 CPPUNIT_ASSERT_EQUAL( aThirdPara, rDoc.GetParaAsString(sal_Int32(2)) );
1615 // Copy initial text using legacy format
1616 uno::Reference< datatransfer::XTransferable > xData = aEditEngine.CreateTransferable( ESelection(0,8,1,14) );
1618 // Paste text at the start
1619 aEditEngine.InsertText( xData, OUString(), rDoc.GetStartPaM(), true );
1621 // Assert changes
1622 OUString aSecondParaAfterCopyPaste = "This is second" + aFirstPara;
1623 CPPUNIT_ASSERT_EQUAL( aTextLen + aCopyTextLen, rDoc.GetTextLen() );
1624 CPPUNIT_ASSERT_EQUAL( OUString("first paragraph"), rDoc.GetParaAsString(sal_Int32(0)) );
1625 CPPUNIT_ASSERT_EQUAL( aSecondParaAfterCopyPaste, rDoc.GetParaAsString(sal_Int32(1)) );
1626 CPPUNIT_ASSERT_EQUAL( aSecondPara, rDoc.GetParaAsString(sal_Int32(2)) );
1627 CPPUNIT_ASSERT_EQUAL( aThirdPara, rDoc.GetParaAsString(sal_Int32(3)) );
1630 void Test::testSectionAttributes()
1632 EditEngine aEngine(mpItemPool.get());
1634 std::unique_ptr<SfxItemSet> pSet(new SfxItemSet(aEngine.GetEmptyItemSet()));
1635 SvxWeightItem aBold(WEIGHT_BOLD, EE_CHAR_WEIGHT);
1636 SvxPostureItem aItalic(ITALIC_NORMAL, EE_CHAR_ITALIC);
1639 aEngine.SetText("aaabbbccc");
1640 pSet->Put(aBold);
1641 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be exactly one item.", static_cast<sal_uInt16>(1), pSet->Count());
1642 aEngine.QuickSetAttribs(*pSet, ESelection(0,0,0,6)); // 'aaabbb' - end point is not inclusive.
1643 pSet.reset(new SfxItemSet(aEngine.GetEmptyItemSet()));
1644 pSet->Put(aItalic);
1645 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be exactly one item.", static_cast<sal_uInt16>(1), pSet->Count());
1647 aEngine.QuickSetAttribs(*pSet, ESelection(0,3,0,9)); // 'bbbccc'
1648 std::unique_ptr<EditTextObject> pEditText(aEngine.CreateTextObject());
1649 CPPUNIT_ASSERT_MESSAGE("Failed to create text object.", pEditText);
1650 std::vector<editeng::Section> aAttrs;
1651 pEditText->GetAllSections(aAttrs);
1653 // Now, we should have a total of 3 sections.
1654 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be 3 sections.", static_cast<size_t>(3), aAttrs.size());
1656 // First section should be 0-3 of paragraph 0, and it should only have boldness applied.
1657 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs[0].mnParagraph));
1658 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs[0].mnStart));
1659 CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(aAttrs[0].mnEnd));
1660 CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs[0].maAttributes.size()));
1661 CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(aAttrs[0]));
1663 // Second section should be 3-6, and it should be both bold and italic.
1664 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs[1].mnParagraph));
1665 CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(aAttrs[1].mnStart));
1666 CPPUNIT_ASSERT_EQUAL(6, static_cast<int>(aAttrs[1].mnEnd));
1667 CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs[1].maAttributes.size()));
1668 CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasBold(aAttrs[1]));
1669 CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasItalic(aAttrs[1]));
1671 // Third section should be 6-9, and it should be only italic.
1672 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs[2].mnParagraph));
1673 CPPUNIT_ASSERT_EQUAL(6, static_cast<int>(aAttrs[2].mnStart));
1674 CPPUNIT_ASSERT_EQUAL(9, static_cast<int>(aAttrs[2].mnEnd));
1675 CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs[2].maAttributes.size()));
1676 CPPUNIT_ASSERT_MESSAGE("This section must be italic.", hasItalic(aAttrs[2]));
1680 // Set text consisting of 5 paragraphs with the 2nd and 4th paragraphs
1681 // being empty.
1682 aEngine.Clear();
1683 aEngine.SetText("one\n\ntwo\n\nthree");
1684 sal_Int32 nParaCount = aEngine.GetParagraphCount();
1685 CPPUNIT_ASSERT_EQUAL(sal_Int32(5), nParaCount);
1687 // Apply boldness to paragraphs 1, 3, 5 only. Leave 2 and 4 unformatted.
1688 pSet.reset(new SfxItemSet(aEngine.GetEmptyItemSet()));
1689 pSet->Put(aBold);
1690 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be exactly one item.", static_cast<sal_uInt16>(1), pSet->Count());
1691 aEngine.QuickSetAttribs(*pSet, ESelection(0,0,0,3));
1692 aEngine.QuickSetAttribs(*pSet, ESelection(2,0,2,3));
1693 aEngine.QuickSetAttribs(*pSet, ESelection(4,0,4,5));
1695 std::unique_ptr<EditTextObject> pEditText(aEngine.CreateTextObject());
1696 CPPUNIT_ASSERT_MESSAGE("Failed to create text object.", pEditText);
1697 std::vector<editeng::Section> aAttrs;
1698 pEditText->GetAllSections(aAttrs);
1699 CPPUNIT_ASSERT_EQUAL(size_t(5), aAttrs.size());
1701 // 1st, 3rd and 5th sections should correspond with 1st, 3rd and 5th paragraphs.
1702 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs[0].mnParagraph));
1703 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs[0].mnStart));
1704 CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(aAttrs[0].mnEnd));
1705 CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs[0].maAttributes.size()));
1706 CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(aAttrs[0]));
1708 CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs[2].mnParagraph));
1709 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs[2].mnStart));
1710 CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(aAttrs[2].mnEnd));
1711 CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs[2].maAttributes.size()));
1712 CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(aAttrs[2]));
1714 CPPUNIT_ASSERT_EQUAL(4, static_cast<int>(aAttrs[4].mnParagraph));
1715 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs[4].mnStart));
1716 CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(aAttrs[4].mnEnd));
1717 CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs[4].maAttributes.size()));
1718 CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(aAttrs[4]));
1720 // The 2nd and 4th paragraphs should be empty.
1721 CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs[1].mnParagraph));
1722 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs[1].mnStart));
1723 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs[1].mnEnd));
1724 CPPUNIT_ASSERT_MESSAGE("Attribute array should be empty.", aAttrs[1].maAttributes.empty());
1726 CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(aAttrs[3].mnParagraph));
1727 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs[3].mnStart));
1728 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs[3].mnEnd));
1729 CPPUNIT_ASSERT_MESSAGE("Attribute array should be empty.", aAttrs[3].maAttributes.empty());
1734 aEngine.Clear();
1735 aEngine.SetText("one\ntwo");
1736 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), aEngine.GetParagraphCount());
1738 // embolden 2nd paragraph
1739 pSet.reset(new SfxItemSet(aEngine.GetEmptyItemSet()));
1740 pSet->Put(aBold);
1741 aEngine.QuickSetAttribs(*pSet, ESelection(1,0,1,3));
1742 // disboldify 1st paragraph
1743 SvxWeightItem aNotSoBold(WEIGHT_NORMAL, EE_CHAR_WEIGHT);
1744 pSet->Put(aNotSoBold);
1745 aEngine.QuickSetAttribs(*pSet, ESelection(0,0,0,3));
1747 // now delete & join the paragraphs - this is fdo#85496 scenario
1748 aEngine.QuickDelete(ESelection(0,0,1,3));
1749 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), aEngine.GetParagraphCount());
1751 std::unique_ptr<EditTextObject> pEditText(aEngine.CreateTextObject());
1752 CPPUNIT_ASSERT_MESSAGE("Failed to create text object.", pEditText);
1753 std::vector<editeng::Section> aAttrs;
1754 pEditText->GetAllSections(aAttrs);
1756 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aAttrs.size());
1758 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs[0].mnParagraph));
1759 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs[0].mnStart));
1760 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs[0].mnEnd));
1761 std::set<sal_uInt16> whiches;
1762 for (size_t i = 0; i < aAttrs[0].maAttributes.size(); ++i)
1764 sal_uInt16 const nWhich(aAttrs[0].maAttributes[i]->Which());
1765 CPPUNIT_ASSERT_MESSAGE("duplicate item in text portion attributes",
1766 whiches.insert(nWhich).second);
1771 void Test::testLargeParaCopyPaste()
1773 // Create EditEngine's instance
1774 EditEngine aEditEngine( mpItemPool.get() );
1776 // Get EditDoc for current EditEngine's instance
1777 EditDoc &rDoc = aEditEngine.GetEditDoc();
1779 // Initially no text should be there
1780 CPPUNIT_ASSERT_EQUAL( sal_Int32(0), rDoc.GetTextLen() );
1781 CPPUNIT_ASSERT_EQUAL( OUString(), rDoc.GetParaAsString(sal_Int32(0)) );
1783 // Insert initial text
1784 OUString aFirstPara = "This is first paragraph";
1785 OUString aSecondPara = "This is second paragraph";
1786 OUString aThirdPara = "This is third paragraph";
1787 OUString aFourthPara = "This is fourth paragraph";
1788 OUString aFifthPara = "This is fifth paragraph";
1789 OUString aSixthPara = "This is sixth paragraph";
1790 //Positions Ref: ........*8.............
1791 OUString aSeventhPara = "This is seventh paragraph";
1792 OUString aEighthPara = "This is eighth paragraph";
1793 //Positions Ref: .............*13
1794 OUString aNinthPara = "This is ninth paragraph";
1795 OUString aTenthPara = "This is tenth paragraph";
1796 OUString aText = aFirstPara + "\n" + aSecondPara + "\n" + aThirdPara + "\n" +
1797 aFourthPara + "\n" + aFifthPara + "\n" + aSixthPara + "\n" + aSeventhPara + "\n" +
1798 aEighthPara + "\n" + aNinthPara + "\n" + aTenthPara;
1799 sal_Int32 aTextLen = aFirstPara.getLength() + aSecondPara.getLength() + aThirdPara.getLength() +
1800 aFourthPara.getLength() + aFifthPara.getLength() + aSixthPara.getLength() +
1801 aSeventhPara.getLength() + aEighthPara.getLength() + aNinthPara.getLength() + aTenthPara.getLength();
1802 aEditEngine.SetText( aText );
1803 OUString aCopyText = "sixth paragraphThis is seventh paragraphThis is eighth";
1804 sal_Int32 aCopyTextLen = aCopyText.getLength();
1806 // Assert changes
1807 CPPUNIT_ASSERT_EQUAL( aTextLen, rDoc.GetTextLen() );
1808 CPPUNIT_ASSERT_EQUAL( aFirstPara, rDoc.GetParaAsString(sal_Int32(0)) );
1809 CPPUNIT_ASSERT_EQUAL( aSecondPara, rDoc.GetParaAsString(sal_Int32(1)) );
1810 CPPUNIT_ASSERT_EQUAL( aThirdPara, rDoc.GetParaAsString(sal_Int32(2)) );
1811 CPPUNIT_ASSERT_EQUAL( aFourthPara, rDoc.GetParaAsString(sal_Int32(3)) );
1812 CPPUNIT_ASSERT_EQUAL( aFifthPara, rDoc.GetParaAsString(sal_Int32(4)) );
1813 CPPUNIT_ASSERT_EQUAL( aSixthPara, rDoc.GetParaAsString(sal_Int32(5)) );
1814 CPPUNIT_ASSERT_EQUAL( aSeventhPara, rDoc.GetParaAsString(sal_Int32(6)) );
1815 CPPUNIT_ASSERT_EQUAL( aEighthPara, rDoc.GetParaAsString(sal_Int32(7)) );
1816 CPPUNIT_ASSERT_EQUAL( aNinthPara, rDoc.GetParaAsString(sal_Int32(8)) );
1817 CPPUNIT_ASSERT_EQUAL( aTenthPara, rDoc.GetParaAsString(sal_Int32(9)) );
1819 // Copy initial text using legacy format
1820 uno::Reference< datatransfer::XTransferable > xData = aEditEngine.CreateTransferable( ESelection(5,8,7,14) );
1822 // Paste text at the end of 4th Para
1823 ContentNode* pLastNode = rDoc.GetObject(3);
1824 aEditEngine.InsertText( xData, OUString(), EditPaM( pLastNode, pLastNode->Len() ), true );
1826 // Assert changes
1827 OUString aFourthParaAfterCopyPaste = aFourthPara + "sixth paragraph";
1828 CPPUNIT_ASSERT_EQUAL( aTextLen + aCopyTextLen, rDoc.GetTextLen() );
1829 CPPUNIT_ASSERT_EQUAL( aFirstPara, rDoc.GetParaAsString(sal_Int32(0)) );
1830 CPPUNIT_ASSERT_EQUAL( aSecondPara, rDoc.GetParaAsString(sal_Int32(1)) );
1831 CPPUNIT_ASSERT_EQUAL( aThirdPara, rDoc.GetParaAsString(sal_Int32(2)) );
1832 CPPUNIT_ASSERT_EQUAL( aFourthParaAfterCopyPaste, rDoc.GetParaAsString(sal_Int32(3)) );
1833 CPPUNIT_ASSERT_EQUAL( aSeventhPara, rDoc.GetParaAsString(sal_Int32(4)) );
1834 CPPUNIT_ASSERT_EQUAL( OUString("This is eighth"), rDoc.GetParaAsString(sal_Int32(5)) );
1835 CPPUNIT_ASSERT_EQUAL( aFifthPara, rDoc.GetParaAsString(sal_Int32(6)) );
1836 CPPUNIT_ASSERT_EQUAL( aSixthPara, rDoc.GetParaAsString(sal_Int32(7)) );
1837 CPPUNIT_ASSERT_EQUAL( aSeventhPara, rDoc.GetParaAsString(sal_Int32(8)) );
1838 CPPUNIT_ASSERT_EQUAL( aEighthPara, rDoc.GetParaAsString(sal_Int32(9)) );
1839 CPPUNIT_ASSERT_EQUAL( aNinthPara, rDoc.GetParaAsString(sal_Int32(10)) );
1840 CPPUNIT_ASSERT_EQUAL( aTenthPara, rDoc.GetParaAsString(sal_Int32(11)) );
1843 OUString lcl_translitTest(EditEngine& aEditEngine, const OUString& text, const ESelection& esel, const TransliterationFlags nType)
1845 aEditEngine.SetText(text);
1846 aEditEngine.TransliterateText(esel, nType);
1847 return aEditEngine.GetText();
1851 void Test::testTransliterate()
1853 // Create EditEngine's instance
1854 EditEngine editEng( mpItemPool.get() );
1856 OUString sText("one (two) three");
1857 editEng.SetText(sText);
1858 editEng.TransliterateText(ESelection(0, 0, 0, sText.getLength()), TransliterationFlags::TITLE_CASE);
1859 CPPUNIT_ASSERT_EQUAL(OUString("One (Two) Three"), editEng.GetText());
1861 using TF = TransliterationFlags;
1862 constexpr OUString sText2 = u"Mary Jones met joe Smith. Time Passed."_ustr;
1863 int selStart = 12;
1864 int selEnd = 12;
1865 ESelection esel(0, selStart, 0, selEnd);
1866 ESelection eSentenSel(0, 0, 0, 25);
1868 /* DocumentContentOperationsManager checks if the cursor is inside of a word before transliterating,
1869 * but Edit Engine has no such check. Therefore, behavior is different between these two when the
1870 * cursor is on a word boundary. */
1872 /* No selection tests. Cursor between the ' ' and 'm' before 'met' - except in SENTENCE_CASE where the complete sentence is selected.*/
1873 CPPUNIT_ASSERT_EQUAL(OUString(""), editEng.GetText(esel));
1874 CPPUNIT_ASSERT_EQUAL(OUString("Mary jones met joe smith. Time Passed."), lcl_translitTest(editEng, sText2, eSentenSel, TF::SENTENCE_CASE));
1875 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones Met joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::TITLE_CASE));
1876 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones MET joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::LOWERCASE_UPPERCASE));
1877 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones met joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::UPPERCASE_LOWERCASE));
1879 /* No selection tests. Cursor between the 't' and the ' ' after 'met'. */
1880 selStart = 14;
1881 selEnd = 14;
1882 esel = ESelection(0, selStart, 0, selEnd);
1883 CPPUNIT_ASSERT_EQUAL(OUString(""), editEng.GetText(esel));
1884 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones Met joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::TITLE_CASE));
1885 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones MET joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::LOWERCASE_UPPERCASE));
1886 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones met joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::UPPERCASE_LOWERCASE));
1888 /* No selection tests. Cursor between the 'h' and the '.' after 'Smith'. */
1889 selStart = 24;
1890 selEnd = 24;
1891 esel = ESelection(0, selStart, 0, selEnd);
1892 CPPUNIT_ASSERT_EQUAL(OUString(""), editEng.GetText(esel));
1893 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones met joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::TITLE_CASE));
1894 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones met joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::LOWERCASE_UPPERCASE));
1895 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones met joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::UPPERCASE_LOWERCASE));
1897 /* No selection tests. Cursor between the 'm' and 'e' in 'met'. */
1898 selStart = 12;
1899 selEnd = 12;
1900 esel = ESelection(0, selStart, 0, selEnd);
1901 CPPUNIT_ASSERT_EQUAL(OUString(""), editEng.GetText(esel));
1902 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones Met joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::TITLE_CASE));
1903 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones MET joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::LOWERCASE_UPPERCASE));
1904 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones met joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::UPPERCASE_LOWERCASE));
1906 /* Test behavior when there is a selection that does not cross a word boundary: "met" */
1907 selStart = 11;
1908 selEnd = 14;
1909 esel = ESelection(0, selStart, 0, selEnd);
1910 CPPUNIT_ASSERT_EQUAL(OUString("met"), editEng.GetText(esel));
1911 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones Met joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::TITLE_CASE));
1912 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones MET joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::LOWERCASE_UPPERCASE));
1913 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones met joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::UPPERCASE_LOWERCASE));
1915 /* Test behavior when there is a selection that does not begin at a word boundary: "et" */
1916 selStart = 12;
1917 selEnd = 14;
1918 esel = ESelection(0, selStart, 0, selEnd);
1919 CPPUNIT_ASSERT_EQUAL(OUString("et"), editEng.GetText(esel));
1920 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones mEt joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::TITLE_CASE));
1921 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones mET joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::LOWERCASE_UPPERCASE));
1922 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones met joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::UPPERCASE_LOWERCASE));
1924 /* Test behavior when there is a selection that ends in the middle of a word */
1925 selStart = 11;
1926 selEnd = 13;
1927 esel = ESelection(0, selStart, 0, selEnd);
1928 CPPUNIT_ASSERT_EQUAL(OUString("me"), editEng.GetText(esel));
1929 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones Met joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::TITLE_CASE));
1930 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones MEt joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::LOWERCASE_UPPERCASE));
1931 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones met joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::UPPERCASE_LOWERCASE));
1934 /* Test behavior when there is a selection that crosses a word boundary: "nes met joe Sm" */
1935 selStart = 7;
1936 selEnd = 21;
1937 esel = ESelection(0, selStart, 0, selEnd);
1938 CPPUNIT_ASSERT_EQUAL(OUString("nes met joe Sm"), editEng.GetText(esel));
1939 CPPUNIT_ASSERT_EQUAL(OUString("Mary JoNes met joe smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::SENTENCE_CASE));
1940 CPPUNIT_ASSERT_EQUAL(OUString("Mary JoNes Met Joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::TITLE_CASE));
1941 CPPUNIT_ASSERT_EQUAL(OUString("Mary JoNES MET JOE SMith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::LOWERCASE_UPPERCASE));
1942 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones met joe smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::UPPERCASE_LOWERCASE));
1944 /* Test behavior when there is a selection that crosses a sentence boundary: "joe Smith. Time Passed." */
1945 selStart = 15;
1946 selEnd = 38;
1947 esel = ESelection(0, selStart, 0, selEnd);
1948 editEng.SetText(sText2);
1949 CPPUNIT_ASSERT_EQUAL(OUString("joe Smith. Time Passed."), editEng.GetText(esel));
1951 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones met Joe smith. Time passed."), lcl_translitTest(editEng, sText2, esel, TF::SENTENCE_CASE));
1952 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones met Joe Smith. Time Passed."), lcl_translitTest(editEng, sText2, esel, TF::TITLE_CASE));
1953 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones met JOE SMITH. TIME PASSED."), lcl_translitTest(editEng, sText2, esel, TF::LOWERCASE_UPPERCASE));
1954 CPPUNIT_ASSERT_EQUAL(OUString("Mary Jones met joe smith. time passed."), lcl_translitTest(editEng, sText2, esel, TF::UPPERCASE_LOWERCASE));
1956 /* Test behavior when sentence ends with a capital that is not selected: "CURRENT IS EQUAL TO 10 A" */
1957 selStart = 0;
1958 selEnd = 19;
1959 esel = ESelection(0, selStart, 0, selEnd);
1960 constexpr OUString sText3(u"CURRENT IS EQUAL TO 10 A"_ustr);
1961 editEng.SetText(sText3);
1962 CPPUNIT_ASSERT_EQUAL(OUString("CURRENT IS EQUAL TO"), editEng.GetText(esel));
1964 CPPUNIT_ASSERT_EQUAL(OUString("Current is equal to 10 A"), lcl_translitTest(editEng, sText3, esel, TF::SENTENCE_CASE));
1965 CPPUNIT_ASSERT_EQUAL(OUString("Current Is Equal To 10 A"), lcl_translitTest(editEng, sText3, esel, TF::TITLE_CASE));
1966 CPPUNIT_ASSERT_EQUAL(OUString("CURRENT IS EQUAL TO 10 A"), lcl_translitTest(editEng, sText3, esel, TF::LOWERCASE_UPPERCASE));
1967 CPPUNIT_ASSERT_EQUAL(OUString("current is equal to 10 A"), lcl_translitTest(editEng, sText3, esel, TF::UPPERCASE_LOWERCASE));
1971 void Test::testTdf147196()
1973 EditEngine editEng( mpItemPool.get() );
1974 editEng.SetText("2.2 Publication of information - CAA\nSection 4.2 of a CA\'s Certificate Policy and/or Certification Practice Statement SHALL state the CA\'s policy or practice on processing CAA Records for Fully Qualified Domain Names; that policy shall be consistent with these Requirements. \n\nIt shall clearly specify the set of Issuer Domain Names that the CA recognises in CAA \"issue\" or \"issuewild\" records as permitting it to issue. The CA SHALL log all actions taken, if any, consistent with its processing practice.");
1975 editEng.TransliterateText(ESelection(0, 0, 3, 232), TransliterationFlags::TITLE_CASE);
1976 CPPUNIT_ASSERT_EQUAL(OUString("2.2 Publication Of Information - Caa\nSection 4.2 Of A Ca\'s Certificate Policy And/Or Certification Practice Statement Shall State The Ca\'s Policy Or Practice On Processing Caa Records For Fully Qualified Domain Names; That Policy Shall Be Consistent With These Requirements. \n\nIt Shall Clearly Specify The Set Of Issuer Domain Names That The Ca Recognises In Caa \"Issue\" Or \"Issuewild\" Records As Permitting It To Issue. The Ca Shall Log All Actions Taken, If Any, Consistent With Its Processing Practice."), editEng.GetText());
1979 void Test::testTdf148148()
1981 using TF = TransliterationFlags;
1982 EditEngine editEng( mpItemPool.get() );
1984 /* Test what happens when node contains text but selection does not contain any text */
1985 int selStart = 0;
1986 int selEnd = 3;
1987 ESelection esel(0, selStart, 0, selEnd);
1988 constexpr OUString sText1(u" text"_ustr);
1989 editEng.SetText(sText1);
1990 CPPUNIT_ASSERT_EQUAL(OUString(" "), editEng.GetText(esel));
1992 CPPUNIT_ASSERT_EQUAL(OUString(" text"), lcl_translitTest(editEng, sText1, esel, TF::SENTENCE_CASE));
1993 CPPUNIT_ASSERT_EQUAL(OUString(" text"), lcl_translitTest(editEng, sText1, esel, TF::TITLE_CASE));
1994 CPPUNIT_ASSERT_EQUAL(OUString(" text"), lcl_translitTest(editEng, sText1, esel, TF::LOWERCASE_UPPERCASE));
1995 CPPUNIT_ASSERT_EQUAL(OUString(" text"), lcl_translitTest(editEng, sText1, esel, TF::UPPERCASE_LOWERCASE));
1997 selStart = 4;
1998 selEnd = 8;
1999 esel = ESelection(0, selStart, 0, selEnd);
2000 constexpr OUString sText2(u"text "_ustr);
2001 editEng.SetText(sText2);
2002 CPPUNIT_ASSERT_EQUAL(OUString(" "), editEng.GetText(esel));
2004 CPPUNIT_ASSERT_EQUAL(OUString("text "), lcl_translitTest(editEng, sText2, esel, TF::SENTENCE_CASE));
2005 CPPUNIT_ASSERT_EQUAL(OUString("text "), lcl_translitTest(editEng, sText2, esel, TF::TITLE_CASE));
2006 CPPUNIT_ASSERT_EQUAL(OUString("text "), lcl_translitTest(editEng, sText2, esel, TF::LOWERCASE_UPPERCASE));
2007 CPPUNIT_ASSERT_EQUAL(OUString("text "), lcl_translitTest(editEng, sText2, esel, TF::UPPERCASE_LOWERCASE));
2009 /* Test what happens when node contains only non-word text but selection does not contain any text */
2010 selStart = 0;
2011 selEnd = 3;
2012 esel = ESelection(0, selStart, 0, selEnd);
2013 constexpr OUString sText3(u" -1"_ustr);
2014 editEng.SetText(sText3);
2015 CPPUNIT_ASSERT_EQUAL(OUString(" "), editEng.GetText(esel));
2017 CPPUNIT_ASSERT_EQUAL(OUString(" -1"), lcl_translitTest(editEng, sText3, esel, TF::SENTENCE_CASE));
2018 CPPUNIT_ASSERT_EQUAL(OUString(" -1"), lcl_translitTest(editEng, sText3, esel, TF::TITLE_CASE));
2019 CPPUNIT_ASSERT_EQUAL(OUString(" -1"), lcl_translitTest(editEng, sText3, esel, TF::LOWERCASE_UPPERCASE));
2020 CPPUNIT_ASSERT_EQUAL(OUString(" -1"), lcl_translitTest(editEng, sText3, esel, TF::UPPERCASE_LOWERCASE));
2022 selStart = 2;
2023 selEnd = 6;
2024 esel = ESelection(0, selStart, 0, selEnd);
2025 constexpr OUString sText4(u"-1 "_ustr);
2026 editEng.SetText(sText4);
2027 CPPUNIT_ASSERT_EQUAL(OUString(" "), editEng.GetText(esel));
2029 CPPUNIT_ASSERT_EQUAL(OUString("-1 "), lcl_translitTest(editEng, sText4, esel, TF::SENTENCE_CASE));
2030 CPPUNIT_ASSERT_EQUAL(OUString("-1 "), lcl_translitTest(editEng, sText4, esel, TF::TITLE_CASE));
2031 CPPUNIT_ASSERT_EQUAL(OUString("-1 "), lcl_translitTest(editEng, sText4, esel, TF::LOWERCASE_UPPERCASE));
2032 CPPUNIT_ASSERT_EQUAL(OUString("-1 "), lcl_translitTest(editEng, sText4, esel, TF::UPPERCASE_LOWERCASE));
2034 /* Test what happens when node and selection contains only non-word text */
2035 selStart = 0;
2036 selEnd = 5;
2037 esel = ESelection(0, selStart, 0, selEnd);
2038 constexpr OUString sText5(u" -1"_ustr);
2039 editEng.SetText(sText3);
2040 CPPUNIT_ASSERT_EQUAL(OUString(" -1"), editEng.GetText(esel));
2042 CPPUNIT_ASSERT_EQUAL(OUString(" -1"), lcl_translitTest(editEng, sText5, esel, TF::SENTENCE_CASE));
2043 CPPUNIT_ASSERT_EQUAL(OUString(" -1"), lcl_translitTest(editEng, sText5, esel, TF::TITLE_CASE));
2044 CPPUNIT_ASSERT_EQUAL(OUString(" -1"), lcl_translitTest(editEng, sText5, esel, TF::LOWERCASE_UPPERCASE));
2045 CPPUNIT_ASSERT_EQUAL(OUString(" -1"), lcl_translitTest(editEng, sText5, esel, TF::UPPERCASE_LOWERCASE));
2047 selStart = 0;
2048 selEnd = 5;
2049 esel = ESelection(0, selStart, 0, selEnd);
2050 constexpr OUString sText6(u"-1 "_ustr);
2051 editEng.SetText(sText4);
2052 CPPUNIT_ASSERT_EQUAL(OUString("-1 "), editEng.GetText(esel));
2054 CPPUNIT_ASSERT_EQUAL(OUString("-1 "), lcl_translitTest(editEng, sText6, esel, TF::SENTENCE_CASE));
2055 CPPUNIT_ASSERT_EQUAL(OUString("-1 "), lcl_translitTest(editEng, sText6, esel, TF::TITLE_CASE));
2056 CPPUNIT_ASSERT_EQUAL(OUString("-1 "), lcl_translitTest(editEng, sText6, esel, TF::LOWERCASE_UPPERCASE));
2057 CPPUNIT_ASSERT_EQUAL(OUString("-1 "), lcl_translitTest(editEng, sText6, esel, TF::UPPERCASE_LOWERCASE));
2062 void Test::testSingleLine()
2064 EditEngine aEditEngine( mpItemPool.get() );
2066 aEditEngine.SetSingleLine(true);
2067 aEditEngine.SetText("Bolivian\nSanta Cruz de la Sierra");
2068 aEditEngine.QuickFormatDoc(true);
2069 CPPUNIT_ASSERT_EQUAL(true, aEditEngine.IsFormatted());
2070 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEditEngine.GetParagraphCount());
2071 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEditEngine.GetLineCount(0));
2074 CPPUNIT_TEST_SUITE_REGISTRATION(Test);
2078 CPPUNIT_PLUGIN_IMPLEMENT();
2080 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */