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/table/XCellRange.hpp>
16 #include <com/sun/star/text/TextContentAnchorType.hpp>
17 #include <com/sun/star/text/AutoTextContainer.hpp>
18 #include <com/sun/star/text/VertOrientation.hpp>
19 #include <com/sun/star/text/XAutoTextGroup.hpp>
20 #include <com/sun/star/text/XTextPortionAppend.hpp>
21 #include <com/sun/star/text/XTextContentAppend.hpp>
22 #include <com/sun/star/text/XTextRangeCompare.hpp>
23 #include <com/sun/star/text/XPasteListener.hpp>
24 #include <com/sun/star/rdf/URI.hpp>
25 #include <com/sun/star/rdf/URIs.hpp>
26 #include <com/sun/star/awt/XDevice.hpp>
27 #include <com/sun/star/awt/XToolkit.hpp>
28 #include <com/sun/star/graphic/XGraphic.hpp>
29 #include <com/sun/star/style/LineSpacing.hpp>
30 #include <com/sun/star/view/XSelectionSupplier.hpp>
31 #include <com/sun/star/text/XTextDocument.hpp>
32 #include <com/sun/star/container/XNameContainer.hpp>
33 #include <com/sun/star/view/XRenderable.hpp>
34 #include <com/sun/star/text/XBookmarksSupplier.hpp>
35 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
36 #include <com/sun/star/text/XTextTable.hpp>
37 #include <com/sun/star/text/XPageCursor.hpp>
39 #include <comphelper/propertyvalue.hxx>
40 #include <tools/UnitConversion.hxx>
41 #include <toolkit/helper/vclunohelper.hxx>
42 #include <vcl/graphicfilter.hxx>
43 #include <comphelper/sequenceashashmap.hxx>
44 #include <comphelper/processfactory.hxx>
48 #include <swdtflvr.hxx>
50 #include <PostItMgr.hxx>
51 #include <postithelper.hxx>
52 #include <AnnotationWin.hxx>
54 #include <fmtanchr.hxx>
55 #include <unotxdoc.hxx>
58 using namespace ::com::sun::star
;
62 /// Listener implementation for testPasteListener.
63 class PasteListener
: public cppu::WeakImplHelper
<text::XPasteListener
>
66 uno::Reference
<text::XTextContent
> m_xTextGraphicObject
;
69 void SAL_CALL
notifyPasteEvent(const uno::Sequence
<beans::PropertyValue
>& rEvent
) override
;
71 OUString
& GetString();
72 uno::Reference
<text::XTextContent
>& GetTextGraphicObject();
75 void PasteListener::notifyPasteEvent(const uno::Sequence
<beans::PropertyValue
>& rEvent
)
77 comphelper::SequenceAsHashMap
aMap(rEvent
);
78 auto it
= aMap
.find("TextRange");
81 auto xTextRange
= it
->second
.get
<uno::Reference
<text::XTextRange
>>();
83 m_aString
= xTextRange
->getString();
87 it
= aMap
.find("TextGraphicObject");
90 auto xTextGraphicObject
= it
->second
.get
<uno::Reference
<text::XTextContent
>>();
91 if (xTextGraphicObject
.is())
92 m_xTextGraphicObject
= xTextGraphicObject
;
96 OUString
& PasteListener::GetString() { return m_aString
; }
98 uno::Reference
<text::XTextContent
>& PasteListener::GetTextGraphicObject()
100 return m_xTextGraphicObject
;
104 /// Test to assert UNO API call results of Writer.
105 class SwUnoWriter
: public SwModelTestBase
109 : SwModelTestBase("/sw/qa/extras/unowriter/data/", "writer8")
114 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testDefaultCharStyle
)
116 // Create a new document, type a character, set its char style to Emphasis
117 // and assert the style was set.
120 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
121 uno::Reference
<text::XSimpleText
> xBodyText
= xTextDocument
->getText();
122 xBodyText
->insertString(xBodyText
->getStart(), "x", false);
124 uno::Reference
<text::XTextCursor
> xCursor(xBodyText
->createTextCursor());
125 xCursor
->goLeft(1, true);
127 uno::Reference
<beans::XPropertySet
> xCursorProps(xCursor
, uno::UNO_QUERY
);
128 xCursorProps
->setPropertyValue("CharStyleName", uno::Any(OUString("Emphasis")));
129 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC
,
130 getProperty
<awt::FontSlant
>(xCursorProps
, "CharPosture"));
132 // Now reset the char style and assert that the font slant is back to none.
133 // This resulted in a lang.IllegalArgumentException, Standard was not
134 // mapped to 'Default Style'.
135 xCursorProps
->setPropertyValue("CharStyleName", uno::Any(OUString("Standard")));
136 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE
,
137 getProperty
<awt::FontSlant
>(xCursorProps
, "CharPosture"));
140 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testInsertStringExpandsHints
)
143 uno::Reference
<text::XTextDocument
> const xTextDocument(mxComponent
, uno::UNO_QUERY
);
144 uno::Reference
<text::XText
> const xText(xTextDocument
->getText());
145 uno::Reference
<text::XTextCursor
> const xCursor(xText
->createTextCursor());
146 uno::Reference
<beans::XPropertySet
> const xProps(xCursor
, uno::UNO_QUERY
);
148 xText
->insertString(xCursor
, "ab", false);
149 xCursor
->gotoStart(false);
150 xCursor
->goRight(1, true);
151 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE
, getProperty
<awt::FontSlant
>(xProps
, "CharPosture"));
152 xProps
->setPropertyValue("CharPosture", uno::Any(awt::FontSlant_ITALIC
));
153 xCursor
->collapseToEnd();
154 xText
->insertString(xCursor
, "x", false);
155 xCursor
->goLeft(1, true);
156 CPPUNIT_ASSERT_EQUAL(OUString("x"), xCursor
->getString());
157 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC
, getProperty
<awt::FontSlant
>(xProps
, "CharPosture"));
160 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testInsertTextPortionNotExpandsHints
)
163 uno::Reference
<text::XTextDocument
> const xTextDocument(mxComponent
, uno::UNO_QUERY
);
164 uno::Reference
<text::XText
> const xText(xTextDocument
->getText());
165 uno::Reference
<text::XTextPortionAppend
> const xTextA(xText
, uno::UNO_QUERY
);
166 uno::Reference
<text::XTextCursor
> const xCursor(xText
->createTextCursor());
167 uno::Reference
<beans::XPropertySet
> const xProps(xCursor
, uno::UNO_QUERY
);
169 xText
->insertString(xCursor
, "ab", false);
170 xCursor
->gotoStart(false);
171 xCursor
->goRight(1, true);
172 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE
, getProperty
<awt::FontSlant
>(xProps
, "CharPosture"));
173 xProps
->setPropertyValue("CharPosture", uno::Any(awt::FontSlant_ITALIC
));
174 xCursor
->collapseToEnd();
175 xTextA
->insertTextPortion("x", uno::Sequence
<beans::PropertyValue
>(), xCursor
);
176 xCursor
->goLeft(1, true);
177 CPPUNIT_ASSERT_EQUAL(OUString("x"), xCursor
->getString());
178 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE
, getProperty
<awt::FontSlant
>(xProps
, "CharPosture"));
181 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testInsertTextContentExpandsHints
)
184 uno::Reference
<text::XTextDocument
> const xTextDocument(mxComponent
, uno::UNO_QUERY
);
185 uno::Reference
<lang::XMultiServiceFactory
> const xFactory(mxComponent
, uno::UNO_QUERY
);
186 uno::Reference
<text::XText
> const xText(xTextDocument
->getText());
187 uno::Reference
<text::XTextCursor
> const xCursor(xText
->createTextCursor());
188 uno::Reference
<beans::XPropertySet
> const xProps(xCursor
, uno::UNO_QUERY
);
190 xText
->insertString(xCursor
, "ab", false);
191 xCursor
->gotoStart(false);
192 xCursor
->goRight(1, true);
193 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE
, getProperty
<awt::FontSlant
>(xProps
, "CharPosture"));
194 xProps
->setPropertyValue("CharPosture", uno::Any(awt::FontSlant_ITALIC
));
195 xCursor
->collapseToEnd();
196 uno::Reference
<text::XTextContent
> const xContent(
197 xFactory
->createInstance("com.sun.star.text.Footnote"), uno::UNO_QUERY
);
198 xText
->insertTextContent(xCursor
, xContent
, false);
199 xCursor
->goLeft(1, true);
200 CPPUNIT_ASSERT_EQUAL(OUString("1"), xCursor
->getString());
201 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC
, getProperty
<awt::FontSlant
>(xProps
, "CharPosture"));
204 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testInsertTextContentWithPropertiesNotExpandsHints
)
207 uno::Reference
<text::XTextDocument
> const xTextDocument(mxComponent
, uno::UNO_QUERY
);
208 uno::Reference
<lang::XMultiServiceFactory
> const xFactory(mxComponent
, uno::UNO_QUERY
);
209 uno::Reference
<text::XText
> const xText(xTextDocument
->getText());
210 uno::Reference
<text::XTextContentAppend
> const xTextA(xText
, uno::UNO_QUERY
);
211 uno::Reference
<text::XTextCursor
> const xCursor(xText
->createTextCursor());
212 uno::Reference
<beans::XPropertySet
> const xProps(xCursor
, uno::UNO_QUERY
);
214 xText
->insertString(xCursor
, "ab", false);
215 xCursor
->gotoStart(false);
216 xCursor
->goRight(1, true);
217 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE
, getProperty
<awt::FontSlant
>(xProps
, "CharPosture"));
218 xProps
->setPropertyValue("CharPosture", uno::Any(awt::FontSlant_ITALIC
));
219 xCursor
->collapseToEnd();
220 uno::Reference
<text::XTextContent
> const xContent(
221 xFactory
->createInstance("com.sun.star.text.Footnote"), uno::UNO_QUERY
);
222 xTextA
->insertTextContentWithProperties(xContent
, uno::Sequence
<beans::PropertyValue
>(),
224 xCursor
->goLeft(1, true);
225 CPPUNIT_ASSERT_EQUAL(OUString("1"), xCursor
->getString());
226 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_NONE
, getProperty
<awt::FontSlant
>(xProps
, "CharPosture"));
229 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testGraphicDescriptorURL
)
233 // Create a graphic object, but don't insert it yet.
234 uno::Reference
<lang::XMultiServiceFactory
> xFactory(mxComponent
, uno::UNO_QUERY
);
235 uno::Reference
<beans::XPropertySet
> xTextGraphic(
236 xFactory
->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY
);
239 xTextGraphic
->setPropertyValue("GraphicURL", uno::Any(createFileURL(u
"test.jpg")));
240 xTextGraphic
->setPropertyValue("AnchorType",
241 uno::Any(text::TextContentAnchorType_AT_CHARACTER
));
244 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
245 uno::Reference
<text::XText
> xBodyText
= xTextDocument
->getText();
246 uno::Reference
<text::XTextCursor
> xCursor(xBodyText
->createTextCursor());
247 uno::Reference
<text::XTextContent
> xTextContent(xTextGraphic
, uno::UNO_QUERY
);
248 xBodyText
->insertTextContent(xCursor
, xTextContent
, false);
250 // This failed, the graphic object had no graphic.
251 auto xGraphic
= getProperty
<uno::Reference
<graphic::XGraphic
>>(getShape(1), "Graphic");
252 CPPUNIT_ASSERT(xGraphic
.is());
255 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testGraphicDescriptorURLBitmap
)
259 // Load a bitmap into the bitmap table.
260 uno::Reference
<lang::XMultiServiceFactory
> xFactory(mxComponent
, uno::UNO_QUERY
);
261 uno::Reference
<container::XNameContainer
> xBitmaps(
262 xFactory
->createInstance("com.sun.star.drawing.BitmapTable"), uno::UNO_QUERY
);
263 xBitmaps
->insertByName("test", uno::Any(createFileURL(u
"test.jpg")));
266 uno::Reference
<beans::XPropertySet
> xTextGraphic(
267 xFactory
->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY
);
268 xTextGraphic
->setPropertyValue("GraphicURL", xBitmaps
->getByName("test"));
269 xTextGraphic
->setPropertyValue("AnchorType",
270 uno::Any(text::TextContentAnchorType_AT_CHARACTER
));
273 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
274 uno::Reference
<text::XText
> xBodyText
= xTextDocument
->getText();
275 uno::Reference
<text::XTextCursor
> xCursor(xBodyText
->createTextCursor());
276 uno::Reference
<text::XTextContent
> xTextContent(xTextGraphic
, uno::UNO_QUERY
);
277 xBodyText
->insertTextContent(xCursor
, xTextContent
, false);
279 // This failed: setting GraphicURL to the result of getByName() did not
281 auto xGraphic
= getProperty
<uno::Reference
<graphic::XGraphic
>>(getShape(1), "Graphic");
282 CPPUNIT_ASSERT(xGraphic
.is());
285 static bool ensureAutoTextExistsByTitle(const uno::Reference
<text::XAutoTextGroup
>& autoTextGroup
,
286 std::u16string_view autoTextName
)
288 const uno::Sequence
<OUString
> aTitles(autoTextGroup
->getTitles());
289 for (const auto& rTitle
: aTitles
)
291 if (rTitle
== autoTextName
)
297 static bool ensureAutoTextExistsByName(const uno::Reference
<text::XAutoTextGroup
>& autoTextGroup
,
298 std::u16string_view autoTextName
)
300 const uno::Sequence
<OUString
> aTitles(autoTextGroup
->getElementNames());
301 for (const auto& rTitle
: aTitles
)
303 if (rTitle
== autoTextName
)
309 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testXAutoTextGroup
)
311 createSwDoc("xautotextgroup.odt");
312 uno::Reference
<text::XAutoTextContainer
> xAutoTextContainer
313 = text::AutoTextContainer::create(comphelper::getProcessComponentContext());
315 uno::Reference
<text::XTextRange
> xTextRange
= getRun(getParagraph(1), 1);
317 static const OUStringLiteral sGroupName
= u
"TestGroup*1";
318 static const OUStringLiteral sTextName
= u
"TEST";
319 static const OUStringLiteral sTextNameNew
= u
"TESTRENAMED";
320 static const OUStringLiteral sTextTitle
= u
"Test Auto Text";
321 static const OUStringLiteral sTextTitleNew
= u
"Test Auto Text Renamed";
323 // Create new temporary group
324 uno::Reference
<text::XAutoTextGroup
> xAutoTextGroup
325 = xAutoTextContainer
->insertNewByName(sGroupName
);
326 CPPUNIT_ASSERT_MESSAGE("AutoTextGroup was not found!", xAutoTextGroup
.is());
328 // Insert new element and ensure it exists
329 uno::Reference
<text::XAutoTextEntry
> xAutoTextEntry
330 = xAutoTextGroup
->insertNewByName(sTextName
, sTextTitle
, xTextRange
);
331 CPPUNIT_ASSERT_MESSAGE("AutoText was not inserted!", xAutoTextEntry
.is());
332 CPPUNIT_ASSERT_MESSAGE("Can't find newly created AutoText by title!",
333 ensureAutoTextExistsByTitle(xAutoTextGroup
, sTextTitle
));
334 CPPUNIT_ASSERT_MESSAGE("Can't find newly created AutoText by name!",
335 ensureAutoTextExistsByName(xAutoTextGroup
, sTextName
));
337 // Insert once again the same should throw an exception
338 CPPUNIT_ASSERT_THROW_MESSAGE("We expect an exception on insertion of same AutoText",
339 xAutoTextGroup
->insertNewByName(sTextName
, sTextTitle
, xTextRange
),
340 container::ElementExistException
);
342 // Rename it & ensure everything is ok
343 xAutoTextGroup
->renameByName(sTextName
, sTextNameNew
, sTextTitleNew
);
344 CPPUNIT_ASSERT_MESSAGE("Can't find renamed AutoText by title!",
345 ensureAutoTextExistsByTitle(xAutoTextGroup
, sTextTitleNew
));
346 CPPUNIT_ASSERT_MESSAGE("Can't find renamed AutoText by name!",
347 ensureAutoTextExistsByName(xAutoTextGroup
, sTextNameNew
));
348 // Not found by old names
349 CPPUNIT_ASSERT_MESSAGE("Found AutoText by old title!",
350 !ensureAutoTextExistsByTitle(xAutoTextGroup
, sTextTitle
));
351 CPPUNIT_ASSERT_MESSAGE("Found AutoText by old name!",
352 !ensureAutoTextExistsByName(xAutoTextGroup
, sTextName
));
354 // Rename not existing should throw an exception
355 CPPUNIT_ASSERT_THROW_MESSAGE(
356 "We expect an exception on renaming not-existing AutoText",
357 xAutoTextGroup
->renameByName(sTextName
, sTextNameNew
, sTextTitleNew
),
358 container::ElementExistException
);
360 // Remove it and ensure it does not exist
361 xAutoTextGroup
->removeByName(sTextNameNew
);
362 CPPUNIT_ASSERT_MESSAGE("AutoText was not removed!",
363 !ensureAutoTextExistsByTitle(xAutoTextGroup
, sTextTitleNew
));
364 CPPUNIT_ASSERT_MESSAGE("AutoText was not removed!",
365 !ensureAutoTextExistsByName(xAutoTextGroup
, sTextNameNew
));
367 // Remove non-existing element should throw an exception
368 CPPUNIT_ASSERT_THROW_MESSAGE("We expect an exception on removing not-existing AutoText",
369 xAutoTextGroup
->removeByName(sTextName
),
370 container::NoSuchElementException
);
372 // Remove our temporary group
373 xAutoTextContainer
->removeByName(sGroupName
);
376 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testSectionAnchorCopyTableAtStart
)
378 // this contains a section that starts with a table
379 createSwDoc("tdf134250.fodt");
381 uno::Reference
<text::XTextTablesSupplier
> const xTextTablesSupplier(mxComponent
,
383 uno::Reference
<container::XIndexAccess
> const xTables(xTextTablesSupplier
->getTextTables(),
385 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables
->getCount());
387 uno::Reference
<text::XTextSectionsSupplier
> const xTextSectionsSupplier(mxComponent
,
389 uno::Reference
<container::XIndexAccess
> const xSections(
390 xTextSectionsSupplier
->getTextSections(), uno::UNO_QUERY
);
392 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections
->getCount());
394 uno::Reference
<text::XTextContent
> const xSection(xSections
->getByIndex(0), uno::UNO_QUERY
);
395 uno::Reference
<text::XTextRange
> const xAnchor(xSection
->getAnchor());
396 CPPUNIT_ASSERT_EQUAL(OUString("foo" SAL_NEWLINE_STRING
"bar"), xAnchor
->getString());
398 // copy the content of the section to a clipboard document
399 uno::Reference
<datatransfer::XTransferableSupplier
> const xTS(
400 uno::Reference
<frame::XModel
>(mxComponent
, uno::UNO_QUERY_THROW
)->getCurrentController(),
402 uno::Reference
<datatransfer::XTransferableTextSupplier
> const xTTS(xTS
, uno::UNO_QUERY
);
403 uno::Reference
<datatransfer::XTransferable
> const xTransferable(
404 xTTS
->getTransferableForTextRange(xAnchor
));
406 // check this doesn't throw
407 CPPUNIT_ASSERT(xAnchor
->getText().is());
408 CPPUNIT_ASSERT(xAnchor
->getStart().is());
409 CPPUNIT_ASSERT(xAnchor
->getEnd().is());
411 // replace section content
412 xAnchor
->setString("quux");
414 // table in section was deleted, but not section itself
415 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xTables
->getCount());
416 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections
->getCount());
417 CPPUNIT_ASSERT_EQUAL(OUString("\""
418 "quux" /*SAL_NEWLINE_STRING*/ "\""),
419 OUString("\"" + xAnchor
->getString() + "\""));
422 uno::Reference
<text::XTextViewCursorSupplier
> const xTVCS(xTS
, uno::UNO_QUERY
);
423 uno::Reference
<text::XTextViewCursor
> const xCursor(xTVCS
->getViewCursor());
424 xCursor
->gotoEnd(false);
425 xTS
->insertTransferable(xTransferable
);
427 // table in section was pasted, but not section itself
428 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables
->getCount());
429 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections
->getCount());
430 xCursor
->gotoStart(true);
431 CPPUNIT_ASSERT_EQUAL(OUString("quux" SAL_NEWLINE_STRING
"foo" SAL_NEWLINE_STRING
"bar"),
432 xCursor
->getString());
435 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testSectionAnchorCopyTableAtEnd
)
437 // this contains a section that ends with a table (plus another section)
438 createSwDoc("tdf134252.fodt");
440 uno::Reference
<text::XTextTablesSupplier
> const xTextTablesSupplier(mxComponent
,
442 uno::Reference
<container::XIndexAccess
> const xTables(xTextTablesSupplier
->getTextTables(),
444 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables
->getCount());
446 uno::Reference
<text::XTextSectionsSupplier
> const xTextSectionsSupplier(mxComponent
,
448 uno::Reference
<container::XIndexAccess
> const xSections(
449 xTextSectionsSupplier
->getTextSections(), uno::UNO_QUERY
);
451 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xSections
->getCount());
453 uno::Reference
<text::XTextContent
> const xSection(xSections
->getByIndex(0), uno::UNO_QUERY
);
454 uno::Reference
<text::XTextRange
> const xAnchor(xSection
->getAnchor());
455 CPPUNIT_ASSERT_EQUAL(OUString("bar" SAL_NEWLINE_STRING
"baz" SAL_NEWLINE_STRING
),
456 xAnchor
->getString());
458 // copy the content of the section to a clipboard document
459 uno::Reference
<datatransfer::XTransferableSupplier
> const xTS(
460 uno::Reference
<frame::XModel
>(mxComponent
, uno::UNO_QUERY_THROW
)->getCurrentController(),
462 uno::Reference
<datatransfer::XTransferableTextSupplier
> const xTTS(xTS
, uno::UNO_QUERY
);
463 uno::Reference
<datatransfer::XTransferable
> const xTransferable(
464 xTTS
->getTransferableForTextRange(xAnchor
));
466 // check this doesn't throw
467 CPPUNIT_ASSERT(xAnchor
->getText().is());
468 CPPUNIT_ASSERT(xAnchor
->getStart().is());
469 CPPUNIT_ASSERT(xAnchor
->getEnd().is());
471 // replace section content
472 xAnchor
->setString("quux");
474 // table in section was deleted, but not section itself
475 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xTables
->getCount());
476 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xSections
->getCount());
477 CPPUNIT_ASSERT_EQUAL(OUString("\""
478 "quux" /*SAL_NEWLINE_STRING*/ "\""),
479 OUString("\"" + xAnchor
->getString() + "\""));
482 uno::Reference
<text::XTextViewCursorSupplier
> const xTVCS(xTS
, uno::UNO_QUERY
);
483 uno::Reference
<text::XTextViewCursor
> const xCursor(xTVCS
->getViewCursor());
484 xCursor
->gotoEnd(false);
485 xTS
->insertTransferable(xTransferable
);
487 // table in section was pasted, but not section itself
488 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables
->getCount());
489 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xSections
->getCount());
490 // note: this selects the 2nd section because it calls StartOfSection()
491 // not SttEndDoc() like it should?
492 xCursor
->gotoStart(true);
493 CPPUNIT_ASSERT_EQUAL(OUString(/*"quux" SAL_NEWLINE_STRING */
494 "foobar" SAL_NEWLINE_STRING
"baz" SAL_NEWLINE_STRING
),
495 xCursor
->getString());
498 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testSectionAnchorCopyTable
)
500 // this contains a section that ends with a table (plus another section)
501 createSwDoc("tdf134252_onlytable_protected.fodt");
503 uno::Reference
<text::XTextTablesSupplier
> const xTextTablesSupplier(mxComponent
,
505 uno::Reference
<container::XIndexAccess
> const xTables(xTextTablesSupplier
->getTextTables(),
507 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables
->getCount());
509 uno::Reference
<text::XTextSectionsSupplier
> const xTextSectionsSupplier(mxComponent
,
511 uno::Reference
<container::XIndexAccess
> const xSections(
512 xTextSectionsSupplier
->getTextSections(), uno::UNO_QUERY
);
514 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections
->getCount());
516 uno::Reference
<text::XTextContent
> const xSection(xSections
->getByIndex(0), uno::UNO_QUERY
);
517 uno::Reference
<text::XTextRange
> const xAnchor(xSection
->getAnchor());
518 CPPUNIT_ASSERT_EQUAL(OUString("baz" SAL_NEWLINE_STRING
), xAnchor
->getString());
520 // copy the content of the section to a clipboard document
521 uno::Reference
<datatransfer::XTransferableSupplier
> const xTS(
522 uno::Reference
<frame::XModel
>(mxComponent
, uno::UNO_QUERY_THROW
)->getCurrentController(),
524 uno::Reference
<datatransfer::XTransferableTextSupplier
> const xTTS(xTS
, uno::UNO_QUERY
);
525 uno::Reference
<datatransfer::XTransferable
> const xTransferable(
526 xTTS
->getTransferableForTextRange(xAnchor
));
528 // check this doesn't throw
529 CPPUNIT_ASSERT(xAnchor
->getText().is());
530 CPPUNIT_ASSERT(xAnchor
->getStart().is());
531 CPPUNIT_ASSERT(xAnchor
->getEnd().is());
533 // replace section content
534 xAnchor
->setString("quux");
536 // table in section was deleted, but not section itself
537 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xTables
->getCount());
538 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections
->getCount());
539 CPPUNIT_ASSERT_EQUAL(OUString("\""
540 "quux" /*SAL_NEWLINE_STRING*/ "\""),
541 OUString("\"" + xAnchor
->getString() + "\""));
544 uno::Reference
<text::XTextViewCursorSupplier
> const xTVCS(xTS
, uno::UNO_QUERY
);
545 uno::Reference
<text::XTextViewCursor
> const xCursor(xTVCS
->getViewCursor());
546 xCursor
->gotoEnd(false);
547 xTS
->insertTransferable(xTransferable
);
549 // table in section was pasted, but not section itself
550 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables
->getCount());
551 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections
->getCount());
552 xCursor
->gotoStart(true);
553 CPPUNIT_ASSERT_EQUAL(
554 OUString("quux" SAL_NEWLINE_STRING
"foo" SAL_NEWLINE_STRING
"baz" SAL_NEWLINE_STRING
),
555 xCursor
->getString());
558 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testTextRangeInTable
)
560 createSwDoc("bookmarkintable.fodt");
562 uno::Reference
<text::XBookmarksSupplier
> const xBS(mxComponent
, uno::UNO_QUERY
);
563 uno::Reference
<container::XNameAccess
> const xMarks(xBS
->getBookmarks());
564 uno::Reference
<text::XTextContent
> const xMark(xMarks
->getByName("Bookmark 1"), uno::UNO_QUERY
);
565 uno::Reference
<container::XEnumerationAccess
> const xAnchor(xMark
->getAnchor(), uno::UNO_QUERY
);
566 uno::Reference
<container::XEnumeration
> const xEnum(xAnchor
->createEnumeration());
567 uno::Reference
<lang::XServiceInfo
> const xPara(xEnum
->nextElement(), uno::UNO_QUERY
);
568 // not the top-level table!
569 CPPUNIT_ASSERT(!xPara
->supportsService("com.sun.star.text.TextTable"));
570 CPPUNIT_ASSERT(!xEnum
->hasMoreElements());
571 uno::Reference
<container::XEnumerationAccess
> const xParaEA(xPara
, uno::UNO_QUERY
);
572 uno::Reference
<container::XEnumeration
> const xPortions(xParaEA
->createEnumeration());
573 uno::Reference
<beans::XPropertySet
> const xP1(xPortions
->nextElement(), uno::UNO_QUERY
);
574 CPPUNIT_ASSERT_EQUAL(OUString("Bookmark"), getProperty
<OUString
>(xP1
, "TextPortionType"));
575 uno::Reference
<beans::XPropertySet
> const xP2(xPortions
->nextElement(), uno::UNO_QUERY
);
576 CPPUNIT_ASSERT_EQUAL(OUString("Text"), getProperty
<OUString
>(xP2
, "TextPortionType"));
577 uno::Reference
<text::XTextRange
> const xP2R(xP2
, uno::UNO_QUERY
);
578 CPPUNIT_ASSERT_EQUAL(OUString("foo"), xP2R
->getString());
579 uno::Reference
<beans::XPropertySet
> const xP3(xPortions
->nextElement(), uno::UNO_QUERY
);
580 CPPUNIT_ASSERT_EQUAL(OUString("Bookmark"), getProperty
<OUString
>(xP3
, "TextPortionType"));
581 CPPUNIT_ASSERT(!xPortions
->hasMoreElements());
584 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testXURI
)
586 uno::Reference
<uno::XComponentContext
> xContext(::comphelper::getProcessComponentContext());
589 uno::Reference
<rdf::XURI
> xURIcreateKnown(
590 rdf::URI::createKnown(xContext
, rdf::URIs::ODF_PREFIX
), uno::UNO_SET_THROW
);
591 CPPUNIT_ASSERT(xURIcreateKnown
.is());
592 CPPUNIT_ASSERT_EQUAL(OUString("http://docs.oasis-open.org/ns/office/1.2/meta/odf#"),
593 xURIcreateKnown
->getNamespace());
594 CPPUNIT_ASSERT_EQUAL(OUString("prefix"), xURIcreateKnown
->getLocalName());
595 CPPUNIT_ASSERT_EQUAL(OUString("http://docs.oasis-open.org/ns/office/1.2/meta/odf#prefix"),
596 xURIcreateKnown
->getStringValue());
598 // createKnown() with invalid constant
599 CPPUNIT_ASSERT_THROW_MESSAGE("We expect an exception on invalid constant",
600 rdf::URI::createKnown(xContext
, 12345),
601 lang::IllegalArgumentException
);
604 uno::Reference
<rdf::XURI
> xURIcreate(
605 rdf::URI::create(xContext
, "http://example.com/url#somedata"), uno::UNO_SET_THROW
);
606 CPPUNIT_ASSERT_EQUAL(OUString("http://example.com/url#"), xURIcreate
->getNamespace());
607 CPPUNIT_ASSERT_EQUAL(OUString("somedata"), xURIcreate
->getLocalName());
608 CPPUNIT_ASSERT_EQUAL(OUString("http://example.com/url#somedata"), xURIcreate
->getStringValue());
610 // create() without local name split with "/"
611 uno::Reference
<rdf::XURI
> xURIcreate2(rdf::URI::create(xContext
, "http://example.com/url"),
613 CPPUNIT_ASSERT_EQUAL(OUString("http://example.com/"), xURIcreate2
->getNamespace());
614 CPPUNIT_ASSERT_EQUAL(OUString("url"), xURIcreate2
->getLocalName());
615 CPPUNIT_ASSERT_EQUAL(OUString("http://example.com/url"), xURIcreate2
->getStringValue());
617 // create() without prefix
618 uno::Reference
<rdf::XURI
> xURIcreate3(rdf::URI::create(xContext
, "#somedata"),
620 CPPUNIT_ASSERT_EQUAL(OUString("#"), xURIcreate3
->getNamespace());
621 CPPUNIT_ASSERT_EQUAL(OUString("somedata"), xURIcreate3
->getLocalName());
622 CPPUNIT_ASSERT_EQUAL(OUString("#somedata"), xURIcreate3
->getStringValue());
624 // create() with invalid URI
625 CPPUNIT_ASSERT_THROW_MESSAGE("We expect an exception on invalid URI",
626 rdf::URI::create(xContext
, "some junk and not URI"),
627 lang::IllegalArgumentException
);
630 uno::Reference
<rdf::XURI
> xURIcreateNS(
631 rdf::URI::createNS(xContext
, "http://example.com/url#", "somedata"), uno::UNO_SET_THROW
);
632 CPPUNIT_ASSERT_EQUAL(OUString("http://example.com/url#"), xURIcreateNS
->getNamespace());
633 CPPUNIT_ASSERT_EQUAL(OUString("somedata"), xURIcreateNS
->getLocalName());
634 CPPUNIT_ASSERT_EQUAL(OUString("http://example.com/url#somedata"),
635 xURIcreateNS
->getStringValue());
637 // TODO: What's going on here? Is such usecase valid?
638 uno::Reference
<rdf::XURI
> xURIcreateNS2(
639 rdf::URI::createNS(xContext
, "http://example.com/url", "somedata"), uno::UNO_SET_THROW
);
640 CPPUNIT_ASSERT_EQUAL(OUString("http://example.com/"), xURIcreateNS2
->getNamespace());
641 CPPUNIT_ASSERT_EQUAL(OUString("urlsomedata"), xURIcreateNS2
->getLocalName());
642 CPPUNIT_ASSERT_EQUAL(OUString("http://example.com/urlsomedata"),
643 xURIcreateNS2
->getStringValue());
645 // createNS() some invalid cases
646 CPPUNIT_ASSERT_THROW_MESSAGE("We expect an exception on invalid URI",
647 rdf::URI::createNS(xContext
, "bla", "bla"),
648 lang::IllegalArgumentException
);
650 CPPUNIT_ASSERT_THROW_MESSAGE("We expect an exception on invalid URI",
651 rdf::URI::createNS(xContext
, OUString(), OUString()),
652 lang::IllegalArgumentException
);
655 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testSetPagePrintSettings
)
657 // Create an empty new document with a single char
660 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
661 uno::Reference
<text::XSimpleText
> xBodyText
= xTextDocument
->getText();
662 xBodyText
->insertString(xBodyText
->getStart(), "x", false);
664 uno::Reference
<text::XPagePrintable
> xPagePrintable(mxComponent
, uno::UNO_QUERY
);
666 // set some stuff, try to get it back
667 uno::Sequence
<beans::PropertyValue
> aProps
{
668 comphelper::makePropertyValue("PageColumns", sal_Int16(2)),
669 comphelper::makePropertyValue("IsLandscape", true)
672 xPagePrintable
->setPagePrintSettings(aProps
);
673 const comphelper::SequenceAsHashMap
aMap(xPagePrintable
->getPagePrintSettings());
675 CPPUNIT_ASSERT_EQUAL(sal_Int16(2), aMap
.getValue("PageColumns").get
<short>());
676 CPPUNIT_ASSERT_EQUAL(true, aMap
.getValue("IsLandscape").get
<bool>());
679 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testDeleteFlyAtCharAtStart
)
682 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
683 CPPUNIT_ASSERT(pTextDoc
);
684 SwWrtShell
* const pWrtShell(pTextDoc
->GetDocShell()->GetWrtShell());
685 SwDoc
* const pDoc(pWrtShell
->GetDoc());
688 IDocumentContentOperations
& rIDCO(pDoc
->getIDocumentContentOperations());
689 rIDCO
.InsertString(*pWrtShell
->GetCursor(), "foo bar baz");
691 // insert fly anchored at start of body text
692 pWrtShell
->ClearMark();
693 pWrtShell
->SttEndDoc(true);
694 SfxItemSet
frameSet(pDoc
->GetAttrPool(), svl::Items
<RES_FRMATR_BEGIN
, RES_FRMATR_END
- 1>);
695 SfxItemSet
grfSet(pDoc
->GetAttrPool(), svl::Items
<RES_GRFATR_BEGIN
, RES_GRFATR_END
- 1>);
696 SwFormatAnchor
anchor(RndStdIds::FLY_AT_CHAR
);
697 frameSet
.Put(anchor
);
699 CPPUNIT_ASSERT(rIDCO
.InsertGraphic(*pWrtShell
->GetCursor(), OUString(), OUString(), &grf
,
700 &frameSet
, &grfSet
, nullptr));
703 CPPUNIT_ASSERT_EQUAL(1, getShapes());
704 uno::Reference
<text::XTextContent
> const xShape(getShape(1), uno::UNO_QUERY
);
705 // anchored at start of body text?
706 uno::Reference
<text::XText
> const xText(pTextDoc
->getText());
707 uno::Reference
<text::XTextRangeCompare
> const xTextRC(xText
, uno::UNO_QUERY
);
708 CPPUNIT_ASSERT_EQUAL(sal_Int16(0),
709 xTextRC
->compareRegionStarts(xText
->getStart(), xShape
->getAnchor()));
711 // delete 1st character
712 uno::Reference
<text::XTextCursor
> const xCursor(xText
->createTextCursor());
713 xCursor
->goRight(1, true);
714 xCursor
->setString("");
716 // there is exactly one fly
717 CPPUNIT_ASSERT_EQUAL(1, getShapes());
719 // select entire body text
720 xCursor
->gotoStart(true);
721 xCursor
->gotoEnd(true);
722 xCursor
->setString("");
725 CPPUNIT_ASSERT_EQUAL(0, getShapes());
728 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testSelectionInTableEnum
)
730 createSwDoc("selection-in-table-enum.odt");
731 // Select the A1 cell's text.
732 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
733 CPPUNIT_ASSERT(pTextDoc
);
734 SwWrtShell
* pWrtShell
= pTextDoc
->GetDocShell()->GetWrtShell();
735 CPPUNIT_ASSERT(pWrtShell
);
736 pWrtShell
->Down(/*bSelect=*/false);
737 pWrtShell
->EndPara(/*bSelect=*/true);
738 CPPUNIT_ASSERT_EQUAL(OUString("A1"),
739 pWrtShell
->GetCursor()->GetPointNode().GetTextNode()->GetText());
741 // Access the selection.
742 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
743 CPPUNIT_ASSERT(xModel
.is());
744 uno::Reference
<container::XIndexAccess
> xSelections(xModel
->getCurrentSelection(),
746 CPPUNIT_ASSERT(xSelections
.is());
747 uno::Reference
<text::XTextRange
> xSelection(xSelections
->getByIndex(0), uno::UNO_QUERY
);
748 CPPUNIT_ASSERT(xSelection
.is());
750 // Enumerate paragraphs in the selection.
751 uno::Reference
<container::XEnumerationAccess
> xCursor(
752 xSelection
->getText()->createTextCursorByRange(xSelection
), uno::UNO_QUERY
);
753 CPPUNIT_ASSERT(xCursor
.is());
754 uno::Reference
<container::XEnumeration
> xEnum
= xCursor
->createEnumeration();
755 xEnum
->nextElement();
756 // Without the accompanying fix in place, this test would have failed: i.e.
757 // the enumeration contained a second paragraph, even if the cell has only
759 CPPUNIT_ASSERT(!xEnum
->hasMoreElements());
762 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testSelectionInTableEnumEnd
)
764 createSwDoc("selection-in-table-enum.odt");
765 // Select from "Before" till the table end.
766 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
767 CPPUNIT_ASSERT(pTextDoc
);
768 SwWrtShell
* pWrtShell
= pTextDoc
->GetDocShell()->GetWrtShell();
769 CPPUNIT_ASSERT(pWrtShell
);
770 pWrtShell
->Down(/*bSelect=*/true);
772 // Access the selection.
773 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
774 CPPUNIT_ASSERT(xModel
.is());
775 uno::Reference
<container::XIndexAccess
> xSelections(xModel
->getCurrentSelection(),
777 CPPUNIT_ASSERT(xSelections
.is());
778 uno::Reference
<text::XTextRange
> xSelection(xSelections
->getByIndex(0), uno::UNO_QUERY
);
779 CPPUNIT_ASSERT(xSelection
.is());
780 CPPUNIT_ASSERT_EQUAL(OUString("Before" SAL_NEWLINE_STRING
"A1" SAL_NEWLINE_STRING
781 "B1" SAL_NEWLINE_STRING
"C2" SAL_NEWLINE_STRING
782 "A2" SAL_NEWLINE_STRING
"B2" SAL_NEWLINE_STRING
783 "C2" SAL_NEWLINE_STRING
),
784 xSelection
->getString());
786 // Enumerate paragraphs in the selection.
787 uno::Reference
<container::XEnumerationAccess
> xCursor(
788 xSelection
->getText()->createTextCursorByRange(xSelection
), uno::UNO_QUERY
);
789 CPPUNIT_ASSERT(xCursor
.is());
790 uno::Reference
<container::XEnumeration
> xEnum
= xCursor
->createEnumeration();
792 xEnum
->nextElement();
794 xEnum
->nextElement();
795 // Without the accompanying fix in place, this test would have failed: i.e.
796 // the enumeration contained the paragraph after the table, but no part of
797 // that paragraph was part of the selection.
798 CPPUNIT_ASSERT(!xEnum
->hasMoreElements());
801 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testRenderablePagePosition
)
803 createSwDoc("renderable-page-position.odt");
804 // Make sure that the document has 2 pages.
805 uno::Reference
<view::XRenderable
> xRenderable(mxComponent
, uno::UNO_QUERY
);
806 CPPUNIT_ASSERT(mxComponent
.is());
808 uno::Any
aSelection(mxComponent
);
810 uno::Reference
<awt::XToolkit
> xToolkit
= VCLUnoHelper::CreateToolkit();
811 uno::Reference
<awt::XDevice
> xDevice(xToolkit
->createScreenCompatibleDevice(32, 32));
813 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
814 uno::Reference
<frame::XController
> xController
= xModel
->getCurrentController();
816 beans::PropertyValues aRenderOptions
= {
817 comphelper::makePropertyValue("IsPrinter", true),
818 comphelper::makePropertyValue("RenderDevice", xDevice
),
819 comphelper::makePropertyValue("View", xController
),
820 comphelper::makePropertyValue("RenderToGraphic", true),
823 sal_Int32 nPages
= xRenderable
->getRendererCount(aSelection
, aRenderOptions
);
824 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(2), nPages
);
826 // Make sure that the first page has some offset.
827 comphelper::SequenceAsHashMap
aRenderer1(
828 xRenderable
->getRenderer(0, aSelection
, aRenderOptions
));
829 // Without the accompanying fix in place, this test would have failed: i.e.
830 // there was no PagePos key in this map.
831 awt::Point aPosition1
= aRenderer1
["PagePos"].get
<awt::Point
>();
832 CPPUNIT_ASSERT_GREATER(static_cast<sal_Int32
>(0), aPosition1
.X
);
833 CPPUNIT_ASSERT_GREATER(static_cast<sal_Int32
>(0), aPosition1
.Y
);
835 // Make sure that the second page is below the first one.
836 comphelper::SequenceAsHashMap
aRenderer2(
837 xRenderable
->getRenderer(1, aSelection
, aRenderOptions
));
838 awt::Point aPosition2
= aRenderer2
["PagePos"].get
<awt::Point
>();
839 CPPUNIT_ASSERT_GREATER(static_cast<sal_Int32
>(0), aPosition2
.X
);
840 CPPUNIT_ASSERT_GREATER(aPosition1
.Y
, aPosition2
.Y
);
843 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testPasteListener
)
847 // Insert initial string.
848 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
849 uno::Reference
<text::XSimpleText
> xBodyText
= xTextDocument
->getText();
850 xBodyText
->insertString(xBodyText
->getStart(), "ABCDEF", false);
852 // Add paste listener.
853 uno::Reference
<text::XPasteBroadcaster
> xBroadcaster(mxComponent
, uno::UNO_QUERY
);
854 uno::Reference
<text::XPasteListener
> xListener(new PasteListener
);
855 auto pListener
= static_cast<PasteListener
*>(xListener
.get());
856 xBroadcaster
->addPasteEventListener(xListener
);
858 // Cut "DE" and then paste it.
859 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
860 CPPUNIT_ASSERT(pTextDoc
);
861 SwWrtShell
* pWrtShell
= pTextDoc
->GetDocShell()->GetWrtShell();
862 CPPUNIT_ASSERT(pWrtShell
);
863 pWrtShell
->Left(SwCursorSkipMode::Chars
, /*bSelect=*/false, 3, /*bBasicCall=*/false);
864 pWrtShell
->Right(SwCursorSkipMode::Chars
, /*bSelect=*/true, 2, /*bBasicCall=*/false);
865 rtl::Reference
<SwTransferable
> pTransfer
= new SwTransferable(*pWrtShell
);
867 TransferableDataHelper
aHelper(pTransfer
);
868 SwTransferable::Paste(*pWrtShell
, aHelper
);
869 // Without working listener registration in place, this test would have
870 // failed with 'Expected: DE; Actual:', i.e. the paste listener was not
872 CPPUNIT_ASSERT_EQUAL(OUString("DE"), pListener
->GetString());
874 // Make sure that paste did not overwrite anything.
875 CPPUNIT_ASSERT_EQUAL(OUString("ABCDEF"), xBodyText
->getString());
877 // Paste again, this time overwriting "BC".
878 pWrtShell
->Left(SwCursorSkipMode::Chars
, /*bSelect=*/false, 4, /*bBasicCall=*/false);
879 pWrtShell
->Right(SwCursorSkipMode::Chars
, /*bSelect=*/true, 2, /*bBasicCall=*/false);
880 pListener
->GetString().clear();
881 SwTransferable::Paste(*pWrtShell
, aHelper
);
882 CPPUNIT_ASSERT_EQUAL(OUString("DE"), pListener
->GetString());
884 // Make sure that paste overwrote "BC".
885 CPPUNIT_ASSERT_EQUAL(OUString("ADEDEF"), xBodyText
->getString());
888 SwView
& rView
= pWrtShell
->GetView();
889 rView
.InsertGraphic(createFileURL(u
"test.jpg"), OUString(), /*bAsLink=*/false,
890 &GraphicFilter::GetGraphicFilter());
892 // Test that the pasted image is anchored as-char.
893 SwFlyFrame
* pFly
= pWrtShell
->GetSelectedFlyFrame();
894 CPPUNIT_ASSERT(pFly
);
895 SwFrameFormat
* pFlyFormat
= pFly
->GetFormat();
896 CPPUNIT_ASSERT(pFlyFormat
);
897 RndStdIds eFlyAnchor
= pFlyFormat
->GetAnchor().GetAnchorId();
898 // Without the working image listener in place, this test would have
899 // failed, eFlyAnchor was FLY_AT_PARA.
900 CPPUNIT_ASSERT_EQUAL(RndStdIds::FLY_AT_CHAR
, eFlyAnchor
);
903 pListener
->GetString().clear();
904 SwTransferable::Paste(*pWrtShell
, aHelper
);
905 // Without the working image listener in place, this test would have
906 // failed, the listener was not invoked in case of a graphic paste.
907 CPPUNIT_ASSERT(pListener
->GetTextGraphicObject().is());
908 CPPUNIT_ASSERT(pListener
->GetString().isEmpty());
910 // Deregister paste listener, make sure it's not invoked.
911 xBroadcaster
->removePasteEventListener(xListener
);
912 pListener
->GetString().clear();
913 SwTransferable::Paste(*pWrtShell
, aHelper
);
914 CPPUNIT_ASSERT(pListener
->GetString().isEmpty());
917 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testImageCommentAtChar
)
919 // Load a document with an at-char image in it (and a comment on the image).
920 createSwDoc("image-comment-at-char.odt");
921 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
922 CPPUNIT_ASSERT(pTextDoc
);
923 SwDoc
* pDoc
= pTextDoc
->GetDocShell()->GetDoc();
925 // Verify that we have an annotation mark (comment with a text range) in the document.
926 // Without the accompanying fix in place, this test would have failed, as comments lost their
927 // ranges on load when their range only covered the placeholder character of the comment (which
928 // is also the anchor position of the image).
929 IDocumentMarkAccess
* pMarks
= pDoc
->getIDocumentMarkAccess();
930 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), pMarks
->getAnnotationMarksCount());
932 uno::Reference
<text::XTextRange
> xPara
= getParagraph(1);
933 CPPUNIT_ASSERT_EQUAL(OUString("Text"),
934 getProperty
<OUString
>(getRun(xPara
, 1), "TextPortionType"));
935 // Without the accompanying fix in place, this test would have failed with 'Expected:
936 // Annotation; Actual: Frame', i.e. the comment-start portion was after the commented image.
937 CPPUNIT_ASSERT_EQUAL(OUString("Annotation"),
938 getProperty
<OUString
>(getRun(xPara
, 2), "TextPortionType"));
939 CPPUNIT_ASSERT_EQUAL(OUString("Frame"),
940 getProperty
<OUString
>(getRun(xPara
, 3), "TextPortionType"));
941 CPPUNIT_ASSERT_EQUAL(OUString("AnnotationEnd"),
942 getProperty
<OUString
>(getRun(xPara
, 4), "TextPortionType"));
943 CPPUNIT_ASSERT_EQUAL(OUString("Text"),
944 getProperty
<OUString
>(getRun(xPara
, 5), "TextPortionType"));
946 // Without the accompanying fix in place, this test would have failed with 'Expected:
947 // 5892; Actual: 1738', i.e. the anchor pos was between the "aaa" and "bbb" portions, not at the
948 // center of the page (horizontally) where the image is. On macOS, though, with the fix in
949 // place the actual value consistently is even greater with 6283 now instead of 5892, for
951 SwView
* pView
= pDoc
->GetDocShell()->GetView();
952 SwPostItMgr
* pPostItMgr
= pView
->GetPostItMgr();
953 for (const auto& pItem
: *pPostItMgr
)
955 const SwRect
& rAnchor
= pItem
->mpPostIt
->GetAnchorRect();
956 CPPUNIT_ASSERT_GREATEREQUAL(static_cast<tools::Long
>(5892), rAnchor
.Left());
960 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testChapterNumberingCharStyle
)
964 uno::Reference
<lang::XMultiServiceFactory
> xDoc(mxComponent
, uno::UNO_QUERY
);
965 uno::Reference
<beans::XPropertySet
> xStyle(
966 xDoc
->createInstance("com.sun.star.style.CharacterStyle"), uno::UNO_QUERY
);
967 uno::Reference
<container::XNamed
> xStyleN(xStyle
, uno::UNO_QUERY
);
968 xStyle
->setPropertyValue("CharColor", uno::Any(sal_Int32(0x00FF0000)));
969 uno::Reference
<style::XStyleFamiliesSupplier
> xSFS(mxComponent
, uno::UNO_QUERY
);
970 uno::Reference
<container::XNameContainer
> xStyles(
971 xSFS
->getStyleFamilies()->getByName("CharacterStyles"), uno::UNO_QUERY
);
972 xStyles
->insertByName("red", uno::Any(xStyle
));
974 uno::Reference
<text::XChapterNumberingSupplier
> xCNS(mxComponent
, uno::UNO_QUERY
);
975 uno::Reference
<container::XIndexReplace
> xOutline(xCNS
->getChapterNumberingRules());
977 comphelper::SequenceAsHashMap
hashMap(xOutline
->getByIndex(0));
978 hashMap
["CharStyleName"] <<= OUString("red");
979 uno::Sequence
<beans::PropertyValue
> props
;
981 xOutline
->replaceByIndex(0, uno::Any(props
));
983 // now rename the style
984 xStyleN
->setName("reddishred");
986 comphelper::SequenceAsHashMap
hashMap(xOutline
->getByIndex(0));
988 // tdf#137810 this failed, was old value "red"
989 CPPUNIT_ASSERT_EQUAL(OUString("reddishred"), hashMap
["CharStyleName"].get
<OUString
>());
993 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testViewCursorPageStyle
)
995 // Load a document with 2 pages, but a single paragraph.
996 createSwDoc("view-cursor-page-style.fodt");
997 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
998 CPPUNIT_ASSERT(xModel
.is());
999 uno::Reference
<text::XTextViewCursorSupplier
> xController(xModel
->getCurrentController(),
1001 CPPUNIT_ASSERT(xController
.is());
1002 uno::Reference
<text::XPageCursor
> xViewCursor(xController
->getViewCursor(), uno::UNO_QUERY
);
1003 CPPUNIT_ASSERT(xViewCursor
.is());
1005 // Go to the first page, which has an explicit page style.
1006 xViewCursor
->jumpToPage(1);
1007 OUString aActualPageStyleName
= getProperty
<OUString
>(xViewCursor
, "PageStyleName");
1008 CPPUNIT_ASSERT_EQUAL(OUString("First Page"), aActualPageStyleName
);
1010 // Go to the second page, which is still the first paragraph, but the page style is different,
1011 // as the explicit 'First Page' page style has a next style defined (Standard).
1012 xViewCursor
->jumpToPage(2);
1013 aActualPageStyleName
= getProperty
<OUString
>(xViewCursor
, "PageStyleName");
1014 // Without the accompanying fix in place, this test would have failed with:
1015 // - Expected: Standard
1016 // - Actual : First Page
1017 // i.e. the cursor position was determined only based on the node index, ignoring the content
1019 CPPUNIT_ASSERT_EQUAL(OUString("Standard"), aActualPageStyleName
);
1022 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testXTextCursor_setPropertyValues
)
1024 // Create a new document, type a character, pass a set of property/value pairs consisting of one
1025 // unknown property and CharStyleName, assert that it threw UnknownPropertyException (actually
1026 // wrapped into WrappedTargetException), and assert the style was set, not discarded.
1029 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
1030 uno::Reference
<text::XSimpleText
> xBodyText
= xTextDocument
->getText();
1031 xBodyText
->insertString(xBodyText
->getStart(), "x", false);
1033 uno::Reference
<text::XTextCursor
> xCursor(xBodyText
->createTextCursor());
1034 xCursor
->goLeft(1, true);
1036 uno::Reference
<beans::XMultiPropertySet
> xCursorProps(xCursor
, uno::UNO_QUERY
);
1037 uno::Sequence
<OUString
> aPropNames
= { "OneUnknownProperty", "CharStyleName" };
1038 uno::Sequence
<uno::Any
> aPropValues
= { uno::Any(), uno::Any(OUString("Emphasis")) };
1039 CPPUNIT_ASSERT_THROW(xCursorProps
->setPropertyValues(aPropNames
, aPropValues
),
1040 lang::WrappedTargetException
);
1041 CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"),
1042 getProperty
<OUString
>(xCursorProps
, "CharStyleName"));
1045 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testShapeAllowOverlap
)
1047 // Test the AllowOverlap frame/shape property.
1049 // Create a new document and insert a rectangle.
1051 uno::Reference
<lang::XMultiServiceFactory
> xDocument(mxComponent
, uno::UNO_QUERY
);
1052 awt::Point
aPoint(1000, 1000);
1053 awt::Size
aSize(10000, 10000);
1054 uno::Reference
<drawing::XShape
> xShape(
1055 xDocument
->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY
);
1056 xShape
->setPosition(aPoint
);
1057 xShape
->setSize(aSize
);
1058 uno::Reference
<drawing::XDrawPageSupplier
> xDrawPageSupplier(xDocument
, uno::UNO_QUERY
);
1059 xDrawPageSupplier
->getDrawPage()->add(xShape
);
1061 // The property is on by default, turn it off & verify.
1062 uno::Reference
<beans::XPropertySet
> xShapeProperties(xShape
, uno::UNO_QUERY
);
1063 xShapeProperties
->setPropertyValue("AllowOverlap", uno::Any(false));
1064 CPPUNIT_ASSERT(!getProperty
<bool>(xShapeProperties
, "AllowOverlap"));
1066 // Turn it back to on & verify.
1067 xShapeProperties
->setPropertyValue("AllowOverlap", uno::Any(true));
1068 CPPUNIT_ASSERT(getProperty
<bool>(xShapeProperties
, "AllowOverlap"));
1071 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testTextConvertToTableLineSpacing
)
1073 // Load a document which has a table with a single cell.
1074 // The cell has both a table style and a paragraph style, with different line spacing
1076 createSwDoc("table-line-spacing.docx");
1077 uno::Reference
<text::XTextTablesSupplier
> xTablesSupplier(mxComponent
, uno::UNO_QUERY
);
1078 uno::Reference
<container::XIndexAccess
> xTables(xTablesSupplier
->getTextTables(),
1080 uno::Reference
<text::XTextTable
> xTable(xTables
->getByIndex(0), uno::UNO_QUERY
);
1081 uno::Reference
<table::XCell
> xCell
= xTable
->getCellByName("A1");
1082 uno::Reference
<text::XText
> xCellText(xCell
, uno::UNO_QUERY
);
1083 uno::Reference
<text::XTextRange
> xParagraph
= getParagraphOfText(1, xCellText
);
1084 style::LineSpacing aLineSpacing
1085 = getProperty
<style::LineSpacing
>(xParagraph
, "ParaLineSpacing");
1086 // Make sure that we take the line spacing from the paragraph style, not from the table style.
1087 // Without the accompanying fix in place, this test would have failed with:
1090 // I.e. the 360 twips line spacing was taken from the table style, not the 220 twips one from
1091 // the paragraph style.
1092 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16
>(convertTwipToMm100(220)), aLineSpacing
.Height
);
1095 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testMultiSelect
)
1097 // Create a new document and add a text with several repeated sequences.
1099 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, css::uno::UNO_QUERY_THROW
);
1100 auto xSimpleText
= xTextDocument
->getText();
1101 xSimpleText
->insertString(xSimpleText
->getStart(), "Abc aBc abC", false);
1103 // Create a search descriptor and find all occurencies of search string
1104 css::uno::Reference
<css::util::XSearchable
> xSearchable(mxComponent
, css::uno::UNO_QUERY_THROW
);
1105 auto xSearchDescriptor
= xSearchable
->createSearchDescriptor();
1106 xSearchDescriptor
->setPropertyValue("SearchStyles", css::uno::Any(false));
1107 xSearchDescriptor
->setPropertyValue("SearchCaseSensitive", css::uno::Any(false));
1108 xSearchDescriptor
->setPropertyValue("SearchBackwards", css::uno::Any(true));
1109 xSearchDescriptor
->setPropertyValue("SearchRegularExpression", css::uno::Any(false));
1110 xSearchDescriptor
->setSearchString("abc");
1111 auto xSearchResult
= xSearchable
->findAll(xSearchDescriptor
);
1114 auto xController
= xTextDocument
->getCurrentController();
1115 css::uno::Reference
<css::view::XSelectionSupplier
> xSelectionSupplier(
1116 xController
, css::uno::UNO_QUERY_THROW
);
1117 xSelectionSupplier
->select(css::uno::Any(xSearchResult
));
1118 css::uno::Reference
<css::container::XIndexAccess
> xSelection(xSelectionSupplier
->getSelection(),
1119 css::uno::UNO_QUERY_THROW
);
1120 // Now check that they all are selected in the reverse order ("SearchBackwards").
1121 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xSelection
->getCount());
1122 css::uno::Reference
<css::text::XTextRange
> xTextRange(xSelection
->getByIndex(0),
1123 css::uno::UNO_QUERY_THROW
);
1124 // For #0, result was empty (cursor was put before the last occurrence without selection)
1125 CPPUNIT_ASSERT_EQUAL(OUString("abC"), xTextRange
->getString());
1126 xTextRange
.set(xSelection
->getByIndex(1), css::uno::UNO_QUERY_THROW
);
1127 CPPUNIT_ASSERT_EQUAL(OUString("aBc"), xTextRange
->getString());
1128 xTextRange
.set(xSelection
->getByIndex(2), css::uno::UNO_QUERY_THROW
);
1129 CPPUNIT_ASSERT_EQUAL(OUString("Abc"), xTextRange
->getString());
1132 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testTransparentText
)
1134 // Test the CharTransparence text portion property.
1136 // Create a new document.
1139 // Set a custom transparency.
1140 uno::Reference
<beans::XPropertySet
> xParagraph(getParagraph(1), uno::UNO_QUERY
);
1141 sal_Int16 nExpected
= 42;
1142 xParagraph
->setPropertyValue("CharTransparence", uno::Any(nExpected
));
1144 // Get the transparency & verify.
1145 CPPUNIT_ASSERT_EQUAL(nExpected
, getProperty
<sal_Int16
>(xParagraph
, "CharTransparence"));
1148 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testTdf129839
)
1150 // Create a new document and add a table
1152 css::uno::Reference
<css::text::XTextDocument
> xTextDocument(mxComponent
,
1153 css::uno::UNO_QUERY_THROW
);
1154 css::uno::Reference
<css::lang::XMultiServiceFactory
> xFac(xTextDocument
,
1155 css::uno::UNO_QUERY_THROW
);
1156 css::uno::Reference
<css::text::XTextTable
> xTable(
1157 xFac
->createInstance("com.sun.star.text.TextTable"), css::uno::UNO_QUERY_THROW
);
1158 xTable
->initialize(4, 4);
1159 auto xSimpleText
= xTextDocument
->getText();
1160 xSimpleText
->insertTextContent(xSimpleText
->createTextCursor(), xTable
, true);
1161 css::uno::Reference
<css::table::XCellRange
> xTableCellRange(xTable
, css::uno::UNO_QUERY_THROW
);
1162 // Get instance of SwXCellRange
1163 css::uno::Reference
<css::beans::XPropertySet
> xCellRange(
1164 xTableCellRange
->getCellRangeByPosition(0, 0, 1, 1), css::uno::UNO_QUERY_THROW
);
1165 // Test retrieval of VertOrient property - this crashed
1166 css::uno::Any aOrient
= xCellRange
->getPropertyValue("VertOrient");
1167 CPPUNIT_ASSERT_EQUAL(css::uno::Any(css::text::VertOrientation::NONE
), aOrient
);
1170 CPPUNIT_TEST_FIXTURE(SwUnoWriter
, testTdf129841
)
1172 // Create a new document and add a table
1174 css::uno::Reference
<css::text::XTextDocument
> xTextDocument(mxComponent
,
1175 css::uno::UNO_QUERY_THROW
);
1176 css::uno::Reference
<css::lang::XMultiServiceFactory
> xFac(xTextDocument
,
1177 css::uno::UNO_QUERY_THROW
);
1178 css::uno::Reference
<css::text::XTextTable
> xTable(
1179 xFac
->createInstance("com.sun.star.text.TextTable"), css::uno::UNO_QUERY_THROW
);
1180 xTable
->initialize(4, 4);
1181 auto xSimpleText
= xTextDocument
->getText();
1182 xSimpleText
->insertTextContent(xSimpleText
->createTextCursor(), xTable
, true);
1183 // Get SwXTextTableCursor
1184 css::uno::Reference
<css::beans::XPropertySet
> xTableCursor(xTable
->createCursorByCellName("A1"),
1185 css::uno::UNO_QUERY_THROW
);
1186 css::uno::Reference
<css::table::XCellRange
> xTableCellRange(xTable
, css::uno::UNO_QUERY_THROW
);
1187 // Get SwXCellRange for the same cell
1188 css::uno::Reference
<css::beans::XPropertySet
> xCellRange(
1189 xTableCellRange
->getCellRangeByName("A1:A1"), css::uno::UNO_QUERY_THROW
);
1190 static const OUStringLiteral sBackColor
= u
"BackColor";
1191 // Apply background color to table cursor, and read background color from cell range
1192 css::uno::Any
aRefColor(sal_Int32(0x00FF0000));
1193 xTableCursor
->setPropertyValue(sBackColor
, aRefColor
);
1194 css::uno::Any aColor
= xCellRange
->getPropertyValue(sBackColor
);
1196 CPPUNIT_ASSERT_EQUAL(aRefColor
, aColor
);
1197 // Now the other way round
1198 aRefColor
<<= sal_Int32(0x0000FF00);
1199 xCellRange
->setPropertyValue(sBackColor
, aRefColor
);
1200 aColor
= xTableCursor
->getPropertyValue(sBackColor
);
1201 CPPUNIT_ASSERT_EQUAL(aRefColor
, aColor
);
1204 CPPUNIT_PLUGIN_IMPLEMENT();
1206 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */