Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / qa / uibase / shells / shells.cxx
blob6543f8f4fcb7efc795afa4683db026f795393590
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 <com/sun/star/frame/XStorable.hpp>
13 #include <com/sun/star/packages/zip/ZipFileAccess.hpp>
14 #include <com/sun/star/text/BibliographyDataType.hpp>
15 #include <com/sun/star/text/XTextDocument.hpp>
17 #include <sfx2/dispatch.hxx>
18 #include <sfx2/viewfrm.hxx>
19 #include <svx/svdpage.hxx>
20 #include <editeng/eeitem.hxx>
21 #include <editeng/adjustitem.hxx>
22 #include <editeng/outlobj.hxx>
23 #include <editeng/editobj.hxx>
24 #include <comphelper/processfactory.hxx>
25 #include <comphelper/propertyvalue.hxx>
26 #include <unotools/ucbstreamhelper.hxx>
27 #include <xmloff/odffields.hxx>
28 #include <comphelper/string.hxx>
29 #include <comphelper/propertysequence.hxx>
30 #include <comphelper/sequence.hxx>
31 #include <osl/thread.hxx>
33 #include <IDocumentContentOperations.hxx>
34 #include <cmdid.h>
35 #include <fmtanchr.hxx>
36 #include <view.hxx>
37 #include <wrtsh.hxx>
38 #include <IDocumentDrawModelAccess.hxx>
39 #include <drawdoc.hxx>
40 #include <docsh.hxx>
41 #include <ndtxt.hxx>
42 #include <ftnidx.hxx>
43 #include <txtftn.hxx>
45 /// Covers sw/source/uibase/shells/ fixes.
46 class SwUibaseShellsTest : public SwModelTestBase
48 public:
49 SwUibaseShellsTest()
50 : SwModelTestBase("/sw/qa/uibase/shells/data/")
55 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testTdf130179)
57 createSwDoc();
58 SwDoc* pDoc = getSwDoc();
59 IDocumentContentOperations& rIDCO = pDoc->getIDocumentContentOperations();
60 SwCursorShell* pShell(pDoc->GetEditShell());
61 SfxItemSet aFrameSet(pDoc->GetAttrPool(), svl::Items<RES_FRMATR_BEGIN, RES_FRMATR_END - 1>);
62 SfxItemSet aGrfSet(pDoc->GetAttrPool(), svl::Items<RES_GRFATR_BEGIN, RES_GRFATR_END - 1>);
63 SwFormatAnchor aAnchor(RndStdIds::FLY_AT_PARA);
64 aFrameSet.Put(aAnchor);
65 Graphic aGrf;
66 CPPUNIT_ASSERT(rIDCO.InsertGraphic(*pShell->GetCursor(), OUString(), OUString(), &aGrf,
67 &aFrameSet, &aGrfSet, nullptr));
68 CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_GRF));
70 SwView* pView = pDoc->GetDocShell()->GetView();
71 selectShape(1);
73 std::unique_ptr<SfxPoolItem> pItem;
74 pView->GetViewFrame().GetBindings().QueryState(FN_POSTIT, pItem);
75 // Without the accompanying fix in place, this test would have failed with:
76 // assertion failed
77 // - Expression: !pItem
78 // i.e. comment insertion was enabled for an at-para anchored image.
79 CPPUNIT_ASSERT(!pItem);
82 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testShapeTextAlignment)
84 // FIXME find out why this fails on macOS/Windows
85 #if !defined(MACOSX) && !defined(_WIN32)
86 // Create a document with a rectangle in it.
87 createSwDoc();
88 SwDoc* pDoc = getSwDoc();
89 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
90 Point aStartPos(1000, 1000);
91 pWrtShell->BeginCreate(SdrObjKind::Rectangle, aStartPos);
92 Point aMovePos(2000, 2000);
93 pWrtShell->MoveCreate(aMovePos);
94 pWrtShell->EndCreate(SdrCreateCmd::ForceEnd);
96 // Start shape text edit.
97 SwView* pView = pDoc->GetDocShell()->GetView();
98 // Select the shape.
99 selectShape(1);
100 // Start the actual text edit.
101 SdrPage* pPage = pWrtShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
102 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pPage->GetObjCount());
103 SdrObject* pObject = pPage->GetObj(0);
104 pView->EnterShapeDrawTextMode(pObject);
105 pView->AttrChangedNotify(nullptr);
107 // Change paragraph adjustment to center.
108 pView->GetViewFrame().GetDispatcher()->Execute(SID_ATTR_PARA_ADJUST_CENTER,
109 SfxCallMode::SYNCHRON);
111 // End shape text edit.
112 pWrtShell->EndTextEdit();
114 const OutlinerParaObject* pOutliner = pObject->GetOutlinerParaObject();
115 // Without the accompanying fix in place, this test would have failed, because the shape had no
116 // text or text formatting. In other words the paragraph adjustment command was ignored.
117 CPPUNIT_ASSERT(pOutliner);
118 const SfxItemSet& rParaAttribs = pOutliner->GetTextObject().GetParaAttribs(0);
119 SvxAdjust eAdjust = rParaAttribs.GetItem(EE_PARA_JUST)->GetAdjust();
120 CPPUNIT_ASSERT_EQUAL(SvxAdjust::Center, eAdjust);
121 #endif
124 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testOleSavePreviewUpdate)
126 // Load a document with 2 charts in it. The second is down enough that you have to scroll to
127 // trigger its rendering. Previews are missing for both.
128 createSwDoc("ole-save-preview-update.odt");
130 // Explicitly update OLE previews, etc.
131 dispatchCommand(mxComponent, ".uno:UpdateAll", {});
133 // Save the document and see if we get the previews.
134 uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
135 xStorable->storeToURL(maTempFile.GetURL(), {});
136 uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
137 = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory),
138 maTempFile.GetURL());
140 // Without the accompanying fix in place, this test would have failed, because the object
141 // replacements were not generated, even after UpdateAll.
142 CPPUNIT_ASSERT(xNameAccess->hasByName("ObjectReplacements/Object 1"));
143 CPPUNIT_ASSERT(xNameAccess->hasByName("ObjectReplacements/Object 2"));
146 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testOlePreviewUpdate)
148 // Given a document with an embedded Writer object:
149 createSwDoc("ole-preview-update.odt");
151 // When updating "all" (including OLE previews):
152 dispatchCommand(mxComponent, ".uno:UpdateAll", {});
154 // Then make sure the preview is no longer a 0-sized stream:
155 uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
156 xStorable->storeToURL(maTempFile.GetURL(), {});
157 uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
158 = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory),
159 maTempFile.GetURL());
160 uno::Reference<io::XInputStream> xInputStream(
161 xNameAccess->getByName("ObjectReplacements/Object 1"), uno::UNO_QUERY);
162 std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
163 // Without the accompanying fix in place, this test would have failed, the stream was still
164 // empty.
165 CPPUNIT_ASSERT_GREATER(static_cast<sal_uInt64>(0), pStream->remainingSize());
168 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testBibliographyUrlContextMenu)
170 // Given a document with a bibliography field:
171 createSwDoc();
172 SwDoc* pDoc = getSwDoc();
173 uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
174 uno::Reference<beans::XPropertySet> xField(
175 xFactory->createInstance("com.sun.star.text.TextField.Bibliography"), uno::UNO_QUERY);
176 uno::Sequence<beans::PropertyValue> aFields = {
177 comphelper::makePropertyValue("BibiliographicType", text::BibliographyDataType::WWW),
178 comphelper::makePropertyValue("Identifier", OUString("AT")),
179 comphelper::makePropertyValue("Author", OUString("Author")),
180 comphelper::makePropertyValue("Title", OUString("Title")),
181 comphelper::makePropertyValue("URL", OUString("http://www.example.com/test.pdf#page=1")),
183 xField->setPropertyValue("Fields", uno::Any(aFields));
184 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
185 uno::Reference<text::XText> xText = xTextDocument->getText();
186 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
187 uno::Reference<text::XTextContent> xContent(xField, uno::UNO_QUERY);
188 xText->insertTextContent(xCursor, xContent, /*bAbsorb=*/false);
190 // When selecting the field and opening the context menu:
191 SwDocShell* pDocShell = pDoc->GetDocShell();
192 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
193 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, /*bBasicCall=*/false);
194 SfxDispatcher* pDispatcher = pDocShell->GetViewShell()->GetViewFrame().GetDispatcher();
195 css::uno::Any aState;
196 SfxItemState eStateOpen = pDispatcher->QueryState(SID_OPEN_HYPERLINK, aState);
197 SfxItemState eStateCopy = pDispatcher->QueryState(SID_COPY_HYPERLINK_LOCATION, aState);
199 // Then the "open hyperlink" and "copy hyperlink location" menu items should be visible:
200 // Without the accompanying fix in place, this test would have failed with:
201 // - Expected: 32 (SfxItemState::DEFAULT)
202 // - Actual : 1 (SfxItemState::DISABLED)
203 // i.e. the menu item was not visible for biblio entry fields with an URL.
204 CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, eStateOpen);
205 CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, eStateCopy);
208 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testProtectedFieldsCopyHyperlinkLocation)
210 // Given a test document document that contains:
211 // - generic url
212 // - empty line
213 // - bibliography mark
214 // - empty line
215 // - generic url
216 // - empty line
217 // - bibliography table heading
218 // - bibliography entry containing only url
219 // - empty line
220 createSwDoc("protectedLinkCopy.fodt");
222 // Copy generic hyperlink
223 dispatchCommand(mxComponent, ".uno:CopyHyperlinkLocation", {});
224 dispatchCommand(mxComponent, ".uno:GoDown", {});
225 dispatchCommand(mxComponent, ".uno:Paste", {});
226 // Assert generic hyperlink was correctly copied and pasted
227 CPPUNIT_ASSERT_EQUAL(OUString("http://reset.url/1"), getParagraph(2)->getString());
229 dispatchCommand(mxComponent, ".uno:GoDown", {});
230 dispatchCommand(mxComponent, ".uno:GoLeft", {});
231 // Copy bibliography mark hyperlink
232 dispatchCommand(mxComponent, ".uno:CopyHyperlinkLocation", {});
233 dispatchCommand(mxComponent, ".uno:GoDown", {});
234 dispatchCommand(mxComponent, ".uno:Paste", {});
235 // Assert bibliography mark hyperlink was correctly copied and pasted
236 CPPUNIT_ASSERT_EQUAL(OUString("https://test.url/1"), getParagraph(4)->getString());
238 dispatchCommand(mxComponent, ".uno:GoDown", {});
239 dispatchCommand(mxComponent, ".uno:GoLeft", {});
240 // Copy generic hyperlink
241 dispatchCommand(mxComponent, ".uno:CopyHyperlinkLocation", {});
242 dispatchCommand(mxComponent, ".uno:GoDown", {});
243 dispatchCommand(mxComponent, ".uno:Paste", {});
244 // Assert generic hyperlink was correctly copied and pasted
245 CPPUNIT_ASSERT_EQUAL(OUString("http://reset.url/2"), getParagraph(6)->getString());
247 dispatchCommand(mxComponent, ".uno:GoDown", {});
248 dispatchCommand(mxComponent, ".uno:GoDown", {});
249 dispatchCommand(mxComponent, ".uno:GoLeft", {});
250 // Copy bibliography table hyperlink
251 dispatchCommand(mxComponent, ".uno:CopyHyperlinkLocation", {});
252 dispatchCommand(mxComponent, ".uno:GoDown", {});
253 dispatchCommand(mxComponent, ".uno:Paste", {});
254 // Assert bibliography table entry hyperlink was correctly copied and pasted
255 CPPUNIT_ASSERT_EQUAL(OUString("https://test.url/1"), getParagraph(9)->getString());
258 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testBibliographyLocalCopyContextMenu)
260 // Given a document with a bibliography field's local copy:
261 createSwDoc();
262 SwDoc* pDoc = getSwDoc();
263 uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
264 uno::Reference<beans::XPropertySet> xField(
265 xFactory->createInstance("com.sun.star.text.TextField.Bibliography"), uno::UNO_QUERY);
266 uno::Sequence<beans::PropertyValue> aFields = {
267 comphelper::makePropertyValue("BibiliographicType", text::BibliographyDataType::WWW),
268 comphelper::makePropertyValue("Identifier", OUString("AT")),
269 comphelper::makePropertyValue("Author", OUString("Author")),
270 comphelper::makePropertyValue("Title", OUString("Title")),
271 comphelper::makePropertyValue("URL", OUString("http://www.example.com/test.pdf#page=1")),
272 comphelper::makePropertyValue("LocalURL", OUString("file:///home/me/test.pdf")),
274 xField->setPropertyValue("Fields", uno::Any(aFields));
275 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
276 uno::Reference<text::XText> xText = xTextDocument->getText();
277 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
278 uno::Reference<text::XTextContent> xContent(xField, uno::UNO_QUERY);
279 xText->insertTextContent(xCursor, xContent, /*bAbsorb=*/false);
281 // When selecting the field and opening the context menu:
282 SwDocShell* pDocShell = pDoc->GetDocShell();
283 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
284 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, /*bBasicCall=*/false);
285 SfxDispatcher* pDispatcher = pDocShell->GetViewShell()->GetViewFrame().GetDispatcher();
286 css::uno::Any aState;
287 SfxItemState eState = pDispatcher->QueryState(FN_OPEN_LOCAL_URL, aState);
289 // Then the "open local copy" menu item should be visible:
290 // Without the accompanying fix in place, this test would have failed with:
291 // - Expected: 32 (SfxItemState::DEFAULT)
292 // - Actual : 1 (SfxItemState::DISABLED)
293 // i.e. the context menu was disabled all the time, even for biblio fields.
294 CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, eState);
297 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testContentControlPageBreak)
299 // Given a document with a content control and a cursor inside the content control:
300 createSwDoc();
301 SwDoc* pDoc = getSwDoc();
302 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
303 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
304 uno::Reference<text::XText> xText = xTextDocument->getText();
305 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
306 xText->insertString(xCursor, "test", /*bAbsorb=*/false);
307 xCursor->gotoStart(/*bExpand=*/false);
308 xCursor->gotoEnd(/*bExpand=*/true);
309 uno::Reference<text::XTextContent> xContentControl(
310 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
311 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
312 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
313 pWrtShell->SttEndDoc(/*bStt=*/true);
314 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
316 // When trying to insert a page break:
317 dispatchCommand(mxComponent, ".uno:InsertPagebreak", {});
319 // Then make sure that the document still has a single page:
320 // Without the accompanying fix in place, this test would have failed with:
321 // - Expected: 1
322 // - Actual : 2
323 // i.e. inline content control had its start and end in different text nodes, which is not
324 // allowed.
325 CPPUNIT_ASSERT_EQUAL(1, getPages());
328 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testInsertTextFormField)
330 // Given an empty document:
331 createSwDoc();
332 SwDoc* pDoc = getSwDoc();
334 // When inserting an ODF_UNHANDLED fieldmark:
335 OUString aExpectedCommand("ADDIN ZOTERO_BIBL foo bar");
336 uno::Sequence<css::beans::PropertyValue> aArgs = {
337 comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
338 comphelper::makePropertyValue("FieldCommand", uno::Any(aExpectedCommand)),
339 comphelper::makePropertyValue("FieldResult", uno::Any(OUString("<p>aaa</p><p>bbb</p>"))),
341 dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
343 // Then make sure that it's type/name is correct:
344 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
345 SwCursor* pCursor = pWrtShell->GetCursor();
346 pCursor->SttEndDoc(/*bSttDoc=*/true);
347 sw::mark::IFieldmark* pFieldmark
348 = pDoc->getIDocumentMarkAccess()->getFieldmarkAt(*pCursor->GetPoint());
349 CPPUNIT_ASSERT(pFieldmark);
350 // Without the accompanying fix in place, this test would have failed with:
351 // - Expected: vnd.oasis.opendocument.field.UNHANDLED
352 // - Actual : vnd.oasis.opendocument.field.FORMTEXT
353 // i.e. the custom type parameter was ignored.
354 CPPUNIT_ASSERT_EQUAL(OUString(ODF_UNHANDLED), pFieldmark->GetFieldname());
356 auto it = pFieldmark->GetParameters()->find(ODF_CODE_PARAM);
357 CPPUNIT_ASSERT(it != pFieldmark->GetParameters()->end());
358 OUString aActualCommand;
359 it->second >>= aActualCommand;
360 CPPUNIT_ASSERT_EQUAL(aExpectedCommand, aActualCommand);
362 SwPaM aPam(pFieldmark->GetMarkStart(), pFieldmark->GetMarkEnd());
363 // Ignore the leading field start + sep.
364 aPam.GetMark()->SetContent(aPam.GetMark()->GetContentIndex() + 2);
365 // Ignore the trailing field end.
366 aPam.GetPoint()->SetContent(aPam.GetPoint()->GetContentIndex() - 1);
367 CPPUNIT_ASSERT(aPam.HasMark());
368 OUString aActualResult = aPam.GetText();
369 CPPUNIT_ASSERT_EQUAL(OUString("aaa\nbbb"), aActualResult);
372 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateFieldmarks)
374 // Given a document with 2 fieldmarks:
375 createSwDoc();
377 uno::Sequence<css::beans::PropertyValue> aArgs = {
378 comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
379 comphelper::makePropertyValue("FieldCommand",
380 uno::Any(OUString("ADDIN ZOTERO_ITEM old command 1"))),
381 comphelper::makePropertyValue("FieldResult", uno::Any(OUString("old result 1"))),
383 dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
386 uno::Sequence<css::beans::PropertyValue> aArgs = {
387 comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
388 comphelper::makePropertyValue("FieldCommand",
389 uno::Any(OUString("ADDIN ZOTERO_ITEM old command 2"))),
390 comphelper::makePropertyValue("FieldResult", uno::Any(OUString("old result 2"))),
392 dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
395 // When updating those fieldmarks:
396 uno::Sequence<css::beans::PropertyValue> aField1{
397 comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
398 comphelper::makePropertyValue("FieldCommand",
399 uno::Any(OUString("ADDIN ZOTERO_ITEM new command 1"))),
400 comphelper::makePropertyValue("FieldResult", uno::Any(OUString("new result 1"))),
402 uno::Sequence<css::beans::PropertyValue> aField2{
403 comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
404 comphelper::makePropertyValue("FieldCommand",
405 uno::Any(OUString("ADDIN ZOTERO_ITEM new command 2"))),
406 comphelper::makePropertyValue("FieldResult", uno::Any(OUString("new result 2"))),
408 uno::Sequence<uno::Sequence<css::beans::PropertyValue>> aFields = { aField1, aField2 };
409 uno::Sequence<css::beans::PropertyValue> aArgs = {
410 comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
411 comphelper::makePropertyValue("FieldCommandPrefix",
412 uno::Any(OUString("ADDIN ZOTERO_ITEM"))),
413 comphelper::makePropertyValue("Fields", uno::Any(aFields)),
415 dispatchCommand(mxComponent, ".uno:TextFormFields", aArgs);
417 // Then make sure that the document text contains the new field results:
418 SwDoc* pDoc = getSwDoc();
419 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
420 pWrtShell->SttEndDoc(/*bStt=*/true);
421 SwCursor* pCursor = pWrtShell->GetCursor();
422 OUString aActual = pCursor->Start()->GetNode().GetTextNode()->GetText();
423 static sal_Unicode const aForbidden[]
424 = { CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDSEP, CH_TXT_ATR_FIELDEND, 0 };
425 aActual = comphelper::string::removeAny(aActual, aForbidden);
426 // Without the accompanying fix in place, this test would have failed with:
427 // - Expected: new result 1new result 2
428 // - Actual : old result 1old result 2
429 // i.e. the fieldmarks were not updated.
430 CPPUNIT_ASSERT_EQUAL(OUString("new result 1new result 2"), aActual);
433 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testInsertBookmark)
435 // Given an empty document:
436 createSwDoc();
437 SwDoc* pDoc = getSwDoc();
439 // When inserting a bookmark with text:
440 OUString aExpectedBookmarkName("ZOTERO_BREF_GiQ7DAWQYWLy");
441 uno::Sequence<css::beans::PropertyValue> aArgs = {
442 comphelper::makePropertyValue("Bookmark", uno::Any(aExpectedBookmarkName)),
443 comphelper::makePropertyValue("BookmarkText", uno::Any(OUString("<p>aaa</p><p>bbb</p>"))),
445 dispatchCommand(mxComponent, ".uno:InsertBookmark", aArgs);
447 // Then make sure that we create a bookmark that covers that text:
448 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
449 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), rIDMA.getBookmarksCount());
450 for (auto it = rIDMA.getBookmarksBegin(); it != rIDMA.getBookmarksEnd(); ++it)
452 sw::mark::IMark* pMark = *it;
453 CPPUNIT_ASSERT_EQUAL(aExpectedBookmarkName, pMark->GetName());
454 SwPaM aPam(pMark->GetMarkStart(), pMark->GetMarkEnd());
455 OUString aActualResult = aPam.GetText();
456 // Without the accompanying fix in place, this test would have failed with:
457 // - Expected: aaa\nbbb
458 // - Actual :
459 // i.e. no text was inserted, the bookmark was collapsed.
460 CPPUNIT_ASSERT_EQUAL(OUString("aaa\nbbb"), aActualResult);
464 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testGotoMark)
466 // Given a document with 2 paragraphs, a bookmark on the second one:
467 createSwDoc();
468 SwDoc* pDoc = getSwDoc();
469 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
470 pWrtShell->SplitNode();
471 pWrtShell->SttEndDoc(/*bStt=*/false);
472 pWrtShell->SetBookmark(vcl::KeyCode(), "mybookmark");
473 SwNodeOffset nExpected = pWrtShell->GetCursor()->GetPointNode().GetIndex();
475 // When jumping to that mark from the doc start:
476 pWrtShell->SttEndDoc(/*bStt=*/true);
477 uno::Sequence<css::beans::PropertyValue> aArgs = {
478 comphelper::makePropertyValue("GotoMark", uno::Any(OUString("mybookmark"))),
480 dispatchCommand(mxComponent, ".uno:GotoMark", aArgs);
482 // Then make sure that the final cursor position is at the bookmark:
483 SwNodeOffset nActual = pWrtShell->GetCursor()->GetPointNode().GetIndex();
484 // Without the accompanying fix in place, this test would have failed with:
485 // - Expected: 10 (bookmark)
486 // - Actual : 9 (doc start)
487 // i.e. the actual jump didn't happen.
488 CPPUNIT_ASSERT_EQUAL(nExpected, nActual);
491 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateBookmarks)
493 // Given a document with 2 bookmarks, first covering "B" and second covering "D":
494 createSwDoc();
495 SwDoc* pDoc = getSwDoc();
496 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
497 pWrtShell->Insert("ABCDE");
498 pWrtShell->SttEndDoc(/*bStt=*/true);
499 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
500 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, /*bBasicCall=*/false);
501 pWrtShell->SetBookmark(vcl::KeyCode(), "ZOTERO_BREF_GiQ7DAWQYWLy");
502 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
503 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, /*bBasicCall=*/false);
504 pWrtShell->SetBookmark(vcl::KeyCode(), "ZOTERO_BREF_PRxDGUb4SWXF");
506 // When updating the content of bookmarks:
507 pWrtShell->SttEndDoc(/*bStt=*/true);
508 std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
510 "BookmarkNamePrefix": {
511 "type": "string",
512 "value": "ZOTERO_BREF_"
514 "Bookmarks": {
515 "type": "[][]com.sun.star.beans.PropertyValue",
516 "value": [
518 "Bookmark": {
519 "type": "string",
520 "value": "ZOTERO_BREF_new1"
522 "BookmarkText": {
523 "type": "string",
524 "value": "new result 1"
528 "Bookmark": {
529 "type": "string",
530 "value": "ZOTERO_BREF_new2"
532 "BookmarkText": {
533 "type": "string",
534 "value": "new result 2"
540 )json");
541 uno::Sequence<beans::PropertyValue> aArgs = comphelper::containerToSequence(aArgsVec);
542 dispatchCommand(mxComponent, ".uno:UpdateBookmarks", aArgs);
544 // Then make sure that the only paragraph is updated correctly:
545 SwCursor* pCursor = pWrtShell->GetCursor();
546 OUString aActual = pCursor->GetPointNode().GetTextNode()->GetText();
547 // Without the accompanying fix in place, this test would have failed with:
548 // - Expected: Anew result 1Cnew result 2E
549 // - Actual : ABCDE
550 // i.e. the content was not updated.
551 CPPUNIT_ASSERT_EQUAL(OUString("Anew result 1Cnew result 2E"), aActual);
553 // Without the accompanying fix in place, this test would have failed, ZOTERO_BREF_GiQ7DAWQYWLy
554 // was not renamed to ZOTERO_BREF_new1.
555 auto it = pDoc->getIDocumentMarkAccess()->findMark("ZOTERO_BREF_new1");
556 CPPUNIT_ASSERT(it != pDoc->getIDocumentMarkAccess()->getAllMarksEnd());
559 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testInsertFieldmarkReadonly)
561 // Given a document with a fieldmark, the cursor inside the fieldmark:
562 createSwDoc();
563 uno::Sequence<css::beans::PropertyValue> aArgs = {
564 comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
565 comphelper::makePropertyValue("FieldCommand", uno::Any(OUString("my command"))),
566 comphelper::makePropertyValue("FieldResult", uno::Any(OUString("my result"))),
568 dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
569 SwDoc* pDoc = getSwDoc();
570 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
571 SwCursor* pCursor = pWrtShell->GetCursor();
572 pCursor->SttEndDoc(/*bSttDoc=*/true);
573 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
575 // When trying to insert an inner fieldmark:
576 // Without the accompanying fix in place, this test would have crashed.
577 dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
579 // Then make sure the read-only content refuses to accept that inner fieldmark, so we still have
580 // just one:
581 size_t nActual = 0;
582 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
583 for (auto it = rIDMA.getFieldmarksBegin(); it != rIDMA.getFieldmarksEnd(); ++it)
585 ++nActual;
587 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), nActual);
590 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateRefmarks)
592 // Given a document with two refmarks, one is not interesting the other is a citation:
593 createSwDoc();
594 SwDoc* pDoc = getSwDoc();
595 uno::Sequence<css::beans::PropertyValue> aArgs = {
596 comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
597 comphelper::makePropertyValue("Name", uno::Any(OUString("some other old refmark"))),
598 comphelper::makePropertyValue("Content", uno::Any(OUString("some other old content"))),
600 dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
601 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
602 pWrtShell->SttEndDoc(/*bStt=*/false);
603 pWrtShell->SplitNode();
604 pWrtShell->SttEndDoc(/*bStt=*/false);
605 aArgs = {
606 comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
607 comphelper::makePropertyValue(
608 "Name", uno::Any(OUString("ZOTERO_ITEM CSL_CITATION {} old refmark"))),
609 comphelper::makePropertyValue("Content", uno::Any(OUString("old content"))),
611 dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
613 // When updating that refmark:
614 std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
616 "TypeName": {
617 "type": "string",
618 "value": "SetRef"
620 "NamePrefix": {
621 "type": "string",
622 "value": "ZOTERO_ITEM CSL_CITATION"
624 "Fields": {
625 "type": "[][]com.sun.star.beans.PropertyValue",
626 "value": [
628 "Name": {
629 "type": "string",
630 "value": "ZOTERO_ITEM CSL_CITATION {} new refmark"
632 "Content": {
633 "type": "string",
634 "value": "new content"
640 )json");
641 aArgs = comphelper::containerToSequence(aArgsVec);
642 dispatchCommand(mxComponent, ".uno:UpdateFields", aArgs);
644 // Then make sure that the document text features the new content:
645 SwTextNode* pTextNode = pWrtShell->GetCursor()->GetPointNode().GetTextNode();
646 // Without the accompanying fix in place, this test would have failed with:
647 // - Expected: new content
648 // - Actual : old content
649 // i.e. the doc content was not updated.
650 CPPUNIT_ASSERT_EQUAL(OUString("new content"), pTextNode->GetText());
653 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateFieldmark)
655 // Given a document with a fieldmark:
656 createSwDoc();
657 uno::Sequence<css::beans::PropertyValue> aArgs = {
658 comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
659 comphelper::makePropertyValue("FieldCommand",
660 uno::Any(OUString("ADDIN ZOTERO_ITEM old command 1"))),
661 comphelper::makePropertyValue("FieldResult", uno::Any(OUString("old result 1"))),
663 dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
665 // When updating that fieldmark to have new field command & result:
666 SwDoc* pDoc = getSwDoc();
667 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
668 pWrtShell->SttEndDoc(/*bStt=*/false);
669 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
670 std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
672 "FieldType": {
673 "type": "string",
674 "value": "vnd.oasis.opendocument.field.UNHANDLED"
676 "FieldCommandPrefix": {
677 "type": "string",
678 "value": "ADDIN ZOTERO_ITEM"
680 "Field": {
681 "type": "[]com.sun.star.beans.PropertyValue",
682 "value": {
683 "FieldType": {
684 "type": "string",
685 "value": "vnd.oasis.opendocument.field.UNHANDLED"
687 "FieldCommand": {
688 "type": "string",
689 "value": "ADDIN ZOTERO_ITEM new command 1"
691 "FieldResult": {
692 "type": "string",
693 "value": "new result 1"
698 )json");
699 aArgs = comphelper::containerToSequence(aArgsVec);
700 dispatchCommand(mxComponent, ".uno:UpdateTextFormField", aArgs);
702 // Then make sure that the document text is updated accordingly:
703 SwCursor* pCursor = pWrtShell->GetCursor();
704 OUString aActual = pCursor->Start()->GetNode().GetTextNode()->GetText();
705 static sal_Unicode const aForbidden[]
706 = { CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDSEP, CH_TXT_ATR_FIELDEND, 0 };
707 aActual = comphelper::string::removeAny(aActual, aForbidden);
708 // Without the accompanying fix in place, this test would have failed with:
709 // - Expected: new result 1
710 // - Actual : old result 1
711 // i.e. the document text was not updated.
712 CPPUNIT_ASSERT_EQUAL(OUString("new result 1"), aActual);
715 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateSections)
717 // Given a document with a section:
718 createSwDoc();
719 uno::Sequence<css::beans::PropertyValue> aArgs = {
720 comphelper::makePropertyValue("RegionName",
721 uno::Any(OUString("ZOTERO_BIBL {} CSL_BIBLIOGRAPHY RNDold"))),
722 comphelper::makePropertyValue("Content", uno::Any(OUString("old content"))),
724 dispatchCommand(mxComponent, ".uno:InsertSection", aArgs);
726 // When updating that section:
727 std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
729 "SectionNamePrefix": {
730 "type": "string",
731 "value": "ZOTERO_BIBL"
733 "Sections": {
734 "type": "[][]com.sun.star.beans.PropertyValue",
735 "value": [
737 "RegionName": {
738 "type": "string",
739 "value": "ZOTERO_BIBL {} CSL_BIBLIOGRAPHY RNDnew"
741 "Content": {
742 "type": "string",
743 "value": "new content"
749 )json");
750 aArgs = comphelper::containerToSequence(aArgsVec);
751 dispatchCommand(mxComponent, ".uno:UpdateSections", aArgs);
753 // Then make sure that the section is updated:
754 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
755 pWrtShell->SttEndDoc(/*bStt=*/true);
756 pWrtShell->EndOfSection(/*bSelect=*/true);
757 SwCursor* pCursor = pWrtShell->GetCursor();
758 OUString aActualResult = pCursor->GetText();
759 // Without the accompanying fix in place, this test would have failed with:
760 // - Expected: new content
761 // - Actual : old content
762 // i.e. the content wasn't updated.
763 CPPUNIT_ASSERT_EQUAL(OUString("new content"), aActualResult);
766 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDeleteFieldmarks)
768 // Given a document with 2 fieldmarks:
769 createSwDoc();
771 uno::Sequence<css::beans::PropertyValue> aArgs = {
772 comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
773 comphelper::makePropertyValue("FieldCommand",
774 uno::Any(OUString("ADDIN ZOTERO_ITEM old command 1"))),
775 comphelper::makePropertyValue("FieldResult", uno::Any(OUString("result 1"))),
777 dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
780 uno::Sequence<css::beans::PropertyValue> aArgs = {
781 comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
782 comphelper::makePropertyValue("FieldCommand",
783 uno::Any(OUString("ADDIN ZOTERO_ITEM old command 2"))),
784 comphelper::makePropertyValue("FieldResult", uno::Any(OUString("result 2"))),
786 dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
789 // When deleting those fieldmarks:
790 uno::Sequence<css::beans::PropertyValue> aArgs
791 = { comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
792 comphelper::makePropertyValue("FieldCommandPrefix",
793 uno::Any(OUString("ADDIN ZOTERO_ITEM"))) };
794 dispatchCommand(mxComponent, ".uno:DeleteTextFormFields", aArgs);
796 // Then make sure that the document doesn't contain fields anymore:
797 SwDoc* pDoc = getSwDoc();
798 // Without the accompanying fix in place, this test would have failed with:
799 // - Expected: 0
800 // - Actual : 2
801 // i.e. the fieldmarks were not deleted.
802 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0),
803 pDoc->getIDocumentMarkAccess()->getAllMarksCount());
804 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
805 pWrtShell->SttEndDoc(/*bStt=*/true);
806 SwCursor* pCursor = pWrtShell->GetCursor();
807 OUString aActual = pCursor->Start()->GetNode().GetTextNode()->GetText();
808 CPPUNIT_ASSERT_EQUAL(OUString("result 1result 2"), aActual);
811 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateBookmark)
813 // Given a document with a bookmarks, covering "BC":
814 createSwDoc();
815 SwDoc* pDoc = getSwDoc();
816 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
817 pWrtShell->Insert("ABCD");
818 pWrtShell->SttEndDoc(/*bStt=*/true);
819 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
820 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 2, /*bBasicCall=*/false);
821 pWrtShell->SetBookmark(vcl::KeyCode(), "ZOTERO_BREF_old");
823 // When updating the content of the bookmark under the cursor:
824 pWrtShell->SttEndDoc(/*bStt=*/true);
825 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 2, /*bBasicCall=*/false);
826 std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
828 "BookmarkNamePrefix": {
829 "type": "string",
830 "value": "ZOTERO_BREF_"
832 "Bookmark": {
833 "type": "[]com.sun.star.beans.PropertyValue",
834 "value": {
835 "Bookmark": {
836 "type": "string",
837 "value": "ZOTERO_BREF_new"
839 "BookmarkText": {
840 "type": "string",
841 "value": "new result"
846 )json");
847 uno::Sequence<beans::PropertyValue> aArgs = comphelper::containerToSequence(aArgsVec);
848 dispatchCommand(mxComponent, ".uno:UpdateBookmark", aArgs);
850 // Then make sure that the only paragraph is updated correctly:
851 SwCursor* pCursor = pWrtShell->GetCursor();
852 OUString aActual = pCursor->GetPointNode().GetTextNode()->GetText();
853 // Without the accompanying fix in place, this test would have failed with:
854 // - Expected: Anew resultD
855 // - Actual : ABCD
856 // i.e. it was not possible to update just the bookmark under cursor.
857 CPPUNIT_ASSERT_EQUAL(OUString("Anew resultD"), aActual);
858 auto it = pDoc->getIDocumentMarkAccess()->findMark("ZOTERO_BREF_new");
859 CPPUNIT_ASSERT(it != pDoc->getIDocumentMarkAccess()->getAllMarksEnd());
862 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateRefmark)
864 // Given a document with a refmark:
865 createSwDoc();
866 SwDoc* pDoc = getSwDoc();
867 uno::Sequence<css::beans::PropertyValue> aArgs = {
868 comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
869 comphelper::makePropertyValue(
870 "Name", uno::Any(OUString("ZOTERO_ITEM CSL_CITATION {} old refmark"))),
871 comphelper::makePropertyValue("Content", uno::Any(OUString("old content"))),
873 dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
875 // When updating that refmark:
876 std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
878 "TypeName": {
879 "type": "string",
880 "value": "SetRef"
882 "NamePrefix": {
883 "type": "string",
884 "value": "ZOTERO_ITEM CSL_CITATION"
886 "Field": {
887 "type": "[]com.sun.star.beans.PropertyValue",
888 "value": {
889 "Name": {
890 "type": "string",
891 "value": "ZOTERO_ITEM CSL_CITATION {} new refmark"
893 "Content": {
894 "type": "string",
895 "value": "new content"
900 )json");
901 aArgs = comphelper::containerToSequence(aArgsVec);
902 dispatchCommand(mxComponent, ".uno:UpdateField", aArgs);
904 // Then make sure that the document text features the new content:
905 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
906 SwTextNode* pTextNode = pWrtShell->GetCursor()->GetPointNode().GetTextNode();
907 // Without the accompanying fix in place, this test would have failed with:
908 // - Expected: new content
909 // - Actual : old content
910 // i.e. the content was not updated.
911 CPPUNIT_ASSERT_EQUAL(OUString("new content"), pTextNode->GetText());
914 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDeleteBookmarks)
916 // Given a document with 2 bookmarks, first covering "B" and second covering "D":
917 createSwDoc();
918 SwDoc* pDoc = getSwDoc();
919 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
920 pWrtShell->Insert("ABCDE");
921 pWrtShell->SttEndDoc(/*bStt=*/true);
922 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
923 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, /*bBasicCall=*/false);
924 pWrtShell->SetBookmark(vcl::KeyCode(), "ZOTERO_BREF_GiQ7DAWQYWLy");
925 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
926 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, /*bBasicCall=*/false);
927 pWrtShell->SetBookmark(vcl::KeyCode(), "other");
929 // When deleting 1 matching bookmark:
930 pWrtShell->SttEndDoc(/*bStt=*/true);
931 std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
933 "BookmarkNamePrefix": {
934 "type": "string",
935 "value": "ZOTERO_BREF_"
938 )json");
939 uno::Sequence<beans::PropertyValue> aArgs = comphelper::containerToSequence(aArgsVec);
940 dispatchCommand(mxComponent, ".uno:DeleteBookmarks", aArgs);
942 // Then make sure that only the other bookmark is kept:
943 auto it = pDoc->getIDocumentMarkAccess()->findMark("ZOTERO_BREF_GiQ7DAWQYWLy");
944 // Without the accompanying fix in place, this test would have failed, the matching bookmark was
945 // not removed.
946 CPPUNIT_ASSERT(bool(it == pDoc->getIDocumentMarkAccess()->getAllMarksEnd()));
947 it = pDoc->getIDocumentMarkAccess()->findMark("other");
948 CPPUNIT_ASSERT(it != pDoc->getIDocumentMarkAccess()->getAllMarksEnd());
951 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDeleteFields)
953 // Given a document with a refmark:
954 createSwDoc();
955 uno::Sequence<css::beans::PropertyValue> aArgs = {
956 comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
957 comphelper::makePropertyValue(
958 "Name", uno::Any(OUString("ZOTERO_ITEM CSL_CITATION {} RNDpyJknp173F"))),
959 comphelper::makePropertyValue("Content", uno::Any(OUString("aaa<b>bbb</b>ccc"))),
961 dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
963 // When deleting the refmarks:
964 std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
966 "TypeName": {
967 "type": "string",
968 "value": "SetRef"
970 "NamePrefix": {
971 "type": "string",
972 "value": "ZOTERO_ITEM CSL_CITATION"
975 )json");
976 aArgs = comphelper::containerToSequence(aArgsVec);
977 dispatchCommand(mxComponent, ".uno:DeleteFields", aArgs);
979 // Then make sure that no refmark is kept:
980 SwDoc* pDoc = getSwDoc();
981 // Without the accompanying fix in place, this test would have failed with:
982 // - Expected: 0
983 // - Actual : 1
984 // i.e. the refmark was not deleted.
985 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(0), pDoc->GetRefMarks());
988 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testInsertTextFormFieldFootnote)
990 // Given an empty document:
991 createSwDoc();
992 SwDoc* pDoc = getSwDoc();
994 // When inserting an ODF_UNHANDLED fieldmark inside a footnote:
995 uno::Sequence<css::beans::PropertyValue> aArgs = {
996 comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
997 comphelper::makePropertyValue("FieldCommand",
998 uno::Any(OUString("ADDIN ZOTERO_BIBL foo bar"))),
999 comphelper::makePropertyValue("FieldResult", uno::Any(OUString("result"))),
1000 comphelper::makePropertyValue("Wrapper", uno::Any(OUString("Footnote"))),
1002 dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
1004 // Then make sure that the footnote is created:
1005 SwFootnoteIdxs& rFootnotes = pDoc->GetFootnoteIdxs();
1006 // Without the accompanying fix in place, this test would have failed with:
1007 // - Expected: 1
1008 // - Actual : 0
1009 // i.e. no footnote was created.
1010 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rFootnotes.size());
1013 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testInsertTextFormFieldEndnote)
1015 // Given an empty document:
1016 createSwDoc();
1017 SwDoc* pDoc = getSwDoc();
1019 // When inserting an ODF_UNHANDLED fieldmark inside an endnote:
1020 uno::Sequence<css::beans::PropertyValue> aArgs = {
1021 comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
1022 comphelper::makePropertyValue("FieldCommand",
1023 uno::Any(OUString("ADDIN ZOTERO_BIBL foo bar"))),
1024 comphelper::makePropertyValue("FieldResult", uno::Any(OUString("result"))),
1025 comphelper::makePropertyValue("Wrapper", uno::Any(OUString("Endnote"))),
1027 dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
1029 // Then make sure that the endnote is created:
1030 SwFootnoteIdxs& rFootnotes = pDoc->GetFootnoteIdxs();
1031 // Without the accompanying fix in place, this test would have failed with:
1032 // - Expected: 1
1033 // - Actual : 0
1034 // i.e. no endnote was inserted.
1035 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rFootnotes.size());
1036 SwTextFootnote* pEndnote = rFootnotes[0];
1037 const SwFormatFootnote& rFormatEndnote = pEndnote->GetFootnote();
1038 CPPUNIT_ASSERT(rFormatEndnote.IsEndNote());
1039 // Also check that the endnote body contains the fieldmark:
1040 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1041 pWrtShell->SttEndDoc(/*bStt=*/true);
1042 pWrtShell->GotoFootnoteText();
1043 pWrtShell->EndOfSection(/*bSelect=*/true);
1044 SwCursor* pCursor = pWrtShell->GetCursor();
1045 OUString aActual = pCursor->GetText();
1046 static sal_Unicode const aForbidden[]
1047 = { CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDSEP, CH_TXT_ATR_FIELDEND, 0 };
1048 aActual = comphelper::string::removeAny(aActual, aForbidden);
1049 // Then this was empty: the fieldmark was inserted before the note anchor, not in the note body.
1050 CPPUNIT_ASSERT_EQUAL(OUString("result"), aActual);
1053 // Disabled because tdf#139141 was reverted and the default time field inserts a fix value again
1054 // Should be reactivated once a new UNO command is added for variable time fields
1055 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateSelectedField)
1057 // Given an empty doc:
1058 createSwDoc();
1059 SwDoc* pDoc = getSwDoc();
1060 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1061 SwPaM* pCursor = pDoc->GetEditShell()->GetCursor();
1063 // Insert a time field and select it:
1064 dispatchCommand(mxComponent, ".uno:InsertTimeField", {});
1066 pCursor->SetMark();
1067 pCursor->Move(fnMoveBackward);
1069 OUString aTimeFieldBefore, aTimeFieldAfter;
1070 pWrtShell->GetSelectedText(aTimeFieldBefore);
1072 // Wait for one second:
1073 osl::Thread::wait(std::chrono::seconds(1));
1075 // Update the field at cursor:
1076 dispatchCommand(mxComponent, ".uno:UpdateSelectedField", {});
1077 pWrtShell->GetSelectedText(aTimeFieldAfter);
1079 // Check that the selected field has changed:
1080 CPPUNIT_ASSERT(aTimeFieldAfter != aTimeFieldBefore);
1083 CPPUNIT_PLUGIN_IMPLEMENT();
1085 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */