Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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 : */
9 :
10 : #include "test/bootstrapfixture.hxx"
11 :
12 : #include <cppunit/TestFixture.h>
13 : #include <cppunit/extensions/HelperMacros.h>
14 :
15 : #include "svl/itempool.hxx"
16 : #include "editeng/eerdll.hxx"
17 : #include "editeng/eerdll2.hxx"
18 : #include "editeng/editeng.hxx"
19 : #include "editeng/eeitem.hxx"
20 : #include "editeng/editids.hrc"
21 : #include "editeng/editdoc.hxx"
22 : #include "editeng/svxacorr.hxx"
23 : #include "editeng/unofield.hxx"
24 : #include "editeng/wghtitem.hxx"
25 : #include "editeng/postitem.hxx"
26 : #include "editeng/section.hxx"
27 : #include "editeng/editobj.hxx"
28 : #include "editeng/flditem.hxx"
29 : #include "svl/srchitem.hxx"
30 : #include "rtl/strbuf.hxx"
31 :
32 : #include <com/sun/star/text/textfield/Type.hpp>
33 :
34 : #include <boost/scoped_ptr.hpp>
35 :
36 : using namespace com::sun::star;
37 :
38 : namespace {
39 :
40 10 : class Test : public test::BootstrapFixture
41 : {
42 : public:
43 : Test();
44 :
45 : virtual void setUp() SAL_OVERRIDE;
46 : virtual void tearDown() SAL_OVERRIDE;
47 :
48 : void testConstruction();
49 :
50 : /// Test UNO service class that implements text field items.
51 : void testUnoTextFields();
52 :
53 : /// AutoCorrect tests
54 : void testAutocorrect();
55 :
56 : /// Test hyperlinks
57 : void testHyperlinkSearch();
58 :
59 : void testSectionAttributes();
60 :
61 2 : CPPUNIT_TEST_SUITE(Test);
62 1 : CPPUNIT_TEST(testConstruction);
63 1 : CPPUNIT_TEST(testUnoTextFields);
64 1 : CPPUNIT_TEST(testAutocorrect);
65 1 : CPPUNIT_TEST(testHyperlinkSearch);
66 1 : CPPUNIT_TEST(testSectionAttributes);
67 5 : CPPUNIT_TEST_SUITE_END();
68 :
69 : private:
70 : EditEngineItemPool* mpItemPool;
71 : };
72 :
73 5 : Test::Test() : mpItemPool(NULL) {}
74 :
75 5 : void Test::setUp()
76 : {
77 5 : test::BootstrapFixture::setUp();
78 :
79 5 : mpItemPool = new EditEngineItemPool(true);
80 5 : }
81 :
82 5 : void Test::tearDown()
83 : {
84 5 : SfxItemPool::Free(mpItemPool);
85 5 : test::BootstrapFixture::tearDown();
86 5 : }
87 :
88 1 : void Test::testConstruction()
89 : {
90 1 : EditEngine aEngine(mpItemPool);
91 :
92 2 : OUString aParaText = "I am Edit Engine.";
93 2 : aEngine.SetText(aParaText);
94 1 : }
95 :
96 : namespace {
97 :
98 14 : bool includes(const uno::Sequence<OUString>& rSeq, const OUString& rVal)
99 : {
100 56 : for (sal_Int32 i = 0, n = rSeq.getLength(); i < n; ++i)
101 56 : if (rSeq[i] == rVal)
102 14 : return true;
103 :
104 0 : return false;
105 : }
106 :
107 : }
108 :
109 1 : void Test::testUnoTextFields()
110 : {
111 : {
112 : // DATE
113 1 : SvxUnoTextField aField(text::textfield::Type::DATE);
114 2 : uno::Sequence<OUString> aSvcs = aField.getSupportedServiceNames();
115 1 : bool bGood = includes(aSvcs, "com.sun.star.text.textfield.DateTime");
116 2 : CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
117 : }
118 :
119 : {
120 : // URL
121 1 : SvxUnoTextField aField(text::textfield::Type::URL);
122 2 : uno::Sequence<OUString> aSvcs = aField.getSupportedServiceNames();
123 1 : bool bGood = includes(aSvcs, "com.sun.star.text.textfield.URL");
124 2 : CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
125 : }
126 :
127 : {
128 : // PAGE
129 1 : SvxUnoTextField aField(text::textfield::Type::PAGE);
130 2 : uno::Sequence<OUString> aSvcs = aField.getSupportedServiceNames();
131 1 : bool bGood = includes(aSvcs, "com.sun.star.text.textfield.PageNumber");
132 2 : CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
133 : }
134 :
135 : {
136 : // PAGES
137 1 : SvxUnoTextField aField(text::textfield::Type::PAGES);
138 2 : uno::Sequence<OUString> aSvcs = aField.getSupportedServiceNames();
139 1 : bool bGood = includes(aSvcs, "com.sun.star.text.textfield.PageCount");
140 2 : CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
141 : }
142 :
143 : {
144 : // TIME
145 1 : SvxUnoTextField aField(text::textfield::Type::TIME);
146 2 : uno::Sequence<OUString> aSvcs = aField.getSupportedServiceNames();
147 1 : bool bGood = includes(aSvcs, "com.sun.star.text.textfield.DateTime");
148 2 : CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
149 : }
150 :
151 : {
152 : // FILE
153 1 : SvxUnoTextField aField(text::textfield::Type::DOCINFO_TITLE);
154 2 : uno::Sequence<OUString> aSvcs = aField.getSupportedServiceNames();
155 1 : bool bGood = includes(aSvcs, "com.sun.star.text.textfield.docinfo.Title");
156 2 : CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
157 : }
158 :
159 : {
160 : // TABLE
161 1 : SvxUnoTextField aField(text::textfield::Type::TABLE);
162 2 : uno::Sequence<OUString> aSvcs = aField.getSupportedServiceNames();
163 1 : bool bGood = includes(aSvcs, "com.sun.star.text.textfield.SheetName");
164 2 : CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
165 : }
166 :
167 : {
168 : // EXTENDED TIME
169 1 : SvxUnoTextField aField(text::textfield::Type::EXTENDED_TIME);
170 2 : uno::Sequence<OUString> aSvcs = aField.getSupportedServiceNames();
171 1 : bool bGood = includes(aSvcs, "com.sun.star.text.textfield.DateTime");
172 2 : CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
173 : }
174 :
175 : {
176 : // EXTENDED FILE
177 1 : SvxUnoTextField aField(text::textfield::Type::EXTENDED_FILE);
178 2 : uno::Sequence<OUString> aSvcs = aField.getSupportedServiceNames();
179 1 : bool bGood = includes(aSvcs, "com.sun.star.text.textfield.FileName");
180 2 : CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
181 : }
182 :
183 : {
184 : // AUTHOR
185 1 : SvxUnoTextField aField(text::textfield::Type::AUTHOR);
186 2 : uno::Sequence<OUString> aSvcs = aField.getSupportedServiceNames();
187 1 : bool bGood = includes(aSvcs, "com.sun.star.text.textfield.Author");
188 2 : CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
189 : }
190 :
191 : {
192 : // MEASURE
193 1 : SvxUnoTextField aField(text::textfield::Type::MEASURE);
194 2 : uno::Sequence<OUString> aSvcs = aField.getSupportedServiceNames();
195 1 : bool bGood = includes(aSvcs, "com.sun.star.text.textfield.Measure");
196 2 : CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
197 : }
198 :
199 : {
200 : // PRESENTATION HEADER
201 1 : SvxUnoTextField aField(text::textfield::Type::PRESENTATION_HEADER);
202 2 : uno::Sequence<OUString> aSvcs = aField.getSupportedServiceNames();
203 1 : bool bGood = includes(aSvcs, "com.sun.star.presentation.textfield.Header");
204 2 : CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
205 : }
206 :
207 : {
208 : // PRESENTATION FOOTER
209 1 : SvxUnoTextField aField(text::textfield::Type::PRESENTATION_FOOTER);
210 2 : uno::Sequence<OUString> aSvcs = aField.getSupportedServiceNames();
211 1 : bool bGood = includes(aSvcs, "com.sun.star.presentation.textfield.Footer");
212 2 : CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
213 : }
214 :
215 : {
216 : // PRESENTATION DATE TIME
217 1 : SvxUnoTextField aField(text::textfield::Type::PRESENTATION_DATE_TIME);
218 2 : uno::Sequence<OUString> aSvcs = aField.getSupportedServiceNames();
219 1 : bool bGood = includes(aSvcs, "com.sun.star.presentation.textfield.DateTime");
220 2 : CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
221 : }
222 1 : }
223 :
224 3 : class TestAutoCorrDoc : public SvxAutoCorrDoc
225 : {
226 : public:
227 : /// just like the real thing, this dummy modifies the rText parameter :(
228 3 : TestAutoCorrDoc(OUString &rText, LanguageType eLang)
229 : : m_rText(rText)
230 3 : , m_eLang(eLang)
231 : {
232 3 : }
233 3 : OUString const& getResult() const
234 : {
235 3 : return m_rText;
236 : }
237 : private:
238 : OUString & m_rText;
239 : LanguageType m_eLang;
240 2 : virtual bool Delete( sal_Int32 nStt, sal_Int32 nEnd ) SAL_OVERRIDE
241 : {
242 : //fprintf(stderr, "TestAutoCorrDoc::Delete\n");
243 2 : m_rText = m_rText.replaceAt(nStt, nEnd-nStt, "");
244 2 : return true;
245 : }
246 3 : virtual bool Insert( sal_Int32 nPos, const OUString& rTxt ) SAL_OVERRIDE
247 : {
248 : //fprintf(stderr, "TestAutoCorrDoc::Insert\n");
249 3 : m_rText = m_rText.replaceAt(nPos, 0, rTxt);
250 3 : return true;
251 : }
252 0 : virtual bool Replace( sal_Int32 nPos, const OUString& rTxt ) SAL_OVERRIDE
253 : {
254 : //fprintf(stderr, "TestAutoCorrDoc::Replace\n");
255 0 : return ReplaceRange( nPos, rTxt.getLength(), rTxt );
256 : }
257 4 : virtual bool ReplaceRange( sal_Int32 nPos, sal_Int32 nLen, const OUString& rTxt ) SAL_OVERRIDE
258 : {
259 : //fprintf(stderr, "TestAutoCorrDoc::ReplaceRange %d %d %s\n", nPos, nLen, OUStringToOString(rTxt, RTL_TEXTENCODING_UTF8).getStr());
260 4 : m_rText = m_rText.replaceAt(nPos, nLen, rTxt);
261 4 : return true;
262 : }
263 1 : virtual bool SetAttr( sal_Int32, sal_Int32, sal_uInt16, SfxPoolItem& ) SAL_OVERRIDE
264 : {
265 : //fprintf(stderr, "TestAutoCorrDoc::SetAttr\n");
266 1 : return true;
267 : }
268 0 : virtual bool SetINetAttr( sal_Int32, sal_Int32, const OUString& ) SAL_OVERRIDE
269 : {
270 : //fprintf(stderr, "TestAutoCorrDoc::SetINetAttr\n");
271 0 : return true;
272 : }
273 0 : virtual OUString const* GetPrevPara(bool) SAL_OVERRIDE
274 : {
275 : //fprintf(stderr, "TestAutoCorrDoc::GetPrevPara\n");
276 0 : return 0;
277 : }
278 2 : virtual bool ChgAutoCorrWord( sal_Int32& rSttPos,
279 : sal_Int32 nEndPos, SvxAutoCorrect& rACorrect,
280 : OUString* pPara ) SAL_OVERRIDE
281 : {
282 : //fprintf(stderr, "TestAutoCorrDoc::ChgAutoCorrWord\n");
283 :
284 2 : if (m_rText.isEmpty())
285 0 : return false;
286 :
287 2 : LanguageTag aLanguageTag( m_eLang);
288 : const SvxAutocorrWord* pFnd = rACorrect.SearchWordsInList(
289 2 : m_rText, rSttPos, nEndPos, *this, aLanguageTag);
290 2 : if (pFnd && pFnd->IsTextOnly())
291 : {
292 0 : m_rText = m_rText.replaceAt(rSttPos, nEndPos, pFnd->GetLong());
293 0 : if( pPara )
294 0 : pPara->clear(); // =&pCurNode->GetString();
295 0 : return true;
296 : }
297 :
298 2 : return false;
299 : }
300 : };
301 :
302 : //https://bugs.libreoffice.org/show_bug.cgi?id=55693
303 : //Two capitalized letters are not corrected if dash or slash are directly
304 : //before the two letters
305 1 : void Test::testAutocorrect()
306 : {
307 1 : OUString sShareAutocorrFile;
308 2 : OUString sUserAutocorrFile;
309 2 : SvxAutoCorrect aAutoCorrect(sShareAutocorrFile, sUserAutocorrFile);
310 :
311 : {
312 1 : OUString sInput("TEst-TEst");
313 1 : sal_Unicode cNextChar(' ');
314 2 : OUString sExpected("Test-Test ");
315 :
316 2 : TestAutoCorrDoc aFoo(sInput, LANGUAGE_ENGLISH_US);
317 1 : aAutoCorrect.DoAutoCorrect(aFoo, sInput, sInput.getLength(), cNextChar, true);
318 :
319 2 : CPPUNIT_ASSERT_MESSAGE("autocorrect", aFoo.getResult() == sExpected);
320 : }
321 :
322 : {
323 1 : OUString sInput("TEst/TEst");
324 1 : sal_Unicode cNextChar(' ');
325 2 : OUString sExpected("Test/Test ");
326 :
327 2 : TestAutoCorrDoc aFoo(sInput, LANGUAGE_ENGLISH_US);
328 1 : aAutoCorrect.DoAutoCorrect(aFoo, sInput, sInput.getLength(), cNextChar, true);
329 :
330 2 : CPPUNIT_ASSERT_MESSAGE("autocorrect", aFoo.getResult() == sExpected);
331 : }
332 :
333 : {
334 : // test auto-bolding with '*'
335 1 : OUString sInput("*foo");
336 1 : sal_Unicode cNextChar('*');
337 2 : OUString sExpected("foo");
338 :
339 2 : TestAutoCorrDoc aFoo(sInput, LANGUAGE_ENGLISH_US);
340 1 : aAutoCorrect.DoAutoCorrect(aFoo, sInput, sInput.getLength(), cNextChar, true);
341 :
342 2 : CPPUNIT_ASSERT_EQUAL(sExpected, aFoo.getResult());
343 1 : }
344 1 : }
345 :
346 : namespace {
347 1 : class UrlEditEngine : public EditEngine
348 : {
349 : public:
350 1 : UrlEditEngine(SfxItemPool *pPool) : EditEngine(pPool) {}
351 :
352 1 : virtual OUString CalcFieldValue( const SvxFieldItem&, sal_Int32, sal_Int32, Color*&, Color*& ) SAL_OVERRIDE
353 : {
354 1 : return OUString("jim@bob.com"); // a sophisticated view of value:
355 : }
356 : };
357 : }
358 :
359 : // Odd accounting for hyperlink position & size etc.
360 : // https://bugzilla.novell.com/show_bug.cgi?id=467459
361 1 : void Test::testHyperlinkSearch()
362 : {
363 1 : UrlEditEngine aEngine(mpItemPool);
364 1 : EditDoc &rDoc = aEngine.GetEditDoc();
365 :
366 2 : OUString aSampleText = "Please write email to . if you find a fish(not a dog).";
367 1 : aEngine.SetText(aSampleText);
368 :
369 1 : CPPUNIT_ASSERT_MESSAGE("set text", rDoc.GetParaAsString(sal_Int32(0)) == aSampleText);
370 :
371 1 : ContentNode *pNode = rDoc.GetObject(0);
372 1 : EditSelection aSel(EditPaM(pNode, 22), EditPaM(pNode, 22));
373 : SvxURLField aURLField("mailto:///jim@bob.com", "jim@bob.com",
374 2 : SVXURLFORMAT_REPR);
375 2 : SvxFieldItem aField(aURLField, EE_FEATURE_FIELD);
376 :
377 1 : aEngine.InsertField(aSel, aField);
378 1 : aEngine.UpdateFields();
379 :
380 2 : OUString aContent = pNode->GetExpandedText();
381 2 : CPPUNIT_ASSERT_MESSAGE("get text", aContent ==
382 1 : "Please write email to jim@bob.com. if you find a fish(not a dog).");
383 1 : CPPUNIT_ASSERT_MESSAGE("wrong length", rDoc.GetTextLen() == (sal_uLong)aContent.getLength());
384 :
385 : // Check expansion and positioning re-work
386 2 : CPPUNIT_ASSERT_MESSAGE("wrong length", pNode->GetExpandedLen() ==
387 1 : (sal_uLong)aContent.getLength());
388 66 : for (sal_Int32 n = 0; n < aContent.getLength(); n++)
389 : {
390 65 : sal_Int32 nStart = n, nEnd = n;
391 65 : pNode->UnExpandPositions(nStart,nEnd);
392 65 : CPPUNIT_ASSERT_MESSAGE("out of bound start", nStart < pNode->Len());
393 65 : CPPUNIT_ASSERT_MESSAGE("out of bound end", nEnd <= pNode->Len());
394 : }
395 :
396 : static const struct {
397 : sal_Int32 mnStart, mnEnd;
398 : sal_Int32 mnNewStart, mnNewEnd;
399 : } aTrickyOnes[] = {
400 : { 0, 1, /* -> */ 0, 1 },
401 : { 21, 25, /* -> */ 21, 23 }, // the field is really just one char
402 : { 25, 27, /* -> */ 22, 23 },
403 : { 50, 56, /* -> */ 40, 46 }
404 : };
405 5 : for (size_t n = 0; n < SAL_N_ELEMENTS(aTrickyOnes); n++)
406 : {
407 4 : sal_Int32 nStart = aTrickyOnes[n].mnStart;
408 4 : sal_Int32 nEnd = aTrickyOnes[n].mnEnd;
409 4 : pNode->UnExpandPositions(nStart,nEnd);
410 :
411 4 : rtl::OStringBuffer aBuf;
412 4 : aBuf = "bound check start is ";
413 4 : aBuf.append(nStart).append(" but should be ").append(aTrickyOnes[n].mnNewStart);
414 4 : aBuf.append(" in row ").append((sal_Int32)n);
415 4 : CPPUNIT_ASSERT_MESSAGE(aBuf.getStr(), nStart == aTrickyOnes[n].mnNewStart);
416 4 : aBuf = "bound check end is ";
417 4 : aBuf.append(nEnd).append(" but should be ").append(aTrickyOnes[n].mnNewEnd);
418 4 : aBuf.append(" in row ").append((sal_Int32)n);
419 4 : CPPUNIT_ASSERT_MESSAGE(aBuf.getStr(), nEnd == aTrickyOnes[n].mnNewEnd);
420 4 : }
421 :
422 2 : SvxSearchItem aItem(1); //SID_SEARCH_ITEM);
423 1 : aItem.SetBackward(false);
424 1 : aItem.SetSelection(false);
425 1 : aItem.SetSearchString("fish");
426 1 : CPPUNIT_ASSERT_MESSAGE("no fish", aEngine.HasText(aItem));
427 1 : aItem.SetSearchString("dog");
428 2 : CPPUNIT_ASSERT_MESSAGE("no dog", aEngine.HasText(aItem));
429 1 : }
430 :
431 5 : bool hasBold(const editeng::Section& rSecAttr)
432 : {
433 5 : std::vector<const SfxPoolItem*>::const_iterator it = rSecAttr.maAttributes.begin(), itEnd = rSecAttr.maAttributes.end();
434 5 : for (; it != itEnd; ++it)
435 : {
436 5 : const SfxPoolItem* p = *it;
437 5 : if (p->Which() != EE_CHAR_WEIGHT)
438 0 : continue;
439 :
440 5 : if (static_cast<const SvxWeightItem*>(p)->GetWeight() != WEIGHT_BOLD)
441 0 : continue;
442 :
443 5 : return true;
444 : }
445 0 : return false;
446 : }
447 :
448 2 : bool hasItalic(const editeng::Section& rSecAttr)
449 : {
450 2 : std::vector<const SfxPoolItem*>::const_iterator it = rSecAttr.maAttributes.begin(), itEnd = rSecAttr.maAttributes.end();
451 3 : for (; it != itEnd; ++it)
452 : {
453 3 : const SfxPoolItem* p = *it;
454 3 : if (p->Which() != EE_CHAR_ITALIC)
455 1 : continue;
456 :
457 2 : if (static_cast<const SvxPostureItem*>(p)->GetPosture() != ITALIC_NORMAL)
458 0 : continue;
459 :
460 2 : return true;
461 : }
462 0 : return false;
463 : }
464 :
465 1 : void Test::testSectionAttributes()
466 : {
467 1 : EditEngine aEngine(mpItemPool);
468 :
469 2 : boost::scoped_ptr<SfxItemSet> pSet(new SfxItemSet(aEngine.GetEmptyItemSet()));
470 2 : SvxWeightItem aBold(WEIGHT_BOLD, EE_CHAR_WEIGHT);
471 2 : SvxPostureItem aItalic(ITALIC_NORMAL, EE_CHAR_ITALIC);
472 :
473 : {
474 1 : OUString aParaText = "aaabbbccc";
475 1 : aEngine.SetText(aParaText);
476 1 : pSet->Put(aBold);
477 1 : CPPUNIT_ASSERT_MESSAGE("There should be exactly one item.", pSet->Count() == 1);
478 1 : aEngine.QuickSetAttribs(*pSet, ESelection(0,0,0,6)); // 'aaabbb' - end point is not inclusive.
479 1 : pSet.reset(new SfxItemSet(aEngine.GetEmptyItemSet()));
480 1 : pSet->Put(aItalic);
481 1 : CPPUNIT_ASSERT_MESSAGE("There should be exactly one item.", pSet->Count() == 1);
482 :
483 1 : aEngine.QuickSetAttribs(*pSet, ESelection(0,3,0,9)); // 'bbbccc'
484 2 : boost::scoped_ptr<EditTextObject> pEditText(aEngine.CreateTextObject());
485 1 : CPPUNIT_ASSERT_MESSAGE("Failed to create text object.", pEditText.get());
486 2 : std::vector<editeng::Section> aAttrs;
487 1 : pEditText->GetAllSections(aAttrs);
488 :
489 : // Now, we should have a total of 3 sections.
490 1 : CPPUNIT_ASSERT_MESSAGE("There should be 3 sections.", aAttrs.size() == 3);
491 :
492 : // First section should be 0-3 of paragraph 0, and it should only have boldness applied.
493 1 : const editeng::Section* pSecAttr = &aAttrs[0];
494 1 : CPPUNIT_ASSERT_EQUAL(0, (int)pSecAttr->mnParagraph);
495 1 : CPPUNIT_ASSERT_EQUAL(0, (int)pSecAttr->mnStart);
496 1 : CPPUNIT_ASSERT_EQUAL(3, (int)pSecAttr->mnEnd);
497 1 : CPPUNIT_ASSERT_EQUAL(1, (int)pSecAttr->maAttributes.size());
498 1 : CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(*pSecAttr));
499 :
500 : // Second section should be 3-6, and it should be both bold and italic.
501 1 : pSecAttr = &aAttrs[1];
502 1 : CPPUNIT_ASSERT_EQUAL(0, (int)pSecAttr->mnParagraph);
503 1 : CPPUNIT_ASSERT_EQUAL(3, (int)pSecAttr->mnStart);
504 1 : CPPUNIT_ASSERT_EQUAL(6, (int)pSecAttr->mnEnd);
505 1 : CPPUNIT_ASSERT_EQUAL(2, (int)pSecAttr->maAttributes.size());
506 1 : CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasBold(*pSecAttr) && hasItalic(*pSecAttr));
507 :
508 : // Third section should be 6-9, and it should be only italic.
509 1 : pSecAttr = &aAttrs[2];
510 1 : CPPUNIT_ASSERT_EQUAL(0, (int)pSecAttr->mnParagraph);
511 1 : CPPUNIT_ASSERT_EQUAL(6, (int)pSecAttr->mnStart);
512 1 : CPPUNIT_ASSERT_EQUAL(9, (int)pSecAttr->mnEnd);
513 1 : CPPUNIT_ASSERT_EQUAL(1, (int)pSecAttr->maAttributes.size());
514 2 : CPPUNIT_ASSERT_MESSAGE("This section must be italic.", hasItalic(*pSecAttr));
515 : }
516 :
517 : {
518 : // Set text consisting of 5 paragraphs with the 2nd and 4th paragraphs
519 : // being empty.
520 1 : aEngine.Clear();
521 1 : aEngine.SetText("one\n\ntwo\n\nthree");
522 1 : sal_Int32 nParaCount = aEngine.GetParagraphCount();
523 1 : sal_Int32 nCheck = 5;
524 1 : CPPUNIT_ASSERT_EQUAL(nCheck, nParaCount);
525 :
526 : // Apply boldness to paragraphs 1, 3, 5 only. Leave 2 and 4 unformatted.
527 1 : pSet.reset(new SfxItemSet(aEngine.GetEmptyItemSet()));
528 1 : pSet->Put(aBold);
529 1 : CPPUNIT_ASSERT_MESSAGE("There should be exactly one item.", pSet->Count() == 1);
530 1 : aEngine.QuickSetAttribs(*pSet, ESelection(0,0,0,3));
531 1 : aEngine.QuickSetAttribs(*pSet, ESelection(2,0,2,3));
532 1 : aEngine.QuickSetAttribs(*pSet, ESelection(4,0,4,5));
533 :
534 1 : boost::scoped_ptr<EditTextObject> pEditText(aEngine.CreateTextObject());
535 1 : CPPUNIT_ASSERT_MESSAGE("Failed to create text object.", pEditText.get());
536 2 : std::vector<editeng::Section> aAttrs;
537 1 : pEditText->GetAllSections(aAttrs);
538 1 : size_t nSecCountCheck = 5;
539 1 : CPPUNIT_ASSERT_EQUAL(nSecCountCheck, aAttrs.size());
540 :
541 : // 1st, 3rd and 5th sections should correspond with 1st, 3rd and 5th paragraphs.
542 1 : const editeng::Section* pSecAttr = &aAttrs[0];
543 1 : CPPUNIT_ASSERT_EQUAL(0, (int)pSecAttr->mnParagraph);
544 1 : CPPUNIT_ASSERT_EQUAL(0, (int)pSecAttr->mnStart);
545 1 : CPPUNIT_ASSERT_EQUAL(3, (int)pSecAttr->mnEnd);
546 1 : CPPUNIT_ASSERT_EQUAL(1, (int)pSecAttr->maAttributes.size());
547 1 : CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(*pSecAttr));
548 :
549 1 : pSecAttr = &aAttrs[2];
550 1 : CPPUNIT_ASSERT_EQUAL(2, (int)pSecAttr->mnParagraph);
551 1 : CPPUNIT_ASSERT_EQUAL(0, (int)pSecAttr->mnStart);
552 1 : CPPUNIT_ASSERT_EQUAL(3, (int)pSecAttr->mnEnd);
553 1 : CPPUNIT_ASSERT_EQUAL(1, (int)pSecAttr->maAttributes.size());
554 1 : CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(*pSecAttr));
555 :
556 1 : pSecAttr = &aAttrs[4];
557 1 : CPPUNIT_ASSERT_EQUAL(4, (int)pSecAttr->mnParagraph);
558 1 : CPPUNIT_ASSERT_EQUAL(0, (int)pSecAttr->mnStart);
559 1 : CPPUNIT_ASSERT_EQUAL(5, (int)pSecAttr->mnEnd);
560 1 : CPPUNIT_ASSERT_EQUAL(1, (int)pSecAttr->maAttributes.size());
561 1 : CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(*pSecAttr));
562 :
563 : // The 2nd and 4th paragraphs should be empty.
564 1 : pSecAttr = &aAttrs[1];
565 1 : CPPUNIT_ASSERT_EQUAL(1, (int)pSecAttr->mnParagraph);
566 1 : CPPUNIT_ASSERT_EQUAL(0, (int)pSecAttr->mnStart);
567 1 : CPPUNIT_ASSERT_EQUAL(0, (int)pSecAttr->mnEnd);
568 1 : CPPUNIT_ASSERT_MESSAGE("Attribute array should be empty.", pSecAttr->maAttributes.empty());
569 :
570 1 : pSecAttr = &aAttrs[3];
571 1 : CPPUNIT_ASSERT_EQUAL(3, (int)pSecAttr->mnParagraph);
572 1 : CPPUNIT_ASSERT_EQUAL(0, (int)pSecAttr->mnStart);
573 1 : CPPUNIT_ASSERT_EQUAL(0, (int)pSecAttr->mnEnd);
574 2 : CPPUNIT_ASSERT_MESSAGE("Attribute array should be empty.", pSecAttr->maAttributes.empty());
575 : }
576 :
577 :
578 : {
579 1 : aEngine.Clear();
580 1 : aEngine.SetText("one\ntwo");
581 1 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), aEngine.GetParagraphCount());
582 :
583 : // embolden 2nd paragraph
584 1 : pSet.reset(new SfxItemSet(aEngine.GetEmptyItemSet()));
585 1 : pSet->Put(aBold);
586 1 : aEngine.QuickSetAttribs(*pSet, ESelection(1,0,1,3));
587 : // disboldify 1st paragraph
588 1 : SvxWeightItem aNotSoBold(WEIGHT_NORMAL, EE_CHAR_WEIGHT);
589 1 : pSet->Put(aNotSoBold);
590 1 : aEngine.QuickSetAttribs(*pSet, ESelection(0,0,0,3));
591 :
592 : // now delete & join the paragraphs - this is fdo#85496 scenario
593 1 : aEngine.QuickDelete(ESelection(0,0,1,3));
594 1 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), aEngine.GetParagraphCount());
595 :
596 2 : boost::scoped_ptr<EditTextObject> pEditText(aEngine.CreateTextObject());
597 1 : CPPUNIT_ASSERT_MESSAGE("Failed to create text object.", pEditText.get());
598 2 : std::vector<editeng::Section> aAttrs;
599 1 : pEditText->GetAllSections(aAttrs);
600 :
601 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aAttrs.size());
602 :
603 1 : const editeng::Section* pSecAttr = &aAttrs[0];
604 1 : CPPUNIT_ASSERT_EQUAL(0, (int)pSecAttr->mnParagraph);
605 1 : CPPUNIT_ASSERT_EQUAL(0, (int)pSecAttr->mnStart);
606 1 : CPPUNIT_ASSERT_EQUAL(0, (int)pSecAttr->mnEnd);
607 2 : std::set<sal_uInt16> whiches;
608 2 : for (size_t i = 0; i < pSecAttr->maAttributes.size(); ++i)
609 : {
610 1 : sal_uInt16 const nWhich(pSecAttr->maAttributes[i]->Which());
611 2 : CPPUNIT_ASSERT_MESSAGE("duplicate item in text portion attributes",
612 1 : whiches.insert(nWhich).second);
613 1 : }
614 1 : }
615 1 : }
616 :
617 1 : CPPUNIT_TEST_SUITE_REGISTRATION(Test);
618 :
619 : }
620 :
621 4 : CPPUNIT_PLUGIN_IMPLEMENT();
622 :
623 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|