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 <cppunit/tools/StringHelper.h>
13 #include <boost/property_tree/json_parser.hpp>
15 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
16 #include <com/sun/star/frame/Desktop.hpp>
17 #include <com/sun/star/frame/DispatchHelper.hpp>
18 #include <com/sun/star/datatransfer/clipboard/LokClipboard.hpp>
19 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
20 #include <comphelper/processfactory.hxx>
21 #include <comphelper/propertysequence.hxx>
22 #include <osl/conditn.hxx>
23 #include <sfx2/dispatch.hxx>
24 #include <sfx2/viewfrm.hxx>
25 #include <svl/stritem.hxx>
27 #include <comphelper/lok.hxx>
28 #include <comphelper/propertyvalue.hxx>
29 #include <sfx2/childwin.hxx>
30 #include <sfx2/lokhelper.hxx>
31 #include <svx/svdpage.hxx>
32 #include <vcl/scheduler.hxx>
33 #include <vcl/vclevent.hxx>
34 #include <vcl/virdev.hxx>
36 #include <comphelper/string.hxx>
37 #include <tools/json_writer.hxx>
38 #include <docoptio.hxx>
40 #include <test/lokcallback.hxx>
41 #include <osl/file.hxx>
42 #include <unotools/tempfile.hxx>
48 #include <scitems.hxx>
49 #include <tabvwsh.hxx>
51 #include <document.hxx>
53 #include <drwlayer.hxx>
54 #include <editutil.hxx>
55 #include <undomanager.hxx>
59 static std::ostream
& operator<<(std::ostream
& os
, ViewShellId
const & id
)
61 os
<< static_cast<sal_Int32
>(id
); return os
;
64 // for passing data to testInvalidateOnTextEditWithDifferentZoomLevels
73 namespace StringHelper
75 // used by CPPUNIT_TEST_PARAMETERIZED for testInvalidateOnTextEditWithDifferentZoomLevels
77 inline std::string
toString(const ColRowZoom
& item
)
79 std::ostringstream ss
;
80 ss
<< "zoom level: " << item
.zoom
<< ", "
81 << "col: " << item
.col
<< ", "
82 << "row: " << item
.row
;
92 class ScTiledRenderingTest
: public UnoApiXmlTest
95 ScTiledRenderingTest();
96 virtual void setUp() override
;
97 virtual void tearDown() override
;
99 void testRowColumnHeaders();
100 void testRowColumnSelections();
102 void testDocumentSize();
103 void testEmptyColumnSelection();
104 void testViewCursors();
105 void testTextViewSelection();
106 void testDocumentSizeChanged();
108 void testColRowResize();
109 void testUndoShells();
110 void testCreateViewGraphicSelection();
111 void testTextEditViews();
112 void testTextEditViewInvalidations();
113 void testGraphicInvalidate();
115 void testHideColRow();
116 void testInvalidateOnCopyPasteCells();
117 void testInvalidateOnInserRowCol();
118 void testCommentCallback();
119 void testUndoLimiting();
120 void testUndoRepairDispatch();
121 void testInsertGraphicInvalidations();
122 void testDocumentSizeWithTwoViews();
123 void testDisableUndoRepair();
124 void testDocumentRepair();
125 void testLanguageStatus();
126 void testMultiViewCopyPaste();
127 void testIMESupport();
128 void testFilterDlg();
129 void testVbaRangeCopyPaste();
130 void testInvalidationLoop();
131 void testPageDownInvalidation();
132 void testSheetChangeInvalidation();
133 void testInsertDeletePageInvalidation();
134 void testGetRowColumnHeadersInvalidation();
135 void testJumpHorizontallyInvalidation();
136 void testJumpToLastRowInvalidation();
137 void testSheetGeometryDataInvariance();
138 void testSheetGeometryDataCorrectness();
139 void testDeleteCellMultilineContent();
140 void testFunctionDlg();
141 void testSpellOnlineParameter();
142 void testSpellOnlineRenderParameter();
143 void testPasteIntoWrapTextCell();
144 void testSortAscendingDescending();
145 void testAutoInputStringBlock();
146 void testAutoInputExactMatch();
147 void testMoveShapeHandle();
148 void testEditCursorBounds();
149 void testTextSelectionBounds();
150 void testSheetViewDataCrash();
151 void testTextBoxInsert();
152 void testCommentCellCopyPaste();
153 void testInvalidEntrySave();
154 void testUndoReordering();
155 void testUndoReorderingRedo();
156 void testUndoReorderingMulti();
157 void testGetViewRenderState();
158 void testInvalidateOnTextEditWithDifferentZoomLevels(const ColRowZoom
& rData
);
160 CPPUNIT_TEST_SUITE(ScTiledRenderingTest
);
161 CPPUNIT_TEST(testRowColumnHeaders
);
162 CPPUNIT_TEST(testRowColumnSelections
);
163 CPPUNIT_TEST(testPartHash
);
164 CPPUNIT_TEST(testDocumentSize
);
165 CPPUNIT_TEST(testEmptyColumnSelection
);
166 CPPUNIT_TEST(testViewCursors
);
167 CPPUNIT_TEST(testTextViewSelection
);
168 CPPUNIT_TEST(testDocumentSizeChanged
);
169 CPPUNIT_TEST(testViewLock
);
170 CPPUNIT_TEST(testColRowResize
);
171 CPPUNIT_TEST(testUndoShells
);
172 CPPUNIT_TEST(testCreateViewGraphicSelection
);
173 CPPUNIT_TEST(testTextEditViews
);
174 CPPUNIT_TEST(testTextEditViewInvalidations
);
175 CPPUNIT_TEST(testGraphicInvalidate
);
176 CPPUNIT_TEST(testAutoSum
);
177 CPPUNIT_TEST(testHideColRow
);
178 CPPUNIT_TEST(testInvalidateOnCopyPasteCells
);
179 CPPUNIT_TEST(testInvalidateOnInserRowCol
);
180 CPPUNIT_TEST(testCommentCallback
);
181 CPPUNIT_TEST(testUndoLimiting
);
182 CPPUNIT_TEST(testUndoRepairDispatch
);
183 CPPUNIT_TEST(testInsertGraphicInvalidations
);
184 CPPUNIT_TEST(testDocumentSizeWithTwoViews
);
185 CPPUNIT_TEST(testDisableUndoRepair
);
186 CPPUNIT_TEST(testDocumentRepair
);
187 CPPUNIT_TEST(testLanguageStatus
);
188 CPPUNIT_TEST(testMultiViewCopyPaste
);
189 CPPUNIT_TEST(testIMESupport
);
190 CPPUNIT_TEST(testFilterDlg
);
191 CPPUNIT_TEST(testVbaRangeCopyPaste
);
192 CPPUNIT_TEST(testInvalidationLoop
);
193 CPPUNIT_TEST(testPageDownInvalidation
);
194 CPPUNIT_TEST(testSheetChangeInvalidation
);
195 CPPUNIT_TEST(testInsertDeletePageInvalidation
);
196 CPPUNIT_TEST(testGetRowColumnHeadersInvalidation
);
197 CPPUNIT_TEST(testJumpHorizontallyInvalidation
);
198 CPPUNIT_TEST(testJumpToLastRowInvalidation
);
199 CPPUNIT_TEST(testSheetGeometryDataInvariance
);
200 CPPUNIT_TEST(testSheetGeometryDataCorrectness
);
201 CPPUNIT_TEST(testDeleteCellMultilineContent
);
202 CPPUNIT_TEST(testFunctionDlg
);
203 CPPUNIT_TEST(testSpellOnlineParameter
);
204 CPPUNIT_TEST(testSpellOnlineRenderParameter
);
205 CPPUNIT_TEST(testPasteIntoWrapTextCell
);
206 CPPUNIT_TEST(testSortAscendingDescending
);
207 CPPUNIT_TEST(testAutoInputStringBlock
);
208 CPPUNIT_TEST(testAutoInputExactMatch
);
209 CPPUNIT_TEST(testMoveShapeHandle
);
210 CPPUNIT_TEST(testEditCursorBounds
);
211 CPPUNIT_TEST(testTextSelectionBounds
);
212 CPPUNIT_TEST(testSheetViewDataCrash
);
213 CPPUNIT_TEST(testTextBoxInsert
);
214 CPPUNIT_TEST(testCommentCellCopyPaste
);
215 CPPUNIT_TEST(testInvalidEntrySave
);
216 CPPUNIT_TEST(testUndoReordering
);
217 CPPUNIT_TEST(testUndoReorderingRedo
);
218 CPPUNIT_TEST(testUndoReorderingMulti
);
219 CPPUNIT_TEST(testGetViewRenderState
);
220 CPPUNIT_TEST_PARAMETERIZED(testInvalidateOnTextEditWithDifferentZoomLevels
,
221 std::initializer_list
<ColRowZoom
>
224 {0, 999, 1}, {99, 0, 1},
226 {0, 999, -5}, {99, 0, -5}
228 CPPUNIT_TEST_SUITE_END();
231 ScModelObj
* createDoc(const char* pName
);
232 void setupLibreOfficeKitViewCallback(SfxViewShell
* pViewShell
);
233 static void callback(int nType
, const char* pPayload
, void* pData
);
234 void callbackImpl(int nType
, const char* pPayload
);
236 /// document size changed callback.
237 osl::Condition m_aDocSizeCondition
;
238 Size m_aDocumentSize
;
240 TestLokCallbackWrapper m_callbackWrapper
;
243 ScTiledRenderingTest::ScTiledRenderingTest()
244 : UnoApiXmlTest("/sc/qa/unit/tiledrendering/data/"),
245 m_callbackWrapper(&callback
, this)
249 void ScTiledRenderingTest::setUp()
251 UnoApiXmlTest::setUp();
253 comphelper::LibreOfficeKit::setActive(true);
256 void ScTiledRenderingTest::tearDown()
258 if (mxComponent
.is())
260 mxComponent
->dispose();
264 m_callbackWrapper
.clear();
265 comphelper::LibreOfficeKit::setActive(false);
267 UnoApiXmlTest::tearDown();
270 ScModelObj
* ScTiledRenderingTest::createDoc(const char* pName
)
272 loadFromURL(OUString::createFromAscii(pName
));
274 ScModelObj
* pModelObj
= dynamic_cast<ScModelObj
*>(mxComponent
.get());
275 CPPUNIT_ASSERT(pModelObj
);
276 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
280 void ScTiledRenderingTest::setupLibreOfficeKitViewCallback(SfxViewShell
* pViewShell
)
282 pViewShell
->setLibreOfficeKitViewCallback(&m_callbackWrapper
);
283 m_callbackWrapper
.setLOKViewId(SfxLokHelper::getView(pViewShell
));
286 void ScTiledRenderingTest::callback(int nType
, const char* pPayload
, void* pData
)
288 static_cast<ScTiledRenderingTest
*>(pData
)->callbackImpl(nType
, pPayload
);
291 /* TODO when needed...
292 static std::vector<OUString> lcl_convertSeparated(const OUString& rString, sal_Unicode nSeparator)
294 std::vector<OUString> aRet;
296 sal_Int32 nIndex = 0;
299 OUString aToken = rString.getToken(0, nSeparator, nIndex);
300 aToken = aToken.trim();
301 if (!aToken.isEmpty())
302 aRet.push_back(aToken);
309 static void lcl_convertRectangle(const OUString& rString, Rectangle& rRectangle)
311 uno::Sequence<OUString> aSeq = comphelper::string::convertCommaSeparated(rString);
312 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), aSeq.getLength());
313 rRectangle.SetLeft(aSeq[0].toInt32());
314 rRectangle.SetTop(aSeq[1].toInt32());
315 rRectangle.setWidth(aSeq[2].toInt32());
316 rRectangle.setHeight(aSeq[3].toInt32());
320 void ScTiledRenderingTest::callbackImpl(int nType
, const char* pPayload
)
324 case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED
:
326 OString
aPayload(pPayload
);
327 sal_Int32 nIndex
= 0;
328 OString aToken
= aPayload
.getToken(0, ',', nIndex
);
329 m_aDocumentSize
.setWidth(aToken
.toInt32());
330 aToken
= aPayload
.getToken(0, ',', nIndex
);
331 m_aDocumentSize
.setHeight(aToken
.toInt32());
332 m_aDocSizeCondition
.set();
338 void ScTiledRenderingTest::testRowColumnSelections()
340 ScModelObj
* pModelObj
= createDoc("select-row-cols.ods");
342 // Select the 5th row with no modifier
343 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
344 { "Row", uno::Any(sal_Int32(5 - 1)) },
345 { "Modifier", uno::Any(sal_uInt16(0)) }
347 dispatchCommand(mxComponent
, ".uno:SelectRow", aArgs
);
349 // Check if it is selected
350 OString aResult
= apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8");
351 OString
aExpected("1\t2\t3\t4\t5\t6\t7\t8\t9\t10\t11\t12\t13\t14\t15\t16\t17\t18\t19\t20\t21\n");
352 CPPUNIT_ASSERT_EQUAL(aExpected
, aResult
);
354 // Select the 10th row with shift modifier
355 aArgs
= comphelper::InitPropertySequence({ { "Row", uno::Any(static_cast<sal_Int32
>(10 - 1)) },
356 { "Modifier", uno::Any(KEY_SHIFT
) } });
357 dispatchCommand(mxComponent
, ".uno:SelectRow", aArgs
);
359 // Check if all the rows from 5th to 10th get selected
360 aResult
= apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8");
361 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";
362 CPPUNIT_ASSERT_EQUAL(aExpected
, aResult
);
364 // Select the 10th row with ctrl modifier
365 aArgs
= comphelper::InitPropertySequence({ { "Row", uno::Any(static_cast<sal_Int32
>(13 - 1)) },
366 { "Modifier", uno::Any(KEY_MOD1
) } });
367 dispatchCommand(mxComponent
, ".uno:SelectRow", aArgs
);
369 // When we copy this, we don't get anything useful, but we must not crash
371 aResult
= apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8");
372 CPPUNIT_ASSERT_EQUAL(OString(), aResult
);
374 // TODO check that we really selected what we wanted here
376 // Select Column 5 with ctrl modifier
377 aArgs
= comphelper::InitPropertySequence({ { "Col", uno::Any(static_cast<sal_Int32
>(5 - 1)) },
378 { "Modifier", uno::Any(KEY_MOD1
) } });
379 dispatchCommand(mxComponent
, ".uno:SelectColumn", aArgs
);
381 // When we copy this, we don't get anything useful, but we must not crash
383 aResult
= apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8");
384 CPPUNIT_ASSERT_EQUAL(OString(), aResult
);
386 // TODO check that we really selected what we wanted here
388 // Test for deselection of already selected rows
389 // First Deselect Row 13 because copy doesn't work for multiple selections
390 aArgs
= comphelper::InitPropertySequence({ { "Row", uno::Any(static_cast<sal_Int32
>(13 - 1)) },
391 { "Modifier", uno::Any(KEY_MOD1
) } });
392 dispatchCommand(mxComponent
, ".uno:SelectRow", aArgs
);
395 aArgs
= comphelper::InitPropertySequence({ { "Row", uno::Any(static_cast<sal_Int32
>(10 - 1)) },
396 { "Modifier", uno::Any(KEY_MOD1
) } });
397 dispatchCommand(mxComponent
, ".uno:SelectRow", aArgs
);
399 // Click at row 6 holding shift
400 aArgs
= comphelper::InitPropertySequence({ { "Row", uno::Any(static_cast<sal_Int32
>(6 - 1)) },
401 { "Modifier", uno::Any(KEY_SHIFT
) } });
402 dispatchCommand(mxComponent
, ".uno:SelectRow", aArgs
);
404 // only row 5 should remain selected
405 aResult
= apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8");
406 aExpected
= "1\t2\t3\t4\t5\t6\t7\t8\t9\t10\t11\t12\t13\t14\t15\t16\t17\t18\t19\t20\t21\n";
407 CPPUNIT_ASSERT_EQUAL(aExpected
, aResult
);
410 void ScTiledRenderingTest::testPartHash()
412 ScModelObj
* pModelObj
= createDoc("sort-range.ods");
414 int nParts
= pModelObj
->getParts();
415 for (int it
= 0; it
< nParts
; it
++)
417 CPPUNIT_ASSERT(!pModelObj
->getPartHash(it
).isEmpty());
420 // check part that it does not exists
421 CPPUNIT_ASSERT(pModelObj
->getPartHash(100).isEmpty());
424 void ScTiledRenderingTest::testDocumentSize()
426 ScModelObj
* pModelObj
= createDoc("sort-range.ods");
427 ScDocShell
* pDocSh
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
428 CPPUNIT_ASSERT(pDocSh
);
430 ScTabViewShell
* pViewShell
= pDocSh
->GetBestViewShell(false);
431 CPPUNIT_ASSERT(pViewShell
);
433 setupLibreOfficeKitViewCallback(pViewShell
);
435 // check initial document size
436 Size aDocSize
= pModelObj
->getDocumentSize();
437 CPPUNIT_ASSERT(aDocSize
.Width() > 0);
438 CPPUNIT_ASSERT(aDocSize
.Height() > 0);
441 pViewShell
->SetCursor(100, 0);
443 osl::Condition::Result aResult
= m_aDocSizeCondition
.wait(std::chrono::seconds(2));
444 CPPUNIT_ASSERT_EQUAL(osl::Condition::result_ok
, aResult
);
447 pViewShell
->SetCursor(0, 100);
449 aResult
= m_aDocSizeCondition
.wait(std::chrono::seconds(2));
450 CPPUNIT_ASSERT_EQUAL(osl::Condition::result_ok
, aResult
);
453 void ScTiledRenderingTest::testEmptyColumnSelection()
455 ScModelObj
* pModelObj
= createDoc("select-row-cols.ods");
457 // Select empty column, 1000
458 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
459 { "Col", uno::Any(sal_Int32(1000 - 1)) },
460 { "Modifier", uno::Any(sal_uInt16(0)) }
462 dispatchCommand(mxComponent
, ".uno:SelectColumn", aArgs
);
464 // should be an empty string
465 CPPUNIT_ASSERT_EQUAL(OString(), apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8"));
468 struct EditCursorMessage final
{
469 tools::Rectangle m_aRelRect
;
474 m_aRelRect
.SetEmpty();
475 m_aRefPoint
= Point(-1, -1);
480 return m_aRelRect
.IsEmpty() &&
481 m_aRefPoint
.X() == -1 &&
482 m_aRefPoint
.Y() == -1;
485 void parseMessage(const char* pMessage
)
488 if (!pMessage
|| !comphelper::LibreOfficeKit::isCompatFlagSet(
489 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
) ||
490 !comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
493 std::stringstream
aStream(pMessage
);
494 boost::property_tree::ptree aTree
;
495 boost::property_tree::read_json(aStream
, aTree
);
497 boost::property_tree::ptree::const_assoc_iterator it
= aTree
.find("refpoint");
498 if (it
!= aTree
.not_found())
499 aVal
= aTree
.get_child("refpoint").get_value
<std::string
>();
501 return; // happens in testTextBoxInsert test
503 uno::Sequence
<OUString
> aSeq
= comphelper::string::convertCommaSeparated(OUString::createFromAscii(aVal
.c_str()));
504 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aSeq
.getLength());
505 m_aRefPoint
.setX(aSeq
[0].toInt32());
506 m_aRefPoint
.setY(aSeq
[1].toInt32());
508 aVal
= aTree
.get_child("relrect").get_value
<std::string
>();
509 aSeq
= comphelper::string::convertCommaSeparated(OUString::createFromAscii(aVal
.c_str()));
510 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), aSeq
.getLength());
511 m_aRelRect
.SetLeft(aSeq
[0].toInt32());
512 m_aRelRect
.SetTop(aSeq
[1].toInt32());
513 m_aRelRect
.setWidth(aSeq
[2].toInt32());
514 m_aRelRect
.setHeight(aSeq
[3].toInt32());
517 tools::Rectangle
getBounds()
519 tools::Rectangle aBounds
= m_aRelRect
;
520 aBounds
.Move(m_aRefPoint
.X(), m_aRefPoint
.Y());
525 struct TextSelectionMessage
527 std::vector
<tools::Rectangle
> m_aRelRects
;
537 return m_aRelRects
.empty();
540 void parseMessage(const char* pMessage
)
546 std::string
aStr(pMessage
);
547 if (aStr
.find(",") == std::string::npos
)
550 size_t nRefDelimStart
= aStr
.find("::");
551 std::string aRectListString
= (nRefDelimStart
== std::string::npos
) ? aStr
: aStr
.substr(0, nRefDelimStart
);
552 std::string aRefPointString
= (nRefDelimStart
== std::string::npos
) ?
553 std::string("0, 0") :
554 aStr
.substr(nRefDelimStart
+ 2, aStr
.length() - 2 - nRefDelimStart
);
555 uno::Sequence
<OUString
> aSeq
= comphelper::string::convertCommaSeparated(OUString::createFromAscii(aRefPointString
.c_str()));
556 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aSeq
.getLength());
557 m_aRefPoint
.setX(aSeq
[0].toInt32());
558 m_aRefPoint
.setY(aSeq
[1].toInt32());
561 size_t nEnd
= aRectListString
.find(";");
562 if (nEnd
== std::string::npos
)
563 nEnd
= aRectListString
.length();
566 std::string aRectString
= aRectListString
.substr(nStart
, nEnd
- nStart
);
568 aSeq
= comphelper::string::convertCommaSeparated(OUString::createFromAscii(aRectString
.c_str()));
569 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), aSeq
.getLength());
570 tools::Rectangle aRect
;
571 aRect
.SetLeft(aSeq
[0].toInt32());
572 aRect
.SetTop(aSeq
[1].toInt32());
573 aRect
.setWidth(aSeq
[2].toInt32());
574 aRect
.setHeight(aSeq
[3].toInt32());
576 m_aRelRects
.push_back(aRect
);
580 nEnd
= aRectListString
.find(";", nStart
);
582 while(nEnd
!= std::string::npos
);
585 tools::Rectangle
getBounds(size_t nIndex
)
587 if (nIndex
>= m_aRelRects
.size())
588 return tools::Rectangle();
590 tools::Rectangle aBounds
= m_aRelRects
[nIndex
];
591 aBounds
.Move(m_aRefPoint
.X(), m_aRefPoint
.Y());
597 /// A view callback tracks callbacks invoked on one specific view.
598 class ViewCallback final
600 SfxViewShell
* mpViewShell
;
603 bool m_bOwnCursorInvalidated
;
604 bool m_bViewCursorInvalidated
;
605 bool m_bTextViewSelectionInvalidated
;
606 bool m_bGraphicSelection
;
607 bool m_bGraphicViewSelection
;
608 bool m_bFullInvalidateTiles
;
609 bool m_bInvalidateTiles
;
610 std::vector
<tools::Rectangle
> m_aInvalidations
;
611 tools::Rectangle m_aCellCursorBounds
;
612 std::vector
<int> m_aInvalidationsParts
;
613 std::vector
<int> m_aInvalidationsMode
;
615 OString m_sCellFormula
;
616 boost::property_tree::ptree m_aCommentCallbackResult
;
617 EditCursorMessage m_aInvalidateCursorResult
;
618 TextSelectionMessage m_aTextSelectionResult
;
619 OString m_sInvalidateHeader
;
620 OString m_sInvalidateSheetGeometry
;
621 OString m_ShapeSelection
;
622 TestLokCallbackWrapper m_callbackWrapper
;
624 ViewCallback(bool bDeleteListenerOnDestruct
=true)
625 : m_bOwnCursorInvalidated(false),
626 m_bViewCursorInvalidated(false),
627 m_bTextViewSelectionInvalidated(false),
628 m_bGraphicSelection(false),
629 m_bGraphicViewSelection(false),
630 m_bFullInvalidateTiles(false),
631 m_bInvalidateTiles(false),
633 m_callbackWrapper(&callback
, this)
635 mpViewShell
= SfxViewShell::Current();
636 mpViewShell
->setLibreOfficeKitViewCallback(&m_callbackWrapper
);
637 mnView
= SfxLokHelper::getView();
638 m_callbackWrapper
.setLOKViewId( mnView
);
639 if (!bDeleteListenerOnDestruct
)
640 mpViewShell
= nullptr;
647 SfxLokHelper::setView(mnView
);
648 mpViewShell
->setLibreOfficeKitViewCallback(nullptr);
652 static void callback(int nType
, const char* pPayload
, void* pData
)
654 static_cast<ViewCallback
*>(pData
)->callbackImpl(nType
, pPayload
);
657 void callbackImpl(int nType
, const char* pPayload
)
661 case LOK_CALLBACK_CELL_CURSOR
:
663 m_bOwnCursorInvalidated
= true;
664 uno::Sequence
<OUString
> aSeq
= comphelper::string::convertCommaSeparated(OUString::createFromAscii(pPayload
));
665 m_aCellCursorBounds
= tools::Rectangle();
666 if (aSeq
.getLength() == 6) {
667 m_aCellCursorBounds
.SetLeft(aSeq
[0].toInt32());
668 m_aCellCursorBounds
.SetTop(aSeq
[1].toInt32());
669 m_aCellCursorBounds
.setWidth(aSeq
[2].toInt32());
670 m_aCellCursorBounds
.setHeight(aSeq
[3].toInt32());
674 case LOK_CALLBACK_CELL_VIEW_CURSOR
:
676 m_bViewCursorInvalidated
= true;
679 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
681 m_bTextViewSelectionInvalidated
= true;
684 case LOK_CALLBACK_VIEW_LOCK
:
686 std::stringstream
aStream(pPayload
);
687 boost::property_tree::ptree aTree
;
688 boost::property_tree::read_json(aStream
, aTree
);
689 m_bViewLock
= aTree
.get_child("rectangle").get_value
<std::string
>() != "EMPTY";
692 case LOK_CALLBACK_GRAPHIC_SELECTION
:
694 m_bGraphicSelection
= true;
695 m_ShapeSelection
= OString(pPayload
);
698 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
700 m_bGraphicViewSelection
= true;
703 case LOK_CALLBACK_INVALIDATE_TILES
:
705 OString
text(pPayload
);
706 if (text
.startsWith("EMPTY"))
708 m_bFullInvalidateTiles
= true;
712 uno::Sequence
<OUString
> aSeq
= comphelper::string::convertCommaSeparated(OUString::createFromAscii(pPayload
));
713 CPPUNIT_ASSERT(aSeq
.getLength() == 4 || aSeq
.getLength() == 6);
714 tools::Rectangle aInvalidationRect
;
715 aInvalidationRect
.SetLeft(aSeq
[0].toInt32());
716 aInvalidationRect
.SetTop(aSeq
[1].toInt32());
717 aInvalidationRect
.setWidth(aSeq
[2].toInt32());
718 aInvalidationRect
.setHeight(aSeq
[3].toInt32());
719 m_aInvalidations
.push_back(aInvalidationRect
);
720 if (aSeq
.getLength() == 6)
722 m_aInvalidationsParts
.push_back(aSeq
[4].toInt32());
723 m_aInvalidationsMode
.push_back(aSeq
[5].toInt32());
725 m_bInvalidateTiles
= true;
729 case LOK_CALLBACK_CELL_FORMULA
:
731 m_sCellFormula
= pPayload
;
734 case LOK_CALLBACK_COMMENT
:
736 m_aCommentCallbackResult
.clear();
737 std::stringstream
aStream(pPayload
);
738 boost::property_tree::read_json(aStream
, m_aCommentCallbackResult
);
739 m_aCommentCallbackResult
= m_aCommentCallbackResult
.get_child("comment");
742 case LOK_CALLBACK_INVALIDATE_HEADER
:
744 m_sInvalidateHeader
= pPayload
;
747 case LOK_CALLBACK_INVALIDATE_SHEET_GEOMETRY
:
749 m_sInvalidateSheetGeometry
= pPayload
;
752 case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
:
754 m_aInvalidateCursorResult
.parseMessage(pPayload
);
757 case LOK_CALLBACK_TEXT_SELECTION
:
759 m_aTextSelectionResult
.parseMessage(pPayload
);
766 void ScTiledRenderingTest::testViewCursors()
768 ScModelObj
* pModelObj
= createDoc("select-row-cols.ods");
770 SfxLokHelper::createView();
771 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
772 ViewCallback
aView2(/*bDeleteListenerOnDestruct*/false);
773 // This was false, the new view did not get the view (cell) cursor of the old view.
774 CPPUNIT_ASSERT(aView2
.m_bViewCursorInvalidated
);
775 CPPUNIT_ASSERT(aView2
.m_bOwnCursorInvalidated
);
776 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DOWN
);
777 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DOWN
);
778 Scheduler::ProcessEventsToIdle();
779 SfxLokHelper::destroyView(SfxLokHelper::getView());
780 CPPUNIT_ASSERT(aView1
.m_bViewCursorInvalidated
);
783 void ScTiledRenderingTest::testSpellOnlineRenderParameter()
785 ScModelObj
* pModelObj
= createDoc("empty.ods");
786 ScDocument
* pDoc
= pModelObj
->GetDocument();
787 bool bSet
= pDoc
->GetDocOptions().IsAutoSpell();
789 uno::Sequence
<beans::PropertyValue
> aPropertyValues
=
791 comphelper::makePropertyValue(".uno:SpellOnline", uno::Any(!bSet
)),
793 pModelObj
->initializeForTiledRendering(aPropertyValues
);
795 CPPUNIT_ASSERT_EQUAL(!bSet
, pDoc
->GetDocOptions().IsAutoSpell());
798 void ScTiledRenderingTest::testTextViewSelection()
800 // Create two views, and leave the second one current.
801 ScModelObj
* pModelObj
= createDoc("select-row-cols.ods");
803 SfxLokHelper::createView();
804 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
807 // Create a selection on two cells in the second view, that's a text selection in LOK terms.
808 aView1
.m_bTextViewSelectionInvalidated
= false;
809 dispatchCommand(mxComponent
, ".uno:GoRightSel", {});
810 Scheduler::ProcessEventsToIdle();
811 // Make sure the first view got its notification.
812 CPPUNIT_ASSERT(aView1
.m_bTextViewSelectionInvalidated
);
815 void ScTiledRenderingTest::testDocumentSizeChanged()
817 // Load a document that doesn't have much content.
818 createDoc("small.ods");
819 setupLibreOfficeKitViewCallback(SfxViewShell::Current());
821 // Go to the A30 cell -- that will extend the document size.
822 uno::Sequence
<beans::PropertyValue
> aPropertyValues
=
824 comphelper::makePropertyValue("ToPoint", OUString("$A$30")),
826 dispatchCommand(mxComponent
, ".uno:GoToCell", aPropertyValues
);
827 Scheduler::ProcessEventsToIdle();
828 // Assert that the size in the payload is not 0.
829 CPPUNIT_ASSERT(m_aDocumentSize
.getWidth() > 0);
830 CPPUNIT_ASSERT(m_aDocumentSize
.getHeight() > 0);
833 void ScTiledRenderingTest::testViewLock()
835 // Load a document that has a shape and create two views.
836 ScModelObj
* pModelObj
= createDoc("shape.ods");
838 SfxLokHelper::createView();
839 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
842 // Begin text edit in the second view and assert that the first gets a lock
844 const ScViewData
* pViewData
= ScDocShell::GetViewData();
845 ScTabViewShell
* pViewShell
= pViewData
->GetViewShell();
846 CPPUNIT_ASSERT(pViewShell
);
847 SdrModel
* pDrawModel
= pViewData
->GetDocument().GetDrawLayer();
848 SdrPage
* pDrawPage
= pDrawModel
->GetPage(0);
849 SdrObject
* pObject
= pDrawPage
->GetObj(0);
850 SdrView
* pView
= pViewShell
->GetScDrawView();
851 aView1
.m_bViewLock
= false;
852 pView
->SdrBeginTextEdit(pObject
);
853 CPPUNIT_ASSERT(aView1
.m_bViewLock
);
855 // End text edit in the second view, and assert that the lock is removed in
857 pView
->SdrEndTextEdit();
858 CPPUNIT_ASSERT(!aView1
.m_bViewLock
);
861 void lcl_extractHandleParameters(std::string_view selection
, sal_uInt32
& id
, sal_uInt32
& x
, sal_uInt32
& y
)
863 OString
extraInfo( selection
.substr(selection
.find("{")) );
864 std::stringstream
aStream(extraInfo
.getStr());
865 boost::property_tree::ptree aTree
;
866 boost::property_tree::read_json(aStream
, aTree
);
867 boost::property_tree::ptree
869 .get_child("handles")
871 .get_child("rectangle")
874 id
= handle0
.get_child("id").get_value
<int>();
875 x
= handle0
.get_child("point").get_child("x").get_value
<int>();
876 y
= handle0
.get_child("point").get_child("y").get_value
<int>();
879 void ScTiledRenderingTest::testMoveShapeHandle()
881 ScModelObj
* pModelObj
= createDoc("shape.ods");
883 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
, /*x=*/ 1,/*y=*/ 1,/*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
884 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
, /*x=*/ 1, /*y=*/ 1, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
885 Scheduler::ProcessEventsToIdle();
887 CPPUNIT_ASSERT(!aView1
.m_ShapeSelection
.isEmpty());
890 lcl_extractHandleParameters(aView1
.m_ShapeSelection
, id
, x
,y
);
893 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
895 {"HandleNum", uno::Any(id
)},
896 {"NewPosX", uno::Any(x
+1)},
897 {"NewPosY", uno::Any(y
+1)}
899 dispatchCommand(mxComponent
, ".uno:MoveShapeHandle", aPropertyValues
);
900 Scheduler::ProcessEventsToIdle();
901 CPPUNIT_ASSERT(!aView1
.m_ShapeSelection
.isEmpty());
902 lcl_extractHandleParameters(aView1
.m_ShapeSelection
, id
, x
,y
);
903 CPPUNIT_ASSERT_EQUAL(x
-1, oldX
);
904 CPPUNIT_ASSERT_EQUAL(y
-1, oldY
);
908 void ScTiledRenderingTest::testColRowResize()
910 ScModelObj
* pModelObj
= createDoc("sort-range.ods");
911 ScDocShell
* pDocSh
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
912 CPPUNIT_ASSERT(pDocSh
);
914 ScTabViewShell
* pViewShell
= pDocSh
->GetBestViewShell(false);
915 CPPUNIT_ASSERT(pViewShell
);
917 setupLibreOfficeKitViewCallback(pViewShell
);
919 ScDocument
& rDoc
= pDocSh
->GetDocument();
922 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
923 { "ColumnWidth", uno::Any(sal_uInt16(4000)) }, // 4cm
924 { "Column", uno::Any(sal_Int16(3)) }
926 dispatchCommand(mxComponent
, ".uno:ColumnWidth", aArgs
);
928 sal_uInt16 nWidth
= o3tl::convert(rDoc
.GetColWidth(static_cast<SCCOL
>(2), static_cast<SCTAB
>(0), false), o3tl::Length::twip
, o3tl::Length::mm100
);
929 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(4001), nWidth
);
932 uno::Sequence
<beans::PropertyValue
> aArgs2( comphelper::InitPropertySequence({
933 { "RowHeight", uno::Any(sal_uInt16(2000)) },
934 { "Row", uno::Any(sal_Int16(5)) },
936 dispatchCommand(mxComponent
, ".uno:RowHeight", aArgs2
);
938 sal_uInt16 nHeight
= o3tl::convert(rDoc
.GetRowHeight(static_cast<SCROW
>(4), static_cast<SCTAB
>(0), false), o3tl::Length::twip
, o3tl::Length::mm100
);
939 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(2000), nHeight
);
942 void ScTiledRenderingTest::testUndoShells()
944 ScModelObj
* pModelObj
= createDoc("small.ods");
945 // Clear the currently selected cell.
946 dispatchCommand(mxComponent
, ".uno:ClearContents", {});
948 auto pDocShell
= dynamic_cast<ScDocShell
*>(pModelObj
->GetEmbeddedObject());
949 CPPUNIT_ASSERT(pDocShell
);
950 ScDocument
& rDoc
= pDocShell
->GetDocument();
951 ScUndoManager
* pUndoManager
= rDoc
.GetUndoManager();
952 CPPUNIT_ASSERT(pUndoManager
);
953 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pUndoManager
->GetUndoActionCount());
954 sal_Int32 nView1
= SfxLokHelper::getView();
955 // This was -1: ScSimpleUndo did not remember what view shell created it.
956 CPPUNIT_ASSERT_EQUAL(ViewShellId(nView1
), pUndoManager
->GetUndoAction()->GetViewShellId());
959 bool lcl_hasEditView(const ScViewData
& rViewData
)
961 bool bResult
= false;
962 for (unsigned int i
=0; i
<4; i
++)
964 bResult
= rViewData
.HasEditView( static_cast<ScSplitPos
>(i
) );
970 void ScTiledRenderingTest::testTextEditViews()
972 ScModelObj
* pModelObj
= createDoc("small.ods");
973 CPPUNIT_ASSERT(pModelObj
);
974 ScViewData
* pViewData
= ScDocShell::GetViewData();
975 CPPUNIT_ASSERT(pViewData
);
979 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
981 // text edit a cell in view #1
982 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
983 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
984 Scheduler::ProcessEventsToIdle();
985 CPPUNIT_ASSERT(lcl_hasEditView(*pViewData
));
988 SfxLokHelper::createView();
989 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
992 // move cell cursor i view #2
993 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DOWN
);
994 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DOWN
);
995 Scheduler::ProcessEventsToIdle();
997 // check that text edit view in view #1 has not be killed
998 CPPUNIT_ASSERT(lcl_hasEditView(*pViewData
));
1001 void ScTiledRenderingTest::testTextEditViewInvalidations()
1003 ScModelObj
* pModelObj
= createDoc("small.ods");
1004 CPPUNIT_ASSERT(pModelObj
);
1005 ScViewData
* pViewData
= ScDocShell::GetViewData();
1006 CPPUNIT_ASSERT(pViewData
);
1009 int nView1
= SfxLokHelper::getView();
1010 ViewCallback aView1
;
1011 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
1014 SfxLokHelper::createView();
1015 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
1016 ViewCallback aView2
;
1018 // text edit a cell in view #1
1019 SfxLokHelper::setView(nView1
);
1020 aView2
.m_bInvalidateTiles
= false;
1021 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
1022 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
1023 Scheduler::ProcessEventsToIdle();
1024 CPPUNIT_ASSERT(lcl_hasEditView(*pViewData
));
1025 CPPUNIT_ASSERT(aView2
.m_bInvalidateTiles
);
1027 // text edit a cell in view #1 until
1028 // we can be sure we are out of the initial tile
1029 for (int i
= 0; i
< 40; ++i
)
1031 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
1032 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
1034 Scheduler::ProcessEventsToIdle();
1036 // text edit a cell in view #1 inside the new tile and
1037 // check that view #2 receive a tile invalidate message
1038 aView2
.m_bInvalidateTiles
= false;
1039 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
1040 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
1041 Scheduler::ProcessEventsToIdle();
1042 CPPUNIT_ASSERT(aView2
.m_bInvalidateTiles
);
1045 SfxLokHelper::createView();
1046 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
1047 ViewCallback aView3
;
1049 // text edit a cell in view #1
1050 SfxLokHelper::setView(nView1
);
1051 aView3
.m_bInvalidateTiles
= false;
1052 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'y', 0);
1053 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'y', 0);
1054 Scheduler::ProcessEventsToIdle();
1055 CPPUNIT_ASSERT(aView3
.m_bInvalidateTiles
);
1058 void ScTiledRenderingTest::testCreateViewGraphicSelection()
1060 // Load a document that has a shape and create two views.
1061 ScModelObj
* pModelObj
= createDoc("shape.ods");
1062 ViewCallback aView1
;
1064 // Mark the graphic in the first view.
1065 const ScViewData
* pViewData
= ScDocShell::GetViewData();
1066 ScTabViewShell
* pViewShell
= pViewData
->GetViewShell();
1067 CPPUNIT_ASSERT(pViewShell
);
1068 SdrModel
* pDrawModel
= pViewData
->GetDocument().GetDrawLayer();
1069 SdrPage
* pDrawPage
= pDrawModel
->GetPage(0);
1070 SdrObject
* pObject
= pDrawPage
->GetObj(0);
1071 SdrView
* pView
= pViewShell
->GetScDrawView();
1072 aView1
.m_bGraphicSelection
= false;
1073 aView1
.m_bGraphicViewSelection
= false;
1074 pView
->MarkObj(pObject
, pView
->GetSdrPageView());
1075 CPPUNIT_ASSERT(aView1
.m_bGraphicSelection
);
1077 // Create a second view.
1078 int nView1
= SfxLokHelper::getView();
1079 SfxLokHelper::createView();
1080 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
1081 ViewCallback aView2
;
1082 CPPUNIT_ASSERT(aView2
.m_bGraphicViewSelection
);
1083 CPPUNIT_ASSERT(aView1
.m_bGraphicViewSelection
);
1085 SfxLokHelper::setView(nView1
);
1086 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1089 void ScTiledRenderingTest::testGraphicInvalidate()
1091 // Load a document that has a shape and create two views.
1092 ScModelObj
* pModelObj
= createDoc("shape.ods");
1095 // Click to select graphic
1096 aView
.m_bGraphicSelection
= false;
1097 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
, /*x=*/ 1,/*y=*/ 1,/*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
1098 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
, /*x=*/ 1, /*y=*/ 1, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
1099 Scheduler::ProcessEventsToIdle();
1100 CPPUNIT_ASSERT(aView
.m_bGraphicSelection
);
1102 // Drag Drop graphic
1103 aView
.m_bGraphicSelection
= false;
1104 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
, /*x=*/ 1,/*y=*/ 1,/*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
1105 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEMOVE
, /*x=*/ 1,/*y=*/ 10,/*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
1106 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
, /*x=*/ 1, /*y=*/ 10, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
1107 Scheduler::ProcessEventsToIdle();
1108 CPPUNIT_ASSERT(!aView
.m_bFullInvalidateTiles
);
1111 Scheduler::ProcessEventsToIdle();
1112 CPPUNIT_ASSERT(!aView
.m_bFullInvalidateTiles
);
1115 void ScTiledRenderingTest::testAutoSum()
1117 createDoc("small.ods");
1121 uno::Sequence
<beans::PropertyValue
> aArgs
;
1122 dispatchCommand(mxComponent
, ".uno:AutoSum", aArgs
);
1123 Scheduler::ProcessEventsToIdle();
1124 CPPUNIT_ASSERT(aView
.m_sCellFormula
.startsWith("=SUM("));
1127 void ScTiledRenderingTest::testHideColRow()
1129 createDoc("small.ods");
1131 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
1132 { "Col", uno::Any(sal_Int32(2 - 1)) },
1133 { "Modifier", uno::Any(KEY_SHIFT
) }
1135 dispatchCommand(mxComponent
, ".uno:SelectColumn", aArgs
);
1137 uno::Sequence
<beans::PropertyValue
> aArgs2( comphelper::InitPropertySequence({
1138 { "Col", uno::Any(sal_Int32(3 - 1)) },
1139 { "Modifier", uno::Any(sal_uInt16(0)) }
1142 dispatchCommand(mxComponent
, ".uno:SelectColumn", aArgs2
);
1143 Scheduler::ProcessEventsToIdle();
1146 SCCOL nOldCurX
= ScDocShell::GetViewData()->GetCurX();
1147 SCROW nOldCurY
= ScDocShell::GetViewData()->GetCurY();
1149 uno::Sequence
<beans::PropertyValue
> aArgs
;
1150 dispatchCommand(mxComponent
, ".uno:HideColumn", aArgs
);
1151 Scheduler::ProcessEventsToIdle();
1154 SCCOL nNewCurX
= ScDocShell::GetViewData()->GetCurX();
1155 SCROW nNewCurY
= ScDocShell::GetViewData()->GetCurY();
1156 CPPUNIT_ASSERT(nNewCurX
> nOldCurX
);
1157 CPPUNIT_ASSERT_EQUAL(nOldCurY
, nNewCurY
);
1159 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
1160 { "Row", uno::Any(sal_Int32(6 - 1)) },
1161 { "Modifier", uno::Any(KEY_SHIFT
) }
1163 dispatchCommand(mxComponent
, ".uno:SelectRow", aArgs
);
1165 uno::Sequence
<beans::PropertyValue
> aArgs2( comphelper::InitPropertySequence({
1166 { "Row", uno::Any(sal_Int32(7 - 1)) },
1167 { "Modifier", uno::Any(sal_uInt16(0)) }
1169 dispatchCommand(mxComponent
, ".uno:SelectRow", aArgs2
);
1170 Scheduler::ProcessEventsToIdle();
1173 nOldCurX
= ScDocShell::GetViewData()->GetCurX();
1174 nOldCurY
= ScDocShell::GetViewData()->GetCurY();
1176 uno::Sequence
<beans::PropertyValue
> aArgs
;
1177 dispatchCommand(mxComponent
, ".uno:HideRow", aArgs
);
1178 Scheduler::ProcessEventsToIdle();
1180 nNewCurX
= ScDocShell::GetViewData()->GetCurX();
1181 nNewCurY
= ScDocShell::GetViewData()->GetCurY();
1182 CPPUNIT_ASSERT(nNewCurY
> nOldCurY
);
1183 CPPUNIT_ASSERT_EQUAL(nOldCurX
, nNewCurX
);
1186 void ScTiledRenderingTest::testInvalidateOnCopyPasteCells()
1188 ScModelObj
* pModelObj
= createDoc("small.ods");
1189 CPPUNIT_ASSERT(pModelObj
);
1194 uno::Sequence
<beans::PropertyValue
> aArgs
;
1195 // select and copy cells
1196 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_HOME
| KEY_MOD1
);
1197 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_HOME
| KEY_MOD1
);
1198 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
| KEY_SHIFT
);
1199 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
| KEY_SHIFT
);
1200 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_RIGHT
| KEY_SHIFT
);
1201 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_RIGHT
| KEY_SHIFT
);
1202 Scheduler::ProcessEventsToIdle();
1203 dispatchCommand(mxComponent
, ".uno:Copy", aArgs
);
1205 // move to destination cell
1206 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
);
1207 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
);
1208 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
| KEY_MOD1
);
1209 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
| KEY_MOD1
);
1210 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_UP
);
1211 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_UP
);
1212 Scheduler::ProcessEventsToIdle();
1215 aView
.m_bInvalidateTiles
= false;
1216 dispatchCommand(mxComponent
, ".uno:Paste", aArgs
);
1217 Scheduler::ProcessEventsToIdle();
1218 CPPUNIT_ASSERT(aView
.m_bInvalidateTiles
);
1221 void ScTiledRenderingTest::testInvalidateOnInserRowCol()
1223 ScModelObj
* pModelObj
= createDoc("small.ods");
1224 CPPUNIT_ASSERT(pModelObj
);
1229 uno::Sequence
<beans::PropertyValue
> aArgs
;
1231 for (int i
= 0; i
< 200; ++i
)
1233 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
);
1234 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
);
1236 Scheduler::ProcessEventsToIdle();
1239 aView
.m_bInvalidateTiles
= false;
1240 aView
.m_aInvalidations
.clear();
1241 dispatchCommand(mxComponent
, ".uno:InsertRows", aArgs
);
1242 Scheduler::ProcessEventsToIdle();
1243 CPPUNIT_ASSERT(aView
.m_bInvalidateTiles
);
1244 CPPUNIT_ASSERT_EQUAL(size_t(1), aView
.m_aInvalidations
.size());
1245 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(-75, 51240, 32212230, 63990), aView
.m_aInvalidations
[0]);
1247 // move on the right
1248 for (int i
= 0; i
< 200; ++i
)
1250 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_RIGHT
);
1251 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_RIGHT
);
1253 Scheduler::ProcessEventsToIdle();
1256 aView
.m_bInvalidateTiles
= false;
1257 aView
.m_aInvalidations
.clear();
1258 dispatchCommand(mxComponent
, ".uno:InsertColumns", aArgs
);
1259 Scheduler::ProcessEventsToIdle();
1260 CPPUNIT_ASSERT(aView
.m_bInvalidateTiles
);
1261 CPPUNIT_ASSERT_EQUAL(size_t(1), aView
.m_aInvalidations
.size());
1262 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(254925, -15, 32212230, 63990), aView
.m_aInvalidations
[0]);
1265 void ScTiledRenderingTest::testCommentCallback()
1267 // Comments callback are emitted only if tiled annotations are off
1268 comphelper::LibreOfficeKit::setTiledAnnotations(false);
1270 // FIXME: Hack because previous tests do not destroy ScDocument(with annotations) on exit (?).
1271 ScPostIt::mnLastPostItId
= 1;
1274 ScModelObj
* pModelObj
= createDoc("small.ods");
1275 ViewCallback aView1
;
1276 int nView1
= SfxLokHelper::getView();
1278 // Create a 2nd view
1279 SfxLokHelper::createView();
1280 pModelObj
->initializeForTiledRendering({});
1281 ViewCallback aView2
;
1283 SfxLokHelper::setView(nView1
);
1285 ScTabViewShell
* pTabViewShell
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
1287 pTabViewShell
->SetCursor(4, 4);
1289 // Add a new comment
1290 uno::Sequence
<beans::PropertyValue
> aArgs(comphelper::InitPropertySequence(
1292 {"Text", uno::Any(OUString("Comment"))},
1293 {"Author", uno::Any(OUString("LOK User1"))},
1295 dispatchCommand(mxComponent
, ".uno:InsertAnnotation", aArgs
);
1296 Scheduler::ProcessEventsToIdle();
1298 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action
1299 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1300 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1301 CPPUNIT_ASSERT_EQUAL(std::string("1"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("id"));
1302 CPPUNIT_ASSERT_EQUAL(std::string("1"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("id"));
1303 CPPUNIT_ASSERT_EQUAL(std::string("0"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("tab"));
1304 CPPUNIT_ASSERT_EQUAL(std::string("0"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("tab"));
1305 CPPUNIT_ASSERT_EQUAL(std::string("LOK User1"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("author"));
1306 CPPUNIT_ASSERT_EQUAL(std::string("LOK User1"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("author"));
1307 CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1308 CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1309 CPPUNIT_ASSERT_EQUAL(std::string("4 4 4 4"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("cellRange"));
1310 CPPUNIT_ASSERT_EQUAL(std::string("4 4 4 4"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("cellRange"));
1312 // Ensure deleting rows updates comments
1314 pTabViewShell
->SetCursor(2, 2);
1316 dispatchCommand(mxComponent
, ".uno:DeleteRows", {});
1317 Scheduler::ProcessEventsToIdle();
1318 CPPUNIT_ASSERT_EQUAL(std::string("4 3 4 3"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("cellRange"));
1319 CPPUNIT_ASSERT_EQUAL(std::string("4 3 4 3"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("cellRange"));
1321 // Ensure deleting columns updates comments
1323 pTabViewShell
->SetCursor(2, 2);
1325 dispatchCommand(mxComponent
, ".uno:DeleteColumns", {});
1326 Scheduler::ProcessEventsToIdle();
1327 CPPUNIT_ASSERT_EQUAL(std::string("3 3 3 3"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("cellRange"));
1328 CPPUNIT_ASSERT_EQUAL(std::string("3 3 3 3"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("cellRange"));
1330 std::string aCommentId
= aView1
.m_aCommentCallbackResult
.get
<std::string
>("id");
1333 // Select some random cell, we should be able to edit the cell note without
1334 // selecting the cell
1336 pTabViewShell
->SetCursor(3, 100);
1337 aArgs
= comphelper::InitPropertySequence(
1339 {"Id", uno::Any(OUString::createFromAscii(aCommentId
.c_str()))},
1340 {"Text", uno::Any(OUString("Edited comment"))},
1341 {"Author", uno::Any(OUString("LOK User2"))},
1343 dispatchCommand(mxComponent
, ".uno:EditAnnotation", aArgs
);
1344 Scheduler::ProcessEventsToIdle();
1346 // We received a LOK_CALLBACK_COMMENT callback with comment 'Modify' action
1347 CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1348 CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1349 CPPUNIT_ASSERT_EQUAL(aCommentId
, aView1
.m_aCommentCallbackResult
.get
<std::string
>("id"));
1350 CPPUNIT_ASSERT_EQUAL(aCommentId
, aView2
.m_aCommentCallbackResult
.get
<std::string
>("id"));
1351 CPPUNIT_ASSERT_EQUAL(std::string("LOK User2"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("author"));
1352 CPPUNIT_ASSERT_EQUAL(std::string("LOK User2"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("author"));
1353 CPPUNIT_ASSERT_EQUAL(std::string("Edited comment"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1354 CPPUNIT_ASSERT_EQUAL(std::string("Edited comment"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1355 CPPUNIT_ASSERT_EQUAL(std::string("3 3 3 3"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("cellRange"));
1356 CPPUNIT_ASSERT_EQUAL(std::string("3 3 3 3"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("cellRange"));
1358 // Delete the comment
1360 pTabViewShell
->SetCursor(4, 43);
1361 aArgs
= comphelper::InitPropertySequence(
1363 {"Id", uno::Any(OUString::createFromAscii(aCommentId
.c_str()))}
1365 dispatchCommand(mxComponent
, ".uno:DeleteNote", aArgs
);
1366 Scheduler::ProcessEventsToIdle();
1368 // We received a LOK_CALLBACK_COMMENT callback with comment 'Remove' action
1369 CPPUNIT_ASSERT_EQUAL(std::string("Remove"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1370 CPPUNIT_ASSERT_EQUAL(std::string("Remove"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1371 CPPUNIT_ASSERT_EQUAL(aCommentId
, aView1
.m_aCommentCallbackResult
.get
<std::string
>("id"));
1372 CPPUNIT_ASSERT_EQUAL(aCommentId
, aView2
.m_aCommentCallbackResult
.get
<std::string
>("id"));
1374 comphelper::LibreOfficeKit::setTiledAnnotations(true);
1377 void ScTiledRenderingTest::testUndoLimiting()
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 dispatchCommand(mxComponent
, ".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 #1
1415 SfxLokHelper::setView(nView1
);
1416 dispatchCommand(mxComponent
, ".uno:Undo", {});
1417 Scheduler::ProcessEventsToIdle();
1418 // check that undo has been executed on view #1
1419 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetUndoActionCount());
1421 // check that redo action count in not 0
1422 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetRedoActionCount());
1424 // try to execute redo in view #2
1425 SfxLokHelper::setView(nView2
);
1426 dispatchCommand(mxComponent
, ".uno:Redo", {});
1427 Scheduler::ProcessEventsToIdle();
1428 // check that redo has not been executed on view #2
1429 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetRedoActionCount());
1431 // try to execute redo in view #1
1432 SfxLokHelper::setView(nView1
);
1433 dispatchCommand(mxComponent
, ".uno:Redo", {});
1434 Scheduler::ProcessEventsToIdle();
1435 // check that redo has been executed on view #1
1436 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetRedoActionCount());
1439 void ScTiledRenderingTest::testUndoRepairDispatch()
1441 ScModelObj
* pModelObj
= createDoc("small.ods");
1442 CPPUNIT_ASSERT(pModelObj
);
1443 ScDocument
* pDoc
= pModelObj
->GetDocument();
1444 CPPUNIT_ASSERT(pDoc
);
1445 ScUndoManager
* pUndoManager
= pDoc
->GetUndoManager();
1446 CPPUNIT_ASSERT(pUndoManager
);
1449 int nView1
= SfxLokHelper::getView();
1450 ViewCallback aView1
;
1453 SfxLokHelper::createView();
1454 int nView2
= SfxLokHelper::getView();
1455 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
1456 ViewCallback aView2
;
1458 // text edit a cell in view #1
1459 SfxLokHelper::setView(nView1
);
1460 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
1461 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
1462 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
1463 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
1464 Scheduler::ProcessEventsToIdle();
1466 // check that undo action count in not 0
1467 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
1469 // try to execute undo in view #2
1470 SfxLokHelper::setView(nView2
);
1471 dispatchCommand(mxComponent
, ".uno:Undo", {});
1472 Scheduler::ProcessEventsToIdle();
1473 // check that undo has not been executed on view #2
1474 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
1476 // try to execute undo in view #2 in repair mode
1477 SfxLokHelper::setView(nView2
);
1478 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
1480 {"Repair", uno::Any(true)}
1482 dispatchCommand(mxComponent
, ".uno:Undo", aPropertyValues
);
1483 Scheduler::ProcessEventsToIdle();
1484 // check that undo has been executed on view #2 in repair mode
1485 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetUndoActionCount());
1488 void ScTiledRenderingTest::testInsertGraphicInvalidations()
1490 ScModelObj
* pModelObj
= createDoc("small.ods");
1491 CPPUNIT_ASSERT(pModelObj
);
1492 ScViewData
* pViewData
= ScDocShell::GetViewData();
1493 CPPUNIT_ASSERT(pViewData
);
1498 // we need to paint a tile in the view for triggering the tile invalidation solution
1499 int nCanvasWidth
= 256;
1500 int nCanvasHeight
= 256;
1501 std::vector
<unsigned char> aBuffer(nCanvasWidth
* nCanvasHeight
* 4);
1502 ScopedVclPtrInstance
<VirtualDevice
> pDevice(DeviceFormat::DEFAULT
);
1503 pDevice
->SetOutputSizePixelScaleOffsetAndLOKBuffer(Size(nCanvasWidth
, nCanvasHeight
), Fraction(1.0), Point(), aBuffer
.data());
1504 pModelObj
->paintTile(*pDevice
, nCanvasWidth
, nCanvasHeight
, /*nTilePosX=*/0, /*nTilePosY=*/0, /*nTileWidth=*/3840, /*nTileHeight=*/3840);
1505 Scheduler::ProcessEventsToIdle();
1507 // insert an image in view and see if both views are invalidated
1508 aView
.m_bInvalidateTiles
= false;
1509 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
1510 { "FileName", uno::Any(createFileURL(u
"smile.png")) }
1512 dispatchCommand(mxComponent
, ".uno:InsertGraphic", aArgs
);
1513 Scheduler::ProcessEventsToIdle();
1514 CPPUNIT_ASSERT(aView
.m_bInvalidateTiles
);
1516 // undo image insertion in view and see if both views are invalidated
1517 aView
.m_bInvalidateTiles
= false;
1518 uno::Sequence
<beans::PropertyValue
> aArgs2
;
1519 dispatchCommand(mxComponent
, ".uno:Undo", aArgs2
);
1520 Scheduler::ProcessEventsToIdle();
1521 CPPUNIT_ASSERT(aView
.m_bInvalidateTiles
);
1524 void ScTiledRenderingTest::testDocumentSizeWithTwoViews()
1526 // Open a document that has the cursor far away & paint a tile
1527 ScModelObj
* pModelObj
= createDoc("cursor-away.ods");
1529 // Set the visible area, and press page down
1530 pModelObj
->setClientVisibleArea(tools::Rectangle(750, 1861, 20583, 6997));
1531 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
);
1532 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
);
1533 Scheduler::ProcessEventsToIdle();
1535 int nCanvasWidth
= 256;
1536 int nCanvasHeight
= 256;
1537 std::vector
<unsigned char> aBuffer1(nCanvasWidth
* nCanvasHeight
* 4);
1538 ScopedVclPtrInstance
<VirtualDevice
> pDevice1(DeviceFormat::DEFAULT
);
1539 pDevice1
->SetOutputSizePixelScaleOffsetAndLOKBuffer(Size(nCanvasWidth
, nCanvasHeight
), Fraction(1.0), Point(), aBuffer1
.data());
1540 pModelObj
->paintTile(*pDevice1
, nCanvasWidth
, nCanvasHeight
, /*nTilePosX=*/0, /*nTilePosY=*/291840, /*nTileWidth=*/3840, /*nTileHeight=*/3840);
1541 Scheduler::ProcessEventsToIdle();
1543 // Create a new view
1544 int nView1
= SfxLokHelper::getView();
1545 SfxLokHelper::createView();
1547 std::vector
<unsigned char> aBuffer2(nCanvasWidth
* nCanvasHeight
* 4);
1548 ScopedVclPtrInstance
<VirtualDevice
> pDevice2(DeviceFormat::DEFAULT
);
1549 pDevice2
->SetOutputSizePixelScaleOffsetAndLOKBuffer(Size(nCanvasWidth
, nCanvasHeight
), Fraction(1.0), Point(), aBuffer2
.data());
1550 pModelObj
->paintTile(*pDevice2
, nCanvasWidth
, nCanvasHeight
, /*nTilePosX=*/0, /*nTilePosY=*/291840, /*nTileWidth=*/3840, /*nTileHeight=*/3840);
1551 Scheduler::ProcessEventsToIdle();
1553 // Check that the tiles actually have the same content
1554 for (size_t i
= 0; i
< aBuffer1
.size(); ++i
)
1555 CPPUNIT_ASSERT_EQUAL(aBuffer1
[i
], aBuffer2
[i
]);
1557 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1558 SfxLokHelper::setView(nView1
);
1559 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1562 void ScTiledRenderingTest::testDisableUndoRepair()
1564 ScModelObj
* pModelObj
= createDoc("cursor-away.ods");
1565 CPPUNIT_ASSERT(pModelObj
);
1568 int nView1
= SfxLokHelper::getView();
1569 SfxViewShell
* pView1
= SfxViewShell::Current();
1572 SfxLokHelper::createView();
1573 int nView2
= SfxLokHelper::getView();
1574 SfxViewShell
* pView2
= SfxViewShell::Current();
1575 CPPUNIT_ASSERT(pView1
!= pView2
);
1577 // both views have UNDO disabled
1579 SfxItemSet
aSet1(pView1
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1580 SfxItemSet
aSet2(pView2
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1581 pView1
->GetSlotState(SID_UNDO
, nullptr, &aSet1
);
1582 pView2
->GetSlotState(SID_UNDO
, nullptr, &aSet2
);
1583 CPPUNIT_ASSERT_EQUAL(SfxItemState::DISABLED
, aSet1
.GetItemState(SID_UNDO
));
1584 CPPUNIT_ASSERT_EQUAL(SfxItemState::DISABLED
, aSet2
.GetItemState(SID_UNDO
));
1587 // text edit a cell in view #1
1588 SfxLokHelper::setView(nView1
);
1589 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'h', 0);
1590 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'h', 0);
1591 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
1592 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
1593 Scheduler::ProcessEventsToIdle();
1594 // view1 has UNDO enabled, view2 is in UNDO-repair
1596 SfxItemSet
aSet1(pView1
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1597 SfxItemSet
aSet2(pView2
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1598 pView1
->GetSlotState(SID_UNDO
, nullptr, &aSet1
);
1599 pView2
->GetSlotState(SID_UNDO
, nullptr, &aSet2
);
1600 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet1
.GetItemState(SID_UNDO
));
1601 CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem
* >(aSet1
.GetItem(SID_UNDO
)));
1602 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet2
.GetItemState(SID_UNDO
));
1603 CPPUNIT_ASSERT(dynamic_cast< const SfxUInt32Item
* >(aSet2
.GetItem(SID_UNDO
)));
1604 const SfxUInt32Item
* pUInt32Item
= dynamic_cast<const SfxUInt32Item
*>(aSet2
.GetItem(SID_UNDO
));
1605 CPPUNIT_ASSERT(pUInt32Item
);
1606 CPPUNIT_ASSERT_EQUAL(static_cast< sal_uInt32
>(SID_REPAIRPACKAGE
), pUInt32Item
->GetValue());
1609 // text edit a cell in view #2
1610 SfxLokHelper::setView(nView2
);
1611 pModelObj
->setPart(1);
1612 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'c', 0);
1613 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'c', 0);
1614 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
1615 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
1616 // both views have UNDO enabled
1617 Scheduler::ProcessEventsToIdle();
1619 SfxItemSet
aSet1(pView1
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1620 SfxItemSet
aSet2(pView2
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1621 pView1
->GetSlotState(SID_UNDO
, nullptr, &aSet1
);
1622 pView2
->GetSlotState(SID_UNDO
, nullptr, &aSet2
);
1623 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet1
.GetItemState(SID_UNDO
));
1624 CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem
* >(aSet1
.GetItem(SID_UNDO
)));
1625 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet2
.GetItemState(SID_UNDO
));
1626 CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem
* >(aSet2
.GetItem(SID_UNDO
)));
1629 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1630 SfxLokHelper::setView(nView1
);
1631 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1634 void ScTiledRenderingTest::testDocumentRepair()
1636 // Create two views.
1637 ScModelObj
* pModelObj
= createDoc("cursor-away.ods");
1638 CPPUNIT_ASSERT(pModelObj
);
1641 SfxViewShell
* pView1
= SfxViewShell::Current();
1644 int nView1
= SfxLokHelper::getView();
1645 SfxLokHelper::createView();
1646 SfxViewShell
* pView2
= SfxViewShell::Current();
1647 int nView2
= SfxLokHelper::getView();
1648 CPPUNIT_ASSERT(pView1
!= pView2
);
1650 std::unique_ptr
<SfxBoolItem
> pItem1
;
1651 std::unique_ptr
<SfxBoolItem
> pItem2
;
1652 pView1
->GetViewFrame()->GetBindings().QueryState(SID_DOC_REPAIR
, pItem1
);
1653 pView2
->GetViewFrame()->GetBindings().QueryState(SID_DOC_REPAIR
, pItem2
);
1654 CPPUNIT_ASSERT(pItem1
);
1655 CPPUNIT_ASSERT(pItem2
);
1656 CPPUNIT_ASSERT_EQUAL(false, pItem1
->GetValue());
1657 CPPUNIT_ASSERT_EQUAL(false, pItem2
->GetValue());
1660 // Insert a character in the second view.
1661 SfxLokHelper::setView(nView2
);
1662 pModelObj
->setPart(1);
1663 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'c', 0);
1664 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'c', 0);
1665 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
1666 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
1667 Scheduler::ProcessEventsToIdle();
1669 std::unique_ptr
<SfxBoolItem
> pItem1
;
1670 std::unique_ptr
<SfxBoolItem
> pItem2
;
1671 pView1
->GetViewFrame()->GetBindings().QueryState(SID_DOC_REPAIR
, pItem1
);
1672 pView2
->GetViewFrame()->GetBindings().QueryState(SID_DOC_REPAIR
, pItem2
);
1673 CPPUNIT_ASSERT(pItem1
);
1674 CPPUNIT_ASSERT(pItem2
);
1675 CPPUNIT_ASSERT_EQUAL(true, pItem1
->GetValue());
1676 CPPUNIT_ASSERT_EQUAL(true, pItem2
->GetValue());
1679 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1680 SfxLokHelper::setView(nView1
);
1681 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1684 void ScTiledRenderingTest::testLanguageStatus()
1686 ScModelObj
* pModelObj
= createDoc("small.ods");
1687 CPPUNIT_ASSERT(pModelObj
);
1688 ScDocShell
* pDocSh
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
1689 CPPUNIT_ASSERT(pDocSh
);
1692 SfxViewShell
* pView1
= SfxViewShell::Current();
1695 int nView1
= SfxLokHelper::getView();
1696 SfxLokHelper::createView();
1697 SfxViewShell
* pView2
= SfxViewShell::Current();
1698 CPPUNIT_ASSERT(pView1
!= pView2
);
1700 std::unique_ptr
<SfxPoolItem
> xItem1
;
1701 std::unique_ptr
<SfxPoolItem
> xItem2
;
1702 pView1
->GetViewFrame()->GetBindings().QueryState(SID_LANGUAGE_STATUS
, xItem1
);
1703 pView2
->GetViewFrame()->GetBindings().QueryState(SID_LANGUAGE_STATUS
, xItem2
);
1704 const SfxStringItem
* pItem1
= dynamic_cast<const SfxStringItem
*>(xItem1
.get());
1705 const SfxStringItem
* pItem2
= dynamic_cast<const SfxStringItem
*>(xItem2
.get());
1706 CPPUNIT_ASSERT(pItem1
);
1707 CPPUNIT_ASSERT(pItem2
);
1708 CPPUNIT_ASSERT(!pItem1
->GetValue().isEmpty());
1709 CPPUNIT_ASSERT(!pItem2
->GetValue().isEmpty());
1713 SfxStringItem
aLangString(SID_LANGUAGE_STATUS
, "Default_Spanish (Bolivia)");
1714 pView1
->GetViewFrame()->GetDispatcher()->ExecuteList(SID_LANGUAGE_STATUS
,
1715 SfxCallMode::SYNCHRON
, { &aLangString
});
1719 std::unique_ptr
<SfxPoolItem
> xItem1
;
1720 std::unique_ptr
<SfxPoolItem
> xItem2
;
1721 pView1
->GetViewFrame()->GetBindings().QueryState(SID_LANGUAGE_STATUS
, xItem1
);
1722 pView2
->GetViewFrame()->GetBindings().QueryState(SID_LANGUAGE_STATUS
, xItem2
);
1723 const SfxStringItem
* pItem1
= dynamic_cast<const SfxStringItem
*>(xItem1
.get());
1724 const SfxStringItem
* pItem2
= dynamic_cast<const SfxStringItem
*>(xItem2
.get());
1725 CPPUNIT_ASSERT(pItem1
);
1726 CPPUNIT_ASSERT(pItem2
);
1727 const OUString
aLangBolivia("Spanish (Bolivia);es-BO");
1728 CPPUNIT_ASSERT_EQUAL(aLangBolivia
, pItem1
->GetValue());
1729 CPPUNIT_ASSERT_EQUAL(aLangBolivia
, pItem2
->GetValue());
1732 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1733 SfxLokHelper::setView(nView1
);
1734 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1737 void ScTiledRenderingTest::testMultiViewCopyPaste()
1739 ScModelObj
* pModelObj
= createDoc("empty.ods");
1740 ScDocument
* pDoc
= pModelObj
->GetDocument();
1741 CPPUNIT_ASSERT(pDoc
);
1743 pDoc
->SetString(ScAddress(0, 0, 0), "TestCopy1");
1744 pDoc
->SetString(ScAddress(1, 0, 0), "TestCopy2");
1747 ScTabViewShell
* pView1
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
1748 CPPUNIT_ASSERT(pView1
);
1749 // emulate clipboard
1750 pView1
->GetViewData().GetActiveWin()->SetClipboard(css::datatransfer::clipboard::LokClipboard::create(comphelper::getProcessComponentContext()));
1753 int nView1
= SfxLokHelper::getView();
1754 SfxLokHelper::createView();
1755 ScTabViewShell
* pView2
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
1756 // emulate clipboard
1757 pView2
->GetViewData().GetActiveWin()->SetClipboard(css::datatransfer::clipboard::LokClipboard::create(comphelper::getProcessComponentContext()));
1758 CPPUNIT_ASSERT(pView2
);
1759 CPPUNIT_ASSERT(pView1
!= pView2
);
1760 CPPUNIT_ASSERT(pView1
->GetViewData().GetActiveWin()->GetClipboard() != pView2
->GetViewData().GetActiveWin()->GetClipboard());
1763 pView1
->SetCursor(0, 0);
1764 pView1
->GetViewFrame()->GetBindings().Execute(SID_COPY
);
1767 pView2
->SetCursor(1, 0);
1768 pView2
->GetViewFrame()->GetBindings().Execute(SID_COPY
);
1770 // paste text view 1
1771 pView1
->SetCursor(0, 1);
1772 pView1
->GetViewFrame()->GetBindings().Execute(SID_PASTE
);
1774 // paste text view 2
1775 pView2
->SetCursor(1, 1);
1776 pView2
->GetViewFrame()->GetBindings().Execute(SID_PASTE
);
1778 CPPUNIT_ASSERT_EQUAL(OUString("TestCopy1"), pDoc
->GetString(ScAddress(0, 1, 0)));
1779 CPPUNIT_ASSERT_EQUAL(OUString("TestCopy2"), pDoc
->GetString(ScAddress(1, 1, 0)));
1781 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1782 SfxLokHelper::setView(nView1
);
1783 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1786 void ScTiledRenderingTest::testIMESupport()
1788 ScModelObj
* pModelObj
= createDoc("empty.ods");
1789 VclPtr
<vcl::Window
> pDocWindow
= pModelObj
->getDocWindow();
1790 ScDocument
* pDoc
= pModelObj
->GetDocument();
1792 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
1793 CPPUNIT_ASSERT(pView
);
1795 pView
->SetCursor(0, 0);
1796 // sequence of chinese IME compositions when 'nihao' is typed in an IME
1797 const std::vector
<OString
> aUtf8Inputs
{ "å¹´", "ä½ ", "ä½ å¥½", "ä½ å“ˆ", "ä½ å¥½", "ä½ å¥½" };
1798 std::vector
<OUString
> aInputs
;
1799 std::transform(aUtf8Inputs
.begin(), aUtf8Inputs
.end(),
1800 std::back_inserter(aInputs
), [](OString aInput
) {
1801 return OUString::fromUtf8(aInput
);
1803 for (const auto& aInput
: aInputs
)
1805 pDocWindow
->PostExtTextInputEvent(VclEventId::ExtTextInput
, aInput
);
1807 pDocWindow
->PostExtTextInputEvent(VclEventId::EndExtTextInput
, "");
1809 // commit the string to the cell
1810 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
1811 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
1812 Scheduler::ProcessEventsToIdle();
1814 CPPUNIT_ASSERT_EQUAL(aInputs
[aInputs
.size() - 1], pDoc
->GetString(ScAddress(0, 0, 0)));
1817 void ScTiledRenderingTest::testFilterDlg()
1819 createDoc("empty.ods");
1822 SfxViewShell
* pView1
= SfxViewShell::Current();
1823 int nView1
= SfxLokHelper::getView();
1826 SfxLokHelper::createView();
1827 SfxViewShell
* pView2
= SfxViewShell::Current();
1828 CPPUNIT_ASSERT(pView1
!= pView2
);
1830 pView2
->GetViewFrame()->GetDispatcher()->Execute(SID_FILTER
,
1831 SfxCallMode::SLOT
|SfxCallMode::RECORD
);
1834 Scheduler::ProcessEventsToIdle();
1835 SfxChildWindow
* pRefWindow
= pView2
->GetViewFrame()->GetChildWindow(SID_FILTER
);
1836 CPPUNIT_ASSERT(pRefWindow
);
1839 SfxLokHelper::setView(nView1
);
1840 CPPUNIT_ASSERT_EQUAL(true, pView2
->GetViewFrame()->GetDispatcher()->IsLocked());
1841 CPPUNIT_ASSERT_EQUAL(false, pView1
->GetViewFrame()->GetDispatcher()->IsLocked());
1843 pRefWindow
->GetController()->response(RET_CANCEL
);
1845 CPPUNIT_ASSERT_EQUAL(false, pView2
->GetViewFrame()->GetDispatcher()->IsLocked());
1846 CPPUNIT_ASSERT_EQUAL(false, pView1
->GetViewFrame()->GetDispatcher()->IsLocked());
1848 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1849 SfxLokHelper::setView(nView1
);
1850 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1853 void ScTiledRenderingTest::testFunctionDlg()
1855 createDoc("empty.ods");
1858 SfxViewShell
* pView1
= SfxViewShell::Current();
1859 int nView1
= SfxLokHelper::getView();
1861 pView1
->GetViewFrame()->GetDispatcher()->Execute(SID_OPENDLG_FUNCTION
,
1862 SfxCallMode::SLOT
|SfxCallMode::RECORD
);
1864 Scheduler::ProcessEventsToIdle();
1865 SfxChildWindow
* pRefWindow
= pView1
->GetViewFrame()->GetChildWindow(SID_OPENDLG_FUNCTION
);
1866 CPPUNIT_ASSERT(pRefWindow
);
1869 int nView2
= SfxLokHelper::createView();
1870 SfxViewShell
* pView2
= SfxViewShell::Current();
1871 CPPUNIT_ASSERT(pView1
!= pView2
);
1874 CPPUNIT_ASSERT_EQUAL(true, pView1
->GetViewFrame()->GetDispatcher()->IsLocked());
1875 CPPUNIT_ASSERT_EQUAL(false, pView2
->GetViewFrame()->GetDispatcher()->IsLocked());
1877 SfxLokHelper::setView(nView1
);
1878 pRefWindow
->GetController()->response(RET_CANCEL
);
1880 CPPUNIT_ASSERT_EQUAL(false, pView1
->GetViewFrame()->GetDispatcher()->IsLocked());
1881 CPPUNIT_ASSERT_EQUAL(false, pView2
->GetViewFrame()->GetDispatcher()->IsLocked());
1883 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1884 SfxLokHelper::setView(nView2
);
1885 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1888 void ScTiledRenderingTest::testSpellOnlineParameter()
1890 ScModelObj
* pModelObj
= createDoc("empty.ods");
1891 ScDocument
* pDoc
= pModelObj
->GetDocument();
1892 bool bSet
= pDoc
->GetDocOptions().IsAutoSpell();
1894 uno::Sequence
<beans::PropertyValue
> params
=
1896 comphelper::makePropertyValue("Enable", uno::Any(!bSet
)),
1898 dispatchCommand(mxComponent
, ".uno:SpellOnline", params
);
1899 CPPUNIT_ASSERT_EQUAL(!bSet
, pDoc
->GetDocOptions().IsAutoSpell());
1901 // set the same state as now and we don't expect any change (no-toggle)
1904 comphelper::makePropertyValue("Enable", uno::Any(!bSet
)),
1906 dispatchCommand(mxComponent
, ".uno:SpellOnline", params
);
1907 CPPUNIT_ASSERT_EQUAL(!bSet
, pDoc
->GetDocOptions().IsAutoSpell());
1910 void ScTiledRenderingTest::testVbaRangeCopyPaste()
1912 ScModelObj
* pModelObj
= createDoc("RangeCopyPaste.ods");
1913 ScDocShell
* pDocShell
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
1914 CPPUNIT_ASSERT(pDocShell
);
1917 uno::Sequence
< uno::Any
> aOutParam
;
1918 uno::Sequence
< uno::Any
> aParams
;
1919 uno::Sequence
< sal_Int16
> aOutParamIndex
;
1921 SfxObjectShell::CallXScript(
1923 "vnd.sun.Star.script:Standard.Module1.Test_RangeCopyPaste?language=Basic&location=document",
1924 aParams
, aRet
, aOutParamIndex
, aOutParam
);
1926 CPPUNIT_ASSERT(!pDocShell
->GetClipData().is());
1929 void ScTiledRenderingTest::testInvalidationLoop()
1931 // Load the document with a form control.
1932 createDoc("invalidation-loop.fods");
1933 // Without the accompanying fix in place, this test would have never returned due to an infinite
1934 // invalidation loop between ScGridWindow::Paint() and vcl::Window::ImplPosSizeWindow().
1935 Scheduler::ProcessEventsToIdle();
1938 void ScTiledRenderingTest::testPageDownInvalidation()
1940 ScModelObj
* pModelObj
= createDoc("empty.ods");
1941 ScViewData
* pViewData
= ScDocShell::GetViewData();
1942 CPPUNIT_ASSERT(pViewData
);
1944 int nView1
= SfxLokHelper::getView();
1945 ViewCallback aView1
;
1946 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
1948 SfxLokHelper::setView(nView1
);
1949 aView1
.m_bInvalidateTiles
= false;
1950 aView1
.m_aInvalidations
.clear();
1951 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, awt::Key::PAGEDOWN
, 0);
1952 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, awt::Key::PAGEDOWN
, 0);
1953 Scheduler::ProcessEventsToIdle();
1954 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
1955 CPPUNIT_ASSERT_EQUAL(size_t(3), aView1
.m_aInvalidations
.size());
1956 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(15, 15, 1230, 225), aView1
.m_aInvalidations
[0]);
1959 void ScTiledRenderingTest::testSheetChangeInvalidation()
1961 const bool oldPartInInvalidation
= comphelper::LibreOfficeKit::isPartInInvalidation();
1962 comphelper::LibreOfficeKit::setPartInInvalidation(true);
1964 ScModelObj
* pModelObj
= createDoc("two_sheets.ods");
1965 ScDocument
* pDoc
= pModelObj
->GetDocument();
1966 ScViewData
* pViewData
= ScDocShell::GetViewData();
1967 CPPUNIT_ASSERT(pViewData
);
1969 int nView1
= SfxLokHelper::getView();
1970 ViewCallback aView1
;
1971 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
1973 SfxLokHelper::setView(nView1
);
1974 aView1
.m_bInvalidateTiles
= false;
1975 aView1
.m_aInvalidations
.clear();
1976 aView1
.m_aInvalidationsParts
.clear();
1977 aView1
.m_aInvalidationsMode
.clear();
1978 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
1979 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
1980 Scheduler::ProcessEventsToIdle();
1981 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
1982 CPPUNIT_ASSERT_EQUAL(size_t(2), aView1
.m_aInvalidations
.size());
1983 const ScSheetLimits
& rLimits
= pDoc
->GetSheetLimits();
1984 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(0, 0, 1280 * rLimits
.GetMaxColCount(),
1985 256 * rLimits
.GetMaxRowCount()),
1986 aView1
.m_aInvalidations
[0]);
1987 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(0, 0, 1000000000, 1000000000), aView1
.m_aInvalidations
[1]);
1988 CPPUNIT_ASSERT_EQUAL(size_t(2), aView1
.m_aInvalidationsParts
.size());
1989 CPPUNIT_ASSERT_EQUAL(pModelObj
->getPart(), aView1
.m_aInvalidationsParts
[0]);
1990 CPPUNIT_ASSERT_EQUAL(pModelObj
->getPart(), aView1
.m_aInvalidationsParts
[1]);
1991 CPPUNIT_ASSERT_EQUAL(size_t(2), aView1
.m_aInvalidationsMode
.size());
1992 CPPUNIT_ASSERT_EQUAL(pModelObj
->getEditMode(), aView1
.m_aInvalidationsMode
[0]);
1993 CPPUNIT_ASSERT_EQUAL(pModelObj
->getEditMode(), aView1
.m_aInvalidationsMode
[1]);
1994 comphelper::LibreOfficeKit::setPartInInvalidation(oldPartInInvalidation
);
1997 void ScTiledRenderingTest::testInsertDeletePageInvalidation()
1999 ScModelObj
* pModelObj
= createDoc("insert_delete_sheet.ods");
2000 // the document has 1 sheet
2001 CPPUNIT_ASSERT_EQUAL(1, pModelObj
->getParts());
2002 ScViewData
* pViewData
= ScDocShell::GetViewData();
2003 CPPUNIT_ASSERT(pViewData
);
2005 int nView1
= SfxLokHelper::getView();
2006 ViewCallback aView1
;
2007 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
2009 SfxLokHelper::setView(nView1
);
2010 aView1
.m_bInvalidateTiles
= false;
2011 aView1
.m_aInvalidations
.clear();
2013 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
2014 { "Name", uno::Any(OUString("")) },
2015 { "Index", uno::Any(sal_Int32(1)) }
2017 dispatchCommand(mxComponent
, ".uno:Insert", aArgs
);
2018 Scheduler::ProcessEventsToIdle();
2019 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
2020 CPPUNIT_ASSERT_EQUAL(size_t(6), aView1
.m_aInvalidations
.size());
2021 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(0, 0, 1000000000, 1000000000), aView1
.m_aInvalidations
[0]);
2022 CPPUNIT_ASSERT_EQUAL(2, pModelObj
->getParts());
2025 aView1
.m_bInvalidateTiles
= false;
2026 aView1
.m_aInvalidations
.clear();
2027 uno::Sequence
<beans::PropertyValue
> aArgs2( comphelper::InitPropertySequence({
2028 { "Index", uno::Any(sal_Int32(1)) }
2030 dispatchCommand(mxComponent
, ".uno:Remove", aArgs2
);
2031 Scheduler::ProcessEventsToIdle();
2032 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
2033 CPPUNIT_ASSERT_EQUAL(size_t(5), aView1
.m_aInvalidations
.size());
2034 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(0, 0, 1000000000, 1000000000), aView1
.m_aInvalidations
[0]);
2035 CPPUNIT_ASSERT_EQUAL(1, pModelObj
->getParts());
2038 void ScTiledRenderingTest::testGetRowColumnHeadersInvalidation()
2040 ScModelObj
* pModelObj
= createDoc("empty.ods");
2041 ScViewData
* pViewData
= ScDocShell::GetViewData();
2042 CPPUNIT_ASSERT(pViewData
);
2044 int nView1
= SfxLokHelper::getView();
2045 ViewCallback aView1
;
2046 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
2048 SfxLokHelper::setView(nView1
);
2049 aView1
.m_bInvalidateTiles
= false;
2050 aView1
.m_aInvalidations
.clear();
2051 tools::JsonWriter aJsonWriter1
;
2052 pModelObj
->getRowColumnHeaders(tools::Rectangle(0, 15, 19650, 5400), aJsonWriter1
);
2053 free(aJsonWriter1
.extractData());
2054 Scheduler::ProcessEventsToIdle();
2055 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
2056 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
2057 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(26775, 0, 49725, 13005), aView1
.m_aInvalidations
[0]);
2059 // Extend area top-to-bottom
2060 aView1
.m_bInvalidateTiles
= false;
2061 aView1
.m_aInvalidations
.clear();
2062 tools::JsonWriter aJsonWriter2
;
2063 pModelObj
->getRowColumnHeaders(tools::Rectangle(0, 5400, 19650, 9800), aJsonWriter2
);
2064 free(aJsonWriter2
.extractData());
2065 Scheduler::ProcessEventsToIdle();
2066 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
2067 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
2068 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(0, 13005, 49725, 19380), aView1
.m_aInvalidations
[0]);
2070 // Extend area left-to-right
2071 aView1
.m_bInvalidateTiles
= false;
2072 aView1
.m_aInvalidations
.clear();
2073 tools::JsonWriter aJsonWriter3
;
2074 pModelObj
->getRowColumnHeaders(tools::Rectangle(5400, 5400, 25050, 9800), aJsonWriter3
);
2075 free(aJsonWriter3
.extractData());
2076 Scheduler::ProcessEventsToIdle();
2077 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
2078 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
2079 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(49725, 0, 75225, 19380), aView1
.m_aInvalidations
[0]);
2082 void ScTiledRenderingTest::testJumpHorizontallyInvalidation()
2084 ScModelObj
* pModelObj
= createDoc("empty.ods");
2085 ScViewData
* pViewData
= ScDocShell::GetViewData();
2086 CPPUNIT_ASSERT(pViewData
);
2088 int nView1
= SfxLokHelper::getView();
2089 ViewCallback aView1
;
2090 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
2092 SfxLokHelper::setView(nView1
);
2093 aView1
.m_bInvalidateTiles
= false;
2094 aView1
.m_aInvalidations
.clear();
2095 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
| KEY_MOD2
);
2096 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
| KEY_MOD2
);
2097 Scheduler::ProcessEventsToIdle();
2098 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
| KEY_MOD2
);
2099 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
| KEY_MOD2
);
2100 Scheduler::ProcessEventsToIdle();
2101 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
2102 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
2103 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(26775, 0, 39525, 13005), aView1
.m_aInvalidations
[0]);
2106 void ScTiledRenderingTest::testJumpToLastRowInvalidation()
2108 ScModelObj
* pModelObj
= createDoc("empty.ods");
2109 ScViewData
* pViewData
= ScDocShell::GetViewData();
2110 CPPUNIT_ASSERT(pViewData
);
2112 int nView1
= SfxLokHelper::getView();
2113 ViewCallback aView1
;
2114 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
2116 SfxLokHelper::setView(nView1
);
2117 aView1
.m_bInvalidateTiles
= false;
2118 aView1
.m_aInvalidations
.clear();
2119 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DOWN
| KEY_MOD1
);
2120 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DOWN
| KEY_MOD1
);
2121 Scheduler::ProcessEventsToIdle();
2122 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
2123 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
2124 // 261375 because we limit how far we jump into empty space in online, 267386880 if we don't limit
2125 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(0, 13005, 26775, 261375), aView1
.m_aInvalidations
[0]);
2128 // We need to ensure that views are not perterbed by rendering (!?) hmm ...
2129 void ScTiledRenderingTest::testRowColumnHeaders()
2131 ScModelObj
* pModelObj
= createDoc("empty.ods");
2132 ScViewData
* pViewData
= ScDocShell::GetViewData();
2133 CPPUNIT_ASSERT(pViewData
);
2136 ViewCallback aView1
;
2137 int nView1
= SfxLokHelper::getView();
2138 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
2141 SfxLokHelper::createView();
2142 int nView2
= SfxLokHelper::getView();
2143 ViewCallback aView2
;
2144 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
2146 // ViewRowColumnHeaders test
2147 SfxLokHelper::setView(nView1
);
2148 tools::JsonWriter aJsonWriter1
;
2149 pModelObj
->getRowColumnHeaders(tools::Rectangle(65,723,10410,4695), aJsonWriter1
);
2150 OString aHeaders1
= aJsonWriter1
.extractAsOString();
2152 SfxLokHelper::setView(nView2
);
2154 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 22474, 47333));
2155 pModelObj
->setClientZoom(256, 256, 6636, 6636);
2156 tools::JsonWriter aJsonWriter2
;
2157 pModelObj
->getRowColumnHeaders(tools::Rectangle(65,723,10410,4695), aJsonWriter2
);
2158 OString aHeaders2
= aJsonWriter2
.extractAsOString();
2160 // Check vs. view #1
2161 SfxLokHelper::setView(nView1
);
2162 tools::JsonWriter aJsonWriter3
;
2163 pModelObj
->getRowColumnHeaders(tools::Rectangle(65,723,10410,4695), aJsonWriter3
);
2164 OString aHeaders1_2
= aJsonWriter3
.extractAsOString();
2165 CPPUNIT_ASSERT_EQUAL(aHeaders1
, aHeaders1_2
);
2167 // Check vs. view #2
2168 SfxLokHelper::setView(nView2
);
2169 tools::JsonWriter aJsonWriter4
;
2170 pModelObj
->getRowColumnHeaders(tools::Rectangle(65,723,10410,4695), aJsonWriter4
);
2171 OString aHeaders2_2
= aJsonWriter4
.extractAsOString();
2172 CPPUNIT_ASSERT_EQUAL(aHeaders2
, aHeaders2_2
);
2174 SfxLokHelper::setView(nView1
);
2175 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2176 SfxLokHelper::setView(nView2
);
2177 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2180 // Helper structs for setup and testing of ScModelObj::getSheetGeometryData()
2189 typedef std::vector
<SpanEntry
> SpanList
;
2193 // TODO: Add group info too to test.
2195 void setDataToDoc(ScDocument
* pDoc
, bool bCol
) const
2197 SCCOLROW nStart
= 0;
2199 for (const auto& rSpan
: aSizes
)
2203 for (SCCOLROW nIdx
= nStart
; nIdx
<= rSpan
.nEnd
; ++nIdx
)
2204 pDoc
->SetColWidthOnly(nIdx
, 0, rSpan
.nVal
);
2207 pDoc
->SetRowHeightOnly(nStart
, rSpan
.nEnd
, 0, rSpan
.nVal
);
2209 nStart
= rSpan
.nEnd
+ 1;
2214 for (const auto& rSpan
: aHidden
)
2217 pDoc
->SetColHidden(nStart
, rSpan
.nEnd
, 0, !!rSpan
.nVal
);
2219 pDoc
->SetRowHidden(nStart
, rSpan
.nEnd
, 0, !!rSpan
.nVal
);
2221 nStart
= rSpan
.nEnd
+ 1;
2224 // There is no ScDocument interface to set ScTable::mpFilteredCols
2225 // It seems ScTable::mpFilteredCols is not really used !?
2231 for (const auto& rSpan
: aFiltered
)
2233 pDoc
->SetRowFiltered(nStart
, rSpan
.nEnd
, 0, !!rSpan
.nVal
);
2234 nStart
= rSpan
.nEnd
+ 1;
2238 void testPropertyTree(const boost::property_tree::ptree
& rTree
, bool bCol
) const
2240 struct SpanListWithKey
2243 const SpanList
& rSpanList
;
2246 const SpanListWithKey aPairList
[] = {
2247 { "sizes", aSizes
},
2248 { "hidden", aHidden
},
2249 { "filtered", aFiltered
}
2252 for (const auto& rEntry
: aPairList
)
2254 // There is no ScDocument interface to set ScTable::mpFilteredCols
2255 // It seems ScTable::mpFilteredCols is not really used !?
2256 if (bCol
&& rEntry
.aKey
== "filtered")
2259 bool bBooleanValue
= rEntry
.aKey
!= "sizes";
2260 OString aExpectedEncoding
;
2262 for (const auto& rSpan
: rEntry
.rSpanList
)
2264 size_t nVal
= rSpan
.nVal
;
2265 if (bBooleanValue
&& bFirst
)
2266 nVal
= static_cast<size_t>(!!nVal
);
2267 if (!bBooleanValue
|| bFirst
)
2268 aExpectedEncoding
+= OString::number(nVal
) + ":";
2269 aExpectedEncoding
+= OString::number(rSpan
.nEnd
) + " ";
2273 // Get the tree's value for the property key ("sizes"/"hidden"/"filtered").
2274 OString aTreeValue
= rTree
.get
<std::string
>(rEntry
.aKey
.getStr()).c_str();
2276 CPPUNIT_ASSERT_EQUAL(aExpectedEncoding
, aTreeValue
);
2281 class SheetGeometryData
2288 SheetGeometryData(const SheetDimData
& rCols
, const SheetDimData
& rRows
) :
2289 aCols(rCols
), aRows(rRows
)
2292 void setDataToDoc(ScDocument
* pDoc
) const
2294 aCols
.setDataToDoc(pDoc
, true);
2295 aRows
.setDataToDoc(pDoc
, false);
2298 void parseTest(const OString
& rJSON
) const
2300 // Assumes all flags passed to getSheetGeometryData() are true.
2301 boost::property_tree::ptree aTree
;
2302 std::stringstream
aStream(rJSON
.getStr());
2303 boost::property_tree::read_json(aStream
, aTree
);
2305 CPPUNIT_ASSERT_EQUAL(OString(".uno:SheetGeometryData"), OString(aTree
.get
<std::string
>("commandName").c_str()));
2307 aCols
.testPropertyTree(aTree
.get_child("columns"), true);
2308 aRows
.testPropertyTree(aTree
.get_child("rows"), false);
2312 // getSheetGeometryData() should return the exact same message
2313 // irrespective of client zoom and view-area. Switching views
2314 // should also not alter it.
2315 void ScTiledRenderingTest::testSheetGeometryDataInvariance()
2317 ScModelObj
* pModelObj
= createDoc("empty.ods");
2318 ScDocument
* pDoc
= pModelObj
->GetDocument();
2319 const SheetGeometryData
aSGData(
2324 { STD_COL_WIDTH
, 20 },
2325 { 2*STD_COL_WIDTH
, 26 },
2326 { STD_COL_WIDTH
, pDoc
->MaxCol() }
2333 { 0, pDoc
->MaxCol() }
2340 { 0, pDoc
->MaxCol() }
2350 { 300, pDoc
->MaxRow() }
2358 { 0, pDoc
->MaxRow() }
2365 { 0, pDoc
->MaxRow() }
2370 ScViewData
* pViewData
= ScDocShell::GetViewData();
2371 CPPUNIT_ASSERT(pViewData
);
2374 ViewCallback aView1
;
2375 int nView1
= SfxLokHelper::getView();
2378 SfxLokHelper::createView();
2379 int nView2
= SfxLokHelper::getView();
2380 ViewCallback aView2
;
2381 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
2383 // Try with the default empty document once (nIdx = 0) and then with sheet geometry settings (nIdx = 1)
2384 for (size_t nIdx
= 0; nIdx
< 2; ++nIdx
)
2387 aSGData
.setDataToDoc(pDoc
);
2389 SfxLokHelper::setView(nView1
);
2390 OString aGeomStr1
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
2391 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
2393 SfxLokHelper::setView(nView2
);
2394 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 22474, 47333));
2395 pModelObj
->setClientZoom(256, 256, 6636, 6636);
2396 OString aGeomStr2
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
2397 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
2399 // Check vs. view #1
2400 SfxLokHelper::setView(nView1
);
2401 OString aGeomStr1_2
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
2402 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
2403 CPPUNIT_ASSERT_EQUAL(aGeomStr1
, aGeomStr1_2
);
2405 // Check vs. view #2
2406 SfxLokHelper::setView(nView2
);
2407 OString aGeomStr2_2
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
2408 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
2409 CPPUNIT_ASSERT_EQUAL(aGeomStr2
, aGeomStr2_2
);
2412 SfxLokHelper::setView(nView1
);
2413 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2414 SfxLokHelper::setView(nView2
);
2415 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2418 void ScTiledRenderingTest::testSheetGeometryDataCorrectness()
2420 ScModelObj
* pModelObj
= createDoc("empty.ods");
2421 ScDocument
* pDoc
= pModelObj
->GetDocument();
2422 const SheetGeometryData
aDefaultSGData(
2426 { { STD_COL_WIDTH
, pDoc
->MaxCol() } },
2428 { { 0, pDoc
->MaxCol() } },
2430 { { 0, pDoc
->MaxCol() } }
2435 { { ScGlobal::nStdRowHeight
, pDoc
->MaxRow() } },
2437 { { 0, pDoc
->MaxRow() } },
2439 { { 0, pDoc
->MaxRow() } }
2443 const SheetGeometryData
aSGData(
2448 { STD_COL_WIDTH
, 20 },
2449 { 2*STD_COL_WIDTH
, 26 },
2450 { STD_COL_WIDTH
, pDoc
->MaxCol() }
2457 { 0, pDoc
->MaxCol() }
2464 { 0, pDoc
->MaxCol() }
2474 { 300, pDoc
->MaxRow() }
2482 { 0, pDoc
->MaxRow() }
2489 { 0, pDoc
->MaxRow() }
2494 ScViewData
* pViewData
= ScDocShell::GetViewData();
2495 CPPUNIT_ASSERT(pViewData
);
2498 ViewCallback aView1
;
2500 // with the default empty sheet and test the JSON encoding.
2501 OString aGeomDefaultStr
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
2502 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
2503 aDefaultSGData
.parseTest(aGeomDefaultStr
);
2505 // Apply geometry settings to the sheet and then test the resulting JSON encoding.
2506 aSGData
.setDataToDoc(pDoc
);
2507 OString aGeomStr
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
2508 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
2509 aSGData
.parseTest(aGeomStr
);
2511 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2514 void ScTiledRenderingTest::testDeleteCellMultilineContent()
2516 ScModelObj
* pModelObj
= createDoc("multiline.ods");
2517 CPPUNIT_ASSERT(pModelObj
);
2518 ScViewData
* pViewData
= ScDocShell::GetViewData();
2519 CPPUNIT_ASSERT(pViewData
);
2520 ScDocShell
* pDocSh
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
2521 CPPUNIT_ASSERT(pDocSh
);
2524 ViewCallback aView1
;
2525 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
2527 aView1
.m_sInvalidateHeader
= "";
2528 ScDocument
& rDoc
= pDocSh
->GetDocument();
2529 sal_uInt16 nRow1Height
= rDoc
.GetRowHeight(static_cast<SCROW
>(0), static_cast<SCTAB
>(0), false);
2531 // delete multiline cell content in view #1
2532 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DOWN
);
2533 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DOWN
);
2534 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DELETE
);
2535 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DELETE
);
2536 Scheduler::ProcessEventsToIdle();
2538 // check if the row header has been invalidated and if the involved row is of the expected height
2539 CPPUNIT_ASSERT_EQUAL(OString("row"), aView1
.m_sInvalidateHeader
);
2540 sal_uInt16 nRow2Height
= rDoc
.GetRowHeight(static_cast<SCROW
>(0), static_cast<SCTAB
>(0), false);
2541 CPPUNIT_ASSERT_EQUAL(nRow1Height
, nRow2Height
);
2542 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2545 void ScTiledRenderingTest::testPasteIntoWrapTextCell()
2547 comphelper::LibreOfficeKit::setCompatFlag(
2548 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
2550 ScModelObj
* pModelObj
= createDoc("empty.ods");
2551 CPPUNIT_ASSERT(pModelObj
);
2552 ScDocument
* pDoc
= pModelObj
->GetDocument();
2554 // Set Wrap text in A3
2555 pDoc
->ApplyAttr(0, 2, 0, ScLineBreakCell(true));
2556 const ScLineBreakCell
* pItem
= pDoc
->GetAttr(0, 2, 0, ATTR_LINEBREAK
);
2557 CPPUNIT_ASSERT(pItem
->GetValue());
2559 ScViewData
* pViewData
= ScDocShell::GetViewData();
2560 CPPUNIT_ASSERT(pViewData
);
2563 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
2565 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2566 CPPUNIT_ASSERT(pView
);
2568 // create source text in A1
2569 OUString
sCopyContent("Very long text to copy");
2570 pDoc
->SetString(0, 0, 0, sCopyContent
);
2573 pView
->SetCursor(0, 0);
2574 Scheduler::ProcessEventsToIdle();
2575 pView
->GetViewFrame()->GetBindings().Execute(SID_COPY
);
2576 Scheduler::ProcessEventsToIdle();
2579 uno::Reference
<datatransfer::clipboard::XClipboard
> xClipboard1
= pView
->GetViewData().GetActiveWin()->GetClipboard();
2580 uno::Reference
< datatransfer::XTransferable
> xDataObj
=
2581 xClipboard1
->getContents();
2582 datatransfer::DataFlavor aFlavor
;
2583 SotExchange::GetFormatDataFlavor(SotClipboardFormatId::STRING
, aFlavor
);
2584 uno::Any aData
= xDataObj
->getTransferData(aFlavor
);
2587 CPPUNIT_ASSERT_EQUAL(sCopyContent
, aTmpText
.trim());
2589 // Go to A2 and paste.
2590 pView
->SetCursor(0, 1);
2591 Scheduler::ProcessEventsToIdle();
2592 aView
.m_sInvalidateSheetGeometry
= "";
2593 pView
->GetViewFrame()->GetBindings().Execute(SID_PASTE
);
2594 Scheduler::ProcessEventsToIdle();
2596 CPPUNIT_ASSERT_EQUAL(sCopyContent
, pDoc
->GetString(0, 1, 0));
2597 CPPUNIT_ASSERT_EQUAL(OString("rows sizes"), aView
.m_sInvalidateSheetGeometry
);
2599 // create new source text in A2
2600 OUString
sCopyContent2("Very long text to copy 2");
2601 pDoc
->SetString(0, 1, 0, sCopyContent2
);
2602 Scheduler::ProcessEventsToIdle();
2605 pView
->GetViewFrame()->GetBindings().Execute(SID_CUT
);
2606 Scheduler::ProcessEventsToIdle();
2609 uno::Reference
<datatransfer::clipboard::XClipboard
> xClipboard2
2610 = pView
->GetViewData().GetActiveWin()->GetClipboard();
2611 xDataObj
= xClipboard2
->getContents();
2612 SotExchange::GetFormatDataFlavor(SotClipboardFormatId::STRING
, aFlavor
);
2613 aData
= xDataObj
->getTransferData(aFlavor
);
2615 CPPUNIT_ASSERT_EQUAL(xClipboard1
, xClipboard2
);
2616 CPPUNIT_ASSERT_EQUAL(sCopyContent2
, aTmpText
.trim());
2618 // Go to A3 and paste.
2619 pView
->SetCursor(0, 2);
2620 Scheduler::ProcessEventsToIdle();
2621 aView
.m_sInvalidateSheetGeometry
= "";
2622 pView
->GetViewFrame()->GetBindings().Execute(SID_PASTE
);
2623 Scheduler::ProcessEventsToIdle();
2625 // SG invalidations for all
2626 CPPUNIT_ASSERT_EQUAL(sCopyContent2
, pDoc
->GetString(0, 1, 0));
2627 CPPUNIT_ASSERT_EQUAL(OString("all"), aView
.m_sInvalidateSheetGeometry
);
2629 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2632 void ScTiledRenderingTest::testSortAscendingDescending()
2634 comphelper::LibreOfficeKit::setCompatFlag(
2635 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
2636 ScModelObj
* pModelObj
= createDoc("sort-range.ods");
2637 ScDocument
* pDoc
= pModelObj
->GetDocument();
2641 // select the values in the first column
2642 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
, 551, 129, 1, MOUSE_LEFT
, 0);
2643 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEMOVE
, 820, 1336, 1, MOUSE_LEFT
, 0);
2644 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
, 820, 1359, 1, MOUSE_LEFT
, 0);
2645 Scheduler::ProcessEventsToIdle();
2646 aView
.m_sInvalidateSheetGeometry
= "";
2649 uno::Sequence
<beans::PropertyValue
> aArgs
;
2650 dispatchCommand(mxComponent
, ".uno:SortAscending", aArgs
);
2652 // check it's sorted
2653 for (SCROW r
= 0; r
< 6; ++r
)
2655 CPPUNIT_ASSERT_EQUAL(double(r
+ 1), pDoc
->GetValue(ScAddress(0, r
, 0)));
2658 Scheduler::ProcessEventsToIdle();
2659 CPPUNIT_ASSERT_EQUAL(OString("rows"), aView
.m_sInvalidateSheetGeometry
);
2661 aView
.m_sInvalidateSheetGeometry
= "";
2663 dispatchCommand(mxComponent
, ".uno:SortDescending", aArgs
);
2665 // check it's sorted
2666 for (SCROW r
= 0; r
< 6; ++r
)
2668 CPPUNIT_ASSERT_EQUAL(double(6 - r
), pDoc
->GetValue(ScAddress(0, r
, 0)));
2671 // nothing else was sorted
2672 CPPUNIT_ASSERT_EQUAL(double(1), pDoc
->GetValue(ScAddress(1, 0, 0)));
2673 CPPUNIT_ASSERT_EQUAL(double(3), pDoc
->GetValue(ScAddress(1, 1, 0)));
2674 CPPUNIT_ASSERT_EQUAL(double(2), pDoc
->GetValue(ScAddress(1, 2, 0)));
2676 Scheduler::ProcessEventsToIdle();
2677 CPPUNIT_ASSERT_EQUAL(OString("rows"), aView
.m_sInvalidateSheetGeometry
);
2680 void lcl_typeCharsInCell(const std::string
& aStr
, SCCOL nCol
, SCROW nRow
, ScTabViewShell
* pView
,
2681 ScModelObj
* pModelObj
, bool bInEdit
= false, bool bCommit
= true)
2684 pView
->SetCursor(nCol
, nRow
);
2686 for (const char& cChar
: aStr
)
2688 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, cChar
, 0);
2689 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, cChar
, 0);
2690 Scheduler::ProcessEventsToIdle();
2695 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
2696 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
2697 Scheduler::ProcessEventsToIdle();
2701 void ScTiledRenderingTest::testAutoInputStringBlock()
2703 ScModelObj
* pModelObj
= createDoc("empty.ods");
2704 CPPUNIT_ASSERT(pModelObj
);
2705 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2706 CPPUNIT_ASSERT(pView
);
2707 ScDocument
* pDoc
= pModelObj
->GetDocument();
2709 pDoc
->SetString(ScAddress(0, 3, 0), "ABC"); // A4
2710 pDoc
->SetString(ScAddress(0, 4, 0), "BAC"); // A5
2711 ScFieldEditEngine
& rEE
= pDoc
->GetEditEngine();
2713 pDoc
->SetEditText(ScAddress(0, 5, 0), rEE
.CreateTextObject()); // A6
2714 pDoc
->SetValue(ScAddress(0, 6, 0), 123);
2715 pDoc
->SetString(ScAddress(0, 7, 0), "ZZZ"); // A8
2717 ScAddress
aA1(0, 0, 0);
2718 lcl_typeCharsInCell("X", aA1
.Col(), aA1
.Row(), pView
, pModelObj
); // Type 'X' in A1
2719 CPPUNIT_ASSERT_EQUAL_MESSAGE("A1 should autocomplete", OUString("XYZ"), pDoc
->GetString(aA1
));
2721 ScAddress
aA3(0, 2, 0); // Adjacent to the string "superblock" A4:A8
2722 lcl_typeCharsInCell("X", aA3
.Col(), aA3
.Row(), pView
, pModelObj
); // Type 'X' in A3
2723 CPPUNIT_ASSERT_EQUAL_MESSAGE("A3 should autocomplete", OUString("XYZ"), pDoc
->GetString(aA3
));
2725 ScAddress
aA9(0, 8, 0); // Adjacent to the string "superblock" A4:A8
2726 lcl_typeCharsInCell("X", aA9
.Col(), aA9
.Row(), pView
, pModelObj
); // Type 'X' in A9
2727 CPPUNIT_ASSERT_EQUAL_MESSAGE("A9 should autocomplete", OUString("XYZ"), pDoc
->GetString(aA9
));
2729 ScAddress
aA11(0, 10, 0);
2730 lcl_typeCharsInCell("X", aA11
.Col(), aA11
.Row(), pView
, pModelObj
); // Type 'X' in A11
2731 CPPUNIT_ASSERT_EQUAL_MESSAGE("A11 should autocomplete", OUString("XYZ"), pDoc
->GetString(aA11
));
2734 void ScTiledRenderingTest::testAutoInputExactMatch()
2736 ScModelObj
* pModelObj
= createDoc("empty.ods");
2737 CPPUNIT_ASSERT(pModelObj
);
2738 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2739 CPPUNIT_ASSERT(pView
);
2740 ScDocument
* pDoc
= pModelObj
->GetDocument();
2742 pDoc
->SetString(ScAddress(0, 1, 0), "Simple"); // A2
2743 pDoc
->SetString(ScAddress(0, 2, 0), "Simple"); // A3
2744 pDoc
->SetString(ScAddress(0, 3, 0), "Sing"); // A4
2745 ScFieldEditEngine
& rEE
= pDoc
->GetEditEngine();
2746 rEE
.SetText("Case");
2747 pDoc
->SetEditText(ScAddress(0, 4, 0), rEE
.CreateTextObject()); // A5
2748 pDoc
->SetString(ScAddress(0, 5, 0), "Time"); // A6
2749 pDoc
->SetString(ScAddress(0, 6, 0), "Castle"); // A7
2751 ScAddress
aA8(0, 7, 0);
2752 lcl_typeCharsInCell("S", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "S" in A8
2753 // Should show the partial completion "i".
2754 CPPUNIT_ASSERT_EQUAL_MESSAGE("1: A8 should have partial completion Si", OUString("Si"), pDoc
->GetString(aA8
));
2756 lcl_typeCharsInCell("Si", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "Si" in A8
2757 // Should not show any suggestions.
2758 CPPUNIT_ASSERT_EQUAL_MESSAGE("2: A8 should not show suggestions", OUString("Si"), pDoc
->GetString(aA8
));
2760 lcl_typeCharsInCell("Sim", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "Sim" in A8
2761 // Should autocomplete to "Simple" which is the only match.
2762 CPPUNIT_ASSERT_EQUAL_MESSAGE("3: A8 should autocomplete", OUString("Simple"), pDoc
->GetString(aA8
));
2764 lcl_typeCharsInCell("Sin", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "Sin" in A8
2765 // Should autocomplete to "Sing" which is the only match.
2766 CPPUNIT_ASSERT_EQUAL_MESSAGE("4: A8 should autocomplete", OUString("Sing"), pDoc
->GetString(aA8
));
2768 lcl_typeCharsInCell("C", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "C" in A8
2769 // Should show the partial completion "as".
2770 CPPUNIT_ASSERT_EQUAL_MESSAGE("5: A8 should have partial completion Cas", OUString("Cas"), pDoc
->GetString(aA8
));
2772 lcl_typeCharsInCell("Cast", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "Cast" in A8
2773 // Should autocomplete to "Castle" which is the only match.
2774 CPPUNIT_ASSERT_EQUAL_MESSAGE("6: A8 should autocomplete", OUString("Castle"), pDoc
->GetString(aA8
));
2776 lcl_typeCharsInCell("T", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "T" in A8
2777 // Should autocomplete to "Time" which is the only match.
2778 CPPUNIT_ASSERT_EQUAL_MESSAGE("7: A8 should autocomplete", OUString("Time"), pDoc
->GetString(aA8
));
2781 void ScTiledRenderingTest::testEditCursorBounds()
2783 comphelper::LibreOfficeKit::setCompatFlag(
2784 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
2785 ScModelObj
* pModelObj
= createDoc("empty.ods");
2786 ScDocument
* pDoc
= pModelObj
->GetDocument();
2789 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2790 CPPUNIT_ASSERT(pView
);
2791 comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(true);
2794 pModelObj
->setClientZoom(256, 256, 2222, 2222);
2795 pModelObj
->setClientVisibleArea(tools::Rectangle(7725, 379832, 16240, 6449));
2796 Scheduler::ProcessEventsToIdle();
2798 constexpr SCCOL nCol
= 5;
2799 constexpr SCROW nRow
= 2048;
2800 pDoc
->SetValue(ScAddress(nCol
, nRow
, 0), 123);
2802 aView
.m_bOwnCursorInvalidated
= false;
2803 // Obtain the cell bounds via cursor.
2804 pView
->SetCursor(nCol
, nRow
);
2805 Scheduler::ProcessEventsToIdle();
2807 CPPUNIT_ASSERT(aView
.m_bOwnCursorInvalidated
);
2808 CPPUNIT_ASSERT(!aView
.m_aCellCursorBounds
.IsEmpty());
2809 tools::Rectangle
aCellBounds(aView
.m_aCellCursorBounds
);
2811 aView
.m_aInvalidateCursorResult
.clear();
2812 // Enter edit mode in the same cell.
2813 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::F2
);
2814 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::F2
);
2815 Scheduler::ProcessEventsToIdle();
2817 CPPUNIT_ASSERT(!aView
.m_aInvalidateCursorResult
.empty());
2818 CPPUNIT_ASSERT_MESSAGE("Edit cursor must be in cell bounds!",
2819 aCellBounds
.Contains(aView
.m_aInvalidateCursorResult
.getBounds()));
2821 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2824 void ScTiledRenderingTest::testTextSelectionBounds()
2826 comphelper::LibreOfficeKit::setCompatFlag(
2827 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
2828 ScModelObj
* pModelObj
= createDoc("empty.ods");
2829 ScDocument
* pDoc
= pModelObj
->GetDocument();
2832 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2833 CPPUNIT_ASSERT(pView
);
2834 comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(true);
2837 pModelObj
->setClientZoom(256, 256, 2222, 2222);
2838 pModelObj
->setClientVisibleArea(tools::Rectangle(7725, 379832, 16240, 6449));
2839 Scheduler::ProcessEventsToIdle();
2841 constexpr SCCOL nCol
= 5;
2842 constexpr SCROW nRow
= 2048;
2843 pDoc
->SetValue(ScAddress(nCol
, nRow
, 0), 123);
2845 aView
.m_bOwnCursorInvalidated
= false;
2846 // Obtain the cell bounds via cursor.
2847 pView
->SetCursor(nCol
, nRow
);
2848 Scheduler::ProcessEventsToIdle();
2850 CPPUNIT_ASSERT(aView
.m_bOwnCursorInvalidated
);
2851 CPPUNIT_ASSERT(!aView
.m_aCellCursorBounds
.IsEmpty());
2852 tools::Rectangle
aCellBounds(aView
.m_aCellCursorBounds
);
2854 aView
.m_aTextSelectionResult
.clear();
2855 // Enter edit mode in the same cell and select all text.
2856 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::F2
);
2857 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::F2
);
2858 Scheduler::ProcessEventsToIdle();
2861 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_MOD1
| awt::Key::A
);
2862 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_MOD1
| awt::Key::A
);
2863 Scheduler::ProcessEventsToIdle();
2865 CPPUNIT_ASSERT(!aView
.m_aTextSelectionResult
.empty());
2866 CPPUNIT_ASSERT_MESSAGE("Text selections must be in cell bounds!",
2867 !aCellBounds
.Intersection(aView
.m_aTextSelectionResult
.getBounds(0)).IsEmpty());
2869 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2872 void ScTiledRenderingTest::testSheetViewDataCrash()
2874 ScModelObj
* pModelObj
= createDoc("empty.ods");
2877 int nView1
= SfxLokHelper::getView();
2878 SfxLokHelper::setView(nView1
);
2880 // Imitate online while creating a new sheet on empty.ods.
2881 uno::Sequence
<beans::PropertyValue
> aArgs(
2882 comphelper::InitPropertySequence({
2883 { "Name", uno::Any(OUString("NewSheet")) },
2884 { "Index", uno::Any(sal_Int32(2)) }
2886 dispatchCommand(mxComponent
, ".uno:Insert", aArgs
);
2887 Scheduler::ProcessEventsToIdle();
2888 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
2889 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
2890 Scheduler::ProcessEventsToIdle();
2891 ScTabViewShell
* pView1
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2892 CPPUNIT_ASSERT(pView1
);
2895 SfxLokHelper::createView();
2896 ScTabViewShell
* pView2
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2897 CPPUNIT_ASSERT(pView2
);
2898 Scheduler::ProcessEventsToIdle();
2900 SfxLokHelper::setView(nView1
);
2902 pView1
->SetCursor(1, 1);
2903 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DOWN
| KEY_SHIFT
);
2904 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DOWN
| KEY_SHIFT
);
2905 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DELETE
);
2906 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DELETE
);
2907 // It will crash at this point without the fix.
2908 Scheduler::ProcessEventsToIdle();
2911 void ScTiledRenderingTest::testTextBoxInsert()
2913 createDoc("empty.ods");
2914 ViewCallback aView1
;
2917 uno::Sequence
<beans::PropertyValue
> aArgs(
2918 comphelper::InitPropertySequence({
2919 { "CreateDirectly", uno::Any(true) }
2921 dispatchCommand(mxComponent
, ".uno:DrawText", aArgs
);
2922 Scheduler::ProcessEventsToIdle();
2924 // check if we have textbox selected
2925 CPPUNIT_ASSERT(!aView1
.m_ShapeSelection
.isEmpty());
2926 CPPUNIT_ASSERT(aView1
.m_ShapeSelection
!= "EMPTY");
2928 Scheduler::ProcessEventsToIdle();
2931 void ScTiledRenderingTest::testCommentCellCopyPaste()
2933 // Comments callback are emitted only if tiled annotations are off
2934 comphelper::LibreOfficeKit::setTiledAnnotations(false);
2936 // FIXME: Hack because previous tests do not destroy ScDocument(with annotations) on exit (?).
2937 ScPostIt::mnLastPostItId
= 1;
2940 ScModelObj
* pModelObj
= createDoc("empty.ods");
2942 int nView
= SfxLokHelper::getView();
2944 SfxLokHelper::setView(nView
);
2946 ScTabViewShell
* pTabViewShell
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2947 CPPUNIT_ASSERT(pTabViewShell
);
2949 lcl_typeCharsInCell("ABC", 0, 0, pTabViewShell
, pModelObj
); // Type "ABC" in A1
2951 pTabViewShell
->SetCursor(1, 1);
2953 // Add a new comment
2954 uno::Sequence
<beans::PropertyValue
> aArgs(comphelper::InitPropertySequence(
2956 {"Text", uno::Any(OUString("LOK Comment Cell B2"))},
2957 {"Author", uno::Any(OUString("LOK Client"))},
2959 dispatchCommand(mxComponent
, ".uno:InsertAnnotation", aArgs
);
2960 Scheduler::ProcessEventsToIdle();
2962 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action
2963 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2964 CPPUNIT_ASSERT_EQUAL(std::string("1"), aView
.m_aCommentCallbackResult
.get
<std::string
>("id"));
2965 CPPUNIT_ASSERT_EQUAL(std::string("0"), aView
.m_aCommentCallbackResult
.get
<std::string
>("tab"));
2966 CPPUNIT_ASSERT_EQUAL(std::string("LOK Client"), aView
.m_aCommentCallbackResult
.get
<std::string
>("author"));
2967 CPPUNIT_ASSERT_EQUAL(std::string("LOK Comment Cell B2"), aView
.m_aCommentCallbackResult
.get
<std::string
>("text"));
2969 uno::Sequence
<beans::PropertyValue
> aCopyPasteArgs
;
2971 // We need separate tests for single cell copy-paste and cell-range copy-paste
2972 // since they hit different code paths in ScColumn methods.
2974 // Single cell(with comment) copy paste test
2976 dispatchCommand(mxComponent
, ".uno:Copy", aCopyPasteArgs
);
2977 Scheduler::ProcessEventsToIdle();
2979 pTabViewShell
->SetCursor(1, 49);
2980 Scheduler::ProcessEventsToIdle();
2981 dispatchCommand(mxComponent
, ".uno:Paste", aCopyPasteArgs
); // Paste to cell B50
2982 Scheduler::ProcessEventsToIdle();
2984 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action
2985 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2986 // Without the fix the id will be "1".
2987 CPPUNIT_ASSERT_EQUAL(std::string("2"), aView
.m_aCommentCallbackResult
.get
<std::string
>("id"));
2988 CPPUNIT_ASSERT_EQUAL(std::string("0"), aView
.m_aCommentCallbackResult
.get
<std::string
>("tab"));
2989 CPPUNIT_ASSERT_EQUAL(std::string("LOK Client"), aView
.m_aCommentCallbackResult
.get
<std::string
>("author"));
2990 CPPUNIT_ASSERT_EQUAL(std::string("LOK Comment Cell B2"), aView
.m_aCommentCallbackResult
.get
<std::string
>("text"));
2993 // Cell range (with a comment) copy paste test
2995 // Select range A1:C3
2996 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_HOME
| KEY_MOD1
);
2997 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_HOME
| KEY_MOD1
);
2998 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
| KEY_SHIFT
);
2999 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
| KEY_SHIFT
);
3000 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
| KEY_SHIFT
);
3001 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
| KEY_SHIFT
);
3002 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_RIGHT
| KEY_SHIFT
);
3003 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_RIGHT
| KEY_SHIFT
);
3004 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_RIGHT
| KEY_SHIFT
);
3005 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_RIGHT
| KEY_SHIFT
);
3006 Scheduler::ProcessEventsToIdle();
3008 dispatchCommand(mxComponent
, ".uno:Copy", aCopyPasteArgs
);
3009 Scheduler::ProcessEventsToIdle();
3011 pTabViewShell
->SetCursor(3, 49);
3012 Scheduler::ProcessEventsToIdle();
3013 dispatchCommand(mxComponent
, ".uno:Paste", aCopyPasteArgs
); // Paste to cell D50
3014 Scheduler::ProcessEventsToIdle();
3016 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action
3017 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView
.m_aCommentCallbackResult
.get
<std::string
>("action"));
3018 // Without the fix the id will be "1".
3019 CPPUNIT_ASSERT_EQUAL(std::string("3"), aView
.m_aCommentCallbackResult
.get
<std::string
>("id"));
3020 CPPUNIT_ASSERT_EQUAL(std::string("0"), aView
.m_aCommentCallbackResult
.get
<std::string
>("tab"));
3021 CPPUNIT_ASSERT_EQUAL(std::string("LOK Client"), aView
.m_aCommentCallbackResult
.get
<std::string
>("author"));
3022 CPPUNIT_ASSERT_EQUAL(std::string("LOK Comment Cell B2"), aView
.m_aCommentCallbackResult
.get
<std::string
>("text"));
3025 comphelper::LibreOfficeKit::setTiledAnnotations(true);
3028 void ScTiledRenderingTest::testInvalidEntrySave()
3030 loadFromURL(u
"validity.xlsx");
3032 // .uno:Save modifies the original file, make a copy first
3033 saveAndReload("Calc Office Open XML");
3034 ScModelObj
* pModelObj
= dynamic_cast<ScModelObj
*>(mxComponent
.get());
3035 CPPUNIT_ASSERT(pModelObj
);
3036 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
3037 const ScDocument
* pDoc
= pModelObj
->GetDocument();
3039 int nView
= SfxLokHelper::getView();
3041 SfxLokHelper::setView(nView
);
3043 ScDocShell
* pDocSh
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
3044 ScTabViewShell
* pTabViewShell
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
3045 CPPUNIT_ASSERT(pTabViewShell
);
3047 // Type partial date "7/8" of "7/8/2013" that
3048 // the validation cell at A8 can accept
3049 lcl_typeCharsInCell("7/8", 0, 7, pTabViewShell
, pModelObj
,
3050 false /* bInEdit */, false /* bCommit */); // Type "7/8" in A8
3052 uno::Sequence
<beans::PropertyValue
> aArgs
;
3053 dispatchCommand(mxComponent
, ".uno:Save", aArgs
);
3054 Scheduler::ProcessEventsToIdle();
3056 CPPUNIT_ASSERT_MESSAGE("Should not be marked modified after save", !pDocSh
->IsModified());
3058 // Complete the date in A8 by appending "/2013" and commit.
3059 lcl_typeCharsInCell("/2013", 0, 7, pTabViewShell
, pModelObj
,
3060 true /* bInEdit */, true /* bCommit */);
3062 // This would hang if the date entered "7/8/2013" is not acceptable.
3063 Scheduler::ProcessEventsToIdle();
3065 // Ensure that the correct date is recorded in the document.
3066 CPPUNIT_ASSERT_EQUAL(double(41463), pDoc
->GetValue(ScAddress(0, 7, 0)));
3069 void ScTiledRenderingTest::testUndoReordering()
3071 ScModelObj
* pModelObj
= createDoc("small.ods");
3072 CPPUNIT_ASSERT(pModelObj
);
3073 ScDocument
* pDoc
= pModelObj
->GetDocument();
3074 CPPUNIT_ASSERT(pDoc
);
3075 ScUndoManager
* pUndoManager
= pDoc
->GetUndoManager();
3076 CPPUNIT_ASSERT(pUndoManager
);
3079 int nView1
= SfxLokHelper::getView();
3080 ViewCallback aView1
;
3083 SfxLokHelper::createView();
3084 int nView2
= SfxLokHelper::getView();
3085 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
3086 ViewCallback aView2
;
3088 // text edit a cell in view #1
3089 SfxLokHelper::setView(nView1
);
3090 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
3091 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
3092 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
3093 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
3094 Scheduler::ProcessEventsToIdle();
3096 // check that undo action count is not 0
3097 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
3099 // text edit a different cell in view #2
3100 SfxLokHelper::setView(nView2
);
3101 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
);
3102 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
);
3103 Scheduler::ProcessEventsToIdle();
3104 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
);
3105 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
);
3106 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
3107 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
3108 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
3109 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
3110 Scheduler::ProcessEventsToIdle();
3112 // check that undo action count is not 1
3113 CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager
->GetUndoActionCount());
3115 // try to execute undo in view #1
3116 SfxLokHelper::setView(nView1
);
3117 dispatchCommand(mxComponent
, ".uno:Undo", {});
3118 Scheduler::ProcessEventsToIdle();
3119 // check that undo has been executed on view #1
3120 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
3122 // try to execute undo in view #2
3123 SfxLokHelper::setView(nView2
);
3124 dispatchCommand(mxComponent
, ".uno:Undo", {});
3125 Scheduler::ProcessEventsToIdle();
3126 // check that undo has been executed on view #2
3127 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetUndoActionCount());
3130 void ScTiledRenderingTest::testUndoReorderingRedo()
3132 ScModelObj
* pModelObj
= createDoc("empty.ods");
3133 CPPUNIT_ASSERT(pModelObj
);
3134 ScDocument
* pDoc
= pModelObj
->GetDocument();
3135 CPPUNIT_ASSERT(pDoc
);
3136 ScUndoManager
* pUndoManager
= pDoc
->GetUndoManager();
3137 CPPUNIT_ASSERT(pUndoManager
);
3138 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetUndoActionCount());
3141 int nView1
= SfxLokHelper::getView();
3142 SfxViewShell
* pView1
= SfxViewShell::Current();
3143 ViewCallback aView1
;
3146 SfxLokHelper::createView();
3147 int nView2
= SfxLokHelper::getView();
3148 SfxViewShell
* pView2
= SfxViewShell::Current();
3149 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
3150 ViewCallback aView2
;
3152 // text edit a cell in view #1
3153 SfxLokHelper::setView(nView1
);
3154 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
3155 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
3156 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
3157 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
3158 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
3159 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
3160 Scheduler::ProcessEventsToIdle();
3161 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
3163 // text edit another cell in view #1
3164 SfxLokHelper::setView(nView1
);
3165 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'y', 0);
3166 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'y', 0);
3167 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'y', 0);
3168 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'y', 0);
3169 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
3170 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
3171 Scheduler::ProcessEventsToIdle();
3172 CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager
->GetUndoActionCount());
3173 CPPUNIT_ASSERT_EQUAL(OUString("xx"), pDoc
->GetString(ScAddress(0, 0, 0)));
3174 CPPUNIT_ASSERT_EQUAL(OUString("yy"), pDoc
->GetString(ScAddress(0, 1, 0)));
3176 // text edit a different cell in view #2
3177 SfxLokHelper::setView(nView2
);
3178 ScTabViewShell
* pViewShell2
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
3179 pViewShell2
->SetCursor(0, 2);
3180 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'C', 0);
3181 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'C', 0);
3182 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'C', 0);
3183 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'C', 0);
3184 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
3185 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
3186 Scheduler::ProcessEventsToIdle();
3187 CPPUNIT_ASSERT_EQUAL(std::size_t(3), pUndoManager
->GetUndoActionCount());
3188 CPPUNIT_ASSERT_EQUAL(OUString("xx"), pDoc
->GetString(ScAddress(0, 0, 0)));
3189 CPPUNIT_ASSERT_EQUAL(OUString("yy"), pDoc
->GetString(ScAddress(0, 1, 0)));
3190 CPPUNIT_ASSERT_EQUAL(OUString("CC"), pDoc
->GetString(ScAddress(0, 2, 0)));
3192 // View 1 presses undo, and the second cell is erased
3193 SfxLokHelper::setView(nView1
);
3194 dispatchCommand(mxComponent
, ".uno:Undo", {});
3195 Scheduler::ProcessEventsToIdle();
3196 CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager
->GetUndoActionCount());
3197 CPPUNIT_ASSERT_EQUAL(OUString("xx"), pDoc
->GetString(ScAddress(0, 0, 0)));
3198 CPPUNIT_ASSERT_EQUAL(OUString(""), pDoc
->GetString(ScAddress(0, 1, 0)));
3199 CPPUNIT_ASSERT_EQUAL(OUString("CC"), pDoc
->GetString(ScAddress(0, 2, 0)));
3201 // Verify that the UNDO buttons/actions are still enabled
3203 SfxItemSet
aSet1(pView1
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
3204 SfxItemSet
aSet2(pView2
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
3205 pView1
->GetSlotState(SID_UNDO
, nullptr, &aSet1
);
3206 pView2
->GetSlotState(SID_UNDO
, nullptr, &aSet2
);
3207 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet1
.GetItemState(SID_UNDO
));
3208 CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem
* >(aSet1
.GetItem(SID_UNDO
)));
3209 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet2
.GetItemState(SID_UNDO
));
3210 CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem
* >(aSet2
.GetItem(SID_UNDO
)));
3213 // View 1 presses undo again, and the first cell is erased
3214 dispatchCommand(mxComponent
, ".uno:Undo", {});
3215 Scheduler::ProcessEventsToIdle();
3216 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
3217 CPPUNIT_ASSERT_EQUAL(OUString(""), pDoc
->GetString(ScAddress(0, 0, 0)));
3218 CPPUNIT_ASSERT_EQUAL(OUString(""), pDoc
->GetString(ScAddress(0, 1, 0)));
3219 CPPUNIT_ASSERT_EQUAL(OUString("CC"), pDoc
->GetString(ScAddress(0, 2, 0)));
3222 void ScTiledRenderingTest::testUndoReorderingMulti()
3224 ScModelObj
* pModelObj
= createDoc("empty.ods");
3225 CPPUNIT_ASSERT(pModelObj
);
3226 ScDocument
* pDoc
= pModelObj
->GetDocument();
3227 CPPUNIT_ASSERT(pDoc
);
3228 ScUndoManager
* pUndoManager
= pDoc
->GetUndoManager();
3229 CPPUNIT_ASSERT(pUndoManager
);
3230 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetUndoActionCount());
3233 int nView1
= SfxLokHelper::getView();
3234 ViewCallback aView1
;
3237 SfxLokHelper::createView();
3238 int nView2
= SfxLokHelper::getView();
3239 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
3240 ViewCallback aView2
;
3242 // text edit a cell in view #1
3243 SfxLokHelper::setView(nView1
);
3244 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
3245 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
3246 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
3247 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
3248 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
3249 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
3250 Scheduler::ProcessEventsToIdle();
3251 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
3253 // text edit a different cell in view #2
3254 SfxLokHelper::setView(nView2
);
3255 ScTabViewShell
* pView2
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
3256 pView2
->SetCursor(0, 2);
3257 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'C', 0);
3258 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'C', 0);
3259 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'C', 0);
3260 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'C', 0);
3261 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
3262 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
3263 Scheduler::ProcessEventsToIdle();
3264 CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager
->GetUndoActionCount());
3265 CPPUNIT_ASSERT_EQUAL(OUString("xx"), pDoc
->GetString(ScAddress(0, 0, 0)));
3266 CPPUNIT_ASSERT_EQUAL(OUString("CC"), pDoc
->GetString(ScAddress(0, 2, 0)));
3268 // and another cell in view #2
3269 pView2
->SetCursor(0, 3);
3270 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'D', 0);
3271 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'D', 0);
3272 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'D', 0);
3273 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'D', 0);
3274 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
3275 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
3276 Scheduler::ProcessEventsToIdle();
3277 CPPUNIT_ASSERT_EQUAL(std::size_t(3), pUndoManager
->GetUndoActionCount());
3278 CPPUNIT_ASSERT_EQUAL(OUString("xx"), pDoc
->GetString(ScAddress(0, 0, 0)));
3279 CPPUNIT_ASSERT_EQUAL(OUString("CC"), pDoc
->GetString(ScAddress(0, 2, 0)));
3280 CPPUNIT_ASSERT_EQUAL(OUString("DD"), pDoc
->GetString(ScAddress(0, 3, 0)));
3282 // View 1 presses undo
3283 SfxLokHelper::setView(nView1
);
3284 dispatchCommand(mxComponent
, ".uno:Undo", {});
3285 Scheduler::ProcessEventsToIdle();
3286 CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager
->GetUndoActionCount());
3287 CPPUNIT_ASSERT_EQUAL(OUString(""), pDoc
->GetString(ScAddress(0, 0, 0)));
3288 CPPUNIT_ASSERT_EQUAL(OUString("CC"), pDoc
->GetString(ScAddress(0, 2, 0)));
3289 CPPUNIT_ASSERT_EQUAL(OUString("DD"), pDoc
->GetString(ScAddress(0, 3, 0)));
3292 void ScTiledRenderingTest::testGetViewRenderState()
3294 // Add a pair of schemes, last added is the default
3295 svtools::EditableColorConfig aColorConfig
;
3296 aColorConfig
.AddScheme(u
"Dark");
3297 aColorConfig
.AddScheme(u
"Light");
3299 ScModelObj
* pModelObj
= createDoc("empty.ods");
3300 int nFirstViewId
= SfxLokHelper::getView();
3301 ViewCallback aView1
;
3303 CPPUNIT_ASSERT_EQUAL(OString(";Default"), pModelObj
->getViewRenderState());
3304 // Create a second view
3305 SfxLokHelper::createView();
3306 ViewCallback aView2
;
3307 CPPUNIT_ASSERT_EQUAL(OString(";Default"), pModelObj
->getViewRenderState());
3308 // Set second view to dark scheme
3310 uno::Sequence
<beans::PropertyValue
> aPropertyValues
= comphelper::InitPropertySequence(
3312 { "NewTheme", uno::Any(OUString("Dark")) },
3315 dispatchCommand(mxComponent
, ".uno:ChangeTheme", aPropertyValues
);
3317 CPPUNIT_ASSERT_EQUAL(OString(";Dark"), pModelObj
->getViewRenderState());
3319 // Switch back to first view and make sure it's the same
3320 SfxLokHelper::setView(nFirstViewId
);
3321 CPPUNIT_ASSERT_EQUAL(OString(";Default"), pModelObj
->getViewRenderState());
3325 * testInvalidateOnTextEditWithDifferentZoomLevels
3327 * set view 1 zoom to the passed zoom level
3328 * in view 1 type a char at the passed cell address
3329 * store invalidation rectangle
3330 * exit from in place editing (press esc)
3331 * create view 2 (keep 100% zoom)
3332 * go to the same cell address used in view 1
3333 * type a char into the cell
3334 * get invalidation rectangle for view 1
3335 * check if the invalidation rectangle is equal to the one stored previously
3337 void ScTiledRenderingTest::testInvalidateOnTextEditWithDifferentZoomLevels(const ColRowZoom
& rData
)
3339 ScModelObj
* pModelObj
= createDoc("empty.ods");
3340 CPPUNIT_ASSERT(pModelObj
);
3341 ScDocument
* pDoc
= pModelObj
->GetDocument();
3342 CPPUNIT_ASSERT(pDoc
);
3344 OUString sZoomUnoCmd
= ".uno:ZoomPlus";
3345 int nZoomLevel
= rData
.zoom
;
3348 nZoomLevel
= -nZoomLevel
;
3349 sZoomUnoCmd
= ".uno:ZoomMinus";
3353 ViewCallback aView1
;
3355 for (int i
= 0; i
< nZoomLevel
; ++i
)
3356 dispatchCommand(mxComponent
, sZoomUnoCmd
, {});
3357 Scheduler::ProcessEventsToIdle();
3359 auto* pTabViewShell1
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
3360 CPPUNIT_ASSERT(pTabViewShell1
);
3362 // enable in place editing in view 1
3363 auto& rInvalidations
= aView1
.m_aInvalidations
;
3364 pTabViewShell1
->SetCursor(rData
.col
, rData
.row
);
3365 Scheduler::ProcessEventsToIdle();
3366 aView1
.m_bInvalidateTiles
= false;
3367 rInvalidations
.clear();
3368 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
3369 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
3370 Scheduler::ProcessEventsToIdle();
3371 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
3372 CPPUNIT_ASSERT(!rInvalidations
.empty());
3373 tools::Rectangle aInvRect1
= rInvalidations
[0];
3376 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::ESCAPE
);
3377 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::ESCAPE
);
3378 Scheduler::ProcessEventsToIdle();
3381 SfxLokHelper::createView();
3382 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
3383 ViewCallback aView2
;
3384 Scheduler::ProcessEventsToIdle();
3386 auto* pTabViewShell2
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
3387 CPPUNIT_ASSERT(pTabViewShell2
);
3388 pTabViewShell2
->SetCursor(rData
.col
, rData
.row
);
3389 Scheduler::ProcessEventsToIdle();
3391 // text edit in view #2
3392 aView1
.m_bInvalidateTiles
= false;
3393 rInvalidations
.clear();
3394 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
3395 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
3396 Scheduler::ProcessEventsToIdle();
3397 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
3398 CPPUNIT_ASSERT(!rInvalidations
.empty());
3399 tools::Rectangle aInvRect2
= rInvalidations
[0];
3401 CPPUNIT_ASSERT_EQUAL_MESSAGE("Invalidation rectangle is wrong.", aInvRect1
, aInvRect2
);
3406 CPPUNIT_TEST_SUITE_REGISTRATION(ScTiledRenderingTest
);
3408 CPPUNIT_PLUGIN_IMPLEMENT();
3410 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */