Use COMReference to handle COM pointers in CreateShortcut
[LibreOffice.git] / sw / qa / core / text / itrform2.cxx
blobdea8ddcc9489ac69bf6679971568939692c89aae
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <swmodeltestbase.hxx>
12 #include <memory>
14 #include <com/sun/star/text/XTextDocument.hpp>
16 #include <comphelper/propertyvalue.hxx>
17 #include <editeng/colritem.hxx>
18 #include <sfx2/viewfrm.hxx>
19 #include <sfx2/dispatch.hxx>
21 #include <IDocumentLayoutAccess.hxx>
22 #include <rootfrm.hxx>
23 #include <sortedobjs.hxx>
24 #include <pagefrm.hxx>
25 #include <cntfrm.hxx>
26 #include <docsh.hxx>
27 #include <wrtsh.hxx>
28 #include <formatcontentcontrol.hxx>
29 #include <textcontentcontrol.hxx>
30 #include <view.hxx>
31 #include <cmdid.h>
33 namespace
35 /// Covers sw/source/core/text/itrform2.cxx fixes.
36 class Test : public SwModelTestBase
38 public:
39 Test()
40 : SwModelTestBase(u"/sw/qa/core/text/data/"_ustr)
45 CPPUNIT_TEST_FIXTURE(Test, testFloattableWrapEmptyParagraph)
47 // Given a document with 2 pages, a floating table on both pages:
48 createSwDoc("floattable-wrap-empty-para.docx");
50 // When calculating the layout:
51 calcLayout();
53 // Then make sure that each page has exactly 1 floating table:
54 SwDoc* pDoc = getSwDoc();
55 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
56 auto pPage = dynamic_cast<SwPageFrame*>(pLayout->Lower());
57 CPPUNIT_ASSERT(pPage);
58 CPPUNIT_ASSERT(pPage->GetSortedObjs());
59 const SwSortedObjs& rPageObjs = *pPage->GetSortedObjs();
60 // Without the accompanying fix in place, this test would have failed with:
61 // - Expected: 1
62 // - Actual : 2
63 // i.e. both tables were on page 1, leading to an overlap.
64 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs.size());
65 auto pPage2 = dynamic_cast<SwPageFrame*>(pPage->GetNext());
66 CPPUNIT_ASSERT(pPage2);
67 CPPUNIT_ASSERT(pPage2->GetSortedObjs());
68 const SwSortedObjs& rPageObjs2 = *pPage2->GetSortedObjs();
69 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs2.size());
72 CPPUNIT_TEST_FIXTURE(Test, testFloattableLegacyWrapEmptyParagraph)
74 // Given a document with 2 pages, a floating table on both pages (from DOC, so the table is
75 // shifted towards the left page edge slightly):
76 createSwDoc("floattable-wrap-empty-para-legacy.docx");
78 // When calculating the layout:
79 calcLayout();
81 // Then make sure that each page has exactly 1 floating table:
82 SwDoc* pDoc = getSwDoc();
83 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
84 auto pPage = dynamic_cast<SwPageFrame*>(pLayout->Lower());
85 CPPUNIT_ASSERT(pPage);
86 CPPUNIT_ASSERT(pPage->GetSortedObjs());
87 const SwSortedObjs& rPageObjs = *pPage->GetSortedObjs();
88 // Without the accompanying fix in place, this test would have failed with:
89 // - Expected: 1
90 // - Actual : 2
91 // i.e. both tables were on page 1, leading to an overlap.
92 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs.size());
93 auto pPage2 = dynamic_cast<SwPageFrame*>(pPage->GetNext());
94 CPPUNIT_ASSERT(pPage2);
95 CPPUNIT_ASSERT(pPage2->GetSortedObjs());
96 const SwSortedObjs& rPageObjs2 = *pPage2->GetSortedObjs();
97 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs2.size());
100 CPPUNIT_TEST_FIXTURE(Test, testApplyTextAttrToEmptyLineAtEndOfParagraph)
102 createSwDoc("A011-charheight.rtf");
104 calcLayout();
106 SwDoc* pDoc = getSwDoc();
107 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
108 auto pPage = dynamic_cast<SwPageFrame*>(pLayout->Lower());
110 SwContentFrame* pLastPara = pPage->FindLastBodyContent();
111 // wrong was 449 (11.5pt)
112 CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(368), pLastPara->getFrameArea().Height());
113 SwContentFrame* pFirstPara = pPage->FindFirstBodyContent();
114 // wrong was 817 (11.5pt)
115 CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(736), pFirstPara->getFrameArea().Height());
118 CPPUNIT_TEST_FIXTURE(Test, testFlyMinimalWrap)
120 // Given a document with a first page that has a shape and a table in it (not floating table),
121 // some empty paragraphs wrapping around the shape:
122 createSwDoc("fly-minimal-wrap.docx");
124 // When calculating the layout:
125 calcLayout();
127 // Then make sure the wrap happens, so the 2nd page only has 2 paragraphs:
128 SwDoc* pDoc = getSwDoc();
129 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
130 auto pPage = dynamic_cast<SwPageFrame*>(pLayout->Lower());
131 CPPUNIT_ASSERT(pPage);
132 CPPUNIT_ASSERT(pPage->GetSortedObjs());
133 const SwSortedObjs& rPageObjs = *pPage->GetSortedObjs();
134 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPageObjs.size());
135 auto pPage2 = dynamic_cast<SwPageFrame*>(pPage->GetNext());
136 CPPUNIT_ASSERT(pPage2);
137 CPPUNIT_ASSERT(!pPage2->GetSortedObjs());
138 SwLayoutFrame* pBody2 = pPage2->FindBodyCont();
139 SwFrame* pPage2Para1 = pBody2->GetLower();
140 CPPUNIT_ASSERT(pPage2Para1);
141 SwFrame* pPage2Para2 = pPage2Para1->GetNext();
142 CPPUNIT_ASSERT(pPage2Para2);
143 // Without the accompanying fix in place, this test would have failed, the second page had 19
144 // text frames in the body frame, not 2.
145 CPPUNIT_ASSERT(!pPage2Para2->GetNext());
148 CPPUNIT_TEST_FIXTURE(Test, testContentControlHeaderPDFExport)
150 // Given a document with a content control in the header:
151 createSwDoc("content-control-header.docx");
153 // When exporting to PDF:
154 save(u"writer_pdf_Export"_ustr);
156 // Then make sure all the expected text is there on page 2:
157 std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport();
158 if (!pPdfDocument)
160 return;
162 std::unique_ptr<vcl::pdf::PDFiumPage> pPage2 = pPdfDocument->openPage(1);
163 int nTextCount = 0;
164 for (int i = 0; i < pPage2->getObjectCount(); ++i)
166 std::unique_ptr<vcl::pdf::PDFiumPageObject> pObject = pPage2->getObject(i);
167 if (pObject->getType() == vcl::pdf::PDFPageObjectType::Text)
169 ++nTextCount;
172 // Without the accompanying fix in place, this test would have failed with:
173 // - Expected: 3
174 // - Actual : 2
175 // i.e. not all of header, heading and body text was there on page 2, content was lost.
176 CPPUNIT_ASSERT_EQUAL(3, nTextCount);
179 CPPUNIT_TEST_FIXTURE(Test, testSplitFlyAnchorLeftMargin)
181 // Given a document with a floating table, anchor para is followed by another para with a left
182 // margin:
183 createSwDoc("floattable-anchor-left-margin.docx");
185 // When laying out that document:
186 calcLayout();
188 // Then make sure that the left margin of this last paragraph is not lost:
189 SwDoc* pDoc = getSwDoc();
190 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
191 auto pPage = dynamic_cast<SwPageFrame*>(pLayout->Lower());
192 CPPUNIT_ASSERT(pPage);
193 SwContentFrame* pLastPara = pPage->FindLastBodyContent();
194 // Without the accompanying fix in place, this test would have failed with:
195 // - Expected: 6480
196 // - Actual : 0
197 // i.e. the left margin was lost.
198 CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(6480), pLastPara->getFramePrintArea().Left());
201 CPPUNIT_TEST_FIXTURE(Test, testCheckedCheckboxContentControlPDF)
203 std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
204 if (!pPDFium)
205 return;
207 SwExportFormFieldsGuard g;
208 // Given a file with a checked checkbox content control:
209 createSwDoc();
210 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
211 pWrtShell->InsertContentControl(SwContentControlType::CHECKBOX);
212 // Toggle it, so we get a checked one:
213 SwTextContentControl* pTextContentControl = pWrtShell->CursorInsideContentControl();
214 const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
215 pWrtShell->GotoContentControl(rFormatContentControl);
217 // When exporting to PDF:
218 save(u"writer_pdf_Export"_ustr);
220 // Then make sure that a checked checkbox form widget is emitted:
221 std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport();
222 std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0);
223 CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount());
224 std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0);
225 CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Widget, pAnnotation->getSubType());
226 CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFFormFieldType::CheckBox,
227 pAnnotation->getFormFieldType(pPdfDocument.get()));
228 OUString aActual = pAnnotation->getFormFieldValue(pPdfDocument.get());
229 // Without the accompanying fix in place, this test would have failed with:
230 // - Expected: Yes
231 // - Actual : Off
232 // i.e. the /AP -> /N key of the checkbox widget annotation object didn't have a sub-key that
233 // would match /V, leading to not showing the checked state.
234 CPPUNIT_ASSERT_EQUAL(u"Yes"_ustr, aActual);
237 CPPUNIT_TEST_FIXTURE(Test, testContentControlPDFFontColor)
239 std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
240 if (!pPDFium)
241 return;
243 SwExportFormFieldsGuard g;
244 // Given a document with a custom orange font color and a content control:
245 createSwDoc();
246 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
247 SfxItemSetFixed<RES_CHRATR_COLOR, RES_CHRATR_COLOR> aSet(pWrtShell->GetAttrPool());
248 Color nOrange(0xff6b00);
249 SvxColorItem aItem(nOrange, RES_CHRATR_COLOR);
250 aSet.Put(aItem);
251 pWrtShell->SetAttrSet(aSet);
252 pWrtShell->InsertContentControl(SwContentControlType::RICH_TEXT);
254 // When exporting that document to PDF:
255 save(u"writer_pdf_Export"_ustr);
257 // Then make sure that the widget in the PDF result has that custom font color:
258 std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport();
259 std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0);
260 pPage->onAfterLoadPage(pPdfDocument.get());
261 CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount());
262 std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0);
263 // Without the accompanying fix in place, this test would have failed with:
264 // - Expected: rgba[ff6b00ff]
265 // - Actual : rgba[000000ff]
266 // i.e. the custom color was lost, the font color was black, not orange.
267 CPPUNIT_ASSERT_EQUAL(nOrange, pAnnotation->getFontColor(pPdfDocument.get()));
270 CPPUNIT_TEST_FIXTURE(Test, testContentControlPDFDropDownText)
272 std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
273 if (!pPDFium)
274 return;
276 SwExportFormFieldsGuard g;
277 // Given a document with a dropdown: custom default text and 3 items:
278 createSwDoc();
279 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
280 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
281 uno::Reference<text::XText> xText = xTextDocument->getText();
282 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
283 xText->insertString(xCursor, u"test"_ustr, /*bAbsorb=*/false);
284 xCursor->gotoStart(/*bExpand=*/false);
285 xCursor->gotoEnd(/*bExpand=*/true);
286 uno::Reference<text::XTextContent> xContentControl(
287 xMSF->createInstance(u"com.sun.star.text.ContentControl"_ustr), uno::UNO_QUERY);
288 uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
290 uno::Sequence<beans::PropertyValues> aListItems = {
292 comphelper::makePropertyValue(u"DisplayText"_ustr, uno::Any(u"red"_ustr)),
293 comphelper::makePropertyValue(u"Value"_ustr, uno::Any(u"R"_ustr)),
296 comphelper::makePropertyValue(u"DisplayText"_ustr, uno::Any(u"green"_ustr)),
297 comphelper::makePropertyValue(u"Value"_ustr, uno::Any(u"G"_ustr)),
300 comphelper::makePropertyValue(u"DisplayText"_ustr, uno::Any(u"blue"_ustr)),
301 comphelper::makePropertyValue(u"Value"_ustr, uno::Any(u"B"_ustr)),
304 xContentControlProps->setPropertyValue(u"ListItems"_ustr, uno::Any(aListItems));
306 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
308 // When exporting that to PDF:
309 save(u"writer_pdf_Export"_ustr);
311 // Then make sure that the custom default is not lost:
312 std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport();
313 std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0);
314 pPage->onAfterLoadPage(pPdfDocument.get());
315 CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount());
316 std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0);
317 // Without the accompanying fix in place, this test would have failed with:
318 // - Expected: 4
319 // - Actual : 3
320 // i.e. only the 3 colors were exported, the default "test" text was not.
321 CPPUNIT_ASSERT_EQUAL(4, pAnnotation->getOptionCount(pPdfDocument.get()));
324 CPPUNIT_TEST_FIXTURE(Test, testContentControlPDFComments)
326 std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
327 if (!pPDFium)
328 return;
330 // Given a document with both a content control and a comment:
331 createSwDoc();
332 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
333 pWrtShell->InsertContentControl(SwContentControlType::RICH_TEXT);
334 pWrtShell->SttEndDoc(/*bStt=*/false);
335 SwDocShell* pDocShell = getSwDocShell();
336 SwView* pView = pDocShell->GetView();
337 pView->GetViewFrame().GetDispatcher()->Execute(FN_POSTIT, SfxCallMode::SYNCHRON);
339 // When exporting to PDF, exporting notes in master (and not as widgets):
340 uno::Sequence<beans::PropertyValue> aFilterData = {
341 comphelper::makePropertyValue(u"ExportFormFields"_ustr, true),
342 comphelper::makePropertyValue(u"ExportNotes"_ustr, false),
343 comphelper::makePropertyValue(u"ExportNotesInMargin"_ustr, true),
345 saveWithParams({
346 comphelper::makePropertyValue(u"FilterName"_ustr, u"writer_pdf_Export"_ustr),
347 comphelper::makePropertyValue(u"FilterData"_ustr, aFilterData),
350 // Then make sure the only widget for the content control has a correct position:
351 std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport();
352 std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0);
353 pPage->onAfterLoadPage(pPdfDocument.get());
354 CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount());
355 std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0);
356 basegfx::B2DPoint aAnnotTopLeft = pAnnotation->getRectangle().getMinimum();
357 // Without the accompanying fix in place, this test would have failed with:
358 // - Expected: (41.749, 639.401)
359 // - Actual : (59.249,716.951)
360 // i.e. the content control rectangle was shifted towards the top right of the page, compared to
361 // where it's expected.
362 CPPUNIT_ASSERT_DOUBLES_EQUAL(41.749, aAnnotTopLeft.getX(), 0.001);
363 CPPUNIT_ASSERT_DOUBLES_EQUAL(639.401, aAnnotTopLeft.getY(), 0.001);
367 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */