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 "tiledrenderingmodeltestbase.cxx"
11 #include <test/helper/transferable.hxx>
13 #include <com/sun/star/datatransfer/clipboard/LokClipboard.hpp>
14 #include <com/sun/star/util/URLTransformer.hpp>
15 #include <comphelper/processfactory.hxx>
16 #include <comphelper/propertysequence.hxx>
17 #include <comphelper/servicehelper.hxx>
18 #include <sfx2/dispatch.hxx>
19 #include <sfx2/viewfrm.hxx>
20 #include <svl/stritem.hxx>
21 #include <svl/numformat.hxx>
22 #include <svl/zformat.hxx>
24 #include <comphelper/lok.hxx>
25 #include <comphelper/propertyvalue.hxx>
26 #include <comphelper/dispatchcommand.hxx>
27 #include <sfx2/msgpool.hxx>
28 #include <sfx2/childwin.hxx>
29 #include <sfx2/lokhelper.hxx>
30 #include <svx/svdpage.hxx>
31 #include <vcl/scheduler.hxx>
32 #include <vcl/vclevent.hxx>
33 #include <vcl/virdev.hxx>
35 #include <tools/json_writer.hxx>
37 #include <unotools/syslocaleoptions.hxx>
40 #include <scitems.hxx>
41 #include <document.hxx>
43 #include <drwlayer.hxx>
44 #include <editutil.hxx>
45 #include <undomanager.hxx>
47 static std::ostream
& operator<<(std::ostream
& os
, ViewShellId
const & id
)
49 os
<< static_cast<sal_Int32
>(id
); return os
;
53 // for passing data to testInvalidateOnTextEditWithDifferentZoomLevels
63 namespace StringHelper
65 // used by CPPUNIT_TEST_PARAMETERIZED for testInvalidateOnTextEditWithDifferentZoomLevels
67 inline std::string
toString(const ColRowZoom
& item
)
69 std::ostringstream ss
;
70 ss
<< "zoom level: " << item
.zoom
<< ", "
71 "col: " << item
.col
<< ", "
78 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testRowColumnSelections
)
80 ScModelObj
* pModelObj
= createDoc("select-row-cols.ods");
82 // Select the 5th row with no modifier
83 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
84 { "Row", uno::Any(sal_Int32(5 - 1)) },
85 { "Modifier", uno::Any(sal_uInt16(0)) }
87 dispatchCommand(mxComponent
, u
".uno:SelectRow"_ustr
, aArgs
);
89 // Check if it is selected
90 OString aResult
= apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8"_ostr
);
91 OString
aExpected("1\t2\t3\t4\t5\t6\t7\t8\t9\t10\t11\t12\t13\t14\t15\t16\t17\t18\t19\t20\t21\n"_ostr
);
92 CPPUNIT_ASSERT_EQUAL(aExpected
, aResult
);
94 // Select the 10th row with shift modifier
95 aArgs
= comphelper::InitPropertySequence({ { "Row", uno::Any(static_cast<sal_Int32
>(10 - 1)) },
96 { "Modifier", uno::Any(KEY_SHIFT
) } });
97 dispatchCommand(mxComponent
, u
".uno:SelectRow"_ustr
, aArgs
);
99 // Check if all the rows from 5th to 10th get selected
100 aResult
= apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8"_ostr
);
101 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"_ostr
;
102 CPPUNIT_ASSERT_EQUAL(aExpected
, aResult
);
104 // Select the 10th row with ctrl modifier
105 aArgs
= comphelper::InitPropertySequence({ { "Row", uno::Any(static_cast<sal_Int32
>(13 - 1)) },
106 { "Modifier", uno::Any(KEY_MOD1
) } });
107 dispatchCommand(mxComponent
, u
".uno:SelectRow"_ustr
, aArgs
);
109 // When we copy this, we don't get anything useful, but we must not crash
111 aResult
= apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8"_ostr
);
112 CPPUNIT_ASSERT_EQUAL("9"_ostr
, aResult
);
114 // TODO check that we really selected what we wanted here
116 // Select Column 5 with ctrl modifier
117 aArgs
= comphelper::InitPropertySequence({ { "Col", uno::Any(static_cast<sal_Int32
>(5 - 1)) },
118 { "Modifier", uno::Any(KEY_MOD1
) } });
119 dispatchCommand(mxComponent
, u
".uno:SelectColumn"_ustr
, aArgs
);
121 // When we copy this, we don't get anything useful, but we must not crash
123 aResult
= apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8"_ostr
);
124 CPPUNIT_ASSERT_EQUAL("1"_ostr
, aResult
);
126 // TODO check that we really selected what we wanted here
128 // Test for deselection of already selected rows
129 // First Deselect Row 13 because copy doesn't work for multiple selections
130 aArgs
= comphelper::InitPropertySequence({ { "Row", uno::Any(static_cast<sal_Int32
>(13 - 1)) },
131 { "Modifier", uno::Any(KEY_MOD1
) } });
132 dispatchCommand(mxComponent
, u
".uno:SelectRow"_ustr
, aArgs
);
135 aArgs
= comphelper::InitPropertySequence({ { "Row", uno::Any(static_cast<sal_Int32
>(10 - 1)) },
136 { "Modifier", uno::Any(KEY_MOD1
) } });
137 dispatchCommand(mxComponent
, u
".uno:SelectRow"_ustr
, aArgs
);
139 // Click at row 6 holding shift
140 aArgs
= comphelper::InitPropertySequence({ { "Row", uno::Any(static_cast<sal_Int32
>(6 - 1)) },
141 { "Modifier", uno::Any(KEY_SHIFT
) } });
142 dispatchCommand(mxComponent
, u
".uno:SelectRow"_ustr
, aArgs
);
144 // only row 5 should remain selected
145 aResult
= apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8"_ostr
);
146 aExpected
= "1\t2\t3\t4\t5\t6\t7\t8\t9\t10\t11\t12\t13\t14\t15\t16\t17\t18\t19\t20\t21\n"_ostr
;
147 CPPUNIT_ASSERT_EQUAL(aExpected
, aResult
);
150 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testPartHash
)
152 ScModelObj
* pModelObj
= createDoc("sort-range.ods");
154 int nParts
= pModelObj
->getParts();
155 for (int it
= 0; it
< nParts
; it
++)
157 CPPUNIT_ASSERT(!pModelObj
->getPartHash(it
).isEmpty());
160 // check part that it does not exists
161 CPPUNIT_ASSERT(pModelObj
->getPartHash(100).isEmpty());
164 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testDocumentSize
)
166 ScModelObj
* pModelObj
= createDoc("sort-range.ods");
167 ScDocShell
* pDocSh
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
168 CPPUNIT_ASSERT(pDocSh
);
170 ScTabViewShell
* pViewShell
= pDocSh
->GetBestViewShell(false);
171 CPPUNIT_ASSERT(pViewShell
);
173 setupLibreOfficeKitViewCallback(pViewShell
);
175 // check initial document size
176 Size aDocSize
= pModelObj
->getDocumentSize();
177 CPPUNIT_ASSERT(aDocSize
.Width() > 0);
178 CPPUNIT_ASSERT(aDocSize
.Height() > 0);
181 pViewShell
->SetCursor(100, 0);
183 osl::Condition::Result aResult
= m_aDocSizeCondition
.wait(std::chrono::seconds(2));
184 CPPUNIT_ASSERT_EQUAL(osl::Condition::result_ok
, aResult
);
187 pViewShell
->SetCursor(0, 100);
189 aResult
= m_aDocSizeCondition
.wait(std::chrono::seconds(2));
190 CPPUNIT_ASSERT_EQUAL(osl::Condition::result_ok
, aResult
);
193 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testEmptyColumnSelection
)
195 ScModelObj
* pModelObj
= createDoc("select-row-cols.ods");
197 // Select empty column, 1000
198 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
199 { "Col", uno::Any(sal_Int32(1000 - 1)) },
200 { "Modifier", uno::Any(sal_uInt16(0)) }
202 dispatchCommand(mxComponent
, u
".uno:SelectColumn"_ustr
, aArgs
);
204 // should be an empty string
205 CPPUNIT_ASSERT_EQUAL(OString(), apitest::helper::transferable::getTextSelection(pModelObj
->getSelection(), "text/plain;charset=utf-8"_ostr
));
208 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testViewCursors
)
210 ScModelObj
* pModelObj
= createDoc("select-row-cols.ods");
212 SfxLokHelper::createView();
213 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
214 ViewCallback
aView2(/*bDeleteListenerOnDestruct*/false);
215 // This was false, the new view did not get the view (cell) cursor of the old view.
216 CPPUNIT_ASSERT(aView2
.m_bViewCursorInvalidated
);
217 CPPUNIT_ASSERT(aView2
.m_bOwnCursorInvalidated
);
218 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DOWN
);
219 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DOWN
);
220 Scheduler::ProcessEventsToIdle();
221 SfxLokHelper::destroyView(SfxLokHelper::getView());
222 CPPUNIT_ASSERT(aView1
.m_bViewCursorInvalidated
);
225 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testSpellOnlineRenderParameter
)
227 ScModelObj
* pModelObj
= createDoc("empty.ods");
229 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
230 CPPUNIT_ASSERT(pView
);
232 bool bSet
= pView
->IsAutoSpell();
234 uno::Sequence
<beans::PropertyValue
> aPropertyValues
=
236 comphelper::makePropertyValue(u
".uno:SpellOnline"_ustr
, uno::Any(!bSet
)),
238 pModelObj
->initializeForTiledRendering(aPropertyValues
);
240 CPPUNIT_ASSERT_EQUAL(!bSet
, pView
->IsAutoSpell());
243 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testTextViewSelection
)
245 // Create two views, and leave the second one current.
246 ScModelObj
* pModelObj
= createDoc("select-row-cols.ods");
248 SfxLokHelper::createView();
249 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
252 // Create a selection on two cells in the second view, that's a text selection in LOK terms.
253 aView1
.m_bTextViewSelectionInvalidated
= false;
254 dispatchCommand(mxComponent
, u
".uno:GoRightSel"_ustr
, {});
255 // Make sure the first view got its notification.
256 CPPUNIT_ASSERT(aView1
.m_bTextViewSelectionInvalidated
);
259 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testDocumentSizeChanged
)
261 // Load a document that doesn't have much content.
262 createDoc("small.ods");
263 setupLibreOfficeKitViewCallback(SfxViewShell::Current());
265 // Go to the A30 cell -- that will extend the document size.
266 uno::Sequence
<beans::PropertyValue
> aPropertyValues
=
268 comphelper::makePropertyValue(u
"ToPoint"_ustr
, u
"$A$30"_ustr
),
270 dispatchCommand(mxComponent
, u
".uno:GoToCell"_ustr
, aPropertyValues
);
271 // Assert that the size in the payload is not 0.
272 CPPUNIT_ASSERT(m_aDocumentSize
.getWidth() > 0);
273 CPPUNIT_ASSERT(m_aDocumentSize
.getHeight() > 0);
276 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testViewLock
)
278 // Load a document that has a shape and create two views.
279 ScModelObj
* pModelObj
= createDoc("shape.ods");
281 SfxLokHelper::createView();
282 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
285 // Begin text edit in the second view and assert that the first gets a lock
287 const ScViewData
* pViewData
= ScDocShell::GetViewData();
288 CPPUNIT_ASSERT(pViewData
);
289 ScTabViewShell
* pViewShell
= pViewData
->GetViewShell();
290 CPPUNIT_ASSERT(pViewShell
);
291 SdrModel
* pDrawModel
= pViewData
->GetDocument().GetDrawLayer();
292 SdrPage
* pDrawPage
= pDrawModel
->GetPage(0);
293 SdrObject
* pObject
= pDrawPage
->GetObj(0);
294 SdrView
* pView
= pViewShell
->GetScDrawView();
295 aView1
.m_bViewLock
= false;
296 pView
->SdrBeginTextEdit(pObject
);
297 CPPUNIT_ASSERT(aView1
.m_bViewLock
);
299 // End text edit in the second view, and assert that the lock is removed in
301 pView
->SdrEndTextEdit();
302 CPPUNIT_ASSERT(!aView1
.m_bViewLock
);
307 void lcl_extractHandleParameters(std::string_view selection
, sal_uInt32
& id
, sal_uInt32
& x
, sal_uInt32
& y
)
309 OString
extraInfo( selection
.substr(selection
.find("{")) );
310 std::stringstream
aStream((std::string(extraInfo
)));
311 boost::property_tree::ptree aTree
;
312 boost::property_tree::read_json(aStream
, aTree
);
313 boost::property_tree::ptree
315 .get_child("handles")
317 .get_child("rectangle")
320 id
= handle0
.get_child("id").get_value
<int>();
321 x
= handle0
.get_child("point").get_child("x").get_value
<int>();
322 y
= handle0
.get_child("point").get_child("y").get_value
<int>();
326 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testMoveShapeHandle
)
328 ScModelObj
* pModelObj
= createDoc("shape.ods");
330 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
, /*x=*/ 1,/*y=*/ 1,/*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
331 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
, /*x=*/ 1, /*y=*/ 1, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
332 Scheduler::ProcessEventsToIdle();
334 CPPUNIT_ASSERT(!aView1
.m_ShapeSelection
.isEmpty());
337 lcl_extractHandleParameters(aView1
.m_ShapeSelection
, id
, x
,y
);
340 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
342 {"HandleNum", uno::Any(id
)},
343 {"NewPosX", uno::Any(x
+1)},
344 {"NewPosY", uno::Any(y
+1)}
346 dispatchCommand(mxComponent
, u
".uno:MoveShapeHandle"_ustr
, aPropertyValues
);
347 CPPUNIT_ASSERT(!aView1
.m_ShapeSelection
.isEmpty());
348 lcl_extractHandleParameters(aView1
.m_ShapeSelection
, id
, x
,y
);
349 CPPUNIT_ASSERT_EQUAL(x
-1, oldX
);
350 CPPUNIT_ASSERT_EQUAL(y
-1, oldY
);
354 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testColRowResize
)
356 ScModelObj
* pModelObj
= createDoc("sort-range.ods");
357 ScDocShell
* pDocSh
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
358 CPPUNIT_ASSERT(pDocSh
);
360 ScTabViewShell
* pViewShell
= pDocSh
->GetBestViewShell(false);
361 CPPUNIT_ASSERT(pViewShell
);
363 setupLibreOfficeKitViewCallback(pViewShell
);
365 ScDocument
& rDoc
= pDocSh
->GetDocument();
368 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
369 { "ColumnWidth", uno::Any(sal_uInt16(4000)) }, // 4cm
370 { "Column", uno::Any(sal_Int16(3)) }
372 dispatchCommand(mxComponent
, u
".uno:ColumnWidth"_ustr
, aArgs
);
374 sal_uInt16 nWidth
= o3tl::convert(rDoc
.GetColWidth(static_cast<SCCOL
>(2), static_cast<SCTAB
>(0), false), o3tl::Length::twip
, o3tl::Length::mm100
);
375 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(4001), nWidth
);
378 uno::Sequence
<beans::PropertyValue
> aArgs2( comphelper::InitPropertySequence({
379 { "RowHeight", uno::Any(sal_uInt16(2000)) },
380 { "Row", uno::Any(sal_Int16(5)) },
382 dispatchCommand(mxComponent
, u
".uno:RowHeight"_ustr
, aArgs2
);
384 sal_uInt16 nHeight
= o3tl::convert(rDoc
.GetRowHeight(static_cast<SCROW
>(4), static_cast<SCTAB
>(0), false), o3tl::Length::twip
, o3tl::Length::mm100
);
385 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(2000), nHeight
);
388 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testUndoShells
)
390 ScModelObj
* pModelObj
= createDoc("small.ods");
391 // Clear the currently selected cell.
392 dispatchCommand(mxComponent
, u
".uno:ClearContents"_ustr
, {});
394 auto pDocShell
= dynamic_cast<ScDocShell
*>(pModelObj
->GetEmbeddedObject());
395 CPPUNIT_ASSERT(pDocShell
);
396 ScDocument
& rDoc
= pDocShell
->GetDocument();
397 ScUndoManager
* pUndoManager
= rDoc
.GetUndoManager();
398 CPPUNIT_ASSERT(pUndoManager
);
399 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pUndoManager
->GetUndoActionCount());
400 sal_Int32 nView1
= SfxLokHelper::getView();
401 // This was -1: ScSimpleUndo did not remember what view shell created it.
402 CPPUNIT_ASSERT_EQUAL(ViewShellId(nView1
), pUndoManager
->GetUndoAction()->GetViewShellId());
407 bool lcl_hasEditView(const ScViewData
& rViewData
)
409 bool bResult
= false;
410 for (unsigned int i
=0; i
<4; i
++)
412 bResult
= rViewData
.HasEditView( static_cast<ScSplitPos
>(i
) );
419 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testTextEditViews
)
421 ScModelObj
* pModelObj
= createDoc("small.ods");
422 CPPUNIT_ASSERT(pModelObj
);
423 ScViewData
* pViewData
= ScDocShell::GetViewData();
424 CPPUNIT_ASSERT(pViewData
);
428 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
430 // text edit a cell in view #1
431 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
432 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
433 Scheduler::ProcessEventsToIdle();
434 CPPUNIT_ASSERT(lcl_hasEditView(*pViewData
));
437 SfxLokHelper::createView();
438 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
441 // move cell cursor i view #2
442 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DOWN
);
443 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DOWN
);
444 Scheduler::ProcessEventsToIdle();
446 // check that text edit view in view #1 has not be killed
447 CPPUNIT_ASSERT(lcl_hasEditView(*pViewData
));
450 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testTextEditViewInvalidations
)
452 ScModelObj
* pModelObj
= createDoc("small.ods");
453 CPPUNIT_ASSERT(pModelObj
);
454 ScViewData
* pViewData
= ScDocShell::GetViewData();
455 CPPUNIT_ASSERT(pViewData
);
458 int nView1
= SfxLokHelper::getView();
460 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
463 SfxLokHelper::createView();
464 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
467 // text edit a cell in view #1
468 SfxLokHelper::setView(nView1
);
469 aView2
.m_bInvalidateTiles
= false;
470 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
471 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
472 Scheduler::ProcessEventsToIdle();
473 CPPUNIT_ASSERT(lcl_hasEditView(*pViewData
));
474 CPPUNIT_ASSERT(aView2
.m_bInvalidateTiles
);
476 // text edit a cell in view #1 until
477 // we can be sure we are out of the initial tile
478 for (int i
= 0; i
< 40; ++i
)
480 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
481 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
483 Scheduler::ProcessEventsToIdle();
485 // text edit a cell in view #1 inside the new tile and
486 // check that view #2 receive a tile invalidate message
487 aView2
.m_bInvalidateTiles
= false;
488 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
489 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
490 Scheduler::ProcessEventsToIdle();
491 CPPUNIT_ASSERT(aView2
.m_bInvalidateTiles
);
494 SfxLokHelper::createView();
495 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
498 // text edit a cell in view #1
499 SfxLokHelper::setView(nView1
);
500 aView3
.m_bInvalidateTiles
= false;
501 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'y', 0);
502 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'y', 0);
503 Scheduler::ProcessEventsToIdle();
504 CPPUNIT_ASSERT(aView3
.m_bInvalidateTiles
);
507 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testCreateViewGraphicSelection
)
509 // Load a document that has a shape and create two views.
510 ScModelObj
* pModelObj
= createDoc("shape.ods");
513 // Mark the graphic in the first view.
514 const ScViewData
* pViewData
= ScDocShell::GetViewData();
515 CPPUNIT_ASSERT(pViewData
);
516 ScTabViewShell
* pViewShell
= pViewData
->GetViewShell();
517 CPPUNIT_ASSERT(pViewShell
);
518 SdrModel
* pDrawModel
= pViewData
->GetDocument().GetDrawLayer();
519 SdrPage
* pDrawPage
= pDrawModel
->GetPage(0);
520 SdrObject
* pObject
= pDrawPage
->GetObj(0);
521 SdrView
* pView
= pViewShell
->GetScDrawView();
522 aView1
.m_bGraphicSelection
= false;
523 aView1
.m_bGraphicViewSelection
= false;
524 pView
->MarkObj(pObject
, pView
->GetSdrPageView());
525 CPPUNIT_ASSERT(aView1
.m_bGraphicSelection
);
527 // Create a second view.
528 int nView1
= SfxLokHelper::getView();
529 SfxLokHelper::createView();
530 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
532 CPPUNIT_ASSERT(aView2
.m_bGraphicViewSelection
);
533 CPPUNIT_ASSERT(aView1
.m_bGraphicViewSelection
);
535 SfxLokHelper::setView(nView1
);
536 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
539 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testGraphicInvalidate
)
541 // Load a document that has a shape and create two views.
542 ScModelObj
* pModelObj
= createDoc("shape.ods");
545 // Click to select graphic
546 aView
.m_bGraphicSelection
= false;
547 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
, /*x=*/ 1,/*y=*/ 1,/*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
548 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
, /*x=*/ 1, /*y=*/ 1, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
549 Scheduler::ProcessEventsToIdle();
550 CPPUNIT_ASSERT(aView
.m_bGraphicSelection
);
553 aView
.m_bGraphicSelection
= false;
554 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
, /*x=*/ 1,/*y=*/ 1,/*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
555 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEMOVE
, /*x=*/ 1,/*y=*/ 10,/*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
556 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
, /*x=*/ 1, /*y=*/ 10, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
557 Scheduler::ProcessEventsToIdle();
558 CPPUNIT_ASSERT(!aView
.m_bFullInvalidateTiles
);
561 Scheduler::ProcessEventsToIdle();
562 CPPUNIT_ASSERT(!aView
.m_bFullInvalidateTiles
);
565 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testAutoSum
)
567 createDoc("small.ods");
571 uno::Sequence
<beans::PropertyValue
> aArgs
;
572 dispatchCommand(mxComponent
, u
".uno:AutoSum"_ustr
, aArgs
);
573 CPPUNIT_ASSERT(aView
.m_sCellFormula
.startsWith("=SUM("));
576 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testHideColRow
)
578 createDoc("small.ods");
580 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
581 { "Col", uno::Any(sal_Int32(2 - 1)) },
582 { "Modifier", uno::Any(KEY_SHIFT
) }
584 dispatchCommand(mxComponent
, u
".uno:SelectColumn"_ustr
, aArgs
);
586 uno::Sequence
<beans::PropertyValue
> aArgs2( comphelper::InitPropertySequence({
587 { "Col", uno::Any(sal_Int32(3 - 1)) },
588 { "Modifier", uno::Any(sal_uInt16(0)) }
591 dispatchCommand(mxComponent
, u
".uno:SelectColumn"_ustr
, aArgs2
);
594 ScViewData
* pViewData
= ScDocShell::GetViewData();
595 CPPUNIT_ASSERT(pViewData
);
596 SCCOL nOldCurX
= pViewData
->GetCurX();
597 SCROW nOldCurY
= pViewData
->GetCurY();
599 uno::Sequence
<beans::PropertyValue
> aArgs
;
600 dispatchCommand(mxComponent
, u
".uno:HideColumn"_ustr
, aArgs
);
603 SCCOL nNewCurX
= pViewData
->GetCurX();
604 SCROW nNewCurY
= pViewData
->GetCurY();
605 CPPUNIT_ASSERT(nNewCurX
> nOldCurX
);
606 CPPUNIT_ASSERT_EQUAL(nOldCurY
, nNewCurY
);
608 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
609 { "Row", uno::Any(sal_Int32(6 - 1)) },
610 { "Modifier", uno::Any(KEY_SHIFT
) }
612 dispatchCommand(mxComponent
, u
".uno:SelectRow"_ustr
, aArgs
);
614 uno::Sequence
<beans::PropertyValue
> aArgs2( comphelper::InitPropertySequence({
615 { "Row", uno::Any(sal_Int32(7 - 1)) },
616 { "Modifier", uno::Any(sal_uInt16(0)) }
618 dispatchCommand(mxComponent
, u
".uno:SelectRow"_ustr
, aArgs2
);
621 nOldCurX
= pViewData
->GetCurX();
622 nOldCurY
= pViewData
->GetCurY();
624 uno::Sequence
<beans::PropertyValue
> aArgs
;
625 dispatchCommand(mxComponent
, u
".uno:HideRow"_ustr
, aArgs
);
627 nNewCurX
= pViewData
->GetCurX();
628 nNewCurY
= pViewData
->GetCurY();
629 CPPUNIT_ASSERT(nNewCurY
> nOldCurY
);
630 CPPUNIT_ASSERT_EQUAL(nOldCurX
, nNewCurX
);
633 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testInvalidateOnCopyPasteCells
)
635 ScModelObj
* pModelObj
= createDoc("small.ods");
636 CPPUNIT_ASSERT(pModelObj
);
641 uno::Sequence
<beans::PropertyValue
> aArgs
;
642 // select and copy cells
643 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_HOME
| KEY_MOD1
);
644 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_HOME
| KEY_MOD1
);
645 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
| KEY_SHIFT
);
646 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
| KEY_SHIFT
);
647 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_RIGHT
| KEY_SHIFT
);
648 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_RIGHT
| KEY_SHIFT
);
649 Scheduler::ProcessEventsToIdle();
650 dispatchCommand(mxComponent
, u
".uno:Copy"_ustr
, aArgs
);
652 // move to destination cell
653 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
);
654 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
);
655 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
| KEY_MOD1
);
656 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
| KEY_MOD1
);
657 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_UP
);
658 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_UP
);
659 Scheduler::ProcessEventsToIdle();
662 aView
.m_bInvalidateTiles
= false;
663 dispatchCommand(mxComponent
, u
".uno:Paste"_ustr
, aArgs
);
664 CPPUNIT_ASSERT(aView
.m_bInvalidateTiles
);
667 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testInvalidateOnInserRowCol
)
669 ScModelObj
* pModelObj
= createDoc("small.ods");
670 CPPUNIT_ASSERT(pModelObj
);
675 uno::Sequence
<beans::PropertyValue
> aArgs
;
677 for (int i
= 0; i
< 200; ++i
)
679 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
);
680 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
);
682 Scheduler::ProcessEventsToIdle();
685 aView
.m_bInvalidateTiles
= false;
686 aView
.m_aInvalidations
.clear();
687 dispatchCommand(mxComponent
, u
".uno:InsertRows"_ustr
, aArgs
);
688 CPPUNIT_ASSERT(aView
.m_bInvalidateTiles
);
689 CPPUNIT_ASSERT_EQUAL(size_t(1), aView
.m_aInvalidations
.size());
690 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(-75, 51240, 32212230, 63990), aView
.m_aInvalidations
[0]);
693 for (int i
= 0; i
< 200; ++i
)
695 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_RIGHT
);
696 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_RIGHT
);
698 Scheduler::ProcessEventsToIdle();
701 aView
.m_bInvalidateTiles
= false;
702 aView
.m_aInvalidations
.clear();
703 dispatchCommand(mxComponent
, u
".uno:InsertColumns"_ustr
, aArgs
);
704 CPPUNIT_ASSERT(aView
.m_bInvalidateTiles
);
705 CPPUNIT_ASSERT_EQUAL(size_t(1), aView
.m_aInvalidations
.size());
706 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(254925, -15, 32212230, 63990), aView
.m_aInvalidations
[0]);
709 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testCommentCallback
)
711 // Comments callback are emitted only if tiled annotations are off
712 comphelper::LibreOfficeKit::setTiledAnnotations(false);
714 // FIXME: Hack because previous tests do not destroy ScDocument(with annotations) on exit (?).
715 ScPostIt::mnLastPostItId
= 1;
718 ScModelObj
* pModelObj
= createDoc("small.ods");
720 int nView1
= SfxLokHelper::getView();
723 SfxLokHelper::createView();
724 pModelObj
->initializeForTiledRendering({});
727 SfxLokHelper::setView(nView1
);
729 ScTabViewShell
* pTabViewShell
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
731 pTabViewShell
->SetCursor(4, 4);
734 uno::Sequence
<beans::PropertyValue
> aArgs(comphelper::InitPropertySequence(
736 {"Text", uno::Any(u
"Comment"_ustr
)},
737 {"Author", uno::Any(u
"LOK User1"_ustr
)},
739 dispatchCommand(mxComponent
, u
".uno:InsertAnnotation"_ustr
, aArgs
);
741 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action
742 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
743 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
744 CPPUNIT_ASSERT_EQUAL(std::string("1"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("id"));
745 CPPUNIT_ASSERT_EQUAL(std::string("1"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("id"));
746 CPPUNIT_ASSERT_EQUAL(std::string("0"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("tab"));
747 CPPUNIT_ASSERT_EQUAL(std::string("0"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("tab"));
748 CPPUNIT_ASSERT_EQUAL(std::string("LOK User1"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("author"));
749 CPPUNIT_ASSERT_EQUAL(std::string("LOK User1"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("author"));
750 CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("text"));
751 CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("text"));
752 CPPUNIT_ASSERT_EQUAL(std::string("4 4 4 4"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("cellRange"));
753 CPPUNIT_ASSERT_EQUAL(std::string("4 4 4 4"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("cellRange"));
755 // Ensure deleting rows updates comments
757 pTabViewShell
->SetCursor(2, 2);
759 dispatchCommand(mxComponent
, u
".uno:DeleteRows"_ustr
, {});
760 Scheduler::ProcessEventsToIdle();
761 CPPUNIT_ASSERT_EQUAL(std::string("4 3 4 3"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("cellRange"));
762 CPPUNIT_ASSERT_EQUAL(std::string("4 3 4 3"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("cellRange"));
764 // Ensure deleting columns updates comments
766 pTabViewShell
->SetCursor(2, 2);
768 dispatchCommand(mxComponent
, u
".uno:DeleteColumns"_ustr
, {});
769 Scheduler::ProcessEventsToIdle();
770 CPPUNIT_ASSERT_EQUAL(std::string("3 3 3 3"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("cellRange"));
771 CPPUNIT_ASSERT_EQUAL(std::string("3 3 3 3"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("cellRange"));
773 std::string aCommentId
= aView1
.m_aCommentCallbackResult
.get
<std::string
>("id");
776 // Select some random cell, we should be able to edit the cell note without
777 // selecting the cell
779 pTabViewShell
->SetCursor(3, 100);
780 aArgs
= comphelper::InitPropertySequence(
782 {"Id", uno::Any(OUString::createFromAscii(aCommentId
))},
783 {"Text", uno::Any(u
"Edited comment"_ustr
)},
784 {"Author", uno::Any(u
"LOK User2"_ustr
)},
786 dispatchCommand(mxComponent
, u
".uno:EditAnnotation"_ustr
, aArgs
);
788 // We received a LOK_CALLBACK_COMMENT callback with comment 'Modify' action
789 CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
790 CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
791 CPPUNIT_ASSERT_EQUAL(aCommentId
, aView1
.m_aCommentCallbackResult
.get
<std::string
>("id"));
792 CPPUNIT_ASSERT_EQUAL(aCommentId
, aView2
.m_aCommentCallbackResult
.get
<std::string
>("id"));
793 CPPUNIT_ASSERT_EQUAL(std::string("LOK User2"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("author"));
794 CPPUNIT_ASSERT_EQUAL(std::string("LOK User2"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("author"));
795 CPPUNIT_ASSERT_EQUAL(std::string("Edited comment"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("text"));
796 CPPUNIT_ASSERT_EQUAL(std::string("Edited comment"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("text"));
797 CPPUNIT_ASSERT_EQUAL(std::string("3 3 3 3"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("cellRange"));
798 CPPUNIT_ASSERT_EQUAL(std::string("3 3 3 3"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("cellRange"));
800 // Delete the comment
802 pTabViewShell
->SetCursor(4, 43);
803 aArgs
= comphelper::InitPropertySequence(
805 {"Id", uno::Any(OUString::createFromAscii(aCommentId
))}
807 dispatchCommand(mxComponent
, u
".uno:DeleteNote"_ustr
, aArgs
);
809 // We received a LOK_CALLBACK_COMMENT callback with comment 'Remove' action
810 CPPUNIT_ASSERT_EQUAL(std::string("Remove"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
811 CPPUNIT_ASSERT_EQUAL(std::string("Remove"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
812 CPPUNIT_ASSERT_EQUAL(aCommentId
, aView1
.m_aCommentCallbackResult
.get
<std::string
>("id"));
813 CPPUNIT_ASSERT_EQUAL(aCommentId
, aView2
.m_aCommentCallbackResult
.get
<std::string
>("id"));
815 comphelper::LibreOfficeKit::setTiledAnnotations(true);
818 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testUndoLimiting
)
820 ScModelObj
* pModelObj
= createDoc("small.ods");
821 CPPUNIT_ASSERT(pModelObj
);
822 ScDocument
* pDoc
= pModelObj
->GetDocument();
823 CPPUNIT_ASSERT(pDoc
);
824 ScUndoManager
* pUndoManager
= pDoc
->GetUndoManager();
825 CPPUNIT_ASSERT(pUndoManager
);
828 int nView1
= SfxLokHelper::getView();
832 SfxLokHelper::createView();
833 int nView2
= SfxLokHelper::getView();
834 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
837 // text edit a cell in view #1
838 SfxLokHelper::setView(nView1
);
839 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
840 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
841 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
842 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
843 Scheduler::ProcessEventsToIdle();
845 // check that undo action count in not 0
846 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
848 // try to execute undo in view #2
849 SfxLokHelper::setView(nView2
);
850 dispatchCommand(mxComponent
, u
".uno:Undo"_ustr
, {});
851 // check that undo has not been executed on view #2
852 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
854 // try to execute undo in view #1
855 SfxLokHelper::setView(nView1
);
856 dispatchCommand(mxComponent
, u
".uno:Undo"_ustr
, {});
857 // check that undo has been executed on view #1
858 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetUndoActionCount());
860 // check that redo action count in not 0
861 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetRedoActionCount());
863 // try to execute redo in view #2
864 SfxLokHelper::setView(nView2
);
865 dispatchCommand(mxComponent
, u
".uno:Redo"_ustr
, {});
866 // check that redo has not been executed on view #2
867 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetRedoActionCount());
869 // try to execute redo in view #1
870 SfxLokHelper::setView(nView1
);
871 dispatchCommand(mxComponent
, u
".uno:Redo"_ustr
, {});
872 // check that redo has been executed on view #1
873 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetRedoActionCount());
876 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testUndoRepairDispatch
)
878 ScModelObj
* pModelObj
= createDoc("small.ods");
879 CPPUNIT_ASSERT(pModelObj
);
880 ScDocument
* pDoc
= pModelObj
->GetDocument();
881 CPPUNIT_ASSERT(pDoc
);
882 ScUndoManager
* pUndoManager
= pDoc
->GetUndoManager();
883 CPPUNIT_ASSERT(pUndoManager
);
886 int nView1
= SfxLokHelper::getView();
890 SfxLokHelper::createView();
891 int nView2
= SfxLokHelper::getView();
892 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
895 // text edit a cell in view #1
896 SfxLokHelper::setView(nView1
);
897 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
898 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
899 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
900 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
901 Scheduler::ProcessEventsToIdle();
903 // check that undo action count in not 0
904 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
906 // try to execute undo in view #2
907 SfxLokHelper::setView(nView2
);
908 dispatchCommand(mxComponent
, u
".uno:Undo"_ustr
, {});
909 // check that undo has not been executed on view #2
910 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
912 // try to execute undo in view #2 in repair mode
913 SfxLokHelper::setView(nView2
);
914 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
916 {"Repair", uno::Any(true)}
918 dispatchCommand(mxComponent
, u
".uno:Undo"_ustr
, aPropertyValues
);
919 // check that undo has been executed on view #2 in repair mode
920 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetUndoActionCount());
923 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testInsertGraphicInvalidations
)
925 ScModelObj
* pModelObj
= createDoc("small.ods");
926 CPPUNIT_ASSERT(pModelObj
);
927 ScViewData
* pViewData
= ScDocShell::GetViewData();
928 CPPUNIT_ASSERT(pViewData
);
933 // we need to paint a tile in the view for triggering the tile invalidation solution
934 int nCanvasWidth
= 256;
935 int nCanvasHeight
= 256;
936 std::vector
<unsigned char> aBuffer(nCanvasWidth
* nCanvasHeight
* 4);
937 ScopedVclPtrInstance
<VirtualDevice
> pDevice(DeviceFormat::WITHOUT_ALPHA
);
938 pDevice
->SetOutputSizePixelScaleOffsetAndLOKBuffer(Size(nCanvasWidth
, nCanvasHeight
), Fraction(1.0), Point(), aBuffer
.data());
939 pModelObj
->paintTile(*pDevice
, nCanvasWidth
, nCanvasHeight
, /*nTilePosX=*/0, /*nTilePosY=*/0, /*nTileWidth=*/3840, /*nTileHeight=*/3840);
940 Scheduler::ProcessEventsToIdle();
942 // insert an image in view and see if both views are invalidated
943 aView
.m_bInvalidateTiles
= false;
944 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
945 { "FileName", uno::Any(createFileURL(u
"smile.png")) }
947 dispatchCommand(mxComponent
, u
".uno:InsertGraphic"_ustr
, aArgs
);
948 CPPUNIT_ASSERT(aView
.m_bInvalidateTiles
);
950 // undo image insertion in view and see if both views are invalidated
951 aView
.m_bInvalidateTiles
= false;
952 uno::Sequence
<beans::PropertyValue
> aArgs2
;
953 dispatchCommand(mxComponent
, u
".uno:Undo"_ustr
, aArgs2
);
954 CPPUNIT_ASSERT(aView
.m_bInvalidateTiles
);
957 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testDocumentSizeWithTwoViews
)
959 // Open a document that has the cursor far away & paint a tile
960 ScModelObj
* pModelObj
= createDoc("cursor-away.ods");
962 // Set the visible area, and press page down
963 pModelObj
->setClientVisibleArea(tools::Rectangle(750, 1861, 20583, 6997));
964 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
);
965 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
);
966 Scheduler::ProcessEventsToIdle();
968 int nCanvasWidth
= 256;
969 int nCanvasHeight
= 256;
970 std::vector
<unsigned char> aBuffer1(nCanvasWidth
* nCanvasHeight
* 4);
971 ScopedVclPtrInstance
<VirtualDevice
> pDevice1(DeviceFormat::WITHOUT_ALPHA
);
972 pDevice1
->SetOutputSizePixelScaleOffsetAndLOKBuffer(Size(nCanvasWidth
, nCanvasHeight
), Fraction(1.0), Point(), aBuffer1
.data());
973 pModelObj
->paintTile(*pDevice1
, nCanvasWidth
, nCanvasHeight
, /*nTilePosX=*/0, /*nTilePosY=*/291840, /*nTileWidth=*/3840, /*nTileHeight=*/3840);
974 Scheduler::ProcessEventsToIdle();
977 int nView1
= SfxLokHelper::getView();
978 SfxLokHelper::createView();
980 std::vector
<unsigned char> aBuffer2(nCanvasWidth
* nCanvasHeight
* 4);
981 ScopedVclPtrInstance
<VirtualDevice
> pDevice2(DeviceFormat::WITHOUT_ALPHA
);
982 pDevice2
->SetOutputSizePixelScaleOffsetAndLOKBuffer(Size(nCanvasWidth
, nCanvasHeight
), Fraction(1.0), Point(), aBuffer2
.data());
983 pModelObj
->paintTile(*pDevice2
, nCanvasWidth
, nCanvasHeight
, /*nTilePosX=*/0, /*nTilePosY=*/291840, /*nTileWidth=*/3840, /*nTileHeight=*/3840);
984 Scheduler::ProcessEventsToIdle();
986 // Check that the tiles actually have the same content
987 for (size_t i
= 0; i
< aBuffer1
.size(); ++i
)
988 CPPUNIT_ASSERT_EQUAL(aBuffer1
[i
], aBuffer2
[i
]);
990 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
991 SfxLokHelper::setView(nView1
);
992 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
995 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testDisableUndoRepair
)
997 ScModelObj
* pModelObj
= createDoc("cursor-away.ods");
998 CPPUNIT_ASSERT(pModelObj
);
1001 int nView1
= SfxLokHelper::getView();
1002 SfxViewShell
* pView1
= SfxViewShell::Current();
1005 SfxLokHelper::createView();
1006 int nView2
= SfxLokHelper::getView();
1007 SfxViewShell
* pView2
= SfxViewShell::Current();
1008 CPPUNIT_ASSERT(pView1
!= pView2
);
1010 // both views have UNDO disabled
1012 SfxItemSet
aSet1(pView1
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1013 SfxItemSet
aSet2(pView2
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1014 pView1
->GetSlotState(SID_UNDO
, nullptr, &aSet1
);
1015 pView2
->GetSlotState(SID_UNDO
, nullptr, &aSet2
);
1016 CPPUNIT_ASSERT_EQUAL(SfxItemState::DISABLED
, aSet1
.GetItemState(SID_UNDO
));
1017 CPPUNIT_ASSERT_EQUAL(SfxItemState::DISABLED
, aSet2
.GetItemState(SID_UNDO
));
1020 // text edit a cell in view #1
1021 SfxLokHelper::setView(nView1
);
1022 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'h', 0);
1023 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'h', 0);
1024 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
1025 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
1026 Scheduler::ProcessEventsToIdle();
1027 // view1 has UNDO enabled, view2 is in UNDO-repair
1029 SfxItemSet
aSet1(pView1
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1030 SfxItemSet
aSet2(pView2
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1031 pView1
->GetSlotState(SID_UNDO
, nullptr, &aSet1
);
1032 pView2
->GetSlotState(SID_UNDO
, nullptr, &aSet2
);
1033 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet1
.GetItemState(SID_UNDO
));
1034 CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem
* >(aSet1
.GetItem(SID_UNDO
)));
1035 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet2
.GetItemState(SID_UNDO
));
1036 CPPUNIT_ASSERT(dynamic_cast< const SfxUInt32Item
* >(aSet2
.GetItem(SID_UNDO
)));
1037 const SfxUInt32Item
* pUInt32Item
= dynamic_cast<const SfxUInt32Item
*>(aSet2
.GetItem(SID_UNDO
));
1038 CPPUNIT_ASSERT(pUInt32Item
);
1039 CPPUNIT_ASSERT_EQUAL(static_cast< sal_uInt32
>(SID_REPAIRPACKAGE
), pUInt32Item
->GetValue());
1042 // text edit a cell in view #2
1043 SfxLokHelper::setView(nView2
);
1044 pModelObj
->setPart(1);
1045 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'c', 0);
1046 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'c', 0);
1047 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
1048 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
1049 // both views have UNDO enabled
1050 Scheduler::ProcessEventsToIdle();
1052 SfxItemSet
aSet1(pView1
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1053 SfxItemSet
aSet2(pView2
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
1054 pView1
->GetSlotState(SID_UNDO
, nullptr, &aSet1
);
1055 pView2
->GetSlotState(SID_UNDO
, nullptr, &aSet2
);
1056 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet1
.GetItemState(SID_UNDO
));
1057 CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem
* >(aSet1
.GetItem(SID_UNDO
)));
1058 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet2
.GetItemState(SID_UNDO
));
1059 CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem
* >(aSet2
.GetItem(SID_UNDO
)));
1062 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1063 SfxLokHelper::setView(nView1
);
1064 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1067 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testDocumentRepair
)
1069 // Create two views.
1070 ScModelObj
* pModelObj
= createDoc("cursor-away.ods");
1071 CPPUNIT_ASSERT(pModelObj
);
1074 SfxViewShell
* pView1
= SfxViewShell::Current();
1077 int nView1
= SfxLokHelper::getView();
1078 SfxLokHelper::createView();
1079 SfxViewShell
* pView2
= SfxViewShell::Current();
1080 int nView2
= SfxLokHelper::getView();
1081 CPPUNIT_ASSERT(pView1
!= pView2
);
1083 std::unique_ptr
<SfxBoolItem
> pItem1
;
1084 std::unique_ptr
<SfxBoolItem
> pItem2
;
1085 pView1
->GetViewFrame().GetBindings().QueryState(SID_DOC_REPAIR
, pItem1
);
1086 pView2
->GetViewFrame().GetBindings().QueryState(SID_DOC_REPAIR
, pItem2
);
1087 CPPUNIT_ASSERT(pItem1
);
1088 CPPUNIT_ASSERT(pItem2
);
1089 CPPUNIT_ASSERT_EQUAL(false, pItem1
->GetValue());
1090 CPPUNIT_ASSERT_EQUAL(false, pItem2
->GetValue());
1093 // Insert a character in the second view.
1094 SfxLokHelper::setView(nView2
);
1095 pModelObj
->setPart(1);
1096 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'c', 0);
1097 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'c', 0);
1098 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
1099 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
1100 Scheduler::ProcessEventsToIdle();
1102 std::unique_ptr
<SfxBoolItem
> pItem1
;
1103 std::unique_ptr
<SfxBoolItem
> pItem2
;
1104 pView1
->GetViewFrame().GetBindings().QueryState(SID_DOC_REPAIR
, pItem1
);
1105 pView2
->GetViewFrame().GetBindings().QueryState(SID_DOC_REPAIR
, pItem2
);
1106 CPPUNIT_ASSERT(pItem1
);
1107 CPPUNIT_ASSERT(pItem2
);
1108 CPPUNIT_ASSERT_EQUAL(true, pItem1
->GetValue());
1109 CPPUNIT_ASSERT_EQUAL(true, pItem2
->GetValue());
1112 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1113 SfxLokHelper::setView(nView1
);
1114 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1117 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testLanguageStatus
)
1119 ScModelObj
* pModelObj
= createDoc("small.ods");
1120 CPPUNIT_ASSERT(pModelObj
);
1121 ScDocShell
* pDocSh
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
1122 CPPUNIT_ASSERT(pDocSh
);
1125 SfxViewShell
* pView1
= SfxViewShell::Current();
1128 int nView1
= SfxLokHelper::getView();
1129 SfxLokHelper::createView();
1130 SfxViewShell
* pView2
= SfxViewShell::Current();
1131 CPPUNIT_ASSERT(pView1
!= pView2
);
1133 std::unique_ptr
<SfxPoolItem
> xItem1
;
1134 std::unique_ptr
<SfxPoolItem
> xItem2
;
1135 pView1
->GetViewFrame().GetBindings().QueryState(SID_LANGUAGE_STATUS
, xItem1
);
1136 pView2
->GetViewFrame().GetBindings().QueryState(SID_LANGUAGE_STATUS
, xItem2
);
1137 const SfxStringItem
* pItem1
= dynamic_cast<const SfxStringItem
*>(xItem1
.get());
1138 const SfxStringItem
* pItem2
= dynamic_cast<const SfxStringItem
*>(xItem2
.get());
1139 CPPUNIT_ASSERT(pItem1
);
1140 CPPUNIT_ASSERT(pItem2
);
1141 CPPUNIT_ASSERT(!pItem1
->GetValue().isEmpty());
1142 CPPUNIT_ASSERT(!pItem2
->GetValue().isEmpty());
1146 SfxStringItem
aLangString(SID_LANGUAGE_STATUS
, u
"Default_Spanish (Bolivia)"_ustr
);
1147 pView1
->GetViewFrame().GetDispatcher()->ExecuteList(SID_LANGUAGE_STATUS
,
1148 SfxCallMode::SYNCHRON
, { &aLangString
});
1152 std::unique_ptr
<SfxPoolItem
> xItem1
;
1153 std::unique_ptr
<SfxPoolItem
> xItem2
;
1154 pView1
->GetViewFrame().GetBindings().QueryState(SID_LANGUAGE_STATUS
, xItem1
);
1155 pView2
->GetViewFrame().GetBindings().QueryState(SID_LANGUAGE_STATUS
, xItem2
);
1156 const SfxStringItem
* pItem1
= dynamic_cast<const SfxStringItem
*>(xItem1
.get());
1157 const SfxStringItem
* pItem2
= dynamic_cast<const SfxStringItem
*>(xItem2
.get());
1158 CPPUNIT_ASSERT(pItem1
);
1159 CPPUNIT_ASSERT(pItem2
);
1160 static constexpr OUString
aLangBolivia(u
"Spanish (Bolivia);es-BO"_ustr
);
1161 CPPUNIT_ASSERT_EQUAL(aLangBolivia
, pItem1
->GetValue());
1162 CPPUNIT_ASSERT_EQUAL(aLangBolivia
, pItem2
->GetValue());
1165 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1166 SfxLokHelper::setView(nView1
);
1167 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1170 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testMultiViewCopyPaste
)
1172 ScModelObj
* pModelObj
= createDoc("empty.ods");
1173 ScDocument
* pDoc
= pModelObj
->GetDocument();
1174 CPPUNIT_ASSERT(pDoc
);
1176 pDoc
->SetString(ScAddress(0, 0, 0), u
"TestCopy1"_ustr
);
1177 pDoc
->SetString(ScAddress(1, 0, 0), u
"TestCopy2"_ustr
);
1180 ScTabViewShell
* pView1
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
1181 CPPUNIT_ASSERT(pView1
);
1182 // emulate clipboard
1183 pView1
->GetViewData().GetActiveWin()->SetClipboard(css::datatransfer::clipboard::LokClipboard::create(comphelper::getProcessComponentContext()));
1186 int nView1
= SfxLokHelper::getView();
1187 SfxLokHelper::createView();
1188 ScTabViewShell
* pView2
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
1189 // emulate clipboard
1190 pView2
->GetViewData().GetActiveWin()->SetClipboard(css::datatransfer::clipboard::LokClipboard::create(comphelper::getProcessComponentContext()));
1191 CPPUNIT_ASSERT(pView2
);
1192 CPPUNIT_ASSERT(pView1
!= pView2
);
1193 CPPUNIT_ASSERT(pView1
->GetViewData().GetActiveWin()->GetClipboard() != pView2
->GetViewData().GetActiveWin()->GetClipboard());
1196 pView1
->SetCursor(0, 0);
1197 pView1
->GetViewFrame().GetBindings().Execute(SID_COPY
);
1200 pView2
->SetCursor(1, 0);
1201 pView2
->GetViewFrame().GetBindings().Execute(SID_COPY
);
1203 // paste text view 1
1204 pView1
->SetCursor(0, 1);
1205 pView1
->GetViewFrame().GetBindings().Execute(SID_PASTE
);
1207 // paste text view 2
1208 pView2
->SetCursor(1, 1);
1209 pView2
->GetViewFrame().GetBindings().Execute(SID_PASTE
);
1211 CPPUNIT_ASSERT_EQUAL(u
"TestCopy1"_ustr
, pDoc
->GetString(ScAddress(0, 1, 0)));
1212 CPPUNIT_ASSERT_EQUAL(u
"TestCopy2"_ustr
, pDoc
->GetString(ScAddress(1, 1, 0)));
1214 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1215 SfxLokHelper::setView(nView1
);
1216 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1219 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testIMESupport
)
1221 ScModelObj
* pModelObj
= createDoc("empty.ods");
1222 VclPtr
<vcl::Window
> pDocWindow
= pModelObj
->getDocWindow();
1223 ScDocument
* pDoc
= pModelObj
->GetDocument();
1225 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
1226 CPPUNIT_ASSERT(pView
);
1228 pView
->SetCursor(0, 0);
1229 // sequence of chinese IME compositions when 'nihao' is typed in an IME
1230 const std::vector
<OString
> aUtf8Inputs
{ "å¹´"_ostr
, "ä½ "_ostr
, "ä½ å¥½"_ostr
, "ä½ å“ˆ"_ostr
, "ä½ å¥½"_ostr
, "ä½ å¥½"_ostr
};
1231 std::vector
<OUString
> aInputs
;
1232 std::transform(aUtf8Inputs
.begin(), aUtf8Inputs
.end(),
1233 std::back_inserter(aInputs
), [](OString aInput
) {
1234 return OUString::fromUtf8(aInput
);
1236 for (const auto& aInput
: aInputs
)
1238 pDocWindow
->PostExtTextInputEvent(VclEventId::ExtTextInput
, aInput
);
1240 pDocWindow
->PostExtTextInputEvent(VclEventId::EndExtTextInput
, u
""_ustr
);
1242 // commit the string to the cell
1243 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
1244 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
1245 Scheduler::ProcessEventsToIdle();
1247 CPPUNIT_ASSERT_EQUAL(aInputs
[aInputs
.size() - 1], pDoc
->GetString(ScAddress(0, 0, 0)));
1250 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testFilterDlg
)
1252 createDoc("empty.ods");
1255 SfxViewShell
* pView1
= SfxViewShell::Current();
1256 int nView1
= SfxLokHelper::getView();
1259 SfxLokHelper::createView();
1260 SfxViewShell
* pView2
= SfxViewShell::Current();
1261 CPPUNIT_ASSERT(pView1
!= pView2
);
1263 pView2
->GetViewFrame().GetDispatcher()->Execute(SID_FILTER
,
1264 SfxCallMode::SLOT
|SfxCallMode::RECORD
);
1267 Scheduler::ProcessEventsToIdle();
1268 SfxChildWindow
* pRefWindow
= pView2
->GetViewFrame().GetChildWindow(SID_FILTER
);
1269 CPPUNIT_ASSERT(pRefWindow
);
1272 SfxLokHelper::setView(nView1
);
1273 CPPUNIT_ASSERT_EQUAL(true, pView2
->GetViewFrame().GetDispatcher()->IsLocked());
1274 CPPUNIT_ASSERT_EQUAL(false, pView1
->GetViewFrame().GetDispatcher()->IsLocked());
1276 pRefWindow
->GetController()->response(RET_CANCEL
);
1278 CPPUNIT_ASSERT_EQUAL(false, pView2
->GetViewFrame().GetDispatcher()->IsLocked());
1279 CPPUNIT_ASSERT_EQUAL(false, pView1
->GetViewFrame().GetDispatcher()->IsLocked());
1281 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1282 SfxLokHelper::setView(nView1
);
1283 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1286 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testFunctionDlg
)
1288 createDoc("empty.ods");
1291 SfxViewShell
* pView1
= SfxViewShell::Current();
1292 int nView1
= SfxLokHelper::getView();
1294 pView1
->GetViewFrame().GetDispatcher()->Execute(SID_OPENDLG_FUNCTION
,
1295 SfxCallMode::SLOT
|SfxCallMode::RECORD
);
1297 Scheduler::ProcessEventsToIdle();
1298 SfxChildWindow
* pRefWindow
= pView1
->GetViewFrame().GetChildWindow(SID_OPENDLG_FUNCTION
);
1299 CPPUNIT_ASSERT(pRefWindow
);
1302 int nView2
= SfxLokHelper::createView();
1303 SfxViewShell
* pView2
= SfxViewShell::Current();
1304 CPPUNIT_ASSERT(pView1
!= pView2
);
1307 CPPUNIT_ASSERT_EQUAL(true, pView1
->GetViewFrame().GetDispatcher()->IsLocked());
1308 CPPUNIT_ASSERT_EQUAL(false, pView2
->GetViewFrame().GetDispatcher()->IsLocked());
1310 SfxLokHelper::setView(nView1
);
1311 pRefWindow
->GetController()->response(RET_CANCEL
);
1313 CPPUNIT_ASSERT_EQUAL(false, pView1
->GetViewFrame().GetDispatcher()->IsLocked());
1314 CPPUNIT_ASSERT_EQUAL(false, pView2
->GetViewFrame().GetDispatcher()->IsLocked());
1316 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1317 SfxLokHelper::setView(nView2
);
1318 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1321 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testSpellOnlineParameter
)
1323 createDoc("empty.ods");
1325 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
1326 CPPUNIT_ASSERT(pView
);
1328 bool bSet
= pView
->IsAutoSpell();
1330 uno::Sequence
<beans::PropertyValue
> params
=
1332 comphelper::makePropertyValue(u
"Enable"_ustr
, uno::Any(!bSet
)),
1334 dispatchCommand(mxComponent
, u
".uno:SpellOnline"_ustr
, params
);
1335 CPPUNIT_ASSERT_EQUAL(!bSet
, pView
->IsAutoSpell());
1337 // set the same state as now and we don't expect any change (no-toggle)
1340 comphelper::makePropertyValue(u
"Enable"_ustr
, uno::Any(!bSet
)),
1342 dispatchCommand(mxComponent
, u
".uno:SpellOnline"_ustr
, params
);
1343 CPPUNIT_ASSERT_EQUAL(!bSet
, pView
->IsAutoSpell());
1346 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testVbaRangeCopyPaste
)
1348 ScModelObj
* pModelObj
= createDoc("RangeCopyPaste.ods");
1349 ScDocShell
* pDocShell
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
1350 CPPUNIT_ASSERT(pDocShell
);
1353 uno::Sequence
< uno::Any
> aOutParam
;
1354 uno::Sequence
< uno::Any
> aParams
;
1355 uno::Sequence
< sal_Int16
> aOutParamIndex
;
1357 SfxObjectShell::CallXScript(
1359 u
"vnd.sun.Star.script:Standard.Module1.Test_RangeCopyPaste?language=Basic&location=document"_ustr
,
1360 aParams
, aRet
, aOutParamIndex
, aOutParam
);
1362 CPPUNIT_ASSERT(!pDocShell
->GetClipData().is());
1365 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testInvalidationLoop
)
1367 // Load the document with a form control.
1368 createDoc("invalidation-loop.fods");
1369 // Without the accompanying fix in place, this test would have never returned due to an infinite
1370 // invalidation loop between ScGridWindow::Paint() and vcl::Window::ImplPosSizeWindow().
1371 Scheduler::ProcessEventsToIdle();
1374 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testPageDownInvalidation
)
1376 ScModelObj
* pModelObj
= createDoc("empty.ods");
1377 ScViewData
* pViewData
= ScDocShell::GetViewData();
1378 CPPUNIT_ASSERT(pViewData
);
1380 int nView1
= SfxLokHelper::getView();
1381 ViewCallback aView1
;
1382 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
1384 SfxLokHelper::setView(nView1
);
1385 aView1
.m_bInvalidateTiles
= false;
1386 aView1
.m_aInvalidations
.clear();
1387 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, awt::Key::PAGEDOWN
, 0);
1388 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, awt::Key::PAGEDOWN
, 0);
1389 Scheduler::ProcessEventsToIdle();
1390 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
1391 CPPUNIT_ASSERT_EQUAL(size_t(3), aView1
.m_aInvalidations
.size());
1392 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(15, 15, 1230, 225), aView1
.m_aInvalidations
[0]);
1395 static Bitmap
getTile(ScModelObj
* pModelObj
, int nTilePosX
, int nTilePosY
, tools::Long nTileWidth
, tools::Long nTileHeight
)
1397 size_t nCanvasSize
= 1024;
1398 size_t nTileSize
= 256;
1399 std::vector
<unsigned char> aPixmap(nCanvasSize
* nCanvasSize
* 4, 0);
1400 ScopedVclPtrInstance
<VirtualDevice
> xDevice(DeviceFormat::WITHOUT_ALPHA
);
1401 xDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
1402 xDevice
->SetOutputSizePixelScaleOffsetAndLOKBuffer(Size(nCanvasSize
, nCanvasSize
),
1403 Fraction(1.0), Point(), aPixmap
.data());
1404 pModelObj
->paintTile(*xDevice
, nCanvasSize
, nCanvasSize
, nTilePosX
, nTilePosY
, nTileWidth
, nTileHeight
);
1405 xDevice
->EnableMapMode(false);
1406 return xDevice
->GetBitmap(Point(0, 0), Size(nTileSize
, nTileSize
));
1411 void lcl_typeCharsInCell(const std::string
& aStr
, SCCOL nCol
, SCROW nRow
, ScTabViewShell
* pView
,
1412 ScModelObj
* pModelObj
, bool bInEdit
= false, bool bCommit
= true)
1415 pView
->SetCursor(nCol
, nRow
);
1417 for (const char& cChar
: aStr
)
1419 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, cChar
, 0);
1420 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, cChar
, 0);
1421 Scheduler::ProcessEventsToIdle();
1426 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
1427 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
1428 Scheduler::ProcessEventsToIdle();
1433 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testSheetChangeNoInvalidation
)
1435 const bool oldPartInInvalidation
= comphelper::LibreOfficeKit::isPartInInvalidation();
1436 comphelper::LibreOfficeKit::setPartInInvalidation(true);
1438 ScModelObj
* pModelObj
= createDoc("two_sheets.ods");
1439 ScViewData
* pViewData
= ScDocShell::GetViewData();
1440 CPPUNIT_ASSERT(pViewData
);
1442 // Set View to initial 100%
1443 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 28050, 10605));
1444 pModelObj
->setClientZoom(256, 256, 1920, 1920);
1446 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
1447 CPPUNIT_ASSERT(pView
);
1449 int nView1
= SfxLokHelper::getView();
1450 ViewCallback aView1
;
1451 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
1453 SfxLokHelper::setView(nView1
);
1455 aView1
.ClearAllInvalids();
1457 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
1458 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
1459 Scheduler::ProcessEventsToIdle();
1460 // switching sheets should trigger no unnecessary invalidations
1461 CPPUNIT_ASSERT(!aView1
.m_bInvalidateTiles
);
1463 // Get the known columns/rows of this sheet 2 now we have switched to it so
1464 // it knows what range to broadcast invalidations for if it knows cells need
1466 tools::JsonWriter aJsonWriter1
;
1467 pModelObj
->getRowColumnHeaders(tools::Rectangle(0, 15, 19650, 5400), aJsonWriter1
);
1468 aJsonWriter1
.finishAndGetAsOString();
1469 Scheduler::ProcessEventsToIdle();
1470 aView1
.ClearAllInvalids();
1472 // switching back should also trigger no unnecessary invalidations
1473 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEUP
| KEY_MOD1
);
1474 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEUP
| KEY_MOD1
);
1475 Scheduler::ProcessEventsToIdle();
1476 CPPUNIT_ASSERT(!aView1
.m_bInvalidateTiles
);
1478 // The 2nd sheet has formulas that depend on B1 in the first sheet. So if
1479 // we change B1 there should be an invalidation in the second sheet for the
1480 // range that depends on it. Because this is a single user document with no
1481 // active view on the 2nd sheet this will happen on switching back to sheet 2
1482 lcl_typeCharsInCell("101", 1, 0, pView
, pModelObj
); // Type '101' in B1
1483 aView1
.ClearAllInvalids();
1485 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
1486 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
1487 Scheduler::ProcessEventsToIdle();
1488 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
1489 aView1
.ClearAllInvalids();
1491 // Paint it to make it valid again
1492 getTile(pModelObj
, 0, 0, 3840, 3840);
1494 // switching back to sheet 1 should trigger no unnecessary invalidations
1495 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEUP
| KEY_MOD1
);
1496 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEUP
| KEY_MOD1
);
1497 Scheduler::ProcessEventsToIdle();
1498 CPPUNIT_ASSERT(!aView1
.m_bInvalidateTiles
);
1500 // switching to sheet 2 should trigger no unnecessary invalidations this time
1501 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
1502 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
1503 Scheduler::ProcessEventsToIdle();
1504 CPPUNIT_ASSERT(!aView1
.m_bInvalidateTiles
);
1506 comphelper::LibreOfficeKit::setPartInInvalidation(oldPartInInvalidation
);
1509 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testInsertDeletePageInvalidation
)
1511 ScModelObj
* pModelObj
= createDoc("insert_delete_sheet.ods");
1512 // the document has 1 sheet
1513 CPPUNIT_ASSERT_EQUAL(1, pModelObj
->getParts());
1514 ScViewData
* pViewData
= ScDocShell::GetViewData();
1515 CPPUNIT_ASSERT(pViewData
);
1517 int nView1
= SfxLokHelper::getView();
1518 ViewCallback aView1
;
1519 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
1521 SfxLokHelper::setView(nView1
);
1522 aView1
.m_bInvalidateTiles
= false;
1523 aView1
.m_aInvalidations
.clear();
1525 uno::Sequence
<beans::PropertyValue
> aArgs( comphelper::InitPropertySequence({
1526 { "Name", uno::Any(u
""_ustr
) },
1527 { "Index", uno::Any(sal_Int32(1)) }
1529 dispatchCommand(mxComponent
, u
".uno:Insert"_ustr
, aArgs
);
1530 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
1531 CPPUNIT_ASSERT_EQUAL(size_t(2), aView1
.m_aInvalidations
.size());
1532 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(0, 0, 1000000000, 1000000000), aView1
.m_aInvalidations
[0]);
1533 CPPUNIT_ASSERT_EQUAL(2, pModelObj
->getParts());
1536 aView1
.m_bInvalidateTiles
= false;
1537 aView1
.m_aInvalidations
.clear();
1538 uno::Sequence
<beans::PropertyValue
> aArgs2( comphelper::InitPropertySequence({
1539 { "Index", uno::Any(sal_Int32(1)) }
1541 dispatchCommand(mxComponent
, u
".uno:Remove"_ustr
, aArgs2
);
1542 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
1543 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
1544 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(0, 0, 1000000000, 1000000000), aView1
.m_aInvalidations
[0]);
1545 CPPUNIT_ASSERT_EQUAL(1, pModelObj
->getParts());
1548 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testGetRowColumnHeadersInvalidation
)
1551 // If you run this test in isolation using CPPUNIT_TEST_NAME=, it will fail because the invalidations
1552 // will be different.
1554 ScModelObj
* pModelObj
= createDoc("empty.ods");
1555 ScViewData
* pViewData
= ScDocShell::GetViewData();
1556 CPPUNIT_ASSERT(pViewData
);
1558 int nView1
= SfxLokHelper::getView();
1559 ViewCallback aView1
;
1560 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
1562 SfxLokHelper::setView(nView1
);
1563 aView1
.m_bInvalidateTiles
= false;
1564 aView1
.m_aInvalidations
.clear();
1565 tools::JsonWriter aJsonWriter1
;
1566 pModelObj
->getRowColumnHeaders(tools::Rectangle(0, 15, 19650, 5400), aJsonWriter1
);
1567 aJsonWriter1
.finishAndGetAsOString();
1568 Scheduler::ProcessEventsToIdle();
1569 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
1570 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
1571 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(26775, 0), Size(22950, 13005)), aView1
.m_aInvalidations
[0]);
1573 // Extend area top-to-bottom
1574 aView1
.m_bInvalidateTiles
= false;
1575 aView1
.m_aInvalidations
.clear();
1576 tools::JsonWriter aJsonWriter2
;
1577 pModelObj
->getRowColumnHeaders(tools::Rectangle(0, 5400, 19650, 9800), aJsonWriter2
);
1578 aJsonWriter2
.finishAndGetAsOString();
1579 Scheduler::ProcessEventsToIdle();
1580 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
1581 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
1582 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(0, 13005), Size(49725, 6375)), aView1
.m_aInvalidations
[0]);
1584 // Extend area left-to-right
1585 aView1
.m_bInvalidateTiles
= false;
1586 aView1
.m_aInvalidations
.clear();
1587 tools::JsonWriter aJsonWriter3
;
1588 pModelObj
->getRowColumnHeaders(tools::Rectangle(5400, 5400, 25050, 9800), aJsonWriter3
);
1589 aJsonWriter3
.finishAndGetAsOString();
1590 Scheduler::ProcessEventsToIdle();
1591 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
1592 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
1593 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(49725, 0), Size(25500, 19380)), aView1
.m_aInvalidations
[0]);
1596 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testJumpHorizontallyInvalidation
)
1598 ScModelObj
* pModelObj
= createDoc("empty.ods");
1599 ScViewData
* pViewData
= ScDocShell::GetViewData();
1600 CPPUNIT_ASSERT(pViewData
);
1602 int nView1
= SfxLokHelper::getView();
1603 ViewCallback aView1
;
1604 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
1606 SfxLokHelper::setView(nView1
);
1607 aView1
.m_bInvalidateTiles
= false;
1608 aView1
.m_aInvalidations
.clear();
1609 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
| KEY_MOD2
);
1610 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
| KEY_MOD2
);
1611 Scheduler::ProcessEventsToIdle();
1612 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
| KEY_MOD2
);
1613 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
| KEY_MOD2
);
1614 Scheduler::ProcessEventsToIdle();
1615 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
1616 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
1617 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(26775, 0, 39525, 13005), aView1
.m_aInvalidations
[0]);
1620 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testJumpToLastRowInvalidation
)
1622 ScModelObj
* pModelObj
= createDoc("empty.ods");
1623 ScViewData
* pViewData
= ScDocShell::GetViewData();
1624 CPPUNIT_ASSERT(pViewData
);
1626 int nView1
= SfxLokHelper::getView();
1627 ViewCallback aView1
;
1628 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
1630 SfxLokHelper::setView(nView1
);
1631 aView1
.m_bInvalidateTiles
= false;
1632 aView1
.m_aInvalidations
.clear();
1633 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DOWN
| KEY_MOD1
);
1634 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DOWN
| KEY_MOD1
);
1635 Scheduler::ProcessEventsToIdle();
1636 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
1637 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
1638 // 261375 because we limit how far we jump into empty space in online, 267386880 if we don't limit
1639 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(0, 13005, 26775, 261375), aView1
.m_aInvalidations
[0]);
1642 // We need to ensure that views are not perterbed by rendering (!?) hmm ...
1643 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testRowColumnHeaders
)
1645 ScModelObj
* pModelObj
= createDoc("empty.ods");
1646 ScViewData
* pViewData
= ScDocShell::GetViewData();
1647 CPPUNIT_ASSERT(pViewData
);
1650 ViewCallback aView1
;
1651 int nView1
= SfxLokHelper::getView();
1652 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
1655 SfxLokHelper::createView();
1656 int nView2
= SfxLokHelper::getView();
1657 ViewCallback aView2
;
1658 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
1660 // ViewRowColumnHeaders test
1661 SfxLokHelper::setView(nView1
);
1662 tools::JsonWriter aJsonWriter1
;
1663 pModelObj
->getRowColumnHeaders(tools::Rectangle(65,723,10410,4695), aJsonWriter1
);
1664 OString aHeaders1
= aJsonWriter1
.finishAndGetAsOString();
1666 SfxLokHelper::setView(nView2
);
1668 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 22474, 47333));
1669 pModelObj
->setClientZoom(256, 256, 6636, 6636);
1670 tools::JsonWriter aJsonWriter2
;
1671 pModelObj
->getRowColumnHeaders(tools::Rectangle(65,723,10410,4695), aJsonWriter2
);
1672 OString aHeaders2
= aJsonWriter2
.finishAndGetAsOString();
1674 // Check vs. view #1
1675 SfxLokHelper::setView(nView1
);
1676 tools::JsonWriter aJsonWriter3
;
1677 pModelObj
->getRowColumnHeaders(tools::Rectangle(65,723,10410,4695), aJsonWriter3
);
1678 OString aHeaders1_2
= aJsonWriter3
.finishAndGetAsOString();
1679 CPPUNIT_ASSERT_EQUAL(aHeaders1
, aHeaders1_2
);
1681 // Check vs. view #2
1682 SfxLokHelper::setView(nView2
);
1683 tools::JsonWriter aJsonWriter4
;
1684 pModelObj
->getRowColumnHeaders(tools::Rectangle(65,723,10410,4695), aJsonWriter4
);
1685 OString aHeaders2_2
= aJsonWriter4
.finishAndGetAsOString();
1686 CPPUNIT_ASSERT_EQUAL(aHeaders2
, aHeaders2_2
);
1688 SfxLokHelper::setView(nView1
);
1689 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1690 SfxLokHelper::setView(nView2
);
1691 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1696 // Helper structs for setup and testing of ScModelObj::getSheetGeometryData()
1705 typedef std::vector
<SpanEntry
> SpanList
;
1709 // TODO: Add group info too to test.
1711 void setDataToDoc(ScDocument
* pDoc
, bool bCol
) const
1713 SCCOLROW nStart
= 0;
1715 for (const auto& rSpan
: aSizes
)
1719 for (SCCOLROW nIdx
= nStart
; nIdx
<= rSpan
.nEnd
; ++nIdx
)
1720 pDoc
->SetColWidthOnly(nIdx
, 0, rSpan
.nVal
);
1723 pDoc
->SetRowHeightOnly(nStart
, rSpan
.nEnd
, 0, rSpan
.nVal
);
1725 nStart
= rSpan
.nEnd
+ 1;
1730 for (const auto& rSpan
: aHidden
)
1733 pDoc
->SetColHidden(nStart
, rSpan
.nEnd
, 0, !!rSpan
.nVal
);
1735 pDoc
->SetRowHidden(nStart
, rSpan
.nEnd
, 0, !!rSpan
.nVal
);
1737 nStart
= rSpan
.nEnd
+ 1;
1740 // There is no ScDocument interface to set ScTable::mpFilteredCols
1741 // It seems ScTable::mpFilteredCols is not really used !?
1747 for (const auto& rSpan
: aFiltered
)
1749 pDoc
->SetRowFiltered(nStart
, rSpan
.nEnd
, 0, !!rSpan
.nVal
);
1750 nStart
= rSpan
.nEnd
+ 1;
1754 void testPropertyTree(const boost::property_tree::ptree
& rTree
, bool bCol
) const
1756 struct SpanListWithKey
1759 const SpanList
& rSpanList
;
1762 const SpanListWithKey aPairList
[] = {
1763 { "sizes"_ostr
, aSizes
},
1764 { "hidden"_ostr
, aHidden
},
1765 { "filtered"_ostr
, aFiltered
}
1768 for (const auto& rEntry
: aPairList
)
1770 // There is no ScDocument interface to set ScTable::mpFilteredCols
1771 // It seems ScTable::mpFilteredCols is not really used !?
1772 if (bCol
&& rEntry
.aKey
== "filtered")
1775 bool bBooleanValue
= rEntry
.aKey
!= "sizes";
1776 OString aExpectedEncoding
;
1778 for (const auto& rSpan
: rEntry
.rSpanList
)
1780 size_t nVal
= rSpan
.nVal
;
1781 if (bBooleanValue
&& bFirst
)
1782 nVal
= static_cast<size_t>(!!nVal
);
1783 if (!bBooleanValue
|| bFirst
)
1784 aExpectedEncoding
+= OString::number(nVal
) + ":";
1785 aExpectedEncoding
+= OString::number(rSpan
.nEnd
) + " ";
1789 // Get the tree's value for the property key ("sizes"/"hidden"/"filtered").
1790 OString
aTreeValue(rTree
.get
<std::string
>(rEntry
.aKey
.getStr()));
1792 CPPUNIT_ASSERT_EQUAL(aExpectedEncoding
, aTreeValue
);
1797 class SheetGeometryData
1804 SheetGeometryData(const SheetDimData
& rCols
, const SheetDimData
& rRows
) :
1805 aCols(rCols
), aRows(rRows
)
1808 void setDataToDoc(ScDocument
* pDoc
) const
1810 aCols
.setDataToDoc(pDoc
, true);
1811 aRows
.setDataToDoc(pDoc
, false);
1814 void parseTest(const OString
& rJSON
) const
1816 // Assumes all flags passed to getSheetGeometryData() are true.
1817 boost::property_tree::ptree aTree
;
1818 std::stringstream
aStream((std::string(rJSON
)));
1819 boost::property_tree::read_json(aStream
, aTree
);
1821 CPPUNIT_ASSERT_EQUAL(".uno:SheetGeometryData"_ostr
, OString(aTree
.get
<std::string
>("commandName")));
1823 aCols
.testPropertyTree(aTree
.get_child("columns"), true);
1824 aRows
.testPropertyTree(aTree
.get_child("rows"), false);
1829 // getSheetGeometryData() should return the exact same message
1830 // irrespective of client zoom and view-area. Switching views
1831 // should also not alter it.
1832 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testSheetGeometryDataInvariance
)
1834 ScModelObj
* pModelObj
= createDoc("empty.ods");
1835 ScDocument
* pDoc
= pModelObj
->GetDocument();
1836 const SheetGeometryData
aSGData(
1841 { STD_COL_WIDTH
, 20 },
1842 { 2*STD_COL_WIDTH
, 26 },
1843 { STD_COL_WIDTH
, pDoc
->MaxCol() }
1850 { 0, pDoc
->MaxCol() }
1857 { 0, pDoc
->MaxCol() }
1867 { 300, pDoc
->MaxRow() }
1875 { 0, pDoc
->MaxRow() }
1882 { 0, pDoc
->MaxRow() }
1887 ScViewData
* pViewData
= ScDocShell::GetViewData();
1888 CPPUNIT_ASSERT(pViewData
);
1891 ViewCallback aView1
;
1892 int nView1
= SfxLokHelper::getView();
1895 SfxLokHelper::createView();
1896 int nView2
= SfxLokHelper::getView();
1897 ViewCallback aView2
;
1898 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
1900 // Try with the default empty document once (nIdx = 0) and then with sheet geometry settings (nIdx = 1)
1901 for (size_t nIdx
= 0; nIdx
< 2; ++nIdx
)
1904 aSGData
.setDataToDoc(pDoc
);
1906 SfxLokHelper::setView(nView1
);
1907 OString aGeomStr1
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
1908 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
1910 SfxLokHelper::setView(nView2
);
1911 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 22474, 47333));
1912 pModelObj
->setClientZoom(256, 256, 6636, 6636);
1913 OString aGeomStr2
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
1914 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
1916 // Check vs. view #1
1917 SfxLokHelper::setView(nView1
);
1918 OString aGeomStr1_2
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
1919 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
1920 CPPUNIT_ASSERT_EQUAL(aGeomStr1
, aGeomStr1_2
);
1922 // Check vs. view #2
1923 SfxLokHelper::setView(nView2
);
1924 OString aGeomStr2_2
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
1925 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
1926 CPPUNIT_ASSERT_EQUAL(aGeomStr2
, aGeomStr2_2
);
1929 SfxLokHelper::setView(nView1
);
1930 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1931 SfxLokHelper::setView(nView2
);
1932 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
1935 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testSheetGeometryDataCorrectness
)
1937 ScModelObj
* pModelObj
= createDoc("empty.ods");
1938 ScDocument
* pDoc
= pModelObj
->GetDocument();
1939 const SheetGeometryData
aDefaultSGData(
1943 { { STD_COL_WIDTH
, pDoc
->MaxCol() } },
1945 { { 0, pDoc
->MaxCol() } },
1947 { { 0, pDoc
->MaxCol() } }
1952 { { ScGlobal::nStdRowHeight
, pDoc
->MaxRow() } },
1954 { { 0, pDoc
->MaxRow() } },
1956 { { 0, pDoc
->MaxRow() } }
1960 const SheetGeometryData
aSGData(
1965 { STD_COL_WIDTH
, 20 },
1966 { 2*STD_COL_WIDTH
, 26 },
1967 { STD_COL_WIDTH
, pDoc
->MaxCol() }
1974 { 0, pDoc
->MaxCol() }
1981 { 0, pDoc
->MaxCol() }
1991 { 300, pDoc
->MaxRow() }
1999 { 0, pDoc
->MaxRow() }
2006 { 0, pDoc
->MaxRow() }
2011 ScViewData
* pViewData
= ScDocShell::GetViewData();
2012 CPPUNIT_ASSERT(pViewData
);
2015 ViewCallback aView1
;
2017 // with the default empty sheet and test the JSON encoding.
2018 OString aGeomDefaultStr
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
2019 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
2020 aDefaultSGData
.parseTest(aGeomDefaultStr
);
2022 // Apply geometry settings to the sheet and then test the resulting JSON encoding.
2023 aSGData
.setDataToDoc(pDoc
);
2024 OString aGeomStr
= pModelObj
->getSheetGeometryData(/*bColumns*/ true, /*bRows*/ true, /*bSizes*/ true,
2025 /*bHidden*/ true, /*bFiltered*/ true, /*bGroups*/ true);
2026 aSGData
.parseTest(aGeomStr
);
2028 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2031 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testDeleteCellMultilineContent
)
2033 ScModelObj
* pModelObj
= createDoc("multiline.ods");
2034 CPPUNIT_ASSERT(pModelObj
);
2035 ScViewData
* pViewData
= ScDocShell::GetViewData();
2036 CPPUNIT_ASSERT(pViewData
);
2037 ScDocShell
* pDocSh
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
2038 CPPUNIT_ASSERT(pDocSh
);
2041 ViewCallback aView1
;
2042 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
2044 aView1
.m_sInvalidateHeader
= ""_ostr
;
2045 ScDocument
& rDoc
= pDocSh
->GetDocument();
2046 sal_uInt16 nRow1Height
= rDoc
.GetRowHeight(static_cast<SCROW
>(0), static_cast<SCTAB
>(0), false);
2048 // delete multiline cell content in view #1
2049 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DOWN
);
2050 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DOWN
);
2051 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DELETE
);
2052 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DELETE
);
2053 Scheduler::ProcessEventsToIdle();
2055 // check if the row header has been invalidated and if the involved row is of the expected height
2056 CPPUNIT_ASSERT_EQUAL("row"_ostr
, aView1
.m_sInvalidateHeader
);
2057 sal_uInt16 nRow2Height
= rDoc
.GetRowHeight(static_cast<SCROW
>(0), static_cast<SCTAB
>(0), false);
2058 CPPUNIT_ASSERT_EQUAL(nRow1Height
, nRow2Height
);
2059 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2062 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testPasteIntoWrapTextCell
)
2064 comphelper::LibreOfficeKit::setCompatFlag(
2065 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
2067 ScModelObj
* pModelObj
= createDoc("empty.ods");
2068 CPPUNIT_ASSERT(pModelObj
);
2069 ScDocument
* pDoc
= pModelObj
->GetDocument();
2071 // Set Wrap text in A3
2072 pDoc
->ApplyAttr(0, 2, 0, ScLineBreakCell(true));
2073 const ScLineBreakCell
* pItem
= pDoc
->GetAttr(0, 2, 0, ATTR_LINEBREAK
);
2074 CPPUNIT_ASSERT(pItem
->GetValue());
2076 ScViewData
* pViewData
= ScDocShell::GetViewData();
2077 CPPUNIT_ASSERT(pViewData
);
2080 CPPUNIT_ASSERT(!lcl_hasEditView(*pViewData
));
2082 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2083 CPPUNIT_ASSERT(pView
);
2085 // create source text in A1
2086 OUString
sCopyContent(u
"Very long text to copy"_ustr
);
2087 pDoc
->SetString(0, 0, 0, sCopyContent
);
2090 pView
->SetCursor(0, 0);
2091 Scheduler::ProcessEventsToIdle();
2092 pView
->GetViewFrame().GetBindings().Execute(SID_COPY
);
2093 Scheduler::ProcessEventsToIdle();
2096 uno::Reference
<datatransfer::clipboard::XClipboard
> xClipboard1
= pView
->GetViewData().GetActiveWin()->GetClipboard();
2097 uno::Reference
< datatransfer::XTransferable
> xDataObj
=
2098 xClipboard1
->getContents();
2099 datatransfer::DataFlavor aFlavor
;
2100 SotExchange::GetFormatDataFlavor(SotClipboardFormatId::STRING
, aFlavor
);
2101 uno::Any aData
= xDataObj
->getTransferData(aFlavor
);
2104 CPPUNIT_ASSERT_EQUAL(sCopyContent
, aTmpText
.trim());
2106 // Go to A2 and paste.
2107 pView
->SetCursor(0, 1);
2108 Scheduler::ProcessEventsToIdle();
2109 aView
.m_sInvalidateSheetGeometry
= ""_ostr
;
2110 pView
->GetViewFrame().GetBindings().Execute(SID_PASTE
);
2111 Scheduler::ProcessEventsToIdle();
2113 CPPUNIT_ASSERT_EQUAL(sCopyContent
, pDoc
->GetString(0, 1, 0));
2114 CPPUNIT_ASSERT_EQUAL("rows sizes"_ostr
, aView
.m_sInvalidateSheetGeometry
);
2116 // create new source text in A2
2117 OUString
sCopyContent2(u
"Very long text to copy 2"_ustr
);
2118 pDoc
->SetString(0, 1, 0, sCopyContent2
);
2119 Scheduler::ProcessEventsToIdle();
2122 pView
->GetViewFrame().GetBindings().Execute(SID_CUT
);
2123 Scheduler::ProcessEventsToIdle();
2126 uno::Reference
<datatransfer::clipboard::XClipboard
> xClipboard2
2127 = pView
->GetViewData().GetActiveWin()->GetClipboard();
2128 xDataObj
= xClipboard2
->getContents();
2129 SotExchange::GetFormatDataFlavor(SotClipboardFormatId::STRING
, aFlavor
);
2130 aData
= xDataObj
->getTransferData(aFlavor
);
2132 CPPUNIT_ASSERT_EQUAL(xClipboard1
, xClipboard2
);
2133 CPPUNIT_ASSERT_EQUAL(sCopyContent2
, aTmpText
.trim());
2135 // Go to A3 and paste.
2136 pView
->SetCursor(0, 2);
2137 Scheduler::ProcessEventsToIdle();
2138 aView
.m_sInvalidateSheetGeometry
= ""_ostr
;
2139 pView
->GetViewFrame().GetBindings().Execute(SID_PASTE
);
2140 Scheduler::ProcessEventsToIdle();
2142 // SG invalidations for all
2143 CPPUNIT_ASSERT_EQUAL(sCopyContent2
, pDoc
->GetString(0, 1, 0));
2144 CPPUNIT_ASSERT_EQUAL("all"_ostr
, aView
.m_sInvalidateSheetGeometry
);
2146 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2149 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testSortAscendingDescending
)
2151 comphelper::LibreOfficeKit::setCompatFlag(
2152 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
2153 ScModelObj
* pModelObj
= createDoc("sort-range.ods");
2154 ScDocument
* pDoc
= pModelObj
->GetDocument();
2158 // select the values in the first column
2159 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
, 551, 129, 1, MOUSE_LEFT
, 0);
2160 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEMOVE
, 820, 1336, 1, MOUSE_LEFT
, 0);
2161 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
, 820, 1359, 1, MOUSE_LEFT
, 0);
2162 Scheduler::ProcessEventsToIdle();
2163 aView
.m_sInvalidateSheetGeometry
= ""_ostr
;
2166 uno::Sequence
<beans::PropertyValue
> aArgs
;
2167 dispatchCommand(mxComponent
, u
".uno:SortAscending"_ustr
, aArgs
);
2169 // check it's sorted
2170 for (SCROW r
= 0; r
< 6; ++r
)
2172 CPPUNIT_ASSERT_EQUAL(double(r
+ 1), pDoc
->GetValue(ScAddress(0, r
, 0)));
2175 Scheduler::ProcessEventsToIdle();
2176 CPPUNIT_ASSERT_EQUAL("rows"_ostr
, aView
.m_sInvalidateSheetGeometry
);
2178 aView
.m_sInvalidateSheetGeometry
= ""_ostr
;
2180 dispatchCommand(mxComponent
, u
".uno:SortDescending"_ustr
, aArgs
);
2182 // check it's sorted
2183 for (SCROW r
= 0; r
< 6; ++r
)
2185 CPPUNIT_ASSERT_EQUAL(double(6 - r
), pDoc
->GetValue(ScAddress(0, r
, 0)));
2188 // nothing else was sorted
2189 CPPUNIT_ASSERT_EQUAL(double(1), pDoc
->GetValue(ScAddress(1, 0, 0)));
2190 CPPUNIT_ASSERT_EQUAL(double(3), pDoc
->GetValue(ScAddress(1, 1, 0)));
2191 CPPUNIT_ASSERT_EQUAL(double(2), pDoc
->GetValue(ScAddress(1, 2, 0)));
2193 Scheduler::ProcessEventsToIdle();
2194 CPPUNIT_ASSERT_EQUAL("rows"_ostr
, aView
.m_sInvalidateSheetGeometry
);
2197 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testAutoInputStringBlock
)
2199 ScModelObj
* pModelObj
= createDoc("empty.ods");
2200 CPPUNIT_ASSERT(pModelObj
);
2201 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2202 CPPUNIT_ASSERT(pView
);
2203 ScDocument
* pDoc
= pModelObj
->GetDocument();
2205 pDoc
->SetString(ScAddress(0, 3, 0), u
"ABC"_ustr
); // A4
2206 pDoc
->SetString(ScAddress(0, 4, 0), u
"BAC"_ustr
); // A5
2207 ScFieldEditEngine
& rEE
= pDoc
->GetEditEngine();
2208 rEE
.SetText(u
"XYZ"_ustr
);
2209 pDoc
->SetEditText(ScAddress(0, 5, 0), rEE
.CreateTextObject()); // A6
2210 pDoc
->SetValue(ScAddress(0, 6, 0), 123);
2211 pDoc
->SetString(ScAddress(0, 7, 0), u
"ZZZ"_ustr
); // A8
2213 ScAddress
aA1(0, 0, 0);
2214 lcl_typeCharsInCell("X", aA1
.Col(), aA1
.Row(), pView
, pModelObj
); // Type 'X' in A1
2215 CPPUNIT_ASSERT_EQUAL_MESSAGE("A1 should autocomplete", u
"XYZ"_ustr
, pDoc
->GetString(aA1
));
2217 ScAddress
aA3(0, 2, 0); // Adjacent to the string "superblock" A4:A8
2218 lcl_typeCharsInCell("X", aA3
.Col(), aA3
.Row(), pView
, pModelObj
); // Type 'X' in A3
2219 CPPUNIT_ASSERT_EQUAL_MESSAGE("A3 should autocomplete", u
"XYZ"_ustr
, pDoc
->GetString(aA3
));
2221 ScAddress
aA9(0, 8, 0); // Adjacent to the string "superblock" A4:A8
2222 lcl_typeCharsInCell("X", aA9
.Col(), aA9
.Row(), pView
, pModelObj
); // Type 'X' in A9
2223 CPPUNIT_ASSERT_EQUAL_MESSAGE("A9 should autocomplete", u
"XYZ"_ustr
, pDoc
->GetString(aA9
));
2225 ScAddress
aA11(0, 10, 0);
2226 lcl_typeCharsInCell("X", aA11
.Col(), aA11
.Row(), pView
, pModelObj
); // Type 'X' in A11
2227 CPPUNIT_ASSERT_EQUAL_MESSAGE("A11 should autocomplete", u
"XYZ"_ustr
, pDoc
->GetString(aA11
));
2230 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testAutoInputExactMatch
)
2232 ScModelObj
* pModelObj
= createDoc("empty.ods");
2233 CPPUNIT_ASSERT(pModelObj
);
2234 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2235 CPPUNIT_ASSERT(pView
);
2236 ScDocument
* pDoc
= pModelObj
->GetDocument();
2238 pDoc
->SetString(ScAddress(0, 1, 0), u
"Simple"_ustr
); // A2
2239 pDoc
->SetString(ScAddress(0, 2, 0), u
"Simple"_ustr
); // A3
2240 pDoc
->SetString(ScAddress(0, 3, 0), u
"Sing"_ustr
); // A4
2241 ScFieldEditEngine
& rEE
= pDoc
->GetEditEngine();
2242 rEE
.SetText(u
"Case"_ustr
);
2243 pDoc
->SetEditText(ScAddress(0, 4, 0), rEE
.CreateTextObject()); // A5
2244 pDoc
->SetString(ScAddress(0, 5, 0), u
"Time"_ustr
); // A6
2245 pDoc
->SetString(ScAddress(0, 6, 0), u
"Castle"_ustr
); // A7
2247 ScAddress
aA8(0, 7, 0);
2248 lcl_typeCharsInCell("S", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "S" in A8
2249 // Should show the partial completion "i".
2250 CPPUNIT_ASSERT_EQUAL_MESSAGE("1: A8 should have partial completion Si", u
"Si"_ustr
, pDoc
->GetString(aA8
));
2252 lcl_typeCharsInCell("Si", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "Si" in A8
2253 // Should not show any suggestions.
2254 CPPUNIT_ASSERT_EQUAL_MESSAGE("2: A8 should not show suggestions", u
"Si"_ustr
, pDoc
->GetString(aA8
));
2256 lcl_typeCharsInCell("Sim", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "Sim" in A8
2257 // Should autocomplete to "Simple" which is the only match.
2258 CPPUNIT_ASSERT_EQUAL_MESSAGE("3: A8 should autocomplete", u
"Simple"_ustr
, pDoc
->GetString(aA8
));
2260 lcl_typeCharsInCell("Sin", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "Sin" in A8
2261 // Should autocomplete to "Sing" which is the only match.
2262 CPPUNIT_ASSERT_EQUAL_MESSAGE("4: A8 should autocomplete", u
"Sing"_ustr
, pDoc
->GetString(aA8
));
2264 lcl_typeCharsInCell("C", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "C" in A8
2265 // Should show the partial completion "as".
2266 CPPUNIT_ASSERT_EQUAL_MESSAGE("5: A8 should have partial completion Cas", u
"Cas"_ustr
, pDoc
->GetString(aA8
));
2268 lcl_typeCharsInCell("Cast", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "Cast" in A8
2269 // Should autocomplete to "Castle" which is the only match.
2270 CPPUNIT_ASSERT_EQUAL_MESSAGE("6: A8 should autocomplete", u
"Castle"_ustr
, pDoc
->GetString(aA8
));
2272 lcl_typeCharsInCell("T", aA8
.Col(), aA8
.Row(), pView
, pModelObj
); // Type "T" in A8
2273 // Should autocomplete to "Time" which is the only match.
2274 CPPUNIT_ASSERT_EQUAL_MESSAGE("7: A8 should autocomplete", u
"Time"_ustr
, pDoc
->GetString(aA8
));
2277 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testEditCursorBounds
)
2279 comphelper::LibreOfficeKit::setCompatFlag(
2280 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
2281 ScModelObj
* pModelObj
= createDoc("empty.ods");
2282 ScDocument
* pDoc
= pModelObj
->GetDocument();
2285 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2286 CPPUNIT_ASSERT(pView
);
2287 comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(true);
2290 pModelObj
->setClientZoom(256, 256, 2222, 2222);
2291 pModelObj
->setClientVisibleArea(tools::Rectangle(7725, 379832, 16240, 6449));
2292 Scheduler::ProcessEventsToIdle();
2294 constexpr SCCOL nCol
= 5;
2295 constexpr SCROW nRow
= 2048;
2296 pDoc
->SetValue(ScAddress(nCol
, nRow
, 0), 123);
2298 aView
.m_bOwnCursorInvalidated
= false;
2299 // Obtain the cell bounds via cursor.
2300 pView
->SetCursor(nCol
, nRow
);
2301 Scheduler::ProcessEventsToIdle();
2303 CPPUNIT_ASSERT(aView
.m_bOwnCursorInvalidated
);
2304 CPPUNIT_ASSERT(!aView
.m_aCellCursorBounds
.IsEmpty());
2305 tools::Rectangle
aCellBounds(aView
.m_aCellCursorBounds
);
2307 aView
.m_aInvalidateCursorResult
.clear();
2308 // Enter edit mode in the same cell.
2309 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::F2
);
2310 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::F2
);
2311 Scheduler::ProcessEventsToIdle();
2313 CPPUNIT_ASSERT(!aView
.m_aInvalidateCursorResult
.empty());
2314 CPPUNIT_ASSERT_MESSAGE("Edit cursor must be in cell bounds!",
2315 aCellBounds
.Contains(aView
.m_aInvalidateCursorResult
.getBounds()));
2317 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2320 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testTextSelectionBounds
)
2322 comphelper::LibreOfficeKit::setCompatFlag(
2323 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
2324 ScModelObj
* pModelObj
= createDoc("empty.ods");
2325 ScDocument
* pDoc
= pModelObj
->GetDocument();
2328 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2329 CPPUNIT_ASSERT(pView
);
2330 comphelper::LibreOfficeKit::setViewIdForVisCursorInvalidation(true);
2333 pModelObj
->setClientZoom(256, 256, 2222, 2222);
2334 pModelObj
->setClientVisibleArea(tools::Rectangle(7725, 379832, 16240, 6449));
2335 Scheduler::ProcessEventsToIdle();
2337 constexpr SCCOL nCol
= 5;
2338 constexpr SCROW nRow
= 2048;
2339 pDoc
->SetValue(ScAddress(nCol
, nRow
, 0), 123);
2341 aView
.m_bOwnCursorInvalidated
= false;
2342 // Obtain the cell bounds via cursor.
2343 pView
->SetCursor(nCol
, nRow
);
2344 Scheduler::ProcessEventsToIdle();
2346 CPPUNIT_ASSERT(aView
.m_bOwnCursorInvalidated
);
2347 CPPUNIT_ASSERT(!aView
.m_aCellCursorBounds
.IsEmpty());
2348 tools::Rectangle
aCellBounds(aView
.m_aCellCursorBounds
);
2350 aView
.m_aTextSelectionResult
.clear();
2351 // Enter edit mode in the same cell and select all text.
2352 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::F2
);
2353 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::F2
);
2354 Scheduler::ProcessEventsToIdle();
2357 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_MOD1
| awt::Key::A
);
2358 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_MOD1
| awt::Key::A
);
2359 Scheduler::ProcessEventsToIdle();
2361 CPPUNIT_ASSERT(!aView
.m_aTextSelectionResult
.empty());
2362 CPPUNIT_ASSERT_MESSAGE("Text selections must be in cell bounds!",
2363 !aCellBounds
.Intersection(aView
.m_aTextSelectionResult
.getBounds(0)).IsEmpty());
2365 SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
2368 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testSheetViewDataCrash
)
2370 ScModelObj
* pModelObj
= createDoc("empty.ods");
2373 int nView1
= SfxLokHelper::getView();
2374 SfxLokHelper::setView(nView1
);
2376 // Imitate online while creating a new sheet on empty.ods.
2377 uno::Sequence
<beans::PropertyValue
> aArgs(
2378 comphelper::InitPropertySequence({
2379 { "Name", uno::Any(u
"NewSheet"_ustr
) },
2380 { "Index", uno::Any(sal_Int32(2)) }
2382 dispatchCommand(mxComponent
, u
".uno:Insert"_ustr
, aArgs
);
2383 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
2384 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
2385 Scheduler::ProcessEventsToIdle();
2386 ScTabViewShell
* pView1
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2387 CPPUNIT_ASSERT(pView1
);
2390 SfxLokHelper::createView();
2391 ScTabViewShell
* pView2
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2392 CPPUNIT_ASSERT(pView2
);
2393 Scheduler::ProcessEventsToIdle();
2395 SfxLokHelper::setView(nView1
);
2397 pView1
->SetCursor(1, 1);
2398 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DOWN
| KEY_SHIFT
);
2399 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DOWN
| KEY_SHIFT
);
2400 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DELETE
);
2401 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DELETE
);
2402 // It will crash at this point without the fix.
2403 Scheduler::ProcessEventsToIdle();
2406 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testTextBoxInsert
)
2408 createDoc("empty.ods");
2409 ViewCallback aView1
;
2412 uno::Sequence
<beans::PropertyValue
> aArgs(
2413 comphelper::InitPropertySequence({
2414 { "CreateDirectly", uno::Any(true) }
2416 dispatchCommand(mxComponent
, u
".uno:DrawText"_ustr
, aArgs
);
2418 // check if we have textbox selected
2419 CPPUNIT_ASSERT(!aView1
.m_ShapeSelection
.isEmpty());
2420 CPPUNIT_ASSERT(aView1
.m_ShapeSelection
!= "EMPTY");
2422 Scheduler::ProcessEventsToIdle();
2425 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testCommentCellCopyPaste
)
2427 // Comments callback are emitted only if tiled annotations are off
2428 comphelper::LibreOfficeKit::setTiledAnnotations(false);
2430 // FIXME: Hack because previous tests do not destroy ScDocument(with annotations) on exit (?).
2431 ScPostIt::mnLastPostItId
= 1;
2434 ScModelObj
* pModelObj
= createDoc("empty.ods");
2436 int nView
= SfxLokHelper::getView();
2438 SfxLokHelper::setView(nView
);
2440 ScTabViewShell
* pTabViewShell
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2441 CPPUNIT_ASSERT(pTabViewShell
);
2443 lcl_typeCharsInCell("ABC", 0, 0, pTabViewShell
, pModelObj
); // Type "ABC" in A1
2445 pTabViewShell
->SetCursor(1, 1);
2447 // Add a new comment
2448 uno::Sequence
<beans::PropertyValue
> aArgs(comphelper::InitPropertySequence(
2450 {"Text", uno::Any(u
"LOK Comment Cell B2"_ustr
)},
2451 {"Author", uno::Any(u
"LOK Client"_ustr
)},
2453 dispatchCommand(mxComponent
, u
".uno:InsertAnnotation"_ustr
, aArgs
);
2455 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action
2456 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2457 CPPUNIT_ASSERT_EQUAL(std::string("1"), aView
.m_aCommentCallbackResult
.get
<std::string
>("id"));
2458 CPPUNIT_ASSERT_EQUAL(std::string("0"), aView
.m_aCommentCallbackResult
.get
<std::string
>("tab"));
2459 CPPUNIT_ASSERT_EQUAL(std::string("LOK Client"), aView
.m_aCommentCallbackResult
.get
<std::string
>("author"));
2460 CPPUNIT_ASSERT_EQUAL(std::string("LOK Comment Cell B2"), aView
.m_aCommentCallbackResult
.get
<std::string
>("text"));
2462 uno::Sequence
<beans::PropertyValue
> aCopyPasteArgs
;
2464 // We need separate tests for single cell copy-paste and cell-range copy-paste
2465 // since they hit different code paths in ScColumn methods.
2467 // Single cell(with comment) copy paste test
2469 dispatchCommand(mxComponent
, u
".uno:Copy"_ustr
, aCopyPasteArgs
);
2471 pTabViewShell
->SetCursor(1, 49);
2472 Scheduler::ProcessEventsToIdle();
2473 dispatchCommand(mxComponent
, u
".uno:Paste"_ustr
, aCopyPasteArgs
); // Paste to cell B50
2475 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action
2476 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2477 // Without the fix the id will be "1".
2478 CPPUNIT_ASSERT_EQUAL(std::string("2"), aView
.m_aCommentCallbackResult
.get
<std::string
>("id"));
2479 CPPUNIT_ASSERT_EQUAL(std::string("0"), aView
.m_aCommentCallbackResult
.get
<std::string
>("tab"));
2480 CPPUNIT_ASSERT_EQUAL(std::string("LOK Client"), aView
.m_aCommentCallbackResult
.get
<std::string
>("author"));
2481 CPPUNIT_ASSERT_EQUAL(std::string("LOK Comment Cell B2"), aView
.m_aCommentCallbackResult
.get
<std::string
>("text"));
2484 // Cell range (with a comment) copy paste test
2486 // Select range A1:C3
2487 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_HOME
| KEY_MOD1
);
2488 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_HOME
| KEY_MOD1
);
2489 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
| KEY_SHIFT
);
2490 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
| KEY_SHIFT
);
2491 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
| KEY_SHIFT
);
2492 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
| KEY_SHIFT
);
2493 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_RIGHT
| KEY_SHIFT
);
2494 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_RIGHT
| KEY_SHIFT
);
2495 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_RIGHT
| KEY_SHIFT
);
2496 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_RIGHT
| KEY_SHIFT
);
2497 Scheduler::ProcessEventsToIdle();
2499 dispatchCommand(mxComponent
, u
".uno:Copy"_ustr
, aCopyPasteArgs
);
2501 pTabViewShell
->SetCursor(3, 49);
2502 Scheduler::ProcessEventsToIdle();
2503 dispatchCommand(mxComponent
, u
".uno:Paste"_ustr
, aCopyPasteArgs
); // Paste to cell D50
2505 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action
2506 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView
.m_aCommentCallbackResult
.get
<std::string
>("action"));
2507 // Without the fix the id will be "1".
2508 CPPUNIT_ASSERT_EQUAL(std::string("3"), aView
.m_aCommentCallbackResult
.get
<std::string
>("id"));
2509 CPPUNIT_ASSERT_EQUAL(std::string("0"), aView
.m_aCommentCallbackResult
.get
<std::string
>("tab"));
2510 CPPUNIT_ASSERT_EQUAL(std::string("LOK Client"), aView
.m_aCommentCallbackResult
.get
<std::string
>("author"));
2511 CPPUNIT_ASSERT_EQUAL(std::string("LOK Comment Cell B2"), aView
.m_aCommentCallbackResult
.get
<std::string
>("text"));
2514 comphelper::LibreOfficeKit::setTiledAnnotations(true);
2517 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testInvalidEntrySave
)
2519 loadFromFile(u
"validity.xlsx");
2521 // .uno:Save modifies the original file, make a copy first
2522 saveAndReload(u
"Calc Office Open XML"_ustr
);
2523 ScModelObj
* pModelObj
= comphelper::getFromUnoTunnel
<ScModelObj
>(mxComponent
);
2524 CPPUNIT_ASSERT(pModelObj
);
2525 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
2526 const ScDocument
* pDoc
= pModelObj
->GetDocument();
2528 int nView
= SfxLokHelper::getView();
2530 SfxLokHelper::setView(nView
);
2532 ScDocShell
* pDocSh
= dynamic_cast< ScDocShell
* >( pModelObj
->GetEmbeddedObject() );
2533 ScTabViewShell
* pTabViewShell
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2534 CPPUNIT_ASSERT(pTabViewShell
);
2536 // Type partial date "7/8" of "7/8/2013" that
2537 // the validation cell at A8 can accept
2538 lcl_typeCharsInCell("7/8", 0, 7, pTabViewShell
, pModelObj
,
2539 false /* bInEdit */, false /* bCommit */); // Type "7/8" in A8
2541 uno::Sequence
<beans::PropertyValue
> aArgs
;
2542 dispatchCommand(mxComponent
, u
".uno:Save"_ustr
, aArgs
);
2544 CPPUNIT_ASSERT_MESSAGE("Should not be marked modified after save", !pDocSh
->IsModified());
2546 // Complete the date in A8 by appending "/2013" and commit.
2547 lcl_typeCharsInCell("/2013", 0, 7, pTabViewShell
, pModelObj
,
2548 true /* bInEdit */, true /* bCommit */);
2550 // This would hang if the date entered "7/8/2013" is not acceptable.
2551 Scheduler::ProcessEventsToIdle();
2553 // Ensure that the correct date is recorded in the document.
2554 CPPUNIT_ASSERT_EQUAL(double(41463), pDoc
->GetValue(ScAddress(0, 7, 0)));
2557 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testUndoReordering
)
2559 ScModelObj
* pModelObj
= createDoc("small.ods");
2560 CPPUNIT_ASSERT(pModelObj
);
2561 ScDocument
* pDoc
= pModelObj
->GetDocument();
2562 CPPUNIT_ASSERT(pDoc
);
2563 ScUndoManager
* pUndoManager
= pDoc
->GetUndoManager();
2564 CPPUNIT_ASSERT(pUndoManager
);
2567 int nView1
= SfxLokHelper::getView();
2568 ViewCallback aView1
;
2571 SfxLokHelper::createView();
2572 int nView2
= SfxLokHelper::getView();
2573 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
2574 ViewCallback aView2
;
2576 // text edit a cell in view #1
2577 SfxLokHelper::setView(nView1
);
2578 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
2579 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
2580 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
2581 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
2582 Scheduler::ProcessEventsToIdle();
2584 // check that undo action count is not 0
2585 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
2587 // text edit a different cell in view #2
2588 SfxLokHelper::setView(nView2
);
2589 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
);
2590 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
);
2591 Scheduler::ProcessEventsToIdle();
2592 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DOWN
);
2593 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DOWN
);
2594 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
2595 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
2596 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
2597 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
2598 Scheduler::ProcessEventsToIdle();
2600 // check that undo action count is not 1
2601 CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager
->GetUndoActionCount());
2603 // try to execute undo in view #1
2604 SfxLokHelper::setView(nView1
);
2605 dispatchCommand(mxComponent
, u
".uno:Undo"_ustr
, {});
2606 // check that undo has been executed on view #1
2607 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
2609 // try to execute undo in view #2
2610 SfxLokHelper::setView(nView2
);
2611 dispatchCommand(mxComponent
, u
".uno:Undo"_ustr
, {});
2612 // check that undo has been executed on view #2
2613 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetUndoActionCount());
2616 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testUndoReorderingRedo
)
2618 ScModelObj
* pModelObj
= createDoc("empty.ods");
2619 CPPUNIT_ASSERT(pModelObj
);
2620 ScDocument
* pDoc
= pModelObj
->GetDocument();
2621 CPPUNIT_ASSERT(pDoc
);
2622 ScUndoManager
* pUndoManager
= pDoc
->GetUndoManager();
2623 CPPUNIT_ASSERT(pUndoManager
);
2624 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetUndoActionCount());
2627 int nView1
= SfxLokHelper::getView();
2628 SfxViewShell
* pView1
= SfxViewShell::Current();
2629 ViewCallback aView1
;
2632 SfxLokHelper::createView();
2633 int nView2
= SfxLokHelper::getView();
2634 SfxViewShell
* pView2
= SfxViewShell::Current();
2635 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
2636 ViewCallback aView2
;
2638 // text edit a cell in view #1
2639 SfxLokHelper::setView(nView1
);
2640 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
2641 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
2642 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
2643 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
2644 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
2645 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
2646 Scheduler::ProcessEventsToIdle();
2647 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
2649 // text edit another cell in view #1
2650 SfxLokHelper::setView(nView1
);
2651 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'y', 0);
2652 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'y', 0);
2653 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'y', 0);
2654 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'y', 0);
2655 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
2656 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
2657 Scheduler::ProcessEventsToIdle();
2658 CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager
->GetUndoActionCount());
2659 CPPUNIT_ASSERT_EQUAL(u
"xx"_ustr
, pDoc
->GetString(ScAddress(0, 0, 0)));
2660 CPPUNIT_ASSERT_EQUAL(u
"yy"_ustr
, pDoc
->GetString(ScAddress(0, 1, 0)));
2662 // text edit a different cell in view #2
2663 SfxLokHelper::setView(nView2
);
2664 ScTabViewShell
* pViewShell2
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2665 pViewShell2
->SetCursor(0, 2);
2666 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'C', 0);
2667 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'C', 0);
2668 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'C', 0);
2669 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'C', 0);
2670 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
2671 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
2672 Scheduler::ProcessEventsToIdle();
2673 CPPUNIT_ASSERT_EQUAL(std::size_t(3), pUndoManager
->GetUndoActionCount());
2674 CPPUNIT_ASSERT_EQUAL(u
"xx"_ustr
, pDoc
->GetString(ScAddress(0, 0, 0)));
2675 CPPUNIT_ASSERT_EQUAL(u
"yy"_ustr
, pDoc
->GetString(ScAddress(0, 1, 0)));
2676 CPPUNIT_ASSERT_EQUAL(u
"CC"_ustr
, pDoc
->GetString(ScAddress(0, 2, 0)));
2678 // View 1 presses undo, and the second cell is erased
2679 SfxLokHelper::setView(nView1
);
2680 dispatchCommand(mxComponent
, u
".uno:Undo"_ustr
, {});
2681 CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager
->GetUndoActionCount());
2682 CPPUNIT_ASSERT_EQUAL(u
"xx"_ustr
, pDoc
->GetString(ScAddress(0, 0, 0)));
2683 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, pDoc
->GetString(ScAddress(0, 1, 0)));
2684 CPPUNIT_ASSERT_EQUAL(u
"CC"_ustr
, pDoc
->GetString(ScAddress(0, 2, 0)));
2686 // Verify that the UNDO buttons/actions are still enabled
2688 SfxItemSet
aSet1(pView1
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
2689 SfxItemSet
aSet2(pView2
->GetPool(), svl::Items
<SID_UNDO
, SID_UNDO
>);
2690 pView1
->GetSlotState(SID_UNDO
, nullptr, &aSet1
);
2691 pView2
->GetSlotState(SID_UNDO
, nullptr, &aSet2
);
2692 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet1
.GetItemState(SID_UNDO
));
2693 CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem
* >(aSet1
.GetItem(SID_UNDO
)));
2694 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, aSet2
.GetItemState(SID_UNDO
));
2695 CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem
* >(aSet2
.GetItem(SID_UNDO
)));
2698 // View 1 presses undo again, and the first cell is erased
2699 dispatchCommand(mxComponent
, u
".uno:Undo"_ustr
, {});
2700 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
2701 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, pDoc
->GetString(ScAddress(0, 0, 0)));
2702 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, pDoc
->GetString(ScAddress(0, 1, 0)));
2703 CPPUNIT_ASSERT_EQUAL(u
"CC"_ustr
, pDoc
->GetString(ScAddress(0, 2, 0)));
2706 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testUndoReorderingMulti
)
2708 ScModelObj
* pModelObj
= createDoc("empty.ods");
2709 CPPUNIT_ASSERT(pModelObj
);
2710 ScDocument
* pDoc
= pModelObj
->GetDocument();
2711 CPPUNIT_ASSERT(pDoc
);
2712 ScUndoManager
* pUndoManager
= pDoc
->GetUndoManager();
2713 CPPUNIT_ASSERT(pUndoManager
);
2714 CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager
->GetUndoActionCount());
2717 int nView1
= SfxLokHelper::getView();
2718 ViewCallback aView1
;
2721 SfxLokHelper::createView();
2722 int nView2
= SfxLokHelper::getView();
2723 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
2724 ViewCallback aView2
;
2726 // text edit a cell in view #1
2727 SfxLokHelper::setView(nView1
);
2728 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
2729 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
2730 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
2731 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
2732 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
2733 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
2734 Scheduler::ProcessEventsToIdle();
2735 CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager
->GetUndoActionCount());
2737 // text edit a different cell in view #2
2738 SfxLokHelper::setView(nView2
);
2739 ScTabViewShell
* pView2
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2740 pView2
->SetCursor(0, 2);
2741 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'C', 0);
2742 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'C', 0);
2743 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'C', 0);
2744 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'C', 0);
2745 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
2746 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
2747 Scheduler::ProcessEventsToIdle();
2748 CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager
->GetUndoActionCount());
2749 CPPUNIT_ASSERT_EQUAL(u
"xx"_ustr
, pDoc
->GetString(ScAddress(0, 0, 0)));
2750 CPPUNIT_ASSERT_EQUAL(u
"CC"_ustr
, pDoc
->GetString(ScAddress(0, 2, 0)));
2752 // and another cell in view #2
2753 pView2
->SetCursor(0, 3);
2754 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'D', 0);
2755 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'D', 0);
2756 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'D', 0);
2757 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'D', 0);
2758 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::RETURN
);
2759 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::RETURN
);
2760 Scheduler::ProcessEventsToIdle();
2761 CPPUNIT_ASSERT_EQUAL(std::size_t(3), pUndoManager
->GetUndoActionCount());
2762 CPPUNIT_ASSERT_EQUAL(u
"xx"_ustr
, pDoc
->GetString(ScAddress(0, 0, 0)));
2763 CPPUNIT_ASSERT_EQUAL(u
"CC"_ustr
, pDoc
->GetString(ScAddress(0, 2, 0)));
2764 CPPUNIT_ASSERT_EQUAL(u
"DD"_ustr
, pDoc
->GetString(ScAddress(0, 3, 0)));
2766 // View 1 presses undo
2767 SfxLokHelper::setView(nView1
);
2768 dispatchCommand(mxComponent
, u
".uno:Undo"_ustr
, {});
2769 CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager
->GetUndoActionCount());
2770 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, pDoc
->GetString(ScAddress(0, 0, 0)));
2771 CPPUNIT_ASSERT_EQUAL(u
"CC"_ustr
, pDoc
->GetString(ScAddress(0, 2, 0)));
2772 CPPUNIT_ASSERT_EQUAL(u
"DD"_ustr
, pDoc
->GetString(ScAddress(0, 3, 0)));
2775 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testGetViewRenderState
)
2777 // Add a pair of schemes, last added is the default
2778 svtools::EditableColorConfig aColorConfig
;
2779 aColorConfig
.AddScheme(u
"Dark"_ustr
);
2780 aColorConfig
.AddScheme(u
"Light"_ustr
);
2782 ScModelObj
* pModelObj
= createDoc("empty.ods");
2783 int nFirstViewId
= SfxLokHelper::getView();
2784 ViewCallback aView1
;
2786 CPPUNIT_ASSERT_EQUAL("S;Default"_ostr
, pModelObj
->getViewRenderState());
2787 // Create a second view
2788 SfxLokHelper::createView();
2789 ViewCallback aView2
;
2790 CPPUNIT_ASSERT_EQUAL("S;Default"_ostr
, pModelObj
->getViewRenderState());
2791 // Set second view to dark scheme
2793 uno::Sequence
<beans::PropertyValue
> aPropertyValues
= comphelper::InitPropertySequence(
2795 { "NewTheme", uno::Any(u
"Dark"_ustr
) },
2798 dispatchCommand(mxComponent
, u
".uno:ChangeTheme"_ustr
, aPropertyValues
);
2800 CPPUNIT_ASSERT_EQUAL("S;Dark"_ostr
, pModelObj
->getViewRenderState());
2802 // Switch back to first view and make sure it's the same
2803 SfxLokHelper::setView(nFirstViewId
);
2804 CPPUNIT_ASSERT_EQUAL("S;Default"_ostr
, pModelObj
->getViewRenderState());
2808 * testInvalidateOnTextEditWithDifferentZoomLevels
2810 * set view 1 zoom to the passed zoom level
2811 * in view 1 type a char at the passed cell address
2812 * store invalidation rectangle
2813 * exit from in place editing (press esc)
2814 * create view 2 (keep 100% zoom)
2815 * go to the same cell address used in view 1
2816 * type a char into the cell
2817 * get invalidation rectangle for view 1
2818 * check if the invalidation rectangle is equal to the one stored previously
2820 class testInvalidateOnTextEditWithDifferentZoomLevels
: public ScTiledRenderingTest
2823 void TestBody(const ColRowZoom
& rData
);
2824 CPPUNIT_TEST_SUITE(testInvalidateOnTextEditWithDifferentZoomLevels
);
2825 CPPUNIT_TEST_PARAMETERIZED(TestBody
,
2826 std::initializer_list
<ColRowZoom
>
2829 {0, 999, 1}, {99, 0, 1},
2831 {0, 999, -5}, {99, 0, -5}
2833 CPPUNIT_TEST_SUITE_END();
2835 CPPUNIT_TEST_SUITE_REGISTRATION(testInvalidateOnTextEditWithDifferentZoomLevels
);
2837 void testInvalidateOnTextEditWithDifferentZoomLevels::TestBody(const ColRowZoom
& rData
)
2839 ScModelObj
* pModelObj
= createDoc("empty.ods");
2840 CPPUNIT_ASSERT(pModelObj
);
2841 ScDocument
* pDoc
= pModelObj
->GetDocument();
2842 CPPUNIT_ASSERT(pDoc
);
2843 OUString sZoomUnoCmd
= u
".uno:ZoomPlus"_ustr
;
2844 int nZoomLevel
= rData
.zoom
;
2847 nZoomLevel
= -nZoomLevel
;
2848 sZoomUnoCmd
= ".uno:ZoomMinus";
2851 ViewCallback aView1
;
2853 for (int i
= 0; i
< nZoomLevel
; ++i
)
2854 dispatchCommand(mxComponent
, sZoomUnoCmd
, {});
2855 Scheduler::ProcessEventsToIdle();
2856 auto* pTabViewShell1
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2857 CPPUNIT_ASSERT(pTabViewShell1
);
2858 // enable in place editing in view 1
2859 auto& rInvalidations
= aView1
.m_aInvalidations
;
2860 pTabViewShell1
->SetCursor(rData
.col
, rData
.row
);
2861 Scheduler::ProcessEventsToIdle();
2862 aView1
.m_bInvalidateTiles
= false;
2863 rInvalidations
.clear();
2864 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
2865 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
2866 Scheduler::ProcessEventsToIdle();
2867 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
2868 CPPUNIT_ASSERT(!rInvalidations
.empty());
2869 tools::Rectangle aInvRect1
= rInvalidations
[0];
2871 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::ESCAPE
);
2872 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::ESCAPE
);
2873 Scheduler::ProcessEventsToIdle();
2875 SfxLokHelper::createView();
2876 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
2877 ViewCallback aView2
;
2878 Scheduler::ProcessEventsToIdle();
2879 auto* pTabViewShell2
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2880 CPPUNIT_ASSERT(pTabViewShell2
);
2881 pTabViewShell2
->SetCursor(rData
.col
, rData
.row
);
2882 Scheduler::ProcessEventsToIdle();
2883 // text edit in view #2
2884 aView1
.m_bInvalidateTiles
= false;
2885 rInvalidations
.clear();
2886 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
2887 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
2888 Scheduler::ProcessEventsToIdle();
2889 CPPUNIT_ASSERT(aView1
.m_bInvalidateTiles
);
2890 CPPUNIT_ASSERT(!rInvalidations
.empty());
2891 tools::Rectangle aInvRect2
= rInvalidations
[0];
2892 CPPUNIT_ASSERT_EQUAL_MESSAGE("Invalidation rectangle is wrong.", aInvRect1
, aInvRect2
);
2895 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testOpenURL
)
2897 // Given a document that has 2 views:
2898 createDoc("empty.ods");
2899 int nView1
= SfxLokHelper::getView();
2900 ViewCallback aView1
;
2901 SfxLokHelper::createView();
2902 ViewCallback aView2
;
2904 // When clicking on a link in view 2, but switching to view 1 before processing async events:
2905 ScGlobal::OpenURL(/*aUrl=*/u
"http://www.example.com/"_ustr
, /*aTarget=*/u
""_ustr
,
2906 /*bIgnoreSettings=*/true);
2907 SfxLokHelper::setView(nView1
);
2908 Scheduler::ProcessEventsToIdle();
2910 // Then make sure view 2 gets the callback, not view 1:
2911 // Without the accompanying fix in place, this test would have failed, view 1 got the hyperlink
2913 CPPUNIT_ASSERT(aView1
.m_aHyperlinkClicked
.isEmpty());
2914 CPPUNIT_ASSERT(!aView2
.m_aHyperlinkClicked
.isEmpty());
2917 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testInvalidateForSplitPanes
)
2919 comphelper::LibreOfficeKit::setCompatFlag(
2920 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
2922 ScModelObj
* pModelObj
= createDoc("split.ods");
2923 CPPUNIT_ASSERT(pModelObj
);
2924 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2925 CPPUNIT_ASSERT(pView
);
2930 // move way over to the right where BP:20 exists, enough so that rows A and B
2931 // would scroll off the page and not be visible, if they were not frozen
2932 pModelObj
->setClientVisibleArea(tools::Rectangle(73050, 0, 94019, 7034));
2933 Scheduler::ProcessEventsToIdle();
2935 ScAddress
aBP20(67, 19, 0); // BP:20
2937 pView
->SetCursor(aBP20
.Col(), aBP20
.Row());
2938 Scheduler::ProcessEventsToIdle();
2940 aView
.m_bInvalidateTiles
= false;
2941 aView
.m_aInvalidations
.clear();
2943 lcl_typeCharsInCell("X", aBP20
.Col(), aBP20
.Row(), pView
, pModelObj
); // Type 'X' in A1
2945 CPPUNIT_ASSERT(aView
.m_bInvalidateTiles
);
2947 // missing before fix
2948 tools::Rectangle
aTopLeftPane(0, 500, 3817, 742);
2949 bool bFoundTopLeftPane
=
2950 std::find(aView
.m_aInvalidations
.begin(), aView
.m_aInvalidations
.end(), aTopLeftPane
) != aView
.m_aInvalidations
.end();
2951 CPPUNIT_ASSERT_MESSAGE("The cell visible in the top left pane should be redrawn", bFoundTopLeftPane
);
2953 // missing before fix
2954 tools::Rectangle
aBottomLeftPane(0, 500, 3817, 3242);
2955 bool bFoundBottomLeftPane
=
2956 std::find(aView
.m_aInvalidations
.begin(), aView
.m_aInvalidations
.end(), aBottomLeftPane
) != aView
.m_aInvalidations
.end();
2957 CPPUNIT_ASSERT_MESSAGE("The cell visible in the bottom left pane should be redrawn", bFoundBottomLeftPane
);
2960 // Saving shouldn't trigger an invalidation
2961 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testNoInvalidateOnSave
)
2963 comphelper::LibreOfficeKit::setCompatFlag(
2964 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
2966 loadFromFile(u
"invalidate-on-save.ods");
2968 // .uno:Save modifies the original file, make a copy first
2969 saveAndReload(u
"calc8"_ustr
);
2970 ScModelObj
* pModelObj
= comphelper::getFromUnoTunnel
<ScModelObj
>(mxComponent
);
2971 CPPUNIT_ASSERT(pModelObj
);
2972 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
2974 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
2975 CPPUNIT_ASSERT(pView
);
2977 Scheduler::ProcessEventsToIdle();
2979 // track invalidations
2982 uno::Sequence
<beans::PropertyValue
> aArgs
;
2983 dispatchCommand(mxComponent
, u
".uno:Save"_ustr
, aArgs
);
2985 Scheduler::ProcessEventsToIdle();
2987 CPPUNIT_ASSERT(!aView
.m_bInvalidateTiles
);
2990 void ScTiledRenderingTest::checkSampleInvalidation(const ViewCallback
& rView
, bool bFullRow
)
2992 // we expect invalidations, but that isn't really important
2993 CPPUNIT_ASSERT(rView
.m_bInvalidateTiles
);
2994 tools::Rectangle aInvalidation
;
2995 for (const auto& rRect
: rView
.m_aInvalidations
)
2996 aInvalidation
.Union(rRect
);
2999 // What matters is that we expect that the invalidation does not extend all the
3000 // way to the max right of the sheet.
3001 // Here we originally got 32212306 and now ~5056 for a single cell case
3002 CPPUNIT_ASSERT_LESSEQUAL(tools::Long(8000), aInvalidation
.GetWidth());
3006 // We expect RTL to continue to invalidate the entire row
3007 // from 0 to end of sheet (see ScDocShell::PostPaint, 'Extend to whole rows'),
3008 // which is different to the adjusted LTR case which
3009 // invalidated the row from left of edited cell to right of end
3011 CPPUNIT_ASSERT_LESSEQUAL(tools::Long(0), aInvalidation
.Left());
3012 CPPUNIT_ASSERT_EQUAL(tools::Long(32212230), aInvalidation
.Right());
3016 void ScTiledRenderingTest::cellInvalidationHelper(ScModelObj
* pModelObj
, ScTabViewShell
* pView
, const ScAddress
& rAdr
,
3017 bool bAddText
, bool bFullRow
)
3024 // Type "Hello World" in D8, process events to idle and don't commit yet
3025 lcl_typeCharsInCell("Hello World", rAdr
.Col(), rAdr
.Row(), pView
, pModelObj
, false, false);
3027 aView
.m_bInvalidateTiles
= false;
3028 aView
.m_aInvalidations
.clear();
3030 // commit text and process events to idle
3031 lcl_typeCharsInCell("", rAdr
.Col(), rAdr
.Row(), pView
, pModelObj
, true, true);
3035 pView
->SetCursor(rAdr
.Col(), rAdr
.Row());
3036 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DELETE
);
3037 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DELETE
);
3038 Scheduler::ProcessEventsToIdle();
3041 checkSampleInvalidation(aView
, bFullRow
);
3044 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testCellMinimalInvalidations
)
3046 ScAddress
aA8(0, 7, 0);
3047 ScAddress
aD4(3, 7, 0);
3048 ScAddress
aD13(3, 12, 0);
3049 ScAddress
aD17(3, 16, 0);
3051 ScModelObj
* pModelObj
= createDoc("cell-invalidations.ods");
3052 CPPUNIT_ASSERT(pModelObj
);
3053 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
3054 CPPUNIT_ASSERT(pView
);
3056 // Changed: Minimized invalidations (bFullRow: false)
3058 // Common case, LTR, default cell formatting
3059 cellInvalidationHelper(pModelObj
, pView
, aA8
, true, false);
3060 cellInvalidationHelper(pModelObj
, pView
, aD4
, true, false);
3061 // Left-aligned merged cells
3062 cellInvalidationHelper(pModelObj
, pView
, aD17
, true, false);
3063 // Delete single cell text case
3064 cellInvalidationHelper(pModelObj
, pView
, aA8
, false, false);
3065 // Paste into a single cell
3067 pView
->SetCursor(aD4
.Col(), aD4
.Row());
3068 uno::Sequence
<beans::PropertyValue
> aArgs
;
3069 dispatchCommand(mxComponent
, u
".uno:Copy"_ustr
, aArgs
);
3070 pView
->SetCursor(aA8
.Col(), aA8
.Row());
3071 Scheduler::ProcessEventsToIdle();
3074 dispatchCommand(mxComponent
, u
".uno:Paste"_ustr
, aArgs
);
3075 Scheduler::ProcessEventsToIdle();
3077 checkSampleInvalidation(aView
, false);
3080 // Unchanged: Non-minimized invalidations (bFullRow: true)
3082 // Centered merged cells;
3083 cellInvalidationHelper(pModelObj
, pView
, aD13
, true, true);
3085 // switch to RTL sheet
3086 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
3087 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::PAGEDOWN
| KEY_MOD1
);
3088 Scheduler::ProcessEventsToIdle();
3090 cellInvalidationHelper(pModelObj
, pView
, aA8
, true, true);
3091 cellInvalidationHelper(pModelObj
, pView
, aD4
, true, true);
3093 cellInvalidationHelper(pModelObj
, pView
, aA8
, false, true);
3096 // That we don't end up with two views on different zooms that invalidate different
3097 // rectangles, each should invalidate the same rectangle
3098 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testCellInvalidationDocWithExistingZoom
)
3100 ScAddress
aB7(1, 6, 0);
3101 ScopedVclPtrInstance
<VirtualDevice
> xDevice(DeviceFormat::WITHOUT_ALPHA
);
3103 ScModelObj
* pModelObj
= createDoc("cell-invalidations-200zoom-settings.ods");
3104 CPPUNIT_ASSERT(pModelObj
);
3105 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
3106 CPPUNIT_ASSERT(pView
);
3108 // Set View #1 to initial 100% and generate a paint
3109 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 19845, 6405));
3110 pModelObj
->setClientZoom(256, 256, 1536, 1536);
3111 pModelObj
->paintTile(*xDevice
, 3328, 512, 0, 0, 19968, 3072);
3113 Scheduler::ProcessEventsToIdle();
3115 int nView1
= SfxLokHelper::getView();
3116 // register to track View #1 invalidations
3117 ViewCallback aView1
;
3120 SfxLokHelper::createView();
3121 int nView2
= SfxLokHelper::getView();
3122 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
3123 // register to track View #1 invalidations
3124 ViewCallback aView2
;
3126 // Set View #2 to initial 100% and generate a paint
3127 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 19845, 6405));
3128 pModelObj
->setClientZoom(256, 256, 1536, 1536);
3129 pModelObj
->paintTile(*xDevice
, 3328, 512, 0, 0, 19968, 3072);
3131 // Set View #1 to 50% zoom and generate a paint
3132 SfxLokHelper::setView(nView1
);
3133 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 41150, 13250));
3134 pModelObj
->setClientZoom(256, 256, 3185, 3185);
3135 pModelObj
->paintTile(*xDevice
, 3328, 512, 0, 0, 41405, 6370);
3137 Scheduler::ProcessEventsToIdle();
3139 // Set View #2 to 200% zoom and generate a paint
3140 SfxLokHelper::setView(nView2
);
3141 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 9574, 3090));
3142 pModelObj
->setClientZoom(256, 256, 741, 741);
3143 pModelObj
->paintTile(*xDevice
, 3328, 512, 0, 0, 19968, 3072);
3145 Scheduler::ProcessEventsToIdle();
3146 aView1
.m_bInvalidateTiles
= false;
3147 aView1
.m_aInvalidations
.clear();
3148 aView2
.m_bInvalidateTiles
= false;
3149 aView2
.m_aInvalidations
.clear();
3151 ScTabViewShell
* pView2
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
3152 CPPUNIT_ASSERT(pView2
);
3153 pView2
->SetCursor(aB7
.Col(), aB7
.Row());
3155 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::DELETE
);
3156 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::DELETE
);
3157 Scheduler::ProcessEventsToIdle();
3159 // The problem tested for here is with two views at different zooms then a
3160 // single cell invalidation resulted in the same rectangle reported as two
3161 // different invalidations rectangles of different scales. While we should
3162 // get the same invalidation rectangle reported.
3164 // (B7 is a good choice to use in the real world to see the effect, to both
3165 // avoid getting the two rects combined into one bigger one, or to have the
3166 // two separated by so much space the 2nd is off-screen and not seen
3167 CPPUNIT_ASSERT_EQUAL(size_t(1), aView1
.m_aInvalidations
.size());
3168 CPPUNIT_ASSERT_EQUAL(size_t(1), aView2
.m_aInvalidations
.size());
3170 // That they don't exactly match doesn't matter, we're not checking rounding issues,
3171 // what matters is that they are not utterly different rectangles
3172 // Without fix result is originally:
3173 // Comparing invalidation rectangles Width expected 6214742 actual 26716502 Tolerance 50
3174 CPPUNIT_ASSERT_RECTANGLE_EQUAL_WITH_TOLERANCE(aView2
.m_aInvalidations
[0],
3175 aView1
.m_aInvalidations
[0],
3179 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testInputHandlerSyncedZoom
)
3181 ScModelObj
* pModelObj
= createDoc("cell-edit-300zoom-settings.ods");
3183 // Set View #1 to initial 150%
3184 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 17933, 4853));
3185 // Before the fix, this zoom would leave the EditEngine reference device
3186 // at the zoom level stored in the document, so normal rendering and
3187 // editing rendering happened with different MapModes
3188 pModelObj
->setClientZoom(256, 256, 1333, 1333);
3190 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
3191 CPPUNIT_ASSERT(pView
);
3192 pView
->SetCursor(0, 4); // A5
3194 Scheduler::ProcessEventsToIdle();
3196 // Activate edit mode in that A5 cell
3197 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::F2
);
3198 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::F2
);
3199 Scheduler::ProcessEventsToIdle();
3201 const ScViewData
* pViewData1
= ScDocShell::GetViewData();
3202 CPPUNIT_ASSERT(pViewData1
);
3204 // Get that active EditView
3205 EditView
* pEditView1
= pViewData1
->GetEditView(SC_SPLIT_BOTTOMLEFT
);
3206 CPPUNIT_ASSERT(pEditView1
);
3207 EditEngine
& rEditEngine1
= pEditView1
->getEditEngine();
3208 // These must match, if they don't then text will have a different width in edit and view modes
3209 CPPUNIT_ASSERT_EQUAL_MESSAGE("EditEngine Ref Dev Zoom and ViewData Zoom should match",
3210 pViewData1
->GetZoomX(), rEditEngine1
.GetRefMapMode().GetScaleX());
3211 CPPUNIT_ASSERT_EQUAL_MESSAGE("EditEngine Ref Dev Zoom and ViewData Zoom should match",
3212 pViewData1
->GetZoomY(), rEditEngine1
.GetRefMapMode().GetScaleY());
3215 SfxLokHelper::createView();
3216 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
3218 // Set View #2 to the same zoom as View #1
3219 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 17933, 4853));
3220 pModelObj
->setClientZoom(256, 256, 1333, 1333);
3222 ScTabViewShell
* pView2
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
3223 CPPUNIT_ASSERT(pView2
);
3224 pView2
->SetCursor(0, 5); // A6
3226 Scheduler::ProcessEventsToIdle();
3228 // Activate edit mode in that A6 cell
3229 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::F2
);
3230 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::F2
);
3231 Scheduler::ProcessEventsToIdle();
3233 const ScViewData
* pViewData2
= ScDocShell::GetViewData();
3234 CPPUNIT_ASSERT(pViewData2
);
3236 // Get the View #2 EditView
3237 EditView
* pEditView2
= pViewData2
->GetEditView(SC_SPLIT_BOTTOMLEFT
);
3238 CPPUNIT_ASSERT(pEditView2
);
3239 EditEngine
& rEditEngine2
= pEditView2
->getEditEngine();
3240 CPPUNIT_ASSERT(&rEditEngine1
!= &rEditEngine2
);
3241 // Before the fix, these had different settings, resulting in the text
3242 // dancing for the second user as they toggle in and out of edit mode, but
3243 // each user should have the same settings.
3244 CPPUNIT_ASSERT_EQUAL(rEditEngine1
.GetControlWord(), rEditEngine2
.GetControlWord());
3247 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testStatusBarLocale
)
3249 // Given 2 views, the second's locale is set to German:
3250 createDoc("empty.ods");
3251 int nView1
= SfxLokHelper::getView();
3252 ViewCallback aView1
;
3253 SfxLokHelper::createView();
3254 ViewCallback aView2
;
3255 SfxViewShell
* pView2
= SfxViewShell::Current();
3256 pView2
->SetLOKLocale(u
"de-DE"_ustr
);
3258 SfxViewFrame
& rFrame
= pView2
->GetViewFrame();
3259 SfxSlotPool
& rSlotPool
= SfxSlotPool::GetSlotPool(&rFrame
);
3260 uno::Reference
<util::XURLTransformer
> xParser(util::URLTransformer::create(m_xContext
));
3261 util::URL aCommandURL
;
3262 aCommandURL
.Complete
= ".uno:RowColSelCount";
3263 xParser
->parseStrict(aCommandURL
);
3264 const SfxSlot
* pSlot
= rSlotPool
.GetUnoSlot(aCommandURL
.Path
);
3265 rFrame
.GetBindings().GetDispatch(pSlot
, aCommandURL
, false);
3267 aView2
.m_aStateChanges
.clear();
3269 // When creating a cell selection in the 2nd view and processing jobs with the 1st view set to
3271 comphelper::dispatchCommand(u
".uno:GoDownSel"_ustr
, {});
3272 SfxLokHelper::setView(nView1
);
3273 pView2
->GetViewFrame().GetBindings().GetTimer().Invoke();
3274 // Once more to hit the pImpl->bMsgDirty = false case in SfxBindings::NextJob_Impl().
3275 pView2
->GetViewFrame().GetBindings().GetTimer().Invoke();
3277 // Then make sure that the locale is taken into account while producing the state changed
3279 auto it
= aView2
.m_aStateChanges
.find(".uno:RowColSelCount");
3280 CPPUNIT_ASSERT(it
!= aView2
.m_aStateChanges
.end());
3281 std::string aLocale
= it
->second
.get
<std::string
>("locale");
3282 // Without the accompanying fix in place, this test would have failed with:
3283 // - Expected: de-DE
3285 // i.e. the 2nd view got its callback with the locale of the first view, which is buggy.
3286 CPPUNIT_ASSERT_EQUAL(std::string("de-DE"), aLocale
);
3289 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testLongFirstColumnMouseClick
)
3291 // Document has a long first column. We want to mouse-click on the column and
3292 // check the selection changed to this column.
3294 // The issue we want to reproduce is that the click on a cell in the first column that is
3295 // very long (longer than ~800px default size of GridWindow) triggers a code-path where the cell
3296 // selected is the neighbouring cell even when we clicked on the area of the first cell.
3298 comphelper::LibreOfficeKit::setCompatFlag(
3299 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
3301 ScModelObj
* pModelObj
= createDoc("DocumentWithLongFirstColumn.ods");
3302 CPPUNIT_ASSERT(pModelObj
);
3303 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
3305 // Fetch current view data
3306 ScViewData
* pViewData
= ScDocShell::GetViewData();
3307 CPPUNIT_ASSERT(pViewData
);
3308 double nPPTX
= pViewData
->GetPPTX();
3309 double nPPTY
= pViewData
->GetPPTX();
3311 // Set click position
3313 // Left side of the first cell
3314 int leftCellSideX
= 1 / nPPTX
; // convert pixels to logical units
3316 // Right side of the first cell. First cell is long so click somewhere more than 800px (default of GridWindow size).
3317 int rightCellSideX
= 1000 / nPPTX
; // convert pixels to logical units
3319 // Vertical position - doesn't matter - select the first row
3323 ViewCallback aView1
;
3324 // Set client rect to 2000 x 2000 pixels
3325 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 2000 / nPPTX
, 2000 / nPPTY
));
3326 Scheduler::ProcessEventsToIdle();
3328 // Click at on the left side of A1 cell
3329 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
, leftCellSideX
, y
, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
3330 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
, leftCellSideX
, y
, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
3331 Scheduler::ProcessEventsToIdle();
3333 // Check the A1 cell is selected in view #1
3334 CPPUNIT_ASSERT_EQUAL(SCCOL(0), ScDocShell::GetViewData()->GetCurX());
3335 CPPUNIT_ASSERT_EQUAL(SCROW(0), ScDocShell::GetViewData()->GetCurY());
3337 // Click at on the right side of A1 cell
3338 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
, rightCellSideX
, y
, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
3339 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
, rightCellSideX
, y
, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
3340 Scheduler::ProcessEventsToIdle();
3342 // Check the A1 cell is selected in view #1
3343 CPPUNIT_ASSERT_EQUAL(SCCOL(0), ScDocShell::GetViewData()->GetCurX());
3344 CPPUNIT_ASSERT_EQUAL(SCROW(0), ScDocShell::GetViewData()->GetCurY());
3346 // Try to check the same scenario in a new view
3349 SfxLokHelper::createView();
3350 int nView2
= SfxLokHelper::getView();
3351 ViewCallback aView2
;
3352 // Set client rect to 2000 x 2000 pixels
3353 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 2000 / nPPTX
, 2000 / nPPTY
));
3355 // Let's make sure we are in view #2
3356 SfxLokHelper::setView(nView2
);
3357 Scheduler::ProcessEventsToIdle();
3359 // Click at on the left side of A1 cell
3360 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
, leftCellSideX
, y
, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
3361 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
, leftCellSideX
, y
, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
3362 Scheduler::ProcessEventsToIdle();
3364 // Check the A1 cell is selected in view #2
3365 CPPUNIT_ASSERT_EQUAL(SCCOL(0), ScDocShell::GetViewData()->GetCurX());
3366 CPPUNIT_ASSERT_EQUAL(SCROW(0), ScDocShell::GetViewData()->GetCurY());
3368 // Click at on the right side of A1 cell
3369 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
, rightCellSideX
, y
, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
3370 pModelObj
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
, rightCellSideX
, y
, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
3371 Scheduler::ProcessEventsToIdle();
3373 // Check the A1 cell is selected in view #2
3374 CPPUNIT_ASSERT_EQUAL(SCCOL(0), ScDocShell::GetViewData()->GetCurX());
3375 CPPUNIT_ASSERT_EQUAL(SCROW(0), ScDocShell::GetViewData()->GetCurY());
3378 // if we extend the tiled area to the right and bottom we want two resulting area
3379 // that don't overlap. If they overlap that typically creates an unnecessary full
3380 // screen invalidation.
3381 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testExtendedAreasDontOverlap
)
3383 comphelper::LibreOfficeKit::setCompatFlag(
3384 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
3386 ScModelObj
* pModelObj
= createDoc("empty.ods");
3387 CPPUNIT_ASSERT(pModelObj
);
3388 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
3389 CPPUNIT_ASSERT(pView
);
3391 // Set an arbitrary initial size smaller than the final size
3392 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 1000, 1000));
3394 Scheduler::ProcessEventsToIdle();
3396 // register to track View #1 invalidations
3397 ViewCallback aView1
;
3399 // extend to the right and bottom
3400 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 39750, 12780));
3402 Scheduler::ProcessEventsToIdle();
3404 // we should get two rectangles for the two new areas
3405 CPPUNIT_ASSERT_EQUAL(size_t(2), aView1
.m_aInvalidations
.size());
3407 // And those should not overlap, otherwise they would merge to form
3408 // a mega rectangle, which defeats the purpose of creating two rects
3409 // in the first place.
3410 CPPUNIT_ASSERT_MESSAGE("Invalidations should not overlap",
3411 !aView1
.m_aInvalidations
[0].Overlaps(aView1
.m_aInvalidations
[1]));
3413 // But they should be adjacent
3414 CPPUNIT_ASSERT_EQUAL(aView1
.m_aInvalidations
[0].Top() +
3415 aView1
.m_aInvalidations
[0].GetSize().Height(),
3416 aView1
.m_aInvalidations
[1].Top());
3419 // Ensure that editing a shape not in the topleft tile has its text shown inside the shape
3420 // center while editing
3421 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testEditShapeText
)
3423 ScModelObj
* pModelObj
= createDoc("edit-shape-text.ods");
3425 // Set View to initial 100%
3426 pModelObj
->setClientVisibleArea(tools::Rectangle(0, 0, 28050, 10605));
3427 pModelObj
->setClientZoom(256, 256, 1920, 1920);
3429 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
3430 CPPUNIT_ASSERT(pView
);
3432 const bool bShapeSelected
= pView
->SelectObject(u
"Shape 1");
3433 CPPUNIT_ASSERT(bShapeSelected
);
3435 CPPUNIT_ASSERT(ScDocShell::GetViewData()->GetScDrawView()->GetMarkedObjectList().GetMarkCount() != 0);
3437 Scheduler::ProcessEventsToIdle();
3439 // Enter editing mode, shape start with no text
3440 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::F2
);
3441 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::F2
);
3443 Scheduler::ProcessEventsToIdle();
3445 // Grab a snapshot of the center of the shape
3446 Bitmap aBitmapBefore
= getTile(pModelObj
, 4096, 3584, 15360, 7680);
3448 // reuse this to type into the active shape edit
3449 lcl_typeCharsInCell("MMMMMMM", 0, 0, pView
, pModelObj
, true, false);
3451 // Grab a new snapshot of the center of the shape
3452 Bitmap aBitmapAfter
= getTile(pModelObj
, 4096, 3584, 15360, 7680);
3454 // Without the fix, the text is not inside this tile and the before and
3455 // after are the same.
3456 CPPUNIT_ASSERT_MESSAGE("Text is not visible", aBitmapBefore
!= aBitmapAfter
);
3459 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testNumberFormatLocaleMultiUser
)
3462 // setup core language to FR as it will be the first session
3463 SvtSysLocaleOptions aLocalOptions
;
3464 aLocalOptions
.SetLocaleConfigString(u
"fr-FR"_ustr
);
3465 aLocalOptions
.SetUILocaleConfigString(u
"fr-FR"_ustr
);
3466 aLocalOptions
.Commit();
3468 loadFromFile(u
"numlocale.xlsx");
3470 ScModelObj
* pModelObj
= comphelper::getFromUnoTunnel
<ScModelObj
>(mxComponent
);
3471 CPPUNIT_ASSERT(pModelObj
);
3473 pModelObj
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
3474 ScDocument
* pDoc
= pModelObj
->GetDocument();
3476 int nViewFR
= SfxLokHelper::getView();
3477 ViewCallback aView1
;
3478 SfxViewShell
* pViewFR
= SfxViewShell::Current();
3479 pViewFR
->SetLOKLocale(u
"fr-FR"_ustr
);
3481 // modify G12 with FR and use French keywords in the format
3482 SfxLokHelper::setView(nViewFR
);
3484 sal_Int32 nCheckPos
;
3485 SvNumFormatType nType
;
3487 OUString
aNumberFormat(u
"JJ/MM/AAAA"_ustr
);
3488 SvNumberFormatter
* pFormatter
= pDoc
->GetFormatTable();
3489 pFormatter
->PutEntry(aNumberFormat
, nCheckPos
, nType
, nFormat
);
3490 ScAddress
aCellPos1(/*nColP=*/6, /*nRowP=*/11, /*nTabP=*/0);
3491 pDoc
->SetNumberFormat(aCellPos1
, nFormat
);
3493 Scheduler::ProcessEventsToIdle();
3497 // now setup DE language in core
3498 SvtSysLocaleOptions aLocalOptions
;
3499 aLocalOptions
.SetLocaleConfigString(u
"de-DE"_ustr
);
3500 aLocalOptions
.SetUILocaleConfigString(u
"de-DE"_ustr
);
3501 aLocalOptions
.Commit();
3504 // .uno:Save modifies the original file, make a copy first
3505 saveAndReload(u
"Calc MS Excel 2007 VBA XML"_ustr
);
3507 ScModelObj
* pModelObj
= comphelper::getFromUnoTunnel
<ScModelObj
>(mxComponent
);
3508 CPPUNIT_ASSERT(pModelObj
);
3510 ScTabViewShell
* pView
= dynamic_cast<ScTabViewShell
*>(SfxViewShell::Current());
3511 CPPUNIT_ASSERT(pView
);
3513 Scheduler::ProcessEventsToIdle();
3515 uno::Sequence
<beans::PropertyValue
> aArgs
;
3516 dispatchCommand(mxComponent
, u
".uno:Save"_ustr
, aArgs
);
3518 Scheduler::ProcessEventsToIdle();
3520 ScDocument
* pDoc
= pModelObj
->GetDocument();
3522 // verify that format is correct (German), doesn't have any "string" inside
3523 sal_uInt32 nNumberFormat
= pDoc
->GetNumberFormat(/*col=*/6, /*row=*/11, /*tab=*/0);
3524 const SvNumberformat
* pNumberFormat
= pDoc
->GetFormatTable()->GetEntry(nNumberFormat
);
3525 CPPUNIT_ASSERT_EQUAL(u
"TT.MM.JJ"_ustr
, pNumberFormat
->GetFormatstring());
3529 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testLeftOverflowEdit
)
3531 comphelper::LibreOfficeKit::setCompatFlag(comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs
);
3532 ScModelObj
* pModelObj
= createDoc("right-aligned-with-overflow.ods");
3536 uno::Sequence
<beans::PropertyValue
> aPropertyValues
= {
3537 comphelper::makePropertyValue(u
"ToPoint"_ustr
, u
"$B$5000"_ustr
),
3539 dispatchCommand(mxComponent
, u
".uno:GoToCell"_ustr
, aPropertyValues
);
3541 // Enter edit mode and select all text.
3542 aView
.m_aTextSelectionResult
.clear();
3543 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::F2
);
3544 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::F2
);
3545 Scheduler::ProcessEventsToIdle();
3547 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_MOD1
| awt::Key::A
);
3548 pModelObj
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_MOD1
| awt::Key::A
);
3549 Scheduler::ProcessEventsToIdle();
3551 // Without the accompanying fix this would fail with
3554 CPPUNIT_ASSERT_EQUAL(tools::Long(20), aView
.m_aTextSelectionResult
.m_aRefPoint
.getX());
3557 CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest
, testFreezeRowOrColumn
)
3559 createDoc("empty.ods");
3561 SfxViewShell
* pView
= SfxViewShell::Current();
3563 // Freeze panes on a column and receive the proper state back
3564 aView
.m_aStateChanges
.clear();
3565 uno::Sequence
<beans::PropertyValue
> aPropertyValues
= {
3566 comphelper::makePropertyValue("Index", uno::Any(static_cast<sal_Int32
>(8))),
3568 comphelper::dispatchCommand(".uno:FreezePanesColumn", aPropertyValues
);
3569 Scheduler::ProcessEventsToIdle();
3570 pView
->GetViewFrame().GetBindings().GetTimer().Invoke();
3571 pView
->GetViewFrame().GetBindings().GetTimer().Invoke();
3572 auto it
= aView
.m_aStateChanges
.find(".uno:FreezePanesColumn");
3573 CPPUNIT_ASSERT(it
!= aView
.m_aStateChanges
.end());
3574 std::string values
= it
->second
.get
<std::string
>("state");
3575 std::string index
= values
.substr(0, values
.find(' '));
3576 // Without the accompanying fix in place, this test would have failed with:
3579 CPPUNIT_ASSERT_EQUAL(std::string("8"), index
);
3581 // Freeze panes on a row and receive the proper state back
3582 aView
.m_aStateChanges
.clear();
3583 comphelper::dispatchCommand(".uno:FreezePanesRow", aPropertyValues
);
3584 Scheduler::ProcessEventsToIdle();
3585 pView
->GetViewFrame().GetBindings().GetTimer().Invoke();
3586 pView
->GetViewFrame().GetBindings().GetTimer().Invoke();
3587 it
= aView
.m_aStateChanges
.find(".uno:FreezePanesRow");
3588 CPPUNIT_ASSERT(it
!= aView
.m_aStateChanges
.end());
3589 values
= it
->second
.get
<std::string
>("state");
3590 index
= values
.substr(0, values
.find(' '));
3591 // Without the accompanying fix in place, this test would have failed with:
3594 CPPUNIT_ASSERT_EQUAL(std::string("8"), index
);
3597 CPPUNIT_PLUGIN_IMPLEMENT();
3599 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */