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 <config_oox.h>
12 #include <string_view>
14 #include <com/sun/star/frame/Desktop.hpp>
15 #include <com/sun/star/lang/XComponent.hpp>
16 #include <com/sun/star/text/XTextDocument.hpp>
17 #include <com/sun/star/awt/Key.hpp>
18 #include <com/sun/star/awt/XReschedule.hpp>
19 #include <com/sun/star/awt/Toolkit.hpp>
20 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
21 #include <com/sun/star/text/TextContentAnchorType.hpp>
22 #include <boost/property_tree/json_parser.hpp>
23 #include <com/sun/star/beans/XPropertySet.hpp>
24 #include <com/sun/star/util/XCloseable.hpp>
26 #include <vcl/scheduler.hxx>
27 #include <vcl/svapp.hxx>
28 #include <vcl/syswin.hxx>
29 #include <vcl/window.hxx>
30 #include <vcl/ctrl.hxx>
31 #include <vcl/uitest/uiobject.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <rtl/math.hxx>
34 #include <rtl/uri.hxx>
35 #include <sfx2/app.hxx>
36 #include <sfx2/childwin.hxx>
37 #include <sfx2/lokhelper.hxx>
38 #include <test/unoapi_test.hxx>
39 #include <comphelper/lok.hxx>
40 #include <comphelper/propertysequence.hxx>
41 #include <osl/conditn.hxx>
42 #include <svl/srchitem.hxx>
43 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
44 #include <unotools/tempfile.hxx>
45 #include <sfx2/viewsh.hxx>
46 #include <sfx2/viewfrm.hxx>
47 #include <sfx2/bindings.hxx>
48 #include <sfx2/sidebar/SidebarController.hxx>
49 #include <sfx2/sidebar/SidebarDockingWindow.hxx>
50 #include <unotools/datetime.hxx>
51 #include <unotools/syslocaleoptions.hxx>
52 #include <comphelper/string.hxx>
53 #include <comphelper/scopeguard.hxx>
55 #include <config_features.h>
56 #include <config_fonts.h>
57 #include <config_mpl.h>
58 #include <tools/json_writer.hxx>
59 #include <o3tl/unit_conversion.hxx>
60 #include <o3tl/string_view.hxx>
62 #include <lib/init.hxx>
63 #include <svx/svxids.hrc>
65 #include <cppunit/TestAssert.h>
66 #include <vcl/BitmapTools.hxx>
67 #include <vcl/filter/PngImageWriter.hxx>
68 #include <vcl/filter/PDFiumLibrary.hxx>
74 using namespace com::sun::star
;
75 using namespace desktop
;
77 static LibreOfficeKitDocumentType
getDocumentTypeFromName(const char* pName
)
79 CPPUNIT_ASSERT_MESSAGE("Document name must be valid.", pName
!= nullptr);
81 const std::string
name(pName
);
82 CPPUNIT_ASSERT_MESSAGE("Document name must include extension.", name
.size() > 4);
84 const auto it
= name
.rfind('.');
85 if (it
!= std::string::npos
)
87 const std::string ext
= name
.substr(it
);
90 return LOK_DOCTYPE_SPREADSHEET
;
93 return LOK_DOCTYPE_PRESENTATION
;
96 CPPUNIT_ASSERT_MESSAGE("Document name must include extension.", it
!= std::string::npos
);
97 return LOK_DOCTYPE_TEXT
;
100 class DesktopLOKTest
: public UnoApiTest
103 DesktopLOKTest() : UnoApiTest("/desktop/qa/data/"),
104 m_nSelectionBeforeSearchResult(0),
105 m_nSelectionAfterSearchResult(0),
112 void readFileIntoByteVector(
113 std::u16string_view sFilename
, std::vector
<sal_uInt8
> & rByteVector
);
115 virtual void setUp() override
117 comphelper::LibreOfficeKit::setActive(true);
122 virtual void tearDown() override
126 // documents are already closed, no need to call UnoApiTest::tearDown
127 test::BootstrapFixture::tearDown();
129 comphelper::LibreOfficeKit::setActive(false);
132 std::unique_ptr
<LibLODocument_Impl
>
133 loadDocImpl(const char* pName
, LibreOfficeKitDocumentType eType
);
136 std::unique_ptr
<LibLODocument_Impl
>
137 loadDocImpl(const char* pName
);
140 std::unique_ptr
<LibLODocument_Impl
>
141 loadDocUrlImpl(const OUString
& rFileURL
, LibreOfficeKitDocumentType eType
);
143 LibLODocument_Impl
* loadDocUrl(const OUString
& rFileURL
, LibreOfficeKitDocumentType eType
);
144 LibLODocument_Impl
* loadDoc(const char* pName
, LibreOfficeKitDocumentType eType
);
145 LibLODocument_Impl
* loadDoc(const char* pName
)
147 return loadDoc(pName
, getDocumentTypeFromName(pName
));
150 void closeDoc(std::unique_ptr
<LibLODocument_Impl
>& loDocument
);
151 void closeDoc() { closeDoc(m_pDocument
); }
152 static void callback(int nType
, const char* pPayload
, void* pData
);
153 void callbackImpl(int nType
, const char* pPayload
);
155 void testGetStyles();
157 void testCreateView();
158 void testGetFilterTypes();
159 void testGetPartPageRectangles();
160 void testSearchCalc();
161 void testSearchAllNotificationsCalc();
162 void testPaintTile();
164 void testSaveAsJsonOptions();
165 void testSaveAsCalc();
166 void testPasteWriter();
167 void testPasteWriterJPEG();
168 void testUndoWriter();
169 void testRowColumnHeaders();
170 void testHiddenRowHeaders();
171 void testCellCursor();
172 void testCommandResult();
173 void testWriterComments();
174 void testSheetOperations();
175 void testSheetSelections();
176 void testSheetDragDrop();
177 void testContextMenuCalc();
178 void testContextMenuWriter();
179 void testContextMenuImpress();
180 void testNotificationCompression();
181 void testTileInvalidationCompression();
182 void testPartInInvalidation();
183 void testBinaryCallback();
185 void testRedlineWriter();
186 void testTrackChanges();
187 void testRedlineCalc();
188 void testPaintPartTile();
190 void testGetFontSubset();
192 void testCommentsWriter();
193 void testCommentsCalc();
194 void testCommentsImpress();
195 void testCommentsCallbacksWriter();
196 void testCommentsAddEditDeleteDraw();
198 void testExtractParameter();
199 void testGetSignatureState_NonSigned();
200 void testGetSignatureState_Signed();
201 #if 0 // broken with system nss on RHEL 7
202 void testInsertCertificate_DER_ODT();
203 void testInsertCertificate_PEM_ODT();
204 void testInsertCertificate_PEM_DOCX();
206 void testSignDocument_PEM_PDF();
207 void testTextSelectionHandles();
208 void testComplexSelection();
209 void testSpellcheckerMultiView();
210 void testDialogPaste();
211 void testShowHideDialog();
212 void testDialogInput();
213 void testCalcSaveAs();
214 void testControlState();
215 void testMetricField();
216 void testMultiDocuments();
217 void testJumpCursor();
218 void testRenderSearchResult_WriterNode();
219 void testRenderSearchResult_CommonNode();
220 void testNoDuplicateTableSelection();
221 void testMultiViewTableSelection();
222 void testColorPaletteCallback();
225 CPPUNIT_TEST_SUITE(DesktopLOKTest
);
226 CPPUNIT_TEST(testGetStyles
);
227 CPPUNIT_TEST(testGetFonts
);
228 CPPUNIT_TEST(testCreateView
);
229 CPPUNIT_TEST(testGetFilterTypes
);
230 CPPUNIT_TEST(testGetPartPageRectangles
);
231 CPPUNIT_TEST(testSearchCalc
);
232 CPPUNIT_TEST(testSearchAllNotificationsCalc
);
233 CPPUNIT_TEST(testPaintTile
);
234 CPPUNIT_TEST(testSaveAs
);
235 CPPUNIT_TEST(testSaveAsJsonOptions
);
236 CPPUNIT_TEST(testSaveAsCalc
);
237 CPPUNIT_TEST(testPasteWriter
);
238 CPPUNIT_TEST(testPasteWriterJPEG
);
239 CPPUNIT_TEST(testUndoWriter
);
240 CPPUNIT_TEST(testRowColumnHeaders
);
241 CPPUNIT_TEST(testHiddenRowHeaders
);
242 CPPUNIT_TEST(testCellCursor
);
243 CPPUNIT_TEST(testCommandResult
);
244 CPPUNIT_TEST(testWriterComments
);
245 CPPUNIT_TEST(testSheetOperations
);
246 CPPUNIT_TEST(testSheetSelections
);
247 CPPUNIT_TEST(testSheetDragDrop
);
248 CPPUNIT_TEST(testContextMenuCalc
);
249 CPPUNIT_TEST(testContextMenuWriter
);
250 CPPUNIT_TEST(testContextMenuImpress
);
251 CPPUNIT_TEST(testNotificationCompression
);
252 CPPUNIT_TEST(testTileInvalidationCompression
);
253 CPPUNIT_TEST(testPartInInvalidation
);
254 CPPUNIT_TEST(testBinaryCallback
);
255 CPPUNIT_TEST(testInput
);
256 CPPUNIT_TEST(testRedlineWriter
);
257 CPPUNIT_TEST(testTrackChanges
);
258 CPPUNIT_TEST(testRedlineCalc
);
259 CPPUNIT_TEST(testPaintPartTile
);
261 CPPUNIT_TEST(testGetFontSubset
);
263 CPPUNIT_TEST(testCommentsWriter
);
264 CPPUNIT_TEST(testCommentsCalc
);
265 CPPUNIT_TEST(testCommentsImpress
);
266 CPPUNIT_TEST(testCommentsCallbacksWriter
);
267 CPPUNIT_TEST(testCommentsAddEditDeleteDraw
);
268 CPPUNIT_TEST(testRunMacro
);
269 CPPUNIT_TEST(testExtractParameter
);
270 CPPUNIT_TEST(testGetSignatureState_Signed
);
271 CPPUNIT_TEST(testGetSignatureState_NonSigned
);
273 #if 0 // broken with system nss on RHEL 7
274 CPPUNIT_TEST(testInsertCertificate_DER_ODT
);
275 CPPUNIT_TEST(testInsertCertificate_PEM_ODT
);
276 CPPUNIT_TEST(testInsertCertificate_PEM_DOCX
);
278 CPPUNIT_TEST(testSignDocument_PEM_PDF
);
280 CPPUNIT_TEST(testTextSelectionHandles
);
281 CPPUNIT_TEST(testComplexSelection
);
282 CPPUNIT_TEST(testSpellcheckerMultiView
);
283 CPPUNIT_TEST(testDialogPaste
);
284 CPPUNIT_TEST(testShowHideDialog
);
285 CPPUNIT_TEST(testDialogInput
);
286 CPPUNIT_TEST(testCalcSaveAs
);
287 CPPUNIT_TEST(testControlState
);
288 CPPUNIT_TEST(testMetricField
);
289 CPPUNIT_TEST(testMultiDocuments
);
290 CPPUNIT_TEST(testJumpCursor
);
291 CPPUNIT_TEST(testRenderSearchResult_WriterNode
);
292 CPPUNIT_TEST(testRenderSearchResult_CommonNode
);
293 CPPUNIT_TEST(testNoDuplicateTableSelection
);
294 CPPUNIT_TEST(testMultiViewTableSelection
);
295 CPPUNIT_TEST(testColorPaletteCallback
);
296 CPPUNIT_TEST(testABI
);
297 CPPUNIT_TEST_SUITE_END();
299 OString m_aTextSelection
;
300 OString m_aTextSelectionStart
;
301 OString m_aTextSelectionEnd
;
302 std::vector
<OString
> m_aSearchResultSelection
;
303 std::vector
<int> m_aSearchResultPart
;
304 int m_nSelectionBeforeSearchResult
;
305 int m_nSelectionAfterSearchResult
;
307 // for testCommandResult
308 osl::Condition m_aCommandResultCondition
;
309 OString m_aCommandResult
;
311 // for testModifiedStatus
312 osl::Condition m_aStateChangedCondition
;
316 // for testContextMenu{Calc, Writer}
317 osl::Condition m_aContextMenuCondition
;
318 boost::property_tree::ptree m_aContextMenuResult
;
320 std::unique_ptr
<LibLODocument_Impl
> m_pDocument
;
323 DesktopLOKTest::~DesktopLOKTest()
330 static Control
* GetFocusControl(vcl::Window
const * pParent
)
332 sal_uInt16 nChildren
= pParent
->GetChildCount();
333 for (sal_uInt16 nChild
= 0; nChild
< nChildren
; ++nChild
)
335 vcl::Window
* pChild
= pParent
->GetChild( nChild
);
336 Control
* pCtrl
= dynamic_cast<Control
*>(pChild
);
337 if (pCtrl
&& pCtrl
->HasControlFocus())
340 Control
* pSubCtrl
= GetFocusControl( pChild
);
347 std::unique_ptr
<LibLODocument_Impl
>
348 DesktopLOKTest::loadDocUrlImpl(const OUString
& rFileURL
, LibreOfficeKitDocumentType eType
)
353 case LOK_DOCTYPE_TEXT
:
354 aService
= "com.sun.star.text.TextDocument";
356 case LOK_DOCTYPE_SPREADSHEET
:
357 aService
= "com.sun.star.sheet.SpreadsheetDocument";
359 case LOK_DOCTYPE_PRESENTATION
:
360 aService
= "com.sun.star.presentation.PresentationDocument";
363 CPPUNIT_ASSERT(false);
367 static int nDocumentIdCounter
= 0;
368 SfxViewShell::SetCurrentDocId(ViewShellDocId(nDocumentIdCounter
));
369 mxComponent
= loadFromDesktop(rFileURL
, aService
);
371 std::unique_ptr
<LibLODocument_Impl
> pDocument(new LibLODocument_Impl(mxComponent
, nDocumentIdCounter
));
372 ++nDocumentIdCounter
;
377 std::unique_ptr
<LibLODocument_Impl
>
378 DesktopLOKTest::loadDocImpl(const char* pName
, LibreOfficeKitDocumentType eType
)
380 OUString aFileURL
= createFileURL(OUString::createFromAscii(pName
));
381 return loadDocUrlImpl(aFileURL
, eType
);
384 std::unique_ptr
<LibLODocument_Impl
>
385 DesktopLOKTest::loadDocImpl(const char* pName
)
387 return loadDocImpl(pName
, getDocumentTypeFromName(pName
));
390 LibLODocument_Impl
* DesktopLOKTest::loadDocUrl(const OUString
& rFileURL
, LibreOfficeKitDocumentType eType
)
392 m_pDocument
= loadDocUrlImpl(rFileURL
, eType
);
393 return m_pDocument
.get();
396 LibLODocument_Impl
* DesktopLOKTest::loadDoc(const char* pName
, LibreOfficeKitDocumentType eType
)
398 m_pDocument
= loadDocImpl(pName
, eType
);
399 return m_pDocument
.get();
402 void DesktopLOKTest::closeDoc(std::unique_ptr
<LibLODocument_Impl
>& pDocument
)
406 pDocument
->pClass
->registerCallback(pDocument
.get(), nullptr, nullptr);
410 if (mxComponent
.is())
412 css::uno::Reference
<util::XCloseable
> xCloseable(mxComponent
, css::uno::UNO_QUERY_THROW
);
413 xCloseable
->close(false);
418 void DesktopLOKTest::callback(int nType
, const char* pPayload
, void* pData
)
420 static_cast<DesktopLOKTest
*>(pData
)->callbackImpl(nType
, pPayload
);
423 void DesktopLOKTest::callbackImpl(int nType
, const char* pPayload
)
427 case LOK_CALLBACK_TEXT_SELECTION
:
429 m_aTextSelection
= pPayload
;
430 if (m_aSearchResultSelection
.empty())
431 ++m_nSelectionBeforeSearchResult
;
433 ++m_nSelectionAfterSearchResult
;
436 case LOK_CALLBACK_TEXT_SELECTION_START
:
437 m_aTextSelectionStart
= pPayload
;
439 case LOK_CALLBACK_TEXT_SELECTION_END
:
440 m_aTextSelectionEnd
= pPayload
;
442 case LOK_CALLBACK_SEARCH_RESULT_SELECTION
:
444 m_aSearchResultSelection
.clear();
445 boost::property_tree::ptree aTree
;
446 std::stringstream
aStream(pPayload
);
447 boost::property_tree::read_json(aStream
, aTree
);
448 for (const boost::property_tree::ptree::value_type
& rValue
: aTree
.get_child("searchResultSelection"))
450 m_aSearchResultSelection
.emplace_back(rValue
.second
.get
<std::string
>("rectangles").c_str());
451 m_aSearchResultPart
.push_back(std::atoi(rValue
.second
.get
<std::string
>("part").c_str()));
455 case LOK_CALLBACK_UNO_COMMAND_RESULT
:
457 m_aCommandResult
= pPayload
;
458 m_aCommandResultCondition
.set();
461 case LOK_CALLBACK_STATE_CHANGED
:
463 OString
aPayload(pPayload
);
464 OString
aPrefix(".uno:ModifiedStatus=");
465 if (aPayload
.startsWith(aPrefix
))
467 m_bModified
= aPayload
.copy(aPrefix
.getLength()).toBoolean();
468 m_aStateChangedCondition
.set();
470 else if (aPayload
.startsWith(".uno:TrackChanges=") && aPayload
.endsWith("=true"))
474 case LOK_CALLBACK_CONTEXT_MENU
:
476 m_aContextMenuResult
.clear();
477 std::stringstream
aStream(pPayload
);
478 boost::property_tree::read_json(aStream
, m_aContextMenuResult
);
479 m_aContextMenuCondition
.set();
485 void DesktopLOKTest::testGetStyles()
487 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
488 boost::property_tree::ptree aTree
;
489 char* pJSON
= pDocument
->m_pDocumentClass
->getCommandValues(pDocument
, ".uno:StyleApply");
490 std::stringstream
aStream(pJSON
);
491 boost::property_tree::read_json(aStream
, aTree
);
492 CPPUNIT_ASSERT( !aTree
.empty() );
493 CPPUNIT_ASSERT_EQUAL( std::string(".uno:StyleApply"), aTree
.get_child("commandName").get_value
<std::string
>() );
495 boost::property_tree::ptree aValues
= aTree
.get_child("commandValues");
496 CPPUNIT_ASSERT( !aValues
.empty() );
497 for (const auto& rPair
: aValues
)
499 if( rPair
.first
!= "ClearStyle")
501 CPPUNIT_ASSERT( !rPair
.second
.empty());
503 if (rPair
.first
!= "CharacterStyles" &&
504 rPair
.first
!= "ParagraphStyles" &&
505 rPair
.first
!= "FrameStyles" &&
506 rPair
.first
!= "PageStyles" &&
507 rPair
.first
!= "NumberingStyles" &&
508 rPair
.first
!= "CellStyles" &&
509 rPair
.first
!= "ShapeStyles" &&
510 rPair
.first
!= "TableStyles" &&
511 rPair
.first
!= "HeaderFooter" &&
512 rPair
.first
!= "Commands")
514 CPPUNIT_FAIL("Unknown style family: " + rPair
.first
);
520 void DesktopLOKTest::testGetFonts()
522 LibLODocument_Impl
* pDocument
= loadDoc("blank_presentation.odp");
523 boost::property_tree::ptree aTree
;
524 char* pJSON
= pDocument
->m_pDocumentClass
->getCommandValues(pDocument
, ".uno:CharFontName");
525 std::stringstream
aStream(pJSON
);
526 boost::property_tree::read_json(aStream
, aTree
);
527 CPPUNIT_ASSERT( !aTree
.empty() );
528 CPPUNIT_ASSERT_EQUAL( std::string(".uno:CharFontName"), aTree
.get_child("commandName").get_value
<std::string
>() );
530 boost::property_tree::ptree aValues
= aTree
.get_child("commandValues");
531 CPPUNIT_ASSERT( !aValues
.empty() );
532 for (const auto& rPair
: aValues
)
534 // check that we have font sizes available for each font
535 CPPUNIT_ASSERT( !rPair
.second
.empty());
540 void DesktopLOKTest::testCreateView()
542 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
543 CPPUNIT_ASSERT_EQUAL(1, pDocument
->m_pDocumentClass
->getViewsCount(pDocument
));
545 int nId0
= pDocument
->m_pDocumentClass
->getView(pDocument
);
546 int nId1
= pDocument
->m_pDocumentClass
->createView(pDocument
);
547 CPPUNIT_ASSERT_EQUAL(2, pDocument
->m_pDocumentClass
->getViewsCount(pDocument
));
549 // Test getViewIds().
550 std::vector
<int> aViewIds(2);
551 CPPUNIT_ASSERT(pDocument
->m_pDocumentClass
->getViewIds(pDocument
, aViewIds
.data(), aViewIds
.size()));
552 CPPUNIT_ASSERT_EQUAL(nId0
, aViewIds
[0]);
553 CPPUNIT_ASSERT_EQUAL(nId1
, aViewIds
[1]);
555 // Make sure the created view is the active one, then switch to the old
557 CPPUNIT_ASSERT_EQUAL(nId1
, pDocument
->m_pDocumentClass
->getView(pDocument
));
558 pDocument
->m_pDocumentClass
->setView(pDocument
, nId0
);
559 CPPUNIT_ASSERT_EQUAL(nId0
, pDocument
->m_pDocumentClass
->getView(pDocument
));
561 pDocument
->m_pDocumentClass
->destroyView(pDocument
, nId1
);
562 CPPUNIT_ASSERT_EQUAL(1, pDocument
->m_pDocumentClass
->getViewsCount(pDocument
));
565 void DesktopLOKTest::testGetPartPageRectangles()
567 // Test that we get as many page rectangles as expected: blank document is
569 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
570 char* pRectangles
= pDocument
->pClass
->getPartPageRectangles(pDocument
);
571 OUString sRectangles
= OUString::fromUtf8(pRectangles
);
573 std::vector
<OUString
> aRectangles
;
574 sal_Int32 nIndex
= 0;
577 OUString aRectangle
= sRectangles
.getToken(0, ';', nIndex
);
578 if (!aRectangle
.isEmpty())
579 aRectangles
.push_back(aRectangle
);
582 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aRectangles
.size());
587 void DesktopLOKTest::testGetFilterTypes()
589 LibLibreOffice_Impl aOffice
;
590 char* pJSON
= aOffice
.m_pOfficeClass
->getFilterTypes(&aOffice
);
592 std::stringstream
aStream(pJSON
);
593 boost::property_tree::ptree aTree
;
594 boost::property_tree::read_json(aStream
, aTree
);
596 CPPUNIT_ASSERT(!aTree
.empty());
597 CPPUNIT_ASSERT_EQUAL(std::string("application/vnd.oasis.opendocument.text"), aTree
.get_child("writer8").get_child("MediaType").get_value
<std::string
>());
601 void DesktopLOKTest::testSearchCalc()
603 LibLibreOffice_Impl aOffice
;
604 LibLODocument_Impl
* pDocument
= loadDoc("search.ods");
605 pDocument
->pClass
->initializeForRendering(pDocument
, nullptr);
606 pDocument
->pClass
->registerCallback(pDocument
, &DesktopLOKTest::callback
, this);
608 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
610 {"SearchItem.SearchString", uno::Any(OUString("foo"))},
611 {"SearchItem.Backward", uno::Any(false)},
612 {"SearchItem.Command", uno::Any(static_cast<sal_uInt16
>(SvxSearchCmd::FIND_ALL
))},
614 dispatchCommand(mxComponent
, ".uno:ExecuteSearch", aPropertyValues
);
616 std::vector
<OString
> aSelections
;
617 sal_Int32 nIndex
= 0;
620 OString aToken
= m_aTextSelection
.getToken(0, ';', nIndex
);
621 aSelections
.push_back(aToken
);
622 } while (nIndex
>= 0);
623 // This was 1, find-all only found one match.
624 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), aSelections
.size());
625 // Make sure that we get exactly as many rectangle lists as matches.
626 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), m_aSearchResultSelection
.size());
627 // Result is on the first sheet.
628 CPPUNIT_ASSERT_EQUAL(0, m_aSearchResultPart
[0]);
631 void DesktopLOKTest::testSearchAllNotificationsCalc()
633 LibLibreOffice_Impl aOffice
;
634 LibLODocument_Impl
* pDocument
= loadDoc("search.ods");
635 pDocument
->pClass
->initializeForRendering(pDocument
, nullptr);
636 pDocument
->pClass
->registerCallback(pDocument
, &DesktopLOKTest::callback
, this);
638 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
640 {"SearchItem.SearchString", uno::Any(OUString("foo"))},
641 {"SearchItem.Backward", uno::Any(false)},
642 {"SearchItem.Command", uno::Any(static_cast<sal_uInt16
>(SvxSearchCmd::FIND_ALL
))},
644 dispatchCommand(mxComponent
, ".uno:ExecuteSearch", aPropertyValues
);
646 // This was 1, make sure that we get no notifications about selection changes during search.
647 CPPUNIT_ASSERT_EQUAL(0, m_nSelectionBeforeSearchResult
);
648 // But we do get the selection afterwards.
649 CPPUNIT_ASSERT(m_nSelectionAfterSearchResult
> 0);
652 void DesktopLOKTest::testPaintTile()
654 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
655 int nCanvasWidth
= 100;
656 int nCanvasHeight
= 300;
657 sal_Int32 nStride
= cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32
, nCanvasWidth
);
658 std::vector
<unsigned char> aBuffer(nStride
* nCanvasHeight
);
661 int nTileWidth
= 1000;
662 int nTileHeight
= 3000;
664 // This used to crash: paintTile() implementation did not handle
665 // nCanvasWidth != nCanvasHeight correctly, as usually both are just always
667 pDocument
->pClass
->paintTile(pDocument
, aBuffer
.data(), nCanvasWidth
, nCanvasHeight
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
669 // This crashed in OutputDevice::DrawDeviceAlphaBitmap().
674 aBuffer
.resize(nCanvasWidth
* nCanvasHeight
* 4);
675 pDocument
->pClass
->paintTile(pDocument
, aBuffer
.data(), nCanvasWidth
, nCanvasHeight
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
678 void DesktopLOKTest::testSaveAs()
680 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
681 CPPUNIT_ASSERT(pDocument
->pClass
->saveAs(pDocument
, maTempFile
.GetURL().toUtf8().getStr(), "png", nullptr));
684 void DesktopLOKTest::testSaveAsJsonOptions()
686 // Given a document with 3 pages:
687 LibLODocument_Impl
* pDocument
= loadDoc("3page.odg");
689 // When exporting that document to PDF, skipping the first page:
690 OString
aOptions("{\"PageRange\":{\"type\":\"string\",\"value\":\"2-\"}}");
691 CPPUNIT_ASSERT(pDocument
->pClass
->saveAs(pDocument
, maTempFile
.GetURL().toUtf8().getStr(), "pdf", aOptions
.getStr()));
693 std::shared_ptr
<vcl::pdf::PDFium
> pPDFium
= vcl::pdf::PDFiumLibrary::get();
697 // Then make sure the resulting PDF has 2 pages:
698 std::unique_ptr
<vcl::pdf::PDFiumDocument
> pPdfDocument
700 // Without the accompanying fix in place, this test would have failed with:
703 // i.e. FilterOptions was ignored.
704 CPPUNIT_ASSERT_EQUAL(2, pPdfDocument
->getPageCount());
707 void DesktopLOKTest::testSaveAsCalc()
709 LibLODocument_Impl
* pDocument
= loadDoc("search.ods");
710 CPPUNIT_ASSERT(pDocument
->pClass
->saveAs(pDocument
, maTempFile
.GetURL().toUtf8().getStr(), "png", nullptr));
713 void DesktopLOKTest::testPasteWriter()
715 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
716 OString
aText("hello");
718 CPPUNIT_ASSERT(pDocument
->pClass
->paste(pDocument
, "text/plain;charset=utf-8", aText
.getStr(), aText
.getLength()));
720 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:SelectAll", nullptr, false);
721 Scheduler::ProcessEventsToIdle();
722 char* pText
= pDocument
->pClass
->getTextSelection(pDocument
, "text/plain;charset=utf-8", nullptr);
723 CPPUNIT_ASSERT_EQUAL(OString("hello"), OString(pText
));
726 // textt/plain should be rejected.
727 CPPUNIT_ASSERT(!pDocument
->pClass
->paste(pDocument
, "textt/plain;charset=utf-8", aText
.getStr(), aText
.getLength()));
728 // Writer is expected to support text/html.
729 CPPUNIT_ASSERT(pDocument
->pClass
->paste(pDocument
, "text/html", aText
.getStr(), aText
.getLength()));
731 // Overwrite doc contents with a HTML paste.
732 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:SelectAll", nullptr, false);
733 Scheduler::ProcessEventsToIdle();
734 OString
aComment("foo <!-- bar --> baz");
735 CPPUNIT_ASSERT(pDocument
->pClass
->paste(pDocument
, "text/html", aComment
.getStr(), aComment
.getLength()));
737 // Check if we have a comment.
738 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
739 uno::Reference
<container::XEnumerationAccess
> xParagraphEnumerationAccess(xTextDocument
->getText(), uno::UNO_QUERY
);
740 uno::Reference
<container::XEnumeration
> xParagraphEnumeration
= xParagraphEnumerationAccess
->createEnumeration();
741 uno::Reference
<container::XEnumerationAccess
> xParagraph(xParagraphEnumeration
->nextElement(), uno::UNO_QUERY
);
742 uno::Reference
<container::XEnumeration
> xTextPortionEnumeration
= xParagraph
->createEnumeration();
743 uno::Reference
<beans::XPropertySet
> xTextPortion(xTextPortionEnumeration
->nextElement(), uno::UNO_QUERY
);
744 CPPUNIT_ASSERT_EQUAL(OUString("Text"), xTextPortion
->getPropertyValue("TextPortionType").get
<OUString
>());
745 // Without the accompanying fix in place, this test would have failed, as we had a comment
746 // between "foo" and "baz".
747 CPPUNIT_ASSERT(!xTextPortionEnumeration
->hasMoreElements());
750 void DesktopLOKTest::testPasteWriterJPEG()
752 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
754 OUString aFileURL
= createFileURL(u
"paste.jpg");
755 std::ifstream
aImageStream(aFileURL
.toUtf8().copy(strlen("file://")).getStr());
756 std::vector
<char> aImageContents((std::istreambuf_iterator
<char>(aImageStream
)), std::istreambuf_iterator
<char>());
758 CPPUNIT_ASSERT(pDocument
->pClass
->paste(pDocument
, "image/jpeg", aImageContents
.data(), aImageContents
.size()));
760 uno::Reference
<drawing::XDrawPageSupplier
> xDrawPageSupplier(mxComponent
, uno::UNO_QUERY
);
761 uno::Reference
<drawing::XDrawPage
> xDrawPage
= xDrawPageSupplier
->getDrawPage();
762 // This was 0, JPEG was not handled as a format for clipboard paste.
763 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), xDrawPage
->getCount());
765 uno::Reference
<beans::XPropertySet
> xShape(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
766 // This was text::TextContentAnchorType_AT_PARAGRAPH.
767 CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AS_CHARACTER
, xShape
->getPropertyValue("AnchorType").get
<text::TextContentAnchorType
>());
769 // Delete the pasted picture, and paste again with a custom anchor type.
770 uno::Reference
<lang::XComponent
>(xShape
, uno::UNO_QUERY_THROW
)->dispose();
771 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
773 {"AnchorType", uno::Any(static_cast<sal_uInt16
>(text::TextContentAnchorType_AT_CHARACTER
))},
775 dispatchCommand(mxComponent
, ".uno:Paste", aPropertyValues
);
776 xShape
.set(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
777 // This was text::TextContentAnchorType_AS_CHARACTER, AnchorType argument was ignored.
778 CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AT_CHARACTER
, xShape
->getPropertyValue("AnchorType").get
<text::TextContentAnchorType
>());
781 void DesktopLOKTest::testUndoWriter()
783 // Load a Writer document and press a key.
784 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
785 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 't', 0);
786 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYUP
, 't', 0);
787 Scheduler::ProcessEventsToIdle();
789 boost::property_tree::ptree aTree
;
790 char* pJSON
= pDocument
->m_pDocumentClass
->getCommandValues(pDocument
, ".uno:Undo");
791 std::stringstream
aStream(pJSON
);
793 CPPUNIT_ASSERT(!aStream
.str().empty());
794 boost::property_tree::read_json(aStream
, aTree
);
795 // Make sure that pressing a key creates exactly one undo action.
796 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aTree
.get_child("actions").size());
799 void DesktopLOKTest::testRowColumnHeaders()
807 * "size": "254.987250637468",
811 * "size": "509.974501274936",
817 * "size": "1274.93625318734",
821 * "size": "2549.87250637468",
827 * "size" defines the bottom/right boundary of a row/column in twips (size between 0 and boundary)
828 * "text" has the header label in UTF-8
830 LibLODocument_Impl
* pDocument
= loadDoc("search.ods");
832 pDocument
->pClass
->initializeForRendering(pDocument
, nullptr);
834 tools::Long nWidth
= 0;
835 tools::Long nHeight
= 0;
836 pDocument
->m_pDocumentClass
->getDocumentSize(pDocument
, &nWidth
, &nHeight
);
837 tools::Long nX
= rtl::math::round(nWidth
/ 4.0);
838 tools::Long nY
= rtl::math::round(nHeight
/ 4.0);
839 nWidth
= rtl::math::round(nWidth
/ 2.0);
840 nHeight
= rtl::math::round(nHeight
/ 2.0);
842 std::stringstream aPayload
;
843 aPayload
<< ".uno:ViewRowColumnHeaders?x=" << nX
<< "&y=" << nY
<< "&width=" << nWidth
<< "&height=" << nHeight
;
845 boost::property_tree::ptree aTree
;
846 char* pJSON
= pDocument
->m_pDocumentClass
->getCommandValues(pDocument
, aPayload
.str().c_str());
847 std::stringstream
aStream(pJSON
);
850 CPPUNIT_ASSERT(!aStream
.str().empty());
852 boost::property_tree::read_json(aStream
, aTree
);
853 sal_Int32 nPrevious
= 0;
854 bool bFirstHeader
= true;
855 bool bNotEnoughHeaders
= true;
856 for (const boost::property_tree::ptree::value_type
& rValue
: aTree
.get_child("rows"))
858 sal_Int32 nSize
= o3tl::toInt32(rValue
.second
.get
<std::string
>("size"));
859 nSize
= o3tl::convert(nSize
, o3tl::Length::px
, o3tl::Length::twip
);
860 OString
aText(rValue
.second
.get
<std::string
>("text"));
864 CPPUNIT_ASSERT(nSize
<= nY
);
865 CPPUNIT_ASSERT_EQUAL(OString("10"), aText
);
866 bFirstHeader
= false;
870 CPPUNIT_ASSERT(nSize
> 0);
871 CPPUNIT_ASSERT(nPrevious
< nSize
);
872 if (nSize
> nY
+ nHeight
)
874 bNotEnoughHeaders
= false;
880 CPPUNIT_ASSERT(!bNotEnoughHeaders
);
884 bNotEnoughHeaders
= true;
885 for (const boost::property_tree::ptree::value_type
& rValue
: aTree
.get_child("columns"))
887 sal_Int32 nSize
= o3tl::toInt32(rValue
.second
.get
<std::string
>("size"));
888 nSize
= o3tl::convert(nSize
, o3tl::Length::px
, o3tl::Length::twip
);
889 OString
aText(rValue
.second
.get
<std::string
>("text"));
892 CPPUNIT_ASSERT(nSize
<= nX
);
893 CPPUNIT_ASSERT_EQUAL(OString("3"), aText
);
894 bFirstHeader
= false;
898 CPPUNIT_ASSERT(nSize
> 0);
899 CPPUNIT_ASSERT(nPrevious
< nSize
);
900 if (nSize
> nX
+ nWidth
)
902 bNotEnoughHeaders
= false;
908 CPPUNIT_ASSERT(!bNotEnoughHeaders
);
911 void DesktopLOKTest::testHiddenRowHeaders()
913 LibLODocument_Impl
* pDocument
= loadDoc("hidden-row.ods");
915 pDocument
->pClass
->initializeForRendering(pDocument
, nullptr);
917 tools::Long
const nX
= 0;
918 tools::Long
const nY
= 0;
919 tools::Long nWidth
= 0;
920 tools::Long nHeight
= 0;
921 pDocument
->m_pDocumentClass
->getDocumentSize(pDocument
, &nWidth
, &nHeight
);
923 std::stringstream aPayload
;
924 aPayload
<< ".uno:ViewRowColumnHeaders?x=" << nX
<< "&y=" << nY
<< "&width=" << nWidth
<< "&height=" << nHeight
;
926 boost::property_tree::ptree aTree
;
927 char* pJSON
= pDocument
->m_pDocumentClass
->getCommandValues(pDocument
, aPayload
.str().c_str());
928 std::stringstream
aStream(pJSON
);
929 CPPUNIT_ASSERT(!aStream
.str().empty());
931 boost::property_tree::read_json(aStream
, aTree
);
933 sal_Int32 nPrevious
= 0;
934 sal_Int32 nIndex
= 0;
935 for (const boost::property_tree::ptree::value_type
& rValue
: aTree
.get_child("rows"))
937 sal_Int32 nSize
= o3tl::toInt32(rValue
.second
.get
<std::string
>("size"));
941 // nSize was 510, nPrevious was 255, i.e. hidden row wasn't reported as 0 height.
942 CPPUNIT_ASSERT_EQUAL(nPrevious
, nSize
);
949 void DesktopLOKTest::testCellCursor()
951 LibLODocument_Impl
* pDocument
= loadDoc("search.ods");
953 boost::property_tree::ptree aTree
;
955 char* pJSON
= pDocument
->m_pDocumentClass
->getCommandValues(pDocument
, ".uno:CellCursor?tileWidth=1&tileHeight=1&outputWidth=1&outputHeight=1");
957 std::stringstream
aStream(pJSON
);
959 CPPUNIT_ASSERT(!aStream
.str().empty());
961 boost::property_tree::read_json(aStream
, aTree
);
963 OString
aRectangle(aTree
.get
<std::string
>("commandValues"));
964 // cell cursor geometry + col + row
965 CPPUNIT_ASSERT_EQUAL(OString("0, 0, 1274, 254, 0, 0"), aRectangle
);
968 void DesktopLOKTest::testCommandResult()
970 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
972 // the postUnoCommand() is supposed to be async, let's test it safely
973 // [no idea if it is async in reality - most probably we are operating
974 // under some solar mutex or something anyway ;-) - but...]
975 TimeValue aTimeValue
= { 2 , 0 }; // 2 seconds max
977 // nothing is triggered when we have no callback yet, we just time out on
978 // the condition var.
979 m_aCommandResultCondition
.reset();
980 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:Bold", nullptr, true);
981 Scheduler::ProcessEventsToIdle();
982 m_aCommandResultCondition
.wait(aTimeValue
);
984 CPPUNIT_ASSERT(m_aCommandResult
.isEmpty());
986 // but we get some real values when the callback is set up
987 pDocument
->pClass
->registerCallback(pDocument
, &DesktopLOKTest::callback
, this);
989 m_aCommandResultCondition
.reset();
990 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:Bold", nullptr, true);
991 Scheduler::ProcessEventsToIdle();
992 m_aCommandResultCondition
.wait(aTimeValue
);
994 boost::property_tree::ptree aTree
;
995 std::stringstream
aStream((std::string(m_aCommandResult
)));
996 boost::property_tree::read_json(aStream
, aTree
);
998 CPPUNIT_ASSERT_EQUAL(std::string(".uno:Bold"), aTree
.get_child("commandName").get_value
<std::string
>());
999 CPPUNIT_ASSERT_EQUAL(true, aTree
.get_child("success").get_value
<bool>());
1002 void DesktopLOKTest::testWriterComments()
1004 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
1005 pDocument
->pClass
->registerCallback(pDocument
, &DesktopLOKTest::callback
, this);
1006 uno::Reference
<awt::XReschedule
> xToolkit
= com::sun::star::awt::Toolkit::create(comphelper::getProcessComponentContext());
1008 // Insert a comment at the beginning of the document and wait till the main
1009 // loop grabs the focus, so characters end up in the annotation window.
1010 TimeValue
const aTimeValue
= {2 , 0}; // 2 seconds max
1011 m_aCommandResultCondition
.reset();
1012 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:InsertAnnotation", nullptr, true);
1013 Scheduler::ProcessEventsToIdle();
1014 m_aCommandResultCondition
.wait(aTimeValue
);
1015 CPPUNIT_ASSERT(!m_aCommandResult
.isEmpty());
1016 xToolkit
->reschedule();
1018 // Test that we have a comment.
1019 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
1020 uno::Reference
<container::XEnumerationAccess
> xParagraphEnumerationAccess(xTextDocument
->getText(), uno::UNO_QUERY
);
1021 uno::Reference
<container::XEnumeration
> xParagraphEnumeration
= xParagraphEnumerationAccess
->createEnumeration();
1022 uno::Reference
<container::XEnumerationAccess
> xParagraph(xParagraphEnumeration
->nextElement(), uno::UNO_QUERY
);
1023 uno::Reference
<container::XEnumeration
> xTextPortionEnumeration
= xParagraph
->createEnumeration();
1024 uno::Reference
<beans::XPropertySet
> xTextPortion(xTextPortionEnumeration
->nextElement(), uno::UNO_QUERY
);
1025 CPPUNIT_ASSERT_EQUAL(OUString("Annotation"), xTextPortion
->getPropertyValue("TextPortionType").get
<OUString
>());
1027 // Type "test" and finish editing.
1028 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 't', 0);
1029 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 'e', 0);
1030 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 's', 0);
1031 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 't', 0);
1032 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 0, com::sun::star::awt::Key::ESCAPE
);
1033 Scheduler::ProcessEventsToIdle();
1035 // Test that the typed characters ended up in the right window.
1036 auto xTextField
= xTextPortion
->getPropertyValue("TextField").get
< uno::Reference
<beans::XPropertySet
> >();
1037 // This was empty, typed characters ended up in the body text.
1038 CPPUNIT_ASSERT_EQUAL(OUString("test"), xTextField
->getPropertyValue("Content").get
<OUString
>());
1041 void DesktopLOKTest::testTrackChanges()
1043 // Load a document and create two views.
1044 LibLibreOffice_Impl aOffice
;
1045 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
1046 pDocument
->pClass
->initializeForRendering(pDocument
, nullptr);
1047 pDocument
->pClass
->registerCallback(pDocument
, &DesktopLOKTest::callback
, this);
1048 pDocument
->pClass
->createView(pDocument
);
1049 pDocument
->pClass
->initializeForRendering(pDocument
, nullptr);
1050 pDocument
->pClass
->registerCallback(pDocument
, &DesktopLOKTest::callback
, this);
1051 Scheduler::ProcessEventsToIdle();
1053 // Enable track changes and assert that both views get notified.
1054 m_nTrackChanges
= 0;
1055 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:TrackChanges", nullptr, false);
1056 Scheduler::ProcessEventsToIdle();
1057 // This was 1, only the active view was notified.
1058 CPPUNIT_ASSERT_EQUAL(2, m_nTrackChanges
);
1061 void DesktopLOKTest::testSheetOperations()
1063 LibLODocument_Impl
* pDocument
= loadDoc("sheets.ods");
1065 // insert the last sheet
1066 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:Insert",
1067 "{ \"Name\": { \"type\": \"string\", \"value\": \"LastSheet\" }, \"Index\": { \"type\": \"long\", \"value\": 0 } }", false);
1069 // insert the first sheet
1070 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:Insert",
1071 "{ \"Name\": { \"type\": \"string\", \"value\": \"FirstSheet\" }, \"Index\": { \"type\": \"long\", \"value\": 1 } }", false);
1073 // rename the \"Sheet1\" (2nd now) to \"Renamed\"
1074 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:Name",
1075 "{ \"Name\": { \"type\": \"string\", \"value\": \"Renamed\" }, \"Index\": { \"type\": \"long\", \"value\": 2 } }", false);
1077 // delete the \"Sheet2\" (3rd)
1078 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:Remove",
1079 "{ \"Index\": { \"type\": \"long\", \"value\": 3 } }", false);
1081 Scheduler::ProcessEventsToIdle();
1082 CPPUNIT_ASSERT_EQUAL(6, pDocument
->pClass
->getParts(pDocument
));
1084 std::vector
<OString
> aExpected
= { "FirstSheet", "Renamed", "Sheet3", "Sheet4", "Sheet5", "LastSheet" };
1085 for (int i
= 0; i
< 6; ++i
)
1087 char* pPartName
= pDocument
->pClass
->getPartName(pDocument
, i
);
1088 CPPUNIT_ASSERT_EQUAL(aExpected
[i
], OString(pPartName
));
1093 void DesktopLOKTest::testSheetSelections()
1095 LibLODocument_Impl
* pDocument
= loadDoc("sheets.ods", LOK_DOCTYPE_SPREADSHEET
);
1096 pDocument
->pClass
->initializeForRendering(pDocument
, nullptr);
1097 pDocument
->pClass
->registerCallback(pDocument
, &DesktopLOKTest::callback
, this);
1100 * Check if selection data is correct
1105 int const col2
= 2200;
1106 int const col3
= 3300;
1110 // Select row 5 from column 1 through column 5
1111 pDocument
->pClass
->postMouseEvent(pDocument
,
1112 LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1115 pDocument
->pClass
->postMouseEvent(pDocument
,
1116 LOK_MOUSEEVENT_MOUSEMOVE
,
1119 pDocument
->pClass
->postMouseEvent(pDocument
,
1120 LOK_MOUSEEVENT_MOUSEMOVE
,
1123 pDocument
->pClass
->postMouseEvent(pDocument
,
1124 LOK_MOUSEEVENT_MOUSEMOVE
,
1127 pDocument
->pClass
->postMouseEvent(pDocument
,
1128 LOK_MOUSEEVENT_MOUSEMOVE
,
1131 pDocument
->pClass
->postMouseEvent(pDocument
,
1132 LOK_MOUSEEVENT_MOUSEBUTTONUP
,
1135 Scheduler::ProcessEventsToIdle();
1137 // Copy the contents and check if matches expected data
1139 char* pUsedMimeType
= nullptr;
1140 char* pCopiedContent
= pDocument
->pClass
->getTextSelection(pDocument
, nullptr, &pUsedMimeType
);
1141 std::vector
<long> aExpected
= {5, 6, 7, 8, 9};
1142 std::istringstream
iss(pCopiedContent
);
1143 for (const long nIndex
: aExpected
)
1147 CPPUNIT_ASSERT_EQUAL(nIndex
, strtol(token
.c_str(), nullptr, 10));
1150 free(pUsedMimeType
);
1151 free(pCopiedContent
);
1155 * Check if clicking inside the selection deselects the whole selection
1158 // Click at row5, col4
1159 pDocument
->pClass
->postMouseEvent(pDocument
,
1160 LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1163 pDocument
->pClass
->postMouseEvent(pDocument
,
1164 LOK_MOUSEEVENT_MOUSEBUTTONUP
,
1167 Scheduler::ProcessEventsToIdle();
1169 // Selected text should get deselected and copying should give us
1170 // content of only one cell, now
1172 char* pUsedMimeType
= nullptr;
1173 char* pCopiedContent
= pDocument
->pClass
->getTextSelection(pDocument
, nullptr, &pUsedMimeType
);
1174 std::vector
<long> aExpected
= { 8 };
1175 std::istringstream
iss(pCopiedContent
);
1176 for (const long nIndex
: aExpected
)
1180 CPPUNIT_ASSERT_EQUAL(nIndex
, strtol(token
.c_str(), nullptr, 10));
1183 free(pUsedMimeType
);
1184 free(pCopiedContent
);
1188 void DesktopLOKTest::testSheetDragDrop()
1190 LibLODocument_Impl
* pDocument
= loadDoc("sheets.ods", LOK_DOCTYPE_SPREADSHEET
);
1191 pDocument
->pClass
->initializeForRendering(pDocument
, nullptr);
1192 pDocument
->pClass
->registerCallback(pDocument
, &DesktopLOKTest::callback
, this);
1201 // Select row 01 from column 01 through column 05
1202 pDocument
->pClass
->postMouseEvent(pDocument
,
1203 LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1206 pDocument
->pClass
->postMouseEvent(pDocument
,
1207 LOK_MOUSEEVENT_MOUSEMOVE
,
1210 pDocument
->pClass
->postMouseEvent(pDocument
,
1211 LOK_MOUSEEVENT_MOUSEMOVE
,
1214 pDocument
->pClass
->postMouseEvent(pDocument
,
1215 LOK_MOUSEEVENT_MOUSEBUTTONUP
,
1219 Scheduler::ProcessEventsToIdle();
1221 SfxViewShell
* pViewShell
= SfxViewShell::Current();
1222 SfxViewFrame
& rViewFrame
= pViewShell
->GetViewFrame();
1225 css::uno::Any aValue
;
1226 css::util::URL aURL
;
1227 std::unique_ptr
<SfxPoolItem
> pState
;
1229 aURL
.Protocol
= ".uno:";
1230 aURL
.Complete
= ".uno:Address";
1231 aURL
.Path
= "Address";
1232 aURL
.Main
= ".uno:Address";
1234 rViewFrame
.GetBindings().QueryState(rViewFrame
.GetBindings().QuerySlotId(aURL
), pState
);
1235 pState
->QueryValue(aValue
);
1237 CPPUNIT_ASSERT_EQUAL(OUString("Sheet5.A1:E1"), sValue
);
1240 // Check selection content
1242 char* pMimeType
= nullptr;
1243 char* pContent
= pDocument
->pClass
->getTextSelection(pDocument
, nullptr, &pMimeType
);
1244 std::vector
<long> aExpected
= {1, 2, 3, 4, 5};
1245 std::istringstream
aContent(pContent
);
1247 for (const long nIndex
: aExpected
)
1250 CPPUNIT_ASSERT_EQUAL(nIndex
, strtol(token
.c_str(), nullptr, 10));
1258 pDocument
->pClass
->postMouseEvent(pDocument
,
1259 LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1262 pDocument
->pClass
->postMouseEvent(pDocument
,
1263 LOK_MOUSEEVENT_MOUSEMOVE
,
1266 pDocument
->pClass
->postMouseEvent(pDocument
,
1267 LOK_MOUSEEVENT_MOUSEMOVE
,
1270 pDocument
->pClass
->postMouseEvent(pDocument
,
1271 LOK_MOUSEEVENT_MOUSEBUTTONUP
,
1275 Scheduler::ProcessEventsToIdle();
1277 SfxViewShell
* pViewShell
= SfxViewShell::Current();
1278 SfxViewFrame
& rViewFrame
= pViewShell
->GetViewFrame();
1281 css::uno::Any aValue
;
1282 css::util::URL aURL
;
1283 std::unique_ptr
<SfxPoolItem
> pState
;
1285 aURL
.Protocol
= ".uno:";
1286 aURL
.Complete
= ".uno:Address";
1287 aURL
.Path
= "Address";
1288 aURL
.Main
= ".uno:Address";
1290 rViewFrame
.GetBindings().QueryState(rViewFrame
.GetBindings().QuerySlotId(aURL
), pState
);
1291 pState
->QueryValue(aValue
);
1293 CPPUNIT_ASSERT_EQUAL(OUString("Sheet5.D1:H1"), sValue
);
1296 // Check selection content
1298 char* pMimeType
= nullptr;
1299 char* pContent
= pDocument
->pClass
->getTextSelection(pDocument
, nullptr, &pMimeType
);
1300 std::vector
<long> aExpected
= {1, 2, 3, 4, 5};
1301 std::istringstream
aContent(pContent
);
1303 for (const long nIndex
: aExpected
)
1306 CPPUNIT_ASSERT_EQUAL(nIndex
, strtol(token
.c_str(), nullptr, 10));
1316 void verifyContextMenuStructure(boost::property_tree::ptree
& aRoot
)
1318 for (const auto& aItemPair
: aRoot
)
1320 // This is an array, so no key
1321 CPPUNIT_ASSERT_EQUAL(aItemPair
.first
, std::string(""));
1323 boost::property_tree::ptree aItemValue
= aItemPair
.second
;
1324 boost::optional
<boost::property_tree::ptree
&> aText
= aItemValue
.get_child_optional("text");
1325 boost::optional
<boost::property_tree::ptree
&> aType
= aItemValue
.get_child_optional("type");
1326 boost::optional
<boost::property_tree::ptree
&> aCommand
= aItemValue
.get_child_optional("command");
1327 boost::optional
<boost::property_tree::ptree
&> aSubmenu
= aItemValue
.get_child_optional("menu");
1328 boost::optional
<boost::property_tree::ptree
&> aEnabled
= aItemValue
.get_child_optional("enabled");
1329 boost::optional
<boost::property_tree::ptree
&> aChecktype
= aItemValue
.get_child_optional("checktype");
1330 boost::optional
<boost::property_tree::ptree
&> aChecked
= aItemValue
.get_child_optional("checked");
1332 // type is omnipresent
1333 CPPUNIT_ASSERT( aType
);
1335 // separator doesn't have any other attribs
1336 if ( aType
.get().data() == "separator" )
1338 CPPUNIT_ASSERT( !aText
);
1339 CPPUNIT_ASSERT( !aCommand
);
1340 CPPUNIT_ASSERT( !aSubmenu
);
1341 CPPUNIT_ASSERT( !aEnabled
);
1342 CPPUNIT_ASSERT( !aChecktype
);
1343 CPPUNIT_ASSERT( !aChecked
);
1345 else if ( aType
.get().data() == "command" )
1347 CPPUNIT_ASSERT( aCommand
);
1348 CPPUNIT_ASSERT( aText
);
1350 else if ( aType
.get().data() == "menu")
1352 CPPUNIT_ASSERT( aSubmenu
);
1353 CPPUNIT_ASSERT( aText
);
1354 verifyContextMenuStructure( aSubmenu
.get() );
1359 CPPUNIT_ASSERT( aChecktype
.get().data() == "radio" ||
1360 aChecktype
.get().data() == "checkmark" ||
1361 aChecktype
.get().data() == "auto" );
1363 CPPUNIT_ASSERT( aChecked
);
1364 CPPUNIT_ASSERT( aChecked
.get().data() == "true" || aChecked
.get().data() == "false" );
1370 boost::optional
<boost::property_tree::ptree
>
1371 getContextMenuItem(boost::property_tree::ptree
& aMenu
, std::string
const & unoSelector
)
1373 boost::optional
<boost::property_tree::ptree
> aMenuItem
;
1374 for (const auto& aItemPair
: aMenu
)
1376 boost::property_tree::ptree aItemValue
= aItemPair
.second
;
1378 boost::optional
<boost::property_tree::ptree
&> aCommand
= aItemValue
.get_child_optional("command");
1379 if (aCommand
&& aCommand
.get().data() == unoSelector
)
1381 aMenuItem
= aItemValue
;
1389 } // end anonymous namespace
1391 void DesktopLOKTest::testContextMenuCalc()
1393 LibLODocument_Impl
* pDocument
= loadDoc("sheet_with_image.ods", LOK_DOCTYPE_SPREADSHEET
);
1394 pDocument
->pClass
->initializeForRendering(pDocument
, nullptr);
1395 pDocument
->pClass
->registerCallback(pDocument
, &DesktopLOKTest::callback
, this);
1398 Point
aPointOnImage(1150, 1100);
1399 pDocument
->pClass
->postMouseEvent(pDocument
,
1400 LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1401 aPointOnImage
.X(), aPointOnImage
.Y(),
1403 Scheduler::ProcessEventsToIdle();
1405 TimeValue
const aTimeValue
= {2 , 0}; // 2 seconds max
1406 m_aContextMenuCondition
.wait(aTimeValue
);
1408 CPPUNIT_ASSERT( !m_aContextMenuResult
.empty() );
1409 boost::optional
<boost::property_tree::ptree
&> aMenu
= m_aContextMenuResult
.get_child_optional("menu");
1410 CPPUNIT_ASSERT( aMenu
);
1411 verifyContextMenuStructure( aMenu
.get() );
1413 // tests for calc specific context menu
1416 boost::optional
<boost::property_tree::ptree
> aMenuItem
= getContextMenuItem(aMenu
.get(), ".uno:Cut");
1417 CPPUNIT_ASSERT(aMenuItem
);
1419 boost::optional
<boost::property_tree::ptree
&> aEnabled
= aMenuItem
.get().get_child_optional("enabled");
1420 CPPUNIT_ASSERT(aEnabled
);
1421 CPPUNIT_ASSERT_EQUAL(aEnabled
.get().data(), std::string("true"));
1426 boost::optional
<boost::property_tree::ptree
> aMenuItem
= getContextMenuItem(aMenu
.get(), ".uno:Copy");
1427 CPPUNIT_ASSERT(aMenuItem
);
1429 boost::optional
<boost::property_tree::ptree
&> aEnabled
= aMenuItem
.get().get_child_optional("enabled");
1430 CPPUNIT_ASSERT(aEnabled
);
1431 CPPUNIT_ASSERT_EQUAL(aEnabled
.get().data(), std::string("true"));
1436 boost::optional
<boost::property_tree::ptree
> aMenuItem
= getContextMenuItem(aMenu
.get(), ".uno:Paste");
1437 CPPUNIT_ASSERT(aMenuItem
);
1439 boost::optional
<boost::property_tree::ptree
&> aEnabled
= aMenuItem
.get().get_child_optional("enabled");
1440 CPPUNIT_ASSERT(aEnabled
);
1441 CPPUNIT_ASSERT_EQUAL(aEnabled
.get().data(), std::string("true"));
1444 // Remove hyperlink is disabled
1446 boost::optional
<boost::property_tree::ptree
> aMenuItem
= getContextMenuItem(aMenu
.get(), ".uno:RemoveHyperlink");
1447 CPPUNIT_ASSERT(aMenuItem
);
1449 boost::optional
<boost::property_tree::ptree
&> aEnabled
= aMenuItem
.get().get_child_optional("enabled");
1450 CPPUNIT_ASSERT(aEnabled
);
1451 CPPUNIT_ASSERT_EQUAL(aEnabled
.get().data(), std::string("false"));
1454 // open hyperlink is disabled
1456 boost::optional
<boost::property_tree::ptree
> aMenuItem
= getContextMenuItem(aMenu
.get(), ".uno:OpenHyperlinkOnCursor");
1457 CPPUNIT_ASSERT(aMenuItem
);
1459 boost::optional
<boost::property_tree::ptree
&> aEnabled
= aMenuItem
.get().get_child_optional("enabled");
1460 CPPUNIT_ASSERT(aEnabled
);
1461 CPPUNIT_ASSERT_EQUAL(aEnabled
.get().data(), std::string("false"));
1464 // checkbutton tests
1466 boost::optional
<boost::property_tree::ptree
> aMenuItem
= getContextMenuItem(aMenu
.get(), ".uno:AnchorMenu");
1467 CPPUNIT_ASSERT(aMenuItem
);
1469 boost::optional
<boost::property_tree::ptree
&> aSubmenu
= aMenuItem
.get().get_child_optional("menu");
1470 CPPUNIT_ASSERT(aSubmenu
);
1472 boost::optional
<boost::property_tree::ptree
> aMenuItemToPage
= getContextMenuItem(aSubmenu
.get(), ".uno:SetAnchorToPage");
1473 CPPUNIT_ASSERT(aMenuItemToPage
);
1475 boost::optional
<boost::property_tree::ptree
> aMenuItemToCell
= getContextMenuItem(aSubmenu
.get(), ".uno:SetAnchorToCell");
1476 CPPUNIT_ASSERT(aMenuItemToCell
);
1478 // these are radio buttons
1479 boost::optional
<boost::property_tree::ptree
&> aChecktypeToPage
= aMenuItemToPage
.get().get_child_optional("checktype");
1480 CPPUNIT_ASSERT(aChecktypeToPage
);
1481 CPPUNIT_ASSERT_EQUAL(aChecktypeToPage
.get().data(), std::string("radio"));
1483 boost::optional
<boost::property_tree::ptree
&> aChecktypeToCell
= aMenuItemToCell
.get().get_child_optional("checktype");
1484 CPPUNIT_ASSERT(aChecktypeToCell
);
1485 CPPUNIT_ASSERT_EQUAL(aChecktypeToCell
.get().data(), std::string("radio"));
1487 // ToPage is checked
1488 boost::optional
<boost::property_tree::ptree
&> aCheckedToPage
= aMenuItemToPage
.get().get_child_optional("checked");
1489 CPPUNIT_ASSERT(aCheckedToPage
);
1490 CPPUNIT_ASSERT_EQUAL(aCheckedToPage
.get().data(), std::string("true"));
1492 // ToCell is unchecked
1493 boost::optional
<boost::property_tree::ptree
&> aCheckedToCell
= aMenuItemToCell
.get().get_child_optional("checked");
1494 CPPUNIT_ASSERT(aCheckedToCell
);
1495 CPPUNIT_ASSERT_EQUAL(aCheckedToCell
.get().data(), std::string("false"));
1499 void DesktopLOKTest::testContextMenuWriter()
1501 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
1502 pDocument
->pClass
->initializeForRendering(pDocument
, nullptr);
1503 pDocument
->pClass
->registerCallback(pDocument
, &DesktopLOKTest::callback
, this);
1505 Point
aRandomPoint(1150, 1100);
1506 pDocument
->pClass
->postMouseEvent(pDocument
,
1507 LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1508 aRandomPoint
.X(), aRandomPoint
.Y(),
1510 Scheduler::ProcessEventsToIdle();
1512 TimeValue
const aTimeValue
= {2 , 0}; // 2 seconds max
1513 m_aContextMenuCondition
.wait(aTimeValue
);
1515 CPPUNIT_ASSERT( !m_aContextMenuResult
.empty() );
1516 boost::optional
<boost::property_tree::ptree
&> aMenu
= m_aContextMenuResult
.get_child_optional("menu");
1517 CPPUNIT_ASSERT( aMenu
);
1518 verifyContextMenuStructure( aMenu
.get() );
1520 // tests for writer specific context menu
1523 boost::optional
<boost::property_tree::ptree
> aMenuItem
= getContextMenuItem(aMenu
.get(), ".uno:Cut");
1524 CPPUNIT_ASSERT(aMenuItem
);
1526 boost::optional
<boost::property_tree::ptree
&> aEnabled
= aMenuItem
.get().get_child_optional("enabled");
1527 CPPUNIT_ASSERT(aEnabled
);
1528 CPPUNIT_ASSERT_EQUAL(aEnabled
.get().data(), std::string("false"));
1533 boost::optional
<boost::property_tree::ptree
> aMenuItem
= getContextMenuItem(aMenu
.get(), ".uno:Copy");
1534 CPPUNIT_ASSERT(aMenuItem
);
1536 boost::optional
<boost::property_tree::ptree
&> aEnabled
= aMenuItem
.get().get_child_optional("enabled");
1537 CPPUNIT_ASSERT(aEnabled
);
1538 CPPUNIT_ASSERT_EQUAL(aEnabled
.get().data(), std::string("false"));
1543 boost::optional
<boost::property_tree::ptree
> aMenuItem
= getContextMenuItem(aMenu
.get(), ".uno:Paste");
1544 CPPUNIT_ASSERT(aMenuItem
);
1546 boost::optional
<boost::property_tree::ptree
&> aEnabled
= aMenuItem
.get().get_child_optional("enabled");
1547 CPPUNIT_ASSERT(aEnabled
);
1548 CPPUNIT_ASSERT_EQUAL(aEnabled
.get().data(), std::string("true"));
1552 void DesktopLOKTest::testContextMenuImpress()
1554 LibLODocument_Impl
* pDocument
= loadDoc("blank_presentation.odp", LOK_DOCTYPE_PRESENTATION
);
1555 pDocument
->pClass
->initializeForRendering(pDocument
, nullptr);
1556 pDocument
->pClass
->registerCallback(pDocument
, &DesktopLOKTest::callback
, this);
1558 // random point where we don't hit an underlying comment or text box
1559 Point
aRandomPoint(10, 1150);
1560 pDocument
->pClass
->postMouseEvent(pDocument
,
1561 LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1562 aRandomPoint
.X(), aRandomPoint
.Y(),
1564 Scheduler::ProcessEventsToIdle();
1566 TimeValue
const aTimeValue
= {2 , 0}; // 2 seconds max
1567 m_aContextMenuCondition
.wait(aTimeValue
);
1569 CPPUNIT_ASSERT( !m_aContextMenuResult
.empty() );
1570 boost::optional
<boost::property_tree::ptree
&> aMenu
= m_aContextMenuResult
.get_child_optional("menu");
1571 CPPUNIT_ASSERT( aMenu
);
1572 verifyContextMenuStructure( aMenu
.get() );
1574 // tests for impress specific context menu
1577 boost::optional
<boost::property_tree::ptree
> aMenuItem
= getContextMenuItem(aMenu
.get(), ".uno:Cut");
1578 CPPUNIT_ASSERT(aMenuItem
);
1580 boost::optional
<boost::property_tree::ptree
&> aEnabled
= aMenuItem
.get().get_child_optional("enabled");
1581 CPPUNIT_ASSERT(aEnabled
);
1582 CPPUNIT_ASSERT_EQUAL(aEnabled
.get().data(), std::string("false"));
1587 boost::optional
<boost::property_tree::ptree
> aMenuItem
= getContextMenuItem(aMenu
.get(), ".uno:Copy");
1588 CPPUNIT_ASSERT(aMenuItem
);
1590 boost::optional
<boost::property_tree::ptree
&> aEnabled
= aMenuItem
.get().get_child_optional("enabled");
1591 CPPUNIT_ASSERT(aEnabled
);
1592 CPPUNIT_ASSERT_EQUAL(aEnabled
.get().data(), std::string("false"));
1597 boost::optional
<boost::property_tree::ptree
> aMenuItem
= getContextMenuItem(aMenu
.get(), ".uno:Paste");
1598 CPPUNIT_ASSERT(aMenuItem
);
1600 boost::optional
<boost::property_tree::ptree
&> aEnabled
= aMenuItem
.get().get_child_optional("enabled");
1601 CPPUNIT_ASSERT(aEnabled
);
1602 CPPUNIT_ASSERT_EQUAL(aEnabled
.get().data(), std::string("true"));
1605 // SaveBackground is disabled
1607 boost::optional
<boost::property_tree::ptree
> aMenuItem
= getContextMenuItem(aMenu
.get(), ".uno:SaveBackground");
1608 CPPUNIT_ASSERT(aMenuItem
);
1610 boost::optional
<boost::property_tree::ptree
&> aEnabled
= aMenuItem
.get().get_child_optional("enabled");
1611 CPPUNIT_ASSERT(aEnabled
);
1612 CPPUNIT_ASSERT_EQUAL(aEnabled
.get().data(), std::string("false"));
1615 // checkbutton tests
1617 boost::optional
<boost::property_tree::ptree
> aMenuItem
= getContextMenuItem(aMenu
.get(), ".uno:ShowRuler");
1618 CPPUNIT_ASSERT(aMenuItem
);
1620 boost::optional
<boost::property_tree::ptree
&> aChecktype
= aMenuItem
.get().get_child_optional("checktype");
1621 CPPUNIT_ASSERT(aChecktype
);
1622 CPPUNIT_ASSERT_EQUAL(aChecktype
.get().data(), std::string("checkmark"));
1624 boost::optional
<boost::property_tree::ptree
&> aChecked
= aMenuItem
.get().get_child_optional("checked");
1625 CPPUNIT_ASSERT(aChecked
);
1626 CPPUNIT_ASSERT_EQUAL(aChecked
.get().data(), std::string("false"));
1629 // Checkbutton tests inside SnapLines submenu
1631 boost::optional
<boost::property_tree::ptree
> aMenuItem
= getContextMenuItem(aMenu
.get(), ".uno:SnapLinesMenu");
1632 CPPUNIT_ASSERT(aMenuItem
);
1634 boost::optional
<boost::property_tree::ptree
&> aSubmenu
= aMenuItem
.get().get_child_optional("menu");
1635 CPPUNIT_ASSERT(aSubmenu
);
1637 boost::optional
<boost::property_tree::ptree
> aMenuItemHelpVis
= getContextMenuItem(aSubmenu
.get(), ".uno:HelplinesVisible");
1638 CPPUNIT_ASSERT(aMenuItemHelpVis
);
1640 boost::optional
<boost::property_tree::ptree
> aMenuItemHelpUse
= getContextMenuItem(aSubmenu
.get(), ".uno:HelplinesUse");
1641 CPPUNIT_ASSERT(aMenuItemHelpUse
);
1643 boost::optional
<boost::property_tree::ptree
> aMenuItemHelpFront
= getContextMenuItem(aSubmenu
.get(), ".uno:HelplinesFront");
1644 CPPUNIT_ASSERT(aMenuItemHelpFront
);
1646 // these are checkmarks
1647 boost::optional
<boost::property_tree::ptree
&> aChecktypeHelpVis
= aMenuItemHelpVis
.get().get_child_optional("checktype");
1648 CPPUNIT_ASSERT(aChecktypeHelpVis
);
1649 CPPUNIT_ASSERT_EQUAL(aChecktypeHelpVis
.get().data(), std::string("checkmark"));
1651 boost::optional
<boost::property_tree::ptree
&> aChecktypeHelpUse
= aMenuItemHelpUse
.get().get_child_optional("checktype");
1652 CPPUNIT_ASSERT(aChecktypeHelpUse
);
1653 CPPUNIT_ASSERT_EQUAL(aChecktypeHelpUse
.get().data(), std::string("checkmark"));
1655 boost::optional
<boost::property_tree::ptree
&> aChecktypeHelpFront
= aMenuItemHelpFront
.get().get_child_optional("checktype");
1656 CPPUNIT_ASSERT(aChecktypeHelpFront
);
1657 CPPUNIT_ASSERT_EQUAL(aChecktypeHelpFront
.get().data(), std::string("checkmark"));
1659 // HelplineVisible is unchecked
1660 boost::optional
<boost::property_tree::ptree
&> aCheckedHelpVis
= aMenuItemHelpVis
.get().get_child_optional("checked");
1661 CPPUNIT_ASSERT(aCheckedHelpVis
);
1662 CPPUNIT_ASSERT_EQUAL(aCheckedHelpVis
.get().data(), std::string("false"));
1664 // HelplineUse is checked
1665 boost::optional
<boost::property_tree::ptree
&> aCheckedHelpUse
= aMenuItemHelpUse
.get().get_child_optional("checked");
1666 CPPUNIT_ASSERT(aCheckedHelpUse
);
1667 CPPUNIT_ASSERT_EQUAL(aCheckedHelpUse
.get().data(), std::string("true"));
1669 // HelplineFront is checked
1670 boost::optional
<boost::property_tree::ptree
&> aCheckedHelpFront
= aMenuItemHelpFront
.get().get_child_optional("checked");
1671 CPPUNIT_ASSERT(aCheckedHelpFront
);
1672 CPPUNIT_ASSERT_EQUAL(aCheckedHelpFront
.get().data(), std::string("true"));
1676 static void callbackCompressionTest(const int type
, const char* payload
, void* data
)
1678 std::vector
<std::tuple
<int, std::string
>>* notifs
= static_cast<std::vector
<std::tuple
<int, std::string
>>*>(data
);
1679 notifs
->emplace_back(type
, std::string(payload
? payload
: "(nil)"));
1682 void DesktopLOKTest::testNotificationCompression()
1684 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
1685 std::vector
<std::tuple
<int, std::string
>> notifs
;
1686 std::unique_ptr
<CallbackFlushHandler
> handler(new CallbackFlushHandler(pDocument
, callbackCompressionTest
, ¬ifs
));
1687 handler
->setViewId(SfxLokHelper::getView());
1689 handler
->queue(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
, ""); // 0
1690 handler
->queue(LOK_CALLBACK_TEXT_SELECTION
, "15, 25, 15, 10"); // Superseded.
1691 handler
->queue(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
, ""); // Should be dropped.
1692 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "15, 25, 15, 10"); // 1
1693 handler
->queue(LOK_CALLBACK_TEXT_SELECTION
, "15, 25, 15, 10"); // Should be dropped.
1694 handler
->queue(LOK_CALLBACK_TEXT_SELECTION
, ""); // Superseded.
1695 handler
->queue(LOK_CALLBACK_STATE_CHANGED
, ""); // 2
1696 handler
->queue(LOK_CALLBACK_STATE_CHANGED
, ".uno:Bold"); // 3
1697 handler
->queue(LOK_CALLBACK_STATE_CHANGED
, ""); // 4
1698 handler
->queue(LOK_CALLBACK_MOUSE_POINTER
, "text"); // 5
1699 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "15, 25, 15, 10"); // Should be dropped.
1700 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "15, 25, 15, 10"); // Should be dropped.
1701 handler
->queue(LOK_CALLBACK_MOUSE_POINTER
, "text"); // Should be dropped.
1702 handler
->queue(LOK_CALLBACK_TEXT_SELECTION_START
, "15, 25, 15, 10"); // Superseded.
1703 handler
->queue(LOK_CALLBACK_TEXT_SELECTION_END
, "15, 25, 15, 10"); // Superseded.
1704 handler
->queue(LOK_CALLBACK_TEXT_SELECTION
, "15, 25, 15, 10"); // Superseded.
1705 handler
->queue(LOK_CALLBACK_TEXT_SELECTION_START
, "15, 25, 15, 10"); // Should be dropped.
1706 handler
->queue(LOK_CALLBACK_TEXT_SELECTION_END
, "15, 25, 15, 10"); // Should be dropped.
1707 handler
->queue(LOK_CALLBACK_TEXT_SELECTION
, ""); // 7
1708 handler
->queue(LOK_CALLBACK_TEXT_SELECTION_START
, "15, 25, 15, 10"); // 8
1709 handler
->queue(LOK_CALLBACK_TEXT_SELECTION_END
, "15, 25, 15, 10"); // 9
1710 handler
->queue(LOK_CALLBACK_CELL_CURSOR
, "15, 25, 15, 10"); // 10
1711 handler
->queue(LOK_CALLBACK_CURSOR_VISIBLE
, ""); // 11
1712 handler
->queue(LOK_CALLBACK_CELL_CURSOR
, "15, 25, 15, 10"); // Should be dropped.
1713 handler
->queue(LOK_CALLBACK_CELL_FORMULA
, "blah"); // 12
1714 handler
->queue(LOK_CALLBACK_SET_PART
, "1"); // 13
1715 handler
->queue(LOK_CALLBACK_STATE_CHANGED
, ".uno:AssignLayout=20"); // Superseded
1716 handler
->queue(LOK_CALLBACK_CURSOR_VISIBLE
, ""); // Should be dropped.
1717 handler
->queue(LOK_CALLBACK_CELL_FORMULA
, "blah"); // Should be dropped.
1718 handler
->queue(LOK_CALLBACK_SET_PART
, "1"); // Should be dropped.
1719 handler
->queue(LOK_CALLBACK_STATE_CHANGED
, ".uno:AssignLayout=1"); // 14
1721 Scheduler::ProcessEventsToIdle();
1723 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(14), notifs
.size());
1726 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
), std::get
<0>(notifs
[i
]));
1727 CPPUNIT_ASSERT_EQUAL(std::string(""), std::get
<1>(notifs
[i
++]));
1729 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_TILES
), std::get
<0>(notifs
[i
]));
1730 CPPUNIT_ASSERT_EQUAL(std::string("15, 25, 15, 10"), std::get
<1>(notifs
[i
++]));
1732 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_STATE_CHANGED
), std::get
<0>(notifs
[i
]));
1733 CPPUNIT_ASSERT_EQUAL(std::string(""), std::get
<1>(notifs
[i
++]));
1735 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_STATE_CHANGED
), std::get
<0>(notifs
[i
]));
1736 CPPUNIT_ASSERT_EQUAL(std::string(".uno:Bold"), std::get
<1>(notifs
[i
++]));
1738 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_STATE_CHANGED
), std::get
<0>(notifs
[i
]));
1739 CPPUNIT_ASSERT_EQUAL(std::string(""), std::get
<1>(notifs
[i
++]));
1741 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_MOUSE_POINTER
), std::get
<0>(notifs
[i
]));
1742 CPPUNIT_ASSERT_EQUAL(std::string("text"), std::get
<1>(notifs
[i
++]));
1744 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_TEXT_SELECTION
), std::get
<0>(notifs
[i
]));
1745 CPPUNIT_ASSERT_EQUAL(std::string(""), std::get
<1>(notifs
[i
++]));
1747 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_TEXT_SELECTION_START
), std::get
<0>(notifs
[i
]));
1748 CPPUNIT_ASSERT_EQUAL(std::string("15, 25, 15, 10"), std::get
<1>(notifs
[i
++]));
1750 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_TEXT_SELECTION_END
), std::get
<0>(notifs
[i
]));
1751 CPPUNIT_ASSERT_EQUAL(std::string("15, 25, 15, 10"), std::get
<1>(notifs
[i
++]));
1753 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_CELL_CURSOR
), std::get
<0>(notifs
[i
]));
1754 CPPUNIT_ASSERT_EQUAL(std::string("15, 25, 15, 10"), std::get
<1>(notifs
[i
++]));
1756 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_CURSOR_VISIBLE
), std::get
<0>(notifs
[i
]));
1757 CPPUNIT_ASSERT_EQUAL(std::string(""), std::get
<1>(notifs
[i
++]));
1759 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_CELL_FORMULA
), std::get
<0>(notifs
[i
]));
1760 CPPUNIT_ASSERT_EQUAL(std::string("blah"), std::get
<1>(notifs
[i
++]));
1762 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_SET_PART
), std::get
<0>(notifs
[i
]));
1763 CPPUNIT_ASSERT_EQUAL(std::string("1"), std::get
<1>(notifs
[i
++]));
1765 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_STATE_CHANGED
), std::get
<0>(notifs
[i
]));
1766 CPPUNIT_ASSERT_EQUAL(std::string(".uno:AssignLayout=1"), std::get
<1>(notifs
[i
++]));
1769 void DesktopLOKTest::testTileInvalidationCompression()
1771 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
1773 comphelper::LibreOfficeKit::setPartInInvalidation(true);
1774 comphelper::ScopeGuard
aGuard([]()
1776 comphelper::LibreOfficeKit::setPartInInvalidation(false);
1779 // Single part merging
1781 std::vector
<std::tuple
<int, std::string
>> notifs
;
1782 std::unique_ptr
<CallbackFlushHandler
> handler(new CallbackFlushHandler(pDocument
, callbackCompressionTest
, ¬ifs
));
1783 handler
->setViewId(SfxLokHelper::getView());
1785 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, 239, 239, 0, 0");
1786 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, 239, 239, 0, 0");
1787 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "-100, -50, 500, 650, 0, 0");
1788 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, -32767, -32767, 0, 0");
1789 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "100, 100, 200, 200, 0, 0");
1791 Scheduler::ProcessEventsToIdle();
1793 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), notifs
.size());
1796 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_TILES
), std::get
<0>(notifs
[i
]));
1797 CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 400, 600, 0, 0"), std::get
<1>(notifs
[i
++]));
1802 std::vector
<std::tuple
<int, std::string
>> notifs
;
1803 std::unique_ptr
<CallbackFlushHandler
> handler(new CallbackFlushHandler(pDocument
, callbackCompressionTest
, ¬ifs
));
1804 handler
->setViewId(SfxLokHelper::getView());
1806 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, 239, 239, 0, 0");
1807 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, 200, 200, 1, 0"); // Different part
1808 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, 0, 0, 2, 0"); // Invalid
1809 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "-121, -121, 200, 200, 0, 0"); // Inside first
1810 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, -32767, -32767, 1, 0"); // Invalid
1812 Scheduler::ProcessEventsToIdle();
1814 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), notifs
.size());
1817 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_TILES
), std::get
<0>(notifs
[i
]));
1818 CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 200, 200, 1, 0"), std::get
<1>(notifs
[i
++]));
1820 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_TILES
), std::get
<0>(notifs
[i
]));
1821 CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 239, 239, 0, 0"), std::get
<1>(notifs
[i
++]));
1826 std::vector
<std::tuple
<int, std::string
>> notifs
;
1827 std::unique_ptr
<CallbackFlushHandler
> handler(new CallbackFlushHandler(pDocument
, callbackCompressionTest
, ¬ifs
));
1828 handler
->setViewId(SfxLokHelper::getView());
1830 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, 239, 239, 0, 0"); // 0
1831 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, 200, 200, 1, 0"); // 1: Different part
1832 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, 0, 0, -1, 0"); // Invalid
1833 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "-121, -121, 200, 200, -1, 0"); // 0: All parts
1834 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, -32767, -32767, -1, 0"); // Invalid
1835 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "-100, -100, 1200, 1200, -1, 0"); // 0: All parts
1836 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, 239, 239, 3, 0"); // Overlapped
1837 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "1000, 1000, 1239, 1239, 2, 0"); // 1: Unique region
1839 Scheduler::ProcessEventsToIdle();
1841 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), notifs
.size());
1844 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_TILES
), std::get
<0>(notifs
[i
]));
1845 CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 1100, 1100, -1, 0"), std::get
<1>(notifs
[i
++]));
1847 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_TILES
), std::get
<0>(notifs
[i
]));
1848 CPPUNIT_ASSERT_EQUAL(std::string("1000, 1000, 1239, 1239, 2, 0"), std::get
<1>(notifs
[i
++]));
1851 // All Parts (partial)
1853 std::vector
<std::tuple
<int, std::string
>> notifs
;
1854 std::unique_ptr
<CallbackFlushHandler
> handler(new CallbackFlushHandler(pDocument
, callbackCompressionTest
, ¬ifs
));
1855 handler
->setViewId(SfxLokHelper::getView());
1857 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, 200, 200, 0, 0"); // 0
1858 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, 100, 100, 1, 0"); // 1: Different part
1859 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, 0, 0, -1, 0"); // Invalid
1860 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "150, 150, 50, 50, -1, 0"); // 2: All-parts
1861 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, -32767, -32767, -1, 0"); // Invalid
1862 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "150, 150, 40, 40, 3, 0"); // Overlapped w/ 2
1863 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, 200, 200, 4, 0"); // 3: Unique
1864 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "1000, 1000, 1239, 1239, 1, 0"); // 4: Unique
1866 Scheduler::ProcessEventsToIdle();
1868 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(5), notifs
.size());
1871 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_TILES
), std::get
<0>(notifs
[i
]));
1872 CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 200, 200, 0, 0"), std::get
<1>(notifs
[i
++]));
1874 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_TILES
), std::get
<0>(notifs
[i
]));
1875 CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 100, 100, 1, 0"), std::get
<1>(notifs
[i
++]));
1877 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_TILES
), std::get
<0>(notifs
[i
]));
1878 CPPUNIT_ASSERT_EQUAL(std::string("150, 150, 50, 50, -1, 0"), std::get
<1>(notifs
[i
++]));
1880 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_TILES
), std::get
<0>(notifs
[i
]));
1881 CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 200, 200, 4, 0"), std::get
<1>(notifs
[i
++]));
1883 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_TILES
), std::get
<0>(notifs
[i
]));
1884 CPPUNIT_ASSERT_EQUAL(std::string("1000, 1000, 1239, 1239, 1, 0"), std::get
<1>(notifs
[i
++]));
1887 // Merge with "EMPTY"
1889 std::vector
<std::tuple
<int, std::string
>> notifs
;
1890 std::unique_ptr
<CallbackFlushHandler
> handler(new CallbackFlushHandler(pDocument
, callbackCompressionTest
, ¬ifs
));
1891 handler
->setViewId(SfxLokHelper::getView());
1893 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, 239, 239, 0, 0");
1894 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "EMPTY, 0, 0");
1895 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, 239, 240, 0, 0");
1896 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "-121, -121, 300, 300, 0, 0");
1897 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "0, 0, -32767, -32767, 0, 0");
1899 Scheduler::ProcessEventsToIdle();
1901 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), notifs
.size());
1904 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_TILES
), std::get
<0>(notifs
[i
]));
1905 CPPUNIT_ASSERT_EQUAL(std::string("EMPTY, 0, 0"), std::get
<1>(notifs
[i
++]));
1909 void DesktopLOKTest::testPartInInvalidation()
1911 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
1912 // No part in invalidation: merge.
1914 std::vector
<std::tuple
<int, std::string
>> notifs
;
1915 std::unique_ptr
<CallbackFlushHandler
> handler(new CallbackFlushHandler(pDocument
, callbackCompressionTest
, ¬ifs
));
1916 handler
->setViewId(SfxLokHelper::getView());
1918 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "10, 10, 20, 10");
1919 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "20, 10, 20, 10");
1921 Scheduler::ProcessEventsToIdle();
1923 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), notifs
.size());
1925 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_TILES
), std::get
<0>(notifs
[0]));
1926 CPPUNIT_ASSERT_EQUAL(std::string("10, 10, 30, 10"), std::get
<1>(notifs
[0]));
1928 // No part in invalidation: don't merge.
1930 std::vector
<std::tuple
<int, std::string
>> notifs
;
1931 std::unique_ptr
<CallbackFlushHandler
> handler(new CallbackFlushHandler(pDocument
, callbackCompressionTest
, ¬ifs
));
1932 handler
->setViewId(SfxLokHelper::getView());
1934 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "10, 10, 20, 10");
1935 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "40, 10, 20, 10");
1937 Scheduler::ProcessEventsToIdle();
1939 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), notifs
.size());
1942 // Part in invalidation, intersection and parts match -> merge.
1944 comphelper::LibreOfficeKit::setPartInInvalidation(true);
1945 comphelper::ScopeGuard
aGuard([]()
1947 comphelper::LibreOfficeKit::setPartInInvalidation(false);
1950 std::vector
<std::tuple
<int, std::string
>> notifs
;
1951 std::unique_ptr
<CallbackFlushHandler
> handler(new CallbackFlushHandler(pDocument
, callbackCompressionTest
, ¬ifs
));
1952 handler
->setViewId(SfxLokHelper::getView());
1954 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "10, 10, 20, 10, 0, 0");
1955 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "20, 10, 20, 10, 0, 0");
1957 Scheduler::ProcessEventsToIdle();
1959 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), notifs
.size());
1961 // Part in invalidation, intersection and parts don't match -> don't merge.
1963 comphelper::LibreOfficeKit::setPartInInvalidation(true);
1964 comphelper::ScopeGuard
aGuard([]()
1966 comphelper::LibreOfficeKit::setPartInInvalidation(false);
1969 std::vector
<std::tuple
<int, std::string
>> notifs
;
1970 std::unique_ptr
<CallbackFlushHandler
> handler(new CallbackFlushHandler(pDocument
, callbackCompressionTest
, ¬ifs
));
1971 handler
->setViewId(SfxLokHelper::getView());
1973 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "10, 10, 20, 10, 0, 0");
1974 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, "20, 10, 20, 10, 1, 0");
1976 Scheduler::ProcessEventsToIdle();
1978 // This failed as RectangleAndPart::Create() always assumed no part in
1979 // payload, so this was merged -> it was 1.
1980 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), notifs
.size());
1984 static void callbackBinaryCallbackTest(const int type
, const char* payload
, void* data
)
1986 std::vector
<std::tuple
<int, std::string
>>* notifs
= static_cast<std::vector
<std::tuple
<int, std::string
>>*>(data
);
1987 notifs
->emplace_back(type
, std::string(payload
? payload
: "(nil)"));
1990 void DesktopLOKTest::testBinaryCallback()
1992 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
1994 const tools::Rectangle
rect1(Point(10,15),Size(20,25));
1995 const std::string
rect1String(rect1
.toString());
1996 // Verify that using queue() and libreOfficeKitViewInvalidateTilesCallback() has the same result.
1998 std::vector
<std::tuple
<int, std::string
>> notifs
;
1999 std::unique_ptr
<CallbackFlushHandler
> handler(new CallbackFlushHandler(pDocument
, callbackBinaryCallbackTest
, ¬ifs
));
2000 handler
->setViewId(SfxLokHelper::getView());
2002 handler
->queue(LOK_CALLBACK_INVALIDATE_TILES
, OString(rect1String
));
2004 Scheduler::ProcessEventsToIdle();
2006 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), notifs
.size());
2007 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_TILES
), std::get
<0>(notifs
[0]));
2008 CPPUNIT_ASSERT_EQUAL(rect1String
, std::get
<1>(notifs
[0]));
2011 std::vector
<std::tuple
<int, std::string
>> notifs
;
2012 std::unique_ptr
<CallbackFlushHandler
> handler(new CallbackFlushHandler(pDocument
, callbackBinaryCallbackTest
, ¬ifs
));
2013 handler
->setViewId(SfxLokHelper::getView());
2015 handler
->libreOfficeKitViewInvalidateTilesCallback(&rect1
, INT_MIN
, 0);
2017 Scheduler::ProcessEventsToIdle();
2019 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), notifs
.size());
2020 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_TILES
), std::get
<0>(notifs
[0]));
2021 CPPUNIT_ASSERT_EQUAL(rect1String
, std::get
<1>(notifs
[0]));
2023 // Verify that the "EMPTY" invalidation gets converted properly.
2025 std::vector
<std::tuple
<int, std::string
>> notifs
;
2026 std::unique_ptr
<CallbackFlushHandler
> handler(new CallbackFlushHandler(pDocument
, callbackBinaryCallbackTest
, ¬ifs
));
2027 handler
->setViewId(SfxLokHelper::getView());
2029 handler
->libreOfficeKitViewInvalidateTilesCallback(nullptr, INT_MIN
, 0);
2031 Scheduler::ProcessEventsToIdle();
2033 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), notifs
.size());
2034 CPPUNIT_ASSERT_EQUAL(int(LOK_CALLBACK_INVALIDATE_TILES
), std::get
<0>(notifs
[0]));
2035 CPPUNIT_ASSERT_EQUAL(std::string("EMPTY"), std::get
<1>(notifs
[0]));
2039 void DesktopLOKTest::testDialogInput()
2041 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
2042 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:HyperlinkDialog", nullptr, false);
2043 Scheduler::ProcessEventsToIdle();
2045 SfxViewShell
* pViewShell
= SfxViewShell::Current();
2046 pViewShell
->GetViewFrame().GetBindings().Update();
2048 VclPtr
<vcl::Window
> pWindow(Application::GetActiveTopWindow());
2049 CPPUNIT_ASSERT(pWindow
);
2051 Control
* pCtrlFocused
= GetFocusControl(pWindow
.get());
2052 CPPUNIT_ASSERT(pCtrlFocused
);
2053 CPPUNIT_ASSERT_EQUAL(WindowType::COMBOBOX
, pCtrlFocused
->GetType());
2054 CPPUNIT_ASSERT_EQUAL(OUString(""), pCtrlFocused
->GetText());
2056 vcl::LOKWindowId nDialogId
= pWindow
->GetLOKWindowId();
2057 pDocument
->pClass
->postWindowExtTextInputEvent(pDocument
, nDialogId
, LOK_EXT_TEXTINPUT
, "wiki.");
2058 pDocument
->pClass
->postWindowExtTextInputEvent(pDocument
, nDialogId
, LOK_EXT_TEXTINPUT_END
, "wiki.");
2059 pDocument
->pClass
->removeTextContext(pDocument
, nDialogId
, 1, 0);
2060 Scheduler::ProcessEventsToIdle();
2061 CPPUNIT_ASSERT_EQUAL(OUString("wiki"), pCtrlFocused
->GetText());
2063 static_cast<SystemWindow
*>(pWindow
.get())->Close();
2064 Scheduler::ProcessEventsToIdle();
2067 void DesktopLOKTest::testInput()
2069 // Load a Writer document, enable change recording and press a key.
2070 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
2072 Scheduler::ProcessEventsToIdle(); // Get focus & other bits setup.
2074 pDocument
->pClass
->postWindowExtTextInputEvent(pDocument
, 0, LOK_EXT_TEXTINPUT
, "far");
2075 pDocument
->pClass
->postWindowExtTextInputEvent(pDocument
, 0, LOK_EXT_TEXTINPUT_END
, "far");
2076 pDocument
->pClass
->postWindowExtTextInputEvent(pDocument
, 0, LOK_EXT_TEXTINPUT
, " ");
2077 pDocument
->pClass
->postWindowExtTextInputEvent(pDocument
, 0, LOK_EXT_TEXTINPUT_END
, " ");
2078 pDocument
->pClass
->postWindowExtTextInputEvent(pDocument
, 0, LOK_EXT_TEXTINPUT
, "beyond");
2079 pDocument
->pClass
->postWindowExtTextInputEvent(pDocument
, 0, LOK_EXT_TEXTINPUT_END
, "beyond");
2080 pDocument
->pClass
->postWindowExtTextInputEvent(pDocument
, 0, LOK_EXT_TEXTINPUT
, " ");
2081 pDocument
->pClass
->postWindowExtTextInputEvent(pDocument
, 0, LOK_EXT_TEXTINPUT_END
, " ");
2083 pDocument
->pClass
->postWindowExtTextInputEvent(pDocument
, 0, LOK_EXT_TEXTINPUT
, "kovely");
2084 pDocument
->pClass
->postWindowExtTextInputEvent(pDocument
, 0, LOK_EXT_TEXTINPUT_END
, "kovely");
2086 pDocument
->pClass
->removeTextContext(pDocument
, 0, 6, 0);
2087 // Replace it with lovely
2088 pDocument
->pClass
->postWindowExtTextInputEvent(pDocument
, 0, LOK_EXT_TEXTINPUT
, "lovely");
2089 pDocument
->pClass
->postWindowExtTextInputEvent(pDocument
, 0, LOK_EXT_TEXTINPUT_END
, "lovely");
2090 pDocument
->pClass
->postWindowExtTextInputEvent(pDocument
, 0, LOK_EXT_TEXTINPUT
, " ");
2091 pDocument
->pClass
->postWindowExtTextInputEvent(pDocument
, 0, LOK_EXT_TEXTINPUT_END
, " ");
2094 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:SelectAll", nullptr, false);
2095 Scheduler::ProcessEventsToIdle();
2096 char* pText
= pDocument
->pClass
->getTextSelection(pDocument
, "text/plain;charset=utf-8", nullptr);
2097 CPPUNIT_ASSERT(pText
!= nullptr);
2098 CPPUNIT_ASSERT_EQUAL(OString("far beyond lovely "), OString(pText
));
2102 void DesktopLOKTest::testRedlineWriter()
2104 // Load a Writer document, enable change recording and press a key.
2105 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
2106 uno::Reference
<beans::XPropertySet
> xPropertySet(mxComponent
, uno::UNO_QUERY
);
2107 xPropertySet
->setPropertyValue("RecordChanges", uno::Any(true));
2108 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 't', 0);
2109 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYUP
, 't', 0);
2110 Scheduler::ProcessEventsToIdle();
2112 // Get redline info.
2113 boost::property_tree::ptree aTree
;
2114 char* pJSON
= pDocument
->m_pDocumentClass
->getCommandValues(pDocument
, ".uno:AcceptTrackedChanges");
2115 std::stringstream
aStream(pJSON
);
2117 CPPUNIT_ASSERT(!aStream
.str().empty());
2118 boost::property_tree::read_json(aStream
, aTree
);
2119 // Make sure that pressing a key creates exactly one redline.
2120 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aTree
.get_child("redlines").size());
2122 for (const boost::property_tree::ptree::value_type
& rRedline
: aTree
.get_child("redlines"))
2123 // This failed with boost::property_tree::ptree_bad_path, as there were no description field.
2124 CPPUNIT_ASSERT_EQUAL(std::string("Insert \xE2\x80\x9Ct\xE2\x80\x9D"), rRedline
.second
.get
<std::string
>("description"));
2125 // U+201C LEFT DOUBLE QUOTATION MARK, U+201D RIGHT DOUBLE QUOTATION
2129 void DesktopLOKTest::testRedlineCalc()
2131 // Load a Writer document, enable change recording and press a key.
2132 LibLODocument_Impl
* pDocument
= loadDoc("sheets.ods");
2133 uno::Reference
<beans::XPropertySet
> xPropertySet(mxComponent
, uno::UNO_QUERY
);
2134 xPropertySet
->setPropertyValue("RecordChanges", uno::Any(true));
2135 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 't', 0);
2136 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYUP
, 't', 0);
2137 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 0, KEY_RETURN
);
2138 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYUP
, 0, KEY_RETURN
);
2139 Scheduler::ProcessEventsToIdle();
2141 // Get redline info.
2142 boost::property_tree::ptree aTree
;
2143 char* pJSON
= pDocument
->m_pDocumentClass
->getCommandValues(pDocument
, ".uno:AcceptTrackedChanges");
2144 std::stringstream
aStream(pJSON
);
2146 CPPUNIT_ASSERT(!aStream
.str().empty());
2147 boost::property_tree::read_json(aStream
, aTree
);
2148 // Make sure that pressing a key creates exactly one redline.
2149 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aTree
.get_child("redlines").size());
2151 for (const boost::property_tree::ptree::value_type
& rRedline
: aTree
.get_child("redlines"))
2152 // This failed with boost::property_tree::ptree_bad_path, as there were no description field.
2153 CPPUNIT_ASSERT_EQUAL(std::string("Cell B4 changed from '5' to 't'"), rRedline
.second
.get
<std::string
>("description"));
2160 LibLODocument_Impl
* mpDocument
;
2163 OString m_aCellFormula
;
2164 int m_nTableSelectionCount
;
2165 int m_nColorPaletteCallbackCount
= 0;
2166 bool m_bEmptyTableSelection
;
2167 bool m_bTilesInvalidated
;
2169 tools::Rectangle m_aOwnCursor
;
2170 boost::property_tree::ptree m_aCommentCallbackResult
;
2171 boost::property_tree::ptree m_aCallbackWindowResult
;
2172 boost::property_tree::ptree m_aColorPaletteCallbackResult
;
2173 bool m_bWindowHidden
;
2175 ViewCallback(LibLODocument_Impl
* pDocument
)
2176 : mpDocument(pDocument
),
2177 m_nTableSelectionCount(0),
2178 m_bEmptyTableSelection(false),
2179 m_bTilesInvalidated(false),
2180 m_bZeroCursor(false)
2182 mnView
= SfxLokHelper::getView();
2183 mpDocument
->m_pDocumentClass
->registerCallback(pDocument
, &ViewCallback::callback
, this);
2188 mpDocument
->m_pDocumentClass
->setView(mpDocument
, mnView
);
2189 mpDocument
->m_pDocumentClass
->registerCallback(mpDocument
, nullptr, nullptr);
2192 static void callback(int nType
, const char* pPayload
, void* pData
)
2194 static_cast<ViewCallback
*>(pData
)->callbackImpl(nType
, pPayload
);
2197 void callbackImpl(int nType
, const char* pPayload
)
2199 OString
aPayload(pPayload
);
2202 case LOK_CALLBACK_INVALIDATE_TILES
:
2204 m_bTilesInvalidated
= true;
2207 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
2209 uno::Sequence
<OUString
> aSeq
= comphelper::string::convertCommaSeparated(OUString::fromUtf8(aPayload
));
2210 if (std::string_view("EMPTY") == pPayload
)
2212 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(4), aSeq
.getLength());
2213 m_aOwnCursor
.SetLeft(aSeq
[0].toInt32());
2214 m_aOwnCursor
.SetTop(aSeq
[1].toInt32());
2215 m_aOwnCursor
.setWidth(aSeq
[2].toInt32());
2216 m_aOwnCursor
.setHeight(aSeq
[3].toInt32());
2218 if (m_aOwnCursor
.Left() == 0 && m_aOwnCursor
.Top() == 0)
2219 m_bZeroCursor
= true;
2222 case LOK_CALLBACK_COMMENT
:
2224 m_aCommentCallbackResult
.clear();
2225 std::stringstream
aStream(pPayload
);
2226 boost::property_tree::read_json(aStream
, m_aCommentCallbackResult
);
2227 m_aCommentCallbackResult
= m_aCommentCallbackResult
.get_child("comment");
2230 case LOK_CALLBACK_WINDOW
:
2232 m_aCallbackWindowResult
.clear();
2233 std::stringstream
aStream(pPayload
);
2234 boost::property_tree::read_json(aStream
, m_aCallbackWindowResult
);
2236 std::string sAction
= m_aCallbackWindowResult
.get
<std::string
>("action");
2237 if (sAction
== "hide")
2238 m_bWindowHidden
= true;
2241 case LOK_CALLBACK_CELL_FORMULA
:
2243 m_aCellFormula
= aPayload
;
2246 case LOK_CALLBACK_TABLE_SELECTED
:
2248 m_bEmptyTableSelection
= (std::string(pPayload
).compare("{ }") == 0);
2249 ++m_nTableSelectionCount
;
2252 case LOK_CALLBACK_COLOR_PALETTES
:
2254 m_aColorPaletteCallbackResult
.clear();
2255 std::stringstream
aStream(pPayload
);
2256 boost::property_tree::read_json(aStream
, m_aColorPaletteCallbackResult
);
2257 ++m_nColorPaletteCallbackCount
;
2266 void DesktopLOKTest::testPaintPartTile()
2268 // Load an impress doc of 2 slides.
2269 // ViewCallback aView1;
2270 // ViewCallback aView2;
2271 LibLODocument_Impl
* pDocument
= loadDoc("2slides.odp");
2272 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
2273 // pDocument->m_pDocumentClass->registerCallback(pDocument, &ViewCallback::callback, &aView1);
2274 int nView1
= pDocument
->m_pDocumentClass
->getView(pDocument
);
2276 // Create a second view.
2277 pDocument
->m_pDocumentClass
->createView(pDocument
);
2278 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
2279 // pDocument->m_pDocumentClass->registerCallback(pDocument, &ViewCallback::callback, &aView2);
2281 // Go to the second slide in the second view.
2282 pDocument
->m_pDocumentClass
->setPart(pDocument
, 1);
2284 // Switch back to the first view and start typing.
2285 pDocument
->m_pDocumentClass
->setView(pDocument
, nView1
);
2286 pDocument
->m_pDocumentClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::TAB
);
2287 pDocument
->m_pDocumentClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYUP
, 0, awt::Key::TAB
);
2288 pDocument
->m_pDocumentClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 'x', 0);
2289 pDocument
->m_pDocumentClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYUP
, 'x', 0);
2290 Scheduler::ProcessEventsToIdle();
2292 // Call paintPartTile() to paint the second part (in whichever view it finds suitable for this).
2293 unsigned char pPixels
[256 * 256 * 4];
2294 pDocument
->m_pDocumentClass
->paintPartTile(pDocument
, pPixels
, 1, 0, 256, 256, 0, 0, 256, 256);
2297 Scheduler::ProcessEventsToIdle();
2298 // aView1.m_bTilesInvalidated = false;
2299 pDocument
->m_pDocumentClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 'x', 0);
2300 pDocument
->m_pDocumentClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYUP
, 'x', 0);
2301 Scheduler::ProcessEventsToIdle();
2302 // This failed: paintPartTile() (as a side-effect) ended the text edit of
2303 // the first view, so there were no invalidations.
2304 //CPPUNIT_ASSERT(aView1.m_bTilesInvalidated);
2308 void DesktopLOKTest::testGetFontSubset()
2310 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
2311 OUString aFontName
= rtl::Uri::encode(
2312 OUString("Liberation Sans"),
2313 rtl_UriCharClassRelSegment
,
2314 rtl_UriEncodeKeepEscapes
,
2315 RTL_TEXTENCODING_UTF8
2317 OString aCommand
= ".uno:FontSubset&name=" + OUStringToOString(aFontName
, RTL_TEXTENCODING_UTF8
);
2318 boost::property_tree::ptree aTree
;
2319 char* pJSON
= pDocument
->m_pDocumentClass
->getCommandValues(pDocument
, aCommand
.getStr());
2320 std::stringstream
aStream(pJSON
);
2321 boost::property_tree::read_json(aStream
, aTree
);
2322 CPPUNIT_ASSERT( !aTree
.empty() );
2323 CPPUNIT_ASSERT_EQUAL( std::string(".uno:FontSubset"), aTree
.get_child("commandName").get_value
<std::string
>() );
2324 boost::property_tree::ptree aValues
= aTree
.get_child("commandValues");
2325 CPPUNIT_ASSERT( !aValues
.empty() );
2330 void DesktopLOKTest::testCommentsWriter()
2332 // Disable tiled rendering for comments
2333 comphelper::LibreOfficeKit::setTiledAnnotations(false);
2335 LibLODocument_Impl
* pDocument
= loadDoc("comments.odt");
2336 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, nullptr);
2337 tools::Long nWidth
, nHeight
;
2338 pDocument
->m_pDocumentClass
->getDocumentSize(pDocument
, &nWidth
, &nHeight
);
2340 // Document width alongwith without sidebar comes to be < 13000
2341 CPPUNIT_ASSERT( nWidth
< 13000 );
2343 // Can we get all the comments using .uno:ViewAnnotations command ?
2344 boost::property_tree::ptree aTree
;
2345 char* pJSON
= pDocument
->m_pDocumentClass
->getCommandValues(pDocument
, ".uno:ViewAnnotations");
2346 std::stringstream
aStream(pJSON
);
2348 CPPUNIT_ASSERT(!aStream
.str().empty());
2349 boost::property_tree::read_json(aStream
, aTree
);
2350 // There are 3 comments in the document already
2351 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aTree
.get_child("comments").size());
2353 int nComment2Id
= 0;
2354 // Check if all comment fields have valid data
2355 for (const auto& rComment
: aTree
.get_child("comments"))
2357 CPPUNIT_ASSERT(rComment
.second
.get
<int>("id") > 0);
2358 CPPUNIT_ASSERT(!rComment
.second
.get
<std::string
>("author").empty());
2359 CPPUNIT_ASSERT(!rComment
.second
.get
<std::string
>("text").empty());
2360 // Has a valid iso 8601 date time string
2361 css::util::DateTime aDateTime
;
2362 OUString aDateTimeString
= OUString::createFromAscii(rComment
.second
.get
<std::string
>("dateTime"));
2363 CPPUNIT_ASSERT(utl::ISO8601parseDateTime(aDateTimeString
, aDateTime
));
2365 // This comment has a marked text range
2366 if (rComment
.second
.get
<std::string
>("text") == "Comment 2")
2368 CPPUNIT_ASSERT(!rComment
.second
.get
<std::string
>("textRange").empty());
2369 nComment2Id
= rComment
.second
.get
<int>("id");
2371 // This is a reply comment
2372 else if (rComment
.second
.get
<std::string
>("text") == "Reply to Comment 2")
2374 CPPUNIT_ASSERT_EQUAL(nComment2Id
, rComment
.second
.get
<int>("parent"));
2378 comphelper::LibreOfficeKit::setTiledAnnotations(true);
2382 void DesktopLOKTest::testCommentsCalc()
2384 // Disable tiled rendering for comments
2385 comphelper::LibreOfficeKit::setTiledAnnotations(false);
2387 LibLODocument_Impl
* pDocument
= loadDoc("sheets.ods");
2388 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, nullptr);
2390 // Can we get all the comments using .uno:ViewAnnotations command ?
2391 boost::property_tree::ptree aTree
;
2392 char* pJSON
= pDocument
->m_pDocumentClass
->getCommandValues(pDocument
, ".uno:ViewAnnotations");
2393 std::stringstream
aStream(pJSON
);
2395 CPPUNIT_ASSERT(!aStream
.str().empty());
2396 boost::property_tree::read_json(aStream
, aTree
);
2397 // There are 2 comments in the document already
2398 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), aTree
.get_child("comments").size());
2400 // Check if all comment fields have valid data
2402 for (const auto& rComment
: aTree
.get_child("comments"))
2408 CPPUNIT_ASSERT_EQUAL(std::string("4"), rComment
.second
.get
<std::string
>("tab"));
2409 CPPUNIT_ASSERT_EQUAL(std::string("Comment1"), rComment
.second
.get
<std::string
>("text"));
2410 CPPUNIT_ASSERT_EQUAL(std::string("7650, 3570, 1274, 254"), rComment
.second
.get
<std::string
>("cellPos"));
2415 CPPUNIT_ASSERT_EQUAL(std::string("4"), rComment
.second
.get
<std::string
>("tab"));
2416 CPPUNIT_ASSERT_EQUAL(std::string("Comment2"), rComment
.second
.get
<std::string
>("text"));
2417 CPPUNIT_ASSERT_EQUAL(std::string("8925, 4335, 1274, 254"), rComment
.second
.get
<std::string
>("cellPos"));
2425 // We checked all the comments
2426 CPPUNIT_ASSERT_EQUAL(2, nIdx
);
2428 comphelper::LibreOfficeKit::setTiledAnnotations(true);
2432 void DesktopLOKTest::testCommentsImpress()
2434 // Disable tiled rendering for comments
2435 comphelper::LibreOfficeKit::setTiledAnnotations(false);
2437 LibLODocument_Impl
* pDocument
= loadDoc("blank_presentation.odp");
2438 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, nullptr);
2440 // Can we get all the comments using .uno:ViewAnnotations command ?
2441 boost::property_tree::ptree aTree
;
2442 char* pJSON
= pDocument
->m_pDocumentClass
->getCommandValues(pDocument
, ".uno:ViewAnnotations");
2443 std::stringstream
aStream(pJSON
);
2445 CPPUNIT_ASSERT(!aStream
.str().empty());
2446 boost::property_tree::read_json(aStream
, aTree
);
2447 // There are 2 comments in the document already
2448 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), aTree
.get_child("comments").size());
2450 // Check if all comment fields have valid data
2452 for (const auto& rComment
: aTree
.get_child("comments"))
2458 CPPUNIT_ASSERT(rComment
.second
.get
<int>("id") > 0);
2459 CPPUNIT_ASSERT_EQUAL(std::string("This is comment1"), rComment
.second
.get
<std::string
>("text"));
2460 CPPUNIT_ASSERT_EQUAL(std::string("LOK User1"), rComment
.second
.get
<std::string
>("author"));
2461 css::util::DateTime aDateTime
;
2462 OUString aDateTimeString
= OUString::createFromAscii(rComment
.second
.get
<std::string
>("dateTime"));
2463 CPPUNIT_ASSERT(utl::ISO8601parseDateTime(aDateTimeString
, aDateTime
));
2468 CPPUNIT_ASSERT(rComment
.second
.get
<int>("id") > 0);
2469 CPPUNIT_ASSERT_EQUAL(std::string("This is comment2"), rComment
.second
.get
<std::string
>("text"));
2470 CPPUNIT_ASSERT_EQUAL(std::string("LOK User2"), rComment
.second
.get
<std::string
>("author"));
2471 css::util::DateTime aDateTime
;
2472 OUString aDateTimeString
= OUString::createFromAscii(rComment
.second
.get
<std::string
>("dateTime"));
2473 CPPUNIT_ASSERT(utl::ISO8601parseDateTime(aDateTimeString
, aDateTime
));
2481 // We checked all the comments
2482 CPPUNIT_ASSERT_EQUAL(2, nIdx
);
2484 comphelper::LibreOfficeKit::setTiledAnnotations(true);
2487 void DesktopLOKTest::testCommentsCallbacksWriter()
2489 // Comments callback are emitted only if tiled annotations are off
2490 comphelper::LibreOfficeKit::setTiledAnnotations(false);
2491 LibLODocument_Impl
* pDocument
= loadDoc("comments.odt");
2492 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
2493 ViewCallback
aView1(pDocument
);
2494 pDocument
->m_pDocumentClass
->createView(pDocument
);
2495 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
2496 ViewCallback
aView2(pDocument
);
2498 // Add a new comment
2499 OString
aCommandArgs("{ \"Text\": { \"type\": \"string\", \"value\": \"Additional comment\" }, \"Author\": { \"type\": \"string\", \"value\": \"LOK User1\" } }");
2500 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:InsertAnnotation", aCommandArgs
.getStr(), false);
2501 Scheduler::ProcessEventsToIdle();
2503 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action
2504 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2505 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2506 int nCommentId1
= aView1
.m_aCommentCallbackResult
.get
<int>("id");
2508 // Reply to a comment just added
2509 aCommandArgs
= "{ \"Id\": { \"type\": \"string\", \"value\": \"" + OString::number(nCommentId1
) + "\" }, \"Text\": { \"type\": \"string\", \"value\": \"Reply comment\" } }";
2510 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:ReplyComment", aCommandArgs
.getStr(), false);
2511 Scheduler::ProcessEventsToIdle();
2513 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action and linked to its parent comment
2514 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2515 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2516 CPPUNIT_ASSERT_EQUAL(nCommentId1
, aView1
.m_aCommentCallbackResult
.get
<int>("parent"));
2517 CPPUNIT_ASSERT_EQUAL(nCommentId1
, aView2
.m_aCommentCallbackResult
.get
<int>("parent"));
2518 CPPUNIT_ASSERT_EQUAL(std::string("Reply comment"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("text"));
2519 CPPUNIT_ASSERT_EQUAL(std::string("Reply comment"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("text"));
2520 int nCommentId2
= aView1
.m_aCommentCallbackResult
.get
<int>("id");
2522 // Edit the previously added comment
2523 aCommandArgs
= "{ \"Id\": { \"type\": \"string\", \"value\": \"" + OString::number(nCommentId2
) + "\" }, \"Text\": { \"type\": \"string\", \"value\": \"Edited comment\" } }";
2524 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:EditAnnotation", aCommandArgs
.getStr(), false);
2525 Scheduler::ProcessEventsToIdle();
2527 // We received a LOK_CALLBACK_COMMENT callback with comment 'Modify' action
2528 CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2529 CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2530 // parent is unchanged still
2531 CPPUNIT_ASSERT_EQUAL(nCommentId1
, aView1
.m_aCommentCallbackResult
.get
<int>("parent"));
2532 CPPUNIT_ASSERT_EQUAL(nCommentId1
, aView2
.m_aCommentCallbackResult
.get
<int>("parent"));
2533 CPPUNIT_ASSERT_EQUAL(std::string("Edited comment"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("text"));
2534 CPPUNIT_ASSERT_EQUAL(std::string("Edited comment"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("text"));
2536 // Delete the reply comment just added
2537 aCommandArgs
= "{ \"Id\": { \"type\": \"string\", \"value\": \"" + OString::number(nCommentId2
) + "\" } }";
2538 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:DeleteComment", aCommandArgs
.getStr(), false);
2539 Scheduler::ProcessEventsToIdle();
2541 // We received a LOK_CALLBACK_COMMENT callback with comment 'Remove' action
2542 CPPUNIT_ASSERT_EQUAL(std::string("Remove"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2543 CPPUNIT_ASSERT_EQUAL(std::string("Remove"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2544 CPPUNIT_ASSERT_EQUAL(nCommentId2
, aView1
.m_aCommentCallbackResult
.get
<int>("id"));
2545 CPPUNIT_ASSERT_EQUAL(nCommentId2
, aView2
.m_aCommentCallbackResult
.get
<int>("id"));
2547 // Reply to nCommentId1 again
2548 aCommandArgs
= "{ \"Id\": { \"type\": \"string\", \"value\": \"" + OString::number(nCommentId1
) + "\" }, \"Text\": { \"type\": \"string\", \"value\": \"Reply comment again\" } }";
2549 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:ReplyComment", aCommandArgs
.getStr(), false);
2550 Scheduler::ProcessEventsToIdle();
2552 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action and linked to its parent comment
2553 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2554 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2555 CPPUNIT_ASSERT_EQUAL(nCommentId1
, aView1
.m_aCommentCallbackResult
.get
<int>("parent"));
2556 CPPUNIT_ASSERT_EQUAL(nCommentId1
, aView2
.m_aCommentCallbackResult
.get
<int>("parent"));
2557 CPPUNIT_ASSERT_EQUAL(std::string("Reply comment again"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("text"));
2558 CPPUNIT_ASSERT_EQUAL(std::string("Reply comment again"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("text"));
2560 // .uno:ViewAnnotations returns total of 5 comments
2561 boost::property_tree::ptree aTree
;
2562 char* pJSON
= pDocument
->m_pDocumentClass
->getCommandValues(pDocument
, ".uno:ViewAnnotations");
2563 std::stringstream
aStream(pJSON
);
2565 CPPUNIT_ASSERT(!aStream
.str().empty());
2566 boost::property_tree::read_json(aStream
, aTree
);
2567 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(5), aTree
.get_child("comments").size());
2573 void addParameter(tools::JsonWriter
& rJson
, const char* sName
, std::string_view type
, std::string_view value
)
2575 auto testNode
= rJson
.startNode(sName
);
2576 rJson
.put("type", type
);
2577 rJson
.put("value", value
);
2582 void DesktopLOKTest::testCommentsAddEditDeleteDraw()
2584 // Comments callback are emitted only if tiled annotations are off
2585 comphelper::LibreOfficeKit::setTiledAnnotations(false);
2586 LibLODocument_Impl
* pDocument
= loadDoc("BlankDrawDocument.odg");
2587 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
2588 ViewCallback
aView1(pDocument
);
2590 // Add a new comment
2591 OString aCommandArgs
;
2593 tools::JsonWriter aJson
;
2594 addParameter(aJson
, "Text", "string", "Comment");
2595 addParameter(aJson
, "Author", "string", "LOK User1");
2596 aCommandArgs
= aJson
.finishAndGetAsOString();
2599 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:InsertAnnotation", aCommandArgs
.getStr(), false);
2600 Scheduler::ProcessEventsToIdle();
2602 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action
2603 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2604 int nCommentId1
= aView1
.m_aCommentCallbackResult
.get
<int>("id");
2606 // Edit the previously added comment
2608 tools::JsonWriter aJson
;
2609 addParameter(aJson
, "Id", "string", OString::number(nCommentId1
));
2610 addParameter(aJson
, "Text", "string", "Edited comment");
2611 aCommandArgs
= aJson
.finishAndGetAsOString();
2614 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:EditAnnotation", aCommandArgs
.getStr(), false);
2615 Scheduler::ProcessEventsToIdle();
2617 // We received a LOK_CALLBACK_COMMENT callback with comment 'Modify' action
2618 CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2619 CPPUNIT_ASSERT_EQUAL(nCommentId1
, aView1
.m_aCommentCallbackResult
.get
<int>("id"));
2623 tools::JsonWriter aJson
;
2624 addParameter(aJson
, "Id", "string", OString::number(nCommentId1
));
2625 aCommandArgs
= aJson
.finishAndGetAsOString();
2627 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:DeleteAnnotation", aCommandArgs
.getStr(), false);
2628 Scheduler::ProcessEventsToIdle();
2630 // We received a LOK_CALLBACK_COMMENT callback with comment 'Remove' action
2631 CPPUNIT_ASSERT_EQUAL(std::string("Remove"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2632 CPPUNIT_ASSERT_EQUAL(nCommentId1
, aView1
.m_aCommentCallbackResult
.get
<int>("id"));
2635 void DesktopLOKTest::testRunMacro()
2637 LibLibreOffice_Impl aOffice
;
2638 bool bGoodMacro
, bNonExistentMacro
;
2640 // Tools macros come pre-installed in system share/basic folder,
2641 bGoodMacro
= aOffice
.m_pOfficeClass
->runMacro(&aOffice
, OString("macro:///Tools.Debug.ActivateReadOnlyFlag()").getStr());
2642 CPPUNIT_ASSERT(bGoodMacro
);
2644 bNonExistentMacro
= aOffice
.m_pOfficeClass
->runMacro(&aOffice
, OString("macro:///I.Am.Not(There)").getStr());
2645 CPPUNIT_ASSERT(!bNonExistentMacro
);
2648 void DesktopLOKTest::testExtractParameter()
2650 OUString
aOptions("Language=de-DE");
2651 OUString aValue
= extractParameter(aOptions
, u
"Language");
2652 CPPUNIT_ASSERT_EQUAL(OUString("de-DE"), aValue
);
2653 CPPUNIT_ASSERT_EQUAL(OUString(), aOptions
);
2655 aOptions
= "Language=en-US,Something";
2656 aValue
= extractParameter(aOptions
, u
"Language");
2657 CPPUNIT_ASSERT_EQUAL(OUString("en-US"), aValue
);
2658 CPPUNIT_ASSERT_EQUAL(OUString("Something"), aOptions
);
2660 aOptions
= "SomethingElse,Language=cs-CZ";
2661 aValue
= extractParameter(aOptions
, u
"Language");
2662 CPPUNIT_ASSERT_EQUAL(OUString("cs-CZ"), aValue
);
2663 CPPUNIT_ASSERT_EQUAL(OUString("SomethingElse"), aOptions
);
2665 aOptions
= "Something1,Language=hu-HU,Something2";
2666 aValue
= extractParameter(aOptions
, u
"Language");
2667 CPPUNIT_ASSERT_EQUAL(OUString("hu-HU"), aValue
);
2668 CPPUNIT_ASSERT_EQUAL(OUString("Something1,Something2"), aOptions
);
2670 aOptions
= "Something1,Something2=blah,Something3";
2671 aValue
= extractParameter(aOptions
, u
"Language");
2672 CPPUNIT_ASSERT_EQUAL(OUString(), aValue
);
2673 CPPUNIT_ASSERT_EQUAL(OUString("Something1,Something2=blah,Something3"), aOptions
);
2676 void DesktopLOKTest::readFileIntoByteVector(std::u16string_view sFilename
, std::vector
<unsigned char> & rByteVector
)
2678 rByteVector
.clear();
2679 OUString aURL
= createFileURL(sFilename
);
2680 SvFileStream
aStream(aURL
, StreamMode::READ
);
2681 rByteVector
.resize(aStream
.remainingSize());
2682 aStream
.ReadBytes(rByteVector
.data(), aStream
.remainingSize());
2685 void DesktopLOKTest::testGetSignatureState_Signed()
2687 LibLODocument_Impl
* pDocument
= loadDoc("signed.odt");
2688 Scheduler::ProcessEventsToIdle();
2689 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
2690 int nState
= pDocument
->m_pDocumentClass
->getSignatureState(pDocument
);
2693 // Already SignatureState::OK, then can't test the effect of trusting new CAs.
2697 CPPUNIT_ASSERT_EQUAL(int(4), nState
);
2699 std::vector
<unsigned char> aCertificate
;
2701 readFileIntoByteVector(u
"rootCA.der", aCertificate
);
2702 bool bResult
= pDocument
->m_pDocumentClass
->addCertificate(
2703 pDocument
, aCertificate
.data(), int(aCertificate
.size()));
2704 CPPUNIT_ASSERT(bResult
);
2708 readFileIntoByteVector(u
"intermediateRootCA.der", aCertificate
);
2709 bool bResult
= pDocument
->m_pDocumentClass
->addCertificate(
2710 pDocument
, aCertificate
.data(), int(aCertificate
.size()));
2711 CPPUNIT_ASSERT(bResult
);
2714 nState
= pDocument
->m_pDocumentClass
->getSignatureState(pDocument
);
2715 CPPUNIT_ASSERT_EQUAL(int(1), nState
);
2718 void DesktopLOKTest::testGetSignatureState_NonSigned()
2720 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
2721 Scheduler::ProcessEventsToIdle();
2722 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
2723 int nState
= pDocument
->m_pDocumentClass
->getSignatureState(pDocument
);
2724 CPPUNIT_ASSERT_EQUAL(int(0), nState
);
2727 #if 0 // broken with system nss on RHEL 7
2728 void DesktopLOKTest::testInsertCertificate_DER_ODT()
2730 // Load the document, save it into a temp file and load that file again
2731 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
2732 CPPUNIT_ASSERT(pDocument
->pClass
->saveAs(pDocument
, maTempFile
.GetURL().toUtf8().getStr(), "odt", nullptr));
2735 pDocument
= loadDocUrl(maTempFile
.GetURL(), LOK_DOCTYPE_TEXT
);
2737 Scheduler::ProcessEventsToIdle();
2738 CPPUNIT_ASSERT(mxComponent
.is());
2739 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
2740 Scheduler::ProcessEventsToIdle();
2742 std::vector
<unsigned char> aCertificate
;
2743 std::vector
<unsigned char> aPrivateKey
;
2746 readFileIntoByteVector(u
"rootCA.der", aCertificate
);
2748 bool bResult
= pDocument
->m_pDocumentClass
->addCertificate(
2749 pDocument
, aCertificate
.data(), int(aCertificate
.size()));
2750 CPPUNIT_ASSERT(bResult
);
2754 readFileIntoByteVector(u
"intermediateRootCA.der", aCertificate
);
2756 bool bResult
= pDocument
->m_pDocumentClass
->addCertificate(
2757 pDocument
, aCertificate
.data(), int(aCertificate
.size()));
2758 CPPUNIT_ASSERT(bResult
);
2762 readFileIntoByteVector(u
"certificate.der", aCertificate
);
2763 readFileIntoByteVector(u
"certificatePrivateKey.der", aPrivateKey
);
2765 bool bResult
= pDocument
->m_pDocumentClass
->insertCertificate(pDocument
,
2766 aCertificate
.data(), int(aCertificate
.size()),
2767 aPrivateKey
.data(), int(aPrivateKey
.size()));
2768 CPPUNIT_ASSERT(bResult
);
2771 int nState
= pDocument
->m_pDocumentClass
->getSignatureState(pDocument
);
2772 CPPUNIT_ASSERT_EQUAL(int(1), nState
);
2776 void DesktopLOKTest::testInsertCertificate_PEM_ODT()
2778 // Load the document, save it into a temp file and load that file again
2779 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
2780 CPPUNIT_ASSERT(pDocument
->pClass
->saveAs(pDocument
, maTempFile
.GetURL().toUtf8().getStr(), "odt", nullptr));
2783 pDocument
= loadDocUrl(maTempFile
.GetURL(), LOK_DOCTYPE_TEXT
);
2785 Scheduler::ProcessEventsToIdle();
2786 CPPUNIT_ASSERT(mxComponent
.is());
2787 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
2788 Scheduler::ProcessEventsToIdle();
2790 std::vector
<unsigned char> aCertificate
;
2791 std::vector
<unsigned char> aPrivateKey
;
2794 readFileIntoByteVector(u
"test-cert-chain-1.pem", aCertificate
);
2796 bool bResult
= pDocument
->m_pDocumentClass
->addCertificate(
2797 pDocument
, aCertificate
.data(), int(aCertificate
.size()));
2798 CPPUNIT_ASSERT(bResult
);
2802 readFileIntoByteVector(u
"test-cert-chain-2.pem", aCertificate
);
2804 bool bResult
= pDocument
->m_pDocumentClass
->addCertificate(
2805 pDocument
, aCertificate
.data(), int(aCertificate
.size()));
2806 CPPUNIT_ASSERT(bResult
);
2810 readFileIntoByteVector(u
"test-cert-chain-3.pem", aCertificate
);
2812 bool bResult
= pDocument
->m_pDocumentClass
->addCertificate(
2813 pDocument
, aCertificate
.data(), int(aCertificate
.size()));
2814 CPPUNIT_ASSERT(bResult
);
2818 readFileIntoByteVector(u
"test-cert-signing.pem", aCertificate
);
2819 readFileIntoByteVector(u
"test-PK-signing.pem", aPrivateKey
);
2821 bool bResult
= pDocument
->m_pDocumentClass
->insertCertificate(pDocument
,
2822 aCertificate
.data(), int(aCertificate
.size()),
2823 aPrivateKey
.data(), int(aPrivateKey
.size()));
2824 CPPUNIT_ASSERT(bResult
);
2827 int nState
= pDocument
->m_pDocumentClass
->getSignatureState(pDocument
);
2828 CPPUNIT_ASSERT_EQUAL(int(1), nState
);
2831 void DesktopLOKTest::testInsertCertificate_PEM_DOCX()
2833 // Load the document, save it into a temp file and load that file again
2834 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.docx");
2835 CPPUNIT_ASSERT(pDocument
->pClass
->saveAs(pDocument
, maTempFile
.GetURL().toUtf8().getStr(), "docx", nullptr));
2838 pDocument
= loadDocUrl(maTempFile
.GetURL(), LOK_DOCTYPE_TEXT
);
2840 Scheduler::ProcessEventsToIdle();
2841 CPPUNIT_ASSERT(mxComponent
.is());
2842 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
2843 Scheduler::ProcessEventsToIdle();
2845 std::vector
<unsigned char> aCertificate
;
2846 std::vector
<unsigned char> aPrivateKey
;
2849 readFileIntoByteVector(u
"test-cert-chain-1.pem", aCertificate
);
2851 bool bResult
= pDocument
->m_pDocumentClass
->addCertificate(
2852 pDocument
, aCertificate
.data(), int(aCertificate
.size()));
2853 CPPUNIT_ASSERT(bResult
);
2857 readFileIntoByteVector(u
"test-cert-chain-2.pem", aCertificate
);
2859 bool bResult
= pDocument
->m_pDocumentClass
->addCertificate(
2860 pDocument
, aCertificate
.data(), int(aCertificate
.size()));
2861 CPPUNIT_ASSERT(bResult
);
2865 readFileIntoByteVector(u
"test-cert-chain-3.pem", aCertificate
);
2867 bool bResult
= pDocument
->m_pDocumentClass
->addCertificate(
2868 pDocument
, aCertificate
.data(), int(aCertificate
.size()));
2869 CPPUNIT_ASSERT(bResult
);
2873 readFileIntoByteVector(u
"test-cert-signing.pem", aCertificate
);
2874 readFileIntoByteVector(u
"test-PK-signing.pem", aPrivateKey
);
2876 bool bResult
= pDocument
->m_pDocumentClass
->insertCertificate(pDocument
,
2877 aCertificate
.data(), int(aCertificate
.size()),
2878 aPrivateKey
.data(), int(aPrivateKey
.size()));
2879 CPPUNIT_ASSERT(bResult
);
2882 int nState
= pDocument
->m_pDocumentClass
->getSignatureState(pDocument
);
2883 CPPUNIT_ASSERT_EQUAL(int(5), nState
);
2887 void DesktopLOKTest::testSignDocument_PEM_PDF()
2889 // Load the document, save it into a temp file and load that file again
2890 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
2892 Scheduler::ProcessEventsToIdle();
2893 CPPUNIT_ASSERT(mxComponent
.is());
2894 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
2895 Scheduler::ProcessEventsToIdle();
2897 std::vector
<unsigned char> aCertificate
;
2898 std::vector
<unsigned char> aPrivateKey
;
2901 readFileIntoByteVector(u
"test-cert-chain-1.pem", aCertificate
);
2903 bool bResult
= pDocument
->m_pDocumentClass
->addCertificate(
2904 pDocument
, aCertificate
.data(), int(aCertificate
.size()));
2905 CPPUNIT_ASSERT(bResult
);
2909 readFileIntoByteVector(u
"test-cert-chain-2.pem", aCertificate
);
2911 bool bResult
= pDocument
->m_pDocumentClass
->addCertificate(
2912 pDocument
, aCertificate
.data(), int(aCertificate
.size()));
2913 CPPUNIT_ASSERT(bResult
);
2917 readFileIntoByteVector(u
"test-cert-chain-3.pem", aCertificate
);
2919 bool bResult
= pDocument
->m_pDocumentClass
->addCertificate(
2920 pDocument
, aCertificate
.data(), int(aCertificate
.size()));
2921 CPPUNIT_ASSERT(bResult
);
2924 CPPUNIT_ASSERT(pDocument
->pClass
->saveAs(pDocument
, maTempFile
.GetURL().toUtf8().getStr(), "pdf", nullptr));
2928 Scheduler::ProcessEventsToIdle();
2930 readFileIntoByteVector(u
"test-cert-signing.pem", aCertificate
);
2931 readFileIntoByteVector(u
"test-PK-signing.pem", aPrivateKey
);
2933 LibLibreOffice_Impl aOffice
;
2934 bool bResult
= aOffice
.m_pOfficeClass
->signDocument(&aOffice
, maTempFile
.GetURL().toUtf8().getStr(),
2935 aCertificate
.data(), int(aCertificate
.size()),
2936 aPrivateKey
.data(), int(aPrivateKey
.size()));
2938 CPPUNIT_ASSERT(bResult
);
2941 void DesktopLOKTest::testTextSelectionHandles()
2943 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
2944 pDocument
->pClass
->registerCallback(pDocument
, &DesktopLOKTest::callback
, this);
2946 OString
aText("hello");
2947 CPPUNIT_ASSERT(pDocument
->pClass
->paste(pDocument
, "text/plain;charset=utf-8", aText
.getStr(), aText
.getLength()));
2949 // select the inserted text
2950 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:SelectAll", nullptr, false);
2951 Scheduler::ProcessEventsToIdle();
2952 char* pText
= pDocument
->pClass
->getTextSelection(pDocument
, "text/plain;charset=utf-8", nullptr);
2953 CPPUNIT_ASSERT_EQUAL(aText
, OString(pText
));
2955 CPPUNIT_ASSERT_EQUAL(OString("1418, 1418, 0, 275"), m_aTextSelectionStart
);
2956 CPPUNIT_ASSERT_EQUAL(OString("1898, 1418, 0, 275"), m_aTextSelectionEnd
);
2959 m_aTextSelectionStart
= "";
2960 m_aTextSelectionEnd
= "";
2961 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 0, com::sun::star::awt::Key::ESCAPE
);
2962 Scheduler::ProcessEventsToIdle();
2963 pText
= pDocument
->pClass
->getTextSelection(pDocument
, "text/plain;charset=utf-8", nullptr);
2964 CPPUNIT_ASSERT_EQUAL(static_cast<char *>(nullptr), pText
);
2966 CPPUNIT_ASSERT_EQUAL(OString(), m_aTextSelectionStart
);
2967 CPPUNIT_ASSERT_EQUAL(OString(), m_aTextSelectionEnd
);
2969 // select again; the positions of the selection handles have to be sent
2971 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:SelectAll", nullptr, false);
2972 Scheduler::ProcessEventsToIdle();
2973 pText
= pDocument
->pClass
->getTextSelection(pDocument
, "text/plain;charset=utf-8", nullptr);
2974 CPPUNIT_ASSERT_EQUAL(aText
, OString(pText
));
2976 CPPUNIT_ASSERT_EQUAL(OString("1418, 1418, 0, 275"), m_aTextSelectionStart
);
2977 CPPUNIT_ASSERT_EQUAL(OString("1898, 1418, 0, 275"), m_aTextSelectionEnd
);
2980 void DesktopLOKTest::testDialogPaste()
2982 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
2983 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:HyperlinkDialog", nullptr, false);
2984 Scheduler::ProcessEventsToIdle();
2986 SfxViewShell
* pViewShell
= SfxViewShell::Current();
2987 pViewShell
->GetViewFrame().GetBindings().Update();
2989 VclPtr
<vcl::Window
> pWindow(Application::GetActiveTopWindow());
2990 CPPUNIT_ASSERT(pWindow
);
2992 pDocument
->pClass
->postWindow(pDocument
, pWindow
->GetLOKWindowId(), LOK_WINDOW_PASTE
,
2993 "{ \"MimeType\" : { \"type\" : \"string\", \"value\" : \"text/plain;charset=utf-8\" }, \"Data\" : { \"type\" : \"[]byte\", \"value\" : \"www.softwarelibre.org.bo\" } }");
2994 Scheduler::ProcessEventsToIdle();
2996 Control
* pCtrlFocused
= GetFocusControl(pWindow
.get());
2997 CPPUNIT_ASSERT(pCtrlFocused
);
2998 CPPUNIT_ASSERT_EQUAL(WindowType::COMBOBOX
, pCtrlFocused
->GetType());
2999 CPPUNIT_ASSERT_EQUAL(OUString("www.softwarelibre.org.bo"), pCtrlFocused
->GetText());
3001 static_cast<SystemWindow
*>(pWindow
.get())->Close();
3002 Scheduler::ProcessEventsToIdle();
3005 void DesktopLOKTest::testShowHideDialog()
3008 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
3010 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
3011 ViewCallback
aView(pDocument
);
3013 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:HyperlinkDialog", nullptr, false);
3014 Scheduler::ProcessEventsToIdle();
3016 VclPtr
<vcl::Window
> pWindow(Application::GetActiveTopWindow());
3017 CPPUNIT_ASSERT(pWindow
);
3019 aView
.m_bWindowHidden
= false;
3022 Scheduler::ProcessEventsToIdle();
3024 CPPUNIT_ASSERT_EQUAL(true, aView
.m_bWindowHidden
);
3026 static_cast<SystemWindow
*>(pWindow
.get())->Close();
3027 Scheduler::ProcessEventsToIdle();
3030 void DesktopLOKTest::testComplexSelection()
3032 // Start with a blank text file and add contents.
3033 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
3034 static constexpr OStringLiteral
aText("hello world");
3036 // Certainly not complex.
3037 CPPUNIT_ASSERT_EQUAL(static_cast<int>(LOK_SELTYPE_NONE
), pDocument
->pClass
->getSelectionType(pDocument
));
3038 CPPUNIT_ASSERT_EQUAL(static_cast<int>(LOK_SELTYPE_NONE
), pDocument
->pClass
->getSelectionTypeAndText(pDocument
,
3039 "", nullptr, nullptr));
3042 CPPUNIT_ASSERT(pDocument
->pClass
->paste(pDocument
, "text/plain;charset=utf-8", aText
.getStr(), aText
.getLength()));
3045 CPPUNIT_ASSERT_EQUAL(static_cast<int>(LOK_SELTYPE_NONE
), pDocument
->pClass
->getSelectionType(pDocument
));
3046 CPPUNIT_ASSERT_EQUAL(static_cast<int>(LOK_SELTYPE_NONE
), pDocument
->pClass
->getSelectionTypeAndText(pDocument
,
3047 "", nullptr, nullptr));
3050 OUString aFileURL
= createFileURL(u
"paste.jpg");
3051 std::ifstream
aImageStream(aFileURL
.toUtf8().copy(strlen("file://")).getStr());
3052 std::vector
<char> aImageContents((std::istreambuf_iterator
<char>(aImageStream
)), std::istreambuf_iterator
<char>());
3053 CPPUNIT_ASSERT(pDocument
->pClass
->paste(pDocument
, "image/jpeg", aImageContents
.data(), aImageContents
.size()));
3056 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:SelectAll", nullptr, false);
3057 Scheduler::ProcessEventsToIdle();
3059 // Export as plain text, we should get only the text part "hello".
3060 char* pText
= pDocument
->pClass
->getTextSelection(pDocument
, "text/plain;charset=utf-8", nullptr);
3061 CPPUNIT_ASSERT(pText
!= nullptr);
3062 CPPUNIT_ASSERT_EQUAL(OString(aText
), OString(pText
));
3065 // Export as rtf, we should also get the image.
3066 pText
= pDocument
->pClass
->getTextSelection(pDocument
, "text/rtf", nullptr);
3067 CPPUNIT_ASSERT(pText
!= nullptr);
3068 CPPUNIT_ASSERT(std::string(pText
).find(aText
.getStr()) != std::string::npos
); // Must have the text.
3069 CPPUNIT_ASSERT(std::string(pText
).find("pict{") != std::string::npos
); // Must have the image as well.
3072 // Export as html, we should also get the image.
3073 pText
= pDocument
->pClass
->getTextSelection(pDocument
, "text/html", nullptr);
3074 CPPUNIT_ASSERT(pText
!= nullptr);
3075 CPPUNIT_ASSERT(std::string(pText
).find(aText
.getStr()) != std::string::npos
); // Must have the text.
3076 CPPUNIT_ASSERT(std::string(pText
).find("<img") != std::string::npos
); // Must have the image as well.
3079 // We expect this to be complex.
3080 CPPUNIT_ASSERT_EQUAL(static_cast<int>(LOK_SELTYPE_COMPLEX
), pDocument
->pClass
->getSelectionType(pDocument
));
3081 CPPUNIT_ASSERT_EQUAL(static_cast<int>(LOK_SELTYPE_COMPLEX
), pDocument
->pClass
->getSelectionTypeAndText(pDocument
,
3082 "", nullptr, nullptr));
3085 void DesktopLOKTest::testCalcSaveAs()
3087 LibLODocument_Impl
* pDocument
= loadDoc("sheets.ods");
3088 CPPUNIT_ASSERT(pDocument
);
3090 // Enter some text, but don't commit.
3091 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 'X', 0);
3092 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYUP
, 'X', 0);
3093 Scheduler::ProcessEventsToIdle();
3095 // Save as a new file.
3096 pDocument
->pClass
->saveAs(pDocument
, maTempFile
.GetURL().toUtf8().getStr(), "ods", nullptr);
3099 // Load the new document and verify that the in-flight changes are saved.
3100 pDocument
= loadDocUrl(maTempFile
.GetURL(), LOK_DOCTYPE_SPREADSHEET
);
3101 CPPUNIT_ASSERT(pDocument
);
3103 ViewCallback
aView(pDocument
);
3104 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
3105 pDocument
->m_pDocumentClass
->registerCallback(pDocument
, &ViewCallback::callback
, &aView
);
3107 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 0, KEY_RIGHT
);
3108 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYUP
, 0, KEY_RIGHT
);
3109 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 0, KEY_LEFT
);
3110 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYUP
, 0, KEY_LEFT
);
3111 Scheduler::ProcessEventsToIdle();
3113 CPPUNIT_ASSERT_EQUAL(OString("X"), aView
.m_aCellFormula
);
3116 void DesktopLOKTest::testSpellcheckerMultiView()
3118 static constexpr OUStringLiteral
aLangISO(u
"en-US");
3119 SvtSysLocaleOptions aSysLocaleOptions
;
3120 aSysLocaleOptions
.SetLocaleConfigString(aLangISO
);
3121 aSysLocaleOptions
.SetUILocaleConfigString(aLangISO
);
3122 comphelper::LibreOfficeKit::setLanguageTag(LanguageTag(aLangISO
, true));
3124 auto aSavedSettings
= Application::GetSettings();
3125 std::unique_ptr
<Resetter
> pResetter(
3126 new Resetter([&]() { Application::SetSettings(aSavedSettings
); }));
3127 AllSettings
aSettings(aSavedSettings
);
3128 aSettings
.SetLanguageTag(aLangISO
, true);
3129 Application::SetSettings(aSettings
);
3131 LibLODocument_Impl
* pDocument
= loadDoc("sheet_with_image.ods", LOK_DOCTYPE_SPREADSHEET
);
3132 pDocument
->pClass
->setViewLanguage(pDocument
, 0, "en-US"); // For spellchecking.
3133 pDocument
->pClass
->initializeForRendering(pDocument
, nullptr);
3134 pDocument
->pClass
->registerCallback(pDocument
, &DesktopLOKTest::callback
, this);
3136 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 'a', 0);
3137 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 'a', 0);
3138 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 'a', 0);
3139 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 0, com::sun::star::awt::Key::ESCAPE
);
3141 // Start spellchecking.
3142 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:SpellDialog", nullptr, false);
3144 // Uncommenting this will result in a deadlock.
3145 // Because the language configuration above is not effective, and no
3146 // language is actually set, the spell-dialog finds no misspelled
3147 // words, and displays a message box, which must be dismissed to
3149 // Need to fix the language configuration issue to enable this.
3150 // Scheduler::ProcessEventsToIdle();
3152 CPPUNIT_ASSERT_EQUAL(1, pDocument
->m_pDocumentClass
->getViewsCount(pDocument
));
3154 // Now create another view.
3155 const int nViewId
= pDocument
->m_pDocumentClass
->createView(pDocument
);
3156 CPPUNIT_ASSERT_EQUAL(2, pDocument
->m_pDocumentClass
->getViewsCount(pDocument
));
3159 pDocument
->m_pDocumentClass
->destroyView(pDocument
, nViewId
);
3161 // We should survive the destroyed view.
3162 CPPUNIT_ASSERT_EQUAL(1, pDocument
->m_pDocumentClass
->getViewsCount(pDocument
));
3165 void DesktopLOKTest::testMultiDocuments()
3167 for (int i
= 0; i
< 3; i
++)
3170 std::unique_ptr
<LibLODocument_Impl
> document1
= loadDocImpl("blank_text.odt");
3171 LibLODocument_Impl
* pDocument1
= document1
.get();
3172 CPPUNIT_ASSERT_EQUAL(1, pDocument1
->m_pDocumentClass
->getViewsCount(pDocument1
));
3173 const int nDocId1
= pDocument1
->mnDocumentId
;
3175 const int nDoc1View0
= pDocument1
->m_pDocumentClass
->getView(pDocument1
);
3176 CPPUNIT_ASSERT_EQUAL(nDocId1
, SfxLokHelper::getDocumentIdOfView(nDoc1View0
));
3177 const int nDoc1View1
= pDocument1
->m_pDocumentClass
->createView(pDocument1
);
3178 CPPUNIT_ASSERT_EQUAL(nDoc1View1
, pDocument1
->m_pDocumentClass
->getView(pDocument1
));
3179 CPPUNIT_ASSERT_EQUAL(nDocId1
, SfxLokHelper::getDocumentIdOfView(nDoc1View1
));
3180 CPPUNIT_ASSERT_EQUAL(2, pDocument1
->m_pDocumentClass
->getViewsCount(pDocument1
));
3182 // Validate the views of document 1.
3183 std::vector
<int> aViewIdsDoc1(2);
3184 CPPUNIT_ASSERT(pDocument1
->m_pDocumentClass
->getViewIds(pDocument1
, aViewIdsDoc1
.data(), aViewIdsDoc1
.size()));
3185 CPPUNIT_ASSERT_EQUAL(nDoc1View0
, aViewIdsDoc1
[0]);
3186 CPPUNIT_ASSERT_EQUAL(nDoc1View1
, aViewIdsDoc1
[1]);
3188 CPPUNIT_ASSERT_EQUAL(nDoc1View1
, pDocument1
->m_pDocumentClass
->getView(pDocument1
));
3189 CPPUNIT_ASSERT_EQUAL(nDocId1
, SfxLokHelper::getDocumentIdOfView(nDoc1View1
));
3190 pDocument1
->m_pDocumentClass
->setView(pDocument1
, nDoc1View0
);
3191 CPPUNIT_ASSERT_EQUAL(nDoc1View0
, pDocument1
->m_pDocumentClass
->getView(pDocument1
));
3192 CPPUNIT_ASSERT_EQUAL(nDocId1
, SfxLokHelper::getDocumentIdOfView(nDoc1View0
));
3193 pDocument1
->m_pDocumentClass
->setView(pDocument1
, nDoc1View1
);
3194 CPPUNIT_ASSERT_EQUAL(nDoc1View1
, pDocument1
->m_pDocumentClass
->getView(pDocument1
));
3195 CPPUNIT_ASSERT_EQUAL(nDocId1
, SfxLokHelper::getDocumentIdOfView(nDoc1View1
));
3196 CPPUNIT_ASSERT_EQUAL(2, pDocument1
->m_pDocumentClass
->getViewsCount(pDocument1
));
3198 // Load another document.
3199 std::unique_ptr
<LibLODocument_Impl
> document2
= loadDocImpl("blank_presentation.odp");
3200 LibLODocument_Impl
* pDocument2
= document2
.get();
3201 CPPUNIT_ASSERT_EQUAL(1, pDocument2
->m_pDocumentClass
->getViewsCount(pDocument2
));
3202 const int nDocId2
= pDocument2
->mnDocumentId
;
3204 const int nDoc2View0
= pDocument2
->m_pDocumentClass
->getView(pDocument2
);
3205 CPPUNIT_ASSERT_EQUAL(nDocId2
, SfxLokHelper::getDocumentIdOfView(nDoc2View0
));
3206 const int nDoc2View1
= pDocument2
->m_pDocumentClass
->createView(pDocument2
);
3207 CPPUNIT_ASSERT_EQUAL(nDoc2View1
, pDocument2
->m_pDocumentClass
->getView(pDocument2
));
3208 CPPUNIT_ASSERT_EQUAL(nDocId2
, SfxLokHelper::getDocumentIdOfView(nDoc2View1
));
3209 CPPUNIT_ASSERT_EQUAL(2, pDocument2
->m_pDocumentClass
->getViewsCount(pDocument2
));
3211 // Validate the views of document 2.
3212 std::vector
<int> aViewIdsDoc2(2);
3213 CPPUNIT_ASSERT(pDocument2
->m_pDocumentClass
->getViewIds(pDocument2
, aViewIdsDoc2
.data(), aViewIdsDoc2
.size()));
3214 CPPUNIT_ASSERT_EQUAL(nDoc2View0
, aViewIdsDoc2
[0]);
3215 CPPUNIT_ASSERT_EQUAL(nDoc2View1
, aViewIdsDoc2
[1]);
3217 CPPUNIT_ASSERT_EQUAL(nDoc2View1
, pDocument2
->m_pDocumentClass
->getView(pDocument2
));
3218 CPPUNIT_ASSERT_EQUAL(nDocId2
, SfxLokHelper::getDocumentIdOfView(nDoc2View1
));
3219 pDocument2
->m_pDocumentClass
->setView(pDocument2
, nDoc2View0
);
3220 CPPUNIT_ASSERT_EQUAL(nDoc2View0
, pDocument2
->m_pDocumentClass
->getView(pDocument2
));
3221 CPPUNIT_ASSERT_EQUAL(nDocId2
, SfxLokHelper::getDocumentIdOfView(nDoc2View0
));
3222 pDocument2
->m_pDocumentClass
->setView(pDocument2
, nDoc2View1
);
3223 CPPUNIT_ASSERT_EQUAL(nDoc2View1
, pDocument2
->m_pDocumentClass
->getView(pDocument2
));
3224 CPPUNIT_ASSERT_EQUAL(nDocId2
, SfxLokHelper::getDocumentIdOfView(nDoc2View1
));
3225 CPPUNIT_ASSERT_EQUAL(2, pDocument2
->m_pDocumentClass
->getViewsCount(pDocument2
));
3227 // The views of document1 should be unchanged.
3228 CPPUNIT_ASSERT(pDocument1
->m_pDocumentClass
->getViewIds(pDocument1
, aViewIdsDoc1
.data(), aViewIdsDoc1
.size()));
3229 CPPUNIT_ASSERT_EQUAL(nDoc1View0
, aViewIdsDoc1
[0]);
3230 CPPUNIT_ASSERT_EQUAL(nDoc1View1
, aViewIdsDoc1
[1]);
3231 // Switch views in the first doc.
3232 CPPUNIT_ASSERT_EQUAL(nDocId1
, SfxLokHelper::getDocumentIdOfView(nDoc1View0
));
3233 pDocument1
->m_pDocumentClass
->setView(pDocument1
, nDoc1View0
);
3234 CPPUNIT_ASSERT_EQUAL(nDoc1View0
, pDocument1
->m_pDocumentClass
->getView(pDocument1
));
3235 CPPUNIT_ASSERT_EQUAL(nDocId1
, SfxLokHelper::getDocumentIdOfView(nDoc1View1
));
3236 pDocument1
->m_pDocumentClass
->destroyView(pDocument1
, nDoc1View1
);
3237 CPPUNIT_ASSERT_EQUAL(1, pDocument1
->m_pDocumentClass
->getViewsCount(pDocument1
));
3239 // The views of document2 should be unchanged.
3240 CPPUNIT_ASSERT(pDocument2
->m_pDocumentClass
->getViewIds(pDocument2
, aViewIdsDoc2
.data(), aViewIdsDoc2
.size()));
3241 CPPUNIT_ASSERT_EQUAL(nDoc2View0
, aViewIdsDoc2
[0]);
3242 CPPUNIT_ASSERT_EQUAL(nDoc2View1
, aViewIdsDoc2
[1]);
3243 // Switch views in the second doc.
3244 CPPUNIT_ASSERT_EQUAL(nDocId2
, SfxLokHelper::getDocumentIdOfView(nDoc2View0
));
3245 pDocument2
->m_pDocumentClass
->setView(pDocument2
, nDoc2View0
);
3246 CPPUNIT_ASSERT_EQUAL(nDoc2View0
, pDocument2
->m_pDocumentClass
->getView(pDocument2
));
3247 CPPUNIT_ASSERT_EQUAL(nDocId2
, SfxLokHelper::getDocumentIdOfView(nDoc2View1
));
3248 pDocument2
->m_pDocumentClass
->destroyView(pDocument2
, nDoc2View1
);
3249 CPPUNIT_ASSERT_EQUAL(1, pDocument2
->m_pDocumentClass
->getViewsCount(pDocument2
));
3251 closeDoc(document2
);
3253 closeDoc(document1
);
3259 SfxChildWindow
* lcl_initializeSidebar()
3261 // in init.cxx we do setupSidebar which creates the controller, do it here
3263 SfxViewShell
* pViewShell
= SfxViewShell::Current();
3264 CPPUNIT_ASSERT(pViewShell
);
3266 SfxViewFrame
& rViewFrame
= pViewShell
->GetViewFrame();
3267 SfxChildWindow
* pSideBar
= rViewFrame
.GetChildWindow(SID_SIDEBAR
);
3268 CPPUNIT_ASSERT(pSideBar
);
3270 auto pDockingWin
= dynamic_cast<sfx2::sidebar::SidebarDockingWindow
*>(pSideBar
->GetWindow());
3271 CPPUNIT_ASSERT(pDockingWin
);
3273 pDockingWin
->GetOrCreateSidebarController(); // just to create the controller
3279 void DesktopLOKTest::testControlState()
3281 LibLODocument_Impl
* pDocument
= loadDoc("search.ods");
3282 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:StarShapes", nullptr, false);
3283 lcl_initializeSidebar();
3284 Scheduler::ProcessEventsToIdle();
3286 boost::property_tree::ptree aState
;
3287 SfxViewShell
* pViewShell
= SfxViewShell::Current();
3288 pViewShell
->GetViewFrame().GetBindings().Update();
3289 pViewShell
->GetViewFrame().GetBindings().QueryControlState(SID_ATTR_TRANSFORM_WIDTH
, aState
);
3290 CPPUNIT_ASSERT(!aState
.empty());
3293 void DesktopLOKTest::testMetricField()
3295 LibLODocument_Impl
* pDocument
= loadDoc("search.ods");
3296 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:StarShapes", nullptr, false);
3297 SfxChildWindow
* pSideBar
= lcl_initializeSidebar();
3298 Scheduler::ProcessEventsToIdle();
3300 vcl::Window
* pWin
= pSideBar
->GetWindow();
3301 CPPUNIT_ASSERT(pWin
);
3303 WindowUIObject
aWinUI(pWin
);
3304 std::unique_ptr
<UIObject
> pUIWin(aWinUI
.get_child("selectwidth"));
3305 CPPUNIT_ASSERT(pUIWin
);
3308 aMap
["VALUE"] = "75.06";
3309 pUIWin
->execute("VALUE", aMap
);
3311 StringMap aRet
= pUIWin
->get_state();
3312 CPPUNIT_ASSERT_EQUAL(aMap
["VALUE"], aRet
["Value"]);
3315 void DesktopLOKTest::testJumpCursor()
3317 comphelper::LibreOfficeKit::setTiledAnnotations(false);
3319 LibLODocument_Impl
* pDocument
= loadDoc("blank_text.odt");
3320 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
3322 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 'B', 0);
3323 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 'o', 0);
3324 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 'l', 0);
3325 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 'i', 0);
3326 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 'v', 0);
3327 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 'i', 0);
3328 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 'a', 0);
3329 pDocument
->pClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, 0, com::sun::star::awt::Key::ESCAPE
);
3330 Scheduler::ProcessEventsToIdle();
3332 // There is a cursor jump to (0, 0) due to
3333 // mpOutlinerView->SetOutputArea( PixelToLogic( tools::Rectangle(0,0,1,1) ) );
3334 // when creating a comment
3335 ViewCallback
aView1(pDocument
);
3337 pDocument
->pClass
->postUnoCommand(pDocument
, ".uno:InsertAnnotation", nullptr, true);
3338 Scheduler::ProcessEventsToIdle();
3340 CPPUNIT_ASSERT(!aView1
.m_bZeroCursor
);
3342 comphelper::LibreOfficeKit::setTiledAnnotations(true);
3345 void DesktopLOKTest::testRenderSearchResult_WriterNode()
3347 constexpr const bool bDumpBitmap
= false;
3349 LibLODocument_Impl
* pDocument
= loadDoc("SearchIndexResultTest.odt");
3350 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
3352 Scheduler::ProcessEventsToIdle();
3354 unsigned char* pBuffer
= nullptr;
3357 "<paragraph node_type=\"writer\" index=\"19\">ABC</paragraph>"
3362 size_t nByteSize
= 0;
3364 bool bResult
= pDocument
->m_pDocumentClass
->renderSearchResult(pDocument
, aPayload
.getStr(), &pBuffer
, &nWidth
, &nHeight
, &nByteSize
);
3366 CPPUNIT_ASSERT(bResult
);
3367 CPPUNIT_ASSERT(pBuffer
);
3369 Scheduler::ProcessEventsToIdle();
3371 CPPUNIT_ASSERT_EQUAL(642, nWidth
);
3372 CPPUNIT_ASSERT_EQUAL(561, nHeight
);
3373 CPPUNIT_ASSERT_EQUAL(size_t(1440648), nByteSize
);
3375 const sal_uInt8
* pD
= reinterpret_cast<const sal_uInt8
*>(pBuffer
);
3376 BitmapEx aBitmap
= vcl::bitmap::CreateFromData(pD
, nWidth
, nHeight
, nWidth
* 4, /*nBitsPerPixel*/32, true, true);
3380 SvFileStream
aStream("~/SearchResultBitmap.png", StreamMode::WRITE
| StreamMode::TRUNC
);
3381 vcl::PngImageWriter
aPNGWriter(aStream
);
3382 aPNGWriter
.write(aBitmap
);
3384 CPPUNIT_ASSERT_EQUAL(tools::Long(642), aBitmap
.GetSizePixel().Width());
3385 CPPUNIT_ASSERT_EQUAL(tools::Long(561), aBitmap
.GetSizePixel().Height());
3390 void DesktopLOKTest::testRenderSearchResult_CommonNode()
3392 constexpr const bool bDumpBitmap
= false;
3394 LibLODocument_Impl
* pDocument
= loadDoc("SearchIndexResultShapeTest.odt");
3395 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
3397 Scheduler::ProcessEventsToIdle();
3399 unsigned char* pBuffer
= nullptr;
3402 "<paragraph node_type=\"common\" index=\"0\" object_name=\"Shape 1\" />"
3407 size_t nByteSize
= 0;
3409 bool bResult
= pDocument
->m_pDocumentClass
->renderSearchResult(pDocument
, aPayload
.getStr(), &pBuffer
, &nWidth
, &nHeight
, &nByteSize
);
3411 CPPUNIT_ASSERT(bResult
);
3412 CPPUNIT_ASSERT(pBuffer
);
3414 Scheduler::ProcessEventsToIdle();
3416 CPPUNIT_ASSERT_EQUAL(192, nWidth
);
3417 CPPUNIT_ASSERT_EQUAL(96, nHeight
);
3418 CPPUNIT_ASSERT_EQUAL(size_t(73728), nByteSize
);
3420 const sal_uInt8
* pD
= reinterpret_cast<const sal_uInt8
*>(pBuffer
);
3421 BitmapEx aBitmap
= vcl::bitmap::CreateFromData(pD
, nWidth
, nHeight
, nWidth
* 4, /*nBitsPerPixel*/32, true, true);
3425 SvFileStream
aStream("~/SearchResultBitmap.png", StreamMode::WRITE
| StreamMode::TRUNC
);
3426 vcl::PngImageWriter
aPNGWriter(aStream
);
3427 aPNGWriter
.write(aBitmap
);
3429 CPPUNIT_ASSERT_EQUAL(tools::Long(192), aBitmap
.GetSizePixel().Width());
3430 CPPUNIT_ASSERT_EQUAL(tools::Long(96), aBitmap
.GetSizePixel().Height());
3435 static void lcl_repeatKeyStroke(LibLODocument_Impl
*pDocument
, int nCharCode
, int nKeyCode
, size_t nCount
)
3437 for (size_t nCtr
= 0; nCtr
< nCount
; ++nCtr
)
3439 pDocument
->m_pDocumentClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYINPUT
, nCharCode
, nKeyCode
);
3440 pDocument
->m_pDocumentClass
->postKeyEvent(pDocument
, LOK_KEYEVENT_KEYUP
, nCharCode
, nKeyCode
);
3444 void DesktopLOKTest::testNoDuplicateTableSelection()
3446 LibLODocument_Impl
* pDocument
= loadDoc("table-selection.odt");
3449 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
3450 ViewCallback
aView1(pDocument
);
3452 lcl_repeatKeyStroke(pDocument
, 0, KEY_DOWN
, 1);
3453 Scheduler::ProcessEventsToIdle();
3454 CPPUNIT_ASSERT_EQUAL(1, aView1
.m_nTableSelectionCount
);
3455 CPPUNIT_ASSERT(aView1
.m_bEmptyTableSelection
);
3457 aView1
.m_nTableSelectionCount
= 0;
3459 lcl_repeatKeyStroke(pDocument
, 0, KEY_DOWN
, 1);
3460 Scheduler::ProcessEventsToIdle();
3461 CPPUNIT_ASSERT_EQUAL(1, aView1
.m_nTableSelectionCount
);
3462 CPPUNIT_ASSERT(!aView1
.m_bEmptyTableSelection
);
3464 aView1
.m_nTableSelectionCount
= 0;
3465 // Move to the last row in Table1.
3466 lcl_repeatKeyStroke(pDocument
, 0, KEY_DOWN
, 2);
3467 Scheduler::ProcessEventsToIdle();
3468 CPPUNIT_ASSERT_EQUAL(0, aView1
.m_nTableSelectionCount
);
3470 // Go outside Table1.
3471 lcl_repeatKeyStroke(pDocument
, 0, KEY_DOWN
, 1);
3472 Scheduler::ProcessEventsToIdle();
3473 CPPUNIT_ASSERT_EQUAL(1, aView1
.m_nTableSelectionCount
);
3474 CPPUNIT_ASSERT(aView1
.m_bEmptyTableSelection
);
3477 void DesktopLOKTest::testMultiViewTableSelection()
3479 LibLODocument_Impl
* pDocument
= loadDoc("table-selection.odt");
3482 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
3483 ViewCallback
aView1(pDocument
);
3484 int nView1
= pDocument
->m_pDocumentClass
->getView(pDocument
);
3487 pDocument
->m_pDocumentClass
->createView(pDocument
);
3488 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
3489 ViewCallback
aView2(pDocument
);
3490 int nView2
= pDocument
->m_pDocumentClass
->getView(pDocument
);
3492 // switch to view 1.
3493 pDocument
->m_pDocumentClass
->setView(pDocument
, nView1
);
3494 lcl_repeatKeyStroke(pDocument
, 0, KEY_DOWN
, 1);
3495 Scheduler::ProcessEventsToIdle();
3496 CPPUNIT_ASSERT_EQUAL(1, aView1
.m_nTableSelectionCount
);
3497 CPPUNIT_ASSERT_EQUAL(1, aView2
.m_nTableSelectionCount
);
3498 CPPUNIT_ASSERT(aView1
.m_bEmptyTableSelection
);
3499 CPPUNIT_ASSERT(aView2
.m_bEmptyTableSelection
);
3501 aView1
.m_nTableSelectionCount
= 0;
3502 aView2
.m_nTableSelectionCount
= 0;
3504 pDocument
->m_pDocumentClass
->setView(pDocument
, nView1
);
3506 lcl_repeatKeyStroke(pDocument
, 0, KEY_DOWN
, 1);
3507 Scheduler::ProcessEventsToIdle();
3508 CPPUNIT_ASSERT_EQUAL(1, aView1
.m_nTableSelectionCount
);
3509 CPPUNIT_ASSERT_EQUAL(0, aView2
.m_nTableSelectionCount
);
3511 aView1
.m_nTableSelectionCount
= 0;
3513 pDocument
->m_pDocumentClass
->setView(pDocument
, nView2
);
3514 // Go to Table2 in view 2.
3515 lcl_repeatKeyStroke(pDocument
, 0, KEY_DOWN
, 7);
3516 Scheduler::ProcessEventsToIdle();
3517 // View1 should not get any table selection messages.
3518 CPPUNIT_ASSERT_EQUAL(0, aView1
.m_nTableSelectionCount
);
3519 // View2 will first get table selection of Table1, then empty selection, and finally on 7th down arrow keypress,
3520 // it will get table-selection of Table2. So in total it should get 3 table selections.
3521 CPPUNIT_ASSERT_EQUAL(3, aView2
.m_nTableSelectionCount
);
3522 CPPUNIT_ASSERT(!aView2
.m_bEmptyTableSelection
);
3524 aView1
.m_nTableSelectionCount
= 0;
3525 aView2
.m_nTableSelectionCount
= 0;
3528 pDocument
->m_pDocumentClass
->setView(pDocument
, nView1
);
3529 // Go out of Table1 and re-enter..
3530 lcl_repeatKeyStroke(pDocument
, 0, KEY_UP
, 1);
3531 lcl_repeatKeyStroke(pDocument
, 0, KEY_DOWN
, 1);
3532 Scheduler::ProcessEventsToIdle();
3533 // View1 should get one empty table selection, then get Table1 selection.
3534 CPPUNIT_ASSERT_EQUAL(2, aView1
.m_nTableSelectionCount
);
3535 // View2 should not get any table selection.
3536 CPPUNIT_ASSERT_EQUAL(0, aView2
.m_nTableSelectionCount
);
3537 CPPUNIT_ASSERT(!aView1
.m_bEmptyTableSelection
);
3540 void DesktopLOKTest::testColorPaletteCallback()
3542 LibLODocument_Impl
* pDocument
= loadDoc("ThemeDocument.docx");
3545 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
3546 ViewCallback
aView1(pDocument
);
3547 Scheduler::ProcessEventsToIdle();
3549 CPPUNIT_ASSERT_EQUAL(1, aView1
.m_nColorPaletteCallbackCount
);
3550 boost::property_tree::ptree aValues
= aView1
.m_aColorPaletteCallbackResult
.get_child("ThemeColors");
3551 CPPUNIT_ASSERT(!aValues
.empty());
3552 CPPUNIT_ASSERT_EQUAL(size_t(6), aValues
.size());
3556 pDocument
->m_pDocumentClass
->createView(pDocument
);
3557 pDocument
->m_pDocumentClass
->initializeForRendering(pDocument
, "{}");
3558 ViewCallback
aView2(pDocument
);
3559 Scheduler::ProcessEventsToIdle();
3561 CPPUNIT_ASSERT_EQUAL(1, aView2
.m_nColorPaletteCallbackCount
);
3562 boost::property_tree::ptree aValues
= aView1
.m_aColorPaletteCallbackResult
.get_child("ThemeColors");
3563 CPPUNIT_ASSERT(!aValues
.empty());
3564 CPPUNIT_ASSERT_EQUAL(size_t(6), aValues
.size());
3570 constexpr size_t classOffset(int i
)
3572 return sizeof(static_cast<struct _LibreOfficeKitClass
*>(nullptr)->nSize
) + i
* sizeof(void*);
3575 constexpr size_t documentClassOffset(int i
)
3577 return sizeof(static_cast<struct _LibreOfficeKitDocumentClass
*>(nullptr)->nSize
) + i
* sizeof(void*);
3582 void DesktopLOKTest::testABI()
3584 // STABLE ABI, NEVER CHANGE (unless there's a very good reason, agreed by ESC, etc.)
3585 CPPUNIT_ASSERT_EQUAL(classOffset(0), offsetof(struct _LibreOfficeKitClass
, destroy
));
3586 CPPUNIT_ASSERT_EQUAL(classOffset(1), offsetof(struct _LibreOfficeKitClass
, documentLoad
));
3587 CPPUNIT_ASSERT_EQUAL(classOffset(2), offsetof(struct _LibreOfficeKitClass
, getError
));
3588 CPPUNIT_ASSERT_EQUAL(classOffset(3), offsetof(struct _LibreOfficeKitClass
, documentLoadWithOptions
));
3589 CPPUNIT_ASSERT_EQUAL(classOffset(4), offsetof(struct _LibreOfficeKitClass
, freeError
));
3590 CPPUNIT_ASSERT_EQUAL(classOffset(5), offsetof(struct _LibreOfficeKitClass
, registerCallback
));
3591 CPPUNIT_ASSERT_EQUAL(classOffset(6), offsetof(struct _LibreOfficeKitClass
, getFilterTypes
));
3592 CPPUNIT_ASSERT_EQUAL(classOffset(7), offsetof(struct _LibreOfficeKitClass
, setOptionalFeatures
));
3593 CPPUNIT_ASSERT_EQUAL(classOffset(8), offsetof(struct _LibreOfficeKitClass
, setDocumentPassword
));
3594 CPPUNIT_ASSERT_EQUAL(classOffset(9), offsetof(struct _LibreOfficeKitClass
, getVersionInfo
));
3595 CPPUNIT_ASSERT_EQUAL(classOffset(10), offsetof(struct _LibreOfficeKitClass
, runMacro
));
3596 CPPUNIT_ASSERT_EQUAL(classOffset(11), offsetof(struct _LibreOfficeKitClass
, signDocument
));
3597 CPPUNIT_ASSERT_EQUAL(classOffset(12), offsetof(struct _LibreOfficeKitClass
, runLoop
));
3598 CPPUNIT_ASSERT_EQUAL(classOffset(13), offsetof(struct _LibreOfficeKitClass
, sendDialogEvent
));
3599 CPPUNIT_ASSERT_EQUAL(classOffset(14), offsetof(struct _LibreOfficeKitClass
, setOption
));
3600 CPPUNIT_ASSERT_EQUAL(classOffset(15), offsetof(struct _LibreOfficeKitClass
, dumpState
));
3601 CPPUNIT_ASSERT_EQUAL(classOffset(16), offsetof(struct _LibreOfficeKitClass
, extractRequest
));
3602 CPPUNIT_ASSERT_EQUAL(classOffset(17), offsetof(struct _LibreOfficeKitClass
, trimMemory
));
3604 // When extending LibreOfficeKit with a new function pointer, add new assert for the offsetof the
3605 // new function pointer and bump this assert for the size of the class.
3606 CPPUNIT_ASSERT_EQUAL(classOffset(18), sizeof(struct _LibreOfficeKitClass
));
3608 CPPUNIT_ASSERT_EQUAL(documentClassOffset(0), offsetof(struct _LibreOfficeKitDocumentClass
, destroy
));
3609 CPPUNIT_ASSERT_EQUAL(documentClassOffset(1), offsetof(struct _LibreOfficeKitDocumentClass
, saveAs
));
3611 // Unstable ABI, but still think twice before changing this
3612 // Eg. can't you add your new member at the end of the struct instead of
3613 // in the middle? The thing you are changing - is it already part of some
3615 CPPUNIT_ASSERT_EQUAL(documentClassOffset(2), offsetof(struct _LibreOfficeKitDocumentClass
, getDocumentType
));
3616 CPPUNIT_ASSERT_EQUAL(documentClassOffset(3), offsetof(struct _LibreOfficeKitDocumentClass
, getParts
));
3617 CPPUNIT_ASSERT_EQUAL(documentClassOffset(4), offsetof(struct _LibreOfficeKitDocumentClass
, getPartPageRectangles
));
3618 CPPUNIT_ASSERT_EQUAL(documentClassOffset(5), offsetof(struct _LibreOfficeKitDocumentClass
, getPart
));
3619 CPPUNIT_ASSERT_EQUAL(documentClassOffset(6), offsetof(struct _LibreOfficeKitDocumentClass
, setPart
));
3620 CPPUNIT_ASSERT_EQUAL(documentClassOffset(7), offsetof(struct _LibreOfficeKitDocumentClass
, getPartName
));
3621 CPPUNIT_ASSERT_EQUAL(documentClassOffset(8), offsetof(struct _LibreOfficeKitDocumentClass
, setPartMode
));
3622 CPPUNIT_ASSERT_EQUAL(documentClassOffset(9), offsetof(struct _LibreOfficeKitDocumentClass
, paintTile
));
3623 CPPUNIT_ASSERT_EQUAL(documentClassOffset(10), offsetof(struct _LibreOfficeKitDocumentClass
, getTileMode
));
3624 CPPUNIT_ASSERT_EQUAL(documentClassOffset(11), offsetof(struct _LibreOfficeKitDocumentClass
, getDocumentSize
));
3625 CPPUNIT_ASSERT_EQUAL(documentClassOffset(12), offsetof(struct _LibreOfficeKitDocumentClass
, initializeForRendering
));
3626 CPPUNIT_ASSERT_EQUAL(documentClassOffset(13), offsetof(struct _LibreOfficeKitDocumentClass
, registerCallback
));
3627 CPPUNIT_ASSERT_EQUAL(documentClassOffset(14), offsetof(struct _LibreOfficeKitDocumentClass
, postKeyEvent
));
3628 CPPUNIT_ASSERT_EQUAL(documentClassOffset(15), offsetof(struct _LibreOfficeKitDocumentClass
, postMouseEvent
));
3629 CPPUNIT_ASSERT_EQUAL(documentClassOffset(16), offsetof(struct _LibreOfficeKitDocumentClass
, postUnoCommand
));
3630 CPPUNIT_ASSERT_EQUAL(documentClassOffset(17), offsetof(struct _LibreOfficeKitDocumentClass
, setTextSelection
));
3631 CPPUNIT_ASSERT_EQUAL(documentClassOffset(18), offsetof(struct _LibreOfficeKitDocumentClass
, getTextSelection
));
3632 CPPUNIT_ASSERT_EQUAL(documentClassOffset(19), offsetof(struct _LibreOfficeKitDocumentClass
, paste
));
3633 CPPUNIT_ASSERT_EQUAL(documentClassOffset(20), offsetof(struct _LibreOfficeKitDocumentClass
, setGraphicSelection
));
3634 CPPUNIT_ASSERT_EQUAL(documentClassOffset(21), offsetof(struct _LibreOfficeKitDocumentClass
, resetSelection
));
3635 CPPUNIT_ASSERT_EQUAL(documentClassOffset(22), offsetof(struct _LibreOfficeKitDocumentClass
, getCommandValues
));
3636 CPPUNIT_ASSERT_EQUAL(documentClassOffset(23), offsetof(struct _LibreOfficeKitDocumentClass
, setClientZoom
));
3637 CPPUNIT_ASSERT_EQUAL(documentClassOffset(24), offsetof(struct _LibreOfficeKitDocumentClass
, setClientVisibleArea
));
3638 CPPUNIT_ASSERT_EQUAL(documentClassOffset(25), offsetof(struct _LibreOfficeKitDocumentClass
, createView
));
3639 CPPUNIT_ASSERT_EQUAL(documentClassOffset(26), offsetof(struct _LibreOfficeKitDocumentClass
, destroyView
));
3640 CPPUNIT_ASSERT_EQUAL(documentClassOffset(27), offsetof(struct _LibreOfficeKitDocumentClass
, setView
));
3641 CPPUNIT_ASSERT_EQUAL(documentClassOffset(28), offsetof(struct _LibreOfficeKitDocumentClass
, getView
));
3642 CPPUNIT_ASSERT_EQUAL(documentClassOffset(29), offsetof(struct _LibreOfficeKitDocumentClass
, getViewsCount
));
3643 CPPUNIT_ASSERT_EQUAL(documentClassOffset(30), offsetof(struct _LibreOfficeKitDocumentClass
, renderFont
));
3644 CPPUNIT_ASSERT_EQUAL(documentClassOffset(31), offsetof(struct _LibreOfficeKitDocumentClass
, getPartHash
));
3645 CPPUNIT_ASSERT_EQUAL(documentClassOffset(32), offsetof(struct _LibreOfficeKitDocumentClass
, paintPartTile
));
3646 CPPUNIT_ASSERT_EQUAL(documentClassOffset(33), offsetof(struct _LibreOfficeKitDocumentClass
, getViewIds
));
3647 CPPUNIT_ASSERT_EQUAL(documentClassOffset(34), offsetof(struct _LibreOfficeKitDocumentClass
, setOutlineState
));
3648 CPPUNIT_ASSERT_EQUAL(documentClassOffset(35), offsetof(struct _LibreOfficeKitDocumentClass
, paintWindow
));
3649 CPPUNIT_ASSERT_EQUAL(documentClassOffset(36), offsetof(struct _LibreOfficeKitDocumentClass
, postWindow
));
3650 CPPUNIT_ASSERT_EQUAL(documentClassOffset(37), offsetof(struct _LibreOfficeKitDocumentClass
, postWindowKeyEvent
));
3651 CPPUNIT_ASSERT_EQUAL(documentClassOffset(38), offsetof(struct _LibreOfficeKitDocumentClass
, postWindowMouseEvent
));
3652 CPPUNIT_ASSERT_EQUAL(documentClassOffset(39), offsetof(struct _LibreOfficeKitDocumentClass
, setViewLanguage
));
3653 CPPUNIT_ASSERT_EQUAL(documentClassOffset(40), offsetof(struct _LibreOfficeKitDocumentClass
, postWindowExtTextInputEvent
));
3654 CPPUNIT_ASSERT_EQUAL(documentClassOffset(41), offsetof(struct _LibreOfficeKitDocumentClass
, getPartInfo
));
3655 CPPUNIT_ASSERT_EQUAL(documentClassOffset(42), offsetof(struct _LibreOfficeKitDocumentClass
, paintWindowDPI
));
3656 CPPUNIT_ASSERT_EQUAL(documentClassOffset(43), offsetof(struct _LibreOfficeKitDocumentClass
, insertCertificate
));
3657 CPPUNIT_ASSERT_EQUAL(documentClassOffset(44), offsetof(struct _LibreOfficeKitDocumentClass
, addCertificate
));
3658 CPPUNIT_ASSERT_EQUAL(documentClassOffset(45), offsetof(struct _LibreOfficeKitDocumentClass
, getSignatureState
));
3659 CPPUNIT_ASSERT_EQUAL(documentClassOffset(46), offsetof(struct _LibreOfficeKitDocumentClass
, renderShapeSelection
));
3660 CPPUNIT_ASSERT_EQUAL(documentClassOffset(47), offsetof(struct _LibreOfficeKitDocumentClass
, postWindowGestureEvent
));
3661 CPPUNIT_ASSERT_EQUAL(documentClassOffset(48), offsetof(struct _LibreOfficeKitDocumentClass
, createViewWithOptions
));
3662 CPPUNIT_ASSERT_EQUAL(documentClassOffset(49), offsetof(struct _LibreOfficeKitDocumentClass
, selectPart
));
3663 CPPUNIT_ASSERT_EQUAL(documentClassOffset(50), offsetof(struct _LibreOfficeKitDocumentClass
, moveSelectedParts
));
3664 CPPUNIT_ASSERT_EQUAL(documentClassOffset(51), offsetof(struct _LibreOfficeKitDocumentClass
, resizeWindow
));
3665 CPPUNIT_ASSERT_EQUAL(documentClassOffset(52), offsetof(struct _LibreOfficeKitDocumentClass
, getClipboard
));
3666 CPPUNIT_ASSERT_EQUAL(documentClassOffset(53), offsetof(struct _LibreOfficeKitDocumentClass
, setClipboard
));
3667 CPPUNIT_ASSERT_EQUAL(documentClassOffset(54), offsetof(struct _LibreOfficeKitDocumentClass
, getSelectionType
));
3668 CPPUNIT_ASSERT_EQUAL(documentClassOffset(55), offsetof(struct _LibreOfficeKitDocumentClass
, removeTextContext
));
3669 CPPUNIT_ASSERT_EQUAL(documentClassOffset(56), offsetof(struct _LibreOfficeKitDocumentClass
, sendDialogEvent
));
3670 CPPUNIT_ASSERT_EQUAL(documentClassOffset(57), offsetof(struct _LibreOfficeKitDocumentClass
, renderFontOrientation
));
3671 CPPUNIT_ASSERT_EQUAL(documentClassOffset(58), offsetof(struct _LibreOfficeKitDocumentClass
, paintWindowForView
));
3672 CPPUNIT_ASSERT_EQUAL(documentClassOffset(59), offsetof(struct _LibreOfficeKitDocumentClass
, completeFunction
));
3673 CPPUNIT_ASSERT_EQUAL(documentClassOffset(60), offsetof(struct _LibreOfficeKitDocumentClass
, setWindowTextSelection
));
3674 CPPUNIT_ASSERT_EQUAL(documentClassOffset(61), offsetof(struct _LibreOfficeKitDocumentClass
, sendFormFieldEvent
));
3675 CPPUNIT_ASSERT_EQUAL(documentClassOffset(62), offsetof(struct _LibreOfficeKitDocumentClass
, setBlockedCommandList
));
3676 CPPUNIT_ASSERT_EQUAL(documentClassOffset(63), offsetof(struct _LibreOfficeKitDocumentClass
, renderSearchResult
));
3677 CPPUNIT_ASSERT_EQUAL(documentClassOffset(64),
3678 offsetof(struct _LibreOfficeKitDocumentClass
, sendContentControlEvent
));
3679 CPPUNIT_ASSERT_EQUAL(documentClassOffset(65), offsetof(struct _LibreOfficeKitDocumentClass
, getSelectionTypeAndText
));
3680 CPPUNIT_ASSERT_EQUAL(documentClassOffset(66), offsetof(struct _LibreOfficeKitDocumentClass
, getDataArea
));
3681 CPPUNIT_ASSERT_EQUAL(documentClassOffset(67), offsetof(struct _LibreOfficeKitDocumentClass
, getEditMode
));
3682 CPPUNIT_ASSERT_EQUAL(documentClassOffset(68),
3683 offsetof(struct _LibreOfficeKitDocumentClass
, setViewTimezone
));
3684 CPPUNIT_ASSERT_EQUAL(documentClassOffset(69),
3685 offsetof(struct _LibreOfficeKitDocumentClass
, setAccessibilityState
));
3686 CPPUNIT_ASSERT_EQUAL(documentClassOffset(70),
3687 offsetof(struct _LibreOfficeKitDocumentClass
, getA11yFocusedParagraph
));
3688 CPPUNIT_ASSERT_EQUAL(documentClassOffset(71),
3689 offsetof(struct _LibreOfficeKitDocumentClass
, getA11yCaretPosition
));
3692 CPPUNIT_ASSERT_EQUAL(documentClassOffset(72), sizeof(struct _LibreOfficeKitDocumentClass
));
3695 CPPUNIT_TEST_SUITE_REGISTRATION(DesktopLOKTest
);
3697 CPPUNIT_PLUGIN_IMPLEMENT();
3699 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */