1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <test/unoapixml_test.hxx>
13 #include <test/helper/transferable.hxx>
14 #include <boost/property_tree/json_parser.hpp>
15 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
16 #include <sal/log.hxx>
17 #include <sfx2/lokhelper.hxx>
18 #include <comphelper/propertysequence.hxx>
19 #include <comphelper/propertyvalue.hxx>
20 #include <comphelper/string.hxx>
21 #include <editeng/eeitem.hxx>
22 #include <editeng/editids.hrc>
23 #include <editeng/editobj.hxx>
24 #include <editeng/editview.hxx>
25 #include <editeng/numitem.hxx>
26 #include <editeng/outliner.hxx>
27 #include <editeng/fhgtitem.hxx>
28 #include <editeng/outlobj.hxx>
29 #include <osl/conditn.hxx>
30 #include <sfx2/dispatch.hxx>
31 #include <sfx2/viewfrm.hxx>
32 #include <svl/stritem.hxx>
33 #include <svl/intitem.hxx>
34 #include <comphelper/lok.hxx>
35 #include <svx/svdotable.hxx>
36 #include <svx/svdoutl.hxx>
37 #include <unotools/datetime.hxx>
38 #include <test/lokcallback.hxx>
40 #include <DrawDocShell.hxx>
41 #include <ViewShellBase.hxx>
42 #include <ViewShell.hxx>
44 #include <unomodel.hxx>
45 #include <drawdoc.hxx>
46 #include <undo/undomanager.hxx>
47 #include <sfx2/request.hxx>
48 #include <svx/svxids.hrc>
50 #include <navigatr.hxx>
51 #include <vcl/cursor.hxx>
52 #include <vcl/scheduler.hxx>
53 #include <vcl/vclevent.hxx>
54 #include <vcl/BitmapReadAccess.hxx>
55 #include <vcl/virdev.hxx>
56 #include <o3tl/string_view.hxx>
60 #include <string_view>
64 static std::ostream
& operator<<(std::ostream
& os
, ViewShellId id
)
66 os
<< static_cast<sal_Int32
>(id
);
70 class SdTiledRenderingTest
: public UnoApiXmlTest
73 SdTiledRenderingTest();
74 virtual void setUp() override
;
75 virtual void tearDown() override
;
78 SdXImpressDocument
* createDoc(const char* pName
, const uno::Sequence
<beans::PropertyValue
>& rArguments
= uno::Sequence
<beans::PropertyValue
>());
79 void setupLibreOfficeKitViewCallback(SfxViewShell
& pViewShell
);
80 static void callback(int nType
, const char* pPayload
, void* pData
);
81 void callbackImpl(int nType
, const char* pPayload
);
82 xmlDocUniquePtr
parseXmlDump();
84 ::tools::Rectangle m_aInvalidation
;
85 std::vector
<::tools::Rectangle
> m_aSelection
;
88 std::vector
<OString
> m_aSearchResultSelection
;
89 std::vector
<int> m_aSearchResultPart
;
90 int m_nSelectionBeforeSearchResult
;
91 int m_nSelectionAfterSearchResult
;
93 /// For document size changed callback.
94 osl::Condition m_aDocumentSizeCondition
;
95 xmlBufferPtr m_pXmlBuffer
;
96 TestLokCallbackWrapper m_callbackWrapper
;
99 SdTiledRenderingTest::SdTiledRenderingTest()
100 : UnoApiXmlTest("/sd/qa/unit/tiledrendering/data/"),
103 m_nSelectionBeforeSearchResult(0),
104 m_nSelectionAfterSearchResult(0),
105 m_pXmlBuffer(nullptr),
106 m_callbackWrapper(&callback
, this)
110 void SdTiledRenderingTest::setUp()
112 UnoApiXmlTest::setUp();
114 // prevent showing warning message box
115 setenv("OOX_NO_SMARTART_WARNING", "1", 1);
116 comphelper::LibreOfficeKit::setActive(true);
119 void SdTiledRenderingTest::tearDown()
121 if (mxComponent
.is())
123 mxComponent
->dispose();
128 xmlBufferFree(m_pXmlBuffer
);
130 m_callbackWrapper
.clear();
131 comphelper::LibreOfficeKit::setActive(false);
133 UnoApiXmlTest::tearDown();
136 SdXImpressDocument
* SdTiledRenderingTest::createDoc(const char* pName
, const uno::Sequence
<beans::PropertyValue
>& rArguments
)
138 loadFromURL(OUString::createFromAscii(pName
));
139 SdXImpressDocument
* pImpressDocument
= dynamic_cast<SdXImpressDocument
*>(mxComponent
.get());
140 CPPUNIT_ASSERT(pImpressDocument
);
141 pImpressDocument
->initializeForTiledRendering(rArguments
);
142 return pImpressDocument
;
145 void SdTiledRenderingTest::setupLibreOfficeKitViewCallback(SfxViewShell
& pViewShell
)
147 pViewShell
.setLibreOfficeKitViewCallback(&m_callbackWrapper
);
148 m_callbackWrapper
.setLOKViewId(SfxLokHelper::getView(&pViewShell
));
151 void SdTiledRenderingTest::callback(int nType
, const char* pPayload
, void* pData
)
153 static_cast<SdTiledRenderingTest
*>(pData
)->callbackImpl(nType
, pPayload
);
159 std::vector
<OUString
> lcl_convertSeparated(std::u16string_view rString
, sal_Unicode nSeparator
)
161 std::vector
<OUString
> aRet
;
163 sal_Int32 nIndex
= 0;
166 OUString
aToken( o3tl::trim(o3tl::getToken(rString
, 0, nSeparator
, nIndex
)) );
167 if (!aToken
.isEmpty())
168 aRet
.push_back(aToken
);
175 void lcl_convertRectangle(std::u16string_view rString
, ::tools::Rectangle
& rRectangle
)
177 uno::Sequence
<OUString
> aSeq
= comphelper::string::convertCommaSeparated(rString
);
178 CPPUNIT_ASSERT(aSeq
.getLength() == 4 || aSeq
.getLength() == 5);
179 rRectangle
.SetLeft(aSeq
[0].toInt32());
180 rRectangle
.SetTop(aSeq
[1].toInt32());
181 rRectangle
.setWidth(aSeq
[2].toInt32());
182 rRectangle
.setHeight(aSeq
[3].toInt32());
185 } // end anonymous namespace
187 void SdTiledRenderingTest::callbackImpl(int nType
, const char* pPayload
)
191 case LOK_CALLBACK_INVALIDATE_TILES
:
193 OUString aPayload
= OUString::createFromAscii(pPayload
);
194 if (aPayload
!= "EMPTY" && m_aInvalidation
.IsEmpty())
195 lcl_convertRectangle(aPayload
, m_aInvalidation
);
198 case LOK_CALLBACK_TEXT_SELECTION
:
200 OUString aPayload
= OUString::createFromAscii(pPayload
);
201 m_aSelection
.clear();
202 for (const OUString
& rString
: lcl_convertSeparated(aPayload
, u
';'))
204 ::tools::Rectangle aRectangle
;
205 lcl_convertRectangle(rString
, aRectangle
);
206 m_aSelection
.push_back(aRectangle
);
208 if (m_aSearchResultSelection
.empty())
209 ++m_nSelectionBeforeSearchResult
;
211 ++m_nSelectionAfterSearchResult
;
214 case LOK_CALLBACK_SEARCH_NOT_FOUND
:
219 case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED
:
221 m_aDocumentSizeCondition
.set();
224 case LOK_CALLBACK_SET_PART
:
226 OUString aPayload
= OUString::createFromAscii(pPayload
);
227 m_nPart
= aPayload
.toInt32();
230 case LOK_CALLBACK_SEARCH_RESULT_SELECTION
:
232 m_aSearchResultSelection
.clear();
233 m_aSearchResultPart
.clear();
234 boost::property_tree::ptree aTree
;
235 std::stringstream
aStream(pPayload
);
236 boost::property_tree::read_json(aStream
, aTree
);
237 for (const boost::property_tree::ptree::value_type
& rValue
: aTree
.get_child("searchResultSelection"))
239 m_aSearchResultSelection
.emplace_back(rValue
.second
.get
<std::string
>("rectangles").c_str());
240 m_aSearchResultPart
.push_back(std::atoi(rValue
.second
.get
<std::string
>("part").c_str()));
247 xmlDocUniquePtr
SdTiledRenderingTest::parseXmlDump()
250 xmlBufferFree(m_pXmlBuffer
);
252 // Create the xml writer.
253 m_pXmlBuffer
= xmlBufferCreate();
254 xmlTextWriterPtr pXmlWriter
= xmlNewTextWriterMemory(m_pXmlBuffer
, 0);
255 (void)xmlTextWriterStartDocument(pXmlWriter
, nullptr, nullptr, nullptr);
258 SdXImpressDocument
* pImpressDocument
= dynamic_cast<SdXImpressDocument
*>(mxComponent
.get());
259 CPPUNIT_ASSERT(pImpressDocument
);
260 pImpressDocument
->GetDoc()->dumpAsXml(pXmlWriter
);
262 // Delete the xml writer.
263 (void)xmlTextWriterEndDocument(pXmlWriter
);
264 xmlFreeTextWriter(pXmlWriter
);
266 auto pCharBuffer
= xmlBufferContent(m_pXmlBuffer
);
267 SAL_INFO("test", "SdTiledRenderingTest::parseXmlDump: pCharBuffer is '" << pCharBuffer
<< "'");
268 return xmlDocUniquePtr(xmlParseDoc(pCharBuffer
));
271 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testCreateDestroy
)
273 createDoc("dummy.odp");
274 // Nothing to do, the tearDown call should cleanup.
277 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testCreateView
)
279 createDoc("dummy.odp");
281 SfxLokHelper::createView();
284 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testRegisterCallback
)
286 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
287 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
288 setupLibreOfficeKitViewCallback(pViewShell
->GetViewShellBase());
290 // Start text edit of the empty title shape.
291 SdPage
* pActualPage
= pViewShell
->GetActualPage();
292 SdrObject
* pObject
= pActualPage
->GetObj(0);
293 SdrView
* pView
= pViewShell
->GetView();
294 pView
->SdrBeginTextEdit(pObject
);
295 CPPUNIT_ASSERT(pView
->GetTextEditObject());
297 // Check that the top left 256x256px tile would be invalidated.
298 CPPUNIT_ASSERT(!m_aInvalidation
.IsEmpty());
299 ::tools::Rectangle
aTopLeft(0, 0, 256*15, 256*15); // 1 px = 15 twips, assuming 96 DPI.
300 CPPUNIT_ASSERT(m_aInvalidation
.Overlaps(aTopLeft
));
303 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testPostKeyEvent
)
305 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
306 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
307 SdPage
* pActualPage
= pViewShell
->GetActualPage();
308 SdrObject
* pObject
= pActualPage
->GetObj(0);
309 CPPUNIT_ASSERT_EQUAL(SdrObjKind::TitleText
, pObject
->GetObjIdentifier());
310 SdrTextObj
* pTextObj
= static_cast<SdrTextObj
*>(pObject
);
311 SdrView
* pView
= pViewShell
->GetView();
312 pView
->MarkObj(pTextObj
, pView
->GetSdrPageView());
313 SfxStringItem
aInputString(SID_ATTR_CHAR
, "x");
314 pViewShell
->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR
,
315 SfxCallMode::SYNCHRON
, { &aInputString
});
317 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
318 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
319 Scheduler::ProcessEventsToIdle();
321 CPPUNIT_ASSERT(pView
->GetTextEditObject());
322 EditView
& rEditView
= pView
->GetTextEditOutlinerView()->GetEditView();
323 // Did we manage to enter a second character?
324 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(2), rEditView
.GetSelection().nStartPos
);
325 ESelection
aWordSelection(0, 0, 0, 2); // start para, start char, end para, end char.
326 rEditView
.SetSelection(aWordSelection
);
327 // Did we enter the expected character?
328 CPPUNIT_ASSERT_EQUAL(OUString("xx"), rEditView
.GetSelected());
331 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testPostMouseEvent
)
333 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
334 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
335 SdPage
* pActualPage
= pViewShell
->GetActualPage();
336 SdrObject
* pObject
= pActualPage
->GetObj(0);
337 CPPUNIT_ASSERT_EQUAL(SdrObjKind::TitleText
, pObject
->GetObjIdentifier());
338 SdrTextObj
* pTextObj
= static_cast<SdrTextObj
*>(pObject
);
339 SdrView
* pView
= pViewShell
->GetView();
340 pView
->MarkObj(pTextObj
, pView
->GetSdrPageView());
341 SfxStringItem
aInputString(SID_ATTR_CHAR
, "x");
342 pViewShell
->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR
,
343 SfxCallMode::SYNCHRON
, { &aInputString
});
344 CPPUNIT_ASSERT(pView
->GetTextEditObject());
345 EditView
& rEditView
= pView
->GetTextEditOutlinerView()->GetEditView();
346 // Did we manage to go after the first character?
347 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), rEditView
.GetSelection().nStartPos
);
349 vcl::Cursor
* pCursor
= rEditView
.GetCursor();
350 Point
aPosition(pCursor
->GetPos().getX(), pCursor
->GetPos().getY() + pCursor
->GetSize().Height() / 2);
351 aPosition
.setX(aPosition
.getX() - 1000);
352 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
353 o3tl::toTwips(aPosition
.getX(), o3tl::Length::mm100
), o3tl::toTwips(aPosition
.getY(), o3tl::Length::mm100
),
355 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
,
356 o3tl::toTwips(aPosition
.getX(), o3tl::Length::mm100
), o3tl::toTwips(aPosition
.getY(), o3tl::Length::mm100
),
358 Scheduler::ProcessEventsToIdle();
359 CPPUNIT_ASSERT(pView
->GetTextEditObject());
360 // The new cursor position must be before the first word.
361 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(0), rEditView
.GetSelection().nStartPos
);
364 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testSetTextSelection
)
366 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
367 uno::Reference
<container::XIndexAccess
> xDrawPage(pXImpressDocument
->getDrawPages()->getByIndex(0), uno::UNO_QUERY
);
368 uno::Reference
<text::XTextRange
> xShape(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
369 xShape
->setString("Aaa bbb.");
370 // Create a selection on the second word.
371 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
372 SdPage
* pActualPage
= pViewShell
->GetActualPage();
373 SdrObject
* pObject
= pActualPage
->GetObj(0);
374 SdrView
* pView
= pViewShell
->GetView();
375 pView
->SdrBeginTextEdit(pObject
);
376 CPPUNIT_ASSERT(pView
->GetTextEditObject());
377 EditView
& rEditView
= pView
->GetTextEditOutlinerView()->GetEditView();
378 ESelection
aWordSelection(0, 4, 0, 7);
379 rEditView
.SetSelection(aWordSelection
);
380 // Did we indeed manage to select the second word?
381 CPPUNIT_ASSERT_EQUAL(OUString("bbb"), rEditView
.GetSelected());
383 // Now use setTextSelection() to move the end of the selection 1000 twips right.
384 vcl::Cursor
* pCursor
= rEditView
.GetCursor();
385 Point aEnd
= pCursor
->GetPos();
386 aEnd
.setX(aEnd
.getX() + 1000);
387 pXImpressDocument
->setTextSelection(LOK_SETTEXTSELECTION_END
, aEnd
.getX(), aEnd
.getY());
388 // The new selection must include the ending dot, too -- but not the first word.
389 CPPUNIT_ASSERT_EQUAL(OUString("bbb."), rEditView
.GetSelected());
392 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testGetTextSelection
)
394 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
395 uno::Reference
<container::XIndexAccess
> xDrawPage(pXImpressDocument
->getDrawPages()->getByIndex(0), uno::UNO_QUERY
);
396 uno::Reference
<text::XTextRange
> xShape(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
397 xShape
->setString("Shape");
398 // Create a selection on the shape text.
399 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
400 SdPage
* pActualPage
= pViewShell
->GetActualPage();
401 SdrObject
* pObject
= pActualPage
->GetObj(0);
402 SdrView
* pView
= pViewShell
->GetView();
403 pView
->SdrBeginTextEdit(pObject
);
404 CPPUNIT_ASSERT(pView
->GetTextEditObject());
405 EditView
& rEditView
= pView
->GetTextEditOutlinerView()->GetEditView();
406 ESelection
aWordSelection(0, 0, 0, 5);
407 rEditView
.SetSelection(aWordSelection
);
408 // Did we indeed manage to copy the selected text?
409 CPPUNIT_ASSERT_EQUAL(OString("Shape"), apitest::helper::transferable::getTextSelection(pXImpressDocument
->getSelection(), "text/plain;charset=utf-8"));
411 // Make sure returned RTF is not empty.
412 CPPUNIT_ASSERT(!apitest::helper::transferable::getTextSelection(pXImpressDocument
->getSelection(), "text/rtf").isEmpty());
415 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testSetGraphicSelection
)
417 SdXImpressDocument
* pXImpressDocument
= createDoc("shape.odp");
418 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
419 SdPage
* pPage
= pViewShell
->GetActualPage();
420 SdrObject
* pObject
= pPage
->GetObj(0);
421 SdrHdlList
handleList(nullptr);
422 pObject
->AddToHdlList(handleList
);
423 // Make sure the rectangle has 8 handles: at each corner and at the center of each edge.
424 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(8), handleList
.GetHdlCount());
425 // Take the bottom center one.
426 SdrHdl
* pHdl
= handleList
.GetHdl(6);
427 CPPUNIT_ASSERT_EQUAL(int(SdrHdlKind::Lower
), static_cast<int>(pHdl
->GetKind()));
428 ::tools::Rectangle aShapeBefore
= pObject
->GetSnapRect();
430 pXImpressDocument
->setGraphicSelection(LOK_SETGRAPHICSELECTION_START
, o3tl::toTwips(pHdl
->GetPos().getX(), o3tl::Length::mm100
), o3tl::toTwips(pHdl
->GetPos().getY(), o3tl::Length::mm100
));
431 pXImpressDocument
->setGraphicSelection(LOK_SETGRAPHICSELECTION_END
, o3tl::toTwips(pHdl
->GetPos().getX(), o3tl::Length::mm100
), o3tl::toTwips(pHdl
->GetPos().getY() + 1000, o3tl::Length::mm100
));
433 // Assert that view shell ID tracking works.
434 sal_Int32 nView1
= SfxLokHelper::getView();
435 SdDrawDocument
* pDocument
= pXImpressDocument
->GetDoc();
436 sd::UndoManager
* pUndoManager
= pDocument
->GetUndoManager();
437 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pUndoManager
->GetUndoActionCount());
438 auto pListAction
= dynamic_cast<SfxListUndoAction
*>(pUndoManager
->GetUndoAction());
439 CPPUNIT_ASSERT(pListAction
);
440 for (size_t i
= 0; i
< pListAction
->maUndoActions
.size(); ++i
)
441 // The second item was -1 here, view shell ID wasn't known.
442 CPPUNIT_ASSERT_EQUAL(ViewShellId(nView1
), pListAction
->GetUndoAction(i
)->GetViewShellId());
444 ::tools::Rectangle aShapeAfter
= pObject
->GetSnapRect();
445 // Check that a resize happened, but aspect ratio is not kept.
446 CPPUNIT_ASSERT_EQUAL(aShapeBefore
.getOpenWidth(), aShapeAfter
.getOpenWidth());
447 CPPUNIT_ASSERT(aShapeBefore
.getOpenHeight() < aShapeAfter
.getOpenHeight());
450 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testUndoShells
)
452 // Load a document and set the page size.
453 SdXImpressDocument
* pXImpressDocument
= createDoc("shape.odp");
454 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
456 {"AttributePageSize.Width", uno::Any(static_cast<sal_Int32
>(10000))},
457 {"AttributePageSize.Height", uno::Any(static_cast<sal_Int32
>(10000))},
459 dispatchCommand(mxComponent
, ".uno:AttributePageSize", aPropertyValues
);
461 // Assert that view shell ID tracking works for SdUndoAction subclasses.
462 SdDrawDocument
* pDocument
= pXImpressDocument
->GetDoc();
463 sd::UndoManager
* pUndoManager
= pDocument
->GetUndoManager();
464 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pUndoManager
->GetUndoActionCount());
465 sal_Int32 nView1
= SfxLokHelper::getView();
466 // This was -1, SdUndoGroup did not track what view shell created it.
467 CPPUNIT_ASSERT_EQUAL(ViewShellId(nView1
), pUndoManager
->GetUndoAction()->GetViewShellId());
470 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testResetSelection
)
472 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
473 uno::Reference
<container::XIndexAccess
> xDrawPage(pXImpressDocument
->getDrawPages()->getByIndex(0), uno::UNO_QUERY
);
474 uno::Reference
<text::XTextRange
> xShape(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
475 xShape
->setString("Aaa bbb.");
476 // Create a selection on the second word.
477 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
478 SdPage
* pActualPage
= pViewShell
->GetActualPage();
479 SdrObject
* pObject
= pActualPage
->GetObj(0);
480 SdrView
* pView
= pViewShell
->GetView();
481 pView
->SdrBeginTextEdit(pObject
);
482 CPPUNIT_ASSERT(pView
->GetTextEditObject());
483 EditView
& rEditView
= pView
->GetTextEditOutlinerView()->GetEditView();
484 ESelection
aWordSelection(0, 4, 0, 7);
485 rEditView
.SetSelection(aWordSelection
);
486 // Did we indeed manage to select the second word?
487 CPPUNIT_ASSERT_EQUAL(OUString("bbb"), rEditView
.GetSelected());
489 // Now use resetSelection() to reset the selection.
490 pXImpressDocument
->resetSelection();
491 CPPUNIT_ASSERT(!pView
->GetTextEditObject());
497 std::vector
<OUString
> getCurrentParts(SdXImpressDocument
* pDocument
)
499 int parts
= pDocument
->getParts();
500 std::vector
<OUString
> result
;
502 result
.reserve(parts
);
503 for (int i
= 0; i
< parts
; i
++)
505 result
.push_back(pDocument
->getPartName(i
));
513 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testInsertDeletePage
)
515 SdXImpressDocument
* pXImpressDocument
= createDoc("insert-delete.odp");
516 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
517 setupLibreOfficeKitViewCallback(pViewShell
->GetViewShellBase());
519 SdDrawDocument
* pDoc
= pXImpressDocument
->GetDocShell()->GetDoc();
520 CPPUNIT_ASSERT(pDoc
);
522 std::vector
<OUString
> aInserted
=
524 "Slide 1", "Slide 2", "Slide 3", "Slide 4", "Slide 5",
525 "Slide 6", "Slide 7", "Slide 8", "Slide 9", "Slide 10", "Slide 11"
528 std::vector
<OUString
> aDeleted
=
533 // the document has 1 slide
534 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(1), pDoc
->GetSdPageCount(PageKind::Standard
));
536 uno::Sequence
<beans::PropertyValue
> aArgs
;
539 m_aDocumentSizeCondition
.reset();
540 for (unsigned it
= 1; it
<= 10; it
++)
541 dispatchCommand(mxComponent
, ".uno:InsertPage", aArgs
);
543 osl::Condition::Result aResult
= m_aDocumentSizeCondition
.wait(std::chrono::seconds(2));
544 CPPUNIT_ASSERT_EQUAL(osl::Condition::result_ok
, aResult
);
546 // Verify inserted slides
547 std::vector
<OUString
> aPageList(getCurrentParts(pXImpressDocument
));
548 CPPUNIT_ASSERT_EQUAL(aPageList
.size(), aInserted
.size());
550 for (auto it1
= aPageList
.begin(), it2
= aInserted
.begin(); it1
!= aPageList
.end(); ++it1
, ++it2
)
552 CPPUNIT_ASSERT_EQUAL(*it1
, *it2
);
556 m_aDocumentSizeCondition
.reset();
557 for (unsigned it
= 1; it
<= 10; it
++)
558 dispatchCommand(mxComponent
, ".uno:DeletePage", aArgs
);
560 aResult
= m_aDocumentSizeCondition
.wait(std::chrono::seconds(2));
561 CPPUNIT_ASSERT_EQUAL(osl::Condition::result_ok
, aResult
);
563 // Verify deleted slides
564 aPageList
= getCurrentParts(pXImpressDocument
);
565 CPPUNIT_ASSERT_EQUAL(aPageList
.size(), aDeleted
.size());
566 for (auto it1
= aPageList
.begin(), it2
= aDeleted
.begin(); it1
!= aPageList
.end(); ++it1
, ++it2
)
568 CPPUNIT_ASSERT_EQUAL(*it1
, *it2
);
571 // Undo deleted slides
572 m_aDocumentSizeCondition
.reset();
573 for (unsigned it
= 1; it
<= 10; it
++)
574 dispatchCommand(mxComponent
, ".uno:Undo", aArgs
);
576 aResult
= m_aDocumentSizeCondition
.wait(std::chrono::seconds(2));
577 CPPUNIT_ASSERT_EQUAL(osl::Condition::result_ok
, aResult
);
579 // Verify inserted slides
580 aPageList
= getCurrentParts(pXImpressDocument
);
581 CPPUNIT_ASSERT_EQUAL(aPageList
.size(), aInserted
.size());
582 for (auto it1
= aPageList
.begin(), it2
= aInserted
.begin(); it1
!= aPageList
.end(); ++it1
, ++it2
)
584 CPPUNIT_ASSERT_EQUAL(*it1
, *it2
);
587 // Redo deleted slides
588 m_aDocumentSizeCondition
.reset();
589 for (unsigned it
= 1; it
<= 10; it
++)
590 dispatchCommand(mxComponent
, ".uno:Redo", aArgs
);
592 aResult
= m_aDocumentSizeCondition
.wait(std::chrono::seconds(2));
593 CPPUNIT_ASSERT_EQUAL(osl::Condition::result_ok
, aResult
);
595 // Verify deleted slides
596 aPageList
= getCurrentParts(pXImpressDocument
);
597 CPPUNIT_ASSERT_EQUAL(aPageList
.size(), aDeleted
.size());
598 for (auto it1
= aPageList
.begin(), it2
= aDeleted
.begin(); it1
!= aPageList
.end(); ++it1
, ++it2
)
600 CPPUNIT_ASSERT_EQUAL(*it1
, *it2
);
603 // the document has 1 slide
604 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(1), pDoc
->GetSdPageCount(PageKind::Standard
));
607 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testInsertTable
)
609 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
611 uno::Sequence
<beans::PropertyValue
> aArgs(comphelper::InitPropertySequence(
613 { "Rows", uno::Any(sal_Int32(3)) },
614 { "Columns", uno::Any(sal_Int32(5)) }
617 dispatchCommand(mxComponent
, ".uno:InsertTable", aArgs
);
620 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
621 SdPage
* pActualPage
= pViewShell
->GetActualPage();
622 SdrObject
* pObject
= pActualPage
->GetObj(1);
623 CPPUNIT_ASSERT(pObject
);
625 // check that the table is not in the top left corner
626 Point
aPos(pObject
->GetRelativePos());
628 CPPUNIT_ASSERT(aPos
.X() != 0);
629 CPPUNIT_ASSERT(aPos
.Y() != 0);
632 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testDeleteTable
)
634 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
636 uno::Sequence
<beans::PropertyValue
> aArgs(comphelper::InitPropertySequence(
638 { "Rows", uno::Any(sal_Int32(3)) },
639 { "Columns", uno::Any(sal_Int32(5)) }
642 dispatchCommand(mxComponent
, ".uno:InsertTable", aArgs
);
643 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
644 SdrView
* pSdrView
= pViewShell
->GetView();
645 const SdrMarkList
& rMarkList
= pSdrView
->GetMarkedObjectList();
646 CPPUNIT_ASSERT(rMarkList
.GetMarkCount());
647 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_MOD1
| awt::Key::A
);
648 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_MOD1
| awt::Key::A
);
649 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_DELETE
);
650 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_DELETE
);
651 Scheduler::ProcessEventsToIdle();
652 CPPUNIT_ASSERT(!rMarkList
.GetMarkCount());
655 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testPartHash
)
657 SdXImpressDocument
* pDoc
= createDoc("dummy.odp");
659 int nParts
= pDoc
->getParts();
660 for (int it
= 0; it
< nParts
; it
++)
662 CPPUNIT_ASSERT(!pDoc
->getPartHash(it
).isEmpty());
665 // check part that it does not exists
666 CPPUNIT_ASSERT(pDoc
->getPartHash(100).isEmpty());
669 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testResizeTable
)
671 // Load the document.
672 SdXImpressDocument
* pXImpressDocument
= createDoc("table.odp");
673 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
674 SdPage
* pActualPage
= pViewShell
->GetActualPage();
675 SdrObject
* pObject
= pActualPage
->GetObj(0);
676 auto pTableObject
= dynamic_cast<sdr::table::SdrTableObj
*>(pObject
);
677 CPPUNIT_ASSERT(pTableObject
);
679 // Select the table by marking it + starting and ending text edit.
680 SdrView
* pView
= pViewShell
->GetView();
681 pView
->MarkObj(pObject
, pView
->GetSdrPageView());
682 pView
->SdrBeginTextEdit(pObject
);
683 pView
->SdrEndTextEdit();
685 // Remember the original row heights.
686 uno::Reference
<table::XColumnRowRange
> xTable
= pTableObject
->getTable();
687 uno::Reference
<container::XIndexAccess
> xRows
= xTable
->getRows();
688 uno::Reference
<beans::XPropertySet
> xRow1(xRows
->getByIndex(0), uno::UNO_QUERY
);
689 sal_Int32 nExpectedRow1
= xRow1
->getPropertyValue("Size").get
<sal_Int32
>();
690 uno::Reference
<beans::XPropertySet
> xRow2(xRows
->getByIndex(1), uno::UNO_QUERY
);
691 sal_Int32 nExpectedRow2
= xRow2
->getPropertyValue("Size").get
<sal_Int32
>();
693 // Resize the upper row, decrease its height by 1 cm.
694 Point aInnerRowEdge
= pObject
->GetSnapRect().Center();
695 pXImpressDocument
->setGraphicSelection(LOK_SETGRAPHICSELECTION_START
, o3tl::toTwips(aInnerRowEdge
.getX(), o3tl::Length::mm100
), o3tl::toTwips(aInnerRowEdge
.getY(), o3tl::Length::mm100
));
696 pXImpressDocument
->setGraphicSelection(LOK_SETGRAPHICSELECTION_END
, o3tl::toTwips(aInnerRowEdge
.getX(), o3tl::Length::mm100
), o3tl::toTwips(aInnerRowEdge
.getY() - 1000, o3tl::Length::mm100
));
698 // Remember the resized row heights.
699 sal_Int32 nResizedRow1
= xRow1
->getPropertyValue("Size").get
<sal_Int32
>();
700 CPPUNIT_ASSERT(nResizedRow1
< nExpectedRow1
);
701 sal_Int32 nResizedRow2
= xRow2
->getPropertyValue("Size").get
<sal_Int32
>();
702 CPPUNIT_ASSERT_EQUAL(nExpectedRow2
, nResizedRow2
);
704 // Now undo the resize.
705 pXImpressDocument
->GetDocShell()->GetUndoManager()->Undo();
707 // Check the undo result.
708 sal_Int32 nActualRow1
= xRow1
->getPropertyValue("Size").get
<sal_Int32
>();
709 CPPUNIT_ASSERT_EQUAL(nExpectedRow1
, nActualRow1
);
710 sal_Int32 nActualRow2
= xRow2
->getPropertyValue("Size").get
<sal_Int32
>();
711 // Expected was 4000, actual was 4572, i.e. the second row after undo was larger than expected.
712 CPPUNIT_ASSERT_EQUAL(nExpectedRow2
, nActualRow2
);
715 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testResizeTableColumn
)
717 // Load the document.
718 SdXImpressDocument
* pXImpressDocument
= createDoc("table-column.odp");
719 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
720 SdPage
* pActualPage
= pViewShell
->GetActualPage();
721 SdrObject
* pObject
= pActualPage
->GetObj(0);
722 auto pTableObject
= dynamic_cast<sdr::table::SdrTableObj
*>(pObject
);
723 CPPUNIT_ASSERT(pTableObject
);
725 // Select the table by marking it + starting and ending text edit.
726 SdrView
* pView
= pViewShell
->GetView();
727 pView
->MarkObj(pObject
, pView
->GetSdrPageView());
728 pView
->SdrBeginTextEdit(pObject
);
729 pView
->SdrEndTextEdit();
731 // Remember the original cell widths.
732 xmlDocUniquePtr pXmlDoc
= parseXmlDump();
733 OString aPrefix
= "/SdDrawDocument/SdrModel/maPages/SdPage/SdrPage/SdrObjList/SdrTableObj/SdrTableObjImpl/TableLayouter/columns/";
734 sal_Int32 nExpectedColumn1
= getXPath(pXmlDoc
, aPrefix
+ "TableLayouter_Layout[1]", "size").toInt32();
735 sal_Int32 nExpectedColumn2
= getXPath(pXmlDoc
, aPrefix
+ "TableLayouter_Layout[2]", "size").toInt32();
738 // Resize the left column, decrease its width by 1 cm.
739 Point aInnerRowEdge
= pObject
->GetSnapRect().Center();
740 pXImpressDocument
->setGraphicSelection(LOK_SETGRAPHICSELECTION_START
, o3tl::toTwips(aInnerRowEdge
.getX(), o3tl::Length::mm100
), o3tl::toTwips(aInnerRowEdge
.getY(), o3tl::Length::mm100
));
741 pXImpressDocument
->setGraphicSelection(LOK_SETGRAPHICSELECTION_END
, o3tl::toTwips(aInnerRowEdge
.getX() - 1000, o3tl::Length::mm100
), o3tl::toTwips(aInnerRowEdge
.getY(), o3tl::Length::mm100
));
743 // Remember the resized column widths.
744 pXmlDoc
= parseXmlDump();
745 sal_Int32 nResizedColumn1
= getXPath(pXmlDoc
, aPrefix
+ "TableLayouter_Layout[1]", "size").toInt32();
746 CPPUNIT_ASSERT(nResizedColumn1
< nExpectedColumn1
);
747 sal_Int32 nResizedColumn2
= getXPath(pXmlDoc
, aPrefix
+ "TableLayouter_Layout[2]", "size").toInt32();
748 CPPUNIT_ASSERT(nResizedColumn2
> nExpectedColumn2
);
751 // Now undo the resize.
752 pXImpressDocument
->GetDocShell()->GetUndoManager()->Undo();
754 // Check the undo result.
755 pXmlDoc
= parseXmlDump();
756 sal_Int32 nActualColumn1
= getXPath(pXmlDoc
, aPrefix
+ "TableLayouter_Layout[1]", "size").toInt32();
757 // Expected was 7049, actual was 6048, i.e. the first column width after undo was 1cm smaller than expected.
758 CPPUNIT_ASSERT_EQUAL(nExpectedColumn1
, nActualColumn1
);
759 sal_Int32 nActualColumn2
= getXPath(pXmlDoc
, aPrefix
+ "TableLayouter_Layout[2]", "size").toInt32();
760 CPPUNIT_ASSERT_EQUAL(nExpectedColumn2
, nActualColumn2
);
766 /// A view callback tracks callbacks invoked on one specific view.
767 class ViewCallback final
769 SfxViewShell
* mpViewShell
;
772 bool m_bGraphicSelectionInvalidated
;
773 bool m_bGraphicViewSelectionInvalidated
;
774 /// Our current part, to be able to decide if a view cursor/selection is relevant for us.
776 bool m_bCursorVisibleChanged
;
777 bool m_bCursorVisible
;
779 bool m_bTilesInvalidated
;
780 std::vector
<tools::Rectangle
> m_aInvalidations
;
781 std::map
<int, bool> m_aViewCursorInvalidations
;
782 std::map
<int, bool> m_aViewCursorVisibilities
;
783 bool m_bViewSelectionSet
;
784 boost::property_tree::ptree m_aCommentCallbackResult
;
785 OString m_ShapeSelection
;
786 TestLokCallbackWrapper m_callbackWrapper
;
789 : m_bGraphicSelectionInvalidated(false),
790 m_bGraphicViewSelectionInvalidated(false),
792 m_bCursorVisibleChanged(false),
793 m_bCursorVisible(false),
795 m_bTilesInvalidated(false),
796 m_bViewSelectionSet(false),
797 m_callbackWrapper(&callback
, this)
799 mpViewShell
= SfxViewShell::Current();
800 mpViewShell
->setLibreOfficeKitViewCallback(&m_callbackWrapper
);
801 mnView
= SfxLokHelper::getView();
802 m_callbackWrapper
.setLOKViewId( mnView
);
807 SfxLokHelper::setView(mnView
);
808 mpViewShell
->setLibreOfficeKitViewCallback(nullptr);
811 static void callback(int nType
, const char* pPayload
, void* pData
)
813 static_cast<ViewCallback
*>(pData
)->callbackImpl(nType
, pPayload
);
816 void callbackImpl(int nType
, const char* pPayload
)
820 case LOK_CALLBACK_INVALIDATE_TILES
:
822 m_bTilesInvalidated
= true;
823 OString
text(pPayload
);
824 if (!text
.startsWith("EMPTY"))
826 uno::Sequence
<OUString
> aSeq
= comphelper::string::convertCommaSeparated(OUString::createFromAscii(pPayload
));
827 CPPUNIT_ASSERT(aSeq
.getLength() == 4 || aSeq
.getLength() == 5);
828 tools::Rectangle aInvalidationRect
;
829 aInvalidationRect
.SetLeft(aSeq
[0].toInt32());
830 aInvalidationRect
.SetTop(aSeq
[1].toInt32());
831 aInvalidationRect
.setWidth(aSeq
[2].toInt32());
832 aInvalidationRect
.setHeight(aSeq
[3].toInt32());
833 m_aInvalidations
.push_back(aInvalidationRect
);
837 case LOK_CALLBACK_GRAPHIC_SELECTION
:
839 m_bGraphicSelectionInvalidated
= true;
840 m_ShapeSelection
= OString(pPayload
);
843 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION
:
845 std::stringstream
aStream(pPayload
);
846 boost::property_tree::ptree aTree
;
847 boost::property_tree::read_json(aStream
, aTree
);
848 if (aTree
.get_child("part").get_value
<int>() == m_nPart
)
849 // Ignore callbacks which are for a different part.
850 m_bGraphicViewSelectionInvalidated
= true;
853 case LOK_CALLBACK_CURSOR_VISIBLE
:
855 m_bCursorVisibleChanged
= true;
856 m_bCursorVisible
= (std::string_view("true") == pPayload
);
859 case LOK_CALLBACK_VIEW_LOCK
:
861 std::stringstream
aStream(pPayload
);
862 boost::property_tree::ptree aTree
;
863 boost::property_tree::read_json(aStream
, aTree
);
864 m_bViewLock
= aTree
.get_child("rectangle").get_value
<std::string
>() != "EMPTY";
867 case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR
:
869 std::stringstream
aStream(pPayload
);
870 boost::property_tree::ptree aTree
;
871 boost::property_tree::read_json(aStream
, aTree
);
872 int nViewId
= aTree
.get_child("viewId").get_value
<int>();
873 m_aViewCursorInvalidations
[nViewId
] = true;
876 case LOK_CALLBACK_VIEW_CURSOR_VISIBLE
:
878 std::stringstream
aStream(pPayload
);
879 boost::property_tree::ptree aTree
;
880 boost::property_tree::read_json(aStream
, aTree
);
881 const int nViewId
= aTree
.get_child("viewId").get_value
<int>();
882 m_aViewCursorVisibilities
[nViewId
] = std::string_view("true") == pPayload
;
885 case LOK_CALLBACK_TEXT_VIEW_SELECTION
:
887 m_bViewSelectionSet
= true;
890 case LOK_CALLBACK_COMMENT
:
892 m_aCommentCallbackResult
.clear();
893 std::stringstream
aStream(pPayload
);
894 boost::property_tree::read_json(aStream
, m_aCommentCallbackResult
);
895 m_aCommentCallbackResult
= m_aCommentCallbackResult
.get_child("comment");
904 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testViewCursors
)
907 SdXImpressDocument
* pXImpressDocument
= createDoc("shape.odp");
909 SfxLokHelper::createView();
912 // Select the shape in the second view.
913 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
914 SdPage
* pActualPage
= pViewShell
->GetActualPage();
915 SdrObject
* pObject
= pActualPage
->GetObj(0);
916 SdrView
* pView
= pViewShell
->GetView();
917 pView
->MarkObj(pObject
, pView
->GetSdrPageView());
918 Scheduler::ProcessEventsToIdle();
920 // First view notices that there was a selection change in the other view.
921 CPPUNIT_ASSERT(aView1
.m_bGraphicViewSelectionInvalidated
);
922 // Second view notices that there was a selection change in its own view.
923 CPPUNIT_ASSERT(aView2
.m_bGraphicSelectionInvalidated
);
926 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testViewCursorParts
)
929 SdXImpressDocument
* pXImpressDocument
= createDoc("shape.odp");
931 SfxLokHelper::createView();
932 pXImpressDocument
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
935 // Select the shape in the second view.
936 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
937 SdPage
* pActualPage
= pViewShell
->GetActualPage();
938 SdrObject
* pObject
= pActualPage
->GetObj(0);
939 SdrView
* pView
= pViewShell
->GetView();
940 pView
->MarkObj(pObject
, pView
->GetSdrPageView());
941 Scheduler::ProcessEventsToIdle();
942 // First view notices that there was a selection change in the other view.
943 CPPUNIT_ASSERT(aView1
.m_bGraphicViewSelectionInvalidated
);
944 pView
->UnmarkAllObj(pView
->GetSdrPageView());
946 // Now switch to the second part in the second view.
947 pXImpressDocument
->setPart(1);
949 aView1
.m_bGraphicViewSelectionInvalidated
= false;
950 pActualPage
= pViewShell
->GetActualPage();
951 pObject
= pActualPage
->GetObj(0);
952 pView
->MarkObj(pObject
, pView
->GetSdrPageView());
953 Scheduler::ProcessEventsToIdle();
954 // First view ignores view selection, as it would be for part 1, and it's in part 0.
955 // This failed when the "part" was always 0 in the callback.
956 CPPUNIT_ASSERT(!aView1
.m_bGraphicViewSelectionInvalidated
);
959 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testCursorViews
)
961 // Create the first view.
962 SdXImpressDocument
* pXImpressDocument
= createDoc("title-shape.odp");
963 int nView1
= SfxLokHelper::getView();
966 // Begin text edit on the only object on the slide.
967 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
968 SdrView
* pView
= pViewShell
->GetView();
969 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::TAB
);
970 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::TAB
);
971 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
972 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
973 Scheduler::ProcessEventsToIdle();
974 CPPUNIT_ASSERT(pView
->IsTextEdit());
976 // Make sure that cursor state is not changed just because we create a second view.
977 aView1
.m_bCursorVisibleChanged
= false;
978 SfxLokHelper::createView();
979 pXImpressDocument
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
980 Scheduler::ProcessEventsToIdle();
981 CPPUNIT_ASSERT(!aView1
.m_bCursorVisibleChanged
);
983 // Make sure that typing in the first view causes an invalidation in the
984 // second view as well, even if the second view was created after begin
985 // text edit in the first view.
987 // This failed: the second view didn't get a lock notification, even if the
988 // first view already started text edit.
989 CPPUNIT_ASSERT(aView2
.m_bViewLock
);
990 SfxLokHelper::setView(nView1
);
991 aView2
.m_bTilesInvalidated
= false;
992 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
993 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
994 Scheduler::ProcessEventsToIdle();
995 // This failed: the second view was not invalidated when pressing a key in
997 CPPUNIT_ASSERT(aView2
.m_bTilesInvalidated
);
1000 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testCursorVisibility_SingleClick
)
1002 // Single-clicking in a text box enters editing only
1003 // when it's on the text, even if it's the default text.
1006 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
1007 ViewCallback aView1
;
1009 // Begin text edit on the only object on the slide.
1010 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
1011 SdPage
* pActualPage
= pViewShell
->GetActualPage();
1012 SdrObject
* pObject1
= pActualPage
->GetObj(0);
1013 CPPUNIT_ASSERT(pObject1
!= nullptr);
1014 CPPUNIT_ASSERT_EQUAL(SdrObjKind::TitleText
, pObject1
->GetObjIdentifier());
1015 SdrTextObj
* pTextObject
= static_cast<SdrTextObj
*>(pObject1
);
1017 // Click once outside of the text (in the first quartile) => no editing.
1018 const ::tools::Rectangle aRect
= pTextObject
->GetCurrentBoundRect();
1019 const auto cornerX
= o3tl::toTwips(aRect
.Left() + (aRect
.getOpenWidth() / 4), o3tl::Length::mm100
);
1020 const auto cornerY
= o3tl::toTwips(aRect
.Top() + (aRect
.getOpenHeight() / 4), o3tl::Length::mm100
);
1021 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1024 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
,
1027 Scheduler::ProcessEventsToIdle();
1030 CPPUNIT_ASSERT(!pViewShell
->GetView()->IsTextEdit());
1031 CPPUNIT_ASSERT(!aView1
.m_bCursorVisible
);
1033 // Click again, now on the text, in the center, to start editing.
1034 const auto centerX
= o3tl::toTwips(aRect
.Left() + (aRect
.getOpenWidth() / 2), o3tl::Length::mm100
);
1035 const auto centerY
= o3tl::toTwips(aRect
.Top() + (aRect
.getOpenHeight() / 2), o3tl::Length::mm100
);
1036 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1039 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
,
1042 Scheduler::ProcessEventsToIdle();
1044 // We must be in text editing mode and have cursor visible.
1045 CPPUNIT_ASSERT(pViewShell
->GetView()->IsTextEdit());
1046 CPPUNIT_ASSERT(aView1
.m_bCursorVisible
);
1050 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testCursorVisibility_DoubleClick
)
1052 // Double-clicking anywhere in the TextBox should start editing.
1054 // Create the first view.
1055 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
1056 ViewCallback aView1
;
1058 // Begin text edit on the only object on the slide.
1059 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
1060 SdPage
* pActualPage
= pViewShell
->GetActualPage();
1061 SdrObject
* pObject1
= pActualPage
->GetObj(0);
1062 CPPUNIT_ASSERT(pObject1
!= nullptr);
1063 CPPUNIT_ASSERT_EQUAL(SdrObjKind::TitleText
, pObject1
->GetObjIdentifier());
1064 SdrTextObj
* pTextObject
= static_cast<SdrTextObj
*>(pObject1
);
1066 // Double-click outside the text to enter edit mode.
1067 const ::tools::Rectangle aRect
= pTextObject
->GetCurrentBoundRect();
1068 const auto cornerX
= o3tl::toTwips(aRect
.Left() + (aRect
.getOpenWidth() / 4), o3tl::Length::mm100
);
1069 const auto cornerY
= o3tl::toTwips(aRect
.Top() + (aRect
.getOpenHeight() / 4), o3tl::Length::mm100
);
1070 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1073 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
,
1076 Scheduler::ProcessEventsToIdle();
1078 // We must be in text editing mode and have cursor visible.
1079 CPPUNIT_ASSERT(pViewShell
->GetView()->IsTextEdit());
1080 CPPUNIT_ASSERT(aView1
.m_bCursorVisible
);
1083 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testCursorVisibility_MultiView
)
1085 // Create the first view.
1086 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
1087 const int nView1
= SfxLokHelper::getView();
1088 ViewCallback aView1
;
1090 // Begin text edit on the only object on the slide.
1091 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
1092 SdPage
* pActualPage
= pViewShell
->GetActualPage();
1093 SdrObject
* pObject1
= pActualPage
->GetObj(0);
1094 CPPUNIT_ASSERT(pObject1
);
1095 CPPUNIT_ASSERT_EQUAL(SdrObjKind::TitleText
, pObject1
->GetObjIdentifier());
1096 SdrTextObj
* pTextObject
= static_cast<SdrTextObj
*>(pObject1
);
1098 // Make sure that cursor state is not changed just because we create a second view.
1099 SfxLokHelper::createView();
1100 pXImpressDocument
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
1101 const int nView2
= SfxLokHelper::getView();
1102 Scheduler::ProcessEventsToIdle();
1103 CPPUNIT_ASSERT_EQUAL(false, aView1
.m_bCursorVisibleChanged
);
1104 CPPUNIT_ASSERT_EQUAL(false, aView1
.m_aViewCursorVisibilities
[nView2
]);
1106 // Also check that the second view gets the notifications.
1107 ViewCallback aView2
;
1109 SfxLokHelper::setView(nView1
);
1111 ::tools::Rectangle aRect
= pTextObject
->GetCurrentBoundRect();
1112 const auto centerX
= o3tl::toTwips(aRect
.Left() + (aRect
.getOpenWidth() / 2), o3tl::Length::mm100
);
1113 const auto centerY
= o3tl::toTwips(aRect
.Top() + (aRect
.getOpenHeight() / 2), o3tl::Length::mm100
);
1114 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1117 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
,
1120 Scheduler::ProcessEventsToIdle();
1122 // We must be in text editing mode and have cursor visible.
1123 CPPUNIT_ASSERT(pViewShell
->GetView()->IsTextEdit());
1124 CPPUNIT_ASSERT(aView1
.m_bCursorVisible
);
1125 CPPUNIT_ASSERT_EQUAL(false, aView1
.m_aViewCursorVisibilities
[nView2
]);
1127 CPPUNIT_ASSERT_EQUAL(false, aView2
.m_bCursorVisible
);
1128 CPPUNIT_ASSERT_EQUAL(false, aView2
.m_aViewCursorVisibilities
[nView1
]);
1129 CPPUNIT_ASSERT_EQUAL(false, aView2
.m_aViewCursorVisibilities
[nView2
]);
1132 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testCursorVisibility_Escape
)
1135 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
1136 ViewCallback aView1
;
1138 // Begin text edit on the only object on the slide.
1139 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
1140 SdPage
* pActualPage
= pViewShell
->GetActualPage();
1141 SdrObject
* pObject1
= pActualPage
->GetObj(0);
1142 CPPUNIT_ASSERT(pObject1
!= nullptr);
1143 CPPUNIT_ASSERT_EQUAL(SdrObjKind::TitleText
, pObject1
->GetObjIdentifier());
1144 SdrTextObj
* pTextObject
= static_cast<SdrTextObj
*>(pObject1
);
1146 // Click once on the text to start editing.
1147 const ::tools::Rectangle aRect
= pTextObject
->GetCurrentBoundRect();
1148 const auto centerX
= o3tl::toTwips(aRect
.Left() + (aRect
.getOpenWidth() / 2), o3tl::Length::mm100
);
1149 const auto centerY
= o3tl::toTwips(aRect
.Top() + (aRect
.getOpenHeight() / 2), o3tl::Length::mm100
);
1150 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1153 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
,
1156 Scheduler::ProcessEventsToIdle();
1158 // We must be in text editing mode and have cursor visible.
1159 CPPUNIT_ASSERT(pViewShell
->GetView()->IsTextEdit());
1160 CPPUNIT_ASSERT(aView1
.m_bCursorVisible
);
1162 // End editing by pressing the escape key.
1163 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::ESCAPE
);
1164 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::ESCAPE
);
1165 Scheduler::ProcessEventsToIdle();
1167 // We must be in text editing mode and have cursor visible.
1168 CPPUNIT_ASSERT(!pViewShell
->GetView()->IsTextEdit());
1169 CPPUNIT_ASSERT_EQUAL(false, aView1
.m_bCursorVisible
);
1172 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testViewLock
)
1174 // Load a document that has a shape and create two views.
1175 SdXImpressDocument
* pXImpressDocument
= createDoc("shape.odp");
1176 ViewCallback aView1
;
1177 SfxLokHelper::createView();
1178 pXImpressDocument
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
1180 // Begin text edit in the second view and assert that the first gets a lock
1182 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
1183 SdPage
* pActualPage
= pViewShell
->GetActualPage();
1184 SdrObject
* pObject
= pActualPage
->GetObj(0);
1185 SdrView
* pView
= pViewShell
->GetView();
1186 aView1
.m_bViewLock
= false;
1187 pView
->SdrBeginTextEdit(pObject
);
1188 CPPUNIT_ASSERT(aView1
.m_bViewLock
);
1190 // End text edit in the second view, and assert that the lock is removed in
1192 pView
->SdrEndTextEdit();
1193 CPPUNIT_ASSERT(!aView1
.m_bViewLock
);
1196 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testUndoLimiting
)
1198 // Create the first view.
1199 SdXImpressDocument
* pXImpressDocument
= createDoc("title-shape.odp");
1200 sd::ViewShell
* pViewShell1
= pXImpressDocument
->GetDocShell()->GetViewShell();
1201 int nView1
= SfxLokHelper::getView();
1202 SfxLokHelper::createView();
1203 sd::ViewShell
* pViewShell2
= pXImpressDocument
->GetDocShell()->GetViewShell();
1204 CPPUNIT_ASSERT(pViewShell1
!= pViewShell2
);
1206 // Begin text edit on the only object on the slide.
1207 SfxLokHelper::setView(nView1
);
1208 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::TAB
);
1209 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::TAB
);
1210 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
1211 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
1212 Scheduler::ProcessEventsToIdle();
1213 CPPUNIT_ASSERT(pViewShell1
->GetView()->IsTextEdit());
1215 // View2 UNDO stack should be empty
1217 SfxRequest
aReq2(SID_UNDO
, SfxCallMode::SLOT
, pXImpressDocument
->GetDocShell()->GetDoc()->GetPool());
1218 aReq2
.AppendItem(SfxUInt16Item(SID_UNDO
, 1));
1219 pViewShell2
->ExecuteSlot(aReq2
);
1220 const auto* pReturnValue
= aReq2
.GetReturnValue();
1221 CPPUNIT_ASSERT(!pReturnValue
);
1226 SfxRequest
aReq1(SID_UNDO
, SfxCallMode::SLOT
, pXImpressDocument
->GetDocShell()->GetDoc()->GetPool());
1227 aReq1
.AppendItem(SfxUInt16Item(SID_UNDO
, 1));
1228 pViewShell1
->ExecuteSlot(aReq1
);
1229 CPPUNIT_ASSERT(aReq1
.IsDone());
1234 SfxRequest
aReq1(SID_REDO
, SfxCallMode::SLOT
, pXImpressDocument
->GetDocShell()->GetDoc()->GetPool());
1235 aReq1
.AppendItem(SfxUInt16Item(SID_REDO
, 1));
1236 pViewShell1
->ExecuteSlot(aReq1
);
1237 CPPUNIT_ASSERT(aReq1
.IsDone());
1240 // Exit text edit mode
1241 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::ESCAPE
);
1242 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::ESCAPE
);
1243 Scheduler::ProcessEventsToIdle();
1245 CPPUNIT_ASSERT(!pViewShell1
->GetView()->IsTextEdit());
1247 // Now check view2 cannot undo actions.
1249 SfxRequest
aReq2(SID_UNDO
, SfxCallMode::SLOT
, pXImpressDocument
->GetDocShell()->GetDoc()->GetPool());
1250 aReq2
.AppendItem(SfxUInt16Item(SID_UNDO
, 1));
1251 pViewShell2
->ExecuteSlot(aReq2
);
1252 const SfxUInt32Item
* pUInt32Item
= dynamic_cast<const SfxUInt32Item
*>(aReq2
.GetReturnValue());
1253 CPPUNIT_ASSERT(pUInt32Item
);
1254 CPPUNIT_ASSERT_EQUAL(static_cast< sal_uInt32
>(SID_REPAIRPACKAGE
), pUInt32Item
->GetValue());
1257 // Now check view1 can undo action
1259 SfxRequest
aReq1(SID_UNDO
, SfxCallMode::SLOT
, pXImpressDocument
->GetDocShell()->GetDoc()->GetPool());
1260 aReq1
.AppendItem(SfxUInt16Item(SID_UNDO
, 1));
1261 pViewShell1
->ExecuteSlot(aReq1
);
1262 CPPUNIT_ASSERT(aReq1
.IsDone());
1266 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testCreateViewGraphicSelection
)
1268 // Load a document and register a callback.
1269 SdXImpressDocument
* pXImpressDocument
= createDoc("shape.odp");
1270 ViewCallback aView1
;
1272 // Select the only shape in the document and assert that the graphic selection is changed.
1273 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
1274 SdPage
* pActualPage
= pViewShell
->GetActualPage();
1275 SdrObject
* pObject
= pActualPage
->GetObj(0);
1276 SdrView
* pView
= pViewShell
->GetView();
1277 aView1
.m_bGraphicSelectionInvalidated
= false;
1278 pView
->MarkObj(pObject
, pView
->GetSdrPageView());
1279 CPPUNIT_ASSERT(aView1
.m_bGraphicSelectionInvalidated
);
1281 // Now create a new view.
1282 aView1
.m_bGraphicSelectionInvalidated
= false;
1283 SfxLokHelper::createView();
1284 pXImpressDocument
->initializeForTiledRendering({});
1285 // This failed, creating a new view affected the graphic selection of an
1287 CPPUNIT_ASSERT(!aView1
.m_bGraphicSelectionInvalidated
);
1289 // Check that when the first view has a shape selected and we register a
1290 // callback on the second view, then it gets a "graphic view selection".
1291 ViewCallback aView2
;
1292 // This failed, the created new view had no "view selection" of the first
1293 // view's selected shape.
1294 CPPUNIT_ASSERT(aView2
.m_bGraphicViewSelectionInvalidated
);
1297 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testCreateViewTextCursor
)
1299 // Load a document and register a callback.
1300 SdXImpressDocument
* pXImpressDocument
= createDoc("title-shape.odp");
1301 ViewCallback aView1
;
1304 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::TAB
);
1305 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::TAB
);
1306 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
1307 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
1308 Scheduler::ProcessEventsToIdle();
1309 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
1310 SdrView
* pSdrView
= pViewShell
->GetView();
1311 CPPUNIT_ASSERT(pSdrView
->IsTextEdit());
1313 // Create an editeng text selection.
1314 EditView
& rEditView
= pSdrView
->GetTextEditOutlinerView()->GetEditView();
1315 // 0th para, 0th char -> 0th para, 1st char.
1316 ESelection
aWordSelection(0, 0, 0, 1);
1317 rEditView
.SetSelection(aWordSelection
);
1319 // Make sure that creating a new view either doesn't affect the previous
1320 // one, or at least the effect is not visible at the end.
1321 aView1
.m_aViewCursorInvalidations
.clear();
1322 aView1
.m_aViewCursorVisibilities
.clear();
1323 SfxLokHelper::createView();
1324 pXImpressDocument
->initializeForTiledRendering({});
1325 ViewCallback aView2
;
1326 bool bFoundCursor
= false;
1327 for (const auto& rInvalidation
: aView1
.m_aViewCursorInvalidations
)
1329 auto itVisibility
= aView1
.m_aViewCursorVisibilities
.find(rInvalidation
.first
);
1330 // For each cursor invalidation: if there is no visibility or the visibility is true, that's a problem.
1331 if (itVisibility
== aView1
.m_aViewCursorVisibilities
.end() || itVisibility
->second
)
1333 bFoundCursor
= true;
1337 // This failed: the second view created an unexpected view cursor in the
1339 CPPUNIT_ASSERT(!bFoundCursor
);
1340 // This failed: the text view selection of the first view wasn't seen by
1342 CPPUNIT_ASSERT(aView2
.m_bViewSelectionSet
);
1345 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testTdf102223
)
1347 // Load the document.
1348 SdXImpressDocument
* pXImpressDocument
= createDoc("tdf102223.odp");
1349 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
1350 SdPage
* pActualPage
= pViewShell
->GetActualPage();
1351 auto pTableObject
= dynamic_cast<sdr::table::SdrTableObj
*>(pActualPage
->GetObj(2));
1352 CPPUNIT_ASSERT(pTableObject
);
1353 SdrView
* pView
= pViewShell
->GetView();
1355 // select contents of cell
1356 ::tools::Rectangle aRect
= pTableObject
->GetCurrentBoundRect();
1357 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1358 o3tl::toTwips(aRect
.Left() + 2, o3tl::Length::mm100
), o3tl::toTwips(aRect
.Top() + 2, o3tl::Length::mm100
),
1360 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
,
1361 o3tl::toTwips(aRect
.Left() + 2, o3tl::Length::mm100
), o3tl::toTwips(aRect
.Top() + 2, o3tl::Length::mm100
),
1363 Scheduler::ProcessEventsToIdle();
1364 pView
->SdrBeginTextEdit(pTableObject
);
1365 CPPUNIT_ASSERT(pView
->GetTextEditObject());
1366 EditView
& rEditView
= pView
->GetTextEditOutlinerView()->GetEditView();
1367 rEditView
.SetSelection(ESelection(0, 0, 0, 3)); // start para, start char, end para, end char.
1368 CPPUNIT_ASSERT_EQUAL(OUString("Red"), rEditView
.GetSelected());
1369 CPPUNIT_ASSERT_EQUAL(
1370 int(1411), static_cast<int>(rEditView
.GetAttribs().Get(EE_CHAR_FONTHEIGHT
).GetHeight()));
1372 // cut contents of cell
1373 uno::Sequence
<beans::PropertyValue
> aArgs
;
1374 dispatchCommand(mxComponent
, ".uno:Cut", aArgs
);
1376 pView
->SdrEndTextEdit(false);
1377 pView
->SdrBeginTextEdit(pTableObject
);
1378 CPPUNIT_ASSERT(pView
->GetTextEditObject());
1379 EditView
& rEditView2
= pView
->GetTextEditOutlinerView()->GetEditView();
1380 rEditView2
.SetSelection(ESelection(0, 0, 0, 1)); // start para, start char, end para, end char.
1381 CPPUNIT_ASSERT_EQUAL(
1382 int(1411), static_cast<int>(rEditView2
.GetAttribs().Get(EE_CHAR_FONTHEIGHT
).GetHeight()));
1385 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testTdf118354
)
1387 // Load the document.
1388 SdXImpressDocument
* pXImpressDocument
= createDoc("tdf118354.odp");
1390 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
1391 SdPage
* pActualPage
= pViewShell
->GetActualPage();
1393 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pActualPage
->GetObjCount());
1395 auto pTableObject
= dynamic_cast<sdr::table::SdrTableObj
*>(pActualPage
->GetObj(0));
1396 CPPUNIT_ASSERT(pTableObject
);
1398 // Without the fix, it would crash here
1399 ::tools::Rectangle aRect
= pTableObject
->GetCurrentBoundRect();
1400 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1401 o3tl::toTwips(aRect
.Left() + 2, o3tl::Length::mm100
), o3tl::toTwips(aRect
.Top() + 2, o3tl::Length::mm100
),
1403 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
,
1404 o3tl::toTwips(aRect
.Left() + 2, o3tl::Length::mm100
), o3tl::toTwips(aRect
.Top() + 2, o3tl::Length::mm100
),
1406 Scheduler::ProcessEventsToIdle();
1408 SdrView
* pView
= pViewShell
->GetView();
1409 auto pMarkedObj
= dynamic_cast<sdr::table::SdrTableObj
*>(pView
->GetMarkedObjectByIndex(0));
1410 CPPUNIT_ASSERT_EQUAL(pMarkedObj
, pTableObject
);
1413 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testPostKeyEventInvalidation
)
1415 // Load a document and begin text edit on the first slide.
1416 SdXImpressDocument
* pXImpressDocument
= createDoc("2slides.odp");
1417 CPPUNIT_ASSERT_EQUAL(0, pXImpressDocument
->getPart());
1418 ViewCallback aView1
;
1419 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
1420 SdrView
* pView
= pViewShell
->GetView();
1421 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_TAB
);
1422 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_TAB
);
1423 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_F2
);
1424 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_F2
);
1425 Scheduler::ProcessEventsToIdle();
1426 CPPUNIT_ASSERT(pView
->GetTextEditObject());
1428 // Create a second view and begin text edit there as well, in parallel.
1429 SfxLokHelper::createView();
1430 pXImpressDocument
->initializeForTiledRendering({});
1431 ViewCallback aView2
;
1432 pXImpressDocument
->setPart(1);
1433 sd::ViewShell
* pViewShell2
= pXImpressDocument
->GetDocShell()->GetViewShell();
1434 SdrView
* pView2
= pViewShell2
->GetView();
1435 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_TAB
);
1436 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_TAB
);
1437 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_F2
);
1438 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_F2
);
1439 Scheduler::ProcessEventsToIdle();
1440 CPPUNIT_ASSERT(pView2
->GetTextEditObject());
1442 // Now go left with the cursor in the second view and watch for
1444 aView2
.m_bTilesInvalidated
= false;
1445 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_LEFT
);
1446 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_LEFT
);
1447 Scheduler::ProcessEventsToIdle();
1448 // This failed: moving the cursor caused unexpected invalidation.
1449 CPPUNIT_ASSERT(!aView2
.m_bTilesInvalidated
);
1453 * tests a cut/paste bug around bullet items in a list
1455 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testTdf103083
)
1457 // Load the document.
1458 SdXImpressDocument
* pXImpressDocument
= createDoc("tdf103083.fodp");
1459 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
1460 SdPage
* pActualPage
= pViewShell
->GetActualPage();
1462 SdrObject
* pObject1
= pActualPage
->GetObj(1);
1463 CPPUNIT_ASSERT_EQUAL(SdrObjKind::OutlineText
, pObject1
->GetObjIdentifier());
1464 SdrTextObj
* pTextObject
= static_cast<SdrTextObj
*>(pObject1
);
1466 SdrView
* pView
= pViewShell
->GetView();
1468 // select contents of bullet item
1469 ::tools::Rectangle aRect
= pTextObject
->GetCurrentBoundRect();
1470 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1471 o3tl::toTwips(aRect
.Left() + 2, o3tl::Length::mm100
), o3tl::toTwips(aRect
.Top() + 2, o3tl::Length::mm100
),
1473 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
,
1474 o3tl::toTwips(aRect
.Left() + 2, o3tl::Length::mm100
), o3tl::toTwips(aRect
.Top() + 2, o3tl::Length::mm100
),
1476 Scheduler::ProcessEventsToIdle();
1477 pView
->SdrBeginTextEdit(pTextObject
);
1478 CPPUNIT_ASSERT(pView
->GetTextEditObject());
1479 EditView
& rEditView
= pView
->GetTextEditOutlinerView()->GetEditView();
1480 rEditView
.SetSelection(ESelection(2, 0, 2, 33)); // start para, start char, end para, end char.
1481 CPPUNIT_ASSERT_EQUAL(OUString("They have all the same formatting"), rEditView
.GetSelected());
1482 SdrOutliner
* pOutliner
= pView
->GetTextEditOutliner();
1483 CPPUNIT_ASSERT_EQUAL(OUString("No-Logo Content~LT~Gliederung 2"),
1484 pOutliner
->GetStyleSheet(2)->GetName());
1485 const EditTextObject
& aEdit
= pTextObject
->GetOutlinerParaObject()->GetTextObject();
1486 const SvxNumBulletItem
* pNumFmt
= aEdit
.GetParaAttribs(2).GetItem(EE_PARA_NUMBULLET
);
1487 SvxNumberFormat
aNumFmt(pNumFmt
->GetNumRule().GetLevel(2));
1489 // cut contents of bullet item
1490 dispatchCommand(mxComponent
, ".uno:Cut", uno::Sequence
<beans::PropertyValue
>());
1492 CPPUNIT_ASSERT(pView
->GetTextEditObject());
1493 EditView
& rEditView2
= pView
->GetTextEditOutlinerView()->GetEditView();
1494 rEditView2
.SetSelection(ESelection(2, 0, 2, 10)); // start para, start char, end para, end char.
1495 CPPUNIT_ASSERT_EQUAL(OUString(), rEditView2
.GetSelected());
1497 // paste contents of bullet item
1498 dispatchCommand(mxComponent
, ".uno:Paste", uno::Sequence
<beans::PropertyValue
>());
1500 // send an ESC key to trigger the commit of the edit to the main model
1501 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::ESCAPE
);
1502 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::ESCAPE
);
1503 Scheduler::ProcessEventsToIdle();
1505 pView
->SdrBeginTextEdit(pTextObject
);
1506 CPPUNIT_ASSERT(pView
->GetTextEditObject());
1507 pOutliner
= pView
->GetTextEditOutliner();
1508 EditView
& rEditView3
= pView
->GetTextEditOutlinerView()->GetEditView();
1509 rEditView3
.SetSelection(ESelection(2, 0, 2, 33)); // start para, start char, end para, end char.
1510 CPPUNIT_ASSERT_EQUAL(OUString("They have all the same formatting"), rEditView3
.GetSelected());
1511 CPPUNIT_ASSERT_EQUAL(OUString("No-Logo Content~LT~Gliederung 2"),
1512 pOutliner
->GetStyleSheet(2)->GetName());
1514 const EditTextObject
& aEdit2
= pTextObject
->GetOutlinerParaObject()->GetTextObject();
1515 const SvxNumBulletItem
* pNumFmt2
= aEdit2
.GetParaAttribs(2).GetItem(EE_PARA_NUMBULLET
);
1516 SvxNumberFormat
aNumFmt2(pNumFmt2
->GetNumRule().GetLevel(2));
1518 bool bEqual(aNumFmt2
== aNumFmt
);
1519 CPPUNIT_ASSERT_MESSAGE("Bullet properties changed after paste", bEqual
);
1523 * tests a clone-formatting bug around table cell attributes
1525 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testTdf104405
)
1527 // Load the document.
1528 SdXImpressDocument
* pXImpressDocument
= createDoc("tdf104405.fodp");
1529 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
1530 SdPage
* pActualPage
= pViewShell
->GetActualPage();
1531 SdrObject
* pObject
= pActualPage
->GetObj(2);
1532 auto pTableObject
= dynamic_cast<sdr::table::SdrTableObj
*>(pObject
);
1533 CPPUNIT_ASSERT(pTableObject
);
1535 // select the middle cell
1536 SdrView
* pView
= pViewShell
->GetView();
1537 pView
->MarkObj(pTableObject
, pView
->GetSdrPageView());
1538 pTableObject
->setActiveCell(sdr::table::CellPos(2,1));
1539 pView
->SdrBeginTextEdit(pTableObject
);
1540 EditView
& rEditView
= pView
->GetTextEditOutlinerView()->GetEditView();
1541 rEditView
.SetSelection(ESelection(0, 0, 0, 3)); // start para, start char, end para, end char.
1543 // trigger the clone-formatting/paintbrush command to copy formatting contents of cell
1544 uno::Sequence aArgs
{ comphelper::makePropertyValue("PersistentCopy", true) };
1545 dispatchCommand(mxComponent
, ".uno:FormatPaintbrush", aArgs
);
1547 // now click on the table
1548 pView
->MarkObj(pTableObject
, pView
->GetSdrPageView());
1549 pTableObject
->setActiveCell(sdr::table::CellPos(0,0));
1550 pView
->SdrEndTextEdit(false);
1551 pView
->SdrBeginTextEdit(pTableObject
);
1552 EditView
& rEditView2
= pView
->GetTextEditOutlinerView()->GetEditView();
1553 rEditView2
.SetSelection(ESelection(0, 0, 0, 3)); // start para, start char, end para, end char.
1554 ::tools::Rectangle aRect
= pTableObject
->GetCurrentBoundRect();
1555 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1556 o3tl::toTwips(aRect
.Left(), o3tl::Length::mm100
), o3tl::toTwips(aRect
.Top(), o3tl::Length::mm100
),
1558 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
,
1559 o3tl::toTwips(aRect
.Left(), o3tl::Length::mm100
), o3tl::toTwips(aRect
.Top(), o3tl::Length::mm100
),
1562 Scheduler::ProcessEventsToIdle();
1564 // check that the first cell has acquired the resulting vertical style
1565 xmlDocUniquePtr pXmlDoc
= parseXmlDump();
1566 // the following name has a compiler-dependent part
1567 CPPUNIT_ASSERT_EQUAL(
1571 "/SdDrawDocument/SdrModel/maPages/SdPage/SdrPage/SdrObjList/SdrTableObj/SdrTableObjImpl"
1572 "/TableModel/Cell[1]/DefaultProperties/SfxItemSet/SdrTextVertAdjustItem",
1576 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testTdf81754
)
1578 SdXImpressDocument
* pXImpressDocument
= createDoc("tdf81754.pptx");
1579 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
1580 SdPage
* pActualPage
= pViewShell
->GetActualPage();
1581 SdrObject
* pObject
= pActualPage
->GetObj(1);
1583 SdrTextObj
* pTextObj
= static_cast<SdrTextObj
*>(pObject
);
1584 SdrView
* pView
= pViewShell
->GetView();
1585 pView
->MarkObj(pTextObj
, pView
->GetSdrPageView());
1586 SfxStringItem
aInputString(SID_ATTR_CHAR
, "x");
1587 pViewShell
->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR
,
1588 SfxCallMode::SYNCHRON
, { &aInputString
});
1590 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'x', 0);
1591 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'x', 0);
1592 Scheduler::ProcessEventsToIdle();
1594 // now save, reload, and assert that we did not lose the edit
1595 saveAndReload("Impress Office Open XML");
1597 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
1598 uno::Reference
<drawing::XDrawPage
> xPage(xDrawPagesSupplier
->getDrawPages()->getByIndex(0),
1600 uno::Reference
<text::XTextRange
> xShape(xPage
->getByIndex(1), uno::UNO_QUERY
);
1601 CPPUNIT_ASSERT_EQUAL(OUString(u
"Somethingxx"), xShape
->getString());
1604 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testTdf105502
)
1606 // Load the document.
1607 SdXImpressDocument
* pXImpressDocument
= createDoc("tdf105502.odp");
1608 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
1609 sd::Window
* pWindow
= pViewShell
->GetActiveWindow();
1610 CPPUNIT_ASSERT(pWindow
);
1611 SdPage
* pActualPage
= pViewShell
->GetActualPage();
1612 SdrObject
* pObject
= pActualPage
->GetObj(0);
1613 auto pTableObject
= dynamic_cast<sdr::table::SdrTableObj
*>(pObject
);
1614 CPPUNIT_ASSERT(pTableObject
);
1616 // Select the first row.
1617 sd::View
* pView
= pViewShell
->GetView();
1618 pView
->MarkObj(pObject
, pView
->GetSdrPageView());
1619 pView
->SdrBeginTextEdit(pObject
);
1620 rtl::Reference
<sdr::SelectionController
> xSelectionController(pView
->getSelectionController());
1621 CPPUNIT_ASSERT(xSelectionController
.is());
1622 SfxRequest
aRequest(*pViewShell
->GetViewFrame(), SID_TABLE_SELECT_ROW
);
1623 xSelectionController
->Execute(aRequest
);
1625 // Assert that the A1:B1 selection succeeded.
1626 CPPUNIT_ASSERT(xSelectionController
->hasSelectedCells());
1627 sdr::table::CellPos aFirstCell
;
1628 sdr::table::CellPos aLastCell
;
1629 xSelectionController
->getSelectedCells(aFirstCell
, aLastCell
);
1630 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(0), aFirstCell
.mnCol
);
1631 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(0), aFirstCell
.mnRow
);
1632 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aLastCell
.mnCol
);
1633 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(0), aLastCell
.mnRow
);
1635 // Grow font size for the selection.
1636 dispatchCommand(mxComponent
, ".uno:Grow", {});
1638 // Assert that the selected A1 has now a larger font than the unselected
1640 xmlDocUniquePtr pXmlDoc
= parseXmlDump();
1641 sal_Int32 nA1Height
= getXPath(pXmlDoc
, "//Cell[1]/SdrText/OutlinerParaObject/EditTextObject/ContentInfo/SfxItemSet/SvxFontHeightItem[1]", "height").toInt32();
1642 sal_Int32 nA2Height
= getXPath(pXmlDoc
, "//Cell[3]/SdrText/OutlinerParaObject/EditTextObject/ContentInfo/attribs[1]/SvxFontHeightItem", "height").toInt32();
1643 // This failed when FuText::ChangeFontSize() never did "continue" in the
1644 // text loop, instead of doing so depending on what IsInSelection() returns.
1645 CPPUNIT_ASSERT(nA1Height
> nA2Height
);
1647 // Check that selection remains the same
1648 CPPUNIT_ASSERT(xSelectionController
->hasSelectedCells());
1649 xSelectionController
->getSelectedCells(aFirstCell
, aLastCell
);
1650 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(0), aFirstCell
.mnCol
);
1651 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(0), aFirstCell
.mnRow
);
1652 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aLastCell
.mnCol
);
1653 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(0), aLastCell
.mnRow
);
1656 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testCommentCallbacks
)
1658 // Load the document.
1659 // Set the tiled annotations off
1660 comphelper::LibreOfficeKit::setTiledAnnotations(false);
1662 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp", comphelper::InitPropertySequence(
1664 {".uno:Author", uno::Any(OUString("LOK User1"))},
1666 ViewCallback aView1
;
1667 int nView1
= SfxLokHelper::getView();
1669 SfxLokHelper::createView();
1670 uno::Sequence
<beans::PropertyValue
> aArgs(comphelper::InitPropertySequence(
1672 {".uno:Author", uno::Any(OUString("LOK User2"))},
1674 pXImpressDocument
->initializeForTiledRendering(aArgs
);
1675 ViewCallback aView2
;
1676 int nView2
= SfxLokHelper::getView();
1678 SfxLokHelper::setView(nView1
);
1680 // Add a new comment
1681 aArgs
= comphelper::InitPropertySequence(
1683 {"Text", uno::Any(OUString("Comment"))},
1685 dispatchCommand(mxComponent
, ".uno:InsertAnnotation", aArgs
);
1687 // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action
1688 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1689 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1690 int nComment1
= aView1
.m_aCommentCallbackResult
.get
<int>("id");
1691 CPPUNIT_ASSERT_EQUAL(nComment1
, aView2
.m_aCommentCallbackResult
.get
<int>("id"));
1692 css::util::DateTime aDateTime
;
1693 OUString aDateTimeString
= OUString::createFromAscii(aView1
.m_aCommentCallbackResult
.get
<std::string
>("dateTime"));
1694 CPPUNIT_ASSERT(utl::ISO8601parseDateTime(aDateTimeString
, aDateTime
));
1695 CPPUNIT_ASSERT_EQUAL(std::string("LOK User1"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("author"));
1696 CPPUNIT_ASSERT_EQUAL(std::string("LOK User1"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("author"));
1697 CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1698 CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1699 CPPUNIT_ASSERT(!aView1
.m_aCommentCallbackResult
.get
<std::string
>("parthash").empty());
1700 CPPUNIT_ASSERT(!aView2
.m_aCommentCallbackResult
.get
<std::string
>("parthash").empty());
1702 // Reply to a just added comment
1703 SfxLokHelper::setView(nView2
);
1704 aArgs
= comphelper::InitPropertySequence(
1706 {"Id", uno::Any(OUString::number(nComment1
))},
1707 {"Text", uno::Any(OUString("Reply to comment"))},
1709 dispatchCommand(mxComponent
, ".uno:ReplyToAnnotation", aArgs
);
1711 // We received a LOK_CALLBACK_COMMENT callback with comment 'Modify' action
1712 CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1713 CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1714 CPPUNIT_ASSERT_EQUAL(nComment1
, aView1
.m_aCommentCallbackResult
.get
<int>("id"));
1715 CPPUNIT_ASSERT_EQUAL(nComment1
, aView2
.m_aCommentCallbackResult
.get
<int>("id"));
1716 CPPUNIT_ASSERT_EQUAL(std::string("LOK User2"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("author"));
1717 CPPUNIT_ASSERT_EQUAL(std::string("LOK User2"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("author"));
1718 OUString aReplyTextView1
= OUString::createFromAscii(aView1
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1719 OUString aReplyTextView2
= OUString::createFromAscii(aView2
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1720 CPPUNIT_ASSERT(aReplyTextView1
.startsWith("Reply to LOK User1"));
1721 CPPUNIT_ASSERT(aReplyTextView1
.endsWith("Reply to comment"));
1722 CPPUNIT_ASSERT(aReplyTextView2
.startsWith("Reply to LOK User1"));
1723 CPPUNIT_ASSERT(aReplyTextView2
.endsWith("Reply to comment"));
1724 CPPUNIT_ASSERT(!aView1
.m_aCommentCallbackResult
.get
<std::string
>("parthash").empty());
1725 CPPUNIT_ASSERT(!aView2
.m_aCommentCallbackResult
.get
<std::string
>("parthash").empty());
1727 // Edit this annotation now
1728 aArgs
= comphelper::InitPropertySequence(
1730 {"Id", uno::Any(OUString::number(nComment1
))},
1731 {"Text", uno::Any(OUString("Edited comment"))},
1733 dispatchCommand(mxComponent
, ".uno:EditAnnotation", aArgs
);
1735 // We received a LOK_CALLBACK_COMMENT callback with comment 'Modify' action
1736 CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1737 CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1738 CPPUNIT_ASSERT_EQUAL(nComment1
, aView1
.m_aCommentCallbackResult
.get
<int>("id"));
1739 CPPUNIT_ASSERT_EQUAL(nComment1
, aView2
.m_aCommentCallbackResult
.get
<int>("id"));
1740 CPPUNIT_ASSERT(!aView1
.m_aCommentCallbackResult
.get
<std::string
>("parthash").empty());
1741 CPPUNIT_ASSERT(!aView2
.m_aCommentCallbackResult
.get
<std::string
>("parthash").empty());
1742 CPPUNIT_ASSERT_EQUAL(std::string("Edited comment"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1743 CPPUNIT_ASSERT_EQUAL(std::string("Edited comment"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1745 // Delete the comment
1746 aArgs
= comphelper::InitPropertySequence(
1748 {"Id", uno::Any(OUString::number(nComment1
))},
1750 dispatchCommand(mxComponent
, ".uno:DeleteAnnotation", aArgs
);
1752 // We received a LOK_CALLBACK_COMMENT callback with comment 'Remove' action
1753 CPPUNIT_ASSERT_EQUAL(std::string("Remove"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1754 CPPUNIT_ASSERT_EQUAL(std::string("Remove"), aView2
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1755 CPPUNIT_ASSERT_EQUAL(nComment1
, aView1
.m_aCommentCallbackResult
.get
<int>("id"));
1756 CPPUNIT_ASSERT_EQUAL(nComment1
, aView2
.m_aCommentCallbackResult
.get
<int>("id"));
1758 comphelper::LibreOfficeKit::setTiledAnnotations(true);
1761 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testCommentChangeImpress
)
1763 uno::Sequence
<beans::PropertyValue
> aArgs
;
1765 // Load the document.
1766 // Set the tiled annotations off
1767 comphelper::LibreOfficeKit::setTiledAnnotations(false);
1769 createDoc("dummy.odp", comphelper::InitPropertySequence(
1771 {".uno:Author", uno::Any(OUString("LOK User1"))},
1774 ViewCallback aView1
;
1776 // Add a new comment
1777 aArgs
= comphelper::InitPropertySequence(
1779 {"Text", uno::Any(OUString("Comment"))},
1781 dispatchCommand(mxComponent
, ".uno:InsertAnnotation", aArgs
);
1783 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1785 int nComment1
= aView1
.m_aCommentCallbackResult
.get
<int>("id");
1787 CPPUNIT_ASSERT(!aView1
.m_aCommentCallbackResult
.get
<std::string
>("parthash").empty());
1788 CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1789 CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 0, 0"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("rectangle"));
1791 // Edit this annotation now
1792 aArgs
= comphelper::InitPropertySequence(
1794 {"Id", uno::Any(OUString::number(nComment1
))},
1795 {"PositionX", uno::Any(sal_Int32(10))},
1796 {"PositionY", uno::Any(sal_Int32(20))}
1798 dispatchCommand(mxComponent
, ".uno:EditAnnotation", aArgs
);
1800 CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1801 CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1802 CPPUNIT_ASSERT_EQUAL(std::string("10, 20, 0, 0"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("rectangle"));
1804 comphelper::LibreOfficeKit::setTiledAnnotations(true);
1807 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testCommentChangeDraw
)
1809 uno::Sequence
<beans::PropertyValue
> aArgs
;
1811 // Load the document.
1812 // Set the tiled annotations off
1813 comphelper::LibreOfficeKit::setTiledAnnotations(false);
1815 createDoc("dummy.odg", comphelper::InitPropertySequence(
1817 {".uno:Author", uno::Any(OUString("LOK User1"))},
1820 ViewCallback aView1
;
1822 // Add a new comment
1823 aArgs
= comphelper::InitPropertySequence(
1825 {"Text", uno::Any(OUString("Comment"))},
1827 dispatchCommand(mxComponent
, ".uno:InsertAnnotation", aArgs
);
1829 CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1831 int nComment1
= aView1
.m_aCommentCallbackResult
.get
<int>("id");
1833 CPPUNIT_ASSERT(!aView1
.m_aCommentCallbackResult
.get
<std::string
>("parthash").empty());
1834 CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1835 CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 0, 0"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("rectangle"));
1837 // Edit this annotation now
1838 aArgs
= comphelper::InitPropertySequence(
1840 {"Id", uno::Any(OUString::number(nComment1
))},
1841 {"PositionX", uno::Any(sal_Int32(10))},
1842 {"PositionY", uno::Any(sal_Int32(20))}
1844 dispatchCommand(mxComponent
, ".uno:EditAnnotation", aArgs
);
1846 CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("action"));
1847 CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("text"));
1848 CPPUNIT_ASSERT_EQUAL(std::string("10, 20, 0, 0"), aView1
.m_aCommentCallbackResult
.get
<std::string
>("rectangle"));
1850 comphelper::LibreOfficeKit::setTiledAnnotations(true);
1853 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testMultiViewInsertDeletePage
)
1855 // Load the document.
1856 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
1857 ViewCallback aView1
;
1858 int nView1
= SfxLokHelper::getView();
1859 uno::Sequence
<beans::PropertyValue
> aArgs
;
1860 SdDrawDocument
* pDoc
= pXImpressDocument
->GetDocShell()->GetDoc();
1862 // Create second view
1863 SfxLokHelper::createView();
1864 pXImpressDocument
->initializeForTiledRendering(aArgs
);
1865 ViewCallback aView2
;
1866 int nView2
= SfxLokHelper::getView();
1868 // the document has 8 slides
1869 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(8), pDoc
->GetSdPageCount(PageKind::Standard
));
1871 // Switch to 5th page in 2nd view
1872 pXImpressDocument
->setPart(4);
1874 // Insert slide in 1st view
1875 SfxLokHelper::setView(nView1
);
1876 dispatchCommand(mxComponent
, ".uno:InsertPage", aArgs
);
1878 // See if the current slide number changed in 2nd view too
1879 SfxLokHelper::setView(nView2
);
1880 CPPUNIT_ASSERT_EQUAL(5, pXImpressDocument
->getPart());
1882 // Delete the page in 1st view now
1883 SfxLokHelper::setView(nView1
);
1884 dispatchCommand(mxComponent
, ".uno:DeletePage", aArgs
);
1886 // See if current slide number changed in 2nd view too
1887 SfxLokHelper::setView(nView2
);
1888 CPPUNIT_ASSERT_EQUAL(4, pXImpressDocument
->getPart());
1891 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testMultiViewInsertDeletePage2
)
1893 // Load the document.
1894 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
1895 ViewCallback aView1
;
1896 int nView1
= SfxLokHelper::getView();
1897 uno::Sequence
<beans::PropertyValue
> aArgs
;
1898 SdDrawDocument
* pDoc
= pXImpressDocument
->GetDocShell()->GetDoc();
1900 // Create second view
1901 SfxLokHelper::createView();
1902 pXImpressDocument
->initializeForTiledRendering(aArgs
);
1903 ViewCallback aView2
;
1904 int nView2
= SfxLokHelper::getView();
1906 // the document has 8 slides
1907 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(8), pDoc
->GetSdPageCount(PageKind::Standard
));
1909 // Switch to 5th page in 2nd view
1910 pXImpressDocument
->setPart(4);
1912 // Begin text edit on the only object on the slide.
1913 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
1914 SdPage
* pActualPage
= pViewShell
->GetActualPage();
1915 SdrObject
* pObject1
= pActualPage
->GetObj(0);
1916 CPPUNIT_ASSERT(pObject1
!= nullptr);
1917 CPPUNIT_ASSERT_EQUAL(SdrObjKind::TitleText
, pObject1
->GetObjIdentifier());
1918 SdrTextObj
* pTextObject
= static_cast<SdrTextObj
*>(pObject1
);
1920 // Double-click outside the text to enter edit mode.
1921 const ::tools::Rectangle aRect
= pTextObject
->GetCurrentBoundRect();
1922 const auto cornerX
= o3tl::toTwips(aRect
.Left() + (aRect
.getOpenWidth() / 4), o3tl::Length::mm100
);
1923 const auto cornerY
= o3tl::toTwips(aRect
.Top() + (aRect
.getOpenHeight() / 4), o3tl::Length::mm100
);
1924 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN
,
1927 pXImpressDocument
->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP
,
1930 Scheduler::ProcessEventsToIdle();
1932 // We must be in text editing mode and have cursor visible.
1933 CPPUNIT_ASSERT(pViewShell
->GetView()->IsTextEdit());
1935 // Insert slide in 1st view
1936 SfxLokHelper::setView(nView1
);
1937 dispatchCommand(mxComponent
, ".uno:InsertPage", aArgs
);
1939 // See if the current slide number changed in 2nd view too
1940 SfxLokHelper::setView(nView2
);
1941 CPPUNIT_ASSERT_EQUAL(5, pXImpressDocument
->getPart());
1943 // Delete the page in 1st view now
1944 SfxLokHelper::setView(nView1
);
1945 dispatchCommand(mxComponent
, ".uno:DeletePage", aArgs
);
1947 // See if current slide number changed in 2nd view too
1948 SfxLokHelper::setView(nView2
);
1949 CPPUNIT_ASSERT_EQUAL(4, pXImpressDocument
->getPart());
1951 // We must be still in text editing mode and have cursor visible.
1952 CPPUNIT_ASSERT(pViewShell
->GetView()->IsTextEdit());
1955 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testDisableUndoRepair
)
1957 // Load the document.
1958 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
1961 SfxViewShell
* pView1
= SfxViewShell::Current();
1962 sd::ViewShell
* pViewShell1
= pXImpressDocument
->GetDocShell()->GetViewShell();
1963 int nView1
= SfxLokHelper::getView();
1966 SfxLokHelper::createView();
1967 SfxViewShell
* pView2
= SfxViewShell::Current();
1968 sd::ViewShell
* pViewShell2
= pXImpressDocument
->GetDocShell()->GetViewShell();
1969 int nView2
= SfxLokHelper::getView();
1971 // Check UNDO is disabled
1973 std::unique_ptr
<SfxPoolItem
> pItem1
;
1974 std::unique_ptr
<SfxPoolItem
> pItem2
;
1975 CPPUNIT_ASSERT_EQUAL(SfxItemState::DISABLED
, pView1
->GetViewFrame().GetBindings().QueryState(SID_UNDO
, pItem1
));
1976 CPPUNIT_ASSERT_EQUAL(SfxItemState::DISABLED
, pView2
->GetViewFrame().GetBindings().QueryState(SID_UNDO
, pItem2
));
1979 // Insert a character in the first view.
1980 SfxLokHelper::setView(nView1
);
1981 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::TAB
);
1982 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::TAB
);
1983 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'h', 0);
1984 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'h', 0);
1985 Scheduler::ProcessEventsToIdle();
1986 CPPUNIT_ASSERT(pViewShell1
->GetView()->IsTextEdit());
1987 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::ESCAPE
);
1988 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::ESCAPE
);
1989 Scheduler::ProcessEventsToIdle();
1990 CPPUNIT_ASSERT(!pViewShell1
->GetView()->IsTextEdit());
1994 std::unique_ptr
<SfxPoolItem
> xItem1
;
1995 pView1
->GetViewFrame().GetBindings().QueryState(SID_UNDO
, xItem1
);
1996 const auto* pUInt32Item1
= dynamic_cast<const SfxUInt32Item
*>(xItem1
.get());
1997 CPPUNIT_ASSERT(!pUInt32Item1
);
1999 std::unique_ptr
<SfxPoolItem
> xItem2
;
2000 pView2
->GetViewFrame().GetBindings().QueryState(SID_UNDO
, xItem2
);
2001 const auto* pUInt32Item2
= dynamic_cast<const SfxUInt32Item
*>(xItem2
.get());
2002 CPPUNIT_ASSERT(pUInt32Item2
);
2003 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32
>(SID_REPAIRPACKAGE
), pUInt32Item2
->GetValue());
2006 // Insert a character in the second view.
2007 SfxLokHelper::setView(nView2
);
2008 pXImpressDocument
->setPart(1);
2009 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::TAB
);
2010 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::TAB
);
2011 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'c', 0);
2012 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'c', 0);
2013 Scheduler::ProcessEventsToIdle();
2014 CPPUNIT_ASSERT(pViewShell2
->GetView()->IsTextEdit());
2015 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::ESCAPE
);
2016 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::ESCAPE
);
2017 Scheduler::ProcessEventsToIdle();
2018 CPPUNIT_ASSERT(!pViewShell2
->GetView()->IsTextEdit());
2022 std::unique_ptr
<SfxPoolItem
> xItem1
;
2023 pView1
->GetViewFrame().GetBindings().QueryState(SID_UNDO
, xItem1
);
2024 const SfxUInt32Item
* pUInt32Item
= dynamic_cast<const SfxUInt32Item
*>(xItem1
.get());
2025 CPPUNIT_ASSERT(pUInt32Item
);
2026 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32
>(SID_REPAIRPACKAGE
), pUInt32Item
->GetValue());
2028 std::unique_ptr
<SfxPoolItem
> xItem2
;
2029 pView2
->GetViewFrame().GetBindings().QueryState(SID_UNDO
, xItem2
);
2030 CPPUNIT_ASSERT(!dynamic_cast< const SfxUInt32Item
* >(xItem2
.get()));
2034 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testDocumentRepair
)
2036 // Create two views.
2037 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
2038 CPPUNIT_ASSERT(pXImpressDocument
);
2041 SfxViewShell
* pView1
= SfxViewShell::Current();
2044 SfxLokHelper::createView();
2045 SfxViewShell
* pView2
= SfxViewShell::Current();
2046 int nView2
= SfxLokHelper::getView();
2047 sd::ViewShell
* pViewShell2
= pXImpressDocument
->GetDocShell()->GetViewShell();
2049 CPPUNIT_ASSERT(pView1
!= pView2
);
2051 std::unique_ptr
<SfxBoolItem
> pItem1
;
2052 pView1
->GetViewFrame().GetBindings().QueryState(SID_DOC_REPAIR
, pItem1
);
2053 CPPUNIT_ASSERT(pItem1
);
2054 CPPUNIT_ASSERT_EQUAL(false, pItem1
->GetValue());
2056 std::unique_ptr
<SfxBoolItem
> pItem2
;
2057 pView2
->GetViewFrame().GetBindings().QueryState(SID_DOC_REPAIR
, pItem2
);
2058 CPPUNIT_ASSERT(pItem2
);
2059 CPPUNIT_ASSERT_EQUAL(false, pItem2
->GetValue());
2062 // Insert a character in the second view.
2063 SfxLokHelper::setView(nView2
);
2064 pXImpressDocument
->setPart(1);
2065 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::TAB
);
2066 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::TAB
);
2067 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 'c', 0);
2068 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 'c', 0);
2069 Scheduler::ProcessEventsToIdle();
2070 CPPUNIT_ASSERT(pViewShell2
->GetView()->IsTextEdit());
2071 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::ESCAPE
);
2072 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::ESCAPE
);
2073 Scheduler::ProcessEventsToIdle();
2074 CPPUNIT_ASSERT(!pViewShell2
->GetView()->IsTextEdit());
2077 std::unique_ptr
<SfxBoolItem
> pItem1
;
2078 pView1
->GetViewFrame().GetBindings().QueryState(SID_DOC_REPAIR
, pItem1
);
2079 CPPUNIT_ASSERT(pItem1
);
2080 CPPUNIT_ASSERT_EQUAL(true, pItem1
->GetValue());
2082 std::unique_ptr
<SfxBoolItem
> pItem2
;
2083 pView2
->GetViewFrame().GetBindings().QueryState(SID_DOC_REPAIR
, pItem2
);
2084 CPPUNIT_ASSERT(pItem2
);
2085 CPPUNIT_ASSERT_EQUAL(true, pItem2
->GetValue());
2089 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testLanguageStatus
)
2091 // Load the document.
2092 createDoc("dummy.odp");
2093 SfxViewShell
* pView1
= SfxViewShell::Current();
2094 SfxLokHelper::createView();
2095 SfxViewShell
* pView2
= SfxViewShell::Current();
2097 std::unique_ptr
<SfxPoolItem
> xItem1
;
2098 std::unique_ptr
<SfxPoolItem
> xItem2
;
2099 pView1
->GetViewFrame().GetBindings().QueryState(SID_LANGUAGE_STATUS
, xItem1
);
2100 pView2
->GetViewFrame().GetBindings().QueryState(SID_LANGUAGE_STATUS
, xItem2
);
2101 auto pStringItem
= dynamic_cast<const SfxStringItem
*>(xItem1
.get());
2102 CPPUNIT_ASSERT(pStringItem
);
2104 CPPUNIT_ASSERT_EQUAL(OUString("English (USA);en-US"), pStringItem
->GetValue());
2106 CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem
* >(xItem2
.get()));
2110 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testLanguageAllText
)
2112 // Load the document, which has a single shape, with Hungarian text.
2113 createDoc("language-all-text.odp");
2115 // Set the language to English for all text.
2116 uno::Sequence
<beans::PropertyValue
> aArgs
= comphelper::InitPropertySequence({
2117 { "Language", uno::Any(OUString("Default_English (USA)")) },
2119 dispatchCommand(mxComponent
, ".uno:LanguageStatus", aArgs
);
2121 // Assert that the shape text language was changed.
2122 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
2123 uno::Reference
<drawing::XDrawPage
> xPage(xDrawPagesSupplier
->getDrawPages()->getByIndex(0),
2125 uno::Reference
<text::XTextRange
> xShape(xPage
->getByIndex(0), uno::UNO_QUERY
);
2126 uno::Reference
<beans::XPropertySet
> xRun(xShape
, uno::UNO_QUERY_THROW
);
2127 lang::Locale aLocale
;
2128 xRun
->getPropertyValue("CharLocale") >>= aLocale
;
2129 // Without the accompanying fix in place, this test would have failed with 'Expected: en;
2130 // Actual: hu', as the shape text language was not set.
2131 CPPUNIT_ASSERT_EQUAL(OUString("en"), aLocale
.Language
);
2134 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testDefaultView
)
2136 // Load the document with notes view.
2137 SdXImpressDocument
* pXImpressDocument
= createDoc("notes-view.odp");
2138 sd::ViewShell
* pView
= pXImpressDocument
->GetDocShell()->GetViewShell();
2140 std::unique_ptr
<SfxBoolItem
> pImpressView
;
2141 std::unique_ptr
<SfxBoolItem
> pNotesView
;
2142 pView
->GetViewFrame()->GetBindings().QueryState(SID_NORMAL_MULTI_PANE_GUI
, pImpressView
);
2143 pView
->GetViewFrame()->GetBindings().QueryState(SID_NOTES_MODE
, pNotesView
);
2144 CPPUNIT_ASSERT(pImpressView
);
2145 CPPUNIT_ASSERT(pNotesView
);
2146 CPPUNIT_ASSERT_EQUAL(true, pImpressView
->GetValue());
2147 CPPUNIT_ASSERT_EQUAL(false, pNotesView
->GetValue());
2151 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testIMESupport
)
2153 // Load the document with notes view.
2154 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
2155 VclPtr
<vcl::Window
> pDocWindow
= pXImpressDocument
->getDocWindow();
2156 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
2157 SdrObject
* pObject
= pViewShell
->GetActualPage()->GetObj(0);
2158 SdrTextObj
* pTextObj
= static_cast<SdrTextObj
*>(pObject
);
2159 SdrView
* pView
= pViewShell
->GetView();
2160 pView
->MarkObj(pTextObj
, pView
->GetSdrPageView());
2161 SfxStringItem
aInputString(SID_ATTR_CHAR
, "x");
2162 pViewShell
->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR
,
2163 SfxCallMode::SYNCHRON
, { &aInputString
});
2165 // sequence of chinese IME compositions when 'nihao' is typed in an IME
2166 const std::vector
<OString
> aUtf8Inputs
{ "å¹´", "ä½ ", "ä½ å¥½", "ä½ å“ˆ", "ä½ å¥½", "ä½ å¥½" };
2167 std::vector
<OUString
> aInputs
;
2168 std::transform(aUtf8Inputs
.begin(), aUtf8Inputs
.end(),
2169 std::back_inserter(aInputs
), [](OString aInput
) {
2170 return OUString::fromUtf8(aInput
);
2172 for (const auto& aInput
: aInputs
)
2174 pDocWindow
->PostExtTextInputEvent(VclEventId::ExtTextInput
, aInput
);
2176 pDocWindow
->PostExtTextInputEvent(VclEventId::EndExtTextInput
, "");
2178 // the cursor should be at position 3rd
2179 EditView
& rEditView
= pView
->GetTextEditOutlinerView()->GetEditView();
2180 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(3), rEditView
.GetSelection().nStartPos
);
2182 ESelection
aWordSelection(0, 0, 0, 3); // start para, start char, end para, end char.
2183 rEditView
.SetSelection(aWordSelection
);
2184 // content contains only the last IME composition, not all
2185 CPPUNIT_ASSERT_EQUAL(OUString("x" + aInputs
[aInputs
.size() - 1]), rEditView
.GetSelected());
2188 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testTdf115783
)
2190 // Load the document.
2191 SdXImpressDocument
* pXImpressDocument
= createDoc("tdf115783.fodp");
2192 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
2193 SdPage
* pActualPage
= pViewShell
->GetActualPage();
2194 SdrObject
* pObject
= pActualPage
->GetObj(0);
2195 auto pTableObject
= dynamic_cast<sdr::table::SdrTableObj
*>(pObject
);
2196 CPPUNIT_ASSERT(pTableObject
);
2197 SdrView
* pView
= pViewShell
->GetView();
2198 pView
->MarkObj(pTableObject
, pView
->GetSdrPageView());
2200 // Create a cell selection and set font height.
2201 // Go to the end of the B1 cell.
2202 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_LEFT
);
2203 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_LEFT
);
2204 // Create a B1->C1 cell selection.
2205 const int nShiftRight
= KEY_SHIFT
+ KEY_RIGHT
;
2206 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, nShiftRight
);
2207 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, nShiftRight
);
2208 uno::Sequence
<beans::PropertyValue
> aArgs
= comphelper::InitPropertySequence({
2209 { "FontHeight.Height", uno::Any(static_cast<float>(12)) },
2211 dispatchCommand(mxComponent
, ".uno:FontHeight", aArgs
);
2213 // Create a text selection on the B1 cell.
2214 pTableObject
->setActiveCell(sdr::table::CellPos(1, 0));
2215 pView
->SdrBeginTextEdit(pTableObject
);
2216 EditView
& rEditView
= pView
->GetTextEditOutlinerView()->GetEditView();
2217 // Start para, start char, end para, end char.
2218 rEditView
.SetSelection(ESelection(0, 0, 0, 5));
2219 CPPUNIT_ASSERT_EQUAL(OUString("hello"), rEditView
.GetSelected());
2221 // Copy selection, paste at the start of the cell.
2223 dispatchCommand(mxComponent
, ".uno:Copy", aArgs
);
2224 rEditView
.SetSelection(ESelection(0, 0, 0, 0));
2226 dispatchCommand(mxComponent
, ".uno:Paste", aArgs
);
2227 pView
->SdrEndTextEdit();
2229 // And now verify that the cell has the correct font size.
2230 uno::Reference
<table::XCellRange
> xTable
= pTableObject
->getTable();
2231 CPPUNIT_ASSERT(xTable
.is());
2232 uno::Reference
<text::XTextRange
> xCell(xTable
->getCellByPosition(1, 0), uno::UNO_QUERY
);
2233 CPPUNIT_ASSERT(xCell
.is());
2234 uno::Reference
<container::XEnumerationAccess
> xText(xCell
->getText(), uno::UNO_QUERY
);
2235 CPPUNIT_ASSERT(xText
.is());
2236 uno::Reference
<container::XEnumerationAccess
> xParagraph(
2237 xText
->createEnumeration()->nextElement(), uno::UNO_QUERY
);
2238 CPPUNIT_ASSERT(xParagraph
.is());
2239 uno::Reference
<text::XTextRange
> xPortion(xParagraph
->createEnumeration()->nextElement(),
2241 CPPUNIT_ASSERT(xPortion
.is());
2242 // This failed, it was only "hello" as the paragraph had 2 portions: a
2243 // "hello" with 12pt size and a "hello" with 18pt.
2244 CPPUNIT_ASSERT_EQUAL(OUString("hellohello"), xPortion
->getString());
2245 uno::Reference
<beans::XPropertySet
> xPropertySet(xPortion
, uno::UNO_QUERY
);
2246 int nHeight
= xPropertySet
->getPropertyValue("CharHeight").get
<float>();
2247 // Make sure that the single font size for the cell is the expected one.
2248 CPPUNIT_ASSERT_EQUAL(12, nHeight
);
2251 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testPasteTextOnSlide
)
2253 // Load the document.
2254 SdXImpressDocument
* pXImpressDocument
= createDoc("paste_text_onslide.odp");
2255 CPPUNIT_ASSERT(pXImpressDocument
);
2257 // select second text object
2258 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::TAB
);
2259 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::TAB
);
2260 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::TAB
);
2261 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::TAB
);
2262 Scheduler::ProcessEventsToIdle();
2264 // step into text editing
2265 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, '1', 0);
2266 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, '1', 0);
2267 Scheduler::ProcessEventsToIdle();
2270 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_LEFT
| KEY_SHIFT
);
2271 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_LEFT
| KEY_SHIFT
);
2272 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_LEFT
| KEY_SHIFT
);
2273 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_LEFT
| KEY_SHIFT
);
2274 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_LEFT
| KEY_SHIFT
);
2275 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_LEFT
| KEY_SHIFT
);
2276 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_LEFT
| KEY_SHIFT
);
2277 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_LEFT
| KEY_SHIFT
);
2278 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_LEFT
| KEY_SHIFT
);
2279 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_LEFT
| KEY_SHIFT
);
2280 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_LEFT
| KEY_SHIFT
);
2281 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_LEFT
| KEY_SHIFT
);
2282 Scheduler::ProcessEventsToIdle();
2285 dispatchCommand(mxComponent
, ".uno:Copy", uno::Sequence
<beans::PropertyValue
>());
2287 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::ESCAPE
);
2288 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::ESCAPE
);
2289 Scheduler::ProcessEventsToIdle();
2291 // Paste onto the slide
2292 dispatchCommand(mxComponent
, ".uno:Paste", uno::Sequence
<beans::PropertyValue
>());
2294 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::ESCAPE
);
2295 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::ESCAPE
);
2296 Scheduler::ProcessEventsToIdle();
2298 // Check the position of the newly added text shape, created for pasted text
2299 SdPage
* pActualPage
= pXImpressDocument
->GetDocShell()->GetViewShell()->GetActualPage();
2300 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pActualPage
->GetObjCount());
2301 SdrObject
* pObject
= pActualPage
->GetObj(2);
2302 CPPUNIT_ASSERT(pObject
);
2303 SdrTextObj
* pTextObj
= DynCastSdrTextObj(pObject
);
2304 CPPUNIT_ASSERT(pTextObj
);
2305 CPPUNIT_ASSERT_EQUAL(SdrObjKind::Text
, pTextObj
->GetObjIdentifier());
2306 const Point aPos
= pTextObj
->GetLastBoundRect().TopLeft();
2307 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long
>(0), aPos
.getX());
2308 CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long
>(0), aPos
.getY());
2311 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testTdf115873
)
2313 // Initialize the navigator.
2314 SdXImpressDocument
* pXImpressDocument
= createDoc("tdf115873.fodp");
2315 SfxViewShell
* pViewShell
= SfxViewShell::Current();
2316 CPPUNIT_ASSERT(pViewShell
);
2317 SfxBindings
& rBindings
= pViewShell
->GetViewFrame().GetBindings();
2318 auto xNavigator
= std::make_unique
<SdNavigatorWin
>(nullptr, &rBindings
, nullptr);
2319 xNavigator
->InitTreeLB(pXImpressDocument
->GetDoc());
2320 SdPageObjsTLV
& rObjects
= xNavigator
->GetObjects();
2321 rObjects
.SelectEntry(u
"Slide 1");
2323 sd::ViewShell
* pSdViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
2324 SdrView
* pSdrView
= pSdViewShell
->GetView();
2325 pSdrView
->UnmarkAllObj(pSdrView
->GetSdrPageView());
2327 // Make sure that no shapes are selected.
2328 const SdrMarkList
& rMarkList
= pSdrView
->GetMarkedObjectList();
2329 Scheduler::ProcessEventsToIdle();
2330 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rMarkList
.GetMarkCount());
2332 // Single-click with the mouse.
2333 MouseEvent
aMouseEvent(Point(0, 0), /*nClicks=*/1, MouseEventModifiers::NONE
, MOUSE_LEFT
);
2334 rObjects
.MousePressHdl(aMouseEvent
);
2335 rObjects
.SelectEntry(u
"Rectangle");
2337 rObjects
.MouseReleaseHdl(aMouseEvent
);
2338 Scheduler::ProcessEventsToIdle();
2339 // This failed, single-click did not result in a shape selection (only
2340 // double-click did).
2341 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rMarkList
.GetMarkCount());
2344 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testTdf115873Group
)
2346 // Initialize the navigator.
2347 SdXImpressDocument
* pXImpressDocument
= createDoc("tdf115873-group.fodp");
2348 SfxViewShell
* pViewShell
= SfxViewShell::Current();
2349 CPPUNIT_ASSERT(pViewShell
);
2350 SfxBindings
& rBindings
= pViewShell
->GetViewFrame().GetBindings();
2351 auto xNavigator
= std::make_unique
<SdNavigatorWin
>(nullptr, &rBindings
, nullptr);
2352 xNavigator
->InitTreeLB(pXImpressDocument
->GetDoc());
2353 SdPageObjsTLV
& rObjects
= xNavigator
->GetObjects();
2354 // This failed, Fill() and IsEqualToDoc() were out of sync for group
2356 CPPUNIT_ASSERT(rObjects
.IsEqualToDoc(pXImpressDocument
->GetDoc()));
2359 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testCutSelectionChange
)
2361 // Load the document.
2362 SdXImpressDocument
* pXImpressDocument
= createDoc("cut_selection_change.odp");
2363 CPPUNIT_ASSERT(pXImpressDocument
);
2365 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
2366 setupLibreOfficeKitViewCallback(pViewShell
->GetViewShellBase());
2367 Scheduler::ProcessEventsToIdle();
2369 // Select first text object
2370 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::TAB
);
2371 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::TAB
);
2372 Scheduler::ProcessEventsToIdle();
2374 // step into text editing
2375 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, '1', 0);
2376 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, '1', 0);
2377 Scheduler::ProcessEventsToIdle();
2380 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_LEFT
| KEY_SHIFT
);
2381 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_LEFT
| KEY_SHIFT
);
2382 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_LEFT
| KEY_SHIFT
);
2383 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_LEFT
| KEY_SHIFT
);
2384 Scheduler::ProcessEventsToIdle();
2386 // Check that we have a selection before cutting
2387 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), m_aSelection
.size());
2389 // Cut the selected text
2390 dispatchCommand(mxComponent
, ".uno:Cut", uno::Sequence
<beans::PropertyValue
>());
2392 // Selection is removed
2393 CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), m_aSelection
.size());
2396 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testGetViewRenderState
)
2398 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
2399 int nFirstViewId
= SfxLokHelper::getView();
2400 ViewCallback aView1
;
2401 CPPUNIT_ASSERT_EQUAL(OString(";Default"), pXImpressDocument
->getViewRenderState());
2402 // Create a second view
2403 SfxLokHelper::createView();
2404 ViewCallback aView2
;
2405 CPPUNIT_ASSERT_EQUAL(OString(";Default"), pXImpressDocument
->getViewRenderState());
2406 // Set to dark scheme
2408 uno::Sequence
<beans::PropertyValue
> aPropertyValues
= comphelper::InitPropertySequence(
2410 { "NewTheme", uno::Any(OUString("Dark")) },
2413 dispatchCommand(mxComponent
, ".uno:ChangeTheme", aPropertyValues
);
2415 CPPUNIT_ASSERT_EQUAL(OString(";Dark"), pXImpressDocument
->getViewRenderState());
2416 // Switch back to the first view, and check that the options string is the same
2417 SfxLokHelper::setView(nFirstViewId
);
2418 CPPUNIT_ASSERT_EQUAL(OString(";Default"), pXImpressDocument
->getViewRenderState());
2421 // Helper function to get a tile to a bitmap and check the pixel color
2422 static void assertTilePixelColor(SdXImpressDocument
* pXImpressDocument
, int nPixelX
, int nPixelY
, Color aColor
)
2424 size_t nCanvasSize
= 1024;
2425 size_t nTileSize
= 256;
2426 std::vector
<unsigned char> aPixmap(nCanvasSize
* nCanvasSize
* 4, 0);
2427 ScopedVclPtrInstance
<VirtualDevice
> pDevice(DeviceFormat::WITHOUT_ALPHA
);
2428 pDevice
->SetBackground(Wallpaper(COL_TRANSPARENT
));
2429 pDevice
->SetOutputSizePixelScaleOffsetAndLOKBuffer(Size(nCanvasSize
, nCanvasSize
),
2430 Fraction(1.0), Point(), aPixmap
.data());
2431 pXImpressDocument
->paintTile(*pDevice
, nCanvasSize
, nCanvasSize
, 0, 0, 15360, 7680);
2432 pDevice
->EnableMapMode(false);
2433 Bitmap aBitmap
= pDevice
->GetBitmap(Point(0, 0), Size(nTileSize
, nTileSize
));
2434 Bitmap::ScopedReadAccess
pAccess(aBitmap
);
2435 Color
aActualColor(pAccess
->GetPixel(nPixelX
, nPixelY
));
2436 CPPUNIT_ASSERT_EQUAL(aColor
, aActualColor
);
2439 // Test that changing the theme in one view doesn't change it in the other view
2440 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testThemeViewSeparation
)
2442 Color
aDarkColor(0x1c, 0x1c, 0x1c);
2443 // Add a minimal dark scheme
2445 svtools::EditableColorConfig aColorConfig
;
2446 svtools::ColorConfigValue aValue
;
2447 aValue
.bIsVisible
= true;
2448 aValue
.nColor
= aDarkColor
;
2449 aColorConfig
.SetColorValue(svtools::DOCCOLOR
, aValue
);
2450 aColorConfig
.AddScheme(u
"Dark");
2452 // Add a minimal light scheme
2454 svtools::EditableColorConfig aColorConfig
;
2455 svtools::ColorConfigValue aValue
;
2456 aValue
.bIsVisible
= true;
2457 aValue
.nColor
= COL_WHITE
;
2458 aColorConfig
.SetColorValue(svtools::DOCCOLOR
, aValue
);
2459 aColorConfig
.AddScheme(u
"Light");
2461 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
2462 int nFirstViewId
= SfxLokHelper::getView();
2463 ViewCallback aView1
;
2464 // Switch first view to light scheme
2466 uno::Sequence
<beans::PropertyValue
> aPropertyValues
= comphelper::InitPropertySequence(
2468 { "NewTheme", uno::Any(OUString("Light")) },
2471 dispatchCommand(mxComponent
, ".uno:ChangeTheme", aPropertyValues
);
2473 // First view is at light scheme
2474 assertTilePixelColor(pXImpressDocument
, 255, 255, COL_WHITE
);
2475 // Create second view
2476 SfxLokHelper::createView();
2477 int nSecondViewId
= SfxLokHelper::getView();
2478 ViewCallback aView2
;
2479 // Set second view to dark scheme
2481 uno::Sequence
<beans::PropertyValue
> aPropertyValues
= comphelper::InitPropertySequence(
2483 { "NewTheme", uno::Any(OUString("Dark")) },
2486 dispatchCommand(mxComponent
, ".uno:ChangeTheme", aPropertyValues
);
2488 assertTilePixelColor(pXImpressDocument
, 255, 255, aDarkColor
);
2489 // First view still in light scheme
2490 SfxLokHelper::setView(nFirstViewId
);
2491 assertTilePixelColor(pXImpressDocument
, 255, 255, COL_WHITE
);
2492 // Second view still in dark scheme
2493 SfxLokHelper::setView(nSecondViewId
);
2494 assertTilePixelColor(pXImpressDocument
, 255, 255, Color(0x1c, 0x1c, 0x1c));
2495 // Switch second view back to light scheme
2497 uno::Sequence
<beans::PropertyValue
> aPropertyValues
= comphelper::InitPropertySequence(
2499 { "NewTheme", uno::Any(OUString("Light")) },
2502 dispatchCommand(mxComponent
, ".uno:ChangeTheme", aPropertyValues
);
2504 // Now in light scheme
2505 assertTilePixelColor(pXImpressDocument
, 255, 255, COL_WHITE
);
2508 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testRegenerateDiagram
)
2510 // Load the document.
2511 SdXImpressDocument
* pXImpressDocument
= createDoc("regenerate-diagram.pptx");
2512 CPPUNIT_ASSERT(pXImpressDocument
);
2514 SdPage
* pActualPage
= pXImpressDocument
->GetDocShell()->GetViewShell()->GetActualPage();
2515 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), pActualPage
->GetObj(0)->GetSubList()->GetObjCount());
2517 // For new Diagram functionality entering group using UI is not allowed as long
2518 // as the group shape is a diagram. Do the same as before done by triggering UI
2519 // events directly in the model
2520 // Remove and free top-left entry (Box showing "A")
2521 pActualPage
->GetObj(0)->GetSubList()->RemoveObject(1);
2524 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, awt::Key::TAB
);
2525 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, awt::Key::TAB
);
2526 Scheduler::ProcessEventsToIdle();
2528 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pActualPage
->GetObj(0)->GetSubList()->GetObjCount());
2530 // regenerate diagram
2531 dispatchCommand(mxComponent
, ".uno:RegenerateDiagram", uno::Sequence
<beans::PropertyValue
>());
2533 // diagram content (child shape count) should be the same as in the beginning
2534 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), pActualPage
->GetObj(0)->GetSubList()->GetObjCount());
2537 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testInsertDeletePageInvalidation
)
2539 // Load the document.
2540 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
2541 ViewCallback aView1
;
2542 CPPUNIT_ASSERT_EQUAL(8, pXImpressDocument
->getParts());
2545 aView1
.m_bTilesInvalidated
= false;
2546 aView1
.m_aInvalidations
.clear();
2547 dispatchCommand(mxComponent
, ".uno:InsertPage", uno::Sequence
<beans::PropertyValue
>());
2548 CPPUNIT_ASSERT(aView1
.m_bTilesInvalidated
);
2549 CPPUNIT_ASSERT_EQUAL(9, pXImpressDocument
->getParts());
2550 CPPUNIT_ASSERT_EQUAL(size_t(9), aView1
.m_aInvalidations
.size());
2553 aView1
.m_bTilesInvalidated
= false;
2554 aView1
.m_aInvalidations
.clear();
2555 dispatchCommand(mxComponent
, ".uno:DeletePage", uno::Sequence
<beans::PropertyValue
>());
2556 CPPUNIT_ASSERT(aView1
.m_bTilesInvalidated
);
2557 CPPUNIT_ASSERT_EQUAL(8, pXImpressDocument
->getParts());
2558 CPPUNIT_ASSERT_EQUAL(size_t(8), aView1
.m_aInvalidations
.size());
2561 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testSpellOnlineRenderParameter
)
2563 // Load the document.
2564 SdXImpressDocument
* pXImpressDocument
= createDoc("dummy.odp");
2565 bool bSet
= pXImpressDocument
->GetDoc()->GetOnlineSpell();
2567 uno::Sequence
<beans::PropertyValue
> aPropertyValues
=
2569 comphelper::InitPropertySequence({ { ".uno:SpellOnline", uno::Any(!bSet
) } }),
2571 pXImpressDocument
->initializeForTiledRendering(aPropertyValues
);
2572 CPPUNIT_ASSERT_EQUAL(!bSet
, pXImpressDocument
->GetDoc()->GetOnlineSpell());
2575 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testSlideDuplicateUndo
)
2577 // Create two views.
2578 SdXImpressDocument
* pXImpressDocument
= createDoc("duplicate-undo.odp");
2579 int nView0
= SfxLokHelper::getView();
2580 SfxLokHelper::createView();
2581 pXImpressDocument
->initializeForTiledRendering({});
2582 int nView1
= SfxLokHelper::getView();
2583 SfxLokHelper::setView(nView0
);
2585 // Switch to the 3rd slide on view 0, and start text editing.
2587 pXImpressDocument
->setPart(2);
2588 sd::ViewShell
* pViewShell0
= pXImpressDocument
->GetDocShell()->GetViewShell();
2589 SdrView
* pView
= pViewShell0
->GetView();
2590 SdPage
* pActualPage
= pViewShell0
->GetActualPage();
2591 SdrObject
* pObject
= pActualPage
->GetObj(1);
2592 SdrTextObj
* pTextObj
= static_cast<SdrTextObj
*>(pObject
);
2593 pView
->MarkObj(pTextObj
, pView
->GetSdrPageView());
2594 SfxStringItem
aInputString(SID_ATTR_CHAR
, "x");
2595 pViewShell0
->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR
,
2596 SfxCallMode::SYNCHRON
, { &aInputString
});
2597 CPPUNIT_ASSERT(pView
->IsTextEdit());
2598 CPPUNIT_ASSERT(pView
->GetTextEditPageView());
2601 // Duplicate the first slide on view 1 and undo it.
2602 SfxLokHelper::setView(nView1
);
2603 dispatchCommand(mxComponent
, ".uno:DuplicatePage", {});
2604 pXImpressDocument
->setPart(0, /*bAllowChangeFocus=*/false);
2605 pXImpressDocument
->setPart(1, /*bAllowChangeFocus=*/false);
2606 SfxLokHelper::setView(nView0
);
2607 pXImpressDocument
->setPart(0, /*bAllowChangeFocus=*/false);
2608 pXImpressDocument
->setPart(3, /*bAllowChangeFocus=*/false);
2609 SfxLokHelper::setView(nView1
);
2610 pXImpressDocument
->getUndoManager()->undo();
2611 // Without the accompanying fix in place, this would have tried to access the outdated page view
2612 // pointer, potentially leading to a crash.
2613 pXImpressDocument
->setPart(2, /*bAllowChangeFocus=*/false);
2615 // Make sure that view 0 now doesn't have an outdated page view pointer.
2616 SfxLokHelper::setView(nView0
);
2617 sd::ViewShell
* pViewShell0
= pXImpressDocument
->GetDocShell()->GetViewShell();
2618 SdrView
* pView0
= pViewShell0
->GetView();
2619 CPPUNIT_ASSERT(!pView0
->GetTextEditPageView());
2625 void lcl_extractHandleParameters(std::string_view selection
, sal_uInt32
& id
, sal_uInt32
& x
, sal_uInt32
& y
)
2627 OString
extraInfo( selection
.substr(selection
.find("{")) );
2628 std::stringstream
aStream((std::string(extraInfo
)));
2629 boost::property_tree::ptree aTree
;
2630 boost::property_tree::read_json(aStream
, aTree
);
2631 boost::property_tree::ptree
2633 .get_child("handles")
2635 .get_child("rectangle")
2638 id
= handle0
.get_child("id").get_value
<int>();
2639 x
= handle0
.get_child("point").get_child("x").get_value
<int>();
2640 y
= handle0
.get_child("point").get_child("y").get_value
<int>();
2645 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testMoveShapeHandle
)
2647 SdXImpressDocument
* pXImpressDocument
= createDoc("shape.odp");
2648 ViewCallback aView1
;
2649 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
2650 SdPage
* pPage
= pViewShell
->GetActualPage();
2651 SdrObject
* pObject
= pPage
->GetObj(0);
2652 SdrView
* pView
= pViewShell
->GetView();
2653 pView
->MarkObj(pObject
, pView
->GetSdrPageView());
2654 Scheduler::ProcessEventsToIdle();
2656 CPPUNIT_ASSERT(!aView1
.m_ShapeSelection
.isEmpty());
2658 sal_uInt32 id
, x
, y
;
2659 lcl_extractHandleParameters(aView1
.m_ShapeSelection
, id
, x
,y
);
2660 sal_uInt32 oldX
= x
;
2661 sal_uInt32 oldY
= y
;
2662 uno::Sequence
<beans::PropertyValue
> aPropertyValues(comphelper::InitPropertySequence(
2664 {"HandleNum", uno::Any(id
)},
2665 {"NewPosX", uno::Any(x
+1)},
2666 {"NewPosY", uno::Any(y
+1)}
2668 dispatchCommand(mxComponent
, ".uno:MoveShapeHandle", aPropertyValues
);
2669 CPPUNIT_ASSERT(!aView1
.m_ShapeSelection
.isEmpty());
2670 lcl_extractHandleParameters(aView1
.m_ShapeSelection
, id
, x
,y
);
2671 CPPUNIT_ASSERT_EQUAL(x
-1, oldX
);
2672 CPPUNIT_ASSERT_EQUAL(y
-1, oldY
);
2676 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testPasteUndo
)
2678 // Given a document with a textbox, containing "world":
2679 SdXImpressDocument
* pXImpressDocument
= createDoc("paste-undo.fodp");
2680 sd::ViewShell
* pViewShell
= pXImpressDocument
->GetDocShell()->GetViewShell();
2681 SdPage
* pActualPage
= pViewShell
->GetActualPage();
2682 SdrObject
* pObject
= pActualPage
->GetObj(0);
2683 SdrView
* pView
= pViewShell
->GetView();
2684 pView
->MarkObj(pObject
, pView
->GetSdrPageView());
2685 pView
->SdrBeginTextEdit(pObject
);
2686 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYINPUT
, 0, KEY_HOME
);
2687 pXImpressDocument
->postKeyEvent(LOK_KEYEVENT_KEYUP
, 0, KEY_HOME
);
2688 EditView
& rEditView
= pView
->GetTextEditOutlinerView()->GetEditView();
2689 ESelection
aWordSelection(0, 0, 0, 1); // "w" of "world"
2690 rEditView
.SetSelection(aWordSelection
);
2691 dispatchCommand(mxComponent
, ".uno:Cut", {});
2693 // When undoing a paste:
2694 dispatchCommand(mxComponent
, ".uno:Paste", {});
2695 dispatchCommand(mxComponent
, ".uno:Undo", {});
2697 // Then make sure the cursor position is still at the beginning:
2698 ESelection aSelection
= rEditView
.GetSelection();
2699 // Without the accompanying fix in place, this test would have failed with:
2702 // i.e. the cursor position after undo was at the end of the line, not at the start, as
2704 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(0), aSelection
.nStartPos
);
2707 CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest
, testShapeEditInMultipleViews
)
2709 SdXImpressDocument
* pXImpressDocument
= createDoc("TextBoxAndRect.odg");
2710 pXImpressDocument
->initializeForTiledRendering(uno::Sequence
<beans::PropertyValue
>());
2711 SdDrawDocument
* pDocument
= pXImpressDocument
->GetDoc();
2714 const int nView1
= SfxLokHelper::getView();
2715 sd::ViewShell
* pViewShell1
= pXImpressDocument
->GetDocShell()->GetViewShell();
2716 SdrView
* pView1
= pViewShell1
->GetView();
2717 Scheduler::ProcessEventsToIdle();
2720 SfxLokHelper::createView();
2721 const int nView2
= SfxLokHelper::getView();
2722 CPPUNIT_ASSERT(nView1
!= nView2
);
2724 sd::ViewShell
* pViewShell2
= pXImpressDocument
->GetDocShell()->GetViewShell();
2725 SdrView
* pView2
= pViewShell2
->GetView();
2726 Scheduler::ProcessEventsToIdle();
2729 SfxLokHelper::setView(nView1
);
2731 SdPage
* pPage1
= pViewShell1
->GetActualPage();
2733 SdrObject
* pTextBoxObject
= pPage1
->GetObj(0);
2734 CPPUNIT_ASSERT_EQUAL(OUString("Text Box"), pTextBoxObject
->GetName());
2736 SdrObject
* pRectangleObject
= pPage1
->GetObj(1);
2737 CPPUNIT_ASSERT_EQUAL(OUString("Rect"), pRectangleObject
->GetName());
2739 SdrObject
* pTableObject
= pPage1
->GetObj(2);
2740 CPPUNIT_ASSERT_EQUAL(OUString("Table1"), pTableObject
->GetName());
2743 // 2 shapes - "Text Box" and "Rect"
2744 // View1 - "Text Box" enters text edit mode, View 2 - moves the "Rect" around
2746 sd::UndoManager
* pUndoManager
= pDocument
->GetUndoManager();
2747 CPPUNIT_ASSERT_EQUAL(size_t(0), pUndoManager
->GetUndoActionCount());
2749 pView1
->SdrBeginTextEdit(pTextBoxObject
);
2750 CPPUNIT_ASSERT_EQUAL(true, pView1
->IsTextEdit());
2751 CPPUNIT_ASSERT_EQUAL(false, pView2
->IsTextEdit());
2753 // Local undo count for View1 is 0
2754 CPPUNIT_ASSERT_EQUAL(size_t(0), pView1
->getViewLocalUndoManager()->GetUndoActionCount());
2755 // Write 'test' in View1
2756 SfxStringItem
aInputString(SID_ATTR_CHAR
, "test");
2757 pViewShell1
->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR
, SfxCallMode::SYNCHRON
, { &aInputString
});
2758 // Local undo count for View1 is now 1
2759 CPPUNIT_ASSERT_EQUAL(size_t(1), pView1
->getViewLocalUndoManager()->GetUndoActionCount());
2761 // Mark rectangle object
2762 pView2
->MarkObj(pRectangleObject
, pView2
->GetSdrPageView());
2764 // Check the initial position of the object
2765 tools::Rectangle aRectangle
= pRectangleObject
->GetLogicRect();
2766 CPPUNIT_ASSERT_EQUAL(6250L, aRectangle
.TopLeft().X());
2767 CPPUNIT_ASSERT_EQUAL(7000L, aRectangle
.TopLeft().Y());
2768 CPPUNIT_ASSERT_EQUAL(6501L, aRectangle
.GetWidth());
2769 CPPUNIT_ASSERT_EQUAL(4501L, aRectangle
.GetHeight());
2771 // On View2 - Move handle 0 on the shape to a new position - resize
2772 Point aNewPosition
= aRectangle
.TopLeft() + Point(-1250, -1000);
2773 pView2
->MoveShapeHandle(0, aNewPosition
, -1);
2774 Scheduler::ProcessEventsToIdle();
2775 CPPUNIT_ASSERT_EQUAL(size_t(1), pUndoManager
->GetUndoActionCount());
2777 // Check the object has a new size
2778 aRectangle
= pRectangleObject
->GetLogicRect();
2779 CPPUNIT_ASSERT_EQUAL(5000L, aRectangle
.TopLeft().X());
2780 CPPUNIT_ASSERT_EQUAL(6000L, aRectangle
.TopLeft().Y());
2781 CPPUNIT_ASSERT_EQUAL(7751L, aRectangle
.GetWidth());
2782 CPPUNIT_ASSERT_EQUAL(5501L, aRectangle
.GetHeight());
2784 // View1 is still in text edit mode...
2785 CPPUNIT_ASSERT_EQUAL(true, pView1
->IsTextEdit());
2786 CPPUNIT_ASSERT_EQUAL(false, pView2
->IsTextEdit());
2788 // On View2 - relative move the shape to a different position
2789 pView2
->MoveMarkedObj(Size(1000, 2000), /*bCopy=*/false);
2790 Scheduler::ProcessEventsToIdle();
2791 CPPUNIT_ASSERT_EQUAL(size_t(2), pUndoManager
->GetUndoActionCount());
2793 // Check the object is at a different position
2794 aRectangle
= pRectangleObject
->GetLogicRect();
2795 CPPUNIT_ASSERT_EQUAL(6000L, aRectangle
.TopLeft().X());
2796 CPPUNIT_ASSERT_EQUAL(8000L, aRectangle
.TopLeft().Y());
2797 CPPUNIT_ASSERT_EQUAL(7751L, aRectangle
.GetWidth());
2798 CPPUNIT_ASSERT_EQUAL(5501L, aRectangle
.GetHeight());
2800 // View1 is still in text edit mode...
2801 CPPUNIT_ASSERT_EQUAL(true, pView1
->IsTextEdit());
2802 CPPUNIT_ASSERT_EQUAL(false, pView2
->IsTextEdit());
2804 // End Text edit - check undo count increase from 2 -> 3
2805 CPPUNIT_ASSERT_EQUAL(size_t(2), pUndoManager
->GetUndoActionCount());
2806 pView1
->SdrEndTextEdit();
2807 Scheduler::ProcessEventsToIdle();
2808 CPPUNIT_ASSERT_EQUAL(size_t(3), pUndoManager
->GetUndoActionCount());
2810 // Check that both views exited the text edit mode
2811 CPPUNIT_ASSERT_EQUAL(false, pView1
->IsTextEdit());
2812 CPPUNIT_ASSERT_EQUAL(false, pView2
->IsTextEdit());
2816 // 1 shapes - "Text Box"
2817 // View1 - "Text Box" enters text edit mode, View 2 - moves the "Text Box" around
2819 sd::UndoManager
* pUndoManager
= pDocument
->GetUndoManager();
2820 CPPUNIT_ASSERT_EQUAL(size_t(3), pUndoManager
->GetUndoActionCount());
2822 pView1
->SdrBeginTextEdit(pTextBoxObject
);
2823 CPPUNIT_ASSERT_EQUAL(true, pView1
->IsTextEdit());
2824 CPPUNIT_ASSERT_EQUAL(false, pView2
->IsTextEdit());
2826 // Local undo count for View1 is 0
2827 CPPUNIT_ASSERT_EQUAL(size_t(0), pView1
->getViewLocalUndoManager()->GetUndoActionCount());
2828 // Write 'test' in View1
2829 SfxStringItem
aInputString(SID_ATTR_CHAR
, "test");
2830 pViewShell1
->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR
, SfxCallMode::SYNCHRON
, { &aInputString
});
2831 // Local undo count for View1 is now 1
2832 CPPUNIT_ASSERT_EQUAL(size_t(1), pView1
->getViewLocalUndoManager()->GetUndoActionCount());
2834 // Mark rectangle object
2835 pView2
->MarkObj(pTextBoxObject
, pView2
->GetSdrPageView());
2837 // Check the initial position of the object
2838 tools::Rectangle aRectangle
= pTextBoxObject
->GetLogicRect();
2839 CPPUNIT_ASSERT_EQUAL(2250L, aRectangle
.TopLeft().X());
2840 CPPUNIT_ASSERT_EQUAL(2000L, aRectangle
.TopLeft().Y());
2841 CPPUNIT_ASSERT_EQUAL(4501L, aRectangle
.GetWidth());
2842 CPPUNIT_ASSERT_EQUAL(2001L, aRectangle
.GetHeight());
2844 // On View2 - Move handle 0 on the shape to a new position - resize
2845 Point aNewPosition
= aRectangle
.TopLeft() + Point(-1250, -1000);
2846 pView2
->MoveShapeHandle(0, aNewPosition
, -1);
2847 Scheduler::ProcessEventsToIdle();
2848 CPPUNIT_ASSERT_EQUAL(size_t(4), pUndoManager
->GetUndoActionCount());
2850 // Check the object has a new size
2851 aRectangle
= pTextBoxObject
->GetLogicRect();
2852 CPPUNIT_ASSERT_EQUAL(1000L, aRectangle
.TopLeft().X());
2853 CPPUNIT_ASSERT_EQUAL(1000L, aRectangle
.TopLeft().Y());
2854 CPPUNIT_ASSERT_EQUAL(4990L, aRectangle
.GetWidth());
2855 CPPUNIT_ASSERT_EQUAL(2175L, aRectangle
.GetHeight());
2857 // View1 is still in text edit mode...
2858 CPPUNIT_ASSERT_EQUAL(true, pView1
->IsTextEdit());
2859 CPPUNIT_ASSERT_EQUAL(false, pView2
->IsTextEdit());
2861 // On View2 - relative move the shape to a different position
2862 pView2
->MoveMarkedObj(Size(1000, 2000), /*bCopy=*/false);
2863 Scheduler::ProcessEventsToIdle();
2864 CPPUNIT_ASSERT_EQUAL(size_t(5), pUndoManager
->GetUndoActionCount());
2866 // Check the object is at a different position
2867 aRectangle
= pTextBoxObject
->GetLogicRect();
2868 CPPUNIT_ASSERT_EQUAL(2000L, aRectangle
.TopLeft().X());
2869 CPPUNIT_ASSERT_EQUAL(3000L, aRectangle
.TopLeft().Y());
2870 CPPUNIT_ASSERT_EQUAL(4990L, aRectangle
.GetWidth());
2871 CPPUNIT_ASSERT_EQUAL(2175L, aRectangle
.GetHeight());
2873 // View1 is still in text edit mode...
2874 CPPUNIT_ASSERT_EQUAL(true, pView1
->IsTextEdit());
2875 CPPUNIT_ASSERT_EQUAL(false, pView2
->IsTextEdit());
2877 // End Text edit - check undo count increase from 5 -> 6
2878 CPPUNIT_ASSERT_EQUAL(size_t(5), pUndoManager
->GetUndoActionCount());
2879 pView1
->SdrEndTextEdit();
2880 Scheduler::ProcessEventsToIdle();
2881 CPPUNIT_ASSERT_EQUAL(size_t(6), pUndoManager
->GetUndoActionCount());
2883 // Check that both views exited the text edit mode
2884 CPPUNIT_ASSERT_EQUAL(false, pView1
->IsTextEdit());
2885 CPPUNIT_ASSERT_EQUAL(false, pView2
->IsTextEdit());
2889 // 1 shapes - "Table1"
2890 // View1 - "Table1" enters text edit mode, View 2 - moves the "Table1" around
2892 sd::UndoManager
* pUndoManager
= pDocument
->GetUndoManager();
2893 CPPUNIT_ASSERT_EQUAL(size_t(6), pUndoManager
->GetUndoActionCount());
2895 pView1
->SdrBeginTextEdit(pTableObject
);
2896 CPPUNIT_ASSERT_EQUAL(true, pView1
->IsTextEdit());
2897 CPPUNIT_ASSERT_EQUAL(false, pView2
->IsTextEdit());
2899 // Local undo count for View1 is 0
2900 CPPUNIT_ASSERT_EQUAL(size_t(0), pView1
->getViewLocalUndoManager()->GetUndoActionCount());
2901 // Write 'test' in View1
2902 SfxStringItem
aInputString(SID_ATTR_CHAR
, "test");
2903 pViewShell1
->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR
, SfxCallMode::SYNCHRON
, { &aInputString
});
2904 // Local undo count for View1 is now 1
2905 CPPUNIT_ASSERT_EQUAL(size_t(1), pView1
->getViewLocalUndoManager()->GetUndoActionCount());
2907 // Mark rectangle object
2908 pView2
->MarkObj(pTableObject
, pView2
->GetSdrPageView());
2910 // Check the initial position of the table
2911 tools::Rectangle aRectangle
= pTableObject
->GetLogicRect();
2912 CPPUNIT_ASSERT_EQUAL(2919L, aRectangle
.TopLeft().X());
2913 CPPUNIT_ASSERT_EQUAL(18063L, aRectangle
.TopLeft().Y());
2914 CPPUNIT_ASSERT_EQUAL(14099L, aRectangle
.GetWidth());
2915 CPPUNIT_ASSERT_EQUAL(5999L, aRectangle
.GetHeight());
2917 // On View2 - relative move the shape to a different position
2918 pView2
->MoveMarkedObj(Size(1000, 2000), /*bCopy=*/false);
2919 Scheduler::ProcessEventsToIdle();
2920 CPPUNIT_ASSERT_EQUAL(size_t(7), pUndoManager
->GetUndoActionCount());
2922 // Check the object is at a different position
2923 aRectangle
= pTableObject
->GetLogicRect();
2924 CPPUNIT_ASSERT_EQUAL(3919L, aRectangle
.TopLeft().X());
2925 CPPUNIT_ASSERT_EQUAL(20063L, aRectangle
.TopLeft().Y());
2926 CPPUNIT_ASSERT_EQUAL(14099L, aRectangle
.GetWidth());
2927 CPPUNIT_ASSERT_EQUAL(5999L, aRectangle
.GetHeight());
2929 // View1 is still in text edit mode...
2930 CPPUNIT_ASSERT_EQUAL(true, pView1
->IsTextEdit());
2931 CPPUNIT_ASSERT_EQUAL(false, pView2
->IsTextEdit());
2933 // End Text edit - check undo count increase from 7 -> 8
2934 CPPUNIT_ASSERT_EQUAL(size_t(7), pUndoManager
->GetUndoActionCount());
2935 pView1
->SdrEndTextEdit();
2936 Scheduler::ProcessEventsToIdle();
2937 CPPUNIT_ASSERT_EQUAL(size_t(8), pUndoManager
->GetUndoActionCount());
2939 // Check that both views exited the text edit mode
2940 CPPUNIT_ASSERT_EQUAL(false, pView1
->IsTextEdit());
2941 CPPUNIT_ASSERT_EQUAL(false, pView2
->IsTextEdit());
2945 CPPUNIT_PLUGIN_IMPLEMENT();
2947 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */