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 <test/unoapixml_test.hxx>
11 #include <test/helper/transferable.hxx>
12 #include <boost/property_tree/json_parser.hpp>
14 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
15 #include <com/sun/star/frame/Desktop.hpp>
16 #include <com/sun/star/datatransfer/clipboard/SystemClipboard.hpp>
17 #include <comphelper/dispatchcommand.hxx>
18 #include <comphelper/processfactory.hxx>
19 #include <comphelper/propertysequence.hxx>
20 #include <osl/conditn.hxx>
21 #include <sfx2/dispatch.hxx>
22 #include <sfx2/viewfrm.hxx>
23 #include <svl/stritem.hxx>
25 #include <comphelper/lok.hxx>
26 #include <comphelper/propertyvalue.hxx>
27 #include <sfx2/childwin.hxx>
28 #include <sfx2/lokhelper.hxx>
29 #include <svx/svdpage.hxx>
30 #include <vcl/scheduler.hxx>
31 #include <vcl/vclevent.hxx>
32 #include <vcl/virdev.hxx>
34 #include <comphelper/string.hxx>
35 #include <tools/json_writer.hxx>
36 #include <docoptio.hxx>
38 #include <test/lokcallback.hxx>
39 #include <osl/file.hxx>
40 #include <unotools/tempfile.hxx>
46 #include <scitems.hxx>
47 #include <tabvwsh.hxx>
49 #include <document.hxx>
51 #include <drwlayer.hxx>
52 #include <editutil.hxx>
53 #include <undomanager.hxx>
57 static std::ostream
& operator<<(std::ostream
& os
, ViewShellId
const & id
)
59 os
<< static_cast<sal_Int32
>(id
); return os
;
65 class ScTiledRenderingTest
: public UnoApiXmlTest
68 ScTiledRenderingTest();
69 virtual void setUp() override
;
70 virtual void tearDown() override
;
72 void testRowColumnHeaders();
73 void testRowColumnSelections();
75 void testDocumentSize();
76 void testEmptyColumnSelection();
77 void testViewCursors();
78 void testTextViewSelection();
79 void testDocumentSizeChanged();
81 void testColRowResize();
82 void testUndoShells();
83 void testCreateViewGraphicSelection();
84 void testTextEditViews();
85 void testTextEditViewInvalidations();
86 void testGraphicInvalidate();
88 void testHideColRow();
89 void testInvalidateOnCopyPasteCells();
90 void testInvalidateOnInserRowCol();
91 void testCommentCallback();
92 void testUndoLimiting();
93 void testUndoRepairDispatch();
94 void testInsertGraphicInvalidations();
95 void testDocumentSizeWithTwoViews();
96 void testDisableUndoRepair();
97 void testDocumentRepair();
98 void testLanguageStatus();
99 void testMultiViewCopyPaste();
100 void testIMESupport();
101 void testFilterDlg();
102 void testVbaRangeCopyPaste();
103 void testInvalidationLoop();
104 void testPageDownInvalidation();
105 void testSheetChangeInvalidation();
106 void testInsertDeletePageInvalidation();
107 void testGetRowColumnHeadersInvalidation();
108 void testJumpHorizontallyInvalidation();
109 void testJumpToLastRowInvalidation();
110 void testSheetGeometryDataInvariance();
111 void testSheetGeometryDataCorrectness();
112 void testDeleteCellMultilineContent();
113 void testFunctionDlg();
114 void testSpellOnlineParameter();
115 void testSpellOnlineRenderParameter();
116 void testPasteIntoWrapTextCell();
117 void testSortAscendingDescending();
118 void testAutoInputStringBlock();
119 void testAutoInputExactMatch();
120 void testMoveShapeHandle();
121 void testEditCursorBounds();
122 void testTextSelectionBounds();
123 void testSheetViewDataCrash();
124 void testTextBoxInsert();
125 void testCommentCellCopyPaste();
126 void testInvalidEntrySave();
127 void testUndoReordering();
128 void testUndoReorderingRedo();
129 void testUndoReorderingMulti();
131 CPPUNIT_TEST_SUITE(ScTiledRenderingTest
);
132 CPPUNIT_TEST(testRowColumnHeaders
);
133 CPPUNIT_TEST(testRowColumnSelections
);
134 CPPUNIT_TEST(testPartHash
);
135 CPPUNIT_TEST(testDocumentSize
);
136 CPPUNIT_TEST(testEmptyColumnSelection
);
137 CPPUNIT_TEST(testViewCursors
);
138 CPPUNIT_TEST(testTextViewSelection
);
139 CPPUNIT_TEST(testDocumentSizeChanged
);
140 CPPUNIT_TEST(testViewLock
);
141 CPPUNIT_TEST(testColRowResize
);
142 CPPUNIT_TEST(testUndoShells
);
143 CPPUNIT_TEST(testCreateViewGraphicSelection
);
144 CPPUNIT_TEST(testTextEditViews
);
145 CPPUNIT_TEST(testTextEditViewInvalidations
);
146 CPPUNIT_TEST(testGraphicInvalidate
);
147 CPPUNIT_TEST(testAutoSum
);
148 CPPUNIT_TEST(testHideColRow
);
149 CPPUNIT_TEST(testInvalidateOnCopyPasteCells
);
150 CPPUNIT_TEST(testInvalidateOnInserRowCol
);
151 CPPUNIT_TEST(testCommentCallback
);
152 CPPUNIT_TEST(testUndoLimiting
);
153 CPPUNIT_TEST(testUndoRepairDispatch
);
154 CPPUNIT_TEST(testInsertGraphicInvalidations
);
155 CPPUNIT_TEST(testDocumentSizeWithTwoViews
);
156 CPPUNIT_TEST(testDisableUndoRepair
);
157 CPPUNIT_TEST(testDocumentRepair
);
158 CPPUNIT_TEST(testLanguageStatus
);
159 CPPUNIT_TEST(testMultiViewCopyPaste
);
160 CPPUNIT_TEST(testIMESupport
);
161 CPPUNIT_TEST(testFilterDlg
);
162 CPPUNIT_TEST(testVbaRangeCopyPaste
);
163 CPPUNIT_TEST(testInvalidationLoop
);
164 CPPUNIT_TEST(testPageDownInvalidation
);
165 CPPUNIT_TEST(testSheetChangeInvalidation
);
166 CPPUNIT_TEST(testInsertDeletePageInvalidation
);
167 CPPUNIT_TEST(testGetRowColumnHeadersInvalidation
);
168 CPPUNIT_TEST(testJumpHorizontallyInvalidation
);
169 CPPUNIT_TEST(testJumpToLastRowInvalidation
);
170 CPPUNIT_TEST(testSheetGeometryDataInvariance
);
171 CPPUNIT_TEST(testSheetGeometryDataCorrectness
);
172 CPPUNIT_TEST(testDeleteCellMultilineContent
);
173 CPPUNIT_TEST(testFunctionDlg
);
174 CPPUNIT_TEST(testSpellOnlineParameter
);
175 CPPUNIT_TEST(testSpellOnlineRenderParameter
);
176 CPPUNIT_TEST(testPasteIntoWrapTextCell
);
177 CPPUNIT_TEST(testSortAscendingDescending
);
178 CPPUNIT_TEST(testAutoInputStringBlock
);
179 CPPUNIT_TEST(testAutoInputExactMatch
);
180 CPPUNIT_TEST(testMoveShapeHandle
);
181 CPPUNIT_TEST(testEditCursorBounds
);
182 CPPUNIT_TEST(testTextSelectionBounds
);
183 CPPUNIT_TEST(testSheetViewDataCrash
);
184 CPPUNIT_TEST(testTextBoxInsert
);
185 CPPUNIT_TEST(testCommentCellCopyPaste
);
186 CPPUNIT_TEST(testInvalidEntrySave
);
187 CPPUNIT_TEST(testUndoReordering
);
188 CPPUNIT_TEST(testUndoReorderingRedo
);
189 CPPUNIT_TEST(testUndoReorderingMulti
);
190 CPPUNIT_TEST_SUITE_END();
193 ScModelObj
* createDoc(const char* pName
);
194 void setupLibreOfficeKitViewCallback(SfxViewShell
* pViewShell
);
195 static void callback(int nType
, const char* pPayload
, void* pData
);
196 void callbackImpl(int nType
, const char* pPayload
);
198 /// document size changed callback.
199 osl::Condition m_aDocSizeCondition
;
200 Size m_aDocumentSize
;
202 TestLokCallbackWrapper m_callbackWrapper
;
205 ScTiledRenderingTest::ScTiledRenderingTest()
206 : UnoApiXmlTest("/sc/qa/unit/tiledrendering/data/"),
207 m_callbackWrapper(&callback
, this)
211 void ScTiledRenderingTest::setUp()
213 UnoApiXmlTest::setUp();
215 comphelper::LibreOfficeKit::setActive(true);
218 void ScTiledRenderingTest::tearDown()
220 if (mxComponent
.is())
222 mxComponent
->dispose();
226 m_callbackWrapper
.clear();
227 comphelper::LibreOfficeKit::setActive(false);
229 UnoApiXmlTest::tearDown();
232 ScModelObj
* ScTiledRenderingTest::createDoc(const char* pName
)
234 loadFromURL(OUString::createFromAscii(pName
));
236 ScModelObj
* pModelObj
= dynamic_cast<ScModelObj
*>(mxComponent
.get());
237 CPPUNIT_ASSERT(pModelObj
);
238 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
242 void ScTiledRenderingTest::setupLibreOfficeKitViewCallback(SfxViewShell
* pViewShell
)
244 pViewShell
->setLibreOfficeKitViewCallback(&m_callbackWrapper
);
245 m_callbackWrapper
.setLOKViewId(SfxLokHelper::getView(pViewShell
));
248 void ScTiledRenderingTest::callback(int nType
, const char* pPayload
, void* pData
)
250 static_cast<ScTiledRenderingTest
*>(pData
)->callbackImpl(nType
, pPayload
);
253 /* TODO when needed...
254 static std::vector<OUString> lcl_convertSeparated(const OUString& rString, sal_Unicode nSeparator)
256 std::vector<OUString> aRet;
258 sal_Int32 nIndex = 0;
261 OUString aToken = rString.getToken(0, nSeparator, nIndex);
262 aToken = aToken.trim();
263 if (!aToken.isEmpty())
264 aRet.push_back(aToken);
271 static void lcl_convertRectangle(const OUString& rString, Rectangle& rRectangle)
273 uno::Sequence<OUString> aSeq = comphelper::string::convertCommaSeparated(rString);
274 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), aSeq.getLength());
275 rRectangle.SetLeft(aSeq[0].toInt32());
276 rRectangle.SetTop(aSeq[1].toInt32());
277 rRectangle.setWidth(aSeq[2].toInt32());
278 rRectangle.setHeight(aSeq[3].toInt32());
282 void ScTiledRenderingTest::callbackImpl(int nType
, const char* pPayload
)
286 case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED
:
288 OString
aPayload(pPayload
);
289 sal_Int32 nIndex
= 0;
290 OString aToken
= aPayload
.getToken(0, ',', nIndex
);
291 m_aDocumentSize
.setWidth(aToken
.toInt32());
292 aToken
= aPayload
.getToken(0, ',', nIndex
);
293 m_aDocumentSize
.setHeight(aToken
.toInt32());
294 m_aDocSizeCondition
.set();
300 void ScTiledRenderingTest::testRowColumnSelections()
302 ScModelObj
* pModelObj
= createDoc("select-row-cols.ods");
304 // Select the 5th row with no modifier
305 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
306 { "Row", uno::Any(sal_Int32(5 - 1)) },
307 { "Modifier", uno::Any(sal_uInt16(0)) }
309 comphelper::dispatchCommand(".uno:SelectRow", aArgs
);
311 // Check if it is selected
312 OString aResult
= apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8");
313 OString
aExpected("1\t2\t3\t4\t5\t6\t7\t8\t9\t10\t11\t12\t13\t14\t15\t16\t17\t18\t19\t20\t21\n");
314 CPPUNIT_ASSERT_EQUAL(aExpected
, aResult
);
316 // Select the 10th row with shift modifier
317 aArgs
= comphelper::InitPropertySequence({ { "Row", uno::Any(static_cast<sal_Int32
>(10 - 1)) },
318 { "Modifier", uno::Any(KEY_SHIFT
) } });
319 comphelper::dispatchCommand(".uno:SelectRow", aArgs
);
321 // Check if all the rows from 5th to 10th get selected
322 aResult
= apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8");
323 aExpected
= "1\t2\t3\t4\t5\t6\t7\t8\t9\t10\t11\t12\t13\t14\t15\t16\t17\t18\t19\t20\t21\n2\t3\t4\t5\t6\t7\t8\t9\t10\t11\t12\t13\t14\t15\t16\t17\t18\t19\t20\t21\t22\n3\t4\t5\t6\t7\t8\t9\t10\t11\t12\t13\t14\t15\t16\t17\t18\t19\t20\t21\t22\t23\n4\t5\t6\t7\t8\t9\t10\t11\t12\t13\t14\t15\t16\t17\t18\t19\t20\t21\t22\t23\t24\n5\t6\t7\t8\t9\t10\t11\t12\t13\t14\t15\t16\t17\t18\t19\t20\t21\t22\t23\t24\t25\n6\t7\t8\t9\t10\t11\t12\t13\t14\t15\t16\t17\t18\t19\t20\t21\t22\t23\t24\t25\t26\n";
324 CPPUNIT_ASSERT_EQUAL(aExpected
, aResult
);
326 // Select the 10th row with ctrl modifier
327 aArgs
= comphelper::InitPropertySequence({ { "Row", uno::Any(static_cast<sal_Int32
>(13 - 1)) },
328 { "Modifier", uno::Any(KEY_MOD1
) } });
329 comphelper::dispatchCommand(".uno:SelectRow", aArgs
);
331 // When we copy this, we don't get anything useful, but we must not crash
333 aResult
= apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8");
334 CPPUNIT_ASSERT_EQUAL(OString(), aResult
);
336 // TODO check that we really selected what we wanted here
338 // Select Column 5 with ctrl modifier
339 aArgs
= comphelper::InitPropertySequence({ { "Col", uno::Any(static_cast<sal_Int32
>(5 - 1)) },
340 { "Modifier", uno::Any(KEY_MOD1
) } });
341 comphelper::dispatchCommand(".uno:SelectColumn", aArgs
);
343 // When we copy this, we don't get anything useful, but we must not crash
345 aResult
= apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8");
346 CPPUNIT_ASSERT_EQUAL(OString(), aResult
);
348 // TODO check that we really selected what we wanted here
350 // Test for deselection of already selected rows
351 // First Deselect Row 13 because copy doesn't work for multiple selections
352 aArgs
= comphelper::InitPropertySequence({ { "Row", uno::Any(static_cast<sal_Int32
>(13 - 1)) },
353 { "Modifier", uno::Any(KEY_MOD1
) } });
354 comphelper::dispatchCommand(".uno:SelectRow", aArgs
);
357 aArgs
= comphelper::InitPropertySequence({ { "Row", uno::Any(static_cast<sal_Int32
>(10 - 1)) },
358 { "Modifier", uno::Any(KEY_MOD1
) } });
359 comphelper::dispatchCommand(".uno:SelectRow", aArgs
);
361 // Click at row 6 holding shift
362 aArgs
= comphelper::InitPropertySequence({ { "Row", uno::Any(static_cast<sal_Int32
>(6 - 1)) },
363 { "Modifier", uno::Any(KEY_SHIFT
) } });
364 comphelper::dispatchCommand(".uno:SelectRow", aArgs
);
366 // only row 5 should remain selected
367 aResult
= apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8");
368 aExpected
= "1\t2\t3\t4\t5\t6\t7\t8\t9\t10\t11\t12\t13\t14\t15\t16\t17\t18\t19\t20\t21\n";
369 CPPUNIT_ASSERT_EQUAL(aExpected
, aResult
);
372 void ScTiledRenderingTest::testPartHash()
374 ScModelObj
* pModelObj
= createDoc("sort-range.ods");
376 int nParts
= pModelObj
->getParts();
377 for (int it
= 0; it
< nParts
; it
++)
379 CPPUNIT_ASSERT(!pModelObj
->getPartHash(it
).isEmpty());
382 // check part that it does not exists
383 CPPUNIT_ASSERT(pModelObj
->getPartHash(100).isEmpty());
386 void ScTiledRenderingTest::testDocumentSize()
388 ScModelObj
* pModelObj
= createDoc("sort-range.ods");
389 ScDocShell
* pDocSh
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
390 CPPUNIT_ASSERT(pDocSh
);
392 ScTabViewShell
* pViewShell
= pDocSh
->GetBestViewShell(false);
393 CPPUNIT_ASSERT(pViewShell
);
395 setupLibreOfficeKitViewCallback(pViewShell
);
397 // check initial document size
398 Size aDocSize
= pModelObj
->getDocumentSize();
399 CPPUNIT_ASSERT(aDocSize
.Width() > 0);
400 CPPUNIT_ASSERT(aDocSize
.Height() > 0);
403 pViewShell
->SetCursor(100, 0);
405 osl::Condition::Result aResult
= m_aDocSizeCondition
.wait(std::chrono::seconds(2));
406 CPPUNIT_ASSERT_EQUAL(osl::Condition::result_ok
, aResult
);
409 pViewShell
->SetCursor(0, 100);
411 aResult
= m_aDocSizeCondition
.wait(std::chrono::seconds(2));
412 CPPUNIT_ASSERT_EQUAL(osl::Condition::result_ok
, aResult
);
415 void ScTiledRenderingTest::testEmptyColumnSelection()
417 ScModelObj
* pModelObj
= createDoc("select-row-cols.ods");
419 // Select empty column, 1000
420 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
421 { "Col", uno::Any(sal_Int32(1000 - 1)) },
422 { "Modifier", uno::Any(sal_uInt16(0)) }
424 comphelper::dispatchCommand(".uno:SelectColumn", aArgs
);
426 // should be an empty string
427 CPPUNIT_ASSERT_EQUAL(OString(), apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8"));
430 struct EditCursorMessage final
{
431 tools::Rectangle m_aRelRect
;
436 m_aRelRect
.SetEmpty();
437 m_aRefPoint
= Point(-1, -1);
442 return m_aRelRect
.IsEmpty() &&
443 m_aRefPoint
.X() == -1 &&
444 m_aRefPoint
.Y() == -1;
447 void parseMessage(const char* pMessage
)
450 if (!pMessage
|| !comphelper::LibreOfficeKit::isCompatFlagSet(
451 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
) ||
452 !comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
455 std::stringstream
aStream(pMessage
);
456 boost::property_tree::ptree aTree
;
457 boost::property_tree::read_json(aStream
, aTree
);
459 boost::property_tree::ptree::const_assoc_iterator it
= aTree
.find("refpoint");
460 if (it
!= aTree
.not_found())
461 aVal
= aTree
.get_child("refpoint").get_value
<std::string
>();
463 return; // happens in testTextBoxInsert test
465 uno::Sequence
<OUString
> aSeq
= comphelper::string::convertCommaSeparated(OUString::createFromAscii(aVal
.c_str()));
466 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aSeq
.getLength());
467 m_aRefPoint
.setX(aSeq
[0].toInt32());
468 m_aRefPoint
.setY(aSeq
[1].toInt32());
470 aVal
= aTree
.get_child("relrect").get_value
<std::string
>();
471 aSeq
= comphelper::string::convertCommaSeparated(OUString::createFromAscii(aVal
.c_str()));
472 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), aSeq
.getLength());
473 m_aRelRect
.SetLeft(aSeq
[0].toInt32());
474 m_aRelRect
.SetTop(aSeq
[1].toInt32());
475 m_aRelRect
.setWidth(aSeq
[2].toInt32());
476 m_aRelRect
.setHeight(aSeq
[3].toInt32());
479 tools::Rectangle
getBounds()
481 tools::Rectangle aBounds
= m_aRelRect
;
482 aBounds
.Move(m_aRefPoint
.X(), m_aRefPoint
.Y());
487 struct TextSelectionMessage
489 std::vector
<tools::Rectangle
> m_aRelRects
;
499 return m_aRelRects
.empty();
502 void parseMessage(const char* pMessage
)
508 std::string
aStr(pMessage
);
509 if (aStr
.find(",") == std::string::npos
)
512 size_t nRefDelimStart
= aStr
.find("::");
513 std::string aRectListString
= (nRefDelimStart
== std::string::npos
) ? aStr
: aStr
.substr(0, nRefDelimStart
);
514 std::string aRefPointString
= (nRefDelimStart
== std::string::npos
) ?
515 std::string("0, 0") :
516 aStr
.substr(nRefDelimStart
+ 2, aStr
.length() - 2 - nRefDelimStart
);
517 uno::Sequence
<OUString
> aSeq
= comphelper::string::convertCommaSeparated(OUString::createFromAscii(aRefPointString
.c_str()));
518 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aSeq
.getLength());
519 m_aRefPoint
.setX(aSeq
[0].toInt32());
520 m_aRefPoint
.setY(aSeq
[1].toInt32());
523 size_t nEnd
= aRectListString
.find(";");
524 if (nEnd
== std::string::npos
)
525 nEnd
= aRectListString
.length();
528 std::string aRectString
= aRectListString
.substr(nStart
, nEnd
- nStart
);
530 aSeq
= comphelper::string::convertCommaSeparated(OUString::createFromAscii(aRectString
.c_str()));
531 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), aSeq
.getLength());
532 tools::Rectangle aRect
;
533 aRect
.SetLeft(aSeq
[0].toInt32());
534 aRect
.SetTop(aSeq
[1].toInt32());
535 aRect
.setWidth(aSeq
[2].toInt32());
536 aRect
.setHeight(aSeq
[3].toInt32());
538 m_aRelRects
.push_back(aRect
);
542 nEnd
= aRectListString
.find(";", nStart
);
544 while(nEnd
!= std::string::npos
);
547 tools::Rectangle
getBounds(size_t nIndex
)
549 if (nIndex
>= m_aRelRects
.size())
550 return tools::Rectangle();
552 tools::Rectangle aBounds
= m_aRelRects
[nIndex
];
553 aBounds
.Move(m_aRefPoint
.X(), m_aRefPoint
.Y());
559 /// A view callback tracks callbacks invoked on one specific view.
560 class ViewCallback final
562 SfxViewShell
* mpViewShell
;
565 bool m_bOwnCursorInvalidated
;
566 bool m_bViewCursorInvalidated
;
567 bool m_bTextViewSelectionInvalidated
;
568 bool m_bGraphicSelection
;
569 bool m_bGraphicViewSelection
;
570 bool m_bFullInvalidateTiles
;
571 bool m_bInvalidateTiles
;
572 std::vector
<tools::Rectangle
> m_aInvalidations
;
573 tools::Rectangle m_aCellCursorBounds
;
574 std::vector
<int> m_aInvalidationsParts
;
575 std::vector
<int> m_aInvalidationsMode
;
577 OString m_sCellFormula
;
578 boost::property_tree::ptree m_aCommentCallbackResult
;
579 EditCursorMessage m_aInvalidateCursorResult
;
580 TextSelectionMessage m_aTextSelectionResult
;
581 OString m_sInvalidateHeader
;
582 OString m_sInvalidateSheetGeometry
;
583 OString m_ShapeSelection
;
584 TestLokCallbackWrapper m_callbackWrapper
;
586 ViewCallback(bool bDeleteListenerOnDestruct
=true)
587 : m_bOwnCursorInvalidated(false),
588 m_bViewCursorInvalidated(false),
589 m_bTextViewSelectionInvalidated(false),
590 m_bGraphicSelection(false),
591 m_bGraphicViewSelection(false),
592 m_bFullInvalidateTiles(false),
593 m_bInvalidateTiles(false),
595 m_callbackWrapper(&callback
, this)
597 mpViewShell
= SfxViewShell::Current();
598 mpViewShell
->setLibreOfficeKitViewCallback(&m_callbackWrapper
);
599 mnView
= SfxLokHelper::getView();
600 m_callbackWrapper
.setLOKViewId( mnView
);
601 if (!bDeleteListenerOnDestruct
)
602 mpViewShell
= nullptr;
609 SfxLokHelper::setView(mnView
);
610 mpViewShell
->setLibreOfficeKitViewCallback(nullptr);
614 static void callback(int nType
, const char* pPayload
, void* pData
)
616 static_cast<ViewCallback
*>(pData
)->callbackImpl(nType
, pPayload
);
619 void callbackImpl(int nType
, const char* pPayload
)
623 case LOK_CALLBACK_CELL_CURSOR
:
625 m_bOwnCursorInvalidated
= true;
626 uno::Sequence
<OUString
> aSeq
= comphelper::string::convertCommaSeparated(OUString::createFromAscii(pPayload
));
627 m_aCellCursorBounds
= tools::Rectangle();
628 if (aSeq
.getLength() == 6) {
629 m_aCellCursorBounds
.SetLeft(aSeq
[0].toInt32());
630 m_aCellCursorBounds
.SetTop(aSeq
[1].toInt32());
631 m_aCellCursorBounds
.setWidth(aSeq
[2].toInt32());
632 m_aCellCursorBounds
.setHeight(aSeq
[3].toInt32());
636 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
638 m_bViewCursorInvalidated
= true;
641 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
643 m_bTextViewSelectionInvalidated
= true;
646 case LOK_CALLBACK_VIEW_LOCK
:
648 std::stringstream
aStream(pPayload
);
649 boost::property_tree::ptree aTree
;
650 boost::property_tree::read_json(aStream
, aTree
);
651 m_bViewLock
= aTree
.get_child("rectangle").get_value
<std::string
>() != "EMPTY";
654 case LOK_CALLBACK_GRAPHIC_SELECTION
:
656 m_bGraphicSelection
= true;
657 m_ShapeSelection
= OString(pPayload
);
660 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
662 m_bGraphicViewSelection
= true;
665 case LOK_CALLBACK_INVALIDATE_TILES
:
667 OString
text(pPayload
);
668 if (text
.startsWith("EMPTY"))
670 m_bFullInvalidateTiles
= true;
674 uno::Sequence
<OUString
> aSeq
= comphelper::string::convertCommaSeparated(OUString::createFromAscii(pPayload
));
675 CPPUNIT_ASSERT(aSeq
.getLength() == 4 || aSeq
.getLength() == 6);
676 tools::Rectangle aInvalidationRect
;
677 aInvalidationRect
.SetLeft(aSeq
[0].toInt32());
678 aInvalidationRect
.SetTop(aSeq
[1].toInt32());
679 aInvalidationRect
.setWidth(aSeq
[2].toInt32());
680 aInvalidationRect
.setHeight(aSeq
[3].toInt32());
681 m_aInvalidations
.push_back(aInvalidationRect
);
682 if (aSeq
.getLength() == 6)
684 m_aInvalidationsParts
.push_back(aSeq
[4].toInt32());
685 m_aInvalidationsMode
.push_back(aSeq
[5].toInt32());
687 m_bInvalidateTiles
= true;
691 case LOK_CALLBACK_CELL_FORMULA
:
693 m_sCellFormula
= pPayload
;
696 case LOK_CALLBACK_COMMENT
:
698 m_aCommentCallbackResult
.clear();
699 std::stringstream
aStream(pPayload
);
700 boost::property_tree::read_json(aStream
, m_aCommentCallbackResult
);
701 m_aCommentCallbackResult
= m_aCommentCallbackResult
.get_child("comment");
704 case LOK_CALLBACK_INVALIDATE_HEADER
:
706 m_sInvalidateHeader
= pPayload
;
709 case LOK_CALLBACK_INVALIDATE_SHEET_GEOMETRY
:
711 m_sInvalidateSheetGeometry
= pPayload
;
714 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
716 m_aInvalidateCursorResult
.parseMessage(pPayload
);
719 case LOK_CALLBACK_TEXT_SELECTION
:
721 m_aTextSelectionResult
.parseMessage(pPayload
);
728 void ScTiledRenderingTest::testViewCursors()
730 ScModelObj
* pModelObj
= createDoc("select-row-cols.ods");
732 SfxLokHelper::createView();
733 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
734 ViewCallback
aView2(/*bDeleteListenerOnDestruct*/false);
735 // This was false, the new view did not get the view (cell) cursor of the old view.
736 CPPUNIT_ASSERT(aView2
.m_bViewCursorInvalidated
);
737 CPPUNIT_ASSERT(aView2
.m_bOwnCursorInvalidated
);
738 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DOWN
);
739 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DOWN
);
740 Scheduler::ProcessEventsToIdle();
741 SfxLokHelper::destroyView(SfxLokHelper::getView());
742 CPPUNIT_ASSERT(aView1
.m_bViewCursorInvalidated
);
745 void ScTiledRenderingTest::testSpellOnlineRenderParameter()
747 ScModelObj
* pModelObj
= createDoc("empty.ods");
748 ScDocument
* pDoc
= pModelObj
->GetDocument();
749 bool bSet
= pDoc
->GetDocOptions().IsAutoSpell();
751 uno::Sequence
<beans::PropertyValue
> aPropertyValues
=
753 comphelper::makePropertyValue(".uno:SpellOnline", uno::Any(!bSet
)),
755 pModelObj
->initializeForTiledRendering(aPropertyValues
);
757 CPPUNIT_ASSERT_EQUAL(!bSet
, pDoc
->GetDocOptions().IsAutoSpell());
760 void ScTiledRenderingTest::testTextViewSelection()
762 // Create two views, and leave the second one current.
763 ScModelObj
* pModelObj
= createDoc("select-row-cols.ods");
765 SfxLokHelper::createView();
766 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
769 // Create a selection on two cells in the second view, that's a text selection in LOK terms.
770 aView1
.m_bTextViewSelectionInvalidated
= false;
771 dispatchCommand(mxComponent
, ".uno:GoRightSel", {});
772 Scheduler::ProcessEventsToIdle();
773 // Make sure the first view got its notification.
774 CPPUNIT_ASSERT(aView1
.m_bTextViewSelectionInvalidated
);
777 void ScTiledRenderingTest::testDocumentSizeChanged()
779 // Load a document that doesn't have much content.
780 createDoc("small.ods");
781 setupLibreOfficeKitViewCallback(SfxViewShell::Current());
783 // Go to the A30 cell -- that will extend the document size.
784 uno::Sequence
<beans::PropertyValue
> aPropertyValues
=
786 comphelper::makePropertyValue("ToPoint", OUString("$A$30")),
788 dispatchCommand(mxComponent
, ".uno:GoToCell", aPropertyValues
);
789 Scheduler::ProcessEventsToIdle();
790 // Assert that the size in the payload is not 0.
791 CPPUNIT_ASSERT(m_aDocumentSize
.getWidth() > 0);
792 CPPUNIT_ASSERT(m_aDocumentSize
.getHeight() > 0);
795 void ScTiledRenderingTest::testViewLock()
797 // Load a document that has a shape and create two views.
798 ScModelObj
* pModelObj
= createDoc("shape.ods");
800 SfxLokHelper::createView();
801 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
804 // Begin text edit in the second view and assert that the first gets a lock
806 const ScViewData
* pViewData
= ScDocShell::GetViewData();
807 ScTabViewShell
* pViewShell
= pViewData
->GetViewShell();
808 CPPUNIT_ASSERT(pViewShell
);
809 SdrModel
* pDrawModel
= pViewData
->GetDocument().GetDrawLayer();
810 SdrPage
* pDrawPage
= pDrawModel
->GetPage(0);
811 SdrObject
* pObject
= pDrawPage
->GetObj(0);
812 SdrView
* pView
= pViewShell
->GetScDrawView();
813 aView1
.m_bViewLock
= false;
814 pView
->SdrBeginTextEdit(pObject
);
815 CPPUNIT_ASSERT(aView1
.m_bViewLock
);
817 // End text edit in the second view, and assert that the lock is removed in
819 pView
->SdrEndTextEdit();
820 CPPUNIT_ASSERT(!aView1
.m_bViewLock
);
823 void lcl_extractHandleParameters(std::string_view selection
, sal_uInt32
& id
, sal_uInt32
& x
, sal_uInt32
& y
)
825 OString
extraInfo( selection
.substr(selection
.find("{")) );
826 std::stringstream
aStream(extraInfo
.getStr());
827 boost::property_tree::ptree aTree
;
828 boost::property_tree::read_json(aStream
, aTree
);
829 boost::property_tree::ptree
831 .get_child("handles")
833 .get_child("rectangle")
836 id
= handle0
.get_child("id").get_value
<int>();
837 x
= handle0
.get_child("point").get_child("x").get_value
<int>();
838 y
= handle0
.get_child("point").get_child("y").get_value
<int>();
841 void ScTiledRenderingTest::testMoveShapeHandle()
843 ScModelObj
* pModelObj
= createDoc("shape.ods");
845 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
, /*x=*/ 1,/*y=*/ 1,/*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
846 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
, /*x=*/ 1, /*y=*/ 1, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
847 Scheduler::ProcessEventsToIdle();
849 CPPUNIT_ASSERT(!aView1
.m_ShapeSelection
.isEmpty());
852 lcl_extractHandleParameters(aView1
.m_ShapeSelection
, id
, x
,y
);
855 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
857 {"HandleNum", uno::Any(id
)},
858 {"NewPosX", uno::Any(x
+1)},
859 {"NewPosY", uno::Any(y
+1)}
861 comphelper::dispatchCommand(".uno:MoveShapeHandle", aPropertyValues
);
862 Scheduler::ProcessEventsToIdle();
863 CPPUNIT_ASSERT(!aView1
.m_ShapeSelection
.isEmpty());
864 lcl_extractHandleParameters(aView1
.m_ShapeSelection
, id
, x
,y
);
865 CPPUNIT_ASSERT_EQUAL(x
-1, oldX
);
866 CPPUNIT_ASSERT_EQUAL(y
-1, oldY
);
870 void ScTiledRenderingTest::testColRowResize()
872 ScModelObj
* pModelObj
= createDoc("sort-range.ods");
873 ScDocShell
* pDocSh
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
874 CPPUNIT_ASSERT(pDocSh
);
876 ScTabViewShell
* pViewShell
= pDocSh
->GetBestViewShell(false);
877 CPPUNIT_ASSERT(pViewShell
);
879 setupLibreOfficeKitViewCallback(pViewShell
);
881 ScDocument
& rDoc
= pDocSh
->GetDocument();
884 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
885 { "ColumnWidth", uno::Any(sal_uInt16(4000)) }, // 4cm
886 { "Column", uno::Any(sal_Int16(3)) }
888 comphelper::dispatchCommand(".uno:ColumnWidth", aArgs
);
890 sal_uInt16 nWidth
= o3tl::convert(rDoc
.GetColWidth(static_cast<SCCOL
>(2), static_cast<SCTAB
>(0), false), o3tl::Length::twip
, o3tl::Length::mm100
);
891 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(4001), nWidth
);
894 uno::Sequence
<beans::PropertyValue
> aArgs2( comphelper::InitPropertySequence({
895 { "RowHeight", uno::Any(sal_uInt16(2000)) },
896 { "Row", uno::Any(sal_Int16(5)) },
898 comphelper::dispatchCommand(".uno:RowHeight", aArgs2
);
900 sal_uInt16 nHeight
= o3tl::convert(rDoc
.GetRowHeight(static_cast<SCROW
>(4), static_cast<SCTAB
>(0), false), o3tl::Length::twip
, o3tl::Length::mm100
);
901 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(2000), nHeight
);
904 void ScTiledRenderingTest::testUndoShells()
906 ScModelObj
* pModelObj
= createDoc("small.ods");
907 // Clear the currently selected cell.
908 comphelper::dispatchCommand(".uno:ClearContents", {});
910 auto pDocShell
= dynamic_cast<ScDocShell
*>(pModelObj
->GetEmbeddedObject());
911 CPPUNIT_ASSERT(pDocShell
);
912 ScDocument
& rDoc
= pDocShell
->GetDocument();
913 ScUndoManager
* pUndoManager
= rDoc
.GetUndoManager();
914 CPPUNIT_ASSERT(pUndoManager
);
915 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pUndoManager
->GetUndoActionCount());
916 sal_Int32 nView1
= SfxLokHelper::getView();
917 // This was -1: ScSimpleUndo did not remember what view shell created it.
918 CPPUNIT_ASSERT_EQUAL(ViewShellId(nView1
), pUndoManager
->GetUndoAction()->GetViewShellId());
921 bool lcl_hasEditView(const ScViewData
& rViewData
)
923 bool bResult
= false;
924 for (unsigned int i
=0; i
<4; i
++)
926 bResult
= rViewData
.HasEditView( static_cast<ScSplitPos
>(i
) );
932 void ScTiledRenderingTest::testTextEditViews()
934 ScModelObj
* pModelObj
= createDoc("small.ods");
935 CPPUNIT_ASSERT(pModelObj
);
936 ScViewData
* pViewData
= ScDocShell::GetViewData();
937 CPPUNIT_ASSERT(pViewData
);
941 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
943 // text edit a cell in view #1
944 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
945 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
946 Scheduler::ProcessEventsToIdle();
947 CPPUNIT_ASSERT(lcl_hasEditView(*pViewData
));
950 SfxLokHelper::createView();
951 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
954 // move cell cursor i view #2
955 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DOWN
);
956 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DOWN
);
957 Scheduler::ProcessEventsToIdle();
959 // check that text edit view in view #1 has not be killed
960 CPPUNIT_ASSERT(lcl_hasEditView(*pViewData
));
963 void ScTiledRenderingTest::testTextEditViewInvalidations()
965 ScModelObj
* pModelObj
= createDoc("small.ods");
966 CPPUNIT_ASSERT(pModelObj
);
967 ScViewData
* pViewData
= ScDocShell::GetViewData();
968 CPPUNIT_ASSERT(pViewData
);
971 int nView1
= SfxLokHelper::getView();
973 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
976 SfxLokHelper::createView();
977 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
980 // text edit a cell in view #1
981 SfxLokHelper::setView(nView1
);
982 aView2
.m_bInvalidateTiles
= false;
983 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
984 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
985 Scheduler::ProcessEventsToIdle();
986 CPPUNIT_ASSERT(lcl_hasEditView(*pViewData
));
987 CPPUNIT_ASSERT(aView2
.m_bInvalidateTiles
);
989 // text edit a cell in view #1 until
990 // we can be sure we are out of the initial tile
991 for (int i
= 0; i
< 40; ++i
)
993 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
994 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
996 Scheduler::ProcessEventsToIdle();
998 // text edit a cell in view #1 inside the new tile and
999 // check that view #2 receive a tile invalidate message
1000 aView2
.m_bInvalidateTiles
= false;
1001 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
1002 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
1003 Scheduler::ProcessEventsToIdle();
1004 CPPUNIT_ASSERT(aView2
.m_bInvalidateTiles
);
1007 SfxLokHelper::createView();
1008 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
1009 ViewCallback aView3
;
1011 // text edit a cell in view #1
1012 SfxLokHelper::setView(nView1
);
1013 aView3
.m_bInvalidateTiles
= false;
1014 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'y', 0);
1015 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'y', 0);
1016 Scheduler::ProcessEventsToIdle();
1017 CPPUNIT_ASSERT(aView3
.m_bInvalidateTiles
);
1020 void ScTiledRenderingTest::testCreateViewGraphicSelection()
1022 // Load a document that has a shape and create two views.
1023 ScModelObj
* pModelObj
= createDoc("shape.ods");
1024 ViewCallback aView1
;
1026 // Mark the graphic in the first view.
1027 const ScViewData
* pViewData
= ScDocShell::GetViewData();
1028 ScTabViewShell
* pViewShell
= pViewData
->GetViewShell();
1029 CPPUNIT_ASSERT(pViewShell
);
1030 SdrModel
* pDrawModel
= pViewData
->GetDocument().GetDrawLayer();
1031 SdrPage
* pDrawPage
= pDrawModel
->GetPage(0);
1032 SdrObject
* pObject
= pDrawPage
->GetObj(0);
1033 SdrView
* pView
= pViewShell
->GetScDrawView();
1034 aView1
.m_bGraphicSelection
= false;
1035 aView1
.m_bGraphicViewSelection
= false;
1036 pView
->MarkObj(pObject
, pView
->GetSdrPageView());
1037 CPPUNIT_ASSERT(aView1
.m_bGraphicSelection
);
1039 // Create a second view.
1040 int nView1
= SfxLokHelper::getView();
1041 SfxLokHelper::createView();
1042 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
1043 ViewCallback aView2
;
1044 CPPUNIT_ASSERT(aView2
.m_bGraphicViewSelection
);
1045 CPPUNIT_ASSERT(aView1
.m_bGraphicViewSelection
);
1047 SfxLokHelper::setView(nView1
);
1048 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1051 void ScTiledRenderingTest::testGraphicInvalidate()
1053 // Load a document that has a shape and create two views.
1054 ScModelObj
* pModelObj
= createDoc("shape.ods");
1057 // Click to select graphic
1058 aView
.m_bGraphicSelection
= false;
1059 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
, /*x=*/ 1,/*y=*/ 1,/*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
1060 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
, /*x=*/ 1, /*y=*/ 1, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
1061 Scheduler::ProcessEventsToIdle();
1062 CPPUNIT_ASSERT(aView
.m_bGraphicSelection
);
1064 // Drag Drop graphic
1065 aView
.m_bGraphicSelection
= false;
1066 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
, /*x=*/ 1,/*y=*/ 1,/*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
1067 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEMOVE
, /*x=*/ 1,/*y=*/ 10,/*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
1068 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
, /*x=*/ 1, /*y=*/ 10, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
1069 Scheduler::ProcessEventsToIdle();
1070 CPPUNIT_ASSERT(!aView
.m_bFullInvalidateTiles
);
1073 Scheduler::ProcessEventsToIdle();
1074 CPPUNIT_ASSERT(!aView
.m_bFullInvalidateTiles
);
1077 void ScTiledRenderingTest::testAutoSum()
1079 createDoc("small.ods");
1083 uno::Sequence
<beans::PropertyValue
> aArgs
;
1084 comphelper::dispatchCommand(".uno:AutoSum", aArgs
);
1085 Scheduler::ProcessEventsToIdle();
1086 CPPUNIT_ASSERT(aView
.m_sCellFormula
.startsWith("=SUM("));
1089 void ScTiledRenderingTest::testHideColRow()
1091 createDoc("small.ods");
1093 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
1094 { "Col", uno::Any(sal_Int32(2 - 1)) },
1095 { "Modifier", uno::Any(KEY_SHIFT
) }
1097 comphelper::dispatchCommand(".uno:SelectColumn", aArgs
);
1099 uno::Sequence
<beans::PropertyValue
> aArgs2( comphelper::InitPropertySequence({
1100 { "Col", uno::Any(sal_Int32(3 - 1)) },
1101 { "Modifier", uno::Any(sal_uInt16(0)) }
1104 comphelper::dispatchCommand(".uno:SelectColumn", aArgs2
);
1105 Scheduler::ProcessEventsToIdle();
1108 SCCOL nOldCurX
= ScDocShell::GetViewData()->GetCurX();
1109 SCROW nOldCurY
= ScDocShell::GetViewData()->GetCurY();
1111 uno::Sequence
<beans::PropertyValue
> aArgs
;
1112 comphelper::dispatchCommand(".uno:HideColumn", aArgs
);
1113 Scheduler::ProcessEventsToIdle();
1116 SCCOL nNewCurX
= ScDocShell::GetViewData()->GetCurX();
1117 SCROW nNewCurY
= ScDocShell::GetViewData()->GetCurY();
1118 CPPUNIT_ASSERT(nNewCurX
> nOldCurX
);
1119 CPPUNIT_ASSERT_EQUAL(nOldCurY
, nNewCurY
);
1121 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
1122 { "Row", uno::Any(sal_Int32(6 - 1)) },
1123 { "Modifier", uno::Any(KEY_SHIFT
) }
1125 comphelper::dispatchCommand(".uno:SelectRow", aArgs
);
1127 uno::Sequence
<beans::PropertyValue
> aArgs2( comphelper::InitPropertySequence({
1128 { "Row", uno::Any(sal_Int32(7 - 1)) },
1129 { "Modifier", uno::Any(sal_uInt16(0)) }
1131 comphelper::dispatchCommand(".uno:SelectRow", aArgs2
);
1132 Scheduler::ProcessEventsToIdle();
1135 nOldCurX
= ScDocShell::GetViewData()->GetCurX();
1136 nOldCurY
= ScDocShell::GetViewData()->GetCurY();
1138 uno::Sequence
<beans::PropertyValue
> aArgs
;
1139 comphelper::dispatchCommand(".uno:HideRow", aArgs
);
1140 Scheduler::ProcessEventsToIdle();
1142 nNewCurX
= ScDocShell::GetViewData()->GetCurX();
1143 nNewCurY
= ScDocShell::GetViewData()->GetCurY();
1144 CPPUNIT_ASSERT(nNewCurY
> nOldCurY
);
1145 CPPUNIT_ASSERT_EQUAL(nOldCurX
, nNewCurX
);
1148 void ScTiledRenderingTest::testInvalidateOnCopyPasteCells()
1150 ScModelObj
* pModelObj
= createDoc("small.ods");
1151 CPPUNIT_ASSERT(pModelObj
);
1156 uno::Sequence
<beans::PropertyValue
> aArgs
;
1157 // select and copy cells
1158 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_HOME
| KEY_MOD1
);
1159 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_HOME
| KEY_MOD1
);
1160 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
| KEY_SHIFT
);
1161 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
| KEY_SHIFT
);
1162 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_RIGHT
| KEY_SHIFT
);
1163 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_RIGHT
| KEY_SHIFT
);
1164 Scheduler::ProcessEventsToIdle();
1165 comphelper::dispatchCommand(".uno:Copy", aArgs
);
1167 // move to destination cell
1168 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
);
1169 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
);
1170 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
| KEY_MOD1
);
1171 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
| KEY_MOD1
);
1172 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_UP
);
1173 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_UP
);
1174 Scheduler::ProcessEventsToIdle();
1177 aView
.m_bInvalidateTiles
= false;
1178 comphelper::dispatchCommand(".uno:Paste", aArgs
);
1179 Scheduler::ProcessEventsToIdle();
1180 CPPUNIT_ASSERT(aView
.m_bInvalidateTiles
);
1183 void ScTiledRenderingTest::testInvalidateOnInserRowCol()
1185 ScModelObj
* pModelObj
= createDoc("small.ods");
1186 CPPUNIT_ASSERT(pModelObj
);
1191 uno::Sequence
<beans::PropertyValue
> aArgs
;
1193 for (int i
= 0; i
< 200; ++i
)
1195 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
);
1196 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
);
1198 Scheduler::ProcessEventsToIdle();
1201 aView
.m_bInvalidateTiles
= false;
1202 aView
.m_aInvalidations
.clear();
1203 comphelper::dispatchCommand(".uno:InsertRows", aArgs
);
1204 Scheduler::ProcessEventsToIdle();
1205 CPPUNIT_ASSERT(aView
.m_bInvalidateTiles
);
1206 CPPUNIT_ASSERT_EQUAL(size_t(2), aView
.m_aInvalidations
.size());
1207 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(-75, 51240, 32212230, 63990), aView
.m_aInvalidations
[0]);
1209 // move on the right
1210 for (int i
= 0; i
< 200; ++i
)
1212 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_RIGHT
);
1213 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_RIGHT
);
1215 Scheduler::ProcessEventsToIdle();
1218 aView
.m_bInvalidateTiles
= false;
1219 aView
.m_aInvalidations
.clear();
1220 comphelper::dispatchCommand(".uno:InsertColumns", aArgs
);
1221 Scheduler::ProcessEventsToIdle();
1222 CPPUNIT_ASSERT(aView
.m_bInvalidateTiles
);
1223 CPPUNIT_ASSERT_EQUAL(size_t(2), aView
.m_aInvalidations
.size());
1224 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(254925, -15, 32212230, 63990), aView
.m_aInvalidations
[0]);
1227 void ScTiledRenderingTest::testCommentCallback()
1229 // Comments callback are emitted only if tiled annotations are off
1230 comphelper::LibreOfficeKit::setTiledAnnotations(false);
1233 ScModelObj
* pModelObj
= createDoc("small.ods");
1234 ViewCallback aView1
;
1235 int nView1
= SfxLokHelper::getView();
1237 // Create a 2nd view
1238 SfxLokHelper::createView();
1239 pModelObj
->initializeForTiledRendering({});
1240 ViewCallback aView2
;
1242 SfxLokHelper::setView(nView1
);
1244 // Add a new comment
1245 uno::Sequence
<beans::PropertyValue
> aArgs(comphelper::InitPropertySequence(
1247 {"Text", uno::Any(OUString("Comment"))},
1248 {"Author", uno::Any(OUString("LOK User1"))},
1250 comphelper::dispatchCommand(".uno:InsertAnnotation", aArgs
);
1251 Scheduler::ProcessEventsToIdle();
1253 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action
1254 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1255 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1256 CPPUNIT_ASSERT_EQUAL(std::string("1"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("id"));
1257 CPPUNIT_ASSERT_EQUAL(std::string("1"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("id"));
1258 CPPUNIT_ASSERT_EQUAL(std::string("0"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("tab"));
1259 CPPUNIT_ASSERT_EQUAL(std::string("0"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("tab"));
1260 CPPUNIT_ASSERT_EQUAL(std::string("LOK User1"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("author"));
1261 CPPUNIT_ASSERT_EQUAL(std::string("LOK User1"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("author"));
1262 CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1263 CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1264 CPPUNIT_ASSERT_EQUAL(std::string("0, 255, 1274, 254"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("cellPos"));
1265 CPPUNIT_ASSERT_EQUAL(std::string("0, 255, 1274, 254"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("cellPos"));
1267 std::string aCommentId
= aView1
.m_aCommentCallbackResult
.get
<std::string
>("id");
1270 // Select some random cell, we should be able to edit the cell note without
1271 // selecting the cell
1272 ScTabViewShell
* pTabViewShell
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
1274 pTabViewShell
->SetCursor(3, 100);
1275 aArgs
= comphelper::InitPropertySequence(
1277 {"Id", uno::Any(OUString::createFromAscii(aCommentId
.c_str()))},
1278 {"Text", uno::Any(OUString("Edited comment"))},
1279 {"Author", uno::Any(OUString("LOK User2"))},
1281 comphelper::dispatchCommand(".uno:EditAnnotation", aArgs
);
1282 Scheduler::ProcessEventsToIdle();
1284 // We received a LOK_CALLBACK_COMMENT callback with comment 'Modify' action
1285 CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1286 CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1287 CPPUNIT_ASSERT_EQUAL(aCommentId
, aView1
.m_aCommentCallbackResult
.get
<std::string
>("id"));
1288 CPPUNIT_ASSERT_EQUAL(aCommentId
, aView2
.m_aCommentCallbackResult
.get
<std::string
>("id"));
1289 CPPUNIT_ASSERT_EQUAL(std::string("LOK User2"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("author"));
1290 CPPUNIT_ASSERT_EQUAL(std::string("LOK User2"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("author"));
1291 CPPUNIT_ASSERT_EQUAL(std::string("Edited comment"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1292 CPPUNIT_ASSERT_EQUAL(std::string("Edited comment"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1293 CPPUNIT_ASSERT_EQUAL(std::string("0, 255, 1274, 254"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("cellPos"));
1294 CPPUNIT_ASSERT_EQUAL(std::string("0, 255, 1274, 254"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("cellPos"));
1296 // Delete the comment
1298 pTabViewShell
->SetCursor(4, 43);
1299 aArgs
= comphelper::InitPropertySequence(
1301 {"Id", uno::Any(OUString::createFromAscii(aCommentId
.c_str()))}
1303 comphelper::dispatchCommand(".uno:DeleteNote", aArgs
);
1304 Scheduler::ProcessEventsToIdle();
1306 // We received a LOK_CALLBACK_COMMENT callback with comment 'Remove' action
1307 CPPUNIT_ASSERT_EQUAL(std::string("Remove"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1308 CPPUNIT_ASSERT_EQUAL(std::string("Remove"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1309 CPPUNIT_ASSERT_EQUAL(aCommentId
, aView1
.m_aCommentCallbackResult
.get
<std::string
>("id"));
1310 CPPUNIT_ASSERT_EQUAL(aCommentId
, aView2
.m_aCommentCallbackResult
.get
<std::string
>("id"));
1312 comphelper::LibreOfficeKit::setTiledAnnotations(true);
1315 void ScTiledRenderingTest::testUndoLimiting()
1317 ScModelObj
* pModelObj
= createDoc("small.ods");
1318 CPPUNIT_ASSERT(pModelObj
);
1319 ScDocument
* pDoc
= pModelObj
->GetDocument();
1320 CPPUNIT_ASSERT(pDoc
);
1321 ScUndoManager
* pUndoManager
= pDoc
->GetUndoManager();
1322 CPPUNIT_ASSERT(pUndoManager
);
1325 int nView1
= SfxLokHelper::getView();
1326 ViewCallback aView1
;
1329 SfxLokHelper::createView();
1330 int nView2
= SfxLokHelper::getView();
1331 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
1332 ViewCallback aView2
;
1334 // text edit a cell in view #1
1335 SfxLokHelper::setView(nView1
);
1336 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
1337 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
1338 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
1339 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
1340 Scheduler::ProcessEventsToIdle();
1342 // check that undo action count in not 0
1343 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
1345 // try to execute undo in view #2
1346 SfxLokHelper::setView(nView2
);
1347 comphelper::dispatchCommand(".uno:Undo", {});
1348 Scheduler::ProcessEventsToIdle();
1349 // check that undo has not been executed on view #2
1350 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
1352 // try to execute undo in view #1
1353 SfxLokHelper::setView(nView1
);
1354 comphelper::dispatchCommand(".uno:Undo", {});
1355 Scheduler::ProcessEventsToIdle();
1356 // check that undo has been executed on view #1
1357 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetUndoActionCount());
1359 // check that redo action count in not 0
1360 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetRedoActionCount());
1362 // try to execute redo in view #2
1363 SfxLokHelper::setView(nView2
);
1364 comphelper::dispatchCommand(".uno:Redo", {});
1365 Scheduler::ProcessEventsToIdle();
1366 // check that redo has not been executed on view #2
1367 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetRedoActionCount());
1369 // try to execute redo in view #1
1370 SfxLokHelper::setView(nView1
);
1371 comphelper::dispatchCommand(".uno:Redo", {});
1372 Scheduler::ProcessEventsToIdle();
1373 // check that redo has been executed on view #1
1374 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetRedoActionCount());
1377 void ScTiledRenderingTest::testUndoRepairDispatch()
1379 ScModelObj
* pModelObj
= createDoc("small.ods");
1380 CPPUNIT_ASSERT(pModelObj
);
1381 ScDocument
* pDoc
= pModelObj
->GetDocument();
1382 CPPUNIT_ASSERT(pDoc
);
1383 ScUndoManager
* pUndoManager
= pDoc
->GetUndoManager();
1384 CPPUNIT_ASSERT(pUndoManager
);
1387 int nView1
= SfxLokHelper::getView();
1388 ViewCallback aView1
;
1391 SfxLokHelper::createView();
1392 int nView2
= SfxLokHelper::getView();
1393 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
1394 ViewCallback aView2
;
1396 // text edit a cell in view #1
1397 SfxLokHelper::setView(nView1
);
1398 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
1399 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
1400 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
1401 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
1402 Scheduler::ProcessEventsToIdle();
1404 // check that undo action count in not 0
1405 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
1407 // try to execute undo in view #2
1408 SfxLokHelper::setView(nView2
);
1409 comphelper::dispatchCommand(".uno:Undo", {});
1410 Scheduler::ProcessEventsToIdle();
1411 // check that undo has not been executed on view #2
1412 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
1414 // try to execute undo in view #2 in repair mode
1415 SfxLokHelper::setView(nView2
);
1416 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
1418 {"Repair", uno::Any(true)}
1420 comphelper::dispatchCommand(".uno:Undo", aPropertyValues
);
1421 Scheduler::ProcessEventsToIdle();
1422 // check that undo has been executed on view #2 in repair mode
1423 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetUndoActionCount());
1426 void ScTiledRenderingTest::testInsertGraphicInvalidations()
1428 ScModelObj
* pModelObj
= createDoc("small.ods");
1429 CPPUNIT_ASSERT(pModelObj
);
1430 ScViewData
* pViewData
= ScDocShell::GetViewData();
1431 CPPUNIT_ASSERT(pViewData
);
1436 // we need to paint a tile in the view for triggering the tile invalidation solution
1437 int nCanvasWidth
= 256;
1438 int nCanvasHeight
= 256;
1439 std::vector
<unsigned char> aBuffer(nCanvasWidth
* nCanvasHeight
* 4);
1440 ScopedVclPtrInstance
<VirtualDevice
> pDevice(DeviceFormat::DEFAULT
);
1441 pDevice
->SetOutputSizePixelScaleOffsetAndLOKBuffer(Size(nCanvasWidth
, nCanvasHeight
), Fraction(1.0), Point(), aBuffer
.data());
1442 pModelObj
->paintTile(*pDevice
, nCanvasWidth
, nCanvasHeight
, /*nTilePosX=*/0, /*nTilePosY=*/0, /*nTileWidth=*/3840, /*nTileHeight=*/3840);
1443 Scheduler::ProcessEventsToIdle();
1445 // insert an image in view and see if both views are invalidated
1446 aView
.m_bInvalidateTiles
= false;
1447 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
1448 { "FileName", uno::Any(createFileURL(u
"smile.png")) }
1450 comphelper::dispatchCommand(".uno:InsertGraphic", aArgs
);
1451 Scheduler::ProcessEventsToIdle();
1452 CPPUNIT_ASSERT(aView
.m_bInvalidateTiles
);
1454 // undo image insertion in view and see if both views are invalidated
1455 aView
.m_bInvalidateTiles
= false;
1456 uno::Sequence
<beans::PropertyValue
> aArgs2
;
1457 comphelper::dispatchCommand(".uno:Undo", aArgs2
);
1458 Scheduler::ProcessEventsToIdle();
1459 CPPUNIT_ASSERT(aView
.m_bInvalidateTiles
);
1462 void ScTiledRenderingTest::testDocumentSizeWithTwoViews()
1464 // Open a document that has the cursor far away & paint a tile
1465 ScModelObj
* pModelObj
= createDoc("cursor-away.ods");
1467 // Set the visible area, and press page down
1468 pModelObj
->setClientVisibleArea(tools::Rectangle(750, 1861, 20583, 6997));
1469 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
);
1470 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
);
1471 Scheduler::ProcessEventsToIdle();
1473 int nCanvasWidth
= 256;
1474 int nCanvasHeight
= 256;
1475 std::vector
<unsigned char> aBuffer1(nCanvasWidth
* nCanvasHeight
* 4);
1476 ScopedVclPtrInstance
<VirtualDevice
> pDevice1(DeviceFormat::DEFAULT
);
1477 pDevice1
->SetOutputSizePixelScaleOffsetAndLOKBuffer(Size(nCanvasWidth
, nCanvasHeight
), Fraction(1.0), Point(), aBuffer1
.data());
1478 pModelObj
->paintTile(*pDevice1
, nCanvasWidth
, nCanvasHeight
, /*nTilePosX=*/0, /*nTilePosY=*/291840, /*nTileWidth=*/3840, /*nTileHeight=*/3840);
1479 Scheduler::ProcessEventsToIdle();
1481 // Create a new view
1482 int nView1
= SfxLokHelper::getView();
1483 SfxLokHelper::createView();
1485 std::vector
<unsigned char> aBuffer2(nCanvasWidth
* nCanvasHeight
* 4);
1486 ScopedVclPtrInstance
<VirtualDevice
> pDevice2(DeviceFormat::DEFAULT
);
1487 pDevice2
->SetOutputSizePixelScaleOffsetAndLOKBuffer(Size(nCanvasWidth
, nCanvasHeight
), Fraction(1.0), Point(), aBuffer2
.data());
1488 pModelObj
->paintTile(*pDevice2
, nCanvasWidth
, nCanvasHeight
, /*nTilePosX=*/0, /*nTilePosY=*/291840, /*nTileWidth=*/3840, /*nTileHeight=*/3840);
1489 Scheduler::ProcessEventsToIdle();
1491 // Check that the tiles actually have the same content
1492 for (size_t i
= 0; i
< aBuffer1
.size(); ++i
)
1493 CPPUNIT_ASSERT_EQUAL(aBuffer1
[i
], aBuffer2
[i
]);
1495 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1496 SfxLokHelper::setView(nView1
);
1497 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1500 void ScTiledRenderingTest::testDisableUndoRepair()
1502 ScModelObj
* pModelObj
= createDoc("cursor-away.ods");
1503 CPPUNIT_ASSERT(pModelObj
);
1506 int nView1
= SfxLokHelper::getView();
1507 SfxViewShell
* pView1
= SfxViewShell::Current();
1510 SfxLokHelper::createView();
1511 int nView2
= SfxLokHelper::getView();
1512 SfxViewShell
* pView2
= SfxViewShell::Current();
1513 CPPUNIT_ASSERT(pView1
!= pView2
);
1515 // both views have UNDO disabled
1517 SfxItemSet
aSet1(pView1
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1518 SfxItemSet
aSet2(pView2
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1519 pView1
->GetSlotState(SID_UNDO
, nullptr, &aSet1
);
1520 pView2
->GetSlotState(SID_UNDO
, nullptr, &aSet2
);
1521 CPPUNIT_ASSERT_EQUAL(SfxItemState::DISABLED
, aSet1
.GetItemState(SID_UNDO
));
1522 CPPUNIT_ASSERT_EQUAL(SfxItemState::DISABLED
, aSet2
.GetItemState(SID_UNDO
));
1525 // text edit a cell in view #1
1526 SfxLokHelper::setView(nView1
);
1527 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'h', 0);
1528 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'h', 0);
1529 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
1530 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
1531 Scheduler::ProcessEventsToIdle();
1532 // view1 has UNDO enabled, view2 is in UNDO-repair
1534 SfxItemSet
aSet1(pView1
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1535 SfxItemSet
aSet2(pView2
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1536 pView1
->GetSlotState(SID_UNDO
, nullptr, &aSet1
);
1537 pView2
->GetSlotState(SID_UNDO
, nullptr, &aSet2
);
1538 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet1
.GetItemState(SID_UNDO
));
1539 CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem
* >(aSet1
.GetItem(SID_UNDO
)));
1540 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet2
.GetItemState(SID_UNDO
));
1541 CPPUNIT_ASSERT(dynamic_cast< const SfxUInt32Item
* >(aSet2
.GetItem(SID_UNDO
)));
1542 const SfxUInt32Item
* pUInt32Item
= dynamic_cast<const SfxUInt32Item
*>(aSet2
.GetItem(SID_UNDO
));
1543 CPPUNIT_ASSERT(pUInt32Item
);
1544 CPPUNIT_ASSERT_EQUAL(static_cast< sal_uInt32
>(SID_REPAIRPACKAGE
), pUInt32Item
->GetValue());
1547 // text edit a cell in view #2
1548 SfxLokHelper::setView(nView2
);
1549 pModelObj
->setPart(1);
1550 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'c', 0);
1551 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'c', 0);
1552 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
1553 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
1554 // both views have UNDO enabled
1555 Scheduler::ProcessEventsToIdle();
1557 SfxItemSet
aSet1(pView1
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1558 SfxItemSet
aSet2(pView2
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1559 pView1
->GetSlotState(SID_UNDO
, nullptr, &aSet1
);
1560 pView2
->GetSlotState(SID_UNDO
, nullptr, &aSet2
);
1561 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet1
.GetItemState(SID_UNDO
));
1562 CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem
* >(aSet1
.GetItem(SID_UNDO
)));
1563 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet2
.GetItemState(SID_UNDO
));
1564 CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem
* >(aSet2
.GetItem(SID_UNDO
)));
1567 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1568 SfxLokHelper::setView(nView1
);
1569 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1572 void ScTiledRenderingTest::testDocumentRepair()
1574 // Create two views.
1575 ScModelObj
* pModelObj
= createDoc("cursor-away.ods");
1576 CPPUNIT_ASSERT(pModelObj
);
1579 SfxViewShell
* pView1
= SfxViewShell::Current();
1582 int nView1
= SfxLokHelper::getView();
1583 SfxLokHelper::createView();
1584 SfxViewShell
* pView2
= SfxViewShell::Current();
1585 int nView2
= SfxLokHelper::getView();
1586 CPPUNIT_ASSERT(pView1
!= pView2
);
1588 std::unique_ptr
<SfxBoolItem
> pItem1
;
1589 std::unique_ptr
<SfxBoolItem
> pItem2
;
1590 pView1
->GetViewFrame()->GetBindings().QueryState(SID_DOC_REPAIR
, pItem1
);
1591 pView2
->GetViewFrame()->GetBindings().QueryState(SID_DOC_REPAIR
, pItem2
);
1592 CPPUNIT_ASSERT(pItem1
);
1593 CPPUNIT_ASSERT(pItem2
);
1594 CPPUNIT_ASSERT_EQUAL(false, pItem1
->GetValue());
1595 CPPUNIT_ASSERT_EQUAL(false, pItem2
->GetValue());
1598 // Insert a character in the second view.
1599 SfxLokHelper::setView(nView2
);
1600 pModelObj
->setPart(1);
1601 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'c', 0);
1602 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'c', 0);
1603 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
1604 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
1605 Scheduler::ProcessEventsToIdle();
1607 std::unique_ptr
<SfxBoolItem
> pItem1
;
1608 std::unique_ptr
<SfxBoolItem
> pItem2
;
1609 pView1
->GetViewFrame()->GetBindings().QueryState(SID_DOC_REPAIR
, pItem1
);
1610 pView2
->GetViewFrame()->GetBindings().QueryState(SID_DOC_REPAIR
, pItem2
);
1611 CPPUNIT_ASSERT(pItem1
);
1612 CPPUNIT_ASSERT(pItem2
);
1613 CPPUNIT_ASSERT_EQUAL(true, pItem1
->GetValue());
1614 CPPUNIT_ASSERT_EQUAL(true, pItem2
->GetValue());
1617 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1618 SfxLokHelper::setView(nView1
);
1619 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1622 void ScTiledRenderingTest::testLanguageStatus()
1624 ScModelObj
* pModelObj
= createDoc("small.ods");
1625 CPPUNIT_ASSERT(pModelObj
);
1626 ScDocShell
* pDocSh
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
1627 CPPUNIT_ASSERT(pDocSh
);
1630 SfxViewShell
* pView1
= SfxViewShell::Current();
1633 int nView1
= SfxLokHelper::getView();
1634 SfxLokHelper::createView();
1635 SfxViewShell
* pView2
= SfxViewShell::Current();
1636 CPPUNIT_ASSERT(pView1
!= pView2
);
1638 std::unique_ptr
<SfxPoolItem
> xItem1
;
1639 std::unique_ptr
<SfxPoolItem
> xItem2
;
1640 pView1
->GetViewFrame()->GetBindings().QueryState(SID_LANGUAGE_STATUS
, xItem1
);
1641 pView2
->GetViewFrame()->GetBindings().QueryState(SID_LANGUAGE_STATUS
, xItem2
);
1642 const SfxStringItem
* pItem1
= dynamic_cast<const SfxStringItem
*>(xItem1
.get());
1643 const SfxStringItem
* pItem2
= dynamic_cast<const SfxStringItem
*>(xItem2
.get());
1644 CPPUNIT_ASSERT(pItem1
);
1645 CPPUNIT_ASSERT(pItem2
);
1646 CPPUNIT_ASSERT(!pItem1
->GetValue().isEmpty());
1647 CPPUNIT_ASSERT(!pItem2
->GetValue().isEmpty());
1651 SfxStringItem
aLangString(SID_LANGUAGE_STATUS
, "Default_Spanish (Bolivia)");
1652 pView1
->GetViewFrame()->GetDispatcher()->ExecuteList(SID_LANGUAGE_STATUS
,
1653 SfxCallMode::SYNCHRON
, { &aLangString
});
1657 std::unique_ptr
<SfxPoolItem
> xItem1
;
1658 std::unique_ptr
<SfxPoolItem
> xItem2
;
1659 pView1
->GetViewFrame()->GetBindings().QueryState(SID_LANGUAGE_STATUS
, xItem1
);
1660 pView2
->GetViewFrame()->GetBindings().QueryState(SID_LANGUAGE_STATUS
, xItem2
);
1661 const SfxStringItem
* pItem1
= dynamic_cast<const SfxStringItem
*>(xItem1
.get());
1662 const SfxStringItem
* pItem2
= dynamic_cast<const SfxStringItem
*>(xItem2
.get());
1663 CPPUNIT_ASSERT(pItem1
);
1664 CPPUNIT_ASSERT(pItem2
);
1665 const OUString
aLangBolivia("Spanish (Bolivia);es-BO");
1666 CPPUNIT_ASSERT_EQUAL(aLangBolivia
, pItem1
->GetValue());
1667 CPPUNIT_ASSERT_EQUAL(aLangBolivia
, pItem2
->GetValue());
1670 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1671 SfxLokHelper::setView(nView1
);
1672 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1675 void ScTiledRenderingTest::testMultiViewCopyPaste()
1677 ScModelObj
* pModelObj
= createDoc("empty.ods");
1678 ScDocument
* pDoc
= pModelObj
->GetDocument();
1679 CPPUNIT_ASSERT(pDoc
);
1681 pDoc
->SetString(ScAddress(0, 0, 0), "TestCopy1");
1682 pDoc
->SetString(ScAddress(1, 0, 0), "TestCopy2");
1685 ScTabViewShell
* pView1
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
1686 CPPUNIT_ASSERT(pView1
);
1687 // emulate clipboard
1688 pView1
->GetViewData().GetActiveWin()->SetClipboard(css::datatransfer::clipboard::SystemClipboard::create(comphelper::getProcessComponentContext()));
1691 int nView1
= SfxLokHelper::getView();
1692 SfxLokHelper::createView();
1693 ScTabViewShell
* pView2
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
1694 // emulate clipboard
1695 pView2
->GetViewData().GetActiveWin()->SetClipboard(css::datatransfer::clipboard::SystemClipboard::create(comphelper::getProcessComponentContext()));
1696 CPPUNIT_ASSERT(pView2
);
1697 CPPUNIT_ASSERT(pView1
!= pView2
);
1698 CPPUNIT_ASSERT(pView1
->GetViewData().GetActiveWin()->GetClipboard() != pView2
->GetViewData().GetActiveWin()->GetClipboard());
1701 pView1
->SetCursor(0, 0);
1702 pView1
->GetViewFrame()->GetBindings().Execute(SID_COPY
);
1705 pView2
->SetCursor(1, 0);
1706 pView2
->GetViewFrame()->GetBindings().Execute(SID_COPY
);
1708 // paste text view 1
1709 pView1
->SetCursor(0, 1);
1710 pView1
->GetViewFrame()->GetBindings().Execute(SID_PASTE
);
1712 // paste text view 2
1713 pView2
->SetCursor(1, 1);
1714 pView2
->GetViewFrame()->GetBindings().Execute(SID_PASTE
);
1716 CPPUNIT_ASSERT_EQUAL(OUString("TestCopy1"), pDoc
->GetString(ScAddress(0, 1, 0)));
1717 CPPUNIT_ASSERT_EQUAL(OUString("TestCopy2"), pDoc
->GetString(ScAddress(1, 1, 0)));
1719 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1720 SfxLokHelper::setView(nView1
);
1721 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1724 void ScTiledRenderingTest::testIMESupport()
1726 ScModelObj
* pModelObj
= createDoc("empty.ods");
1727 VclPtr
<vcl::Window
> pDocWindow
= pModelObj
->getDocWindow();
1728 ScDocument
* pDoc
= pModelObj
->GetDocument();
1730 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
1731 CPPUNIT_ASSERT(pView
);
1733 pView
->SetCursor(0, 0);
1734 // sequence of chinese IME compositions when 'nihao' is typed in an IME
1735 const std::vector
<OString
> aUtf8Inputs
{ "å¹´", "ä½ ", "ä½ å¥½", "ä½ å“ˆ", "ä½ å¥½", "ä½ å¥½" };
1736 std::vector
<OUString
> aInputs
;
1737 std::transform(aUtf8Inputs
.begin(), aUtf8Inputs
.end(),
1738 std::back_inserter(aInputs
), [](OString aInput
) {
1739 return OUString::fromUtf8(aInput
);
1741 for (const auto& aInput
: aInputs
)
1743 pDocWindow
->PostExtTextInputEvent(VclEventId::ExtTextInput
, aInput
);
1745 pDocWindow
->PostExtTextInputEvent(VclEventId::EndExtTextInput
, "");
1747 // commit the string to the cell
1748 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
1749 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
1750 Scheduler::ProcessEventsToIdle();
1752 CPPUNIT_ASSERT_EQUAL(aInputs
[aInputs
.size() - 1], pDoc
->GetString(ScAddress(0, 0, 0)));
1755 void ScTiledRenderingTest::testFilterDlg()
1757 createDoc("empty.ods");
1760 SfxViewShell
* pView1
= SfxViewShell::Current();
1761 int nView1
= SfxLokHelper::getView();
1764 SfxLokHelper::createView();
1765 SfxViewShell
* pView2
= SfxViewShell::Current();
1766 CPPUNIT_ASSERT(pView1
!= pView2
);
1768 pView2
->GetViewFrame()->GetDispatcher()->Execute(SID_FILTER
,
1769 SfxCallMode::SLOT
|SfxCallMode::RECORD
);
1772 Scheduler::ProcessEventsToIdle();
1773 SfxChildWindow
* pRefWindow
= pView2
->GetViewFrame()->GetChildWindow(SID_FILTER
);
1774 CPPUNIT_ASSERT(pRefWindow
);
1777 SfxLokHelper::setView(nView1
);
1778 CPPUNIT_ASSERT_EQUAL(true, pView2
->GetViewFrame()->GetDispatcher()->IsLocked());
1779 CPPUNIT_ASSERT_EQUAL(false, pView1
->GetViewFrame()->GetDispatcher()->IsLocked());
1781 pRefWindow
->GetController()->response(RET_CANCEL
);
1783 CPPUNIT_ASSERT_EQUAL(false, pView2
->GetViewFrame()->GetDispatcher()->IsLocked());
1784 CPPUNIT_ASSERT_EQUAL(false, pView1
->GetViewFrame()->GetDispatcher()->IsLocked());
1786 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1787 SfxLokHelper::setView(nView1
);
1788 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1791 void ScTiledRenderingTest::testFunctionDlg()
1793 createDoc("empty.ods");
1796 SfxViewShell
* pView1
= SfxViewShell::Current();
1797 int nView1
= SfxLokHelper::getView();
1799 pView1
->GetViewFrame()->GetDispatcher()->Execute(SID_OPENDLG_FUNCTION
,
1800 SfxCallMode::SLOT
|SfxCallMode::RECORD
);
1802 Scheduler::ProcessEventsToIdle();
1803 SfxChildWindow
* pRefWindow
= pView1
->GetViewFrame()->GetChildWindow(SID_OPENDLG_FUNCTION
);
1804 CPPUNIT_ASSERT(pRefWindow
);
1807 int nView2
= SfxLokHelper::createView();
1808 SfxViewShell
* pView2
= SfxViewShell::Current();
1809 CPPUNIT_ASSERT(pView1
!= pView2
);
1812 CPPUNIT_ASSERT_EQUAL(true, pView1
->GetViewFrame()->GetDispatcher()->IsLocked());
1813 CPPUNIT_ASSERT_EQUAL(false, pView2
->GetViewFrame()->GetDispatcher()->IsLocked());
1815 SfxLokHelper::setView(nView1
);
1816 pRefWindow
->GetController()->response(RET_CANCEL
);
1818 CPPUNIT_ASSERT_EQUAL(false, pView1
->GetViewFrame()->GetDispatcher()->IsLocked());
1819 CPPUNIT_ASSERT_EQUAL(false, pView2
->GetViewFrame()->GetDispatcher()->IsLocked());
1821 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1822 SfxLokHelper::setView(nView2
);
1823 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1826 void ScTiledRenderingTest::testSpellOnlineParameter()
1828 ScModelObj
* pModelObj
= createDoc("empty.ods");
1829 ScDocument
* pDoc
= pModelObj
->GetDocument();
1830 bool bSet
= pDoc
->GetDocOptions().IsAutoSpell();
1832 uno::Sequence
<beans::PropertyValue
> params
=
1834 comphelper::makePropertyValue("Enable", uno::Any(!bSet
)),
1836 dispatchCommand(mxComponent
, ".uno:SpellOnline", params
);
1837 CPPUNIT_ASSERT_EQUAL(!bSet
, pDoc
->GetDocOptions().IsAutoSpell());
1839 // set the same state as now and we don't expect any change (no-toggle)
1842 comphelper::makePropertyValue("Enable", uno::Any(!bSet
)),
1844 dispatchCommand(mxComponent
, ".uno:SpellOnline", params
);
1845 CPPUNIT_ASSERT_EQUAL(!bSet
, pDoc
->GetDocOptions().IsAutoSpell());
1848 void ScTiledRenderingTest::testVbaRangeCopyPaste()
1850 ScModelObj
* pModelObj
= createDoc("RangeCopyPaste.ods");
1851 ScDocShell
* pDocShell
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
1852 CPPUNIT_ASSERT(pDocShell
);
1855 uno::Sequence
< uno::Any
> aOutParam
;
1856 uno::Sequence
< uno::Any
> aParams
;
1857 uno::Sequence
< sal_Int16
> aOutParamIndex
;
1859 SfxObjectShell::CallXScript(
1861 "vnd.sun.Star.script:Standard.Module1.Test_RangeCopyPaste?language=Basic&location=document",
1862 aParams
, aRet
, aOutParamIndex
, aOutParam
);
1864 CPPUNIT_ASSERT(!pDocShell
->GetClipData().is());
1867 void ScTiledRenderingTest::testInvalidationLoop()
1869 // Load the document with a form control.
1870 createDoc("invalidation-loop.fods");
1871 // Without the accompanying fix in place, this test would have never returned due to an infinite
1872 // invalidation loop between ScGridWindow::Paint() and vcl::Window::ImplPosSizeWindow().
1873 Scheduler::ProcessEventsToIdle();
1876 void ScTiledRenderingTest::testPageDownInvalidation()
1878 ScModelObj
* pModelObj
= createDoc("empty.ods");
1879 ScViewData
* pViewData
= ScDocShell::GetViewData();
1880 CPPUNIT_ASSERT(pViewData
);
1882 int nView1
= SfxLokHelper::getView();
1883 ViewCallback aView1
;
1884 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
1886 SfxLokHelper::setView(nView1
);
1887 aView1
.m_bInvalidateTiles
= false;
1888 aView1
.m_aInvalidations
.clear();
1889 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, awt::Key::PAGEDOWN
, 0);
1890 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, awt::Key::PAGEDOWN
, 0);
1891 Scheduler::ProcessEventsToIdle();
1892 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
1893 CPPUNIT_ASSERT_EQUAL(size_t(3), aView1
.m_aInvalidations
.size());
1894 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(15, 15, 1230, 225), aView1
.m_aInvalidations
[0]);
1897 void ScTiledRenderingTest::testSheetChangeInvalidation()
1899 const bool oldPartInInvalidation
= comphelper::LibreOfficeKit::isPartInInvalidation();
1900 comphelper::LibreOfficeKit::setPartInInvalidation(true);
1902 ScModelObj
* pModelObj
= createDoc("two_sheets.ods");
1903 ScDocument
* pDoc
= pModelObj
->GetDocument();
1904 ScViewData
* pViewData
= ScDocShell::GetViewData();
1905 CPPUNIT_ASSERT(pViewData
);
1907 int nView1
= SfxLokHelper::getView();
1908 ViewCallback aView1
;
1909 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
1911 SfxLokHelper::setView(nView1
);
1912 aView1
.m_bInvalidateTiles
= false;
1913 aView1
.m_aInvalidations
.clear();
1914 aView1
.m_aInvalidationsParts
.clear();
1915 aView1
.m_aInvalidationsMode
.clear();
1916 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
1917 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
1918 Scheduler::ProcessEventsToIdle();
1919 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
1920 CPPUNIT_ASSERT_EQUAL(size_t(2), aView1
.m_aInvalidations
.size());
1921 const ScSheetLimits
& rLimits
= pDoc
->GetSheetLimits();
1922 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(0, 0, 1280 * rLimits
.GetMaxColCount(),
1923 256 * rLimits
.GetMaxRowCount()),
1924 aView1
.m_aInvalidations
[0]);
1925 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(0, 0, 1000000000, 1000000000), aView1
.m_aInvalidations
[1]);
1926 CPPUNIT_ASSERT_EQUAL(size_t(2), aView1
.m_aInvalidationsParts
.size());
1927 CPPUNIT_ASSERT_EQUAL(pModelObj
->getPart(), aView1
.m_aInvalidationsParts
[0]);
1928 CPPUNIT_ASSERT_EQUAL(pModelObj
->getPart(), aView1
.m_aInvalidationsParts
[1]);
1929 CPPUNIT_ASSERT_EQUAL(size_t(2), aView1
.m_aInvalidationsMode
.size());
1930 CPPUNIT_ASSERT_EQUAL(pModelObj
->getEditMode(), aView1
.m_aInvalidationsMode
[0]);
1931 CPPUNIT_ASSERT_EQUAL(pModelObj
->getEditMode(), aView1
.m_aInvalidationsMode
[1]);
1932 comphelper::LibreOfficeKit::setPartInInvalidation(oldPartInInvalidation
);
1935 void ScTiledRenderingTest::testInsertDeletePageInvalidation()
1937 ScModelObj
* pModelObj
= createDoc("insert_delete_sheet.ods");
1938 // the document has 1 sheet
1939 CPPUNIT_ASSERT_EQUAL(1, pModelObj
->getParts());
1940 ScViewData
* pViewData
= ScDocShell::GetViewData();
1941 CPPUNIT_ASSERT(pViewData
);
1943 int nView1
= SfxLokHelper::getView();
1944 ViewCallback aView1
;
1945 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
1947 SfxLokHelper::setView(nView1
);
1948 aView1
.m_bInvalidateTiles
= false;
1949 aView1
.m_aInvalidations
.clear();
1951 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
1952 { "Name", uno::Any(OUString("")) },
1953 { "Index", uno::Any(sal_Int32(1)) }
1955 comphelper::dispatchCommand(".uno:Insert", aArgs
);
1956 Scheduler::ProcessEventsToIdle();
1957 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
1958 CPPUNIT_ASSERT_EQUAL(size_t(6), aView1
.m_aInvalidations
.size());
1959 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(0, 0, 1000000000, 1000000000), aView1
.m_aInvalidations
[0]);
1960 CPPUNIT_ASSERT_EQUAL(2, pModelObj
->getParts());
1963 aView1
.m_bInvalidateTiles
= false;
1964 aView1
.m_aInvalidations
.clear();
1965 uno::Sequence
<beans::PropertyValue
> aArgs2( comphelper::InitPropertySequence({
1966 { "Index", uno::Any(sal_Int32(1)) }
1968 comphelper::dispatchCommand(".uno:Remove", aArgs2
);
1969 Scheduler::ProcessEventsToIdle();
1970 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
1971 CPPUNIT_ASSERT_EQUAL(size_t(5), aView1
.m_aInvalidations
.size());
1972 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(0, 0, 1000000000, 1000000000), aView1
.m_aInvalidations
[0]);
1973 CPPUNIT_ASSERT_EQUAL(1, pModelObj
->getParts());
1976 void ScTiledRenderingTest::testGetRowColumnHeadersInvalidation()
1978 ScModelObj
* pModelObj
= createDoc("empty.ods");
1979 ScViewData
* pViewData
= ScDocShell::GetViewData();
1980 CPPUNIT_ASSERT(pViewData
);
1982 int nView1
= SfxLokHelper::getView();
1983 ViewCallback aView1
;
1984 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
1986 SfxLokHelper::setView(nView1
);
1987 aView1
.m_bInvalidateTiles
= false;
1988 aView1
.m_aInvalidations
.clear();
1989 tools::JsonWriter aJsonWriter1
;
1990 pModelObj
->getRowColumnHeaders(tools::Rectangle(0, 15, 19650, 5400), aJsonWriter1
);
1991 free(aJsonWriter1
.extractData());
1992 Scheduler::ProcessEventsToIdle();
1993 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
1994 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
1995 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(26775, 0, 49725, 13005), aView1
.m_aInvalidations
[0]);
1997 // Extend area top-to-bottom
1998 aView1
.m_bInvalidateTiles
= false;
1999 aView1
.m_aInvalidations
.clear();
2000 tools::JsonWriter aJsonWriter2
;
2001 pModelObj
->getRowColumnHeaders(tools::Rectangle(0, 5400, 19650, 9800), aJsonWriter2
);
2002 free(aJsonWriter2
.extractData());
2003 Scheduler::ProcessEventsToIdle();
2004 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
2005 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
2006 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(0, 13005, 49725, 19380), aView1
.m_aInvalidations
[0]);
2008 // Extend area left-to-right
2009 aView1
.m_bInvalidateTiles
= false;
2010 aView1
.m_aInvalidations
.clear();
2011 tools::JsonWriter aJsonWriter3
;
2012 pModelObj
->getRowColumnHeaders(tools::Rectangle(5400, 5400, 25050, 9800), aJsonWriter3
);
2013 free(aJsonWriter3
.extractData());
2014 Scheduler::ProcessEventsToIdle();
2015 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
2016 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
2017 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(49725, 0, 75225, 19380), aView1
.m_aInvalidations
[0]);
2020 void ScTiledRenderingTest::testJumpHorizontallyInvalidation()
2022 ScModelObj
* pModelObj
= createDoc("empty.ods");
2023 ScViewData
* pViewData
= ScDocShell::GetViewData();
2024 CPPUNIT_ASSERT(pViewData
);
2026 int nView1
= SfxLokHelper::getView();
2027 ViewCallback aView1
;
2028 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
2030 SfxLokHelper::setView(nView1
);
2031 aView1
.m_bInvalidateTiles
= false;
2032 aView1
.m_aInvalidations
.clear();
2033 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
| KEY_MOD2
);
2034 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
| KEY_MOD2
);
2035 Scheduler::ProcessEventsToIdle();
2036 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
| KEY_MOD2
);
2037 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
| KEY_MOD2
);
2038 Scheduler::ProcessEventsToIdle();
2039 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
2040 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
2041 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(26775, 0, 39525, 13005), aView1
.m_aInvalidations
[0]);
2044 void ScTiledRenderingTest::testJumpToLastRowInvalidation()
2046 ScModelObj
* pModelObj
= createDoc("empty.ods");
2047 ScViewData
* pViewData
= ScDocShell::GetViewData();
2048 CPPUNIT_ASSERT(pViewData
);
2050 int nView1
= SfxLokHelper::getView();
2051 ViewCallback aView1
;
2052 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
2054 SfxLokHelper::setView(nView1
);
2055 aView1
.m_bInvalidateTiles
= false;
2056 aView1
.m_aInvalidations
.clear();
2057 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DOWN
| KEY_MOD1
);
2058 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DOWN
| KEY_MOD1
);
2059 Scheduler::ProcessEventsToIdle();
2060 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
2061 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
2062 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(0, 13005, 26775, 267386880), aView1
.m_aInvalidations
[0]);
2065 // We need to ensure that views are not perterbed by rendering (!?) hmm ...
2066 void ScTiledRenderingTest::testRowColumnHeaders()
2068 ScModelObj
* pModelObj
= createDoc("empty.ods");
2069 ScViewData
* pViewData
= ScDocShell::GetViewData();
2070 CPPUNIT_ASSERT(pViewData
);
2073 ViewCallback aView1
;
2074 int nView1
= SfxLokHelper::getView();
2075 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
2078 SfxLokHelper::createView();
2079 int nView2
= SfxLokHelper::getView();
2080 ViewCallback aView2
;
2081 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
2083 // ViewRowColumnHeaders test
2084 SfxLokHelper::setView(nView1
);
2085 tools::JsonWriter aJsonWriter1
;
2086 pModelObj
->getRowColumnHeaders(tools::Rectangle(65,723,10410,4695), aJsonWriter1
);
2087 OString aHeaders1
= aJsonWriter1
.extractAsOString();
2089 SfxLokHelper::setView(nView2
);
2091 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 22474, 47333));
2092 pModelObj
->setClientZoom(256, 256, 6636, 6636);
2093 tools::JsonWriter aJsonWriter2
;
2094 pModelObj
->getRowColumnHeaders(tools::Rectangle(65,723,10410,4695), aJsonWriter2
);
2095 OString aHeaders2
= aJsonWriter2
.extractAsOString();
2097 // Check vs. view #1
2098 SfxLokHelper::setView(nView1
);
2099 tools::JsonWriter aJsonWriter3
;
2100 pModelObj
->getRowColumnHeaders(tools::Rectangle(65,723,10410,4695), aJsonWriter3
);
2101 OString aHeaders1_2
= aJsonWriter3
.extractAsOString();
2102 CPPUNIT_ASSERT_EQUAL(aHeaders1
, aHeaders1_2
);
2104 // Check vs. view #2
2105 SfxLokHelper::setView(nView2
);
2106 tools::JsonWriter aJsonWriter4
;
2107 pModelObj
->getRowColumnHeaders(tools::Rectangle(65,723,10410,4695), aJsonWriter4
);
2108 OString aHeaders2_2
= aJsonWriter4
.extractAsOString();
2109 CPPUNIT_ASSERT_EQUAL(aHeaders2
, aHeaders2_2
);
2111 SfxLokHelper::setView(nView1
);
2112 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2113 SfxLokHelper::setView(nView2
);
2114 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2117 // Helper structs for setup and testing of ScModelObj::getSheetGeometryData()
2126 typedef std::vector
<SpanEntry
> SpanList
;
2130 // TODO: Add group info too to test.
2132 void setDataToDoc(ScDocument
* pDoc
, bool bCol
) const
2134 SCCOLROW nStart
= 0;
2136 for (const auto& rSpan
: aSizes
)
2140 for (SCCOLROW nIdx
= nStart
; nIdx
<= rSpan
.nEnd
; ++nIdx
)
2141 pDoc
->SetColWidthOnly(nIdx
, 0, rSpan
.nVal
);
2144 pDoc
->SetRowHeightOnly(nStart
, rSpan
.nEnd
, 0, rSpan
.nVal
);
2146 nStart
= rSpan
.nEnd
+ 1;
2151 for (const auto& rSpan
: aHidden
)
2154 pDoc
->SetColHidden(nStart
, rSpan
.nEnd
, 0, !!rSpan
.nVal
);
2156 pDoc
->SetRowHidden(nStart
, rSpan
.nEnd
, 0, !!rSpan
.nVal
);
2158 nStart
= rSpan
.nEnd
+ 1;
2161 // There is no ScDocument interface to set ScTable::mpFilteredCols
2162 // It seems ScTable::mpFilteredCols is not really used !?
2168 for (const auto& rSpan
: aFiltered
)
2170 pDoc
->SetRowFiltered(nStart
, rSpan
.nEnd
, 0, !!rSpan
.nVal
);
2171 nStart
= rSpan
.nEnd
+ 1;
2175 void testPropertyTree(const boost::property_tree::ptree
& rTree
, bool bCol
) const
2177 struct SpanListWithKey
2180 const SpanList
& rSpanList
;
2183 const SpanListWithKey aPairList
[] = {
2184 { "sizes", aSizes
},
2185 { "hidden", aHidden
},
2186 { "filtered", aFiltered
}
2189 for (const auto& rEntry
: aPairList
)
2191 // There is no ScDocument interface to set ScTable::mpFilteredCols
2192 // It seems ScTable::mpFilteredCols is not really used !?
2193 if (bCol
&& rEntry
.aKey
== "filtered")
2196 bool bBooleanValue
= rEntry
.aKey
!= "sizes";
2197 OString aExpectedEncoding
;
2199 for (const auto& rSpan
: rEntry
.rSpanList
)
2201 size_t nVal
= rSpan
.nVal
;
2202 if (bBooleanValue
&& bFirst
)
2203 nVal
= static_cast<size_t>(!!nVal
);
2204 if (!bBooleanValue
|| bFirst
)
2205 aExpectedEncoding
+= OString::number(nVal
) + ":";
2206 aExpectedEncoding
+= OString::number(rSpan
.nEnd
) + " ";
2210 // Get the tree's value for the property key ("sizes"/"hidden"/"filtered").
2211 OString aTreeValue
= rTree
.get
<std::string
>(rEntry
.aKey
.getStr()).c_str();
2213 CPPUNIT_ASSERT_EQUAL(aExpectedEncoding
, aTreeValue
);
2218 class SheetGeometryData
2225 SheetGeometryData(const SheetDimData
& rCols
, const SheetDimData
& rRows
) :
2226 aCols(rCols
), aRows(rRows
)
2229 void setDataToDoc(ScDocument
* pDoc
) const
2231 aCols
.setDataToDoc(pDoc
, true);
2232 aRows
.setDataToDoc(pDoc
, false);
2235 void parseTest(const OString
& rJSON
) const
2237 // Assumes all flags passed to getSheetGeometryData() are true.
2238 boost::property_tree::ptree aTree
;
2239 std::stringstream
aStream(rJSON
.getStr());
2240 boost::property_tree::read_json(aStream
, aTree
);
2242 CPPUNIT_ASSERT_EQUAL(OString(".uno:SheetGeometryData"), OString(aTree
.get
<std::string
>("commandName").c_str()));
2244 aCols
.testPropertyTree(aTree
.get_child("columns"), true);
2245 aRows
.testPropertyTree(aTree
.get_child("rows"), false);
2249 // getSheetGeometryData() should return the exact same message
2250 // irrespective of client zoom and view-area. Switching views
2251 // should also not alter it.
2252 void ScTiledRenderingTest::testSheetGeometryDataInvariance()
2254 ScModelObj
* pModelObj
= createDoc("empty.ods");
2255 ScDocument
* pDoc
= pModelObj
->GetDocument();
2256 const SheetGeometryData
aSGData(
2261 { STD_COL_WIDTH
, 20 },
2262 { 2*STD_COL_WIDTH
, 26 },
2263 { STD_COL_WIDTH
, pDoc
->MaxCol() }
2270 { 0, pDoc
->MaxCol() }
2277 { 0, pDoc
->MaxCol() }
2287 { 300, pDoc
->MaxRow() }
2295 { 0, pDoc
->MaxRow() }
2302 { 0, pDoc
->MaxRow() }
2307 ScViewData
* pViewData
= ScDocShell::GetViewData();
2308 CPPUNIT_ASSERT(pViewData
);
2311 ViewCallback aView1
;
2312 int nView1
= SfxLokHelper::getView();
2315 SfxLokHelper::createView();
2316 int nView2
= SfxLokHelper::getView();
2317 ViewCallback aView2
;
2318 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
2320 // Try with the default empty document once (nIdx = 0) and then with sheet geometry settings (nIdx = 1)
2321 for (size_t nIdx
= 0; nIdx
< 2; ++nIdx
)
2324 aSGData
.setDataToDoc(pDoc
);
2326 SfxLokHelper::setView(nView1
);
2327 OString aGeomStr1
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
2328 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
2330 SfxLokHelper::setView(nView2
);
2331 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 22474, 47333));
2332 pModelObj
->setClientZoom(256, 256, 6636, 6636);
2333 OString aGeomStr2
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
2334 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
2336 // Check vs. view #1
2337 SfxLokHelper::setView(nView1
);
2338 OString aGeomStr1_2
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
2339 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
2340 CPPUNIT_ASSERT_EQUAL(aGeomStr1
, aGeomStr1_2
);
2342 // Check vs. view #2
2343 SfxLokHelper::setView(nView2
);
2344 OString aGeomStr2_2
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
2345 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
2346 CPPUNIT_ASSERT_EQUAL(aGeomStr2
, aGeomStr2_2
);
2349 SfxLokHelper::setView(nView1
);
2350 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2351 SfxLokHelper::setView(nView2
);
2352 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2355 void ScTiledRenderingTest::testSheetGeometryDataCorrectness()
2357 ScModelObj
* pModelObj
= createDoc("empty.ods");
2358 ScDocument
* pDoc
= pModelObj
->GetDocument();
2359 const SheetGeometryData
aDefaultSGData(
2363 { { STD_COL_WIDTH
, pDoc
->MaxCol() } },
2365 { { 0, pDoc
->MaxCol() } },
2367 { { 0, pDoc
->MaxCol() } }
2372 { { ScGlobal::nStdRowHeight
, pDoc
->MaxRow() } },
2374 { { 0, pDoc
->MaxRow() } },
2376 { { 0, pDoc
->MaxRow() } }
2380 const SheetGeometryData
aSGData(
2385 { STD_COL_WIDTH
, 20 },
2386 { 2*STD_COL_WIDTH
, 26 },
2387 { STD_COL_WIDTH
, pDoc
->MaxCol() }
2394 { 0, pDoc
->MaxCol() }
2401 { 0, pDoc
->MaxCol() }
2411 { 300, pDoc
->MaxRow() }
2419 { 0, pDoc
->MaxRow() }
2426 { 0, pDoc
->MaxRow() }
2431 ScViewData
* pViewData
= ScDocShell::GetViewData();
2432 CPPUNIT_ASSERT(pViewData
);
2435 ViewCallback aView1
;
2437 // with the default empty sheet and test the JSON encoding.
2438 OString aGeomDefaultStr
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
2439 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
2440 aDefaultSGData
.parseTest(aGeomDefaultStr
);
2442 // Apply geometry settings to the sheet and then test the resulting JSON encoding.
2443 aSGData
.setDataToDoc(pDoc
);
2444 OString aGeomStr
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
2445 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
2446 aSGData
.parseTest(aGeomStr
);
2448 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2451 void ScTiledRenderingTest::testDeleteCellMultilineContent()
2453 ScModelObj
* pModelObj
= createDoc("multiline.ods");
2454 CPPUNIT_ASSERT(pModelObj
);
2455 ScViewData
* pViewData
= ScDocShell::GetViewData();
2456 CPPUNIT_ASSERT(pViewData
);
2457 ScDocShell
* pDocSh
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
2458 CPPUNIT_ASSERT(pDocSh
);
2461 ViewCallback aView1
;
2462 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
2464 aView1
.m_sInvalidateHeader
= "";
2465 ScDocument
& rDoc
= pDocSh
->GetDocument();
2466 sal_uInt16 nRow1Height
= rDoc
.GetRowHeight(static_cast<SCROW
>(0), static_cast<SCTAB
>(0), false);
2468 // delete multiline cell content in view #1
2469 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DOWN
);
2470 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DOWN
);
2471 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DELETE
);
2472 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DELETE
);
2473 Scheduler::ProcessEventsToIdle();
2475 // check if the row header has been invalidated and if the involved row is of the expected height
2476 CPPUNIT_ASSERT_EQUAL(OString("row"), aView1
.m_sInvalidateHeader
);
2477 sal_uInt16 nRow2Height
= rDoc
.GetRowHeight(static_cast<SCROW
>(0), static_cast<SCTAB
>(0), false);
2478 CPPUNIT_ASSERT_EQUAL(nRow1Height
, nRow2Height
);
2479 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2482 void ScTiledRenderingTest::testPasteIntoWrapTextCell()
2484 comphelper::LibreOfficeKit::setCompatFlag(
2485 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
2487 ScModelObj
* pModelObj
= createDoc("empty.ods");
2488 CPPUNIT_ASSERT(pModelObj
);
2489 ScDocument
* pDoc
= pModelObj
->GetDocument();
2491 // Set Wrap text in A3
2492 pDoc
->ApplyAttr(0, 2, 0, ScLineBreakCell(true));
2493 const ScLineBreakCell
* pItem
= pDoc
->GetAttr(0, 2, 0, ATTR_LINEBREAK
);
2494 CPPUNIT_ASSERT(pItem
->GetValue());
2496 ScViewData
* pViewData
= ScDocShell::GetViewData();
2497 CPPUNIT_ASSERT(pViewData
);
2500 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
2502 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2503 CPPUNIT_ASSERT(pView
);
2505 // Go to A2 and paste.
2506 pView
->SetCursor(0, 1);
2507 Scheduler::ProcessEventsToIdle();
2508 aView
.m_sInvalidateSheetGeometry
= "";
2509 pView
->GetViewFrame()->GetBindings().Execute(SID_PASTE
);
2510 Scheduler::ProcessEventsToIdle();
2512 // No SG invalidations
2513 CPPUNIT_ASSERT_EQUAL(OString(""), aView
.m_sInvalidateSheetGeometry
);
2515 // Go to A3 and paste.
2516 pView
->SetCursor(0, 2);
2517 Scheduler::ProcessEventsToIdle();
2518 aView
.m_sInvalidateSheetGeometry
= "";
2519 pView
->GetViewFrame()->GetBindings().Execute(SID_PASTE
);
2520 Scheduler::ProcessEventsToIdle();
2522 // SG invalidations for all
2523 CPPUNIT_ASSERT_EQUAL(OString("all"), aView
.m_sInvalidateSheetGeometry
);
2525 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2528 void ScTiledRenderingTest::testSortAscendingDescending()
2530 comphelper::LibreOfficeKit::setCompatFlag(
2531 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
2532 ScModelObj
* pModelObj
= createDoc("sort-range.ods");
2533 ScDocument
* pDoc
= pModelObj
->GetDocument();
2537 // select the values in the first column
2538 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
, 551, 129, 1, MOUSE_LEFT
, 0);
2539 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEMOVE
, 820, 1336, 1, MOUSE_LEFT
, 0);
2540 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
, 820, 1359, 1, MOUSE_LEFT
, 0);
2541 Scheduler::ProcessEventsToIdle();
2542 aView
.m_sInvalidateSheetGeometry
= "";
2545 uno::Sequence
<beans::PropertyValue
> aArgs
;
2546 comphelper::dispatchCommand(".uno:SortAscending", aArgs
);
2548 // check it's sorted
2549 for (SCROW r
= 0; r
< 6; ++r
)
2551 CPPUNIT_ASSERT_EQUAL(double(r
+ 1), pDoc
->GetValue(ScAddress(0, r
, 0)));
2554 Scheduler::ProcessEventsToIdle();
2555 CPPUNIT_ASSERT_EQUAL(OString("rows"), aView
.m_sInvalidateSheetGeometry
);
2557 aView
.m_sInvalidateSheetGeometry
= "";
2559 comphelper::dispatchCommand(".uno:SortDescending", aArgs
);
2561 // check it's sorted
2562 for (SCROW r
= 0; r
< 6; ++r
)
2564 CPPUNIT_ASSERT_EQUAL(double(6 - r
), pDoc
->GetValue(ScAddress(0, r
, 0)));
2567 // nothing else was sorted
2568 CPPUNIT_ASSERT_EQUAL(double(1), pDoc
->GetValue(ScAddress(1, 0, 0)));
2569 CPPUNIT_ASSERT_EQUAL(double(3), pDoc
->GetValue(ScAddress(1, 1, 0)));
2570 CPPUNIT_ASSERT_EQUAL(double(2), pDoc
->GetValue(ScAddress(1, 2, 0)));
2572 Scheduler::ProcessEventsToIdle();
2573 CPPUNIT_ASSERT_EQUAL(OString("rows"), aView
.m_sInvalidateSheetGeometry
);
2576 void lcl_typeCharsInCell(const std::string
& aStr
, SCCOL nCol
, SCROW nRow
, ScTabViewShell
* pView
,
2577 ScModelObj
* pModelObj
, bool bInEdit
= false, bool bCommit
= true)
2580 pView
->SetCursor(nCol
, nRow
);
2582 for (const char& cChar
: aStr
)
2584 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, cChar
, 0);
2585 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, cChar
, 0);
2586 Scheduler::ProcessEventsToIdle();
2591 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
2592 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
2593 Scheduler::ProcessEventsToIdle();
2597 void ScTiledRenderingTest::testAutoInputStringBlock()
2599 ScModelObj
* pModelObj
= createDoc("empty.ods");
2600 CPPUNIT_ASSERT(pModelObj
);
2601 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2602 CPPUNIT_ASSERT(pView
);
2603 ScDocument
* pDoc
= pModelObj
->GetDocument();
2605 pDoc
->SetString(ScAddress(0, 3, 0), "ABC"); // A4
2606 pDoc
->SetString(ScAddress(0, 4, 0), "BAC"); // A5
2607 ScFieldEditEngine
& rEE
= pDoc
->GetEditEngine();
2609 pDoc
->SetEditText(ScAddress(0, 5, 0), rEE
.CreateTextObject()); // A6
2610 pDoc
->SetValue(ScAddress(0, 6, 0), 123);
2611 pDoc
->SetString(ScAddress(0, 7, 0), "ZZZ"); // A8
2613 ScAddress
aA1(0, 0, 0);
2614 lcl_typeCharsInCell("X", aA1
.Col(), aA1
.Row(), pView
, pModelObj
); // Type 'X' in A1
2615 CPPUNIT_ASSERT_EQUAL_MESSAGE("A1 should autocomplete", OUString("XYZ"), pDoc
->GetString(aA1
));
2617 ScAddress
aA3(0, 2, 0); // Adjacent to the string "superblock" A4:A8
2618 lcl_typeCharsInCell("X", aA3
.Col(), aA3
.Row(), pView
, pModelObj
); // Type 'X' in A3
2619 CPPUNIT_ASSERT_EQUAL_MESSAGE("A3 should autocomplete", OUString("XYZ"), pDoc
->GetString(aA3
));
2621 ScAddress
aA9(0, 8, 0); // Adjacent to the string "superblock" A4:A8
2622 lcl_typeCharsInCell("X", aA9
.Col(), aA9
.Row(), pView
, pModelObj
); // Type 'X' in A9
2623 CPPUNIT_ASSERT_EQUAL_MESSAGE("A9 should autocomplete", OUString("XYZ"), pDoc
->GetString(aA9
));
2625 ScAddress
aA11(0, 10, 0);
2626 lcl_typeCharsInCell("X", aA11
.Col(), aA11
.Row(), pView
, pModelObj
); // Type 'X' in A11
2627 CPPUNIT_ASSERT_EQUAL_MESSAGE("A11 should autocomplete", OUString("XYZ"), pDoc
->GetString(aA11
));
2630 void ScTiledRenderingTest::testAutoInputExactMatch()
2632 ScModelObj
* pModelObj
= createDoc("empty.ods");
2633 CPPUNIT_ASSERT(pModelObj
);
2634 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2635 CPPUNIT_ASSERT(pView
);
2636 ScDocument
* pDoc
= pModelObj
->GetDocument();
2638 pDoc
->SetString(ScAddress(0, 1, 0), "Simple"); // A2
2639 pDoc
->SetString(ScAddress(0, 2, 0), "Simple"); // A3
2640 pDoc
->SetString(ScAddress(0, 3, 0), "Sing"); // A4
2641 ScFieldEditEngine
& rEE
= pDoc
->GetEditEngine();
2642 rEE
.SetText("Case");
2643 pDoc
->SetEditText(ScAddress(0, 4, 0), rEE
.CreateTextObject()); // A5
2644 pDoc
->SetString(ScAddress(0, 5, 0), "Time"); // A6
2645 pDoc
->SetString(ScAddress(0, 6, 0), "Castle"); // A7
2647 ScAddress
aA8(0, 7, 0);
2648 lcl_typeCharsInCell("S", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "S" in A8
2649 // Should show the partial completion "i".
2650 CPPUNIT_ASSERT_EQUAL_MESSAGE("1: A8 should have partial completion Si", OUString("Si"), pDoc
->GetString(aA8
));
2652 lcl_typeCharsInCell("Si", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "Si" in A8
2653 // Should not show any suggestions.
2654 CPPUNIT_ASSERT_EQUAL_MESSAGE("2: A8 should not show suggestions", OUString("Si"), pDoc
->GetString(aA8
));
2656 lcl_typeCharsInCell("Sim", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "Sim" in A8
2657 // Should autocomplete to "Simple" which is the only match.
2658 CPPUNIT_ASSERT_EQUAL_MESSAGE("3: A8 should autocomplete", OUString("Simple"), pDoc
->GetString(aA8
));
2660 lcl_typeCharsInCell("Sin", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "Sin" in A8
2661 // Should autocomplete to "Sing" which is the only match.
2662 CPPUNIT_ASSERT_EQUAL_MESSAGE("4: A8 should autocomplete", OUString("Sing"), pDoc
->GetString(aA8
));
2664 lcl_typeCharsInCell("C", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "C" in A8
2665 // Should show the partial completion "as".
2666 CPPUNIT_ASSERT_EQUAL_MESSAGE("5: A8 should have partial completion Cas", OUString("Cas"), pDoc
->GetString(aA8
));
2668 lcl_typeCharsInCell("Cast", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "Cast" in A8
2669 // Should autocomplete to "Castle" which is the only match.
2670 CPPUNIT_ASSERT_EQUAL_MESSAGE("6: A8 should autocomplete", OUString("Castle"), pDoc
->GetString(aA8
));
2672 lcl_typeCharsInCell("T", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "T" in A8
2673 // Should autocomplete to "Time" which is the only match.
2674 CPPUNIT_ASSERT_EQUAL_MESSAGE("7: A8 should autocomplete", OUString("Time"), pDoc
->GetString(aA8
));
2677 void ScTiledRenderingTest::testEditCursorBounds()
2679 comphelper::LibreOfficeKit::setCompatFlag(
2680 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
2681 ScModelObj
* pModelObj
= createDoc("empty.ods");
2682 ScDocument
* pDoc
= pModelObj
->GetDocument();
2685 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2686 CPPUNIT_ASSERT(pView
);
2687 comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(true);
2690 pModelObj
->setClientZoom(256, 256, 2222, 2222);
2691 pModelObj
->setClientVisibleArea(tools::Rectangle(7725, 379832, 16240, 6449));
2692 Scheduler::ProcessEventsToIdle();
2694 constexpr SCCOL nCol
= 5;
2695 constexpr SCROW nRow
= 2048;
2696 pDoc
->SetValue(ScAddress(nCol
, nRow
, 0), 123);
2698 aView
.m_bOwnCursorInvalidated
= false;
2699 // Obtain the cell bounds via cursor.
2700 pView
->SetCursor(nCol
, nRow
);
2701 Scheduler::ProcessEventsToIdle();
2703 CPPUNIT_ASSERT(aView
.m_bOwnCursorInvalidated
);
2704 CPPUNIT_ASSERT(!aView
.m_aCellCursorBounds
.IsEmpty());
2705 tools::Rectangle
aCellBounds(aView
.m_aCellCursorBounds
);
2707 aView
.m_aInvalidateCursorResult
.clear();
2708 // Enter edit mode in the same cell.
2709 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::F2
);
2710 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::F2
);
2711 Scheduler::ProcessEventsToIdle();
2713 CPPUNIT_ASSERT(!aView
.m_aInvalidateCursorResult
.empty());
2714 CPPUNIT_ASSERT_MESSAGE("Edit cursor must be in cell bounds!",
2715 aCellBounds
.Contains(aView
.m_aInvalidateCursorResult
.getBounds()));
2717 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2720 void ScTiledRenderingTest::testTextSelectionBounds()
2722 comphelper::LibreOfficeKit::setCompatFlag(
2723 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
2724 ScModelObj
* pModelObj
= createDoc("empty.ods");
2725 ScDocument
* pDoc
= pModelObj
->GetDocument();
2728 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2729 CPPUNIT_ASSERT(pView
);
2730 comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(true);
2733 pModelObj
->setClientZoom(256, 256, 2222, 2222);
2734 pModelObj
->setClientVisibleArea(tools::Rectangle(7725, 379832, 16240, 6449));
2735 Scheduler::ProcessEventsToIdle();
2737 constexpr SCCOL nCol
= 5;
2738 constexpr SCROW nRow
= 2048;
2739 pDoc
->SetValue(ScAddress(nCol
, nRow
, 0), 123);
2741 aView
.m_bOwnCursorInvalidated
= false;
2742 // Obtain the cell bounds via cursor.
2743 pView
->SetCursor(nCol
, nRow
);
2744 Scheduler::ProcessEventsToIdle();
2746 CPPUNIT_ASSERT(aView
.m_bOwnCursorInvalidated
);
2747 CPPUNIT_ASSERT(!aView
.m_aCellCursorBounds
.IsEmpty());
2748 tools::Rectangle
aCellBounds(aView
.m_aCellCursorBounds
);
2750 aView
.m_aTextSelectionResult
.clear();
2751 // Enter edit mode in the same cell and select all text.
2752 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::F2
);
2753 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::F2
);
2754 Scheduler::ProcessEventsToIdle();
2757 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_MOD1
| awt::Key::A
);
2758 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_MOD1
| awt::Key::A
);
2759 Scheduler::ProcessEventsToIdle();
2761 CPPUNIT_ASSERT(!aView
.m_aTextSelectionResult
.empty());
2762 CPPUNIT_ASSERT_MESSAGE("Text selections must be in cell bounds!",
2763 !aCellBounds
.Intersection(aView
.m_aTextSelectionResult
.getBounds(0)).IsEmpty());
2765 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2768 void ScTiledRenderingTest::testSheetViewDataCrash()
2770 ScModelObj
* pModelObj
= createDoc("empty.ods");
2773 int nView1
= SfxLokHelper::getView();
2774 SfxLokHelper::setView(nView1
);
2776 // Imitate online while creating a new sheet on empty.ods.
2777 uno::Sequence
<beans::PropertyValue
> aArgs(
2778 comphelper::InitPropertySequence({
2779 { "Name", uno::Any(OUString("NewSheet")) },
2780 { "Index", uno::Any(sal_Int32(2)) }
2782 comphelper::dispatchCommand(".uno:Insert", aArgs
);
2783 Scheduler::ProcessEventsToIdle();
2784 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
2785 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
2786 Scheduler::ProcessEventsToIdle();
2787 ScTabViewShell
* pView1
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2788 CPPUNIT_ASSERT(pView1
);
2791 SfxLokHelper::createView();
2792 ScTabViewShell
* pView2
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2793 CPPUNIT_ASSERT(pView2
);
2794 Scheduler::ProcessEventsToIdle();
2796 SfxLokHelper::setView(nView1
);
2798 pView1
->SetCursor(1, 1);
2799 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DOWN
| KEY_SHIFT
);
2800 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DOWN
| KEY_SHIFT
);
2801 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DELETE
);
2802 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DELETE
);
2803 // It will crash at this point without the fix.
2804 Scheduler::ProcessEventsToIdle();
2807 void ScTiledRenderingTest::testTextBoxInsert()
2809 createDoc("empty.ods");
2810 ViewCallback aView1
;
2813 uno::Sequence
<beans::PropertyValue
> aArgs(
2814 comphelper::InitPropertySequence({
2815 { "CreateDirectly", uno::Any(true) }
2817 comphelper::dispatchCommand(".uno:DrawText", aArgs
);
2818 Scheduler::ProcessEventsToIdle();
2820 // check if we have textbox selected
2821 CPPUNIT_ASSERT(!aView1
.m_ShapeSelection
.isEmpty());
2822 CPPUNIT_ASSERT(aView1
.m_ShapeSelection
!= "EMPTY");
2824 Scheduler::ProcessEventsToIdle();
2827 void ScTiledRenderingTest::testCommentCellCopyPaste()
2829 // Comments callback are emitted only if tiled annotations are off
2830 comphelper::LibreOfficeKit::setTiledAnnotations(false);
2832 // FIXME: Hack because previous tests do not destroy ScDocument(with annotations) on exit (?).
2833 ScPostIt::mnLastPostItId
= 1;
2836 ScModelObj
* pModelObj
= createDoc("empty.ods");
2838 int nView
= SfxLokHelper::getView();
2840 SfxLokHelper::setView(nView
);
2842 ScTabViewShell
* pTabViewShell
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2843 CPPUNIT_ASSERT(pTabViewShell
);
2845 lcl_typeCharsInCell("ABC", 0, 0, pTabViewShell
, pModelObj
); // Type "ABC" in A1
2847 pTabViewShell
->SetCursor(1, 1);
2849 // Add a new comment
2850 uno::Sequence
<beans::PropertyValue
> aArgs(comphelper::InitPropertySequence(
2852 {"Text", uno::Any(OUString("LOK Comment Cell B2"))},
2853 {"Author", uno::Any(OUString("LOK Client"))},
2855 comphelper::dispatchCommand(".uno:InsertAnnotation", aArgs
);
2856 Scheduler::ProcessEventsToIdle();
2858 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action
2859 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2860 CPPUNIT_ASSERT_EQUAL(std::string("1"), aView
.m_aCommentCallbackResult
.get
<std::string
>("id"));
2861 CPPUNIT_ASSERT_EQUAL(std::string("0"), aView
.m_aCommentCallbackResult
.get
<std::string
>("tab"));
2862 CPPUNIT_ASSERT_EQUAL(std::string("LOK Client"), aView
.m_aCommentCallbackResult
.get
<std::string
>("author"));
2863 CPPUNIT_ASSERT_EQUAL(std::string("LOK Comment Cell B2"), aView
.m_aCommentCallbackResult
.get
<std::string
>("text"));
2865 uno::Sequence
<beans::PropertyValue
> aCopyPasteArgs
;
2867 // We need separate tests for single cell copy-paste and cell-range copy-paste
2868 // since they hit different code paths in ScColumn methods.
2870 // Single cell(with comment) copy paste test
2872 comphelper::dispatchCommand(".uno:Copy", aCopyPasteArgs
);
2873 Scheduler::ProcessEventsToIdle();
2875 pTabViewShell
->SetCursor(1, 49);
2876 Scheduler::ProcessEventsToIdle();
2877 comphelper::dispatchCommand(".uno:Paste", aCopyPasteArgs
); // Paste to cell B50
2878 Scheduler::ProcessEventsToIdle();
2880 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action
2881 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2882 // Without the fix the id will be "1".
2883 CPPUNIT_ASSERT_EQUAL(std::string("2"), aView
.m_aCommentCallbackResult
.get
<std::string
>("id"));
2884 CPPUNIT_ASSERT_EQUAL(std::string("0"), aView
.m_aCommentCallbackResult
.get
<std::string
>("tab"));
2885 CPPUNIT_ASSERT_EQUAL(std::string("LOK Client"), aView
.m_aCommentCallbackResult
.get
<std::string
>("author"));
2886 CPPUNIT_ASSERT_EQUAL(std::string("LOK Comment Cell B2"), aView
.m_aCommentCallbackResult
.get
<std::string
>("text"));
2889 // Cell range (with a comment) copy paste test
2891 // Select range A1:C3
2892 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_HOME
| KEY_MOD1
);
2893 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_HOME
| KEY_MOD1
);
2894 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
| KEY_SHIFT
);
2895 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
| KEY_SHIFT
);
2896 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
| KEY_SHIFT
);
2897 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
| KEY_SHIFT
);
2898 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_RIGHT
| KEY_SHIFT
);
2899 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_RIGHT
| KEY_SHIFT
);
2900 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_RIGHT
| KEY_SHIFT
);
2901 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_RIGHT
| KEY_SHIFT
);
2902 Scheduler::ProcessEventsToIdle();
2904 comphelper::dispatchCommand(".uno:Copy", aCopyPasteArgs
);
2905 Scheduler::ProcessEventsToIdle();
2907 pTabViewShell
->SetCursor(3, 49);
2908 Scheduler::ProcessEventsToIdle();
2909 comphelper::dispatchCommand(".uno:Paste", aCopyPasteArgs
); // Paste to cell D50
2910 Scheduler::ProcessEventsToIdle();
2912 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action
2913 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2914 // Without the fix the id will be "1".
2915 CPPUNIT_ASSERT_EQUAL(std::string("3"), aView
.m_aCommentCallbackResult
.get
<std::string
>("id"));
2916 CPPUNIT_ASSERT_EQUAL(std::string("0"), aView
.m_aCommentCallbackResult
.get
<std::string
>("tab"));
2917 CPPUNIT_ASSERT_EQUAL(std::string("LOK Client"), aView
.m_aCommentCallbackResult
.get
<std::string
>("author"));
2918 CPPUNIT_ASSERT_EQUAL(std::string("LOK Comment Cell B2"), aView
.m_aCommentCallbackResult
.get
<std::string
>("text"));
2921 comphelper::LibreOfficeKit::setTiledAnnotations(true);
2924 void ScTiledRenderingTest::testInvalidEntrySave()
2926 loadFromURL(u
"validity.xlsx");
2928 // .uno:Save modifies the original file, make a copy first
2929 saveAndReload("Calc Office Open XML");
2930 ScModelObj
* pModelObj
= dynamic_cast<ScModelObj
*>(mxComponent
.get());
2931 CPPUNIT_ASSERT(pModelObj
);
2932 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
2933 const ScDocument
* pDoc
= pModelObj
->GetDocument();
2935 int nView
= SfxLokHelper::getView();
2937 SfxLokHelper::setView(nView
);
2939 ScDocShell
* pDocSh
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
2940 ScTabViewShell
* pTabViewShell
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2941 CPPUNIT_ASSERT(pTabViewShell
);
2943 // Type partial date "7/8" of "7/8/2013" that
2944 // the validation cell at A8 can accept
2945 lcl_typeCharsInCell("7/8", 0, 7, pTabViewShell
, pModelObj
,
2946 false /* bInEdit */, false /* bCommit */); // Type "7/8" in A8
2948 uno::Sequence
<beans::PropertyValue
> aArgs
;
2949 comphelper::dispatchCommand(".uno:Save", aArgs
);
2950 Scheduler::ProcessEventsToIdle();
2952 CPPUNIT_ASSERT_MESSAGE("Should not be marked modified after save", !pDocSh
->IsModified());
2954 // Complete the date in A8 by appending "/2013" and commit.
2955 lcl_typeCharsInCell("/2013", 0, 7, pTabViewShell
, pModelObj
,
2956 true /* bInEdit */, true /* bCommit */);
2958 // This would hang if the date entered "7/8/2013" is not acceptable.
2959 Scheduler::ProcessEventsToIdle();
2961 // Ensure that the correct date is recorded in the document.
2962 CPPUNIT_ASSERT_EQUAL(double(41463), pDoc
->GetValue(ScAddress(0, 7, 0)));
2965 void ScTiledRenderingTest::testUndoReordering()
2967 ScModelObj
* pModelObj
= createDoc("small.ods");
2968 CPPUNIT_ASSERT(pModelObj
);
2969 ScDocument
* pDoc
= pModelObj
->GetDocument();
2970 CPPUNIT_ASSERT(pDoc
);
2971 ScUndoManager
* pUndoManager
= pDoc
->GetUndoManager();
2972 CPPUNIT_ASSERT(pUndoManager
);
2975 int nView1
= SfxLokHelper::getView();
2976 ViewCallback aView1
;
2979 SfxLokHelper::createView();
2980 int nView2
= SfxLokHelper::getView();
2981 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
2982 ViewCallback aView2
;
2984 // text edit a cell in view #1
2985 SfxLokHelper::setView(nView1
);
2986 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
2987 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
2988 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
2989 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
2990 Scheduler::ProcessEventsToIdle();
2992 // check that undo action count is not 0
2993 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
2995 // text edit a different cell in view #2
2996 SfxLokHelper::setView(nView2
);
2997 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
);
2998 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
);
2999 Scheduler::ProcessEventsToIdle();
3000 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
);
3001 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
);
3002 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
3003 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
3004 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
3005 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
3006 Scheduler::ProcessEventsToIdle();
3008 // check that undo action count is not 1
3009 CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager
->GetUndoActionCount());
3011 // try to execute undo in view #1
3012 SfxLokHelper::setView(nView1
);
3013 comphelper::dispatchCommand(".uno:Undo", {});
3014 Scheduler::ProcessEventsToIdle();
3015 // check that undo has been executed on view #1
3016 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
3018 // try to execute undo in view #2
3019 SfxLokHelper::setView(nView2
);
3020 comphelper::dispatchCommand(".uno:Undo", {});
3021 Scheduler::ProcessEventsToIdle();
3022 // check that undo has been executed on view #2
3023 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetUndoActionCount());
3026 void ScTiledRenderingTest::testUndoReorderingRedo()
3028 ScModelObj
* pModelObj
= createDoc("empty.ods");
3029 CPPUNIT_ASSERT(pModelObj
);
3030 ScDocument
* pDoc
= pModelObj
->GetDocument();
3031 CPPUNIT_ASSERT(pDoc
);
3032 ScUndoManager
* pUndoManager
= pDoc
->GetUndoManager();
3033 CPPUNIT_ASSERT(pUndoManager
);
3034 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetUndoActionCount());
3037 int nView1
= SfxLokHelper::getView();
3038 SfxViewShell
* pView1
= SfxViewShell::Current();
3039 ViewCallback aView1
;
3042 SfxLokHelper::createView();
3043 int nView2
= SfxLokHelper::getView();
3044 SfxViewShell
* pView2
= SfxViewShell::Current();
3045 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
3046 ViewCallback aView2
;
3048 // text edit a cell in view #1
3049 SfxLokHelper::setView(nView1
);
3050 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
3051 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
3052 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
3053 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
3054 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
3055 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
3056 Scheduler::ProcessEventsToIdle();
3057 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
3059 // text edit another cell in view #1
3060 SfxLokHelper::setView(nView1
);
3061 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'y', 0);
3062 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'y', 0);
3063 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'y', 0);
3064 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'y', 0);
3065 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
3066 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
3067 Scheduler::ProcessEventsToIdle();
3068 CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager
->GetUndoActionCount());
3069 CPPUNIT_ASSERT_EQUAL(OUString("xx"), pDoc
->GetString(ScAddress(0, 0, 0)));
3070 CPPUNIT_ASSERT_EQUAL(OUString("yy"), pDoc
->GetString(ScAddress(0, 1, 0)));
3072 // text edit a different cell in view #2
3073 SfxLokHelper::setView(nView2
);
3074 ScTabViewShell
* pViewShell2
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
3075 pViewShell2
->SetCursor(0, 2);
3076 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'C', 0);
3077 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'C', 0);
3078 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'C', 0);
3079 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'C', 0);
3080 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
3081 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
3082 Scheduler::ProcessEventsToIdle();
3083 CPPUNIT_ASSERT_EQUAL(std::size_t(3), pUndoManager
->GetUndoActionCount());
3084 CPPUNIT_ASSERT_EQUAL(OUString("xx"), pDoc
->GetString(ScAddress(0, 0, 0)));
3085 CPPUNIT_ASSERT_EQUAL(OUString("yy"), pDoc
->GetString(ScAddress(0, 1, 0)));
3086 CPPUNIT_ASSERT_EQUAL(OUString("CC"), pDoc
->GetString(ScAddress(0, 2, 0)));
3088 // View 1 presses undo, and the second cell is erased
3089 SfxLokHelper::setView(nView1
);
3090 dispatchCommand(mxComponent
, ".uno:Undo", {});
3091 Scheduler::ProcessEventsToIdle();
3092 CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager
->GetUndoActionCount());
3093 CPPUNIT_ASSERT_EQUAL(OUString("xx"), pDoc
->GetString(ScAddress(0, 0, 0)));
3094 CPPUNIT_ASSERT_EQUAL(OUString(""), pDoc
->GetString(ScAddress(0, 1, 0)));
3095 CPPUNIT_ASSERT_EQUAL(OUString("CC"), pDoc
->GetString(ScAddress(0, 2, 0)));
3097 // Verify that the UNDO buttons/actions are still enabled
3099 SfxItemSet
aSet1(pView1
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
3100 SfxItemSet
aSet2(pView2
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
3101 pView1
->GetSlotState(SID_UNDO
, nullptr, &aSet1
);
3102 pView2
->GetSlotState(SID_UNDO
, nullptr, &aSet2
);
3103 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet1
.GetItemState(SID_UNDO
));
3104 CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem
* >(aSet1
.GetItem(SID_UNDO
)));
3105 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet2
.GetItemState(SID_UNDO
));
3106 CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem
* >(aSet2
.GetItem(SID_UNDO
)));
3109 // View 1 presses undo again, and the first cell is erased
3110 dispatchCommand(mxComponent
, ".uno:Undo", {});
3111 Scheduler::ProcessEventsToIdle();
3112 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
3113 CPPUNIT_ASSERT_EQUAL(OUString(""), pDoc
->GetString(ScAddress(0, 0, 0)));
3114 CPPUNIT_ASSERT_EQUAL(OUString(""), pDoc
->GetString(ScAddress(0, 1, 0)));
3115 CPPUNIT_ASSERT_EQUAL(OUString("CC"), pDoc
->GetString(ScAddress(0, 2, 0)));
3118 void ScTiledRenderingTest::testUndoReorderingMulti()
3120 ScModelObj
* pModelObj
= createDoc("empty.ods");
3121 CPPUNIT_ASSERT(pModelObj
);
3122 ScDocument
* pDoc
= pModelObj
->GetDocument();
3123 CPPUNIT_ASSERT(pDoc
);
3124 ScUndoManager
* pUndoManager
= pDoc
->GetUndoManager();
3125 CPPUNIT_ASSERT(pUndoManager
);
3126 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetUndoActionCount());
3129 int nView1
= SfxLokHelper::getView();
3130 ViewCallback aView1
;
3133 SfxLokHelper::createView();
3134 int nView2
= SfxLokHelper::getView();
3135 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
3136 ViewCallback aView2
;
3138 // text edit a cell in view #1
3139 SfxLokHelper::setView(nView1
);
3140 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
3141 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
3142 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
3143 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
3144 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
3145 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
3146 Scheduler::ProcessEventsToIdle();
3147 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
3149 // text edit a different cell in view #2
3150 SfxLokHelper::setView(nView2
);
3151 ScTabViewShell
* pView2
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
3152 pView2
->SetCursor(0, 2);
3153 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'C', 0);
3154 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'C', 0);
3155 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'C', 0);
3156 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'C', 0);
3157 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
3158 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
3159 Scheduler::ProcessEventsToIdle();
3160 CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager
->GetUndoActionCount());
3161 CPPUNIT_ASSERT_EQUAL(OUString("xx"), pDoc
->GetString(ScAddress(0, 0, 0)));
3162 CPPUNIT_ASSERT_EQUAL(OUString("CC"), pDoc
->GetString(ScAddress(0, 2, 0)));
3164 // and another cell in view #2
3165 pView2
->SetCursor(0, 3);
3166 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'D', 0);
3167 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'D', 0);
3168 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'D', 0);
3169 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'D', 0);
3170 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
3171 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
3172 Scheduler::ProcessEventsToIdle();
3173 CPPUNIT_ASSERT_EQUAL(std::size_t(3), pUndoManager
->GetUndoActionCount());
3174 CPPUNIT_ASSERT_EQUAL(OUString("xx"), pDoc
->GetString(ScAddress(0, 0, 0)));
3175 CPPUNIT_ASSERT_EQUAL(OUString("CC"), pDoc
->GetString(ScAddress(0, 2, 0)));
3176 CPPUNIT_ASSERT_EQUAL(OUString("DD"), pDoc
->GetString(ScAddress(0, 3, 0)));
3178 // View 1 presses undo
3179 SfxLokHelper::setView(nView1
);
3180 dispatchCommand(mxComponent
, ".uno:Undo", {});
3181 Scheduler::ProcessEventsToIdle();
3182 CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager
->GetUndoActionCount());
3183 CPPUNIT_ASSERT_EQUAL(OUString(""), pDoc
->GetString(ScAddress(0, 0, 0)));
3184 CPPUNIT_ASSERT_EQUAL(OUString("CC"), pDoc
->GetString(ScAddress(0, 2, 0)));
3185 CPPUNIT_ASSERT_EQUAL(OUString("DD"), pDoc
->GetString(ScAddress(0, 3, 0)));
3190 CPPUNIT_TEST_SUITE_REGISTRATION(ScTiledRenderingTest
);
3192 CPPUNIT_PLUGIN_IMPLEMENT();
3194 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */