1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
10 #include <swmodeltestbase.hxx>
12 #include <com/sun/star/awt/FontSlant.hpp>
13 #include <com/sun/star/datatransfer/XTransferableSupplier.hpp>
14 #include <com/sun/star/datatransfer/XTransferableTextSupplier.hpp>
15 #include <com/sun/star/frame/XDispatch.hpp>
16 #include <com/sun/star/frame/XDispatchProviderInterception.hpp>
17 #include <com/sun/star/frame/XDispatchProviderInterceptor.hpp>
18 #include <com/sun/star/table/XCellRange.hpp>
19 #include <com/sun/star/text/TextContentAnchorType.hpp>
20 #include <com/sun/star/text/AutoTextContainer.hpp>
21 #include <com/sun/star/text/VertOrientation.hpp>
22 #include <com/sun/star/text/XAutoTextGroup.hpp>
23 #include <com/sun/star/text/XTextPortionAppend.hpp>
24 #include <com/sun/star/text/XTextContentAppend.hpp>
25 #include <com/sun/star/text/XTextRangeCompare.hpp>
26 #include <com/sun/star/text/XPasteListener.hpp>
27 #include <com/sun/star/rdf/URI.hpp>
28 #include <com/sun/star/rdf/URIs.hpp>
29 #include <com/sun/star/awt/XDevice.hpp>
30 #include <com/sun/star/awt/XToolkit.hpp>
31 #include <com/sun/star/graphic/XGraphic.hpp>
32 #include <com/sun/star/style/LineSpacing.hpp>
33 #include <com/sun/star/view/XSelectionSupplier.hpp>
34 #include <com/sun/star/text/XTextDocument.hpp>
35 #include <com/sun/star/container/XNameContainer.hpp>
36 #include <com/sun/star/view/XRenderable.hpp>
37 #include <com/sun/star/text/XBookmarksSupplier.hpp>
38 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
39 #include <com/sun/star/text/XTextTable.hpp>
40 #include <com/sun/star/text/XPageCursor.hpp>
42 #include <comphelper/propertyvalue.hxx>
43 #include <tools/UnitConversion.hxx>
44 #include <toolkit/helper/vclunohelper.hxx>
45 #include <vcl/graphicfilter.hxx>
46 #include <comphelper/sequenceashashmap.hxx>
47 #include <comphelper/processfactory.hxx>
48 #include <comphelper/propertysequence.hxx>
49 #include <comphelper/compbase.hxx>
53 #include <swdtflvr.hxx>
55 #include <PostItMgr.hxx>
56 #include <postithelper.hxx>
57 #include <AnnotationWin.hxx>
59 #include <fmtanchr.hxx>
60 #include <unotxdoc.hxx>
63 using namespace ::com::sun::star
;
67 /// Listener implementation for testPasteListener.
68 class PasteListener
: public cppu::WeakImplHelper
<text::XPasteListener
>
71 uno::Reference
<text::XTextContent
> m_xTextGraphicObject
;
74 void SAL_CALL
notifyPasteEvent(const uno::Sequence
<beans::PropertyValue
>& rEvent
) override
;
76 OUString
& GetString();
77 uno::Reference
<text::XTextContent
>& GetTextGraphicObject();
80 void PasteListener::notifyPasteEvent(const uno::Sequence
<beans::PropertyValue
>& rEvent
)
82 comphelper::SequenceAsHashMap
aMap(rEvent
);
83 auto it
= aMap
.find(u
"TextRange"_ustr
);
86 auto xTextRange
= it
->second
.get
<uno::Reference
<text::XTextRange
>>();
88 m_aString
= xTextRange
->getString();
92 it
= aMap
.find(u
"TextGraphicObject"_ustr
);
95 auto xTextGraphicObject
= it
->second
.get
<uno::Reference
<text::XTextContent
>>();
96 if (xTextGraphicObject
.is())
97 m_xTextGraphicObject
= xTextGraphicObject
;
101 OUString
& PasteListener::GetString() { return m_aString
; }
103 uno::Reference
<text::XTextContent
>& PasteListener::GetTextGraphicObject()
105 return m_xTextGraphicObject
;
108 /// Test to assert UNO API call results of Writer.
109 class SwUnoWriter
: public SwModelTestBase
113 : SwModelTestBase(u
"/sw/qa/extras/unowriter/data/"_ustr
, u
"writer8"_ustr
)
118 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testDefaultCharStyle
)
120 // Create a new document, type a character, set its char style to Emphasis
121 // and assert the style was set.
124 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
125 uno::Reference
<text::XSimpleText
> xBodyText
= xTextDocument
->getText();
126 xBodyText
->insertString(xBodyText
->getStart(), u
"x"_ustr
, false);
128 uno::Reference
<text::XTextCursor
> xCursor(xBodyText
->createTextCursor());
129 xCursor
->goLeft(1, true);
131 uno::Reference
<beans::XPropertySet
> xCursorProps(xCursor
, uno::UNO_QUERY
);
132 xCursorProps
->setPropertyValue(u
"CharStyleName"_ustr
, uno::Any(u
"Emphasis"_ustr
));
133 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC
,
134 getProperty
<awt::FontSlant
>(xCursorProps
, u
"CharPosture"_ustr
));
136 // Now reset the char style and assert that the font slant is back to none.
137 // This resulted in a lang.IllegalArgumentException, Standard was not
138 // mapped to 'Default Style'.
139 xCursorProps
->setPropertyValue(u
"CharStyleName"_ustr
, uno::Any(u
"Standard"_ustr
));
140 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE
,
141 getProperty
<awt::FontSlant
>(xCursorProps
, u
"CharPosture"_ustr
));
144 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testInsertStringExpandsHints
)
147 uno::Reference
<text::XTextDocument
> const xTextDocument(mxComponent
, uno::UNO_QUERY
);
148 uno::Reference
<text::XText
> const xText(xTextDocument
->getText());
149 uno::Reference
<text::XTextCursor
> const xCursor(xText
->createTextCursor());
150 uno::Reference
<beans::XPropertySet
> const xProps(xCursor
, uno::UNO_QUERY
);
152 xText
->insertString(xCursor
, u
"ab"_ustr
, false);
153 xCursor
->gotoStart(false);
154 xCursor
->goRight(1, true);
155 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE
,
156 getProperty
<awt::FontSlant
>(xProps
, u
"CharPosture"_ustr
));
157 xProps
->setPropertyValue(u
"CharPosture"_ustr
, uno::Any(awt::FontSlant_ITALIC
));
158 xCursor
->collapseToEnd();
159 xText
->insertString(xCursor
, u
"x"_ustr
, false);
160 xCursor
->goLeft(1, true);
161 CPPUNIT_ASSERT_EQUAL(u
"x"_ustr
, xCursor
->getString());
162 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC
,
163 getProperty
<awt::FontSlant
>(xProps
, u
"CharPosture"_ustr
));
166 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testInsertTextPortionNotExpandsHints
)
169 uno::Reference
<text::XTextDocument
> const xTextDocument(mxComponent
, uno::UNO_QUERY
);
170 uno::Reference
<text::XText
> const xText(xTextDocument
->getText());
171 uno::Reference
<text::XTextPortionAppend
> const xTextA(xText
, uno::UNO_QUERY
);
172 uno::Reference
<text::XTextCursor
> const xCursor(xText
->createTextCursor());
173 uno::Reference
<beans::XPropertySet
> const xProps(xCursor
, uno::UNO_QUERY
);
175 xText
->insertString(xCursor
, u
"ab"_ustr
, false);
176 xCursor
->gotoStart(false);
177 xCursor
->goRight(1, true);
178 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE
,
179 getProperty
<awt::FontSlant
>(xProps
, u
"CharPosture"_ustr
));
180 xProps
->setPropertyValue(u
"CharPosture"_ustr
, uno::Any(awt::FontSlant_ITALIC
));
181 xCursor
->collapseToEnd();
182 xTextA
->insertTextPortion(u
"x"_ustr
, uno::Sequence
<beans::PropertyValue
>(), xCursor
);
183 xCursor
->goLeft(1, true);
184 CPPUNIT_ASSERT_EQUAL(u
"x"_ustr
, xCursor
->getString());
185 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE
,
186 getProperty
<awt::FontSlant
>(xProps
, u
"CharPosture"_ustr
));
189 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testInsertTextContentExpandsHints
)
192 uno::Reference
<text::XTextDocument
> const xTextDocument(mxComponent
, uno::UNO_QUERY
);
193 uno::Reference
<lang::XMultiServiceFactory
> const xFactory(mxComponent
, uno::UNO_QUERY
);
194 uno::Reference
<text::XText
> const xText(xTextDocument
->getText());
195 uno::Reference
<text::XTextCursor
> const xCursor(xText
->createTextCursor());
196 uno::Reference
<beans::XPropertySet
> const xProps(xCursor
, uno::UNO_QUERY
);
198 xText
->insertString(xCursor
, u
"ab"_ustr
, false);
199 xCursor
->gotoStart(false);
200 xCursor
->goRight(1, true);
201 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE
,
202 getProperty
<awt::FontSlant
>(xProps
, u
"CharPosture"_ustr
));
203 xProps
->setPropertyValue(u
"CharPosture"_ustr
, uno::Any(awt::FontSlant_ITALIC
));
204 xCursor
->collapseToEnd();
205 uno::Reference
<text::XTextContent
> const xContent(
206 xFactory
->createInstance(u
"com.sun.star.text.Footnote"_ustr
), uno::UNO_QUERY
);
207 xText
->insertTextContent(xCursor
, xContent
, false);
208 xCursor
->goLeft(1, true);
209 CPPUNIT_ASSERT_EQUAL(u
"1"_ustr
, xCursor
->getString());
210 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC
,
211 getProperty
<awt::FontSlant
>(xProps
, u
"CharPosture"_ustr
));
214 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testInsertTextContentWithPropertiesNotExpandsHints
)
217 uno::Reference
<text::XTextDocument
> const xTextDocument(mxComponent
, uno::UNO_QUERY
);
218 uno::Reference
<lang::XMultiServiceFactory
> const xFactory(mxComponent
, uno::UNO_QUERY
);
219 uno::Reference
<text::XText
> const xText(xTextDocument
->getText());
220 uno::Reference
<text::XTextContentAppend
> const xTextA(xText
, uno::UNO_QUERY
);
221 uno::Reference
<text::XTextCursor
> const xCursor(xText
->createTextCursor());
222 uno::Reference
<beans::XPropertySet
> const xProps(xCursor
, uno::UNO_QUERY
);
224 xText
->insertString(xCursor
, u
"ab"_ustr
, false);
225 xCursor
->gotoStart(false);
226 xCursor
->goRight(1, true);
227 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE
,
228 getProperty
<awt::FontSlant
>(xProps
, u
"CharPosture"_ustr
));
229 xProps
->setPropertyValue(u
"CharPosture"_ustr
, uno::Any(awt::FontSlant_ITALIC
));
230 xCursor
->collapseToEnd();
231 uno::Reference
<text::XTextContent
> const xContent(
232 xFactory
->createInstance(u
"com.sun.star.text.Footnote"_ustr
), uno::UNO_QUERY
);
233 xTextA
->insertTextContentWithProperties(xContent
, uno::Sequence
<beans::PropertyValue
>(),
235 xCursor
->goLeft(1, true);
236 CPPUNIT_ASSERT_EQUAL(u
"1"_ustr
, xCursor
->getString());
237 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE
,
238 getProperty
<awt::FontSlant
>(xProps
, u
"CharPosture"_ustr
));
241 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testGraphicDescriptorURL
)
245 // Create a graphic object, but don't insert it yet.
246 uno::Reference
<lang::XMultiServiceFactory
> xFactory(mxComponent
, uno::UNO_QUERY
);
247 uno::Reference
<beans::XPropertySet
> xTextGraphic(
248 xFactory
->createInstance(u
"com.sun.star.text.TextGraphicObject"_ustr
), uno::UNO_QUERY
);
251 xTextGraphic
->setPropertyValue(u
"GraphicURL"_ustr
, uno::Any(createFileURL(u
"test.jpg")));
252 xTextGraphic
->setPropertyValue(u
"AnchorType"_ustr
,
253 uno::Any(text::TextContentAnchorType_AT_CHARACTER
));
256 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
257 uno::Reference
<text::XText
> xBodyText
= xTextDocument
->getText();
258 uno::Reference
<text::XTextCursor
> xCursor(xBodyText
->createTextCursor());
259 uno::Reference
<text::XTextContent
> xTextContent(xTextGraphic
, uno::UNO_QUERY
);
260 xBodyText
->insertTextContent(xCursor
, xTextContent
, false);
262 // This failed, the graphic object had no graphic.
263 auto xGraphic
= getProperty
<uno::Reference
<graphic::XGraphic
>>(getShape(1), u
"Graphic"_ustr
);
264 CPPUNIT_ASSERT(xGraphic
.is());
267 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testGraphicDescriptorURLBitmap
)
271 // Load a bitmap into the bitmap table.
272 uno::Reference
<lang::XMultiServiceFactory
> xFactory(mxComponent
, uno::UNO_QUERY
);
273 uno::Reference
<container::XNameContainer
> xBitmaps(
274 xFactory
->createInstance(u
"com.sun.star.drawing.BitmapTable"_ustr
), uno::UNO_QUERY
);
275 xBitmaps
->insertByName(u
"test"_ustr
, uno::Any(createFileURL(u
"test.jpg")));
278 uno::Reference
<beans::XPropertySet
> xTextGraphic(
279 xFactory
->createInstance(u
"com.sun.star.text.TextGraphicObject"_ustr
), uno::UNO_QUERY
);
280 xTextGraphic
->setPropertyValue(u
"GraphicURL"_ustr
, xBitmaps
->getByName(u
"test"_ustr
));
281 xTextGraphic
->setPropertyValue(u
"AnchorType"_ustr
,
282 uno::Any(text::TextContentAnchorType_AT_CHARACTER
));
285 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
286 uno::Reference
<text::XText
> xBodyText
= xTextDocument
->getText();
287 uno::Reference
<text::XTextCursor
> xCursor(xBodyText
->createTextCursor());
288 uno::Reference
<text::XTextContent
> xTextContent(xTextGraphic
, uno::UNO_QUERY
);
289 xBodyText
->insertTextContent(xCursor
, xTextContent
, false);
291 // This failed: setting GraphicURL to the result of getByName() did not
293 auto xGraphic
= getProperty
<uno::Reference
<graphic::XGraphic
>>(getShape(1), u
"Graphic"_ustr
);
294 CPPUNIT_ASSERT(xGraphic
.is());
297 bool ensureAutoTextExistsByTitle(const uno::Reference
<text::XAutoTextGroup
>& autoTextGroup
,
298 std::u16string_view autoTextName
)
300 const uno::Sequence
<OUString
> aTitles(autoTextGroup
->getTitles());
301 for (const auto& rTitle
: aTitles
)
303 if (rTitle
== autoTextName
)
309 bool ensureAutoTextExistsByName(const uno::Reference
<text::XAutoTextGroup
>& autoTextGroup
,
310 std::u16string_view autoTextName
)
312 const uno::Sequence
<OUString
> aTitles(autoTextGroup
->getElementNames());
313 for (const auto& rTitle
: aTitles
)
315 if (rTitle
== autoTextName
)
321 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testXAutoTextGroup
)
323 createSwDoc("xautotextgroup.odt");
324 uno::Reference
<text::XAutoTextContainer
> xAutoTextContainer
325 = text::AutoTextContainer::create(comphelper::getProcessComponentContext());
327 uno::Reference
<text::XTextRange
> xTextRange
= getRun(getParagraph(1), 1);
329 static constexpr OUString sGroupName
= u
"TestGroup*1"_ustr
;
330 static constexpr OUString sTextName
= u
"TEST"_ustr
;
331 static constexpr OUString sTextNameNew
= u
"TESTRENAMED"_ustr
;
332 static constexpr OUString sTextTitle
= u
"Test Auto Text"_ustr
;
333 static constexpr OUString sTextTitleNew
= u
"Test Auto Text Renamed"_ustr
;
335 // Create new temporary group
336 uno::Reference
<text::XAutoTextGroup
> xAutoTextGroup
337 = xAutoTextContainer
->insertNewByName(sGroupName
);
338 CPPUNIT_ASSERT_MESSAGE("AutoTextGroup was not found!", xAutoTextGroup
.is());
340 // Insert new element and ensure it exists
341 uno::Reference
<text::XAutoTextEntry
> xAutoTextEntry
342 = xAutoTextGroup
->insertNewByName(sTextName
, sTextTitle
, xTextRange
);
343 CPPUNIT_ASSERT_MESSAGE("AutoText was not inserted!", xAutoTextEntry
.is());
344 CPPUNIT_ASSERT_MESSAGE("Can't find newly created AutoText by title!",
345 ensureAutoTextExistsByTitle(xAutoTextGroup
, sTextTitle
));
346 CPPUNIT_ASSERT_MESSAGE("Can't find newly created AutoText by name!",
347 ensureAutoTextExistsByName(xAutoTextGroup
, sTextName
));
349 // Insert once again the same should throw an exception
350 CPPUNIT_ASSERT_THROW_MESSAGE("We expect an exception on insertion of same AutoText",
351 xAutoTextGroup
->insertNewByName(sTextName
, sTextTitle
, xTextRange
),
352 container::ElementExistException
);
354 // Rename it & ensure everything is ok
355 xAutoTextGroup
->renameByName(sTextName
, sTextNameNew
, sTextTitleNew
);
356 CPPUNIT_ASSERT_MESSAGE("Can't find renamed AutoText by title!",
357 ensureAutoTextExistsByTitle(xAutoTextGroup
, sTextTitleNew
));
358 CPPUNIT_ASSERT_MESSAGE("Can't find renamed AutoText by name!",
359 ensureAutoTextExistsByName(xAutoTextGroup
, sTextNameNew
));
360 // Not found by old names
361 CPPUNIT_ASSERT_MESSAGE("Found AutoText by old title!",
362 !ensureAutoTextExistsByTitle(xAutoTextGroup
, sTextTitle
));
363 CPPUNIT_ASSERT_MESSAGE("Found AutoText by old name!",
364 !ensureAutoTextExistsByName(xAutoTextGroup
, sTextName
));
366 // Rename not existing should throw an exception
367 CPPUNIT_ASSERT_THROW_MESSAGE(
368 "We expect an exception on renaming not-existing AutoText",
369 xAutoTextGroup
->renameByName(sTextName
, sTextNameNew
, sTextTitleNew
),
370 container::ElementExistException
);
372 // Remove it and ensure it does not exist
373 xAutoTextGroup
->removeByName(sTextNameNew
);
374 CPPUNIT_ASSERT_MESSAGE("AutoText was not removed!",
375 !ensureAutoTextExistsByTitle(xAutoTextGroup
, sTextTitleNew
));
376 CPPUNIT_ASSERT_MESSAGE("AutoText was not removed!",
377 !ensureAutoTextExistsByName(xAutoTextGroup
, sTextNameNew
));
379 // Remove non-existing element should throw an exception
380 CPPUNIT_ASSERT_THROW_MESSAGE("We expect an exception on removing not-existing AutoText",
381 xAutoTextGroup
->removeByName(sTextName
),
382 container::NoSuchElementException
);
384 // Remove our temporary group
385 xAutoTextContainer
->removeByName(sGroupName
);
388 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testSectionAnchorCopyTableAtStart
)
390 // this contains a section that starts with a table
391 createSwDoc("tdf134250.fodt");
393 uno::Reference
<text::XTextTablesSupplier
> const xTextTablesSupplier(mxComponent
,
395 uno::Reference
<container::XIndexAccess
> const xTables(xTextTablesSupplier
->getTextTables(),
397 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables
->getCount());
399 uno::Reference
<text::XTextSectionsSupplier
> const xTextSectionsSupplier(mxComponent
,
401 uno::Reference
<container::XIndexAccess
> const xSections(
402 xTextSectionsSupplier
->getTextSections(), uno::UNO_QUERY
);
404 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections
->getCount());
406 uno::Reference
<text::XTextContent
> const xSection(xSections
->getByIndex(0), uno::UNO_QUERY
);
407 uno::Reference
<text::XTextRange
> const xAnchor(xSection
->getAnchor());
408 CPPUNIT_ASSERT_EQUAL(u
"foo" SAL_NEWLINE_STRING
"bar"_ustr
, xAnchor
->getString());
410 // copy the content of the section to a clipboard document
411 uno::Reference
<datatransfer::XTransferableSupplier
> const xTS(
412 uno::Reference
<frame::XModel
>(mxComponent
, uno::UNO_QUERY_THROW
)->getCurrentController(),
414 uno::Reference
<datatransfer::XTransferableTextSupplier
> const xTTS(xTS
, uno::UNO_QUERY
);
415 uno::Reference
<datatransfer::XTransferable
> const xTransferable(
416 xTTS
->getTransferableForTextRange(xAnchor
));
418 // check this doesn't throw
419 CPPUNIT_ASSERT(xAnchor
->getText().is());
420 CPPUNIT_ASSERT(xAnchor
->getStart().is());
421 CPPUNIT_ASSERT(xAnchor
->getEnd().is());
423 // replace section content
424 xAnchor
->setString(u
"quux"_ustr
);
426 // table in section was deleted, but not section itself
427 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xTables
->getCount());
428 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections
->getCount());
429 CPPUNIT_ASSERT_EQUAL(u
"\""
430 "quux" /*SAL_NEWLINE_STRING*/ "\""_ustr
,
431 OUString("\"" + xAnchor
->getString() + "\""));
434 uno::Reference
<text::XTextViewCursorSupplier
> const xTVCS(xTS
, uno::UNO_QUERY
);
435 uno::Reference
<text::XTextViewCursor
> const xCursor(xTVCS
->getViewCursor());
436 xCursor
->gotoEnd(false);
437 xTS
->insertTransferable(xTransferable
);
439 // table in section was pasted, but not section itself
440 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables
->getCount());
441 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections
->getCount());
442 xCursor
->gotoStart(true);
443 CPPUNIT_ASSERT_EQUAL(u
"quux" SAL_NEWLINE_STRING
"foo" SAL_NEWLINE_STRING
"bar"_ustr
,
444 xCursor
->getString());
447 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testSectionAnchorCopyTableAtEnd
)
449 // this contains a section that ends with a table (plus another section)
450 createSwDoc("tdf134252.fodt");
452 uno::Reference
<text::XTextTablesSupplier
> const xTextTablesSupplier(mxComponent
,
454 uno::Reference
<container::XIndexAccess
> const xTables(xTextTablesSupplier
->getTextTables(),
456 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables
->getCount());
458 uno::Reference
<text::XTextSectionsSupplier
> const xTextSectionsSupplier(mxComponent
,
460 uno::Reference
<container::XIndexAccess
> const xSections(
461 xTextSectionsSupplier
->getTextSections(), uno::UNO_QUERY
);
463 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xSections
->getCount());
465 uno::Reference
<text::XTextContent
> const xSection(xSections
->getByIndex(0), uno::UNO_QUERY
);
466 uno::Reference
<text::XTextRange
> const xAnchor(xSection
->getAnchor());
467 CPPUNIT_ASSERT_EQUAL(u
"bar" SAL_NEWLINE_STRING
"baz" SAL_NEWLINE_STRING
""_ustr
,
468 xAnchor
->getString());
470 // copy the content of the section to a clipboard document
471 uno::Reference
<datatransfer::XTransferableSupplier
> const xTS(
472 uno::Reference
<frame::XModel
>(mxComponent
, uno::UNO_QUERY_THROW
)->getCurrentController(),
474 uno::Reference
<datatransfer::XTransferableTextSupplier
> const xTTS(xTS
, uno::UNO_QUERY
);
475 uno::Reference
<datatransfer::XTransferable
> const xTransferable(
476 xTTS
->getTransferableForTextRange(xAnchor
));
478 // check this doesn't throw
479 CPPUNIT_ASSERT(xAnchor
->getText().is());
480 CPPUNIT_ASSERT(xAnchor
->getStart().is());
481 CPPUNIT_ASSERT(xAnchor
->getEnd().is());
483 // replace section content
484 xAnchor
->setString(u
"quux"_ustr
);
486 // table in section was deleted, but not section itself
487 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xTables
->getCount());
488 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xSections
->getCount());
489 CPPUNIT_ASSERT_EQUAL(u
"\""
490 "quux" /*SAL_NEWLINE_STRING*/ "\""_ustr
,
491 OUString("\"" + xAnchor
->getString() + "\""));
494 uno::Reference
<text::XTextViewCursorSupplier
> const xTVCS(xTS
, uno::UNO_QUERY
);
495 uno::Reference
<text::XTextViewCursor
> const xCursor(xTVCS
->getViewCursor());
496 xCursor
->gotoEnd(false);
497 xTS
->insertTransferable(xTransferable
);
499 // table in section was pasted, but not section itself
500 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables
->getCount());
501 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xSections
->getCount());
502 // note: this selects the 2nd section because it calls StartOfSection()
503 // not SttEndDoc() like it should?
504 xCursor
->gotoStart(true);
505 CPPUNIT_ASSERT_EQUAL(u
"foobar" SAL_NEWLINE_STRING
"baz" SAL_NEWLINE_STRING
""_ustr
,
506 xCursor
->getString());
509 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testSectionAnchorCopyTable
)
511 // this contains a section that ends with a table (plus another section)
512 createSwDoc("tdf134252_onlytable_protected.fodt");
514 uno::Reference
<text::XTextTablesSupplier
> const xTextTablesSupplier(mxComponent
,
516 uno::Reference
<container::XIndexAccess
> const xTables(xTextTablesSupplier
->getTextTables(),
518 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables
->getCount());
520 uno::Reference
<text::XTextSectionsSupplier
> const xTextSectionsSupplier(mxComponent
,
522 uno::Reference
<container::XIndexAccess
> const xSections(
523 xTextSectionsSupplier
->getTextSections(), uno::UNO_QUERY
);
525 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections
->getCount());
527 uno::Reference
<text::XTextContent
> const xSection(xSections
->getByIndex(0), uno::UNO_QUERY
);
528 uno::Reference
<text::XTextRange
> const xAnchor(xSection
->getAnchor());
529 CPPUNIT_ASSERT_EQUAL(u
"baz" SAL_NEWLINE_STRING
""_ustr
, xAnchor
->getString());
531 // copy the content of the section to a clipboard document
532 uno::Reference
<datatransfer::XTransferableSupplier
> const xTS(
533 uno::Reference
<frame::XModel
>(mxComponent
, uno::UNO_QUERY_THROW
)->getCurrentController(),
535 uno::Reference
<datatransfer::XTransferableTextSupplier
> const xTTS(xTS
, uno::UNO_QUERY
);
536 uno::Reference
<datatransfer::XTransferable
> const xTransferable(
537 xTTS
->getTransferableForTextRange(xAnchor
));
539 // check this doesn't throw
540 CPPUNIT_ASSERT(xAnchor
->getText().is());
541 CPPUNIT_ASSERT(xAnchor
->getStart().is());
542 CPPUNIT_ASSERT(xAnchor
->getEnd().is());
544 // replace section content
545 xAnchor
->setString(u
"quux"_ustr
);
547 // table in section was deleted, but not section itself
548 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xTables
->getCount());
549 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections
->getCount());
550 CPPUNIT_ASSERT_EQUAL(u
"\""
551 "quux" /*SAL_NEWLINE_STRING*/ "\""_ustr
,
552 OUString("\"" + xAnchor
->getString() + "\""));
555 uno::Reference
<text::XTextViewCursorSupplier
> const xTVCS(xTS
, uno::UNO_QUERY
);
556 uno::Reference
<text::XTextViewCursor
> const xCursor(xTVCS
->getViewCursor());
557 xCursor
->gotoEnd(false);
558 xTS
->insertTransferable(xTransferable
);
560 // table in section was pasted, but not section itself
561 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables
->getCount());
562 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections
->getCount());
563 xCursor
->gotoStart(true);
564 CPPUNIT_ASSERT_EQUAL(u
"quux" SAL_NEWLINE_STRING
"foo" SAL_NEWLINE_STRING
565 "baz" SAL_NEWLINE_STRING
""_ustr
,
566 xCursor
->getString());
569 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testSectionAnchorProperties
)
571 createSwDoc("section-table.fodt");
573 uno::Reference
<text::XTextSectionsSupplier
> const xTextSectionsSupplier(mxComponent
,
575 uno::Reference
<container::XIndexAccess
> const xSections(
576 xTextSectionsSupplier
->getTextSections(), uno::UNO_QUERY
);
577 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections
->getCount());
579 uno::Reference
<text::XTextContent
> const xSection(xSections
->getByIndex(0), uno::UNO_QUERY
);
580 uno::Reference
<text::XTextRange
> const xAnchor(xSection
->getAnchor());
581 uno::Reference
<beans::XPropertySet
> const xAnchorProp(xAnchor
, uno::UNO_QUERY
);
583 // the problem was that the property set didn't work
584 auto xSecFromProp
= getProperty
<uno::Reference
<text::XTextContent
>>(xAnchorProp
, "TextSection");
585 CPPUNIT_ASSERT_EQUAL(xSection
, xSecFromProp
);
587 xAnchorProp
->setPropertyValue("CharHeight", uno::Any(float(64)));
588 CPPUNIT_ASSERT_EQUAL(float(64), getProperty
<float>(xAnchorProp
, "CharHeight"));
589 uno::Reference
<beans::XPropertyState
> const xAnchorState(xAnchor
, uno::UNO_QUERY
);
590 // TODO: why does this return DEFAULT_VALUE instead of DIRECT_VALUE?
591 CPPUNIT_ASSERT_EQUAL(beans::PropertyState_DEFAULT_VALUE
,
592 xAnchorState
->getPropertyState("CharHeight"));
593 CPPUNIT_ASSERT_EQUAL(beans::PropertyState_DEFAULT_VALUE
,
594 xAnchorState
->getPropertyStates({ "CharHeight" })[0]);
595 CPPUNIT_ASSERT_EQUAL(float(12), xAnchorState
->getPropertyDefault("CharHeight").get
<float>());
596 xAnchorState
->setPropertyToDefault("CharHeight");
597 CPPUNIT_ASSERT_EQUAL(float(12), getProperty
<float>(xAnchorProp
, "CharHeight"));
600 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testTextRangeInTable
)
602 createSwDoc("bookmarkintable.fodt");
604 uno::Reference
<text::XBookmarksSupplier
> const xBS(mxComponent
, uno::UNO_QUERY
);
605 uno::Reference
<container::XNameAccess
> const xMarks(xBS
->getBookmarks());
606 uno::Reference
<text::XTextContent
> const xMark(xMarks
->getByName(u
"Bookmark 1"_ustr
),
608 uno::Reference
<container::XEnumerationAccess
> const xAnchor(xMark
->getAnchor(), uno::UNO_QUERY
);
609 uno::Reference
<container::XEnumeration
> const xEnum(xAnchor
->createEnumeration());
610 uno::Reference
<lang::XServiceInfo
> const xPara(xEnum
->nextElement(), uno::UNO_QUERY
);
611 // not the top-level table!
612 CPPUNIT_ASSERT(!xPara
->supportsService(u
"com.sun.star.text.TextTable"_ustr
));
613 CPPUNIT_ASSERT(!xEnum
->hasMoreElements());
614 uno::Reference
<container::XEnumerationAccess
> const xParaEA(xPara
, uno::UNO_QUERY
);
615 uno::Reference
<container::XEnumeration
> const xPortions(xParaEA
->createEnumeration());
616 uno::Reference
<beans::XPropertySet
> const xP1(xPortions
->nextElement(), uno::UNO_QUERY
);
617 CPPUNIT_ASSERT_EQUAL(u
"Bookmark"_ustr
, getProperty
<OUString
>(xP1
, u
"TextPortionType"_ustr
));
618 uno::Reference
<beans::XPropertySet
> const xP2(xPortions
->nextElement(), uno::UNO_QUERY
);
619 CPPUNIT_ASSERT_EQUAL(u
"Text"_ustr
, getProperty
<OUString
>(xP2
, u
"TextPortionType"_ustr
));
620 uno::Reference
<text::XTextRange
> const xP2R(xP2
, uno::UNO_QUERY
);
621 CPPUNIT_ASSERT_EQUAL(u
"foo"_ustr
, xP2R
->getString());
622 uno::Reference
<beans::XPropertySet
> const xP3(xPortions
->nextElement(), uno::UNO_QUERY
);
623 CPPUNIT_ASSERT_EQUAL(u
"Bookmark"_ustr
, getProperty
<OUString
>(xP3
, u
"TextPortionType"_ustr
));
624 CPPUNIT_ASSERT(!xPortions
->hasMoreElements());
627 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testXURI
)
629 uno::Reference
<uno::XComponentContext
> xContext(::comphelper::getProcessComponentContext());
632 uno::Reference
<rdf::XURI
> xURIcreateKnown(
633 rdf::URI::createKnown(xContext
, rdf::URIs::ODF_PREFIX
), uno::UNO_SET_THROW
);
634 CPPUNIT_ASSERT(xURIcreateKnown
.is());
635 CPPUNIT_ASSERT_EQUAL(u
"http://docs.oasis-open.org/ns/office/1.2/meta/odf#"_ustr
,
636 xURIcreateKnown
->getNamespace());
637 CPPUNIT_ASSERT_EQUAL(u
"prefix"_ustr
, xURIcreateKnown
->getLocalName());
638 CPPUNIT_ASSERT_EQUAL(u
"http://docs.oasis-open.org/ns/office/1.2/meta/odf#prefix"_ustr
,
639 xURIcreateKnown
->getStringValue());
641 // createKnown() with invalid constant
642 CPPUNIT_ASSERT_THROW_MESSAGE("We expect an exception on invalid constant",
643 rdf::URI::createKnown(xContext
, 12345),
644 lang::IllegalArgumentException
);
647 uno::Reference
<rdf::XURI
> xURIcreate(
648 rdf::URI::create(xContext
, u
"http://example.com/url#somedata"_ustr
), uno::UNO_SET_THROW
);
649 CPPUNIT_ASSERT_EQUAL(u
"http://example.com/url#"_ustr
, xURIcreate
->getNamespace());
650 CPPUNIT_ASSERT_EQUAL(u
"somedata"_ustr
, xURIcreate
->getLocalName());
651 CPPUNIT_ASSERT_EQUAL(u
"http://example.com/url#somedata"_ustr
, xURIcreate
->getStringValue());
653 // create() without local name split with "/"
654 uno::Reference
<rdf::XURI
> xURIcreate2(
655 rdf::URI::create(xContext
, u
"http://example.com/url"_ustr
), uno::UNO_SET_THROW
);
656 CPPUNIT_ASSERT_EQUAL(u
"http://example.com/"_ustr
, xURIcreate2
->getNamespace());
657 CPPUNIT_ASSERT_EQUAL(u
"url"_ustr
, xURIcreate2
->getLocalName());
658 CPPUNIT_ASSERT_EQUAL(u
"http://example.com/url"_ustr
, xURIcreate2
->getStringValue());
660 // create() without prefix
661 uno::Reference
<rdf::XURI
> xURIcreate3(rdf::URI::create(xContext
, u
"#somedata"_ustr
),
663 CPPUNIT_ASSERT_EQUAL(u
"#"_ustr
, xURIcreate3
->getNamespace());
664 CPPUNIT_ASSERT_EQUAL(u
"somedata"_ustr
, xURIcreate3
->getLocalName());
665 CPPUNIT_ASSERT_EQUAL(u
"#somedata"_ustr
, xURIcreate3
->getStringValue());
667 // create() with invalid URI
668 CPPUNIT_ASSERT_THROW_MESSAGE("We expect an exception on invalid URI",
669 rdf::URI::create(xContext
, u
"some junk and not URI"_ustr
),
670 lang::IllegalArgumentException
);
673 uno::Reference
<rdf::XURI
> xURIcreateNS(
674 rdf::URI::createNS(xContext
, u
"http://example.com/url#"_ustr
, u
"somedata"_ustr
),
676 CPPUNIT_ASSERT_EQUAL(u
"http://example.com/url#"_ustr
, xURIcreateNS
->getNamespace());
677 CPPUNIT_ASSERT_EQUAL(u
"somedata"_ustr
, xURIcreateNS
->getLocalName());
678 CPPUNIT_ASSERT_EQUAL(u
"http://example.com/url#somedata"_ustr
, xURIcreateNS
->getStringValue());
680 // TODO: What's going on here? Is such usecase valid?
681 uno::Reference
<rdf::XURI
> xURIcreateNS2(
682 rdf::URI::createNS(xContext
, u
"http://example.com/url"_ustr
, u
"somedata"_ustr
),
684 CPPUNIT_ASSERT_EQUAL(u
"http://example.com/"_ustr
, xURIcreateNS2
->getNamespace());
685 CPPUNIT_ASSERT_EQUAL(u
"urlsomedata"_ustr
, xURIcreateNS2
->getLocalName());
686 CPPUNIT_ASSERT_EQUAL(u
"http://example.com/urlsomedata"_ustr
, xURIcreateNS2
->getStringValue());
688 // createNS() some invalid cases
689 CPPUNIT_ASSERT_THROW_MESSAGE("We expect an exception on invalid URI",
690 rdf::URI::createNS(xContext
, u
"bla"_ustr
, u
"bla"_ustr
),
691 lang::IllegalArgumentException
);
693 CPPUNIT_ASSERT_THROW_MESSAGE("We expect an exception on invalid URI",
694 rdf::URI::createNS(xContext
, OUString(), OUString()),
695 lang::IllegalArgumentException
);
698 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testSetPagePrintSettings
)
700 // Create an empty new document with a single char
703 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
704 uno::Reference
<text::XSimpleText
> xBodyText
= xTextDocument
->getText();
705 xBodyText
->insertString(xBodyText
->getStart(), u
"x"_ustr
, false);
707 uno::Reference
<text::XPagePrintable
> xPagePrintable(mxComponent
, uno::UNO_QUERY
);
709 // set some stuff, try to get it back
710 uno::Sequence
<beans::PropertyValue
> aProps
{
711 comphelper::makePropertyValue(u
"PageColumns"_ustr
, sal_Int16(2)),
712 comphelper::makePropertyValue(u
"IsLandscape"_ustr
, true)
715 xPagePrintable
->setPagePrintSettings(aProps
);
716 const comphelper::SequenceAsHashMap
aMap(xPagePrintable
->getPagePrintSettings());
718 CPPUNIT_ASSERT_EQUAL(sal_Int16(2), aMap
.getValue(u
"PageColumns"_ustr
).get
<short>());
719 CPPUNIT_ASSERT_EQUAL(true, aMap
.getValue(u
"IsLandscape"_ustr
).get
<bool>());
722 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testDeleteFlyAtCharAtStart
)
725 SwWrtShell
* const pWrtShell(getSwDocShell()->GetWrtShell());
726 SwDoc
* const pDoc(pWrtShell
->GetDoc());
729 IDocumentContentOperations
& rIDCO(pDoc
->getIDocumentContentOperations());
730 rIDCO
.InsertString(*pWrtShell
->GetCursor(), u
"foo bar baz"_ustr
);
732 // insert fly anchored at start of body text
733 pWrtShell
->ClearMark();
734 pWrtShell
->SttEndDoc(true);
735 SfxItemSet
frameSet(pDoc
->GetAttrPool(), svl::Items
<RES_FRMATR_BEGIN
, RES_FRMATR_END
- 1>);
736 SfxItemSet
grfSet(pDoc
->GetAttrPool(), svl::Items
<RES_GRFATR_BEGIN
, RES_GRFATR_END
- 1>);
737 SwFormatAnchor
anchor(RndStdIds::FLY_AT_CHAR
);
738 frameSet
.Put(anchor
);
740 CPPUNIT_ASSERT(rIDCO
.InsertGraphic(*pWrtShell
->GetCursor(), OUString(), OUString(), &grf
,
741 &frameSet
, &grfSet
, nullptr));
744 CPPUNIT_ASSERT_EQUAL(1, getShapes());
745 uno::Reference
<text::XTextContent
> const xShape(getShape(1), uno::UNO_QUERY
);
746 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
747 // anchored at start of body text?
748 uno::Reference
<text::XText
> const xText(xTextDocument
->getText());
749 uno::Reference
<text::XTextRangeCompare
> const xTextRC(xText
, uno::UNO_QUERY
);
750 CPPUNIT_ASSERT_EQUAL(sal_Int16(0),
751 xTextRC
->compareRegionStarts(xText
->getStart(), xShape
->getAnchor()));
753 // delete 1st character
754 uno::Reference
<text::XTextCursor
> const xCursor(xText
->createTextCursor());
755 xCursor
->goRight(1, true);
756 xCursor
->setString(u
""_ustr
);
758 // there is exactly one fly
759 CPPUNIT_ASSERT_EQUAL(1, getShapes());
761 // select entire body text
762 xCursor
->gotoStart(true);
763 xCursor
->gotoEnd(true);
764 xCursor
->setString(u
""_ustr
);
767 CPPUNIT_ASSERT_EQUAL(0, getShapes());
770 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testSelectionInTableEnum
)
772 createSwDoc("selection-in-table-enum.odt");
773 // Select the A1 cell's text.
774 SwWrtShell
* pWrtShell
= getSwDocShell()->GetWrtShell();
775 CPPUNIT_ASSERT(pWrtShell
);
776 pWrtShell
->Down(/*bSelect=*/false);
777 pWrtShell
->EndPara(/*bSelect=*/true);
778 CPPUNIT_ASSERT_EQUAL(u
"A1"_ustr
,
779 pWrtShell
->GetCursor()->GetPointNode().GetTextNode()->GetText());
781 // Access the selection.
782 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
783 CPPUNIT_ASSERT(xModel
.is());
784 uno::Reference
<container::XIndexAccess
> xSelections(xModel
->getCurrentSelection(),
786 CPPUNIT_ASSERT(xSelections
.is());
787 uno::Reference
<text::XTextRange
> xSelection(xSelections
->getByIndex(0), uno::UNO_QUERY
);
788 CPPUNIT_ASSERT(xSelection
.is());
790 // Enumerate paragraphs in the selection.
791 uno::Reference
<container::XEnumerationAccess
> xCursor(
792 xSelection
->getText()->createTextCursorByRange(xSelection
), uno::UNO_QUERY
);
793 CPPUNIT_ASSERT(xCursor
.is());
794 uno::Reference
<container::XEnumeration
> xEnum
= xCursor
->createEnumeration();
795 xEnum
->nextElement();
796 // Without the accompanying fix in place, this test would have failed: i.e.
797 // the enumeration contained a second paragraph, even if the cell has only
799 CPPUNIT_ASSERT(!xEnum
->hasMoreElements());
802 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testSelectionInTableEnumEnd
)
804 createSwDoc("selection-in-table-enum.odt");
805 // Select from "Before" till the table end.
806 SwWrtShell
* pWrtShell
= getSwDocShell()->GetWrtShell();
807 CPPUNIT_ASSERT(pWrtShell
);
808 pWrtShell
->Down(/*bSelect=*/true);
810 // Access the selection.
811 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
812 CPPUNIT_ASSERT(xModel
.is());
813 uno::Reference
<container::XIndexAccess
> xSelections(xModel
->getCurrentSelection(),
815 CPPUNIT_ASSERT(xSelections
.is());
816 uno::Reference
<text::XTextRange
> xSelection(xSelections
->getByIndex(0), uno::UNO_QUERY
);
817 CPPUNIT_ASSERT(xSelection
.is());
818 CPPUNIT_ASSERT_EQUAL(u
"Before" SAL_NEWLINE_STRING
"A1" SAL_NEWLINE_STRING
819 "B1" SAL_NEWLINE_STRING
"C2" SAL_NEWLINE_STRING
"A2" SAL_NEWLINE_STRING
820 "B2" SAL_NEWLINE_STRING
"C2" SAL_NEWLINE_STRING
""_ustr
,
821 xSelection
->getString());
823 // Enumerate paragraphs in the selection.
824 uno::Reference
<container::XEnumerationAccess
> xCursor(
825 xSelection
->getText()->createTextCursorByRange(xSelection
), uno::UNO_QUERY
);
826 CPPUNIT_ASSERT(xCursor
.is());
827 uno::Reference
<container::XEnumeration
> xEnum
= xCursor
->createEnumeration();
829 xEnum
->nextElement();
831 xEnum
->nextElement();
832 // Without the accompanying fix in place, this test would have failed: i.e.
833 // the enumeration contained the paragraph after the table, but no part of
834 // that paragraph was part of the selection.
835 CPPUNIT_ASSERT(!xEnum
->hasMoreElements());
838 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testTdf62603
)
840 // Unit test for tdf#62603
841 // Test to see if font style is retained when performing find/replace on strings
842 // containing mixed font styles/sizes
844 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
845 uno::Reference
<text::XText
> xText
= xTextDocument
->getText();
846 uno::Reference
<text::XTextCursor
> xCursor
= xText
->createTextCursor();
847 uno::Reference
<beans::XPropertySet
> xCursorProps(xCursor
, uno::UNO_QUERY
);
849 // Set up test by inserting strings with different font style/sizes
850 // Inserts 1st string containing quotation marks (") with no font style
851 xText
->insertString(xCursor
, "\"", false);
852 xCursor
->gotoStart(true); // selects full string
853 CPPUNIT_ASSERT_EQUAL(OUString("\""), xCursor
->getString());
854 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE
,
855 getProperty
<awt::FontSlant
>(xCursorProps
, "CharPosture"));
856 xCursor
->collapseToEnd();
858 // Inserts 2nd string 'test' with italic font style
859 xCursorProps
->setPropertyValue("CharPosture", uno::Any(awt::FontSlant_ITALIC
));
860 xText
->insertString(xCursor
, "test", false);
861 xCursor
->goLeft(4, true); // selects 2nd string
862 CPPUNIT_ASSERT_EQUAL(OUString("test"), xCursor
->getString());
863 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC
,
864 getProperty
<awt::FontSlant
>(xCursorProps
, "CharPosture"));
865 xCursor
->collapseToEnd();
867 // Insert 3rd string '? ' with 28 pt font height
868 xCursorProps
->setPropertyValue("CharPosture", uno::Any(awt::FontSlant_NONE
)); // no font style
869 xCursorProps
->setPropertyValue("CharHeight", uno::Any(float(28.0)));
870 xText
->insertString(xCursor
, "? ", false);
871 xCursor
->goLeft(2, true); // selects 3rd string
872 CPPUNIT_ASSERT_EQUAL(float(28.0), getProperty
<float>(xCursorProps
, "CharHeight"));
873 xCursor
->collapseToEnd();
875 // Insert 4th string 'who' with default 12 pt font height
876 xCursorProps
->setPropertyValue("CharHeight", uno::Any(float(12.0)));
877 xText
->insertString(xCursor
, "who", false);
878 xCursor
->goLeft(3, true); // selects 4rd string
879 CPPUNIT_ASSERT_EQUAL(float(12.0), getProperty
<float>(xCursorProps
, "CharHeight"));
880 xCursor
->collapseToEnd();
882 // Asserts that full string is properly inserted as: '"test? who'
883 CPPUNIT_ASSERT_EQUAL(1, getParagraphs());
884 CPPUNIT_ASSERT_EQUAL(OUString("\"test? who"), getParagraph(1)->getString());
886 uno::Reference
<util::XReplaceable
> xReplace(mxComponent
, uno::UNO_QUERY
);
887 uno::Reference
<util::XReplaceDescriptor
> xReplaceDesc(xReplace
->createReplaceDescriptor());
889 // Searches for "t and replaces with "gu
890 // Note: Search string contains both no font style and italic font style
891 xReplaceDesc
->setSearchString("\"t");
892 xReplaceDesc
->setReplaceString("\"gu");
893 xReplace
->replaceAll(xReplaceDesc
);
895 // Search/replace adds extra space between ? and w
896 // Note: Search string contains both 28 pt and 12 pt font sizes
897 xReplaceDesc
->setSearchString("? w");
898 xReplaceDesc
->setReplaceString("? w");
899 xReplace
->replaceAll(xReplaceDesc
);
901 // Asserts that '"test? who' is replaced with '"guest? who'
902 CPPUNIT_ASSERT_EQUAL(OUString("\"guest? who"), getParagraph(1)->getString());
904 // Asserts no font style is on double quote mark (")
905 CPPUNIT_ASSERT_EQUAL(
907 getProperty
<awt::FontSlant
>(getRun(getParagraph(1), 1, u
"\""_ustr
), "CharPosture"));
909 // Asserts font style for 'guest' is italic
910 // Without the test, 'g' and 'u' in 'guest' will change to no font style
911 // - Expected: 2 // ITALIC
912 // - Actual: 0 // NONE
913 CPPUNIT_ASSERT_EQUAL(
914 awt::FontSlant_ITALIC
,
915 getProperty
<awt::FontSlant
>(getRun(getParagraph(1), 2, u
"guest"_ustr
), "CharPosture"));
917 // Asserts font size is 28 pt
918 CPPUNIT_ASSERT_EQUAL(float(28.0),
919 getProperty
<float>(getRun(getParagraph(1), 3, u
"? "_ustr
), "CharHeight"));
921 // Asserts font size is 12 pt
922 // Without the test, the space ' ' and 'w' will change to 28 pt font size
925 CPPUNIT_ASSERT_EQUAL(
926 float(12.0), getProperty
<float>(getRun(getParagraph(1), 4, u
" who"_ustr
), "CharHeight"));
929 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testRenderablePagePosition
)
931 createSwDoc("renderable-page-position.odt");
932 // Make sure that the document has 2 pages.
934 uno::Any
aSelection(mxComponent
);
936 uno::Reference
<awt::XToolkit
> xToolkit
= VCLUnoHelper::CreateToolkit();
937 uno::Reference
<awt::XDevice
> xDevice(xToolkit
->createScreenCompatibleDevice(32, 32));
939 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
940 uno::Reference
<frame::XController
> xController
= xModel
->getCurrentController();
942 beans::PropertyValues aRenderOptions
= {
943 comphelper::makePropertyValue(u
"IsPrinter"_ustr
, true),
944 comphelper::makePropertyValue(u
"RenderDevice"_ustr
, xDevice
),
945 comphelper::makePropertyValue(u
"View"_ustr
, xController
),
946 comphelper::makePropertyValue(u
"RenderToGraphic"_ustr
, true),
949 uno::Reference
<view::XRenderable
> xRenderable(mxComponent
, uno::UNO_QUERY
);
950 sal_Int32 nPages
= xRenderable
->getRendererCount(aSelection
, aRenderOptions
);
951 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(2), nPages
);
953 // Make sure that the first page has some offset.
954 comphelper::SequenceAsHashMap
aRenderer1(
955 xRenderable
->getRenderer(0, aSelection
, aRenderOptions
));
956 // Without the accompanying fix in place, this test would have failed: i.e.
957 // there was no PagePos key in this map.
958 awt::Point aPosition1
= aRenderer1
[u
"PagePos"_ustr
].get
<awt::Point
>();
959 CPPUNIT_ASSERT_GREATER(static_cast<sal_Int32
>(0), aPosition1
.X
);
960 CPPUNIT_ASSERT_GREATER(static_cast<sal_Int32
>(0), aPosition1
.Y
);
962 // Make sure that the second page is below the first one.
963 comphelper::SequenceAsHashMap
aRenderer2(
964 xRenderable
->getRenderer(1, aSelection
, aRenderOptions
));
965 awt::Point aPosition2
= aRenderer2
[u
"PagePos"_ustr
].get
<awt::Point
>();
966 CPPUNIT_ASSERT_GREATER(static_cast<sal_Int32
>(0), aPosition2
.X
);
967 CPPUNIT_ASSERT_GREATER(aPosition1
.Y
, aPosition2
.Y
);
970 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testPasteListener
)
974 // Insert initial string.
975 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
976 uno::Reference
<text::XSimpleText
> xBodyText
= xTextDocument
->getText();
977 xBodyText
->insertString(xBodyText
->getStart(), u
"ABCDEF"_ustr
, false);
979 // Add paste listener.
980 uno::Reference
<text::XPasteBroadcaster
> xBroadcaster(mxComponent
, uno::UNO_QUERY
);
981 uno::Reference
<text::XPasteListener
> xListener(new PasteListener
);
982 auto pListener
= static_cast<PasteListener
*>(xListener
.get());
983 xBroadcaster
->addPasteEventListener(xListener
);
985 // Cut "DE" and then paste it.
986 SwWrtShell
* pWrtShell
= getSwDocShell()->GetWrtShell();
987 CPPUNIT_ASSERT(pWrtShell
);
988 pWrtShell
->Left(SwCursorSkipMode::Chars
, /*bSelect=*/false, 3, /*bBasicCall=*/false);
989 pWrtShell
->Right(SwCursorSkipMode::Chars
, /*bSelect=*/true, 2, /*bBasicCall=*/false);
990 rtl::Reference
<SwTransferable
> pTransfer
= new SwTransferable(*pWrtShell
);
992 TransferableDataHelper
aHelper(pTransfer
);
993 SwTransferable::Paste(*pWrtShell
, aHelper
);
994 // Without working listener registration in place, this test would have
995 // failed with 'Expected: DE; Actual:', i.e. the paste listener was not
997 CPPUNIT_ASSERT_EQUAL(u
"DE"_ustr
, pListener
->GetString());
999 // Make sure that paste did not overwrite anything.
1000 CPPUNIT_ASSERT_EQUAL(u
"ABCDEF"_ustr
, xBodyText
->getString());
1002 // Paste again, this time overwriting "BC".
1003 pWrtShell
->Left(SwCursorSkipMode::Chars
, /*bSelect=*/false, 4, /*bBasicCall=*/false);
1004 pWrtShell
->Right(SwCursorSkipMode::Chars
, /*bSelect=*/true, 2, /*bBasicCall=*/false);
1005 pListener
->GetString().clear();
1006 SwTransferable::Paste(*pWrtShell
, aHelper
);
1007 CPPUNIT_ASSERT_EQUAL(u
"DE"_ustr
, pListener
->GetString());
1009 // Make sure that paste overwrote "BC".
1010 CPPUNIT_ASSERT_EQUAL(u
"ADEDEF"_ustr
, xBodyText
->getString());
1012 // Test image paste.
1013 SwView
& rView
= pWrtShell
->GetView();
1014 rView
.InsertGraphic(createFileURL(u
"test.jpg"), OUString(), /*bAsLink=*/false,
1015 &GraphicFilter::GetGraphicFilter());
1017 // Test that the pasted image is anchored as-char.
1018 SwFlyFrame
* pFly
= pWrtShell
->GetSelectedFlyFrame();
1019 CPPUNIT_ASSERT(pFly
);
1020 SwFrameFormat
* pFlyFormat
= pFly
->GetFormat();
1021 CPPUNIT_ASSERT(pFlyFormat
);
1022 RndStdIds eFlyAnchor
= pFlyFormat
->GetAnchor().GetAnchorId();
1023 // Without the working image listener in place, this test would have
1024 // failed, eFlyAnchor was FLY_AT_PARA.
1025 CPPUNIT_ASSERT_EQUAL(RndStdIds::FLY_AT_CHAR
, eFlyAnchor
);
1028 pListener
->GetString().clear();
1029 SwTransferable::Paste(*pWrtShell
, aHelper
);
1030 // Without the working image listener in place, this test would have
1031 // failed, the listener was not invoked in case of a graphic paste.
1032 CPPUNIT_ASSERT(pListener
->GetTextGraphicObject().is());
1033 CPPUNIT_ASSERT(pListener
->GetString().isEmpty());
1035 // Deregister paste listener, make sure it's not invoked.
1036 xBroadcaster
->removePasteEventListener(xListener
);
1037 pListener
->GetString().clear();
1038 SwTransferable::Paste(*pWrtShell
, aHelper
);
1039 CPPUNIT_ASSERT(pListener
->GetString().isEmpty());
1042 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testImageCommentAtChar
)
1044 // Load a document with an at-char image in it (and a comment on the image).
1045 createSwDoc("image-comment-at-char.odt");
1046 SwDoc
* pDoc
= getSwDoc();
1048 // Verify that we have an annotation mark (comment with a text range) in the document.
1049 // Without the accompanying fix in place, this test would have failed, as comments lost their
1050 // ranges on load when their range only covered the placeholder character of the comment (which
1051 // is also the anchor position of the image).
1052 IDocumentMarkAccess
* pMarks
= pDoc
->getIDocumentMarkAccess();
1053 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), pMarks
->getAnnotationMarksCount());
1055 uno::Reference
<text::XTextRange
> xPara
= getParagraph(1);
1056 CPPUNIT_ASSERT_EQUAL(u
"Text"_ustr
,
1057 getProperty
<OUString
>(getRun(xPara
, 1), u
"TextPortionType"_ustr
));
1058 // Without the accompanying fix in place, this test would have failed with 'Expected:
1059 // Annotation; Actual: Frame', i.e. the comment-start portion was after the commented image.
1060 CPPUNIT_ASSERT_EQUAL(u
"Annotation"_ustr
,
1061 getProperty
<OUString
>(getRun(xPara
, 2), u
"TextPortionType"_ustr
));
1062 CPPUNIT_ASSERT_EQUAL(u
"Frame"_ustr
,
1063 getProperty
<OUString
>(getRun(xPara
, 3), u
"TextPortionType"_ustr
));
1064 CPPUNIT_ASSERT_EQUAL(u
"AnnotationEnd"_ustr
,
1065 getProperty
<OUString
>(getRun(xPara
, 4), u
"TextPortionType"_ustr
));
1066 CPPUNIT_ASSERT_EQUAL(u
"Text"_ustr
,
1067 getProperty
<OUString
>(getRun(xPara
, 5), u
"TextPortionType"_ustr
));
1069 // Without the accompanying fix in place, this test would have failed with 'Expected:
1070 // 5892; Actual: 1738', i.e. the anchor pos was between the "aaa" and "bbb" portions, not at the
1071 // center of the page (horizontally) where the image is. On macOS, though, with the fix in
1072 // place the actual value consistently is even greater with 6283 now instead of 5892, for
1074 SwView
* pView
= getSwDocShell()->GetView();
1075 SwPostItMgr
* pPostItMgr
= pView
->GetPostItMgr();
1076 for (const auto& pItem
: *pPostItMgr
)
1078 const SwRect
& rAnchor
= pItem
->mpPostIt
->GetAnchorRect();
1079 CPPUNIT_ASSERT_GREATEREQUAL(static_cast<tools::Long
>(5892), rAnchor
.Left());
1083 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testChapterNumberingCharStyle
)
1087 uno::Reference
<lang::XMultiServiceFactory
> xDoc(mxComponent
, uno::UNO_QUERY
);
1088 uno::Reference
<beans::XPropertySet
> xStyle(
1089 xDoc
->createInstance(u
"com.sun.star.style.CharacterStyle"_ustr
), uno::UNO_QUERY
);
1090 uno::Reference
<container::XNamed
> xStyleN(xStyle
, uno::UNO_QUERY
);
1091 xStyle
->setPropertyValue(u
"CharColor"_ustr
, uno::Any(COL_LIGHTRED
));
1092 uno::Reference
<style::XStyleFamiliesSupplier
> xSFS(mxComponent
, uno::UNO_QUERY
);
1093 uno::Reference
<container::XNameContainer
> xStyles(
1094 xSFS
->getStyleFamilies()->getByName(u
"CharacterStyles"_ustr
), uno::UNO_QUERY
);
1095 xStyles
->insertByName(u
"red"_ustr
, uno::Any(xStyle
));
1097 uno::Reference
<text::XChapterNumberingSupplier
> xCNS(mxComponent
, uno::UNO_QUERY
);
1098 uno::Reference
<container::XIndexReplace
> xOutline(xCNS
->getChapterNumberingRules());
1100 comphelper::SequenceAsHashMap
hashMap(xOutline
->getByIndex(0));
1101 hashMap
[u
"CharStyleName"_ustr
] <<= u
"red"_ustr
;
1102 uno::Sequence
<beans::PropertyValue
> props
;
1104 xOutline
->replaceByIndex(0, uno::Any(props
));
1106 // now rename the style
1107 xStyleN
->setName(u
"reddishred"_ustr
);
1109 comphelper::SequenceAsHashMap
hashMap(xOutline
->getByIndex(0));
1111 // tdf#137810 this failed, was old value "red"
1112 CPPUNIT_ASSERT_EQUAL(u
"reddishred"_ustr
, hashMap
[u
"CharStyleName"_ustr
].get
<OUString
>());
1116 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testViewCursorPageStyle
)
1118 // Load a document with 2 pages, but a single paragraph.
1119 createSwDoc("view-cursor-page-style.fodt");
1120 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
1121 CPPUNIT_ASSERT(xModel
.is());
1122 uno::Reference
<text::XTextViewCursorSupplier
> xController(xModel
->getCurrentController(),
1124 CPPUNIT_ASSERT(xController
.is());
1125 uno::Reference
<text::XPageCursor
> xViewCursor(xController
->getViewCursor(), uno::UNO_QUERY
);
1126 CPPUNIT_ASSERT(xViewCursor
.is());
1128 // Go to the first page, which has an explicit page style.
1129 xViewCursor
->jumpToPage(1);
1130 OUString aActualPageStyleName
= getProperty
<OUString
>(xViewCursor
, u
"PageStyleName"_ustr
);
1131 CPPUNIT_ASSERT_EQUAL(u
"First Page"_ustr
, aActualPageStyleName
);
1133 // Go to the second page, which is still the first paragraph, but the page style is different,
1134 // as the explicit 'First Page' page style has a next style defined (Standard).
1135 xViewCursor
->jumpToPage(2);
1136 aActualPageStyleName
= getProperty
<OUString
>(xViewCursor
, u
"PageStyleName"_ustr
);
1137 // Without the accompanying fix in place, this test would have failed with:
1138 // - Expected: Standard
1139 // - Actual : First Page
1140 // i.e. the cursor position was determined only based on the node index, ignoring the content
1142 CPPUNIT_ASSERT_EQUAL(u
"Standard"_ustr
, aActualPageStyleName
);
1145 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testXTextCursor_setPropertyValues
)
1147 // Create a new document, type a character, pass a set of property/value pairs consisting of one
1148 // unknown property and CharStyleName, assert that it threw UnknownPropertyException (actually
1149 // wrapped into WrappedTargetException), and assert the style was set, not discarded.
1152 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
1153 uno::Reference
<text::XSimpleText
> xBodyText
= xTextDocument
->getText();
1154 xBodyText
->insertString(xBodyText
->getStart(), u
"x"_ustr
, false);
1156 uno::Reference
<text::XTextCursor
> xCursor(xBodyText
->createTextCursor());
1157 xCursor
->goLeft(1, true);
1159 uno::Reference
<beans::XMultiPropertySet
> xCursorProps(xCursor
, uno::UNO_QUERY
);
1160 uno::Sequence
<OUString
> aPropNames
= { u
"OneUnknownProperty"_ustr
, u
"CharStyleName"_ustr
};
1161 uno::Sequence
<uno::Any
> aPropValues
= { uno::Any(), uno::Any(u
"Emphasis"_ustr
) };
1162 CPPUNIT_ASSERT_THROW(xCursorProps
->setPropertyValues(aPropNames
, aPropValues
),
1163 lang::WrappedTargetException
);
1164 CPPUNIT_ASSERT_EQUAL(u
"Emphasis"_ustr
,
1165 getProperty
<OUString
>(xCursorProps
, u
"CharStyleName"_ustr
));
1168 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testShapeAllowOverlap
)
1170 // Test the AllowOverlap frame/shape property.
1172 // Create a new document and insert a rectangle.
1174 uno::Reference
<lang::XMultiServiceFactory
> xDocument(mxComponent
, uno::UNO_QUERY
);
1175 awt::Point
aPoint(1000, 1000);
1176 awt::Size
aSize(10000, 10000);
1177 uno::Reference
<drawing::XShape
> xShape(
1178 xDocument
->createInstance(u
"com.sun.star.drawing.RectangleShape"_ustr
), uno::UNO_QUERY
);
1179 xShape
->setPosition(aPoint
);
1180 xShape
->setSize(aSize
);
1181 uno::Reference
<drawing::XDrawPageSupplier
> xDrawPageSupplier(xDocument
, uno::UNO_QUERY
);
1182 xDrawPageSupplier
->getDrawPage()->add(xShape
);
1184 // The property is on by default, turn it off & verify.
1185 uno::Reference
<beans::XPropertySet
> xShapeProperties(xShape
, uno::UNO_QUERY
);
1186 xShapeProperties
->setPropertyValue(u
"AllowOverlap"_ustr
, uno::Any(false));
1187 CPPUNIT_ASSERT(!getProperty
<bool>(xShapeProperties
, u
"AllowOverlap"_ustr
));
1189 // Turn it back to on & verify.
1190 xShapeProperties
->setPropertyValue(u
"AllowOverlap"_ustr
, uno::Any(true));
1191 CPPUNIT_ASSERT(getProperty
<bool>(xShapeProperties
, u
"AllowOverlap"_ustr
));
1194 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testTextConvertToTableLineSpacing
)
1196 // Load a document which has a table with a single cell.
1197 // The cell has both a table style and a paragraph style, with different line spacing
1199 createSwDoc("table-line-spacing.docx");
1200 uno::Reference
<text::XTextTablesSupplier
> xTablesSupplier(mxComponent
, uno::UNO_QUERY
);
1201 uno::Reference
<container::XIndexAccess
> xTables(xTablesSupplier
->getTextTables(),
1203 uno::Reference
<text::XTextTable
> xTable(xTables
->getByIndex(0), uno::UNO_QUERY
);
1204 uno::Reference
<table::XCell
> xCell
= xTable
->getCellByName(u
"A1"_ustr
);
1205 uno::Reference
<text::XText
> xCellText(xCell
, uno::UNO_QUERY
);
1206 uno::Reference
<text::XTextRange
> xParagraph
= getParagraphOfText(1, xCellText
);
1207 style::LineSpacing aLineSpacing
1208 = getProperty
<style::LineSpacing
>(xParagraph
, u
"ParaLineSpacing"_ustr
);
1209 // Make sure that we take the line spacing from the paragraph style, not from the table style.
1210 // Without the accompanying fix in place, this test would have failed with:
1213 // I.e. the 360 twips line spacing was taken from the table style, not the 220 twips one from
1214 // the paragraph style.
1215 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16
>(convertTwipToMm100(220)), aLineSpacing
.Height
);
1218 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testMultiSelect
)
1220 // Create a new document and add a text with several repeated sequences.
1222 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, css::uno::UNO_QUERY_THROW
);
1223 auto xSimpleText
= xTextDocument
->getText();
1224 xSimpleText
->insertString(xSimpleText
->getStart(), u
"Abc aBc abC"_ustr
, false);
1226 // Create a search descriptor and find all occurrences of search string
1227 css::uno::Reference
<css::util::XSearchable
> xSearchable(mxComponent
, css::uno::UNO_QUERY_THROW
);
1228 auto xSearchDescriptor
= xSearchable
->createSearchDescriptor();
1229 xSearchDescriptor
->setPropertyValue(u
"SearchStyles"_ustr
, css::uno::Any(false));
1230 xSearchDescriptor
->setPropertyValue(u
"SearchCaseSensitive"_ustr
, css::uno::Any(false));
1231 xSearchDescriptor
->setPropertyValue(u
"SearchBackwards"_ustr
, css::uno::Any(true));
1232 xSearchDescriptor
->setPropertyValue(u
"SearchRegularExpression"_ustr
, css::uno::Any(false));
1233 xSearchDescriptor
->setSearchString(u
"abc"_ustr
);
1234 auto xSearchResult
= xSearchable
->findAll(xSearchDescriptor
);
1237 auto xController
= xTextDocument
->getCurrentController();
1238 css::uno::Reference
<css::view::XSelectionSupplier
> xSelectionSupplier(
1239 xController
, css::uno::UNO_QUERY_THROW
);
1240 xSelectionSupplier
->select(css::uno::Any(xSearchResult
));
1241 css::uno::Reference
<css::container::XIndexAccess
> xSelection(xSelectionSupplier
->getSelection(),
1242 css::uno::UNO_QUERY_THROW
);
1243 // Now check that they all are selected in the reverse order ("SearchBackwards").
1244 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xSelection
->getCount());
1245 css::uno::Reference
<css::text::XTextRange
> xTextRange(xSelection
->getByIndex(0),
1246 css::uno::UNO_QUERY_THROW
);
1247 // For #0, result was empty (cursor was put before the last occurrence without selection)
1248 CPPUNIT_ASSERT_EQUAL(u
"abC"_ustr
, xTextRange
->getString());
1249 xTextRange
.set(xSelection
->getByIndex(1), css::uno::UNO_QUERY_THROW
);
1250 CPPUNIT_ASSERT_EQUAL(u
"aBc"_ustr
, xTextRange
->getString());
1251 xTextRange
.set(xSelection
->getByIndex(2), css::uno::UNO_QUERY_THROW
);
1252 CPPUNIT_ASSERT_EQUAL(u
"Abc"_ustr
, xTextRange
->getString());
1255 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testTransparentText
)
1257 // Test the CharTransparence text portion property.
1259 // Create a new document.
1262 // Set a custom transparency.
1263 uno::Reference
<beans::XPropertySet
> xParagraph(getParagraph(1), uno::UNO_QUERY
);
1264 sal_Int16 nExpected
= 42;
1265 xParagraph
->setPropertyValue(u
"CharTransparence"_ustr
, uno::Any(nExpected
));
1267 // Get the transparency & verify.
1268 CPPUNIT_ASSERT_EQUAL(nExpected
, getProperty
<sal_Int16
>(xParagraph
, u
"CharTransparence"_ustr
));
1271 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testTdf129839
)
1273 // Create a new document and add a table
1275 css::uno::Reference
<css::text::XTextDocument
> xTextDocument(mxComponent
,
1276 css::uno::UNO_QUERY_THROW
);
1277 css::uno::Reference
<css::lang::XMultiServiceFactory
> xFac(xTextDocument
,
1278 css::uno::UNO_QUERY_THROW
);
1279 css::uno::Reference
<css::text::XTextTable
> xTable(
1280 xFac
->createInstance(u
"com.sun.star.text.TextTable"_ustr
), css::uno::UNO_QUERY_THROW
);
1281 xTable
->initialize(4, 4);
1282 auto xSimpleText
= xTextDocument
->getText();
1283 xSimpleText
->insertTextContent(xSimpleText
->createTextCursor(), xTable
, true);
1284 css::uno::Reference
<css::table::XCellRange
> xTableCellRange(xTable
, css::uno::UNO_QUERY_THROW
);
1285 // Get instance of SwXCellRange
1286 css::uno::Reference
<css::beans::XPropertySet
> xCellRange(
1287 xTableCellRange
->getCellRangeByPosition(0, 0, 1, 1), css::uno::UNO_QUERY_THROW
);
1288 // Test retrieval of VertOrient property - this crashed
1289 css::uno::Any aOrient
= xCellRange
->getPropertyValue(u
"VertOrient"_ustr
);
1290 CPPUNIT_ASSERT_EQUAL(css::uno::Any(css::text::VertOrientation::NONE
), aOrient
);
1293 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testTdf129841
)
1295 // Create a new document and add a table
1297 css::uno::Reference
<css::text::XTextDocument
> xTextDocument(mxComponent
,
1298 css::uno::UNO_QUERY_THROW
);
1299 css::uno::Reference
<css::lang::XMultiServiceFactory
> xFac(xTextDocument
,
1300 css::uno::UNO_QUERY_THROW
);
1301 css::uno::Reference
<css::text::XTextTable
> xTable(
1302 xFac
->createInstance(u
"com.sun.star.text.TextTable"_ustr
), css::uno::UNO_QUERY_THROW
);
1303 xTable
->initialize(4, 4);
1304 auto xSimpleText
= xTextDocument
->getText();
1305 xSimpleText
->insertTextContent(xSimpleText
->createTextCursor(), xTable
, true);
1306 // Get SwXTextTableCursor
1307 css::uno::Reference
<css::beans::XPropertySet
> xTableCursor(
1308 xTable
->createCursorByCellName(u
"A1"_ustr
), css::uno::UNO_QUERY_THROW
);
1309 css::uno::Reference
<css::table::XCellRange
> xTableCellRange(xTable
, css::uno::UNO_QUERY_THROW
);
1310 // Get SwXCellRange for the same cell
1311 css::uno::Reference
<css::beans::XPropertySet
> xCellRange(
1312 xTableCellRange
->getCellRangeByName(u
"A1:A1"_ustr
), css::uno::UNO_QUERY_THROW
);
1313 static constexpr OUString sBackColor
= u
"BackColor"_ustr
;
1314 // Apply background color to table cursor, and read background color from cell range
1315 css::uno::Any
aRefColor(COL_LIGHTRED
);
1316 xTableCursor
->setPropertyValue(sBackColor
, aRefColor
);
1317 css::uno::Any aColor
= xCellRange
->getPropertyValue(sBackColor
);
1319 CPPUNIT_ASSERT_EQUAL(aRefColor
, aColor
);
1320 // Now the other way round
1321 aRefColor
<<= COL_LIGHTGREEN
;
1322 xCellRange
->setPropertyValue(sBackColor
, aRefColor
);
1323 aColor
= xTableCursor
->getPropertyValue(sBackColor
);
1324 CPPUNIT_ASSERT_EQUAL(aRefColor
, aColor
);
1327 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testTdf141525
)
1329 // Unit test for tdf#141525:
1330 // Checks if "Line with Arrow/Circle" is inserted with correct end points
1333 // Insert "Line with Arrow/Circle" shape with CTRL key
1334 uno::Sequence
<beans::PropertyValue
> aArgs(
1335 comphelper::InitPropertySequence({ { "KeyModifier", uno::Any(KEY_MOD1
) } }));
1336 dispatchCommand(mxComponent
, u
".uno:LineArrowCircle"_ustr
, aArgs
);
1338 // Asserts line shape has been inserted into the doc
1339 CPPUNIT_ASSERT_EQUAL(1, getShapes());
1340 CPPUNIT_ASSERT_EQUAL(u
"com.sun.star.drawing.LineShape"_ustr
, getShape(1)->getShapeType());
1342 // Asserts end of line has a circle
1343 // Without the test, "Line Starts with Arrow" is inserted
1344 // i.e. the circle is missing from the line end point
1345 // - Expected: "Circle"
1347 CPPUNIT_ASSERT_EQUAL(u
"Circle"_ustr
, getProperty
<OUString
>(getShape(1), u
"LineEndName"_ustr
));
1348 // Asserts start of line has an arrow
1349 CPPUNIT_ASSERT_EQUAL(u
"Arrow"_ustr
, getProperty
<OUString
>(getShape(1), u
"LineStartName"_ustr
));
1352 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testTdf160278
)
1355 auto xTextDocument(mxComponent
.queryThrow
<css::text::XTextDocument
>());
1356 auto xText(xTextDocument
->getText());
1357 xText
->setString(u
"123"_ustr
);
1358 CPPUNIT_ASSERT_EQUAL(u
"123"_ustr
, xText
->getString());
1359 auto xCursor
= xText
->createTextCursorByRange(xText
->getEnd());
1360 xCursor
->goLeft(1, true);
1361 CPPUNIT_ASSERT_EQUAL(u
"3"_ustr
, xCursor
->getString());
1362 // Insert an SMP character U+1f702 (so it's two UTF-16 code units, 0xd83d 0xdf02):
1363 xCursor
->setString(u
"🜂"_ustr
);
1364 // Without the fix, the replacement would expand the cursor one too many characters to the left,
1365 // and the cursor text would become "2🜂", failing the next test:
1366 CPPUNIT_ASSERT_EQUAL(u
"🜂"_ustr
, xCursor
->getString());
1367 xCursor
->setString(u
"test"_ustr
);
1368 CPPUNIT_ASSERT_EQUAL(u
"test"_ustr
, xCursor
->getString());
1369 // This test would fail, too; the text would be "1test":
1370 CPPUNIT_ASSERT_EQUAL(u
"12test"_ustr
, xText
->getString());
1373 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testTdf161035
)
1375 // Given a paragraph with a bookmark:
1376 createSwDoc("tdf161035.fodt");
1377 auto xModel
= mxComponent
.queryThrow
<frame::XModel
>();
1379 // Create a text view cursor in the paragraph.
1380 auto xController
= xModel
->getCurrentController().queryThrow
<text::XTextViewCursorSupplier
>();
1381 auto xViewCursor
= xController
->getViewCursor();
1382 CPPUNIT_ASSERT(xViewCursor
);
1383 auto xText
= xViewCursor
->getText();
1384 CPPUNIT_ASSERT(xText
);
1385 // Create a text cursor from the text view cursor, and move it to the end of the paragraph
1386 auto xTextCursor
= xText
->createTextCursorByRange(xViewCursor
);
1387 CPPUNIT_ASSERT(xTextCursor
);
1388 xTextCursor
->gotoEnd(false);
1389 // Get the first paragraph portion from the text cursor
1390 auto xParaEnum
= xTextCursor
.queryThrow
<container::XEnumerationAccess
>()->createEnumeration();
1391 CPPUNIT_ASSERT(xParaEnum
);
1392 auto xPara
= xParaEnum
->nextElement().queryThrow
<container::XEnumerationAccess
>();
1393 // Try to enumerate text portions. Without the fix, it would fail an assertion in debug builds,
1394 // and hang in release builds, because the paragraph portion started after the bookmark, and
1395 // so the bookmark wasn't processed (expectedly):
1396 auto xRunEnum
= xPara
->createEnumeration();
1397 CPPUNIT_ASSERT(!xRunEnum
->hasMoreElements()); // Empty enumeration for empty selection
1400 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testTdf162480
)
1404 uno::Sequence
<beans::PropertyValue
> aPropertyValues
= comphelper::InitPropertySequence({
1405 { "Name", uno::Any(createFileURL(u
"textboxInColumn2.fodt")) },
1408 // Inserting a document with text box attached in a table's second column must not crash
1409 dispatchCommand(mxComponent
, u
".uno:InsertDoc"_ustr
, aPropertyValues
);
1411 auto xTextBox
= getShape(1).queryThrow
<css::text::XTextContent
>();
1412 auto xTable
= getParagraphOrTable(2).queryThrow
<css::text::XTextTable
>();
1413 auto xAnchorRange
= xTextBox
->getAnchor();
1414 auto xCellText
= xTable
->getCellByName("B1").queryThrow
<css::text::XText
>();
1415 CPPUNIT_ASSERT_EQUAL(xCellText
, xAnchorRange
->getText());
1418 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testTdf164885
)
1420 class LocalDispatch
: public comphelper::WeakImplHelper
<css::frame::XDispatch
>
1423 LocalDispatch() = default;
1425 void SAL_CALL
dispatch(const css::util::URL
& URL
,
1426 const css::uno::Sequence
<css::beans::PropertyValue
>&) override
1428 sLastCommand
= URL
.Complete
;
1430 void SAL_CALL
addStatusListener(const css::uno::Reference
<css::frame::XStatusListener
>&,
1431 const css::util::URL
&) override
1435 void SAL_CALL
removeStatusListener(const css::uno::Reference
<css::frame::XStatusListener
>&,
1436 const css::util::URL
&) override
1441 OUString sLastCommand
;
1444 class LocalInterceptor
1445 : public comphelper::WeakImplHelper
<css::frame::XDispatchProviderInterceptor
>
1448 LocalInterceptor() = default;
1450 // XDispatchProvider
1451 css::uno::Reference
<css::frame::XDispatch
>
1452 SAL_CALL
queryDispatch(const css::util::URL
& URL
, const OUString
& TargetFrameName
,
1453 sal_Int32 SearchFlags
) override
1455 if (URL
.Complete
== ".uno:Open")
1458 return m_slave
->queryDispatch(URL
, TargetFrameName
, SearchFlags
);
1461 css::uno::Sequence
<css::uno::Reference
<css::frame::XDispatch
>> SAL_CALL
1462 queryDispatches(const css::uno::Sequence
<css::frame::DispatchDescriptor
>&) override
1467 // XDispatchProviderInterceptor
1468 css::uno::Reference
<css::frame::XDispatchProvider
>
1469 SAL_CALL
getSlaveDispatchProvider() override
1473 void SAL_CALL
setSlaveDispatchProvider(
1474 const css::uno::Reference
<css::frame::XDispatchProvider
>& val
) override
1478 css::uno::Reference
<css::frame::XDispatchProvider
>
1479 SAL_CALL
getMasterDispatchProvider() override
1483 void SAL_CALL
setMasterDispatchProvider(
1484 const css::uno::Reference
<css::frame::XDispatchProvider
>& val
) override
1489 rtl::Reference
<LocalDispatch
> pDispatch
{ new LocalDispatch
};
1492 css::uno::Reference
<css::frame::XDispatchProvider
> m_master
;
1493 css::uno::Reference
<css::frame::XDispatchProvider
> m_slave
;
1496 // Given a document with a hyperlink
1497 createSwDoc("hyperlink.fodt");
1498 auto controller(mxComponent
.queryThrow
<frame::XModel
>()->getCurrentController());
1499 auto xProvider(controller
->getFrame().queryThrow
<css::frame::XDispatchProviderInterception
>());
1501 rtl::Reference
<LocalInterceptor
> interceptor(new LocalInterceptor
);
1502 xProvider
->registerDispatchProviderInterceptor(interceptor
);
1504 auto xCursor
= controller
.queryThrow
<text::XTextViewCursorSupplier
>()->getViewCursor();
1505 xCursor
->goRight(5, false); // put cursor inside the hyperlink
1507 // Initiate "open hyperlink"
1508 dispatchCommand(mxComponent
, u
".uno:OpenHyperlinkOnCursor"_ustr
, {});
1510 xProvider
->releaseDispatchProviderInterceptor(interceptor
);
1512 // Without the fix, this failed with
1513 // - Expected: .uno:Open
1515 // because the interception didn't happen
1516 CPPUNIT_ASSERT_EQUAL(u
".uno:Open"_ustr
, interceptor
->pDispatch
->sLastCommand
);
1519 } // end of anonymous namespace
1520 CPPUNIT_PLUGIN_IMPLEMENT();
1522 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */