diff options
Diffstat (limited to '')
34 files changed, 5952 insertions, 0 deletions
diff --git a/sd/qa/unit/tiledrendering/CallbackRecorder.hxx b/sd/qa/unit/tiledrendering/CallbackRecorder.hxx new file mode 100644 index 0000000000..ad64f5ab39 --- /dev/null +++ b/sd/qa/unit/tiledrendering/CallbackRecorder.hxx @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <cppunit/TestAssert.h> + +#include <LibreOfficeKit/LibreOfficeKitEnums.h> +#include <boost/property_tree/json_parser.hpp> +#include <comphelper/string.hxx> +#include <osl/conditn.hxx> +#include <sfx2/viewsh.hxx> +#include <test/lokcallback.hxx> +#include <o3tl/string_view.hxx> + +using namespace css; + +namespace +{ +std::vector<OUString> lcl_convertSeparated(std::u16string_view rString, sal_Unicode nSeparator) +{ + std::vector<OUString> aRet; + + sal_Int32 nIndex = 0; + do + { + OUString aToken(o3tl::trim(o3tl::getToken(rString, 0, nSeparator, nIndex))); + if (!aToken.isEmpty()) + aRet.push_back(aToken); + } while (nIndex >= 0); + + return aRet; +} + +void lcl_convertRectangle(std::u16string_view rString, tools::Rectangle& rRectangle) +{ + uno::Sequence<OUString> aSeq = comphelper::string::convertCommaSeparated(rString); + CPPUNIT_ASSERT(aSeq.getLength() == 4 || aSeq.getLength() == 5); + rRectangle.SetLeft(aSeq[0].toInt32()); + rRectangle.SetTop(aSeq[1].toInt32()); + rRectangle.setWidth(aSeq[2].toInt32()); + rRectangle.setHeight(aSeq[3].toInt32()); +} +} + +struct CallbackRecorder +{ + CallbackRecorder() + : m_bFound(true) + , m_nPart(0) + , m_nSelectionBeforeSearchResult(0) + , m_nSelectionAfterSearchResult(0) + , m_nSearchResultCount(0) + , m_callbackWrapper(&callback, this) + { + } + + tools::Rectangle m_aInvalidation; + std::vector<::tools::Rectangle> m_aSelection; + bool m_bFound; + sal_Int32 m_nPart; + std::vector<OString> m_aSearchResultSelection; + std::vector<int> m_aSearchResultPart; + int m_nSelectionBeforeSearchResult; + int m_nSelectionAfterSearchResult; + int m_nSearchResultCount; + /// For document size changed callback. + osl::Condition m_aDocumentSizeCondition; + TestLokCallbackWrapper m_callbackWrapper; + + static void callback(int nType, const char* pPayload, void* pData) + { + static_cast<CallbackRecorder*>(pData)->processCallback(nType, pPayload); + } + + void processCallback(int nType, const char* pPayload) + { + switch (nType) + { + case LOK_CALLBACK_INVALIDATE_TILES: + { + OUString aPayload = OUString::createFromAscii(pPayload); + if (aPayload != "EMPTY" && m_aInvalidation.IsEmpty()) + lcl_convertRectangle(aPayload, m_aInvalidation); + } + break; + case LOK_CALLBACK_TEXT_SELECTION: + { + OUString aPayload = OUString::createFromAscii(pPayload); + m_aSelection.clear(); + for (const OUString& rString : lcl_convertSeparated(aPayload, u';')) + { + ::tools::Rectangle aRectangle; + lcl_convertRectangle(rString, aRectangle); + m_aSelection.push_back(aRectangle); + } + if (m_aSearchResultSelection.empty()) + ++m_nSelectionBeforeSearchResult; + else + ++m_nSelectionAfterSearchResult; + } + break; + case LOK_CALLBACK_SEARCH_NOT_FOUND: + { + m_bFound = false; + } + break; + case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED: + { + m_aDocumentSizeCondition.set(); + } + break; + case LOK_CALLBACK_SET_PART: + { + OUString aPayload = OUString::createFromAscii(pPayload); + m_nPart = aPayload.toInt32(); + } + break; + case LOK_CALLBACK_SEARCH_RESULT_SELECTION: + { + m_nSearchResultCount++; + m_aSearchResultSelection.clear(); + m_aSearchResultPart.clear(); + boost::property_tree::ptree aTree; + std::stringstream aStream(pPayload); + boost::property_tree::read_json(aStream, aTree); + for (const boost::property_tree::ptree::value_type& rValue : + aTree.get_child("searchResultSelection")) + { + m_aSearchResultSelection.emplace_back( + rValue.second.get<std::string>("rectangles").c_str()); + m_aSearchResultPart.push_back( + std::atoi(rValue.second.get<std::string>("part").c_str())); + } + } + break; + } + } + + void registerCallbacksFor(SfxViewShell& rViewShell) + { + rViewShell.setLibreOfficeKitViewCallback(&m_callbackWrapper); + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx new file mode 100644 index 0000000000..35b32640b5 --- /dev/null +++ b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx @@ -0,0 +1,948 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "CallbackRecorder.hxx" +#include <test/unoapi_test.hxx> + +#include <test/helper/transferable.hxx> + +#include <comphelper/propertysequence.hxx> +#include <comphelper/lok.hxx> +#include <svl/srchitem.hxx> +#include <vcl/scheduler.hxx> +#include <ViewShellBase.hxx> +#include <ViewShell.hxx> +#include <unomodel.hxx> + +#include <DrawDocShell.hxx> +#include <drawdoc.hxx> +#include <sdpage.hxx> +#include <svx/svdograf.hxx> +#include <vcl/filter/PDFiumLibrary.hxx> + +using namespace css; + +class LOKitSearchTest : public UnoApiTest +{ +public: + LOKitSearchTest() + : UnoApiTest("/sd/qa/unit/tiledrendering/data/") + { + } + + virtual void setUp() override; + virtual void tearDown() override; + + void testSearch(); + void testSearchAll(); + void testSearchAllSelections(); + void testSearchAllNotifications(); + void testSearchAllFollowedBySearch(); + void testDontSearchInMasterPages(); + void testSearchInPDFNonExisting(); + void testSearchInPDF(); + void testSearchInPDFOnePDFObject(); + void testSearchInPDFInMultiplePages(); + void testSearchInPDFInMultiplePagesBackwards(); + void testSearchIn2MixedObjects(); + void testSearchIn6MixedObjects(); + void testReplace(); + void testReplaceAll(); + void testReplaceCombined(); + + CPPUNIT_TEST_SUITE(LOKitSearchTest); + CPPUNIT_TEST(testSearch); + CPPUNIT_TEST(testSearchAll); + CPPUNIT_TEST(testSearchAllSelections); + CPPUNIT_TEST(testSearchAllNotifications); + CPPUNIT_TEST(testSearchAllFollowedBySearch); + CPPUNIT_TEST(testDontSearchInMasterPages); + CPPUNIT_TEST(testSearchInPDFNonExisting); + CPPUNIT_TEST(testSearchInPDF); + CPPUNIT_TEST(testSearchInPDFOnePDFObject); + CPPUNIT_TEST(testSearchInPDFInMultiplePages); + CPPUNIT_TEST(testSearchInPDFInMultiplePagesBackwards); + CPPUNIT_TEST(testSearchIn2MixedObjects); + CPPUNIT_TEST(testSearchIn6MixedObjects); + CPPUNIT_TEST(testReplace); + CPPUNIT_TEST(testReplaceAll); + CPPUNIT_TEST(testReplaceCombined); + CPPUNIT_TEST_SUITE_END(); + +private: + SdXImpressDocument* createDoc(const char* pName, + const uno::Sequence<beans::PropertyValue>& rArguments + = uno::Sequence<beans::PropertyValue>()); + void lcl_search(const OUString& rKey, bool bFindAll = false, bool bBackwards = false); + void lcl_replace(const OUString& rKey, const OUString& rReplace, bool bAll = false); + + std::unique_ptr<CallbackRecorder> mpCallbackRecorder; +}; + +void LOKitSearchTest::setUp() +{ + UnoApiTest::setUp(); + + // prevent showing warning message box + setenv("OOX_NO_SMARTART_WARNING", "1", 1); + comphelper::LibreOfficeKit::setActive(true); + + mpCallbackRecorder = std::make_unique<CallbackRecorder>(); +} + +void LOKitSearchTest::tearDown() +{ + if (mxComponent.is()) + { + mxComponent->dispose(); + mxComponent.clear(); + } + + comphelper::LibreOfficeKit::setActive(false); + + UnoApiTest::tearDown(); +} + +SdXImpressDocument* +LOKitSearchTest::createDoc(const char* pName, const uno::Sequence<beans::PropertyValue>& rArguments) +{ + loadFromFile(OUString::createFromAscii(pName)); + SdXImpressDocument* pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get()); + CPPUNIT_ASSERT(pImpressDocument); + pImpressDocument->initializeForTiledRendering(rArguments); + return pImpressDocument; +} + +void LOKitSearchTest::lcl_search(const OUString& rKey, bool bFindAll, bool bBackwards) +{ + Scheduler::ProcessEventsToIdle(); + SvxSearchCmd eSearch = bFindAll ? SvxSearchCmd::FIND_ALL : SvxSearchCmd::FIND; + + uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence({ + { "SearchItem.SearchString", uno::Any(rKey) }, + { "SearchItem.Backward", uno::Any(bBackwards) }, + { "SearchItem.Command", uno::Any(sal_uInt16(eSearch)) }, + })); + + dispatchCommand(mxComponent, ".uno:ExecuteSearch", aPropertyValues); +} + +void LOKitSearchTest::lcl_replace(const OUString& rKey, const OUString& rReplace, bool bAll) +{ + Scheduler::ProcessEventsToIdle(); + + SvxSearchCmd eSearch = bAll ? SvxSearchCmd::REPLACE_ALL : SvxSearchCmd::REPLACE; + + uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence({ + { "SearchItem.SearchString", uno::Any(rKey) }, + { "SearchItem.ReplaceString", uno::Any(rReplace) }, + { "SearchItem.Command", uno::Any(sal_uInt16(eSearch)) }, + })); + + dispatchCommand(mxComponent, ".uno:ExecuteSearch", aPropertyValues); +} + +namespace +{ +SdrObject* lclGetSelectedObject(sd::ViewShell* pViewShell) +{ + SdrView* pSdrView = pViewShell->GetView(); + const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList(); + CPPUNIT_ASSERT_EQUAL(size_t(1), rMarkList.GetMarkCount()); + SdrObject* pObject = rMarkList.GetMark(0)->GetMarkedSdrObj(); + return pObject; +} + +} // end anonymous namespace + +void LOKitSearchTest::testSearch() +{ + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase()); + uno::Reference<container::XIndexAccess> xDrawPage( + pXImpressDocument->getDrawPages()->getByIndex(0), uno::UNO_QUERY); + uno::Reference<text::XTextRange> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + xShape->setString("Aaa bbb."); + + lcl_search("bbb"); + + SdrView* pView = pViewShell->GetView(); + EditView& rEditView = pView->GetTextEditOutlinerView()->GetEditView(); + // Did we indeed manage to select the second word? + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), rEditView.GetSelected()); + + // Did the selection callback fire? + CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), mpCallbackRecorder->m_aSelection.size()); + + // Search for something on the second slide, and make sure that the set-part callback fired. + lcl_search("bbb"); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), mpCallbackRecorder->m_nPart); + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + // This was 0; should be 1 match for "find". + CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), + mpCallbackRecorder->m_aSearchResultSelection.size()); + // Result is on the second slide. + CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_aSearchResultPart[0]); + + // This should trigger the not-found callback. + lcl_search("ccc"); + CPPUNIT_ASSERT_EQUAL(false, mpCallbackRecorder->m_bFound); +} + +void LOKitSearchTest::testSearchAll() +{ + SdXImpressDocument* pXImpressDocument = createDoc("search-all.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase()); + + lcl_search("match", /*bFindAll=*/true); + + // This was empty: find-all did not highlight the first match. + CPPUNIT_ASSERT_EQUAL("match"_ostr, + apitest::helper::transferable::getTextSelection( + pXImpressDocument->getSelection(), "text/plain;charset=utf-8"_ostr)); + + // We're on the first slide, search for something on the second slide and make sure we get a SET_PART. + mpCallbackRecorder->m_nPart = 0; + lcl_search("second", /*bFindAll=*/true); + // This was 0: no SET_PART was emitted. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), mpCallbackRecorder->m_nPart); +} + +void LOKitSearchTest::testSearchAllSelections() +{ + SdXImpressDocument* pXImpressDocument = createDoc("search-all.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase()); + + lcl_search("third", /*bFindAll=*/true); + // Make sure this is found on the 3rd slide. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), mpCallbackRecorder->m_nPart); + // This was 1: only the first match was highlighted. + CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), mpCallbackRecorder->m_aSelection.size()); +} + +void LOKitSearchTest::testSearchAllNotifications() +{ + SdXImpressDocument* pXImpressDocument = createDoc("search-all.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase()); + + lcl_search("third", /*bFindAll=*/true); + // Make sure that we get no notifications about selection changes during search. + CPPUNIT_ASSERT_EQUAL(0, mpCallbackRecorder->m_nSelectionBeforeSearchResult); + // But we do get the selection of the first hit. + CPPUNIT_ASSERT(mpCallbackRecorder->m_nSelectionAfterSearchResult > 0); +} + +void LOKitSearchTest::testSearchAllFollowedBySearch() +{ + SdXImpressDocument* pXImpressDocument = createDoc("search-all.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase()); + + lcl_search("third", /*bFindAll=*/true); + lcl_search("match" /*,bFindAll=false*/); + + // This used to give wrong result: 'search' after 'search all' still + // returned 'third' + CPPUNIT_ASSERT_EQUAL("match"_ostr, + apitest::helper::transferable::getTextSelection( + pXImpressDocument->getSelection(), "text/plain;charset=utf-8"_ostr)); +} + +void LOKitSearchTest::testDontSearchInMasterPages() +{ + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase()); + + // This should trigger the not-found callback ("date" is present only on + // the master page) + lcl_search("date"); + CPPUNIT_ASSERT_EQUAL(false, mpCallbackRecorder->m_bFound); +} + +void LOKitSearchTest::testSearchInPDFNonExisting() +{ + auto pPdfium = vcl::pdf::PDFiumLibrary::get(); + if (!pPdfium) + { + return; + } + + SdXImpressDocument* pXImpressDocument = createDoc("PDFSearch.pdf"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + CPPUNIT_ASSERT(pViewShell); + mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase()); + + SdPage* pPage = pViewShell->GetActualPage(); + CPPUNIT_ASSERT(pPage); + + SdrObject* pObject = pPage->GetObj(0); + CPPUNIT_ASSERT(pObject); + + SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject); + CPPUNIT_ASSERT(pGraphicObject); + + Graphic aGraphic = pGraphicObject->GetGraphic(); + auto const& pVectorGraphicData = aGraphic.getVectorGraphicData(); + CPPUNIT_ASSERT(pVectorGraphicData); + CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf, pVectorGraphicData->getType()); + + lcl_search("NonExisting"); + + CPPUNIT_ASSERT_EQUAL(false, mpCallbackRecorder->m_bFound); +} + +void LOKitSearchTest::testSearchInPDF() +{ + auto pPdfium = vcl::pdf::PDFiumLibrary::get(); + if (!pPdfium) + { + return; + } + + SdXImpressDocument* pXImpressDocument = createDoc("PDFSearch.pdf"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + CPPUNIT_ASSERT(pViewShell); + mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase()); + + SdPage* pPage = pViewShell->GetActualPage(); + CPPUNIT_ASSERT(pPage); + + SdrObject* pObject = pPage->GetObj(0); + CPPUNIT_ASSERT(pObject); + + SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject); + CPPUNIT_ASSERT(pGraphicObject); + + Graphic aGraphic = pGraphicObject->GetGraphic(); + auto const& pVectorGraphicData = aGraphic.getVectorGraphicData(); + CPPUNIT_ASSERT(pVectorGraphicData); + CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf, pVectorGraphicData->getType()); + + // Search + lcl_search("ABC"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL("3763, 1331, 1432, 483"_ostr, + mpCallbackRecorder->m_aSearchResultSelection[0]); + CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(3763, 1331), Size(1433, 484)), + mpCallbackRecorder->m_aSelection[0]); + + // Search again - same result + lcl_search("ABC"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(2, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL("3763, 1331, 1432, 483"_ostr, + mpCallbackRecorder->m_aSearchResultSelection[0]); + CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(3763, 1331), Size(1433, 484)), + mpCallbackRecorder->m_aSelection[0]); +} + +void LOKitSearchTest::testSearchInPDFOnePDFObject() +{ + auto pPdfium = vcl::pdf::PDFiumLibrary::get(); + if (!pPdfium) + { + return; + } + + SdXImpressDocument* pXImpressDocument = createDoc("OnePDFObject.odg"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + CPPUNIT_ASSERT(pViewShell); + mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase()); + + SdPage* pPage = pViewShell->GetActualPage(); + CPPUNIT_ASSERT(pPage); + + SdrObject* pObject = pPage->GetObj(0); + CPPUNIT_ASSERT(pObject); + + SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject); + CPPUNIT_ASSERT(pGraphicObject); + + Graphic aGraphic = pGraphicObject->GetGraphic(); + auto const& pVectorGraphicData = aGraphic.getVectorGraphicData(); + CPPUNIT_ASSERT(pVectorGraphicData); + CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf, pVectorGraphicData->getType()); + + // Search down + lcl_search("ABC", false, false); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_nSearchResultCount); + + // Search up + lcl_search("ABC", false, true); // This caused a crash + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(2, mpCallbackRecorder->m_nSearchResultCount); +} + +void LOKitSearchTest::testSearchInPDFInMultiplePages() +{ + auto pPdfium = vcl::pdf::PDFiumLibrary::get(); + if (!pPdfium) + { + return; + } + + SdXImpressDocument* pXImpressDocument = createDoc("PDFSearch.pdf"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + CPPUNIT_ASSERT(pViewShell); + mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase()); + + SdPage* pPage = pViewShell->GetActualPage(); + CPPUNIT_ASSERT(pPage); + + { + SdrObject* pObject = pPage->GetObj(0); + CPPUNIT_ASSERT(pObject); + + SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject); + CPPUNIT_ASSERT(pGraphicObject); + + Graphic aGraphic = pGraphicObject->GetGraphic(); + auto const& pVectorGraphicData = aGraphic.getVectorGraphicData(); + CPPUNIT_ASSERT(pVectorGraphicData); + CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf, pVectorGraphicData->getType()); + } + + // Search for "him" + lcl_search("him"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + + CPPUNIT_ASSERT_EQUAL(0, mpCallbackRecorder->m_aSearchResultPart[0]); + CPPUNIT_ASSERT_EQUAL("9463, 3382, 1099, 499"_ostr, + mpCallbackRecorder->m_aSearchResultSelection[0]); + + // Search for "him" + lcl_search("him"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(2, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + + CPPUNIT_ASSERT_EQUAL(0, mpCallbackRecorder->m_aSearchResultPart[0]); + CPPUNIT_ASSERT_EQUAL("5592, 5038, 1100, 499"_ostr, + mpCallbackRecorder->m_aSearchResultSelection[0]); + + // Search for "him" + lcl_search("him"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(3, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + + CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_aSearchResultPart[0]); + CPPUNIT_ASSERT_EQUAL("9463, 1308, 1099, 499"_ostr, + mpCallbackRecorder->m_aSearchResultSelection[0]); + + // Search for "him" + lcl_search("him"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(4, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + + CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_aSearchResultPart[0]); + CPPUNIT_ASSERT_EQUAL("5592, 2964, 1100, 499"_ostr, + mpCallbackRecorder->m_aSearchResultSelection[0]); + + // Search for "him" - back to start + lcl_search("him"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(5, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + + CPPUNIT_ASSERT_EQUAL(0, mpCallbackRecorder->m_aSearchResultPart[0]); + CPPUNIT_ASSERT_EQUAL("9463, 3382, 1099, 499"_ostr, + mpCallbackRecorder->m_aSearchResultSelection[0]); +} + +void LOKitSearchTest::testSearchInPDFInMultiplePagesBackwards() +{ + auto pPdfium = vcl::pdf::PDFiumLibrary::get(); + if (!pPdfium) + { + return; + } + + SdXImpressDocument* pXImpressDocument = createDoc("PDFSearch.pdf"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + CPPUNIT_ASSERT(pViewShell); + mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase()); + + SdPage* pPage = pViewShell->GetActualPage(); + CPPUNIT_ASSERT(pPage); + + { + SdrObject* pObject = pPage->GetObj(0); + CPPUNIT_ASSERT(pObject); + + SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject); + CPPUNIT_ASSERT(pGraphicObject); + + Graphic aGraphic = pGraphicObject->GetGraphic(); + auto const& pVectorGraphicData = aGraphic.getVectorGraphicData(); + CPPUNIT_ASSERT(pVectorGraphicData); + CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf, pVectorGraphicData->getType()); + } + + // Expected for backwards search is: + // - Start with Page 1 + // + search backwards through objects + // + inside objects search backwards through text + // - Switch to Page 2 + // + search backwards through objects + // + inside objects search backwards through text + + // Search for "him" + lcl_search("him", /*FindAll*/ false, /*Backwards*/ true); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + + CPPUNIT_ASSERT_EQUAL(0, mpCallbackRecorder->m_aSearchResultPart[0]); + CPPUNIT_ASSERT_EQUAL("5592, 5038, 1100, 499"_ostr, + mpCallbackRecorder->m_aSearchResultSelection[0]); + + // Search for "him" + lcl_search("him", /*FindAll*/ false, /*Backwards*/ true); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(2, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + + CPPUNIT_ASSERT_EQUAL(0, mpCallbackRecorder->m_aSearchResultPart[0]); + CPPUNIT_ASSERT_EQUAL("9463, 3382, 1099, 499"_ostr, + mpCallbackRecorder->m_aSearchResultSelection[0]); + + // Search for "him" + lcl_search("him", /*FindAll*/ false, /*Backwards*/ true); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(3, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + + CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_aSearchResultPart[0]); + CPPUNIT_ASSERT_EQUAL("5592, 2964, 1100, 499"_ostr, + mpCallbackRecorder->m_aSearchResultSelection[0]); + + // Search for "him" + lcl_search("him", /*FindAll*/ false, /*Backwards*/ true); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(4, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + + CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_aSearchResultPart[0]); + CPPUNIT_ASSERT_EQUAL("9463, 1308, 1099, 499"_ostr, + mpCallbackRecorder->m_aSearchResultSelection[0]); + + // Search for "him" - back to start + lcl_search("him", /*FindAll*/ false, /*Backwards*/ true); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(5, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + + CPPUNIT_ASSERT_EQUAL(0, mpCallbackRecorder->m_aSearchResultPart[0]); + CPPUNIT_ASSERT_EQUAL("5592, 5038, 1100, 499"_ostr, + mpCallbackRecorder->m_aSearchResultSelection[0]); +} + +// Test searching in document with mixed objects. +// We have 2 objects: 1. Text Object, 2. Graphic Object with PDF +void LOKitSearchTest::testSearchIn2MixedObjects() +{ + auto pPdfium = vcl::pdf::PDFiumLibrary::get(); + if (!pPdfium) + { + return; + } + + SdXImpressDocument* pXImpressDocument = createDoc("MixedTest1.odg"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + CPPUNIT_ASSERT(pViewShell); + SdDrawDocument* pDocument = pXImpressDocument->GetDocShell()->GetDoc(); + CPPUNIT_ASSERT(pDocument); + mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase()); + + // Check we have one page + CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), pDocument->GetSdPageCount(PageKind::Standard)); + + SdPage* pPage = pViewShell->GetActualPage(); + CPPUNIT_ASSERT(pPage); + + // Check page has 2 objects only + CPPUNIT_ASSERT_EQUAL(size_t(2), pPage->GetObjCount()); + + // Check Object 1 + { + SdrObject* pObject = pPage->GetObj(0); + CPPUNIT_ASSERT(pObject); + + CPPUNIT_ASSERT_EQUAL(SdrObjKind::Text, pObject->GetObjIdentifier()); + } + + // Check Object 2 + { + SdrObject* pObject = pPage->GetObj(1); + CPPUNIT_ASSERT(pObject); + + CPPUNIT_ASSERT_EQUAL(SdrObjKind::Graphic, pObject->GetObjIdentifier()); + + SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject); + CPPUNIT_ASSERT(pGraphicObject); + + Graphic aGraphic = pGraphicObject->GetGraphic(); + auto const& pVectorGraphicData = aGraphic.getVectorGraphicData(); + CPPUNIT_ASSERT(pVectorGraphicData); + + CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf, pVectorGraphicData->getType()); + } + + // Let's try to search now + + lcl_search("ABC"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + + CPPUNIT_ASSERT_EQUAL("3546, 3174, 738, 402"_ostr, + mpCallbackRecorder->m_aSearchResultSelection[0]); + + // Search next + + lcl_search("ABC"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(2, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + + CPPUNIT_ASSERT_EQUAL("8412, 6385, 519, 174"_ostr, + mpCallbackRecorder->m_aSearchResultSelection[0]); + + // Search next again - we should get the first object again + + lcl_search("ABC"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(3, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + + CPPUNIT_ASSERT_EQUAL("3546, 3174, 738, 402"_ostr, + mpCallbackRecorder->m_aSearchResultSelection[0]); +} + +// Test searching in document with mixed objects. We have 6 objects. +void LOKitSearchTest::testSearchIn6MixedObjects() +{ + auto pPdfium = vcl::pdf::PDFiumLibrary::get(); + if (!pPdfium) + { + return; + } + + SdXImpressDocument* pXImpressDocument = createDoc("MixedTest2.odg"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + CPPUNIT_ASSERT(pViewShell); + SdDrawDocument* pDocument = pXImpressDocument->GetDocShell()->GetDoc(); + CPPUNIT_ASSERT(pDocument); + mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase()); + + // Check we have one page + CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), pDocument->GetSdPageCount(PageKind::Standard)); + + SdPage* pPage = pViewShell->GetActualPage(); + CPPUNIT_ASSERT(pPage); + + // Check page has 6 objects only + CPPUNIT_ASSERT_EQUAL(size_t(6), pPage->GetObjCount()); + + // Check we have the right objects that we expect + + // Check Object 1 + { + SdrObject* pObject = pPage->GetObj(0); + CPPUNIT_ASSERT(pObject); + CPPUNIT_ASSERT_EQUAL(SdrObjKind::Text, pObject->GetObjIdentifier()); + } + + // Check Object 2 + { + SdrObject* pObject = pPage->GetObj(1); + CPPUNIT_ASSERT(pObject); + CPPUNIT_ASSERT_EQUAL(SdrObjKind::Graphic, pObject->GetObjIdentifier()); + SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject); + CPPUNIT_ASSERT(pGraphicObject); + auto const& pVectorGraphicData = pGraphicObject->GetGraphic().getVectorGraphicData(); + CPPUNIT_ASSERT(pVectorGraphicData); + CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf, pVectorGraphicData->getType()); + } + + // Check Object 3 + { + SdrObject* pObject = pPage->GetObj(2); + CPPUNIT_ASSERT(pObject); + CPPUNIT_ASSERT_EQUAL(SdrObjKind::CustomShape, pObject->GetObjIdentifier()); + } + + // Check Object 4 + { + SdrObject* pObject = pPage->GetObj(3); + CPPUNIT_ASSERT(pObject); + CPPUNIT_ASSERT_EQUAL(SdrObjKind::CustomShape, pObject->GetObjIdentifier()); + } + + // Check Object 5 + { + SdrObject* pObject = pPage->GetObj(4); + CPPUNIT_ASSERT(pObject); + CPPUNIT_ASSERT_EQUAL(SdrObjKind::Graphic, pObject->GetObjIdentifier()); + SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject); + CPPUNIT_ASSERT(pGraphicObject); + auto const& pVectorGraphicData = pGraphicObject->GetGraphic().getVectorGraphicData(); + CPPUNIT_ASSERT(pVectorGraphicData); + CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Svg, pVectorGraphicData->getType()); + } + + // Check Object 6 + { + SdrObject* pObject = pPage->GetObj(5); + CPPUNIT_ASSERT(pObject); + CPPUNIT_ASSERT_EQUAL(SdrObjKind::Graphic, pObject->GetObjIdentifier()); + SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject); + CPPUNIT_ASSERT(pGraphicObject); + auto const& pVectorGraphicData = pGraphicObject->GetGraphic().getVectorGraphicData(); + CPPUNIT_ASSERT(pVectorGraphicData); + CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf, pVectorGraphicData->getType()); + } + + // Search "ABC" which is in all objects (2 times in Object 3) + + // Object 1 + lcl_search("ABC"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + CPPUNIT_ASSERT_EQUAL(pPage->GetObj(0), lclGetSelectedObject(pViewShell)); + + // Object 2 + lcl_search("ABC"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(2, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + CPPUNIT_ASSERT_EQUAL(pPage->GetObj(1), lclGetSelectedObject(pViewShell)); + + // Object 3 + lcl_search("ABC"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(3, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + CPPUNIT_ASSERT_EQUAL(pPage->GetObj(2), lclGetSelectedObject(pViewShell)); + + // Object 3 again + lcl_search("ABC"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(4, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + CPPUNIT_ASSERT_EQUAL(pPage->GetObj(2), lclGetSelectedObject(pViewShell)); + + // Object 4 + lcl_search("ABC"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(5, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + CPPUNIT_ASSERT_EQUAL(pPage->GetObj(3), lclGetSelectedObject(pViewShell)); + + // Object 5 + lcl_search("ABC"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(6, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + CPPUNIT_ASSERT_EQUAL(pPage->GetObj(4), lclGetSelectedObject(pViewShell)); + + // Object 6 + lcl_search("ABC"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(7, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + CPPUNIT_ASSERT_EQUAL(pPage->GetObj(5), lclGetSelectedObject(pViewShell)); + + // Loop to Object 1 again + lcl_search("ABC"); + + CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound); + CPPUNIT_ASSERT_EQUAL(8, mpCallbackRecorder->m_nSearchResultCount); + + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size()); + CPPUNIT_ASSERT_EQUAL(pPage->GetObj(0), lclGetSelectedObject(pViewShell)); +} +namespace +{ +OUString getShapeText(SdXImpressDocument* pXImpressDocument, sal_uInt32 nPage, sal_uInt32 nShape) +{ + uno::Reference<container::XIndexAccess> xDrawPage; + xDrawPage.set(pXImpressDocument->getDrawPages()->getByIndex(nPage), uno::UNO_QUERY); + + uno::Reference<text::XTextRange> xShape(xDrawPage->getByIndex(nShape), uno::UNO_QUERY); + return xShape->getString(); +} +} + +void LOKitSearchTest::testReplace() +{ + SdXImpressDocument* pXImpressDocument = createDoc("ReplaceTest.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase()); + + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 0, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("Bbb bbb bbb bbb"), getShapeText(pXImpressDocument, 1, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 2, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 3, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 4, 0)); + + lcl_replace("bbb", "aaa", false); // select + + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 0, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("Bbb bbb bbb bbb"), getShapeText(pXImpressDocument, 1, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 2, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 3, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 4, 0)); + + lcl_replace("bbb", "aaa", false); // replace + + CPPUNIT_ASSERT_EQUAL(OUString("aaa"), getShapeText(pXImpressDocument, 0, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("Bbb bbb bbb bbb"), getShapeText(pXImpressDocument, 1, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 2, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 3, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 4, 0)); +} + +void LOKitSearchTest::testReplaceAll() +{ + SdXImpressDocument* pXImpressDocument = createDoc("ReplaceTest.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase()); + + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 0, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("Bbb bbb bbb bbb"), getShapeText(pXImpressDocument, 1, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 2, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 3, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 4, 0)); + + lcl_replace("bbb", "ccc", true); + + CPPUNIT_ASSERT_EQUAL(OUString("ccc"), getShapeText(pXImpressDocument, 0, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("ccc ccc ccc ccc"), getShapeText(pXImpressDocument, 1, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("ccc"), getShapeText(pXImpressDocument, 2, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("ccc"), getShapeText(pXImpressDocument, 3, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("ccc"), getShapeText(pXImpressDocument, 4, 0)); + + lcl_replace("ccc", "bbb", true); + + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 0, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb bbb bbb bbb"), getShapeText(pXImpressDocument, 1, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 2, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 3, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 4, 0)); +} + +void LOKitSearchTest::testReplaceCombined() +{ + SdXImpressDocument* pXImpressDocument = createDoc("ReplaceTest.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase()); + + lcl_replace("bbb", "aaa", false); // select + lcl_replace("bbb", "aaa", false); // replace + + CPPUNIT_ASSERT_EQUAL(OUString("aaa"), getShapeText(pXImpressDocument, 0, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("Bbb bbb bbb bbb"), getShapeText(pXImpressDocument, 1, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 2, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 3, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), getShapeText(pXImpressDocument, 4, 0)); + + lcl_replace("bbb", "ccc", true); + + CPPUNIT_ASSERT_EQUAL(OUString("aaa"), getShapeText(pXImpressDocument, 0, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("ccc ccc ccc ccc"), getShapeText(pXImpressDocument, 1, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("ccc"), getShapeText(pXImpressDocument, 2, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("ccc"), getShapeText(pXImpressDocument, 3, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("ccc"), getShapeText(pXImpressDocument, 4, 0)); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(LOKitSearchTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/qa/unit/tiledrendering/data/2slides.odp b/sd/qa/unit/tiledrendering/data/2slides.odp Binary files differnew file mode 100644 index 0000000000..baa42ba9fc --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/2slides.odp diff --git a/sd/qa/unit/tiledrendering/data/MixedTest1.odg b/sd/qa/unit/tiledrendering/data/MixedTest1.odg Binary files differnew file mode 100644 index 0000000000..db952318c7 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/MixedTest1.odg diff --git a/sd/qa/unit/tiledrendering/data/MixedTest2.odg b/sd/qa/unit/tiledrendering/data/MixedTest2.odg Binary files differnew file mode 100644 index 0000000000..2709707c1b --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/MixedTest2.odg diff --git a/sd/qa/unit/tiledrendering/data/OnePDFObject.odg b/sd/qa/unit/tiledrendering/data/OnePDFObject.odg Binary files differnew file mode 100644 index 0000000000..225741c7b5 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/OnePDFObject.odg diff --git a/sd/qa/unit/tiledrendering/data/PDFSearch.pdf b/sd/qa/unit/tiledrendering/data/PDFSearch.pdf Binary files differnew file mode 100644 index 0000000000..ea8a0919a4 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/PDFSearch.pdf diff --git a/sd/qa/unit/tiledrendering/data/ReplaceTest.odp b/sd/qa/unit/tiledrendering/data/ReplaceTest.odp Binary files differnew file mode 100644 index 0000000000..9b0fc61aaf --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/ReplaceTest.odp diff --git a/sd/qa/unit/tiledrendering/data/TextBoxAndRect.odg b/sd/qa/unit/tiledrendering/data/TextBoxAndRect.odg Binary files differnew file mode 100644 index 0000000000..aa1a37b831 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/TextBoxAndRect.odg diff --git a/sd/qa/unit/tiledrendering/data/cut_selection_change.odp b/sd/qa/unit/tiledrendering/data/cut_selection_change.odp Binary files differnew file mode 100644 index 0000000000..19d3a18480 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/cut_selection_change.odp diff --git a/sd/qa/unit/tiledrendering/data/dummy.odg b/sd/qa/unit/tiledrendering/data/dummy.odg Binary files differnew file mode 100644 index 0000000000..19ae49d63b --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/dummy.odg diff --git a/sd/qa/unit/tiledrendering/data/dummy.odp b/sd/qa/unit/tiledrendering/data/dummy.odp Binary files differnew file mode 100644 index 0000000000..83dee413c5 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/dummy.odp diff --git a/sd/qa/unit/tiledrendering/data/duplicate-undo.odp b/sd/qa/unit/tiledrendering/data/duplicate-undo.odp Binary files differnew file mode 100644 index 0000000000..f66c9f6081 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/duplicate-undo.odp diff --git a/sd/qa/unit/tiledrendering/data/insert-delete.odp b/sd/qa/unit/tiledrendering/data/insert-delete.odp Binary files differnew file mode 100644 index 0000000000..e388fb60b6 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/insert-delete.odp diff --git a/sd/qa/unit/tiledrendering/data/language-all-text.odp b/sd/qa/unit/tiledrendering/data/language-all-text.odp Binary files differnew file mode 100644 index 0000000000..a484a6310e --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/language-all-text.odp diff --git a/sd/qa/unit/tiledrendering/data/notes-view.odp b/sd/qa/unit/tiledrendering/data/notes-view.odp Binary files differnew file mode 100644 index 0000000000..d41bdf9599 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/notes-view.odp diff --git a/sd/qa/unit/tiledrendering/data/paste-undo.fodp b/sd/qa/unit/tiledrendering/data/paste-undo.fodp new file mode 100644 index 0000000000..2615d1e114 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/paste-undo.fodp @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.presentation"> + <office:styles> + <style:presentation-page-layout style:name="AL1T0"> + <presentation:placeholder presentation:object="title" svg:x="2.058cm" svg:y="1.743cm" svg:width="23.912cm" svg:height="3.507cm"/> + <presentation:placeholder presentation:object="subtitle" svg:x="2.058cm" svg:y="5.838cm" svg:width="23.912cm" svg:height="13.23cm"/> + </style:presentation-page-layout> + </office:styles> + <office:automatic-styles> + <style:page-layout style:name="PM0"> + <style:page-layout-properties fo:margin-top="0cm" fo:margin-bottom="0cm" fo:margin-left="0cm" fo:margin-right="0cm" fo:page-width="21cm" fo:page-height="29.7cm" style:print-orientation="portrait"/> + </style:page-layout> + <style:page-layout style:name="PM1"> + <style:page-layout-properties fo:margin-top="0cm" fo:margin-bottom="0cm" fo:margin-left="0cm" fo:margin-right="0cm" fo:page-width="28cm" fo:page-height="15.75cm" style:print-orientation="landscape"/> + </style:page-layout> + <style:style style:name="dp3" style:family="drawing-page"> + </style:style> + <style:style style:name="gr3" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" svg:stroke-color="#000000" draw:fill="none" draw:fill-color="#ffffff" draw:auto-grow-height="true" draw:auto-grow-width="false" fo:max-height="0cm" fo:min-height="0.712cm"/> + <style:paragraph-properties style:writing-mode="lr-tb"/> + </style:style> + </office:automatic-styles> + <office:body> + <office:presentation> + <draw:page draw:name="page1" draw:style-name="dp3" draw:master-page-name="Default" presentation:presentation-page-layout-name="AL1T0"> + <draw:frame draw:style-name="gr3" draw:text-style-name="P7" draw:layer="layout" svg:width="7.5cm" svg:height="0.962cm" svg:x="3.5cm" svg:y="3.5cm"> + <draw:text-box> + <text:p>world</text:p> + </draw:text-box> + </draw:frame> + </draw:page> + </office:presentation> + </office:body> +</office:document> diff --git a/sd/qa/unit/tiledrendering/data/paste_text_onslide.odp b/sd/qa/unit/tiledrendering/data/paste_text_onslide.odp Binary files differnew file mode 100644 index 0000000000..c33b7c1102 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/paste_text_onslide.odp diff --git a/sd/qa/unit/tiledrendering/data/regenerate-diagram.pptx b/sd/qa/unit/tiledrendering/data/regenerate-diagram.pptx Binary files differnew file mode 100644 index 0000000000..97635a5187 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/regenerate-diagram.pptx diff --git a/sd/qa/unit/tiledrendering/data/search-all.odp b/sd/qa/unit/tiledrendering/data/search-all.odp Binary files differnew file mode 100644 index 0000000000..46ddaf412b --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/search-all.odp diff --git a/sd/qa/unit/tiledrendering/data/shape.odp b/sd/qa/unit/tiledrendering/data/shape.odp Binary files differnew file mode 100644 index 0000000000..b1ffa54e36 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/shape.odp diff --git a/sd/qa/unit/tiledrendering/data/table-column.odp b/sd/qa/unit/tiledrendering/data/table-column.odp Binary files differnew file mode 100644 index 0000000000..d2c274e888 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/table-column.odp diff --git a/sd/qa/unit/tiledrendering/data/table.odp b/sd/qa/unit/tiledrendering/data/table.odp Binary files differnew file mode 100644 index 0000000000..6d92898a00 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/table.odp diff --git a/sd/qa/unit/tiledrendering/data/tdf102223.odp b/sd/qa/unit/tiledrendering/data/tdf102223.odp Binary files differnew file mode 100644 index 0000000000..6b8570f070 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/tdf102223.odp diff --git a/sd/qa/unit/tiledrendering/data/tdf103083.fodp b/sd/qa/unit/tiledrendering/data/tdf103083.fodp new file mode 100644 index 0000000000..8de5e37b8f --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/tdf103083.fodp @@ -0,0 +1,932 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:smil="urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.presentation"> + <office:meta> + <meta:creation-date>2016-10-03T11:33:02.159552013</meta:creation-date> + <meta:editing-duration>PT21M51S</meta:editing-duration> + <meta:editing-cycles>2</meta:editing-cycles> + <meta:generator>LibreOfficeDev/5.3.0.0.alpha0$Linux_X86_64 LibreOffice_project/36b8fd83a57132f486d918e5ab39a6e8898bb630</meta:generator> + <dc:date>2016-10-03T11:33:43.592997719</dc:date><meta:document-statistic meta:object-count="27"/></office:meta> + <office:settings> + <config:config-item-set config:name="ooo:view-settings"> + <config:config-item config:name="VisibleAreaTop" config:type="int">-275</config:config-item> + <config:config-item config:name="VisibleAreaLeft" config:type="int">-1323</config:config-item> + <config:config-item config:name="VisibleAreaWidth" config:type="int">28053</config:config-item> + <config:config-item config:name="VisibleAreaHeight" config:type="int">19616</config:config-item> + <config:config-item-map-indexed config:name="Views"> + <config:config-item-map-entry> + <config:config-item config:name="ViewId" config:type="string">view1</config:config-item> + <config:config-item config:name="GridIsVisible" config:type="boolean">false</config:config-item> + <config:config-item config:name="GridIsFront" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsSnapToGrid" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsSnapToPageMargins" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsSnapToSnapLines" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsSnapToObjectFrame" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsSnapToObjectPoints" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPlusHandlesAlwaysVisible" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsFrameDragSingles" config:type="boolean">true</config:config-item> + <config:config-item config:name="EliminatePolyPointLimitAngle" config:type="int">1500</config:config-item> + <config:config-item config:name="IsEliminatePolyPoints" config:type="boolean">false</config:config-item> + <config:config-item config:name="VisibleLayers" config:type="base64Binary">//////////////////////////////////////////8=</config:config-item> + <config:config-item config:name="PrintableLayers" config:type="base64Binary">//////////////////////////////////////////8=</config:config-item> + <config:config-item config:name="LockedLayers" config:type="base64Binary"/> + <config:config-item config:name="NoAttribs" config:type="boolean">false</config:config-item> + <config:config-item config:name="NoColors" config:type="boolean">true</config:config-item> + <config:config-item config:name="SnapLinesDrawing" config:type="string">V2278V23104H18449H578V627V24757H4049H2466H17561</config:config-item> + <config:config-item config:name="RulerIsVisible" config:type="boolean">true</config:config-item> + <config:config-item config:name="PageKind" config:type="short">0</config:config-item> + <config:config-item config:name="SelectedPage" config:type="short">0</config:config-item> + <config:config-item config:name="IsLayerMode" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsDoubleClickTextEdit" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsClickChangeRotation" config:type="boolean">false</config:config-item> + <config:config-item config:name="SlidesPerRow" config:type="short">4</config:config-item> + <config:config-item config:name="EditMode" config:type="int">0</config:config-item> + <config:config-item config:name="VisibleAreaTop" config:type="int">-275</config:config-item> + <config:config-item config:name="VisibleAreaLeft" config:type="int">-1323</config:config-item> + <config:config-item config:name="VisibleAreaWidth" config:type="int">28057</config:config-item> + <config:config-item config:name="VisibleAreaHeight" config:type="int">19620</config:config-item> + <config:config-item config:name="GridCoarseWidth" config:type="int">2540</config:config-item> + <config:config-item config:name="GridCoarseHeight" config:type="int">2540</config:config-item> + <config:config-item config:name="GridFineWidth" config:type="int">254</config:config-item> + <config:config-item config:name="GridFineHeight" config:type="int">254</config:config-item> + <config:config-item config:name="GridSnapWidthXNumerator" config:type="int">254</config:config-item> + <config:config-item config:name="GridSnapWidthXDenominator" config:type="int">1</config:config-item> + <config:config-item config:name="GridSnapWidthYNumerator" config:type="int">254</config:config-item> + <config:config-item config:name="GridSnapWidthYDenominator" config:type="int">1</config:config-item> + <config:config-item config:name="IsAngleSnapEnabled" config:type="boolean">false</config:config-item> + <config:config-item config:name="SnapAngle" config:type="int">1500</config:config-item> + <config:config-item config:name="ZoomOnPage" config:type="boolean">true</config:config-item> + <config:config-item config:name="AnchoredTextOverflowLegacy" config:type="boolean">true</config:config-item> + </config:config-item-map-entry> + </config:config-item-map-indexed> + </config:config-item-set> + <config:config-item-set config:name="ooo:configuration-settings"> + <config:config-item config:name="ApplyUserData" config:type="boolean">true</config:config-item> + <config:config-item config:name="BitmapTableURL" config:type="string">$(inst)/share/palette%3B$(user)/config/standard.sob</config:config-item> + <config:config-item config:name="CharacterCompressionType" config:type="short">0</config:config-item> + <config:config-item config:name="ColorTableURL" config:type="string">$(inst)/share/palette%3B$(user)/config/standard.soc</config:config-item> + <config:config-item config:name="DashTableURL" config:type="string">$(inst)/share/palette%3B$(user)/config/standard.sod</config:config-item> + <config:config-item config:name="DefaultTabStop" config:type="int">1270</config:config-item> + <config:config-item config:name="EmbedFonts" config:type="boolean">false</config:config-item> + <config:config-item-map-indexed config:name="ForbiddenCharacters"> + <config:config-item-map-entry> + <config:config-item config:name="Language" config:type="string">de</config:config-item> + <config:config-item config:name="Country" config:type="string">DE</config:config-item> + <config:config-item config:name="Variant" config:type="string"/> + <config:config-item config:name="BeginLine" config:type="string"/> + <config:config-item config:name="EndLine" config:type="string"/> + </config:config-item-map-entry> + <config:config-item-map-entry> + <config:config-item config:name="Language" config:type="string">en</config:config-item> + <config:config-item config:name="Country" config:type="string">US</config:config-item> + <config:config-item config:name="Variant" config:type="string"/> + <config:config-item config:name="BeginLine" config:type="string"/> + <config:config-item config:name="EndLine" config:type="string"/> + </config:config-item-map-entry> + <config:config-item-map-entry> + <config:config-item config:name="Language" config:type="string">en</config:config-item> + <config:config-item config:name="Country" config:type="string">GB</config:config-item> + <config:config-item config:name="Variant" config:type="string"/> + <config:config-item config:name="BeginLine" config:type="string"/> + <config:config-item config:name="EndLine" config:type="string"/> + </config:config-item-map-entry> + <config:config-item-map-entry> + <config:config-item config:name="Language" config:type="string">en</config:config-item> + <config:config-item config:name="Country" config:type="string">ZA</config:config-item> + <config:config-item config:name="Variant" config:type="string"/> + <config:config-item config:name="BeginLine" config:type="string"/> + <config:config-item config:name="EndLine" config:type="string"/> + </config:config-item-map-entry> + </config:config-item-map-indexed> + <config:config-item config:name="GradientTableURL" config:type="string">$(inst)/share/palette%3B$(user)/config/standard.sog</config:config-item> + <config:config-item config:name="HandoutsHorizontal" config:type="boolean">true</config:config-item> + <config:config-item config:name="HatchTableURL" config:type="string">$(inst)/share/palette%3B$(user)/config/standard.soh</config:config-item> + <config:config-item config:name="IsKernAsianPunctuation" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintBooklet" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintBookletBack" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsPrintBookletFront" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsPrintDate" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintDrawing" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsPrintFitPage" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintHandout" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintHiddenPages" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsPrintNotes" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintOutline" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintPageName" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintTilePage" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintTime" config:type="boolean">false</config:config-item> + <config:config-item config:name="LineEndTableURL" config:type="string">$(inst)/share/palette%3B$(user)/config/standard.soe</config:config-item> + <config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item> + <config:config-item config:name="PageNumberFormat" config:type="int">4</config:config-item> + <config:config-item config:name="ParagraphSummation" config:type="boolean">false</config:config-item> + <config:config-item config:name="PrintQuality" config:type="int">0</config:config-item> + <config:config-item config:name="PrinterIndependentLayout" config:type="string">low-resolution</config:config-item> + <config:config-item config:name="PrinterName" config:type="string"/> + <config:config-item config:name="PrinterSetup" config:type="base64Binary"/> + <config:config-item config:name="SaveVersionOnClose" config:type="boolean">false</config:config-item> + <config:config-item config:name="SlidesPerHandout" config:type="short">6</config:config-item> + <config:config-item config:name="UpdateFromTemplate" config:type="boolean">true</config:config-item> + </config:config-item-set> + </office:settings> + <office:scripts> + <office:script script:language="ooo:Basic"> + <ooo:libraries xmlns:ooo="http://openoffice.org/2004/office" xmlns:xlink="http://www.w3.org/1999/xlink"/> + </office:script> + </office:scripts> + <office:font-face-decls> + <style:font-face style:name="Arial2" svg:font-family="Arial" style:font-family-generic="swiss"/> + <style:font-face style:name="Liberation Sans" svg:font-family="'Liberation Sans'" style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Thorndale AMT" svg:font-family="'Thorndale AMT'" style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="swiss" style:font-pitch="variable"/> + <style:font-face style:name="Arial1" svg:font-family="Arial" style:font-adornments="Regular" style:font-family-generic="swiss" style:font-pitch="variable"/> + <style:font-face style:name="Calibri" svg:font-family="Calibri" style:font-family-generic="swiss" style:font-pitch="variable"/> + <style:font-face style:name="Albany AMT" svg:font-family="'Albany AMT'" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="FreeSans" svg:font-family="FreeSans" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="Mangal" svg:font-family="Mangal" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="Microsoft YaHei" svg:font-family="'Microsoft YaHei'" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="Noto Sans CJK SC Regular" svg:font-family="'Noto Sans CJK SC Regular'" style:font-family-generic="system" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <draw:marker draw:name="Arrow" svg:viewBox="0 0 20 30" svg:d="M10 0l-10 30h20z"/> + <draw:stroke-dash draw:name="Dashed_20__28_var_29__20_2" draw:display-name="Dashed (var) 2" draw:style="rect" draw:dots1="1" draw:dots1-length="0.02cm" draw:dots2="1" draw:dots2-length="0.02cm" draw:distance="0.02cm"/> + <style:default-style style:family="graphic"> + <style:graphic-properties svg:stroke-color="#000000" draw:fill-color="#99ccff" fo:wrap-option="no-wrap"/> + <style:paragraph-properties style:text-autospace="ideograph-alpha" style:punctuation-wrap="simple" style:line-break="strict" style:writing-mode="lr-tb" style:font-independent-line-spacing="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:use-window-font-color="true" style:font-name="Thorndale AMT" fo:font-size="24pt" fo:language="en" fo:country="US" style:font-name-asian="Albany AMT" style:font-size-asian="24pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Albany AMT" style:font-size-complex="24pt" style:language-complex="hi" style:country-complex="IN"/> + </style:default-style> + <style:style style:name="standard" style:family="graphic"> + <style:graphic-properties draw:stroke="solid" draw:stroke-dash="Dashed_20__28_var_29__20_2" svg:stroke-width="0.076cm" svg:stroke-color="#454c51" draw:marker-start-width="0.406cm" draw:marker-start-center="false" draw:marker-end-width="0.406cm" draw:marker-end-center="false" draw:fill="solid" draw:fill-color="#e4e5e6" draw:fill-image-width="0cm" draw:fill-image-height="0cm" draw:auto-grow-width="true" fo:padding-top="0.125cm" fo:padding-bottom="0.125cm" fo:padding-left="0.25cm" fo:padding-right="0.25cm" draw:shadow="hidden" draw:shadow-offset-x="0.305cm" draw:shadow-offset-y="0.305cm" draw:shadow-color="#808080"> + <text:list-style style:name="standard"> + <text:list-level-style-bullet text:level="1" text:bullet-char="●"> + <style:list-level-properties/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="2" text:bullet-char="●"> + <style:list-level-properties text:space-before="0.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="3" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="4" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="5" text:bullet-char="●"> + <style:list-level-properties text:space-before="2.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="6" text:bullet-char="●"> + <style:list-level-properties text:space-before="3cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="7" text:bullet-char="●"> + <style:list-level-properties text:space-before="3.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="8" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="9" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="10" text:bullet-char="●"> + <style:list-level-properties text:space-before="5.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + </text:list-style> + </style:graphic-properties> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" fo:line-height="100%" fo:text-indent="0cm"/> + <style:text-properties style:use-window-font-color="true" style:text-outline="false" style:text-line-through-style="none" style:text-line-through-type="none" style:font-name="Arial1" fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="18pt" fo:font-style="normal" fo:text-shadow="none" style:text-underline-style="none" fo:font-weight="normal" style:letter-kerning="true" style:font-name-asian="Microsoft YaHei" style:font-family-asian="'Microsoft YaHei'" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="18pt" style:font-style-asian="normal" style:font-weight-asian="normal" style:font-name-complex="Mangal" style:font-family-complex="Mangal" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="18pt" style:font-style-complex="normal" style:font-weight-complex="normal" style:text-emphasize="none" style:font-relief="none"/> + </style:style> + <style:style style:name="objectwitharrow" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="solid" svg:stroke-width="0.15cm" svg:stroke-color="#000000" draw:marker-start="Arrow" draw:marker-start-width="0.7cm" draw:marker-start-center="true" draw:marker-end-width="0.3cm"/> + </style:style> + <style:style style:name="objectwithshadow" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:shadow="visible" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:shadow-color="#808080"/> + </style:style> + <style:style style:name="objectwithoutfill" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:fill="none"/> + </style:style> + <style:style style:name="Object_20_with_20_no_20_fill_20_and_20_no_20_line" style:display-name="Object with no fill and no line" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + </style:style> + <style:style style:name="text" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + </style:style> + <style:style style:name="textbody" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:text-properties fo:font-size="16pt"/> + </style:style> + <style:style style:name="textbodyjustfied" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:paragraph-properties fo:text-align="justify"/> + </style:style> + <style:style style:name="textbodyindent" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0.6cm"/> + </style:style> + <style:style style:name="title" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:text-properties fo:font-size="40pt"/> + </style:style> + <style:style style:name="title1" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="solid" draw:fill-color="#008080" draw:shadow="visible" draw:shadow-offset-x="0.2cm" draw:shadow-offset-y="0.2cm" draw:shadow-color="#808080"/> + <style:paragraph-properties fo:text-align="center"/> + <style:text-properties fo:font-size="24pt"/> + </style:style> + <style:style style:name="title2" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties svg:stroke-width="0.05cm" draw:fill-color="#ffcc99" draw:shadow="visible" draw:shadow-offset-x="0.2cm" draw:shadow-offset-y="0.2cm" draw:shadow-color="#808080"/> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0.2cm" fo:margin-top="0.1cm" fo:margin-bottom="0.1cm" fo:text-align="center" fo:text-indent="0cm"/> + <style:text-properties fo:font-size="32pt"/> + </style:style> + <style:style style:name="headline" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:paragraph-properties fo:margin-top="0.42cm" fo:margin-bottom="0.21cm"/> + <style:text-properties fo:font-size="24pt"/> + </style:style> + <style:style style:name="headline1" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:paragraph-properties fo:margin-top="0.42cm" fo:margin-bottom="0.21cm"/> + <style:text-properties fo:font-size="18pt" fo:font-weight="bold"/> + </style:style> + <style:style style:name="headline2" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:paragraph-properties fo:margin-top="0.42cm" fo:margin-bottom="0.21cm"/> + <style:text-properties fo:font-size="14pt" fo:font-style="normal" fo:font-weight="normal"/> + </style:style> + <style:style style:name="measure" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="solid" draw:marker-start="Arrow" draw:marker-start-width="0.2cm" draw:marker-end="Arrow" draw:marker-end-width="0.2cm" draw:fill="none" draw:show-unit="true"/> + <style:text-properties fo:font-size="12pt"/> + </style:style> + <style:style style:name="Normal" style:family="graphic"> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0.623cm" fo:line-height="115%" fo:text-align="start" fo:text-indent="0cm" style:text-autospace="ideograph-alpha"/> + <style:text-properties style:font-name="Arial1" fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="11pt" fo:language="en" fo:country="US" style:font-name-asian="Calibri" style:font-family-asian="Calibri" style:font-family-generic-asian="swiss" style:font-pitch-asian="variable" style:font-size-asian="11pt" style:language-asian="en" style:country-asian="US" style:font-name-complex="Calibri" style:font-family-complex="Calibri" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" style:font-size-complex="11pt" style:language-complex="ar" style:country-complex="SA"/> + </style:style> + <style:style style:name="Default_20_Paragraph_20_Font" style:display-name="Default Paragraph Font" style:family="graphic"> + <style:paragraph-properties style:text-autospace="none"/> + <style:text-properties style:font-name="Arial1" fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" style:font-pitch="variable"/> + </style:style> + <style:style style:name="No-Logo_20_Content-background" style:display-name="No-Logo Content-background" style:family="presentation"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:fill-image-width="0cm" draw:fill-image-height="0cm"/> + <style:text-properties style:letter-kerning="true"/> + </style:style> + <style:style style:name="No-Logo_20_Content-backgroundobjects" style:display-name="No-Logo Content-backgroundobjects" style:family="presentation"> + <style:graphic-properties draw:shadow="hidden" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:shadow-color="#808080"/> + <style:text-properties style:font-name="Arial1" fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" style:font-pitch="variable" style:letter-kerning="true"/> + </style:style> + <style:style style:name="No-Logo_20_Content-notes" style:display-name="No-Logo Content-notes" style:family="presentation"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:paragraph-properties fo:margin-left="0.6cm" fo:margin-right="0cm" fo:text-indent="0cm"/> + <style:text-properties style:use-window-font-color="true" style:text-outline="false" style:text-line-through-style="none" style:text-line-through-type="none" style:font-name="Arial2" fo:font-family="Arial" style:font-family-generic="swiss" fo:font-size="14pt" fo:font-style="normal" fo:text-shadow="none" style:text-underline-style="none" fo:font-weight="normal" style:letter-kerning="true" style:font-name-asian="Microsoft YaHei" style:font-family-asian="'Microsoft YaHei'" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="14pt" style:font-style-asian="normal" style:font-weight-asian="normal" style:font-name-complex="Mangal" style:font-family-complex="Mangal" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="14pt" style:font-style-complex="normal" style:font-weight-complex="normal" style:text-emphasize="none" style:font-relief="none"/> + </style:style> + <style:style style:name="No-Logo_20_Content-outline1" style:display-name="No-Logo Content-outline1" style:family="presentation"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:textarea-horizontal-align="left" draw:auto-grow-height="false" draw:fit-to-size="false"> + <text:list-style style:name="No-Logo_20_Content-outline1" style:display-name="No-Logo Content-outline1"> + <text:list-level-style-bullet text:level="1" text:bullet-char="•"> + <style:list-level-properties text:space-before="0.008cm" text:min-label-width="0.47cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="2" text:bullet-char="‒"> + <style:list-level-properties text:space-before="0.766cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="3" text:bullet-char="‒"> + <style:list-level-properties text:space-before="1.515cm" text:min-label-width="0.452cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="4" text:bullet-char="‒"> + <style:list-level-properties text:space-before="2.028cm" text:min-label-width="0.47cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="5" text:bullet-char="‒"> + <style:list-level-properties text:space-before="2.786cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="6" text:bullet-char="‒"> + <style:list-level-properties text:space-before="3.561cm" text:min-label-width="0.505cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="7" text:bullet-char="‒"> + <style:list-level-properties text:space-before="4.061cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="8" text:bullet-char="‒"> + <style:list-level-properties text:space-before="9.119cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="9" text:bullet-char="‒"> + <style:list-level-properties text:space-before="10.312cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="10" text:bullet-char="‒"> + <style:list-level-properties text:space-before="11.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + </text:list-style> + </style:graphic-properties> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0.405cm" fo:text-indent="0cm"/> + <style:text-properties fo:color="#000000" style:text-outline="false" style:text-line-through-style="none" style:text-line-through-type="none" style:font-name="Arial1" fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="24pt" fo:font-style="normal" fo:text-shadow="none" style:text-underline-style="none" fo:font-weight="normal" style:letter-kerning="true" style:font-name-asian="Microsoft YaHei" style:font-family-asian="'Microsoft YaHei'" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="32pt" style:font-style-asian="normal" style:font-weight-asian="normal" style:font-name-complex="Mangal" style:font-family-complex="Mangal" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="32pt" style:font-style-complex="normal" style:font-weight-complex="normal" style:text-emphasize="none" style:font-relief="none"/> + </style:style> + <style:style style:name="No-Logo_20_Content-outline2" style:display-name="No-Logo Content-outline2" style:family="presentation" style:parent-style-name="No-Logo_20_Content-outline1"> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0.406cm" fo:text-indent="0cm"/> + <style:text-properties fo:color="#000000" fo:font-size="20pt" style:font-size-asian="28pt" style:font-size-complex="28pt"/> + </style:style> + <style:style style:name="No-Logo_20_Content-outline3" style:display-name="No-Logo Content-outline3" style:family="presentation" style:parent-style-name="No-Logo_20_Content-outline2"> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0.406cm" fo:text-indent="0cm"/> + <style:text-properties fo:color="#000000" fo:font-size="16pt" style:font-size-asian="24pt" style:font-size-complex="24pt"/> + </style:style> + <style:style style:name="No-Logo_20_Content-outline4" style:display-name="No-Logo Content-outline4" style:family="presentation" style:parent-style-name="No-Logo_20_Content-outline3"> + <style:paragraph-properties fo:margin-left="0.266cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0.406cm" fo:text-indent="0cm"/> + <style:text-properties fo:color="#000000" fo:font-size="14pt" style:font-size-asian="20pt" style:font-size-complex="20pt"/> + </style:style> + <style:style style:name="No-Logo_20_Content-outline5" style:display-name="No-Logo Content-outline5" style:family="presentation" style:parent-style-name="No-Logo_20_Content-outline4"> + <style:paragraph-properties fo:margin-left="0.265cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0.406cm" fo:text-indent="0cm"/> + <style:text-properties fo:color="#000000" fo:font-size="12pt" style:font-size-asian="20pt" style:font-size-complex="20pt"/> + </style:style> + <style:style style:name="No-Logo_20_Content-outline6" style:display-name="No-Logo Content-outline6" style:family="presentation" style:parent-style-name="No-Logo_20_Content-outline5"> + <style:paragraph-properties fo:margin-left="0.239cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0.406cm" fo:text-indent="0cm"/> + <style:text-properties fo:color="#000000" fo:font-size="12pt" style:font-size-asian="20pt" style:font-size-complex="20pt"/> + </style:style> + <style:style style:name="No-Logo_20_Content-outline7" style:display-name="No-Logo Content-outline7" style:family="presentation" style:parent-style-name="No-Logo_20_Content-outline6"> + <style:paragraph-properties fo:margin-left="0.505cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0.406cm" fo:text-indent="0cm"/> + <style:text-properties fo:color="#000000" fo:font-size="12pt" style:font-size-asian="20pt" style:font-size-complex="20pt"/> + </style:style> + <style:style style:name="No-Logo_20_Content-outline8" style:display-name="No-Logo Content-outline8" style:family="presentation" style:parent-style-name="No-Logo_20_Content-outline7"> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0.406cm" fo:text-indent="0cm"/> + <style:text-properties fo:color="#000000" fo:font-size="12pt" style:font-size-asian="20pt" style:font-size-complex="20pt"/> + </style:style> + <style:style style:name="No-Logo_20_Content-outline9" style:display-name="No-Logo Content-outline9" style:family="presentation" style:parent-style-name="No-Logo_20_Content-outline8"> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0.406cm" fo:text-indent="0cm"/> + <style:text-properties fo:color="#000000" fo:font-size="12pt" style:font-size-asian="20pt" style:font-size-complex="20pt"/> + </style:style> + <style:style style:name="No-Logo_20_Content-subtitle" style:display-name="No-Logo Content-subtitle" style:family="presentation"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:textarea-vertical-align="middle"> + <text:list-style style:name="No-Logo_20_Content-subtitle" style:display-name="No-Logo Content-subtitle"> + <text:list-level-style-bullet text:level="1" text:bullet-char="●"> + <style:list-level-properties/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="2" text:bullet-char="●"> + <style:list-level-properties text:space-before="0.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="3" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="4" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="5" text:bullet-char="●"> + <style:list-level-properties text:space-before="2.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="6" text:bullet-char="●"> + <style:list-level-properties text:space-before="3cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="7" text:bullet-char="●"> + <style:list-level-properties text:space-before="3.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="8" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="9" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="10" text:bullet-char="●"> + <style:list-level-properties text:space-before="5.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + </text:list-style> + </style:graphic-properties> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-align="center" fo:text-indent="0cm"/> + <style:text-properties style:use-window-font-color="true" style:text-outline="false" style:text-line-through-style="none" style:text-line-through-type="none" style:font-name="Arial1" fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="20pt" fo:font-style="normal" fo:text-shadow="none" style:text-underline-style="none" fo:font-weight="normal" style:letter-kerning="true" style:font-name-asian="Microsoft YaHei" style:font-family-asian="'Microsoft YaHei'" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="32pt" style:font-style-asian="normal" style:font-weight-asian="normal" style:font-name-complex="Mangal" style:font-family-complex="Mangal" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="32pt" style:font-style-complex="normal" style:font-weight-complex="normal" style:text-emphasize="none" style:font-relief="none"/> + </style:style> + <style:style style:name="No-Logo_20_Content-title" style:display-name="No-Logo Content-title" style:family="presentation"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:textarea-vertical-align="middle"> + <text:list-style style:name="No-Logo_20_Content-title" style:display-name="No-Logo Content-title"> + <text:list-level-style-bullet text:level="1" text:bullet-char="●"> + <style:list-level-properties/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="2" text:bullet-char="●"> + <style:list-level-properties text:space-before="0.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="3" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="4" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="5" text:bullet-char="●"> + <style:list-level-properties text:space-before="2.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="6" text:bullet-char="●"> + <style:list-level-properties text:space-before="3cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="7" text:bullet-char="●"> + <style:list-level-properties text:space-before="3.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="8" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="9" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="10" text:bullet-char="●"> + <style:list-level-properties text:space-before="5.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + </text:list-style> + </style:graphic-properties> + <style:paragraph-properties fo:text-align="start"/> + <style:text-properties fo:color="#000000" style:text-outline="false" style:text-line-through-style="none" style:text-line-through-type="none" style:font-name="Arial1" fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="32pt" fo:font-style="normal" fo:text-shadow="none" style:text-underline-style="none" fo:font-weight="bold" style:letter-kerning="true" style:font-name-asian="Microsoft YaHei" style:font-family-asian="'Microsoft YaHei'" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="44pt" style:font-style-asian="normal" style:font-weight-asian="bold" style:font-name-complex="Mangal" style:font-family-complex="Mangal" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="44pt" style:font-style-complex="normal" style:font-weight-complex="bold" style:text-emphasize="none" style:font-relief="none"/> + </style:style> + <style:presentation-page-layout style:name="AL0T26"> + <presentation:placeholder presentation:object="handout" svg:x="2.058cm" svg:y="1.743cm" svg:width="10.556cm" svg:height="-0.233cm"/> + <presentation:placeholder presentation:object="handout" svg:x="15.414cm" svg:y="1.743cm" svg:width="10.556cm" svg:height="-0.233cm"/> + <presentation:placeholder presentation:object="handout" svg:x="2.058cm" svg:y="3.612cm" svg:width="10.556cm" svg:height="-0.233cm"/> + <presentation:placeholder presentation:object="handout" svg:x="15.414cm" svg:y="3.612cm" svg:width="10.556cm" svg:height="-0.233cm"/> + <presentation:placeholder presentation:object="handout" svg:x="2.058cm" svg:y="5.481cm" svg:width="10.556cm" svg:height="-0.233cm"/> + <presentation:placeholder presentation:object="handout" svg:x="15.414cm" svg:y="5.481cm" svg:width="10.556cm" svg:height="-0.233cm"/> + </style:presentation-page-layout> + <style:presentation-page-layout style:name="AL1T1"> + <presentation:placeholder presentation:object="title" svg:x="2.058cm" svg:y="1.743cm" svg:width="23.912cm" svg:height="3.507cm"/> + <presentation:placeholder presentation:object="outline" svg:x="2.058cm" svg:y="5.838cm" svg:width="23.912cm" svg:height="13.23cm"/> + </style:presentation-page-layout> + </office:styles> + <office:automatic-styles> + <style:page-layout style:name="PM0"> + <style:page-layout-properties fo:margin-top="0cm" fo:margin-bottom="0cm" fo:margin-left="0cm" fo:margin-right="0cm" fo:page-width="21.59cm" fo:page-height="27.94cm" style:print-orientation="portrait"/> + </style:page-layout> + <style:page-layout style:name="PM1"> + <style:page-layout-properties fo:margin-top="0cm" fo:margin-bottom="0cm" fo:margin-left="0cm" fo:margin-right="0cm" fo:page-width="25.4cm" fo:page-height="19.05cm" style:print-orientation="landscape"/> + </style:page-layout> + <style:style style:name="dp1" style:family="drawing-page"> + <style:drawing-page-properties draw:background-size="border" draw:fill="none" draw:fill-image-width="0cm" draw:fill-image-height="0cm"/> + </style:style> + <style:style style:name="dp2" style:family="drawing-page"> + <style:drawing-page-properties presentation:display-header="true" presentation:display-footer="true" presentation:display-page-number="false" presentation:display-date-time="true"/> + </style:style> + <style:style style:name="dp3" style:family="drawing-page"> + <style:drawing-page-properties presentation:background-visible="true" presentation:background-objects-visible="true" presentation:display-footer="true" presentation:display-page-number="false" presentation:display-date-time="true"/> + </style:style> + <style:style style:name="gr1" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:fill-color="#ffffff" draw:auto-grow-height="false" fo:min-height="1.397cm" fo:min-width="4.236cm"/> + </style:style> + <style:style style:name="gr2" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:fill-color="#ffffff" draw:auto-grow-height="false" fo:min-height="1.397cm" fo:min-width="5.234cm"/> + </style:style> + <style:style style:name="gr3" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:fill-color="#ffffff" draw:textarea-vertical-align="bottom" draw:auto-grow-height="false" fo:min-height="1.397cm" fo:min-width="3.694cm"/> + </style:style> + <style:style style:name="gr4" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:fill-color="#ffffff" draw:textarea-vertical-align="bottom" draw:auto-grow-height="false" fo:min-height="1.397cm" fo:min-width="4.506cm"/> + </style:style> + <style:style style:name="gr5" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:textarea-horizontal-align="center" draw:textarea-vertical-align="middle" draw:color-mode="standard" draw:luminance="0%" draw:contrast="0%" draw:gamma="100%" draw:red="0%" draw:green="0%" draw:blue="0%" fo:clip="rect(0cm, 0cm, 0cm, 0cm)" draw:image-opacity="100%" style:mirror="none"/> + </style:style> + <style:style style:name="gr6" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" svg:stroke-width="0.076cm" draw:stroke-linejoin="round" draw:fill="none" draw:textarea-vertical-align="top" draw:auto-grow-height="false" fo:padding-top="0.13cm" fo:padding-bottom="0.13cm" fo:padding-left="0.25cm" fo:padding-right="0.25cm" fo:wrap-option="wrap"/> + </style:style> + <style:style style:name="gr7" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:fill-color="#ffffff" draw:textarea-vertical-align="middle" draw:auto-grow-width="true" fo:min-height="0.952cm" fo:min-width="1.78cm"/> + </style:style> + <style:style style:name="gr8" style:family="graphic"> + <style:graphic-properties style:protect="size"/> + </style:style> + <style:style style:name="pr1" style:family="presentation" style:parent-style-name="No-Logo_20_Content-backgroundobjects"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:fill-color="#ffffff" draw:auto-grow-height="false" fo:min-height="1.397cm" fo:min-width="8.869cm"/> + </style:style> + <style:style style:name="pr2" style:family="presentation" style:parent-style-name="No-Logo_20_Content-backgroundobjects"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:fill-color="#ffffff" draw:textarea-vertical-align="bottom" draw:auto-grow-height="false" fo:min-height="1.397cm" fo:min-width="8.869cm"/> + </style:style> + <style:style style:name="pr3" style:family="presentation" style:parent-style-name="No-Logo_20_Content-title"> + <style:graphic-properties draw:auto-grow-height="true" fo:min-height="2.743cm" fo:min-width="21.058cm"/> + </style:style> + <style:style style:name="pr4" style:family="presentation" style:parent-style-name="No-Logo_20_Content-outline1"> + <style:graphic-properties draw:fit-to-size="false" fo:min-height="10.799cm" fo:min-width="10.066cm"/> + </style:style> + <style:style style:name="pr5" style:family="presentation" style:parent-style-name="No-Logo_20_Content-notes"> + <style:graphic-properties draw:fill-color="#ffffff" draw:auto-grow-height="true" fo:min-height="12.572cm" fo:min-width="16.771cm"/> + </style:style> + <style:style style:name="P1" style:family="paragraph"> + <style:text-properties fo:font-size="14pt" style:font-size-asian="14pt" style:font-size-complex="14pt"/> + </style:style> + <style:style style:name="P2" style:family="paragraph"> + <loext:graphic-properties draw:fill="none" draw:fill-color="#ffffff"/> + <style:text-properties fo:font-size="14pt" style:font-size-asian="14pt" style:font-size-complex="14pt"/> + </style:style> + <style:style style:name="P3" style:family="paragraph"> + <style:paragraph-properties fo:text-align="end"/> + <style:text-properties fo:font-size="14pt" style:font-size-asian="14pt" style:font-size-complex="14pt"/> + </style:style> + <style:style style:name="P4" style:family="paragraph"> + <loext:graphic-properties draw:fill="none" draw:fill-color="#ffffff"/> + <style:paragraph-properties fo:text-align="end"/> + <style:text-properties fo:font-size="14pt" style:font-size-asian="14pt" style:font-size-complex="14pt"/> + </style:style> + <style:style style:name="P5" style:family="paragraph"> + <loext:graphic-properties draw:fill="none"/> + <style:paragraph-properties fo:text-align="center"/> + </style:style> + <style:style style:name="P6" style:family="paragraph"> + <loext:graphic-properties draw:fill="none"/> + <style:paragraph-properties fo:text-align="start"/> + <style:text-properties fo:font-size="18pt"/> + </style:style> + <style:style style:name="P7" style:family="paragraph"> + <style:paragraph-properties fo:text-align="center"/> + </style:style> + <style:style style:name="P8" style:family="paragraph"> + <loext:graphic-properties draw:fill="none" draw:fill-color="#ffffff"/> + </style:style> + <style:style style:name="P9" style:family="paragraph"> + <loext:graphic-properties draw:fill-color="#ffffff"/> + </style:style> + <style:style style:name="T1" style:family="text"> + <style:text-properties fo:font-size="14pt" style:font-size-asian="14pt" style:font-size-complex="14pt"/> + </style:style> + <style:style style:name="T2" style:family="text"> + <style:text-properties fo:color="#ffffff" style:font-name="Arial" fo:font-size="11pt" style:font-size-asian="11pt" style:font-size-complex="11pt"/> + </style:style> + <style:style style:name="T3" style:family="text"> + <style:text-properties style:text-position="super 58%"/> + </style:style> + <text:list-style style:name="L1"> + <text:list-level-style-bullet text:level="1" text:bullet-char="●"> + <style:list-level-properties/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="2" text:bullet-char="●"> + <style:list-level-properties text:space-before="0.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="3" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="4" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="5" text:bullet-char="●"> + <style:list-level-properties text:space-before="2.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="6" text:bullet-char="●"> + <style:list-level-properties text:space-before="3cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="7" text:bullet-char="●"> + <style:list-level-properties text:space-before="3.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="8" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="9" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="10" text:bullet-char="●"> + <style:list-level-properties text:space-before="5.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + </text:list-style> + <text:list-style style:name="L2"> + <text:list-level-style-bullet text:level="1" text:bullet-char="●"> + <style:list-level-properties text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="2" text:bullet-char="●"> + <style:list-level-properties text:space-before="0.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="3" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="4" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="5" text:bullet-char="●"> + <style:list-level-properties text:space-before="2.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="6" text:bullet-char="●"> + <style:list-level-properties text:space-before="3cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="7" text:bullet-char="●"> + <style:list-level-properties text:space-before="3.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="8" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="9" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="10" text:bullet-char="●"> + <style:list-level-properties text:space-before="5.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + </text:list-style> + <text:list-style style:name="L3"> + <text:list-level-style-bullet text:level="1" text:bullet-char="•"> + <style:list-level-properties text:space-before="0.008cm" text:min-label-width="0.47cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="2" text:bullet-char="‒"> + <style:list-level-properties text:space-before="0.766cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="3" text:bullet-char="‒"> + <style:list-level-properties text:space-before="1.515cm" text:min-label-width="0.452cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="4" text:bullet-char="‒"> + <style:list-level-properties text:space-before="2.028cm" text:min-label-width="0.47cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="5" text:bullet-char="‒"> + <style:list-level-properties text:space-before="2.786cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="6" text:bullet-char="‒"> + <style:list-level-properties text:space-before="3.561cm" text:min-label-width="0.505cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="7" text:bullet-char="‒"> + <style:list-level-properties text:space-before="4.061cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="8" text:bullet-char="‒"> + <style:list-level-properties text:space-before="9.119cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="9" text:bullet-char="‒"> + <style:list-level-properties text:space-before="10.312cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="10" text:bullet-char="‒"> + <style:list-level-properties text:space-before="11.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="Arial" style:font-style-name="Regular" style:font-family-generic="swiss" fo:color="#000000" fo:font-size="65%"/> + </text:list-level-style-bullet> + </text:list-style> + <text:list-style style:name="L4"> + <text:list-level-style-bullet text:level="1" text:bullet-char="●"> + <style:list-level-properties text:space-before="-0.005cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="2" text:bullet-char="●"> + <style:list-level-properties text:space-before="0.766cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="3" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.51cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="4" text:bullet-char="●"> + <style:list-level-properties text:space-before="2.285cm" text:min-label-width="0.505cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="5" text:bullet-char="●"> + <style:list-level-properties text:space-before="3.056cm" text:min-label-width="0.505cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="6" text:bullet-char="●"> + <style:list-level-properties text:space-before="3.806cm" text:min-label-width="0.473cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="7" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.576cm" text:min-label-width="0.473cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="8" text:bullet-char="●"> + <style:list-level-properties text:space-before="9.127cm" text:min-label-width="0.473cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="9" text:bullet-char="●"> + <style:list-level-properties text:space-before="10.312cm" text:min-label-width="0.473cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="10" text:bullet-char="●"> + <style:list-level-properties text:space-before="11.405cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + </text:list-style> + <text:list-style style:name="L5"> + <text:list-level-style-bullet text:level="1" text:bullet-char="●"> + <style:list-level-properties text:space-before="0.008cm" text:min-label-width="0.47cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="2" text:bullet-char="●"> + <style:list-level-properties text:space-before="0.766cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="3" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.515cm" text:min-label-width="0.452cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="4" text:bullet-char="●"> + <style:list-level-properties text:space-before="2.028cm" text:min-label-width="0.47cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="5" text:bullet-char="●"> + <style:list-level-properties text:space-before="2.786cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="6" text:bullet-char="●"> + <style:list-level-properties text:space-before="3.561cm" text:min-label-width="0.505cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="7" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.061cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="8" text:bullet-char="●"> + <style:list-level-properties text:space-before="9.119cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="9" text:bullet-char="●"> + <style:list-level-properties text:space-before="10.312cm" text:min-label-width="0.483cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="10" text:bullet-char="●"> + <style:list-level-properties text:space-before="11.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:font-charset="x-symbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + </text:list-style> + </office:automatic-styles> + <office:master-styles> + <draw:layer-set> + <draw:layer draw:name="layout"/> + <draw:layer draw:name="background"/> + <draw:layer draw:name="backgroundobjects"/> + <draw:layer draw:name="controls"/> + <draw:layer draw:name="measurelines"/> + </draw:layer-set> + <style:handout-master presentation:presentation-page-layout-name="AL0T26" style:page-layout-name="PM0" draw:style-name="dp2"> + <draw:frame draw:style-name="gr1" draw:text-style-name="P2" draw:layer="backgroundobjects" svg:width="7.133cm" svg:height="1.396cm" svg:x="1.119cm" svg:y="0cm" presentation:class="header"> + <draw:text-box> + <text:p text:style-name="P1"><text:span text:style-name="T1"><presentation:header/></text:span><text:span text:style-name="T1"> </text:span><text:span text:style-name="T1"><presentation:header/></text:span><text:span text:style-name="T1"> </text:span><presentation:header/></text:p> + </draw:text-box> + </draw:frame> + <draw:frame draw:style-name="gr2" draw:text-style-name="P4" draw:layer="backgroundobjects" svg:width="8.63cm" svg:height="1.396cm" svg:x="12.589cm" svg:y="0cm" presentation:class="date-time"> + <draw:text-box> + <text:p text:style-name="P3"><text:span text:style-name="T1"><presentation:date-time/></text:span><text:span text:style-name="T1"> </text:span><text:span text:style-name="T1"><presentation:date-time/></text:span><text:span text:style-name="T1"> </text:span><presentation:date-time/></text:p> + </draw:text-box> + </draw:frame> + <draw:frame draw:style-name="gr3" draw:text-style-name="P2" draw:layer="backgroundobjects" svg:width="6.32cm" svg:height="1.396cm" svg:x="1.525cm" svg:y="26.543cm" presentation:class="footer"> + <draw:text-box> + <text:p text:style-name="P1"><text:span text:style-name="T1"><presentation:footer/></text:span><text:span text:style-name="T1"> </text:span><text:span text:style-name="T1"><presentation:footer/></text:span><text:span text:style-name="T1"> </text:span><presentation:footer/></text:p> + </draw:text-box> + </draw:frame> + <draw:frame draw:style-name="gr4" draw:text-style-name="P4" draw:layer="backgroundobjects" svg:width="7.538cm" svg:height="1.396cm" svg:x="13.135cm" svg:y="26.543cm" presentation:class="page-number"> + <draw:text-box> + <text:p text:style-name="P3"><text:span text:style-name="T1"><text:page-number><number></text:page-number></text:span><text:span text:style-name="T1"> </text:span><text:span text:style-name="T1"><text:page-number><number></text:page-number></text:span><text:span text:style-name="T1"> </text:span><text:page-number><number></text:page-number></text:p> + </draw:text-box> + </draw:frame> + <draw:page-thumbnail draw:layer="backgroundobjects" svg:width="9.294cm" svg:height="6.97cm" svg:x="1cm" svg:y="2.435cm"/> + <draw:page-thumbnail draw:layer="backgroundobjects" svg:width="9.294cm" svg:height="6.97cm" svg:x="1cm" svg:y="10.483cm"/> + <draw:page-thumbnail draw:layer="backgroundobjects" svg:width="9.294cm" svg:height="6.97cm" svg:x="1cm" svg:y="18.531cm"/> + <draw:page-thumbnail draw:layer="backgroundobjects" svg:width="9.294cm" svg:height="6.97cm" svg:x="11.295cm" svg:y="2.435cm"/> + <draw:page-thumbnail draw:layer="backgroundobjects" svg:width="9.294cm" svg:height="6.97cm" svg:x="11.295cm" svg:y="10.483cm"/> + <draw:page-thumbnail draw:layer="backgroundobjects" svg:width="9.294cm" svg:height="6.97cm" svg:x="11.295cm" svg:y="18.531cm"/> + </style:handout-master> + <style:master-page style:name="No-Logo_20_Content" style:display-name="No-Logo Content" style:page-layout-name="PM1" draw:style-name="dp1"> + <draw:frame draw:style-name="gr5" draw:text-style-name="P5" draw:layer="backgroundobjects" svg:width="24.125cm" svg:height="0.792cm" svg:x="0.626cm" svg:y="18.269cm"> + </draw:frame> + <draw:frame presentation:style-name="No-Logo_20_Content-title" draw:layer="backgroundobjects" svg:width="20.93cm" svg:height="2.743cm" svg:x="2.286cm" svg:y="0.711cm" presentation:class="title" presentation:placeholder="true"> + <draw:text-box/> + </draw:frame> + <draw:frame presentation:style-name="No-Logo_20_Content-outline1" draw:layer="backgroundobjects" svg:width="22.859cm" svg:height="11.048cm" svg:x="1.27cm" svg:y="4.457cm" presentation:class="outline" presentation:placeholder="true"> + <draw:text-box/> + </draw:frame> + <draw:frame presentation:style-name="No-Logo_20_Content-outline1" draw:layer="backgroundobjects" svg:width="20.93cm" svg:height="11.049cm" svg:x="2.286cm" svg:y="4.039cm" presentation:class="outline" presentation:placeholder="true"> + <draw:text-box/> + </draw:frame> + <draw:custom-shape draw:name="Text Box 4" draw:style-name="gr6" draw:text-style-name="P6" draw:layer="backgroundobjects" svg:width="16.024cm" svg:height="0.656cm" svg:x="2.403cm" svg:y="18.318cm"> + <text:p/> + <draw:enhanced-geometry svg:viewBox="0 0 21600 21600" draw:type="rectangle" draw:enhanced-path="M 0 0 L 21600 0 21600 21600 0 21600 0 0 Z N"/> + </draw:custom-shape> + <draw:frame draw:style-name="gr7" draw:text-style-name="P8" draw:layer="backgroundobjects" svg:width="2.39cm" svg:height="1.202cm" svg:x="0.305cm" svg:y="18.102cm"> + <draw:text-box> + <text:p text:style-name="P7"><text:span text:style-name="T2"><text:page-number><number></text:page-number></text:span><text:span text:style-name="T2"> </text:span></text:p> + </draw:text-box> + </draw:frame> + <presentation:notes style:page-layout-name="PM0"> + <draw:page-thumbnail presentation:style-name="No-Logo_20_Content-title" draw:layer="backgroundobjects" svg:width="13.97cm" svg:height="10.465cm" svg:x="3.81cm" svg:y="2.134cm" presentation:class="page"/> + <draw:frame presentation:style-name="No-Logo_20_Content-notes" draw:layer="backgroundobjects" svg:width="17.271cm" svg:height="12.572cm" svg:x="2.159cm" svg:y="13.271cm" presentation:class="notes" presentation:placeholder="true"> + <draw:text-box/> + </draw:frame> + <draw:frame presentation:style-name="No-Logo_20_Content-notes" draw:layer="backgroundobjects" svg:width="17.271cm" svg:height="12.572cm" svg:x="2.159cm" svg:y="13.271cm" presentation:class="notes" presentation:placeholder="true"> + <draw:text-box/> + </draw:frame> + <draw:frame presentation:style-name="pr1" draw:text-style-name="P2" draw:layer="backgroundobjects" svg:width="9.369cm" svg:height="1.396cm" svg:x="0cm" svg:y="0cm" presentation:class="header"> + <draw:text-box> + <text:p text:style-name="P1"><text:span text:style-name="T1"><presentation:header/></text:span><text:span text:style-name="T1"> </text:span><text:span text:style-name="T1"><presentation:header/></text:span><text:span text:style-name="T1"> </text:span><presentation:header/></text:p> + </draw:text-box> + </draw:frame> + <draw:frame presentation:style-name="pr1" draw:text-style-name="P4" draw:layer="backgroundobjects" svg:width="9.369cm" svg:height="1.396cm" svg:x="12.22cm" svg:y="0cm" presentation:class="date-time"> + <draw:text-box> + <text:p text:style-name="P3"><text:span text:style-name="T1"><presentation:date-time/></text:span><text:span text:style-name="T1"> </text:span><text:span text:style-name="T1"><presentation:date-time/></text:span><text:span text:style-name="T1"> </text:span><presentation:date-time/></text:p> + </draw:text-box> + </draw:frame> + <draw:frame presentation:style-name="pr2" draw:text-style-name="P2" draw:layer="backgroundobjects" svg:width="9.369cm" svg:height="1.396cm" svg:x="0cm" svg:y="26.543cm" presentation:class="footer"> + <draw:text-box> + <text:p text:style-name="P1"><text:span text:style-name="T1"><presentation:footer/></text:span><text:span text:style-name="T1"> </text:span><text:span text:style-name="T1"><presentation:footer/></text:span><text:span text:style-name="T1"> </text:span><presentation:footer/></text:p> + </draw:text-box> + </draw:frame> + <draw:frame presentation:style-name="pr2" draw:text-style-name="P4" draw:layer="backgroundobjects" svg:width="9.369cm" svg:height="1.396cm" svg:x="12.22cm" svg:y="26.543cm" presentation:class="page-number"> + <draw:text-box> + <text:p text:style-name="P3"><text:span text:style-name="T1"><text:page-number><number></text:page-number></text:span><text:span text:style-name="T1"> </text:span><text:span text:style-name="T1"><text:page-number><number></text:page-number></text:span><text:span text:style-name="T1"> </text:span><text:page-number><number></text:page-number></text:p> + </draw:text-box> + </draw:frame> + </presentation:notes> + </style:master-page> + </office:master-styles> + <office:body> + <office:presentation> + <draw:page draw:name="page1" draw:style-name="dp3" draw:master-page-name="No-Logo_20_Content" presentation:presentation-page-layout-name="AL1T1"> + <office:forms form:automatic-focus="false" form:apply-design-mode="false"/> + <draw:frame presentation:style-name="pr3" draw:layer="layout" svg:width="20.93cm" svg:height="2.743cm" svg:x="2.286cm" svg:y="0.711cm" presentation:class="title" presentation:user-transformed="true"> + <draw:text-box> + <text:p>How to reproduce</text:p> + </draw:text-box> + </draw:frame> + <draw:frame presentation:style-name="pr4" draw:layer="layout" svg:width="20.93cm" svg:height="13.487cm" svg:x="2.286cm" svg:y="4.039cm" presentation:class="outline" presentation:user-transformed="true"> + <draw:text-box> + <text:list text:style-name="L3"> + <text:list-item> + <text:p>This is the 1<text:span text:style-name="T3">st</text:span> level</text:p> + </text:list-item> + </text:list> + <text:list text:style-name="L4"> + <text:list-item> + <text:list> + <text:list-item> + <text:p>These are the 4 bullet points we are focussing on</text:p> + </text:list-item> + </text:list> + </text:list-item> + </text:list> + <text:list text:style-name="L5"> + <text:list-item> + <text:list> + <text:list-item> + <text:p>They have all the same formatting</text:p> + </text:list-item> + </text:list> + </text:list-item> + </text:list> + <text:list text:style-name="L4"> + <text:list-item> + <text:list> + <text:list-item> + <text:p>Simply cut (CTRL+X) and paste (CTRL+V) a line</text:p> + </text:list-item> + <text:list-item> + <text:p>And see what happens. But bullet point changes format</text:p> + </text:list-item> + </text:list> + </text:list-item> + </text:list> + </draw:text-box> + </draw:frame> + <presentation:notes draw:style-name="dp2"> + <draw:page-thumbnail draw:style-name="gr8" draw:layer="layout" svg:width="13.97cm" svg:height="10.465cm" svg:x="3.81cm" svg:y="2.134cm" draw:page-number="1" presentation:class="page"/> + <draw:frame presentation:style-name="pr5" draw:text-style-name="P9" draw:layer="layout" svg:width="17.271cm" svg:height="12.572cm" svg:x="2.159cm" svg:y="13.271cm" presentation:class="notes" presentation:placeholder="true" presentation:user-transformed="true"> + <draw:text-box/> + </draw:frame> + </presentation:notes> + </draw:page> + <presentation:settings presentation:mouse-visible="false"/> + </office:presentation> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sd/qa/unit/tiledrendering/data/tdf104405.fodp b/sd/qa/unit/tiledrendering/data/tdf104405.fodp new file mode 100644 index 0000000000..d902f177d5 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/tdf104405.fodp @@ -0,0 +1,822 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:smil="urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.presentation"> + <office:meta><meta:creation-date>2016-11-16T15:27:08.222708354</meta:creation-date><dc:date>2016-11-16T15:30:23.342583235</dc:date><meta:editing-duration>PT3M18S</meta:editing-duration><meta:editing-cycles>1</meta:editing-cycles><meta:document-statistic meta:object-count="26"/><meta:generator>LibreOfficeDev/5.3.0.0.alpha1$Linux_X86_64 LibreOffice_project/f0c20dc458d8fe9e86b323c8c24df2f3d31610ad</meta:generator></office:meta> + <office:settings> + <config:config-item-set config:name="ooo:view-settings"> + <config:config-item config:name="VisibleAreaTop" config:type="int">0</config:config-item> + <config:config-item config:name="VisibleAreaLeft" config:type="int">0</config:config-item> + <config:config-item config:name="VisibleAreaWidth" config:type="int">14099</config:config-item> + <config:config-item config:name="VisibleAreaHeight" config:type="int">9999</config:config-item> + <config:config-item-map-indexed config:name="Views"> + <config:config-item-map-entry> + <config:config-item config:name="ViewId" config:type="string">view1</config:config-item> + <config:config-item config:name="GridIsVisible" config:type="boolean">false</config:config-item> + <config:config-item config:name="GridIsFront" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsSnapToGrid" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsSnapToPageMargins" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsSnapToSnapLines" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsSnapToObjectFrame" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsSnapToObjectPoints" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPlusHandlesAlwaysVisible" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsFrameDragSingles" config:type="boolean">true</config:config-item> + <config:config-item config:name="EliminatePolyPointLimitAngle" config:type="int">1500</config:config-item> + <config:config-item config:name="IsEliminatePolyPoints" config:type="boolean">false</config:config-item> + <config:config-item config:name="VisibleLayers" config:type="base64Binary">//////////////////////////////////////////8=</config:config-item> + <config:config-item config:name="PrintableLayers" config:type="base64Binary">//////////////////////////////////////////8=</config:config-item> + <config:config-item config:name="LockedLayers" config:type="base64Binary"/> + <config:config-item config:name="NoAttribs" config:type="boolean">false</config:config-item> + <config:config-item config:name="NoColors" config:type="boolean">true</config:config-item> + <config:config-item config:name="RulerIsVisible" config:type="boolean">false</config:config-item> + <config:config-item config:name="PageKind" config:type="short">0</config:config-item> + <config:config-item config:name="SelectedPage" config:type="short">0</config:config-item> + <config:config-item config:name="IsLayerMode" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsDoubleClickTextEdit" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsClickChangeRotation" config:type="boolean">true</config:config-item> + <config:config-item config:name="SlidesPerRow" config:type="short">4</config:config-item> + <config:config-item config:name="EditMode" config:type="int">0</config:config-item> + <config:config-item config:name="VisibleAreaTop" config:type="int">-310</config:config-item> + <config:config-item config:name="VisibleAreaLeft" config:type="int">-2139</config:config-item> + <config:config-item config:name="VisibleAreaWidth" config:type="int">32314</config:config-item> + <config:config-item config:name="VisibleAreaHeight" config:type="int">21646</config:config-item> + <config:config-item config:name="GridCoarseWidth" config:type="int">2000</config:config-item> + <config:config-item config:name="GridCoarseHeight" config:type="int">2000</config:config-item> + <config:config-item config:name="GridFineWidth" config:type="int">200</config:config-item> + <config:config-item config:name="GridFineHeight" config:type="int">200</config:config-item> + <config:config-item config:name="GridSnapWidthXNumerator" config:type="int">200</config:config-item> + <config:config-item config:name="GridSnapWidthXDenominator" config:type="int">1</config:config-item> + <config:config-item config:name="GridSnapWidthYNumerator" config:type="int">200</config:config-item> + <config:config-item config:name="GridSnapWidthYDenominator" config:type="int">1</config:config-item> + <config:config-item config:name="IsAngleSnapEnabled" config:type="boolean">false</config:config-item> + <config:config-item config:name="SnapAngle" config:type="int">1500</config:config-item> + <config:config-item config:name="ZoomOnPage" config:type="boolean">true</config:config-item> + <config:config-item config:name="AnchoredTextOverflowLegacy" config:type="boolean">false</config:config-item> + </config:config-item-map-entry> + </config:config-item-map-indexed> + </config:config-item-set> + <config:config-item-set config:name="ooo:configuration-settings"> + <config:config-item config:name="ApplyUserData" config:type="boolean">true</config:config-item> + <config:config-item config:name="BitmapTableURL" config:type="string">$(inst)/share/palette%3B$(user)/config/standard.sob</config:config-item> + <config:config-item config:name="CharacterCompressionType" config:type="short">0</config:config-item> + <config:config-item config:name="ColorTableURL" config:type="string">$(inst)/share/palette%3B$(user)/config/standard.soc</config:config-item> + <config:config-item config:name="DashTableURL" config:type="string">$(inst)/share/palette%3B$(user)/config/standard.sod</config:config-item> + <config:config-item config:name="DefaultTabStop" config:type="int">1250</config:config-item> + <config:config-item config:name="EmbedFonts" config:type="boolean">false</config:config-item> + <config:config-item-map-indexed config:name="ForbiddenCharacters"> + <config:config-item-map-entry> + <config:config-item config:name="Language" config:type="string">en</config:config-item> + <config:config-item config:name="Country" config:type="string">ZA</config:config-item> + <config:config-item config:name="Variant" config:type="string"/> + <config:config-item config:name="BeginLine" config:type="string"/> + <config:config-item config:name="EndLine" config:type="string"/> + </config:config-item-map-entry> + </config:config-item-map-indexed> + <config:config-item config:name="GradientTableURL" config:type="string">$(inst)/share/palette%3B$(user)/config/standard.sog</config:config-item> + <config:config-item config:name="HandoutsHorizontal" config:type="boolean">true</config:config-item> + <config:config-item config:name="HatchTableURL" config:type="string">$(inst)/share/palette%3B$(user)/config/standard.soh</config:config-item> + <config:config-item config:name="IsKernAsianPunctuation" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintBooklet" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintBookletBack" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsPrintBookletFront" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsPrintDate" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintDrawing" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsPrintFitPage" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintHandout" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintHiddenPages" config:type="boolean">true</config:config-item> + <config:config-item config:name="IsPrintNotes" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintOutline" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintPageName" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintTilePage" config:type="boolean">false</config:config-item> + <config:config-item config:name="IsPrintTime" config:type="boolean">false</config:config-item> + <config:config-item config:name="LineEndTableURL" config:type="string">$(inst)/share/palette%3B$(user)/config/standard.soe</config:config-item> + <config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item> + <config:config-item config:name="PageNumberFormat" config:type="int">4</config:config-item> + <config:config-item config:name="ParagraphSummation" config:type="boolean">false</config:config-item> + <config:config-item config:name="PrintQuality" config:type="int">0</config:config-item> + <config:config-item config:name="PrinterIndependentLayout" config:type="string">low-resolution</config:config-item> + <config:config-item config:name="PrinterName" config:type="string"/> + <config:config-item config:name="PrinterSetup" config:type="base64Binary"/> + <config:config-item config:name="SaveVersionOnClose" config:type="boolean">false</config:config-item> + <config:config-item config:name="SlidesPerHandout" config:type="short">6</config:config-item> + <config:config-item config:name="UpdateFromTemplate" config:type="boolean">true</config:config-item> + </config:config-item-set> + </office:settings> + <office:scripts> + <office:script script:language="ooo:Basic"> + <ooo:libraries xmlns:ooo="http://openoffice.org/2004/office" xmlns:xlink="http://www.w3.org/1999/xlink"/> + </office:script> + </office:scripts> + <office:font-face-decls> + <style:font-face style:name="Liberation Sans" svg:font-family="'Liberation Sans'" style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="DejaVu Sans" svg:font-family="'DejaVu Sans'" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="FreeSans" svg:font-family="FreeSans" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="Noto Sans CJK SC Regular" svg:font-family="'Noto Sans CJK SC Regular'" style:font-family-generic="system" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <draw:marker draw:name="Arrow" svg:viewBox="0 0 20 30" svg:d="M10 0l-10 30h20z"/> + <style:default-style style:family="graphic"> + <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap"/> + <style:paragraph-properties style:text-autospace="ideograph-alpha" style:punctuation-wrap="simple" style:line-break="strict" style:writing-mode="lr-tb" style:font-independent-line-spacing="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:use-window-font-color="true" style:font-name="Liberation Serif" fo:font-size="24pt" fo:language="en" fo:country="ZA" style:font-name-asian="DejaVu Sans" style:font-size-asian="24pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="DejaVu Sans" style:font-size-complex="24pt" style:language-complex="hi" style:country-complex="IN"/> + </style:default-style> + <style:style style:name="standard" style:family="graphic"> + <style:graphic-properties draw:stroke="solid" svg:stroke-width="0cm" svg:stroke-color="#3465a4" draw:marker-start-width="0.2cm" draw:marker-start-center="false" draw:marker-end-width="0.2cm" draw:marker-end-center="false" draw:fill="solid" draw:fill-color="#729fcf" draw:textarea-horizontal-align="justify" fo:padding-top="0.125cm" fo:padding-bottom="0.125cm" fo:padding-left="0.25cm" fo:padding-right="0.25cm" draw:shadow="hidden" draw:shadow-offset-x="0.2cm" draw:shadow-offset-y="0.2cm" draw:shadow-color="#808080"> + <text:list-style style:name="standard"> + <text:list-level-style-bullet text:level="1" text:bullet-char="●"> + <style:list-level-properties text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="2" text:bullet-char="●"> + <style:list-level-properties text:space-before="0.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="3" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="4" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="5" text:bullet-char="●"> + <style:list-level-properties text:space-before="2.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="6" text:bullet-char="●"> + <style:list-level-properties text:space-before="3cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="7" text:bullet-char="●"> + <style:list-level-properties text:space-before="3.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="8" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="9" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="10" text:bullet-char="●"> + <style:list-level-properties text:space-before="5.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + </text:list-style> + </style:graphic-properties> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" fo:line-height="100%" fo:text-indent="0cm"/> + <style:text-properties fo:font-variant="normal" fo:text-transform="none" style:use-window-font-color="true" style:text-outline="false" style:text-line-through-style="none" style:text-line-through-type="none" style:font-name="Liberation Sans" fo:font-family="'Liberation Sans'" style:font-family-generic="roman" style:font-pitch="variable" fo:font-size="18pt" fo:font-style="normal" fo:text-shadow="none" style:text-underline-style="none" fo:font-weight="normal" style:letter-kerning="true" style:font-name-asian="Noto Sans CJK SC Regular" style:font-family-asian="'Noto Sans CJK SC Regular'" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="18pt" style:font-style-asian="normal" style:font-weight-asian="normal" style:font-name-complex="FreeSans" style:font-family-complex="FreeSans" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="18pt" style:font-style-complex="normal" style:font-weight-complex="normal" style:text-emphasize="none" style:font-relief="none" style:text-overline-style="none" style:text-overline-color="font-color"/> + </style:style> + <style:style style:name="objectwitharrow" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="solid" svg:stroke-width="0.15cm" svg:stroke-color="#000000" draw:marker-start="Arrow" draw:marker-start-width="0.7cm" draw:marker-start-center="true" draw:marker-end-width="0.3cm"/> + </style:style> + <style:style style:name="objectwithshadow" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:shadow="visible" draw:shadow-offset-x="0.2cm" draw:shadow-offset-y="0.2cm" draw:shadow-color="#808080"/> + </style:style> + <style:style style:name="objectwithoutfill" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties svg:stroke-color="#000000" draw:fill="none"/> + </style:style> + <style:style style:name="Object_20_with_20_no_20_fill_20_and_20_no_20_line" style:display-name="Object with no fill and no line" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + </style:style> + <style:style style:name="text" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + </style:style> + <style:style style:name="textbody" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:text-properties fo:font-size="16pt"/> + </style:style> + <style:style style:name="textbodyjustfied" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:paragraph-properties fo:text-align="justify"/> + </style:style> + <style:style style:name="textbodyindent" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0.6cm"/> + </style:style> + <style:style style:name="title" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:text-properties fo:font-size="44pt"/> + </style:style> + <style:style style:name="title1" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="solid" draw:fill-color="#008080" draw:shadow="visible" draw:shadow-offset-x="0.2cm" draw:shadow-offset-y="0.2cm" draw:shadow-color="#808080"/> + <style:paragraph-properties fo:text-align="center"/> + <style:text-properties fo:font-size="24pt"/> + </style:style> + <style:style style:name="title2" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties svg:stroke-width="0.05cm" draw:fill-color="#ffcc99" draw:shadow="visible" draw:shadow-offset-x="0.2cm" draw:shadow-offset-y="0.2cm" draw:shadow-color="#808080"/> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0.2cm" fo:margin-top="0.1cm" fo:margin-bottom="0.1cm" fo:text-align="center" fo:text-indent="0cm"/> + <style:text-properties fo:font-size="36pt"/> + </style:style> + <style:style style:name="headline" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:paragraph-properties fo:margin-top="0.42cm" fo:margin-bottom="0.21cm"/> + <style:text-properties fo:font-size="24pt"/> + </style:style> + <style:style style:name="headline1" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:paragraph-properties fo:margin-top="0.42cm" fo:margin-bottom="0.21cm"/> + <style:text-properties fo:font-size="18pt" fo:font-weight="bold"/> + </style:style> + <style:style style:name="headline2" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:paragraph-properties fo:margin-top="0.42cm" fo:margin-bottom="0.21cm"/> + <style:text-properties fo:font-size="14pt" fo:font-style="italic" fo:font-weight="bold"/> + </style:style> + <style:style style:name="measure" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="solid" svg:stroke-color="#000000" draw:marker-start="Arrow" draw:marker-start-width="0.2cm" draw:marker-end="Arrow" draw:marker-end-width="0.2cm" draw:fill="none" draw:show-unit="true"/> + <style:text-properties fo:font-size="12pt"/> + </style:style> + <style:style style:name="default" style:family="table-cell"> + <loext:graphic-properties draw:fill="solid" draw:fill-color="#ccccff" draw:textarea-horizontal-align="left" draw:textarea-vertical-align="top" fo:padding-top="0.13cm" fo:padding-bottom="0.13cm" fo:padding-left="0.25cm" fo:padding-right="0.25cm"/> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" fo:line-height="100%" fo:text-indent="0cm" fo:border="0.03pt solid #ffffff"/> + <style:text-properties style:use-window-font-color="true" style:font-name="Liberation Sans" fo:font-family="'Liberation Sans'" style:font-family-generic="roman" style:font-pitch="variable" fo:font-size="18pt" style:letter-kerning="true" style:font-name-asian="Noto Sans CJK SC Regular" style:font-family-asian="'Noto Sans CJK SC Regular'" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="18pt" style:font-name-complex="FreeSans" style:font-family-complex="FreeSans" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="18pt"/> + </style:style> + <style:style style:name="gray1" style:family="table-cell" style:parent-style-name="default"> + <loext:graphic-properties draw:fill="solid" draw:fill-color="#e6e6e6"/> + </style:style> + <style:style style:name="gray2" style:family="table-cell" style:parent-style-name="default"> + <loext:graphic-properties draw:fill="solid" draw:fill-color="#cccccc"/> + </style:style> + <style:style style:name="gray3" style:family="table-cell" style:parent-style-name="default"> + <loext:graphic-properties draw:fill="solid" draw:fill-color="#b3b3b3"/> + </style:style> + <table:table-template text:style-name="default"> + <table:first-row table:style-name="gray3"/> + <table:last-row table:style-name="gray3"/> + <table:first-column table:style-name="gray3"/> + <table:last-column table:style-name="gray3"/> + <table:body table:style-name="gray1"/> + <table:odd-rows table:style-name="gray2"/> + <table:odd-columns table:style-name="gray2"/> + </table:table-template> + <style:style style:name="Default-background" style:family="presentation"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:text-properties style:letter-kerning="true"/> + </style:style> + <style:style style:name="Default-backgroundobjects" style:family="presentation"> + <style:graphic-properties draw:textarea-horizontal-align="justify" draw:shadow="hidden" draw:shadow-offset-x="0.2cm" draw:shadow-offset-y="0.2cm" draw:shadow-color="#808080"/> + <style:text-properties style:letter-kerning="true"/> + </style:style> + <style:style style:name="Default-notes" style:family="presentation"> + <style:graphic-properties draw:stroke="none" draw:fill="none"/> + <style:paragraph-properties fo:margin-left="0.6cm" fo:margin-right="0cm" fo:text-indent="-0.6cm"/> + <style:text-properties fo:font-variant="normal" fo:text-transform="none" style:use-window-font-color="true" style:text-outline="false" style:text-line-through-style="none" style:text-line-through-type="none" style:font-name="Liberation Sans" fo:font-family="'Liberation Sans'" style:font-family-generic="roman" style:font-pitch="variable" fo:font-size="20pt" fo:font-style="normal" fo:text-shadow="none" style:text-underline-style="none" fo:font-weight="normal" style:letter-kerning="true" fo:background-color="transparent" style:font-name-asian="Noto Sans CJK SC Regular" style:font-family-asian="'Noto Sans CJK SC Regular'" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="20pt" style:font-style-asian="normal" style:font-weight-asian="normal" style:font-name-complex="FreeSans" style:font-family-complex="FreeSans" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="20pt" style:font-style-complex="normal" style:font-weight-complex="normal" style:text-emphasize="none" style:font-relief="none" style:text-overline-style="none" style:text-overline-color="font-color"/> + </style:style> + <style:style style:name="Default-outline1" style:family="presentation"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:auto-grow-height="false" draw:fit-to-size="shrink-to-fit"> + <text:list-style style:name="Default-outline1"> + <text:list-level-style-bullet text:level="1" text:bullet-char="●"> + <style:list-level-properties text:space-before="0.3cm" text:min-label-width="0.9cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="2" text:bullet-char="–"> + <style:list-level-properties text:space-before="1.5cm" text:min-label-width="0.9cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="75%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="3" text:bullet-char="●"> + <style:list-level-properties text:space-before="2.8cm" text:min-label-width="0.8cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="4" text:bullet-char="–"> + <style:list-level-properties text:space-before="4.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="75%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="5" text:bullet-char="●"> + <style:list-level-properties text:space-before="5.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="6" text:bullet-char="●"> + <style:list-level-properties text:space-before="6.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="7" text:bullet-char="●"> + <style:list-level-properties text:space-before="7.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="8" text:bullet-char="●"> + <style:list-level-properties text:space-before="9cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="9" text:bullet-char="●"> + <style:list-level-properties text:space-before="10.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="10" text:bullet-char="●"> + <style:list-level-properties text:space-before="11.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + </text:list-style> + </style:graphic-properties> + <style:paragraph-properties fo:margin-top="0.5cm" fo:margin-bottom="0cm"/> + <style:text-properties fo:font-variant="normal" fo:text-transform="none" style:use-window-font-color="true" style:text-outline="false" style:text-line-through-style="none" style:text-line-through-type="none" style:font-name="Liberation Sans" fo:font-family="'Liberation Sans'" style:font-family-generic="roman" style:font-pitch="variable" fo:font-size="32pt" fo:font-style="normal" fo:text-shadow="none" style:text-underline-style="none" fo:font-weight="normal" style:letter-kerning="true" fo:background-color="transparent" style:font-name-asian="Noto Sans CJK SC Regular" style:font-family-asian="'Noto Sans CJK SC Regular'" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="32pt" style:font-style-asian="normal" style:font-weight-asian="normal" style:font-name-complex="FreeSans" style:font-family-complex="FreeSans" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="32pt" style:font-style-complex="normal" style:font-weight-complex="normal" style:text-emphasize="none" style:font-relief="none" style:text-overline-style="none" style:text-overline-color="font-color"/> + </style:style> + <style:style style:name="Default-outline2" style:family="presentation" style:parent-style-name="Default-outline1"> + <style:paragraph-properties fo:margin-top="0.4cm" fo:margin-bottom="0cm"/> + <style:text-properties fo:font-size="28pt" style:font-size-asian="28pt" style:font-size-complex="28pt"/> + </style:style> + <style:style style:name="Default-outline3" style:family="presentation" style:parent-style-name="Default-outline2"> + <style:paragraph-properties fo:margin-top="0.3cm" fo:margin-bottom="0cm"/> + <style:text-properties fo:font-size="24pt" style:font-size-asian="24pt" style:font-size-complex="24pt"/> + </style:style> + <style:style style:name="Default-outline4" style:family="presentation" style:parent-style-name="Default-outline3"> + <style:paragraph-properties fo:margin-top="0.2cm" fo:margin-bottom="0cm"/> + <style:text-properties fo:font-size="20pt" style:font-size-asian="20pt" style:font-size-complex="20pt"/> + </style:style> + <style:style style:name="Default-outline5" style:family="presentation" style:parent-style-name="Default-outline4"> + <style:paragraph-properties fo:margin-top="0.1cm" fo:margin-bottom="0cm"/> + <style:text-properties fo:font-size="20pt" style:font-size-asian="20pt" style:font-size-complex="20pt"/> + </style:style> + <style:style style:name="Default-outline6" style:family="presentation" style:parent-style-name="Default-outline5"> + <style:paragraph-properties fo:margin-top="0.1cm" fo:margin-bottom="0cm"/> + <style:text-properties fo:font-size="20pt" style:font-size-asian="20pt" style:font-size-complex="20pt"/> + </style:style> + <style:style style:name="Default-outline7" style:family="presentation" style:parent-style-name="Default-outline6"> + <style:paragraph-properties fo:margin-top="0.1cm" fo:margin-bottom="0cm"/> + <style:text-properties fo:font-size="20pt" style:font-size-asian="20pt" style:font-size-complex="20pt"/> + </style:style> + <style:style style:name="Default-outline8" style:family="presentation" style:parent-style-name="Default-outline7"> + <style:paragraph-properties fo:margin-top="0.1cm" fo:margin-bottom="0cm"/> + <style:text-properties fo:font-size="20pt" style:font-size-asian="20pt" style:font-size-complex="20pt"/> + </style:style> + <style:style style:name="Default-outline9" style:family="presentation" style:parent-style-name="Default-outline8"> + <style:paragraph-properties fo:margin-top="0.1cm" fo:margin-bottom="0cm"/> + <style:text-properties fo:font-size="20pt" style:font-size-asian="20pt" style:font-size-complex="20pt"/> + </style:style> + <style:style style:name="Default-subtitle" style:family="presentation"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:textarea-vertical-align="middle"> + <text:list-style style:name="Default-subtitle"> + <text:list-level-style-bullet text:level="1" text:bullet-char="●"> + <style:list-level-properties text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="2" text:bullet-char="●"> + <style:list-level-properties text:space-before="0.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="3" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="4" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="5" text:bullet-char="●"> + <style:list-level-properties text:space-before="2.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="6" text:bullet-char="●"> + <style:list-level-properties text:space-before="3cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="7" text:bullet-char="●"> + <style:list-level-properties text:space-before="3.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="8" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="9" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="10" text:bullet-char="●"> + <style:list-level-properties text:space-before="5.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + </text:list-style> + </style:graphic-properties> + <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-align="center" fo:text-indent="0cm"/> + <style:text-properties fo:font-variant="normal" fo:text-transform="none" style:use-window-font-color="true" style:text-outline="false" style:text-line-through-style="none" style:text-line-through-type="none" style:font-name="Liberation Sans" fo:font-family="'Liberation Sans'" style:font-family-generic="roman" style:font-pitch="variable" fo:font-size="32pt" fo:font-style="normal" fo:text-shadow="none" style:text-underline-style="none" fo:font-weight="normal" style:letter-kerning="true" fo:background-color="transparent" style:font-name-asian="Noto Sans CJK SC Regular" style:font-family-asian="'Noto Sans CJK SC Regular'" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="32pt" style:font-style-asian="normal" style:font-weight-asian="normal" style:font-name-complex="FreeSans" style:font-family-complex="FreeSans" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="32pt" style:font-style-complex="normal" style:font-weight-complex="normal" style:text-emphasize="none" style:font-relief="none" style:text-overline-style="none" style:text-overline-color="font-color"/> + </style:style> + <style:style style:name="Default-title" style:family="presentation"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:textarea-vertical-align="middle"> + <text:list-style style:name="Default-title"> + <text:list-level-style-bullet text:level="1" text:bullet-char="●"> + <style:list-level-properties text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="2" text:bullet-char="●"> + <style:list-level-properties text:space-before="0.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="3" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="4" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="5" text:bullet-char="●"> + <style:list-level-properties text:space-before="2.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="6" text:bullet-char="●"> + <style:list-level-properties text:space-before="3cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="7" text:bullet-char="●"> + <style:list-level-properties text:space-before="3.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="8" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="9" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="10" text:bullet-char="●"> + <style:list-level-properties text:space-before="5.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + </text:list-style> + </style:graphic-properties> + <style:paragraph-properties fo:text-align="center"/> + <style:text-properties fo:font-variant="normal" fo:text-transform="none" style:use-window-font-color="true" style:text-outline="false" style:text-line-through-style="none" style:text-line-through-type="none" style:font-name="Liberation Sans" fo:font-family="'Liberation Sans'" style:font-family-generic="roman" style:font-pitch="variable" fo:font-size="44pt" fo:font-style="normal" fo:text-shadow="none" style:text-underline-style="none" fo:font-weight="normal" style:letter-kerning="true" fo:background-color="transparent" style:font-name-asian="Noto Sans CJK SC Regular" style:font-family-asian="'Noto Sans CJK SC Regular'" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="44pt" style:font-style-asian="normal" style:font-weight-asian="normal" style:font-name-complex="FreeSans" style:font-family-complex="FreeSans" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="44pt" style:font-style-complex="normal" style:font-weight-complex="normal" style:text-emphasize="none" style:font-relief="none" style:text-overline-style="none" style:text-overline-color="font-color"/> + </style:style> + <style:presentation-page-layout style:name="AL0T26"> + <presentation:placeholder presentation:object="handout" svg:x="2.058cm" svg:y="1.743cm" svg:width="10.556cm" svg:height="-0.233cm"/> + <presentation:placeholder presentation:object="handout" svg:x="15.414cm" svg:y="1.743cm" svg:width="10.556cm" svg:height="-0.233cm"/> + <presentation:placeholder presentation:object="handout" svg:x="2.058cm" svg:y="3.612cm" svg:width="10.556cm" svg:height="-0.233cm"/> + <presentation:placeholder presentation:object="handout" svg:x="15.414cm" svg:y="3.612cm" svg:width="10.556cm" svg:height="-0.233cm"/> + <presentation:placeholder presentation:object="handout" svg:x="2.058cm" svg:y="5.481cm" svg:width="10.556cm" svg:height="-0.233cm"/> + <presentation:placeholder presentation:object="handout" svg:x="15.414cm" svg:y="5.481cm" svg:width="10.556cm" svg:height="-0.233cm"/> + </style:presentation-page-layout> + <style:presentation-page-layout style:name="AL1T0"> + <presentation:placeholder presentation:object="title" svg:x="2.058cm" svg:y="1.743cm" svg:width="23.912cm" svg:height="3.507cm"/> + <presentation:placeholder presentation:object="subtitle" svg:x="2.058cm" svg:y="5.838cm" svg:width="23.912cm" svg:height="13.23cm"/> + </style:presentation-page-layout> + </office:styles> + <office:automatic-styles> + <style:page-layout style:name="PM0"> + <style:page-layout-properties fo:margin-top="0cm" fo:margin-bottom="0cm" fo:margin-left="0cm" fo:margin-right="0cm" fo:page-width="21cm" fo:page-height="29.7cm" style:print-orientation="portrait"/> + </style:page-layout> + <style:page-layout style:name="PM1"> + <style:page-layout-properties fo:margin-top="0cm" fo:margin-bottom="0cm" fo:margin-left="0cm" fo:margin-right="0cm" fo:page-width="28cm" fo:page-height="21cm" style:print-orientation="landscape"/> + </style:page-layout> + <style:style style:name="dp1" style:family="drawing-page"> + <style:drawing-page-properties draw:background-size="border" draw:fill="none"/> + </style:style> + <style:style style:name="dp2" style:family="drawing-page"> + <style:drawing-page-properties presentation:display-header="true" presentation:display-footer="true" presentation:display-page-number="false" presentation:display-date-time="true"/> + </style:style> + <style:style style:name="dp3" style:family="drawing-page"> + <style:drawing-page-properties presentation:background-visible="true" presentation:background-objects-visible="true" presentation:display-footer="true" presentation:display-page-number="false" presentation:display-date-time="true"/> + </style:style> + <style:style style:name="gr1" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:fill-color="#ffffff" draw:auto-grow-height="false" fo:min-height="1.485cm"/> + </style:style> + <style:style style:name="gr2" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:fill-color="#ffffff" draw:textarea-vertical-align="bottom" draw:auto-grow-height="false" fo:min-height="1.485cm"/> + </style:style> + <style:style style:name="gr3" style:family="graphic"> + <style:graphic-properties style:protect="size"/> + </style:style> + <style:style style:name="pr1" style:family="presentation" style:parent-style-name="Default-backgroundobjects"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:fill-color="#ffffff" draw:auto-grow-height="false" fo:min-height="1.449cm"/> + </style:style> + <style:style style:name="pr2" style:family="presentation" style:parent-style-name="Default-backgroundobjects"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:fill-color="#ffffff" draw:auto-grow-height="false" fo:min-height="1.485cm"/> + </style:style> + <style:style style:name="pr3" style:family="presentation" style:parent-style-name="Default-backgroundobjects"> + <style:graphic-properties draw:stroke="none" draw:fill="none" draw:fill-color="#ffffff" draw:textarea-vertical-align="bottom" draw:auto-grow-height="false" fo:min-height="1.485cm"/> + </style:style> + <style:style style:name="pr4" style:family="presentation" style:parent-style-name="Default-title"> + <style:graphic-properties fo:min-height="3.506cm"/> + </style:style> + <style:style style:name="pr5" style:family="presentation" style:parent-style-name="Default-subtitle"> + <style:graphic-properties draw:fill-color="#ffffff" fo:min-height="12.179cm"/> + </style:style> + <style:style style:name="pr6" style:family="presentation" style:parent-style-name="Default-notes"> + <style:graphic-properties draw:fill-color="#ffffff" fo:min-height="13.364cm"/> + </style:style> + <style:style style:name="co1" style:family="table-column"> + <style:table-column-properties style:column-width="4.758cm" style:use-optimal-column-width="false"/> + </style:style> + <style:style style:name="co2" style:family="table-column"> + <style:table-column-properties style:column-width="4.767cm" style:use-optimal-column-width="false"/> + </style:style> + <style:style style:name="ro1" style:family="table-row"> + <style:table-row-properties style:row-height="2.848cm"/> + </style:style> + <style:style style:name="ro2" style:family="table-row"> + <style:table-row-properties style:row-height="2.855cm"/> + </style:style> + <style:style style:name="ce1" style:family="table-cell"> + <style:paragraph-properties fo:text-align="center"/> + </style:style> + <style:style style:name="ce2" style:family="table-cell"> + <loext:graphic-properties draw:textarea-vertical-align="bottom"/> + <style:paragraph-properties fo:text-align="center"/> + </style:style> + <style:style style:name="P1" style:family="paragraph"> + <style:text-properties fo:font-size="14pt" style:font-size-asian="14pt" style:font-size-complex="14pt"/> + </style:style> + <style:style style:name="P2" style:family="paragraph"> + <loext:graphic-properties draw:fill="none" draw:fill-color="#ffffff"/> + <style:text-properties fo:font-size="14pt" style:font-size-asian="14pt" style:font-size-complex="14pt"/> + </style:style> + <style:style style:name="P3" style:family="paragraph"> + <style:paragraph-properties fo:text-align="end"/> + <style:text-properties fo:font-size="14pt" style:font-size-asian="14pt" style:font-size-complex="14pt"/> + </style:style> + <style:style style:name="P4" style:family="paragraph"> + <loext:graphic-properties draw:fill="none" draw:fill-color="#ffffff"/> + <style:paragraph-properties fo:text-align="end"/> + <style:text-properties fo:font-size="14pt" style:font-size-asian="14pt" style:font-size-complex="14pt"/> + </style:style> + <style:style style:name="P5" style:family="paragraph"> + <style:paragraph-properties fo:text-align="center"/> + <style:text-properties fo:font-size="14pt" style:font-size-asian="14pt" style:font-size-complex="14pt"/> + </style:style> + <style:style style:name="P6" style:family="paragraph"> + <loext:graphic-properties draw:fill="none" draw:fill-color="#ffffff"/> + <style:paragraph-properties fo:text-align="center"/> + <style:text-properties fo:font-size="14pt" style:font-size-asian="14pt" style:font-size-complex="14pt"/> + </style:style> + <style:style style:name="P7" style:family="paragraph"> + <loext:graphic-properties draw:fill-color="#ffffff"/> + </style:style> + <style:style style:name="P8" style:family="paragraph"> + <style:paragraph-properties fo:text-align="center"/> + </style:style> + <text:list-style style:name="L1"> + <text:list-level-style-bullet text:level="1" text:bullet-char="●"> + <style:list-level-properties text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="2" text:bullet-char="●"> + <style:list-level-properties text:space-before="0.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="3" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="4" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="5" text:bullet-char="●"> + <style:list-level-properties text:space-before="2.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="6" text:bullet-char="●"> + <style:list-level-properties text:space-before="3cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="7" text:bullet-char="●"> + <style:list-level-properties text:space-before="3.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="8" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="9" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="10" text:bullet-char="●"> + <style:list-level-properties text:space-before="5.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + </text:list-style> + <text:list-style style:name="L2"> + <text:list-level-style-bullet text:level="1" text:bullet-char="●"> + <style:list-level-properties text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="2" text:bullet-char="●"> + <style:list-level-properties text:space-before="0.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="3" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="4" text:bullet-char="●"> + <style:list-level-properties text:space-before="1.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="5" text:bullet-char="●"> + <style:list-level-properties text:space-before="2.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="6" text:bullet-char="●"> + <style:list-level-properties text:space-before="3cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="7" text:bullet-char="●"> + <style:list-level-properties text:space-before="3.6cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="8" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.2cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="9" text:bullet-char="●"> + <style:list-level-properties text:space-before="4.8cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + <text:list-level-style-bullet text:level="10" text:bullet-char="●"> + <style:list-level-properties text:space-before="5.4cm" text:min-label-width="0.6cm"/> + <style:text-properties fo:font-family="StarSymbol" style:use-window-font-color="true" fo:font-size="45%"/> + </text:list-level-style-bullet> + </text:list-style> + </office:automatic-styles> + <office:master-styles> + <draw:layer-set> + <draw:layer draw:name="layout"/> + <draw:layer draw:name="background"/> + <draw:layer draw:name="backgroundobjects"/> + <draw:layer draw:name="controls"/> + <draw:layer draw:name="measurelines"/> + </draw:layer-set> + <style:handout-master presentation:presentation-page-layout-name="AL0T26" style:page-layout-name="PM0" draw:style-name="dp2"> + <draw:page-thumbnail draw:layer="backgroundobjects" svg:width="8.999cm" svg:height="6.749cm" svg:x="1cm" svg:y="2.898cm"/> + <draw:page-thumbnail draw:layer="backgroundobjects" svg:width="8.999cm" svg:height="6.749cm" svg:x="1cm" svg:y="11.474cm"/> + <draw:page-thumbnail draw:layer="backgroundobjects" svg:width="8.999cm" svg:height="6.749cm" svg:x="1cm" svg:y="20.05cm"/> + <draw:page-thumbnail draw:layer="backgroundobjects" svg:width="8.999cm" svg:height="6.749cm" svg:x="11cm" svg:y="2.898cm"/> + <draw:page-thumbnail draw:layer="backgroundobjects" svg:width="8.999cm" svg:height="6.749cm" svg:x="11cm" svg:y="11.474cm"/> + <draw:page-thumbnail draw:layer="backgroundobjects" svg:width="8.999cm" svg:height="6.749cm" svg:x="11cm" svg:y="20.05cm"/> + <draw:frame draw:style-name="gr1" draw:text-style-name="P2" draw:layer="backgroundobjects" svg:width="9.113cm" svg:height="1.484cm" svg:x="0cm" svg:y="0cm" presentation:class="header"> + <draw:text-box> + <text:p text:style-name="P1"><presentation:header/></text:p> + </draw:text-box> + </draw:frame> + <draw:frame draw:style-name="gr1" draw:text-style-name="P4" draw:layer="backgroundobjects" svg:width="9.113cm" svg:height="1.484cm" svg:x="11.886cm" svg:y="0cm" presentation:class="date-time"> + <draw:text-box> + <text:p text:style-name="P3"><presentation:date-time/></text:p> + </draw:text-box> + </draw:frame> + <draw:frame draw:style-name="gr2" draw:text-style-name="P2" draw:layer="backgroundobjects" svg:width="9.113cm" svg:height="1.484cm" svg:x="0cm" svg:y="28.215cm" presentation:class="footer"> + <draw:text-box> + <text:p text:style-name="P1"><presentation:footer/></text:p> + </draw:text-box> + </draw:frame> + <draw:frame draw:style-name="gr2" draw:text-style-name="P4" draw:layer="backgroundobjects" svg:width="9.113cm" svg:height="1.484cm" svg:x="11.886cm" svg:y="28.215cm" presentation:class="page-number"> + <draw:text-box> + <text:p text:style-name="P3"><text:page-number><number></text:page-number></text:p> + </draw:text-box> + </draw:frame> + </style:handout-master> + <style:master-page style:name="Default" style:page-layout-name="PM1" draw:style-name="dp1"> + <draw:frame presentation:style-name="Default-title" draw:layer="backgroundobjects" svg:width="25.199cm" svg:height="3.506cm" svg:x="1.4cm" svg:y="0.837cm" presentation:class="title" presentation:placeholder="true"> + <draw:text-box/> + </draw:frame> + <draw:frame presentation:style-name="Default-outline1" draw:layer="backgroundobjects" svg:width="25.199cm" svg:height="12.179cm" svg:x="1.4cm" svg:y="4.914cm" presentation:class="outline" presentation:placeholder="true"> + <draw:text-box/> + </draw:frame> + <draw:frame presentation:style-name="pr1" draw:text-style-name="P2" draw:layer="backgroundobjects" svg:width="6.523cm" svg:height="1.448cm" svg:x="1.4cm" svg:y="19.131cm" presentation:class="date-time"> + <draw:text-box> + <text:p text:style-name="P1"><presentation:date-time/></text:p> + </draw:text-box> + </draw:frame> + <draw:frame presentation:style-name="pr1" draw:text-style-name="P6" draw:layer="backgroundobjects" svg:width="8.875cm" svg:height="1.448cm" svg:x="9.576cm" svg:y="19.131cm" presentation:class="footer"> + <draw:text-box> + <text:p text:style-name="P5"><presentation:footer/></text:p> + </draw:text-box> + </draw:frame> + <draw:frame presentation:style-name="pr1" draw:text-style-name="P4" draw:layer="backgroundobjects" svg:width="6.523cm" svg:height="1.448cm" svg:x="20.076cm" svg:y="19.131cm" presentation:class="page-number"> + <draw:text-box> + <text:p text:style-name="P3"><text:page-number><number></text:page-number></text:p> + </draw:text-box> + </draw:frame> + <presentation:notes style:page-layout-name="PM0"> + <draw:page-thumbnail presentation:style-name="Default-title" draw:layer="backgroundobjects" svg:width="14.848cm" svg:height="11.136cm" svg:x="3.075cm" svg:y="2.257cm" presentation:class="page"/> + <draw:frame presentation:style-name="Default-notes" draw:layer="backgroundobjects" svg:width="16.799cm" svg:height="13.364cm" svg:x="2.1cm" svg:y="14.107cm" presentation:class="notes" presentation:placeholder="true"> + <draw:text-box/> + </draw:frame> + <draw:frame presentation:style-name="pr2" draw:text-style-name="P2" draw:layer="backgroundobjects" svg:width="9.113cm" svg:height="1.484cm" svg:x="0cm" svg:y="0cm" presentation:class="header"> + <draw:text-box> + <text:p text:style-name="P1"><presentation:header/></text:p> + </draw:text-box> + </draw:frame> + <draw:frame presentation:style-name="pr2" draw:text-style-name="P4" draw:layer="backgroundobjects" svg:width="9.113cm" svg:height="1.484cm" svg:x="11.886cm" svg:y="0cm" presentation:class="date-time"> + <draw:text-box> + <text:p text:style-name="P3"><presentation:date-time/></text:p> + </draw:text-box> + </draw:frame> + <draw:frame presentation:style-name="pr3" draw:text-style-name="P2" draw:layer="backgroundobjects" svg:width="9.113cm" svg:height="1.484cm" svg:x="0cm" svg:y="28.215cm" presentation:class="footer"> + <draw:text-box> + <text:p text:style-name="P1"><presentation:footer/></text:p> + </draw:text-box> + </draw:frame> + <draw:frame presentation:style-name="pr3" draw:text-style-name="P4" draw:layer="backgroundobjects" svg:width="9.113cm" svg:height="1.484cm" svg:x="11.886cm" svg:y="28.215cm" presentation:class="page-number"> + <draw:text-box> + <text:p text:style-name="P3"><text:page-number><number></text:page-number></text:p> + </draw:text-box> + </draw:frame> + </presentation:notes> + </style:master-page> + </office:master-styles> + <office:body> + <office:presentation> + <draw:page draw:name="page1" draw:style-name="dp3" draw:master-page-name="Default" presentation:presentation-page-layout-name="AL1T0"> + <draw:frame presentation:style-name="pr4" draw:layer="layout" svg:width="25.199cm" svg:height="3.506cm" svg:x="1.4cm" svg:y="0.837cm" presentation:class="title" presentation:placeholder="true"> + <draw:text-box/> + </draw:frame> + <draw:frame presentation:style-name="pr5" draw:text-style-name="P7" draw:layer="layout" svg:width="25.199cm" svg:height="12.179cm" svg:x="1.4cm" svg:y="4.914cm" presentation:class="subtitle" presentation:placeholder="true"> + <draw:text-box/> + </draw:frame> + <draw:frame draw:style-name="standard" draw:layer="layout" svg:width="23.798cm" svg:height="11.398cm" svg:x="1.8cm" svg:y="5.4cm"> + <table:table table:template-name="default" table:use-first-row-styles="true" table:use-banding-rows-styles="true"> + <table:table-column table:style-name="co1"/> + <table:table-column table:style-name="co1"/> + <table:table-column table:style-name="co1"/> + <table:table-column table:style-name="co1"/> + <table:table-column table:style-name="co2"/> + <table:table-row table:style-name="ro1" table:default-cell-style-name="gray3"> + <table:table-cell> + <text:p>aaa</text:p> + </table:table-cell> + <table:table-cell> + <text:p>aa</text:p> + </table:table-cell> + <table:table-cell table:style-name="ce1"> + <text:p text:style-name="P8">aaaa</text:p> + </table:table-cell> + <table:table-cell> + <text:p>aaaaa</text:p> + </table:table-cell> + <table:table-cell> + <text:p>aaaa</text:p> + </table:table-cell> + </table:table-row> + <table:table-row table:style-name="ro1" table:default-cell-style-name="gray2"> + <table:table-cell> + <text:p>aaa</text:p> + </table:table-cell> + <table:table-cell> + <text:p>aaa</text:p> + </table:table-cell> + <table:table-cell table:style-name="ce2"> + <text:p text:style-name="P8">aaa</text:p> + </table:table-cell> + <table:table-cell> + <text:p>aaa</text:p> + </table:table-cell> + <table:table-cell> + <text:p>aaaaaa</text:p> + </table:table-cell> + </table:table-row> + <table:table-row table:style-name="ro1" table:default-cell-style-name="gray1"> + <table:table-cell> + <text:p>aaa</text:p> + </table:table-cell> + <table:table-cell> + <text:p>aaaaa</text:p> + </table:table-cell> + <table:table-cell> + <text:p>aaa</text:p> + </table:table-cell> + <table:table-cell> + <text:p>aaaa</text:p> + </table:table-cell> + <table:table-cell> + <text:p>aaaaaa</text:p> + </table:table-cell> + </table:table-row> + <table:table-row table:style-name="ro2" table:default-cell-style-name="gray2"> + <table:table-cell> + <text:p>aaa</text:p> + </table:table-cell> + <table:table-cell> + <text:p>aaaaaa</text:p> + </table:table-cell> + <table:table-cell> + <text:p>aaa</text:p> + </table:table-cell> + <table:table-cell> + <text:p>aaa</text:p> + </table:table-cell> + <table:table-cell> + <text:p>aaa</text:p> + </table:table-cell> + </table:table-row> + </table:table><draw:image> + <office:binary-data>iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAAEElEQVR4nGJgAQAAAP//AwAA + BgAFV7+r1AAAAABJRU5ErkJggg== + </office:binary-data> + </draw:image> + </draw:frame> + <presentation:notes draw:style-name="dp2"> + <draw:page-thumbnail draw:style-name="gr3" draw:layer="layout" svg:width="14.848cm" svg:height="11.136cm" svg:x="3.075cm" svg:y="2.257cm" draw:page-number="1" presentation:class="page"/> + <draw:frame presentation:style-name="pr6" draw:text-style-name="P7" draw:layer="layout" svg:width="16.799cm" svg:height="13.364cm" svg:x="2.1cm" svg:y="14.107cm" presentation:class="notes" presentation:placeholder="true"> + <draw:text-box/> + </draw:frame> + </presentation:notes> + </draw:page> + <presentation:settings presentation:mouse-visible="false"/> + </office:presentation> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sd/qa/unit/tiledrendering/data/tdf105502.odp b/sd/qa/unit/tiledrendering/data/tdf105502.odp Binary files differnew file mode 100644 index 0000000000..2150f1152b --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/tdf105502.odp diff --git a/sd/qa/unit/tiledrendering/data/tdf115783.fodp b/sd/qa/unit/tiledrendering/data/tdf115783.fodp new file mode 100644 index 0000000000..d9ada63ad1 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/tdf115783.fodp @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:smil="urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.presentation"> + <office:font-face-decls> + <style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="swiss" style:font-pitch="variable"/> + </office:font-face-decls> + <office:automatic-styles> + <style:style style:name="co1" style:family="table-column"> + <style:table-column-properties style:column-width="4.3cm" style:use-optimal-column-width="false"/> + </style:style> + <style:style style:name="co2" style:family="table-column"> + <style:table-column-properties style:column-width="6.241cm" style:use-optimal-column-width="false"/> + </style:style> + <style:style style:name="co3" style:family="table-column"> + <style:table-column-properties style:column-width="4.909cm" style:use-optimal-column-width="false"/> + </style:style> + <style:style style:name="ro1" style:family="table-row"> + <style:table-row-properties style:row-height="1.364cm"/> + </style:style> + <style:style style:name="ce1" style:family="table-cell"> + <loext:graphic-properties draw:fill="none" style:repeat="repeat"/> + <style:paragraph-properties fo:border="0.03pt solid #000000"/> + <style:text-properties style:font-name="Arial" fo:font-size="12pt"/> + </style:style> + <style:style style:name="T1" style:family="text"> + <style:text-properties style:font-name="Arial" fo:font-size="12pt"/> + </style:style> + </office:automatic-styles> + <office:body> + <office:presentation> + <draw:page draw:name="page1"> + <draw:frame draw:style-name="standard" draw:layer="layout" svg:width="15.449cm" svg:height="1.363cm" svg:x="2.179cm" svg:y="3.302cm"> + <table:table table:template-name="default"> + <table:table-column table:style-name="co1"/> + <table:table-column table:style-name="co2"/> + <table:table-column table:style-name="co3"/> + <table:table-row table:style-name="ro1" table:default-cell-style-name="ce1"> + <table:table-cell> + <text:p><text:span text:style-name="T1">before</text:span></text:p> + </table:table-cell> + <table:table-cell> + <text:p><text:span text:style-name="T1">hello</text:span></text:p> + </table:table-cell> + <table:table-cell> + <text:p><text:span text:style-name="T1">after</text:span></text:p> + </table:table-cell> + </table:table-row> + </table:table> + </draw:frame> + </draw:page> + </office:presentation> + </office:body> +</office:document> diff --git a/sd/qa/unit/tiledrendering/data/tdf115873-group.fodp b/sd/qa/unit/tiledrendering/data/tdf115873-group.fodp new file mode 100644 index 0000000000..603ec4c7e5 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/tdf115873-group.fodp @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:smil="urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.presentation"> + <office:automatic-styles> + <style:style style:name="dp1" style:family="drawing-page"> + </style:style> + <style:style style:name="gr1" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:textarea-horizontal-align="justify" draw:textarea-vertical-align="middle" draw:auto-grow-height="false" fo:min-height="2.15cm" fo:min-width="1.3cm"/> + </style:style> + <style:style style:name="gr2" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:textarea-horizontal-align="justify" draw:textarea-vertical-align="middle" draw:auto-grow-height="false" fo:min-height="1.55cm" fo:min-width="1.3cm"/> + </style:style> + <style:style style:name="gr3" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:textarea-horizontal-align="justify" draw:textarea-vertical-align="middle" draw:auto-grow-height="false" fo:min-height="1.55cm" fo:min-width="2.1cm"/> + </style:style> + </office:automatic-styles> + <office:body> + <office:presentation> + <draw:page draw:name="page1" draw:style-name="dp1"> + <draw:g draw:name="Group 1"> + <draw:custom-shape draw:name="Rectangle 1" draw:style-name="gr1" draw:layer="layout" svg:width="1.8cm" svg:height="2.4cm" svg:x="2.8cm" svg:y="2.8cm"> + <text:p/> + <draw:enhanced-geometry svg:viewBox="0 0 21600 21600" draw:type="rectangle" draw:enhanced-path="M 0 0 L 21600 0 21600 21600 0 21600 0 0 Z N"/> + </draw:custom-shape> + <draw:custom-shape draw:name="Rectangle 2" draw:style-name="gr2" draw:layer="layout" svg:width="1.8cm" svg:height="1.8cm" svg:x="6cm" svg:y="3.2cm"> + <text:p/> + <draw:enhanced-geometry svg:viewBox="0 0 21600 21600" draw:type="rectangle" draw:enhanced-path="M 0 0 L 21600 0 21600 21600 0 21600 0 0 Z N"/> + </draw:custom-shape> + </draw:g> + <draw:custom-shape draw:name="Rectangle 3" draw:style-name="gr3" draw:layer="layout" svg:width="2.6cm" svg:height="1.8cm" svg:x="4.6cm" svg:y="7.4cm"> + <text:p/> + <draw:enhanced-geometry svg:viewBox="0 0 21600 21600" draw:type="rectangle" draw:enhanced-path="M 0 0 L 21600 0 21600 21600 0 21600 0 0 Z N"/> + </draw:custom-shape> + </draw:page> + </office:presentation> + </office:body> +</office:document> diff --git a/sd/qa/unit/tiledrendering/data/tdf115873.fodp b/sd/qa/unit/tiledrendering/data/tdf115873.fodp new file mode 100644 index 0000000000..1633a04714 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/tdf115873.fodp @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:smil="urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0" xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.presentation"> + <office:font-face-decls> + <style:font-face style:name="Liberation Sans" svg:font-family="'Liberation Sans'" style:font-family-generic="roman" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <style:default-style style:family="graphic"> + <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap"/> + <style:paragraph-properties style:text-autospace="ideograph-alpha" style:punctuation-wrap="simple" style:line-break="strict" style:font-independent-line-spacing="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:use-window-font-color="true" style:font-name="Liberation Sans" fo:font-size="24pt" fo:language="en" fo:country="US" style:font-size-asian="24pt" style:language-asian="zh" style:country-asian="CN" style:font-size-complex="24pt" style:language-complex="hi" style:country-complex="IN"/> + </style:default-style> + </office:styles> + <office:automatic-styles> + <style:style style:name="gr1" style:family="graphic" style:parent-style-name="standard"> + <style:graphic-properties draw:textarea-horizontal-align="justify" draw:textarea-vertical-align="middle" draw:auto-grow-height="false" fo:min-height="2.544cm" fo:min-width="4.58cm"/> + </style:style> + </office:automatic-styles> + <office:body> + <office:presentation> + <draw:page draw:name="page1"> + <draw:custom-shape draw:name="Rectangle" draw:style-name="gr1" draw:layer="layout" svg:width="5.08cm" svg:height="2.794cm" svg:x="12.954cm" svg:y="7.62cm"> + <draw:enhanced-geometry svg:viewBox="0 0 21600 21600" draw:type="rectangle" draw:enhanced-path="M 0 0 L 21600 0 21600 21600 0 21600 0 0 Z N"/> + </draw:custom-shape> + </draw:page> + </office:presentation> + </office:body> +</office:document> diff --git a/sd/qa/unit/tiledrendering/data/tdf118354.odp b/sd/qa/unit/tiledrendering/data/tdf118354.odp Binary files differnew file mode 100644 index 0000000000..beb132c7e3 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/tdf118354.odp diff --git a/sd/qa/unit/tiledrendering/data/tdf81754.pptx b/sd/qa/unit/tiledrendering/data/tdf81754.pptx Binary files differnew file mode 100644 index 0000000000..8a1fa1dcfd --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/tdf81754.pptx diff --git a/sd/qa/unit/tiledrendering/data/title-shape.odp b/sd/qa/unit/tiledrendering/data/title-shape.odp Binary files differnew file mode 100644 index 0000000000..15d39d68e1 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/title-shape.odp diff --git a/sd/qa/unit/tiledrendering/tiledrendering.cxx b/sd/qa/unit/tiledrendering/tiledrendering.cxx new file mode 100644 index 0000000000..31d61c1fb1 --- /dev/null +++ b/sd/qa/unit/tiledrendering/tiledrendering.cxx @@ -0,0 +1,2947 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <test/unoapixml_test.hxx> + +#include <app.hrc> +#include <test/helper/transferable.hxx> +#include <boost/property_tree/json_parser.hpp> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> +#include <sal/log.hxx> +#include <sfx2/lokhelper.hxx> +#include <comphelper/propertysequence.hxx> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/string.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/editids.hrc> +#include <editeng/editobj.hxx> +#include <editeng/editview.hxx> +#include <editeng/numitem.hxx> +#include <editeng/outliner.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/outlobj.hxx> +#include <osl/conditn.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <svl/stritem.hxx> +#include <svl/intitem.hxx> +#include <comphelper/lok.hxx> +#include <svx/svdotable.hxx> +#include <svx/svdoutl.hxx> +#include <unotools/datetime.hxx> +#include <test/lokcallback.hxx> + +#include <DrawDocShell.hxx> +#include <ViewShellBase.hxx> +#include <ViewShell.hxx> +#include <sdpage.hxx> +#include <unomodel.hxx> +#include <drawdoc.hxx> +#include <undo/undomanager.hxx> +#include <sfx2/request.hxx> +#include <svx/svxids.hrc> +#include <pres.hxx> +#include <navigatr.hxx> +#include <vcl/cursor.hxx> +#include <vcl/scheduler.hxx> +#include <vcl/vclevent.hxx> +#include <vcl/BitmapReadAccess.hxx> +#include <vcl/virdev.hxx> +#include <o3tl/string_view.hxx> + +#include <chrono> +#include <cstdlib> +#include <string_view> + +using namespace css; + +static std::ostream& operator<<(std::ostream& os, ViewShellId id) +{ + os << static_cast<sal_Int32>(id); + return os; +} + +class SdTiledRenderingTest : public UnoApiXmlTest +{ +public: + SdTiledRenderingTest(); + virtual void setUp() override; + virtual void tearDown() override; + +protected: + SdXImpressDocument* createDoc(const char* pName, const uno::Sequence<beans::PropertyValue>& rArguments = uno::Sequence<beans::PropertyValue>()); + void setupLibreOfficeKitViewCallback(SfxViewShell& pViewShell); + static void callback(int nType, const char* pPayload, void* pData); + void callbackImpl(int nType, const char* pPayload); + xmlDocUniquePtr parseXmlDump(); + + ::tools::Rectangle m_aInvalidation; + std::vector<::tools::Rectangle> m_aSelection; + bool m_bFound; + sal_Int32 m_nPart; + std::vector<OString> m_aSearchResultSelection; + std::vector<int> m_aSearchResultPart; + int m_nSelectionBeforeSearchResult; + int m_nSelectionAfterSearchResult; + + /// For document size changed callback. + osl::Condition m_aDocumentSizeCondition; + xmlBufferPtr m_pXmlBuffer; + TestLokCallbackWrapper m_callbackWrapper; +}; + +SdTiledRenderingTest::SdTiledRenderingTest() + : UnoApiXmlTest("/sd/qa/unit/tiledrendering/data/"), + m_bFound(true), + m_nPart(0), + m_nSelectionBeforeSearchResult(0), + m_nSelectionAfterSearchResult(0), + m_pXmlBuffer(nullptr), + m_callbackWrapper(&callback, this) +{ +} + +void SdTiledRenderingTest::setUp() +{ + UnoApiXmlTest::setUp(); + + // prevent showing warning message box + setenv("OOX_NO_SMARTART_WARNING", "1", 1); + comphelper::LibreOfficeKit::setActive(true); +} + +void SdTiledRenderingTest::tearDown() +{ + if (mxComponent.is()) + { + mxComponent->dispose(); + mxComponent.clear(); + } + + if (m_pXmlBuffer) + xmlBufferFree(m_pXmlBuffer); + + m_callbackWrapper.clear(); + comphelper::LibreOfficeKit::setActive(false); + + UnoApiXmlTest::tearDown(); +} + +SdXImpressDocument* SdTiledRenderingTest::createDoc(const char* pName, const uno::Sequence<beans::PropertyValue>& rArguments) +{ + loadFromFile(OUString::createFromAscii(pName)); + SdXImpressDocument* pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get()); + CPPUNIT_ASSERT(pImpressDocument); + pImpressDocument->initializeForTiledRendering(rArguments); + return pImpressDocument; +} + +void SdTiledRenderingTest::setupLibreOfficeKitViewCallback(SfxViewShell& pViewShell) +{ + pViewShell.setLibreOfficeKitViewCallback(&m_callbackWrapper); + m_callbackWrapper.setLOKViewId(SfxLokHelper::getView(&pViewShell)); +} + +void SdTiledRenderingTest::callback(int nType, const char* pPayload, void* pData) +{ + static_cast<SdTiledRenderingTest*>(pData)->callbackImpl(nType, pPayload); +} + +namespace +{ + +std::vector<OUString> lcl_convertSeparated(std::u16string_view rString, sal_Unicode nSeparator) +{ + std::vector<OUString> aRet; + + sal_Int32 nIndex = 0; + do + { + OUString aToken( o3tl::trim(o3tl::getToken(rString, 0, nSeparator, nIndex)) ); + if (!aToken.isEmpty()) + aRet.push_back(aToken); + } + while (nIndex >= 0); + + return aRet; +} + +void lcl_convertRectangle(std::u16string_view rString, ::tools::Rectangle& rRectangle) +{ + uno::Sequence<OUString> aSeq = comphelper::string::convertCommaSeparated(rString); + CPPUNIT_ASSERT(aSeq.getLength() == 4 || aSeq.getLength() == 5); + rRectangle.SetLeft(aSeq[0].toInt32()); + rRectangle.SetTop(aSeq[1].toInt32()); + rRectangle.setWidth(aSeq[2].toInt32()); + rRectangle.setHeight(aSeq[3].toInt32()); +} + +} // end anonymous namespace + +void SdTiledRenderingTest::callbackImpl(int nType, const char* pPayload) +{ + switch (nType) + { + case LOK_CALLBACK_INVALIDATE_TILES: + { + OUString aPayload = OUString::createFromAscii(pPayload); + if (aPayload != "EMPTY" && m_aInvalidation.IsEmpty()) + lcl_convertRectangle(aPayload, m_aInvalidation); + } + break; + case LOK_CALLBACK_TEXT_SELECTION: + { + OUString aPayload = OUString::createFromAscii(pPayload); + m_aSelection.clear(); + for (const OUString& rString : lcl_convertSeparated(aPayload, u';')) + { + ::tools::Rectangle aRectangle; + lcl_convertRectangle(rString, aRectangle); + m_aSelection.push_back(aRectangle); + } + if (m_aSearchResultSelection.empty()) + ++m_nSelectionBeforeSearchResult; + else + ++m_nSelectionAfterSearchResult; + } + break; + case LOK_CALLBACK_SEARCH_NOT_FOUND: + { + m_bFound = false; + } + break; + case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED: + { + m_aDocumentSizeCondition.set(); + } + break; + case LOK_CALLBACK_SET_PART: + { + OUString aPayload = OUString::createFromAscii(pPayload); + m_nPart = aPayload.toInt32(); + } + break; + case LOK_CALLBACK_SEARCH_RESULT_SELECTION: + { + m_aSearchResultSelection.clear(); + m_aSearchResultPart.clear(); + boost::property_tree::ptree aTree; + std::stringstream aStream(pPayload); + boost::property_tree::read_json(aStream, aTree); + for (const boost::property_tree::ptree::value_type& rValue : aTree.get_child("searchResultSelection")) + { + m_aSearchResultSelection.emplace_back(rValue.second.get<std::string>("rectangles").c_str()); + m_aSearchResultPart.push_back(std::atoi(rValue.second.get<std::string>("part").c_str())); + } + } + break; + } +} + +xmlDocUniquePtr SdTiledRenderingTest::parseXmlDump() +{ + if (m_pXmlBuffer) + xmlBufferFree(m_pXmlBuffer); + + // Create the xml writer. + m_pXmlBuffer = xmlBufferCreate(); + xmlTextWriterPtr pXmlWriter = xmlNewTextWriterMemory(m_pXmlBuffer, 0); + (void)xmlTextWriterStartDocument(pXmlWriter, nullptr, nullptr, nullptr); + + // Create the dump. + SdXImpressDocument* pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get()); + CPPUNIT_ASSERT(pImpressDocument); + pImpressDocument->GetDoc()->dumpAsXml(pXmlWriter); + + // Delete the xml writer. + (void)xmlTextWriterEndDocument(pXmlWriter); + xmlFreeTextWriter(pXmlWriter); + + auto pCharBuffer = xmlBufferContent(m_pXmlBuffer); + SAL_INFO("test", "SdTiledRenderingTest::parseXmlDump: pCharBuffer is '" << pCharBuffer << "'"); + return xmlDocUniquePtr(xmlParseDoc(pCharBuffer)); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testCreateDestroy) +{ + createDoc("dummy.odp"); + // Nothing to do, the tearDown call should cleanup. +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testCreateView) +{ + createDoc("dummy.odp"); + + SfxLokHelper::createView(); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testRegisterCallback) +{ + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + setupLibreOfficeKitViewCallback(pViewShell->GetViewShellBase()); + + // Start text edit of the empty title shape. + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(0); + SdrView* pView = pViewShell->GetView(); + pView->SdrBeginTextEdit(pObject); + CPPUNIT_ASSERT(pView->GetTextEditObject()); + + // Check that the top left 256x256px tile would be invalidated. + CPPUNIT_ASSERT(!m_aInvalidation.IsEmpty()); + ::tools::Rectangle aTopLeft(0, 0, 256*15, 256*15); // 1 px = 15 twips, assuming 96 DPI. + CPPUNIT_ASSERT(m_aInvalidation.Overlaps(aTopLeft)); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testPostKeyEvent) +{ + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(0); + CPPUNIT_ASSERT_EQUAL(SdrObjKind::TitleText, pObject->GetObjIdentifier()); + SdrTextObj* pTextObj = static_cast<SdrTextObj*>(pObject); + SdrView* pView = pViewShell->GetView(); + pView->MarkObj(pTextObj, pView->GetSdrPageView()); + SfxStringItem aInputString(SID_ATTR_CHAR, "x"); + pViewShell->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR, + SfxCallMode::SYNCHRON, { &aInputString }); + + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0); + Scheduler::ProcessEventsToIdle(); + + CPPUNIT_ASSERT(pView->GetTextEditObject()); + EditView& rEditView = pView->GetTextEditOutlinerView()->GetEditView(); + // Did we manage to enter a second character? + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), rEditView.GetSelection().nStartPos); + ESelection aWordSelection(0, 0, 0, 2); // start para, start char, end para, end char. + rEditView.SetSelection(aWordSelection); + // Did we enter the expected character? + CPPUNIT_ASSERT_EQUAL(OUString("xx"), rEditView.GetSelected()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testPostMouseEvent) +{ + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(0); + CPPUNIT_ASSERT_EQUAL(SdrObjKind::TitleText, pObject->GetObjIdentifier()); + SdrTextObj* pTextObj = static_cast<SdrTextObj*>(pObject); + SdrView* pView = pViewShell->GetView(); + pView->MarkObj(pTextObj, pView->GetSdrPageView()); + SfxStringItem aInputString(SID_ATTR_CHAR, "x"); + pViewShell->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR, + SfxCallMode::SYNCHRON, { &aInputString }); + CPPUNIT_ASSERT(pView->GetTextEditObject()); + EditView& rEditView = pView->GetTextEditOutlinerView()->GetEditView(); + // Did we manage to go after the first character? + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), rEditView.GetSelection().nStartPos); + + vcl::Cursor* pCursor = rEditView.GetCursor(); + Point aPosition(pCursor->GetPos().getX(), pCursor->GetPos().getY() + pCursor->GetSize().Height() / 2); + aPosition.setX(aPosition.getX() - 1000); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, + o3tl::toTwips(aPosition.getX(), o3tl::Length::mm100), o3tl::toTwips(aPosition.getY(), o3tl::Length::mm100), + 1, MOUSE_LEFT, 0); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, + o3tl::toTwips(aPosition.getX(), o3tl::Length::mm100), o3tl::toTwips(aPosition.getY(), o3tl::Length::mm100), + 1, MOUSE_LEFT, 0); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(pView->GetTextEditObject()); + // The new cursor position must be before the first word. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), rEditView.GetSelection().nStartPos); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testSetTextSelection) +{ + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + uno::Reference<container::XIndexAccess> xDrawPage(pXImpressDocument->getDrawPages()->getByIndex(0), uno::UNO_QUERY); + uno::Reference<text::XTextRange> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + xShape->setString("Aaa bbb."); + // Create a selection on the second word. + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(0); + SdrView* pView = pViewShell->GetView(); + pView->SdrBeginTextEdit(pObject); + CPPUNIT_ASSERT(pView->GetTextEditObject()); + EditView& rEditView = pView->GetTextEditOutlinerView()->GetEditView(); + ESelection aWordSelection(0, 4, 0, 7); + rEditView.SetSelection(aWordSelection); + // Did we indeed manage to select the second word? + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), rEditView.GetSelected()); + + // Now use setTextSelection() to move the end of the selection 1000 twips right. + vcl::Cursor* pCursor = rEditView.GetCursor(); + Point aEnd = pCursor->GetPos(); + aEnd.setX(aEnd.getX() + 1000); + pXImpressDocument->setTextSelection(LOK_SETTEXTSELECTION_END, aEnd.getX(), aEnd.getY()); + // The new selection must include the ending dot, too -- but not the first word. + CPPUNIT_ASSERT_EQUAL(OUString("bbb."), rEditView.GetSelected()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testGetTextSelection) +{ + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + uno::Reference<container::XIndexAccess> xDrawPage(pXImpressDocument->getDrawPages()->getByIndex(0), uno::UNO_QUERY); + uno::Reference<text::XTextRange> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + xShape->setString("Shape"); + // Create a selection on the shape text. + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(0); + SdrView* pView = pViewShell->GetView(); + pView->SdrBeginTextEdit(pObject); + CPPUNIT_ASSERT(pView->GetTextEditObject()); + EditView& rEditView = pView->GetTextEditOutlinerView()->GetEditView(); + ESelection aWordSelection(0, 0, 0, 5); + rEditView.SetSelection(aWordSelection); + // Did we indeed manage to copy the selected text? + CPPUNIT_ASSERT_EQUAL("Shape"_ostr, apitest::helper::transferable::getTextSelection(pXImpressDocument->getSelection(), "text/plain;charset=utf-8"_ostr)); + + // Make sure returned RTF is not empty. + CPPUNIT_ASSERT(!apitest::helper::transferable::getTextSelection(pXImpressDocument->getSelection(), "text/rtf"_ostr).isEmpty()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testSetGraphicSelection) +{ + SdXImpressDocument* pXImpressDocument = createDoc("shape.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pPage = pViewShell->GetActualPage(); + SdrObject* pObject = pPage->GetObj(0); + SdrHdlList handleList(nullptr); + pObject->AddToHdlList(handleList); + // Make sure the rectangle has 8 handles: at each corner and at the center of each edge. + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(8), handleList.GetHdlCount()); + // Take the bottom center one. + SdrHdl* pHdl = handleList.GetHdl(6); + CPPUNIT_ASSERT_EQUAL(int(SdrHdlKind::Lower), static_cast<int>(pHdl->GetKind())); + ::tools::Rectangle aShapeBefore = pObject->GetSnapRect(); + // Resize. + pXImpressDocument->setGraphicSelection(LOK_SETGRAPHICSELECTION_START, o3tl::toTwips(pHdl->GetPos().getX(), o3tl::Length::mm100), o3tl::toTwips(pHdl->GetPos().getY(), o3tl::Length::mm100)); + pXImpressDocument->setGraphicSelection(LOK_SETGRAPHICSELECTION_END, o3tl::toTwips(pHdl->GetPos().getX(), o3tl::Length::mm100), o3tl::toTwips(pHdl->GetPos().getY() + 1000, o3tl::Length::mm100)); + + // Assert that view shell ID tracking works. + sal_Int32 nView1 = SfxLokHelper::getView(); + SdDrawDocument* pDocument = pXImpressDocument->GetDoc(); + sd::UndoManager* pUndoManager = pDocument->GetUndoManager(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pUndoManager->GetUndoActionCount()); + auto pListAction = dynamic_cast<SfxListUndoAction*>(pUndoManager->GetUndoAction()); + CPPUNIT_ASSERT(pListAction); + for (size_t i = 0; i < pListAction->maUndoActions.size(); ++i) + // The second item was -1 here, view shell ID wasn't known. + CPPUNIT_ASSERT_EQUAL(ViewShellId(nView1), pListAction->GetUndoAction(i)->GetViewShellId()); + + ::tools::Rectangle aShapeAfter = pObject->GetSnapRect(); + // Check that a resize happened, but aspect ratio is not kept. + CPPUNIT_ASSERT_EQUAL(aShapeBefore.getOpenWidth(), aShapeAfter.getOpenWidth()); + CPPUNIT_ASSERT(aShapeBefore.getOpenHeight() < aShapeAfter.getOpenHeight()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testUndoShells) +{ + // Load a document and set the page size. + SdXImpressDocument* pXImpressDocument = createDoc("shape.odp"); + uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence( + { + {"AttributePageSize.Width", uno::Any(static_cast<sal_Int32>(10000))}, + {"AttributePageSize.Height", uno::Any(static_cast<sal_Int32>(10000))}, + })); + dispatchCommand(mxComponent, ".uno:AttributePageSize", aPropertyValues); + + // Assert that view shell ID tracking works for SdUndoAction subclasses. + SdDrawDocument* pDocument = pXImpressDocument->GetDoc(); + sd::UndoManager* pUndoManager = pDocument->GetUndoManager(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pUndoManager->GetUndoActionCount()); + sal_Int32 nView1 = SfxLokHelper::getView(); + // This was -1, SdUndoGroup did not track what view shell created it. + CPPUNIT_ASSERT_EQUAL(ViewShellId(nView1), pUndoManager->GetUndoAction()->GetViewShellId()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testResetSelection) +{ + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + uno::Reference<container::XIndexAccess> xDrawPage(pXImpressDocument->getDrawPages()->getByIndex(0), uno::UNO_QUERY); + uno::Reference<text::XTextRange> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + xShape->setString("Aaa bbb."); + // Create a selection on the second word. + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(0); + SdrView* pView = pViewShell->GetView(); + pView->SdrBeginTextEdit(pObject); + CPPUNIT_ASSERT(pView->GetTextEditObject()); + EditView& rEditView = pView->GetTextEditOutlinerView()->GetEditView(); + ESelection aWordSelection(0, 4, 0, 7); + rEditView.SetSelection(aWordSelection); + // Did we indeed manage to select the second word? + CPPUNIT_ASSERT_EQUAL(OUString("bbb"), rEditView.GetSelected()); + + // Now use resetSelection() to reset the selection. + pXImpressDocument->resetSelection(); + CPPUNIT_ASSERT(!pView->GetTextEditObject()); +} + +namespace +{ + +std::vector<OUString> getCurrentParts(SdXImpressDocument* pDocument) +{ + int parts = pDocument->getParts(); + std::vector<OUString> result; + + result.reserve(parts); + for (int i = 0; i < parts; i++) + { + result.push_back(pDocument->getPartName(i)); + } + + return result; +} + +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testInsertDeletePage) +{ + SdXImpressDocument* pXImpressDocument = createDoc("insert-delete.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + setupLibreOfficeKitViewCallback(pViewShell->GetViewShellBase()); + + SdDrawDocument* pDoc = pXImpressDocument->GetDocShell()->GetDoc(); + CPPUNIT_ASSERT(pDoc); + + std::vector<OUString> aInserted = + { + "Slide 1", "Slide 2", "Slide 3", "Slide 4", "Slide 5", + "Slide 6", "Slide 7", "Slide 8", "Slide 9", "Slide 10", "Slide 11" + }; + + std::vector<OUString> aDeleted = + { + "Slide 1" + }; + + // the document has 1 slide + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1), pDoc->GetSdPageCount(PageKind::Standard)); + + uno::Sequence<beans::PropertyValue> aArgs; + + // Insert slides + m_aDocumentSizeCondition.reset(); + for (unsigned it = 1; it <= 10; it++) + dispatchCommand(mxComponent, ".uno:InsertPage", aArgs); + + osl::Condition::Result aResult = m_aDocumentSizeCondition.wait(std::chrono::seconds(2)); + CPPUNIT_ASSERT_EQUAL(osl::Condition::result_ok, aResult); + + // Verify inserted slides + std::vector<OUString> aPageList(getCurrentParts(pXImpressDocument)); + CPPUNIT_ASSERT_EQUAL(aPageList.size(), aInserted.size()); + + for (auto it1 = aPageList.begin(), it2 = aInserted.begin(); it1 != aPageList.end(); ++it1, ++it2) + { + CPPUNIT_ASSERT_EQUAL(*it1, *it2); + } + + // Delete slides + m_aDocumentSizeCondition.reset(); + for (unsigned it = 1; it <= 10; it++) + dispatchCommand(mxComponent, ".uno:DeletePage", aArgs); + + aResult = m_aDocumentSizeCondition.wait(std::chrono::seconds(2)); + CPPUNIT_ASSERT_EQUAL(osl::Condition::result_ok, aResult); + + // Verify deleted slides + aPageList = getCurrentParts(pXImpressDocument); + CPPUNIT_ASSERT_EQUAL(aPageList.size(), aDeleted.size()); + for (auto it1 = aPageList.begin(), it2 = aDeleted.begin(); it1 != aPageList.end(); ++it1, ++it2) + { + CPPUNIT_ASSERT_EQUAL(*it1, *it2); + } + + // Undo deleted slides + m_aDocumentSizeCondition.reset(); + for (unsigned it = 1; it <= 10; it++) + dispatchCommand(mxComponent, ".uno:Undo", aArgs); + + aResult = m_aDocumentSizeCondition.wait(std::chrono::seconds(2)); + CPPUNIT_ASSERT_EQUAL(osl::Condition::result_ok, aResult); + + // Verify inserted slides + aPageList = getCurrentParts(pXImpressDocument); + CPPUNIT_ASSERT_EQUAL(aPageList.size(), aInserted.size()); + for (auto it1 = aPageList.begin(), it2 = aInserted.begin(); it1 != aPageList.end(); ++it1, ++it2) + { + CPPUNIT_ASSERT_EQUAL(*it1, *it2); + } + + // Redo deleted slides + m_aDocumentSizeCondition.reset(); + for (unsigned it = 1; it <= 10; it++) + dispatchCommand(mxComponent, ".uno:Redo", aArgs); + + aResult = m_aDocumentSizeCondition.wait(std::chrono::seconds(2)); + CPPUNIT_ASSERT_EQUAL(osl::Condition::result_ok, aResult); + + // Verify deleted slides + aPageList = getCurrentParts(pXImpressDocument); + CPPUNIT_ASSERT_EQUAL(aPageList.size(), aDeleted.size()); + for (auto it1 = aPageList.begin(), it2 = aDeleted.begin(); it1 != aPageList.end(); ++it1, ++it2) + { + CPPUNIT_ASSERT_EQUAL(*it1, *it2); + } + + // the document has 1 slide + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1), pDoc->GetSdPageCount(PageKind::Standard)); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testInsertTable) +{ + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + + uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence( + { + { "Rows", uno::Any(sal_Int32(3)) }, + { "Columns", uno::Any(sal_Int32(5)) } + })); + + dispatchCommand(mxComponent, ".uno:InsertTable", aArgs); + + // get the table + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(1); + CPPUNIT_ASSERT(pObject); + + // check that the table is not in the top left corner + Point aPos(pObject->GetRelativePos()); + + CPPUNIT_ASSERT(aPos.X() != 0); + CPPUNIT_ASSERT(aPos.Y() != 0); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testDeleteTable) +{ + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + + uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence( + { + { "Rows", uno::Any(sal_Int32(3)) }, + { "Columns", uno::Any(sal_Int32(5)) } + })); + + dispatchCommand(mxComponent, ".uno:InsertTable", aArgs); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdrView* pSdrView = pViewShell->GetView(); + const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList(); + CPPUNIT_ASSERT(rMarkList.GetMarkCount()); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_MOD1 | awt::Key::A); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_MOD1 | awt::Key::A); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_DELETE); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_DELETE); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(!rMarkList.GetMarkCount()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testPartHash) +{ + SdXImpressDocument* pDoc = createDoc("dummy.odp"); + + int nParts = pDoc->getParts(); + for (int it = 0; it < nParts; it++) + { + CPPUNIT_ASSERT(!pDoc->getPartHash(it).isEmpty()); + } + + // check part that it does not exists + CPPUNIT_ASSERT(pDoc->getPartHash(100).isEmpty()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testResizeTable) +{ + // Load the document. + SdXImpressDocument* pXImpressDocument = createDoc("table.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(0); + auto pTableObject = dynamic_cast<sdr::table::SdrTableObj*>(pObject); + CPPUNIT_ASSERT(pTableObject); + + // Select the table by marking it + starting and ending text edit. + SdrView* pView = pViewShell->GetView(); + pView->MarkObj(pObject, pView->GetSdrPageView()); + pView->SdrBeginTextEdit(pObject); + pView->SdrEndTextEdit(); + + // Remember the original row heights. + uno::Reference<table::XColumnRowRange> xTable = pTableObject->getTable(); + uno::Reference<container::XIndexAccess> xRows = xTable->getRows(); + uno::Reference<beans::XPropertySet> xRow1(xRows->getByIndex(0), uno::UNO_QUERY); + sal_Int32 nExpectedRow1 = xRow1->getPropertyValue("Size").get<sal_Int32>(); + uno::Reference<beans::XPropertySet> xRow2(xRows->getByIndex(1), uno::UNO_QUERY); + sal_Int32 nExpectedRow2 = xRow2->getPropertyValue("Size").get<sal_Int32>(); + + // Resize the upper row, decrease its height by 1 cm. + Point aInnerRowEdge = pObject->GetSnapRect().Center(); + pXImpressDocument->setGraphicSelection(LOK_SETGRAPHICSELECTION_START, o3tl::toTwips(aInnerRowEdge.getX(), o3tl::Length::mm100), o3tl::toTwips(aInnerRowEdge.getY(), o3tl::Length::mm100)); + pXImpressDocument->setGraphicSelection(LOK_SETGRAPHICSELECTION_END, o3tl::toTwips(aInnerRowEdge.getX(), o3tl::Length::mm100), o3tl::toTwips(aInnerRowEdge.getY() - 1000, o3tl::Length::mm100)); + + // Remember the resized row heights. + sal_Int32 nResizedRow1 = xRow1->getPropertyValue("Size").get<sal_Int32>(); + CPPUNIT_ASSERT(nResizedRow1 < nExpectedRow1); + sal_Int32 nResizedRow2 = xRow2->getPropertyValue("Size").get<sal_Int32>(); + CPPUNIT_ASSERT_EQUAL(nExpectedRow2, nResizedRow2); + + // Now undo the resize. + pXImpressDocument->GetDocShell()->GetUndoManager()->Undo(); + + // Check the undo result. + sal_Int32 nActualRow1 = xRow1->getPropertyValue("Size").get<sal_Int32>(); + CPPUNIT_ASSERT_EQUAL(nExpectedRow1, nActualRow1); + sal_Int32 nActualRow2 = xRow2->getPropertyValue("Size").get<sal_Int32>(); + // Expected was 4000, actual was 4572, i.e. the second row after undo was larger than expected. + CPPUNIT_ASSERT_EQUAL(nExpectedRow2, nActualRow2); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testResizeTableColumn) +{ + // Load the document. + SdXImpressDocument* pXImpressDocument = createDoc("table-column.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(0); + auto pTableObject = dynamic_cast<sdr::table::SdrTableObj*>(pObject); + CPPUNIT_ASSERT(pTableObject); + + // Select the table by marking it + starting and ending text edit. + SdrView* pView = pViewShell->GetView(); + pView->MarkObj(pObject, pView->GetSdrPageView()); + pView->SdrBeginTextEdit(pObject); + pView->SdrEndTextEdit(); + + // Remember the original cell widths. + xmlDocUniquePtr pXmlDoc = parseXmlDump(); + OString aPrefix = "/SdDrawDocument/SdrModel/maPages/SdPage/SdrPage/SdrObjList/SdrTableObj/SdrTableObjImpl/TableLayouter/columns/"_ostr; + sal_Int32 nExpectedColumn1 = getXPath(pXmlDoc, aPrefix + "TableLayouter_Layout[1]", "size"_ostr).toInt32(); + sal_Int32 nExpectedColumn2 = getXPath(pXmlDoc, aPrefix + "TableLayouter_Layout[2]", "size"_ostr).toInt32(); + pXmlDoc = nullptr; + + // Resize the left column, decrease its width by 1 cm. + Point aInnerRowEdge = pObject->GetSnapRect().Center(); + pXImpressDocument->setGraphicSelection(LOK_SETGRAPHICSELECTION_START, o3tl::toTwips(aInnerRowEdge.getX(), o3tl::Length::mm100), o3tl::toTwips(aInnerRowEdge.getY(), o3tl::Length::mm100)); + pXImpressDocument->setGraphicSelection(LOK_SETGRAPHICSELECTION_END, o3tl::toTwips(aInnerRowEdge.getX() - 1000, o3tl::Length::mm100), o3tl::toTwips(aInnerRowEdge.getY(), o3tl::Length::mm100)); + + // Remember the resized column widths. + pXmlDoc = parseXmlDump(); + sal_Int32 nResizedColumn1 = getXPath(pXmlDoc, aPrefix + "TableLayouter_Layout[1]", "size"_ostr).toInt32(); + CPPUNIT_ASSERT(nResizedColumn1 < nExpectedColumn1); + sal_Int32 nResizedColumn2 = getXPath(pXmlDoc, aPrefix + "TableLayouter_Layout[2]", "size"_ostr).toInt32(); + CPPUNIT_ASSERT(nResizedColumn2 > nExpectedColumn2); + pXmlDoc = nullptr; + + // Now undo the resize. + pXImpressDocument->GetDocShell()->GetUndoManager()->Undo(); + + // Check the undo result. + pXmlDoc = parseXmlDump(); + sal_Int32 nActualColumn1 = getXPath(pXmlDoc, aPrefix + "TableLayouter_Layout[1]", "size"_ostr).toInt32(); + // Expected was 7049, actual was 6048, i.e. the first column width after undo was 1cm smaller than expected. + CPPUNIT_ASSERT_EQUAL(nExpectedColumn1, nActualColumn1); + sal_Int32 nActualColumn2 = getXPath(pXmlDoc, aPrefix + "TableLayouter_Layout[2]", "size"_ostr).toInt32(); + CPPUNIT_ASSERT_EQUAL(nExpectedColumn2, nActualColumn2); + pXmlDoc = nullptr; +} + +namespace { + +/// A view callback tracks callbacks invoked on one specific view. +class ViewCallback final +{ + SfxViewShell* mpViewShell; + int mnView; +public: + bool m_bGraphicSelectionInvalidated; + bool m_bGraphicViewSelectionInvalidated; + /// Our current part, to be able to decide if a view cursor/selection is relevant for us. + int m_nPart; + bool m_bCursorVisibleChanged; + bool m_bCursorVisible; + bool m_bViewLock; + bool m_bTilesInvalidated; + std::vector<tools::Rectangle> m_aInvalidations; + std::map<int, bool> m_aViewCursorInvalidations; + std::map<int, bool> m_aViewCursorVisibilities; + bool m_bViewSelectionSet; + boost::property_tree::ptree m_aCommentCallbackResult; + OString m_ShapeSelection; + TestLokCallbackWrapper m_callbackWrapper; + + ViewCallback() + : m_bGraphicSelectionInvalidated(false), + m_bGraphicViewSelectionInvalidated(false), + m_nPart(0), + m_bCursorVisibleChanged(false), + m_bCursorVisible(false), + m_bViewLock(false), + m_bTilesInvalidated(false), + m_bViewSelectionSet(false), + m_callbackWrapper(&callback, this) + { + mpViewShell = SfxViewShell::Current(); + mpViewShell->setLibreOfficeKitViewCallback(&m_callbackWrapper); + mnView = SfxLokHelper::getView(); + m_callbackWrapper.setLOKViewId( mnView ); + } + + ~ViewCallback() + { + SfxLokHelper::setView(mnView); + mpViewShell->setLibreOfficeKitViewCallback(nullptr); + } + + static void callback(int nType, const char* pPayload, void* pData) + { + static_cast<ViewCallback*>(pData)->callbackImpl(nType, pPayload); + } + + void callbackImpl(int nType, const char* pPayload) + { + switch (nType) + { + case LOK_CALLBACK_INVALIDATE_TILES: + { + m_bTilesInvalidated = true; + OString text(pPayload); + if (!text.startsWith("EMPTY")) + { + uno::Sequence<OUString> aSeq = comphelper::string::convertCommaSeparated(OUString::createFromAscii(pPayload)); + CPPUNIT_ASSERT(aSeq.getLength() == 4 || aSeq.getLength() == 5); + tools::Rectangle aInvalidationRect; + aInvalidationRect.SetLeft(aSeq[0].toInt32()); + aInvalidationRect.SetTop(aSeq[1].toInt32()); + aInvalidationRect.setWidth(aSeq[2].toInt32()); + aInvalidationRect.setHeight(aSeq[3].toInt32()); + m_aInvalidations.push_back(aInvalidationRect); + } + } + break; + case LOK_CALLBACK_GRAPHIC_SELECTION: + { + m_bGraphicSelectionInvalidated = true; + m_ShapeSelection = OString(pPayload); + } + break; + case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION: + { + std::stringstream aStream(pPayload); + boost::property_tree::ptree aTree; + boost::property_tree::read_json(aStream, aTree); + if (aTree.get_child("part").get_value<int>() == m_nPart) + // Ignore callbacks which are for a different part. + m_bGraphicViewSelectionInvalidated = true; + } + break; + case LOK_CALLBACK_CURSOR_VISIBLE: + { + m_bCursorVisibleChanged = true; + m_bCursorVisible = (std::string_view("true") == pPayload); + } + break; + case LOK_CALLBACK_VIEW_LOCK: + { + std::stringstream aStream(pPayload); + boost::property_tree::ptree aTree; + boost::property_tree::read_json(aStream, aTree); + m_bViewLock = aTree.get_child("rectangle").get_value<std::string>() != "EMPTY"; + } + break; + case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR: + { + std::stringstream aStream(pPayload); + boost::property_tree::ptree aTree; + boost::property_tree::read_json(aStream, aTree); + int nViewId = aTree.get_child("viewId").get_value<int>(); + m_aViewCursorInvalidations[nViewId] = true; + } + break; + case LOK_CALLBACK_VIEW_CURSOR_VISIBLE: + { + std::stringstream aStream(pPayload); + boost::property_tree::ptree aTree; + boost::property_tree::read_json(aStream, aTree); + const int nViewId = aTree.get_child("viewId").get_value<int>(); + m_aViewCursorVisibilities[nViewId] = std::string_view("true") == pPayload; + } + break; + case LOK_CALLBACK_TEXT_VIEW_SELECTION: + { + m_bViewSelectionSet = true; + } + break; + case LOK_CALLBACK_COMMENT: + { + m_aCommentCallbackResult.clear(); + std::stringstream aStream(pPayload); + boost::property_tree::read_json(aStream, m_aCommentCallbackResult); + m_aCommentCallbackResult = m_aCommentCallbackResult.get_child("comment"); + } + break; + } + } +}; + +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testViewCursors) +{ + // Create two views. + SdXImpressDocument* pXImpressDocument = createDoc("shape.odp"); + ViewCallback aView1; + SfxLokHelper::createView(); + ViewCallback aView2; + + // Select the shape in the second view. + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(0); + SdrView* pView = pViewShell->GetView(); + pView->MarkObj(pObject, pView->GetSdrPageView()); + Scheduler::ProcessEventsToIdle(); + + // First view notices that there was a selection change in the other view. + CPPUNIT_ASSERT(aView1.m_bGraphicViewSelectionInvalidated); + // Second view notices that there was a selection change in its own view. + CPPUNIT_ASSERT(aView2.m_bGraphicSelectionInvalidated); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testViewCursorParts) +{ + // Create two views. + SdXImpressDocument* pXImpressDocument = createDoc("shape.odp"); + ViewCallback aView1; + SfxLokHelper::createView(); + pXImpressDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>()); + ViewCallback aView2; + + // Select the shape in the second view. + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(0); + SdrView* pView = pViewShell->GetView(); + pView->MarkObj(pObject, pView->GetSdrPageView()); + Scheduler::ProcessEventsToIdle(); + // First view notices that there was a selection change in the other view. + CPPUNIT_ASSERT(aView1.m_bGraphicViewSelectionInvalidated); + pView->UnmarkAllObj(pView->GetSdrPageView()); + + // Now switch to the second part in the second view. + pXImpressDocument->setPart(1); + aView2.m_nPart = 1; + aView1.m_bGraphicViewSelectionInvalidated = false; + pActualPage = pViewShell->GetActualPage(); + pObject = pActualPage->GetObj(0); + pView->MarkObj(pObject, pView->GetSdrPageView()); + Scheduler::ProcessEventsToIdle(); + // First view ignores view selection, as it would be for part 1, and it's in part 0. + // This failed when the "part" was always 0 in the callback. + CPPUNIT_ASSERT(!aView1.m_bGraphicViewSelectionInvalidated); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testCursorViews) +{ + // Create the first view. + SdXImpressDocument* pXImpressDocument = createDoc("title-shape.odp"); + int nView1 = SfxLokHelper::getView(); + ViewCallback aView1; + + // Begin text edit on the only object on the slide. + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdrView* pView = pViewShell->GetView(); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(pView->IsTextEdit()); + + // Make sure that cursor state is not changed just because we create a second view. + aView1.m_bCursorVisibleChanged = false; + SfxLokHelper::createView(); + pXImpressDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>()); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(!aView1.m_bCursorVisibleChanged); + + // Make sure that typing in the first view causes an invalidation in the + // second view as well, even if the second view was created after begin + // text edit in the first view. + ViewCallback aView2; + // This failed: the second view didn't get a lock notification, even if the + // first view already started text edit. + CPPUNIT_ASSERT(aView2.m_bViewLock); + SfxLokHelper::setView(nView1); + aView2.m_bTilesInvalidated = false; + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0); + Scheduler::ProcessEventsToIdle(); + // This failed: the second view was not invalidated when pressing a key in + // the first view. + CPPUNIT_ASSERT(aView2.m_bTilesInvalidated); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testCursorVisibility_SingleClick) +{ + // Single-clicking in a text box enters editing only + // when it's on the text, even if it's the default text. + + // Load doc. + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + ViewCallback aView1; + + // Begin text edit on the only object on the slide. + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject1 = pActualPage->GetObj(0); + CPPUNIT_ASSERT(pObject1 != nullptr); + CPPUNIT_ASSERT_EQUAL(SdrObjKind::TitleText, pObject1->GetObjIdentifier()); + SdrTextObj* pTextObject = static_cast<SdrTextObj*>(pObject1); + + // Click once outside of the text (in the first quartile) => no editing. + const ::tools::Rectangle aRect = pTextObject->GetCurrentBoundRect(); + const auto cornerX = o3tl::toTwips(aRect.Left() + (aRect.getOpenWidth() / 4), o3tl::Length::mm100); + const auto cornerY = o3tl::toTwips(aRect.Top() + (aRect.getOpenHeight() / 4), o3tl::Length::mm100); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, + cornerX, cornerY, + 1, MOUSE_LEFT, 0); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, + cornerX, cornerY, + 1, MOUSE_LEFT, 0); + Scheduler::ProcessEventsToIdle(); + + // No editing. + CPPUNIT_ASSERT(!pViewShell->GetView()->IsTextEdit()); + CPPUNIT_ASSERT(!aView1.m_bCursorVisible); + + // Click again, now on the text, in the center, to start editing. + const auto centerX = o3tl::toTwips(aRect.Left() + (aRect.getOpenWidth() / 2), o3tl::Length::mm100); + const auto centerY = o3tl::toTwips(aRect.Top() + (aRect.getOpenHeight() / 2), o3tl::Length::mm100); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, + centerX, centerY, + 1, MOUSE_LEFT, 0); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, + centerX, centerY, + 1, MOUSE_LEFT, 0); + Scheduler::ProcessEventsToIdle(); + + // We must be in text editing mode and have cursor visible. + CPPUNIT_ASSERT(pViewShell->GetView()->IsTextEdit()); + CPPUNIT_ASSERT(aView1.m_bCursorVisible); +} + + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testCursorVisibility_DoubleClick) +{ + // Double-clicking anywhere in the TextBox should start editing. + + // Create the first view. + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + ViewCallback aView1; + + // Begin text edit on the only object on the slide. + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject1 = pActualPage->GetObj(0); + CPPUNIT_ASSERT(pObject1 != nullptr); + CPPUNIT_ASSERT_EQUAL(SdrObjKind::TitleText, pObject1->GetObjIdentifier()); + SdrTextObj* pTextObject = static_cast<SdrTextObj*>(pObject1); + + // Double-click outside the text to enter edit mode. + const ::tools::Rectangle aRect = pTextObject->GetCurrentBoundRect(); + const auto cornerX = o3tl::toTwips(aRect.Left() + (aRect.getOpenWidth() / 4), o3tl::Length::mm100); + const auto cornerY = o3tl::toTwips(aRect.Top() + (aRect.getOpenHeight() / 4), o3tl::Length::mm100); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, + cornerX, cornerY, + 2, MOUSE_LEFT, 0); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, + cornerX, cornerY, + 2, MOUSE_LEFT, 0); + Scheduler::ProcessEventsToIdle(); + + // We must be in text editing mode and have cursor visible. + CPPUNIT_ASSERT(pViewShell->GetView()->IsTextEdit()); + CPPUNIT_ASSERT(aView1.m_bCursorVisible); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testCursorVisibility_MultiView) +{ + // Create the first view. + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + const int nView1 = SfxLokHelper::getView(); + ViewCallback aView1; + + // Begin text edit on the only object on the slide. + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject1 = pActualPage->GetObj(0); + CPPUNIT_ASSERT(pObject1); + CPPUNIT_ASSERT_EQUAL(SdrObjKind::TitleText, pObject1->GetObjIdentifier()); + SdrTextObj* pTextObject = static_cast<SdrTextObj*>(pObject1); + + // Make sure that cursor state is not changed just because we create a second view. + SfxLokHelper::createView(); + pXImpressDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>()); + const int nView2 = SfxLokHelper::getView(); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(false, aView1.m_bCursorVisibleChanged); + CPPUNIT_ASSERT_EQUAL(false, aView1.m_aViewCursorVisibilities[nView2]); + + // Also check that the second view gets the notifications. + ViewCallback aView2; + + SfxLokHelper::setView(nView1); + + ::tools::Rectangle aRect = pTextObject->GetCurrentBoundRect(); + const auto centerX = o3tl::toTwips(aRect.Left() + (aRect.getOpenWidth() / 2), o3tl::Length::mm100); + const auto centerY = o3tl::toTwips(aRect.Top() + (aRect.getOpenHeight() / 2), o3tl::Length::mm100); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, + centerX, centerY, + 2, MOUSE_LEFT, 0); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, + centerX, centerY, + 2, MOUSE_LEFT, 0); + Scheduler::ProcessEventsToIdle(); + + // We must be in text editing mode and have cursor visible. + CPPUNIT_ASSERT(pViewShell->GetView()->IsTextEdit()); + CPPUNIT_ASSERT(aView1.m_bCursorVisible); + CPPUNIT_ASSERT_EQUAL(false, aView1.m_aViewCursorVisibilities[nView2]); + + CPPUNIT_ASSERT_EQUAL(false, aView2.m_bCursorVisible); + CPPUNIT_ASSERT_EQUAL(false, aView2.m_aViewCursorVisibilities[nView1]); + CPPUNIT_ASSERT_EQUAL(false, aView2.m_aViewCursorVisibilities[nView2]); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testCursorVisibility_Escape) +{ + // Load doc. + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + ViewCallback aView1; + + // Begin text edit on the only object on the slide. + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject1 = pActualPage->GetObj(0); + CPPUNIT_ASSERT(pObject1 != nullptr); + CPPUNIT_ASSERT_EQUAL(SdrObjKind::TitleText, pObject1->GetObjIdentifier()); + SdrTextObj* pTextObject = static_cast<SdrTextObj*>(pObject1); + + // Click once on the text to start editing. + const ::tools::Rectangle aRect = pTextObject->GetCurrentBoundRect(); + const auto centerX = o3tl::toTwips(aRect.Left() + (aRect.getOpenWidth() / 2), o3tl::Length::mm100); + const auto centerY = o3tl::toTwips(aRect.Top() + (aRect.getOpenHeight() / 2), o3tl::Length::mm100); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, + centerX, centerY, + 1, MOUSE_LEFT, 0); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, + centerX, centerY, + 1, MOUSE_LEFT, 0); + Scheduler::ProcessEventsToIdle(); + + // We must be in text editing mode and have cursor visible. + CPPUNIT_ASSERT(pViewShell->GetView()->IsTextEdit()); + CPPUNIT_ASSERT(aView1.m_bCursorVisible); + + // End editing by pressing the escape key. + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::ESCAPE); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::ESCAPE); + Scheduler::ProcessEventsToIdle(); + + // We must be in text editing mode and have cursor visible. + CPPUNIT_ASSERT(!pViewShell->GetView()->IsTextEdit()); + CPPUNIT_ASSERT_EQUAL(false, aView1.m_bCursorVisible); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testViewLock) +{ + // Load a document that has a shape and create two views. + SdXImpressDocument* pXImpressDocument = createDoc("shape.odp"); + ViewCallback aView1; + SfxLokHelper::createView(); + pXImpressDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>()); + + // Begin text edit in the second view and assert that the first gets a lock + // notification. + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(0); + SdrView* pView = pViewShell->GetView(); + aView1.m_bViewLock = false; + pView->SdrBeginTextEdit(pObject); + CPPUNIT_ASSERT(aView1.m_bViewLock); + + // End text edit in the second view, and assert that the lock is removed in + // the first view. + pView->SdrEndTextEdit(); + CPPUNIT_ASSERT(!aView1.m_bViewLock); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testUndoLimiting) +{ + // Create the first view. + SdXImpressDocument* pXImpressDocument = createDoc("title-shape.odp"); + sd::ViewShell* pViewShell1 = pXImpressDocument->GetDocShell()->GetViewShell(); + int nView1 = SfxLokHelper::getView(); + SfxLokHelper::createView(); + sd::ViewShell* pViewShell2 = pXImpressDocument->GetDocShell()->GetViewShell(); + CPPUNIT_ASSERT(pViewShell1 != pViewShell2); + + // Begin text edit on the only object on the slide. + SfxLokHelper::setView(nView1); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(pViewShell1->GetView()->IsTextEdit()); + + // View2 UNDO stack should be empty + { + SfxRequest aReq2(SID_UNDO, SfxCallMode::SLOT, pXImpressDocument->GetDocShell()->GetDoc()->GetPool()); + aReq2.AppendItem(SfxUInt16Item(SID_UNDO, 1)); + pViewShell2->ExecuteSlot(aReq2); + const auto* pReturnValue = aReq2.GetReturnValue().getItem(); + CPPUNIT_ASSERT(!pReturnValue); + } + + // View1 can UNDO + { + SfxRequest aReq1(SID_UNDO, SfxCallMode::SLOT, pXImpressDocument->GetDocShell()->GetDoc()->GetPool()); + aReq1.AppendItem(SfxUInt16Item(SID_UNDO, 1)); + pViewShell1->ExecuteSlot(aReq1); + CPPUNIT_ASSERT(aReq1.IsDone()); + } + + // View1 can REDO + { + SfxRequest aReq1(SID_REDO, SfxCallMode::SLOT, pXImpressDocument->GetDocShell()->GetDoc()->GetPool()); + aReq1.AppendItem(SfxUInt16Item(SID_REDO, 1)); + pViewShell1->ExecuteSlot(aReq1); + CPPUNIT_ASSERT(aReq1.IsDone()); + } + + // Exit text edit mode + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::ESCAPE); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::ESCAPE); + Scheduler::ProcessEventsToIdle(); + + CPPUNIT_ASSERT(!pViewShell1->GetView()->IsTextEdit()); + + // Now check view2 cannot undo actions. + { + SfxRequest aReq2(SID_UNDO, SfxCallMode::SLOT, pXImpressDocument->GetDocShell()->GetDoc()->GetPool()); + aReq2.AppendItem(SfxUInt16Item(SID_UNDO, 1)); + pViewShell2->ExecuteSlot(aReq2); + const SfxUInt32Item* pUInt32Item = dynamic_cast<const SfxUInt32Item*>(aReq2.GetReturnValue().getItem()); + CPPUNIT_ASSERT(pUInt32Item); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_uInt32 >(SID_REPAIRPACKAGE), pUInt32Item->GetValue()); + } + + // Now check view1 can undo action + { + SfxRequest aReq1(SID_UNDO, SfxCallMode::SLOT, pXImpressDocument->GetDocShell()->GetDoc()->GetPool()); + aReq1.AppendItem(SfxUInt16Item(SID_UNDO, 1)); + pViewShell1->ExecuteSlot(aReq1); + CPPUNIT_ASSERT(aReq1.IsDone()); + } +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testCreateViewGraphicSelection) +{ + // Load a document and register a callback. + SdXImpressDocument* pXImpressDocument = createDoc("shape.odp"); + ViewCallback aView1; + + // Select the only shape in the document and assert that the graphic selection is changed. + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(0); + SdrView* pView = pViewShell->GetView(); + aView1.m_bGraphicSelectionInvalidated = false; + pView->MarkObj(pObject, pView->GetSdrPageView()); + CPPUNIT_ASSERT(aView1.m_bGraphicSelectionInvalidated); + + // Now create a new view. + aView1.m_bGraphicSelectionInvalidated = false; + SfxLokHelper::createView(); + pXImpressDocument->initializeForTiledRendering({}); + // This failed, creating a new view affected the graphic selection of an + // existing view. + CPPUNIT_ASSERT(!aView1.m_bGraphicSelectionInvalidated); + + // Check that when the first view has a shape selected and we register a + // callback on the second view, then it gets a "graphic view selection". + ViewCallback aView2; + // This failed, the created new view had no "view selection" of the first + // view's selected shape. + CPPUNIT_ASSERT(aView2.m_bGraphicViewSelectionInvalidated); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testCreateViewTextCursor) +{ + // Load a document and register a callback. + SdXImpressDocument* pXImpressDocument = createDoc("title-shape.odp"); + ViewCallback aView1; + + // Begin text edit. + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0); + Scheduler::ProcessEventsToIdle(); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdrView* pSdrView = pViewShell->GetView(); + CPPUNIT_ASSERT(pSdrView->IsTextEdit()); + + // Create an editeng text selection. + EditView& rEditView = pSdrView->GetTextEditOutlinerView()->GetEditView(); + // 0th para, 0th char -> 0th para, 1st char. + ESelection aWordSelection(0, 0, 0, 1); + rEditView.SetSelection(aWordSelection); + + // Make sure that creating a new view either doesn't affect the previous + // one, or at least the effect is not visible at the end. + aView1.m_aViewCursorInvalidations.clear(); + aView1.m_aViewCursorVisibilities.clear(); + SfxLokHelper::createView(); + pXImpressDocument->initializeForTiledRendering({}); + ViewCallback aView2; + bool bFoundCursor = false; + for (const auto& rInvalidation : aView1.m_aViewCursorInvalidations) + { + auto itVisibility = aView1.m_aViewCursorVisibilities.find(rInvalidation.first); + // For each cursor invalidation: if there is no visibility or the visibility is true, that's a problem. + if (itVisibility == aView1.m_aViewCursorVisibilities.end() || itVisibility->second) + { + bFoundCursor = true; + break; + } + } + // This failed: the second view created an unexpected view cursor in the + // first view. + CPPUNIT_ASSERT(!bFoundCursor); + // This failed: the text view selection of the first view wasn't seen by + // the second view. + CPPUNIT_ASSERT(aView2.m_bViewSelectionSet); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testTdf102223) +{ + // Load the document. + SdXImpressDocument* pXImpressDocument = createDoc("tdf102223.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + auto pTableObject = dynamic_cast<sdr::table::SdrTableObj*>(pActualPage->GetObj(2)); + CPPUNIT_ASSERT(pTableObject); + SdrView* pView = pViewShell->GetView(); + + // select contents of cell + ::tools::Rectangle aRect = pTableObject->GetCurrentBoundRect(); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, + o3tl::toTwips(aRect.Left() + 2, o3tl::Length::mm100), o3tl::toTwips(aRect.Top() + 2, o3tl::Length::mm100), + 1, MOUSE_LEFT, 0); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, + o3tl::toTwips(aRect.Left() + 2, o3tl::Length::mm100), o3tl::toTwips(aRect.Top() + 2, o3tl::Length::mm100), + 1, MOUSE_LEFT, 0); + Scheduler::ProcessEventsToIdle(); + pView->SdrBeginTextEdit(pTableObject); + CPPUNIT_ASSERT(pView->GetTextEditObject()); + EditView& rEditView = pView->GetTextEditOutlinerView()->GetEditView(); + rEditView.SetSelection(ESelection(0, 0, 0, 3)); // start para, start char, end para, end char. + CPPUNIT_ASSERT_EQUAL(OUString("Red"), rEditView.GetSelected()); + CPPUNIT_ASSERT_EQUAL( + int(1411), static_cast<int>(rEditView.GetAttribs().Get(EE_CHAR_FONTHEIGHT).GetHeight())); + + // cut contents of cell + uno::Sequence<beans::PropertyValue> aArgs; + dispatchCommand(mxComponent, ".uno:Cut", aArgs); + + pView->SdrEndTextEdit(false); + pView->SdrBeginTextEdit(pTableObject); + CPPUNIT_ASSERT(pView->GetTextEditObject()); + EditView& rEditView2 = pView->GetTextEditOutlinerView()->GetEditView(); + rEditView2.SetSelection(ESelection(0, 0, 0, 1)); // start para, start char, end para, end char. + CPPUNIT_ASSERT_EQUAL( + int(1411), static_cast<int>(rEditView2.GetAttribs().Get(EE_CHAR_FONTHEIGHT).GetHeight())); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testTdf118354) +{ + // Load the document. + SdXImpressDocument* pXImpressDocument = createDoc("tdf118354.odp"); + + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pActualPage->GetObjCount()); + + auto pTableObject = dynamic_cast<sdr::table::SdrTableObj*>(pActualPage->GetObj(0)); + CPPUNIT_ASSERT(pTableObject); + + // Without the fix, it would crash here + ::tools::Rectangle aRect = pTableObject->GetCurrentBoundRect(); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, + o3tl::toTwips(aRect.Left() + 2, o3tl::Length::mm100), o3tl::toTwips(aRect.Top() + 2, o3tl::Length::mm100), + 1, MOUSE_LEFT, 0); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, + o3tl::toTwips(aRect.Left() + 2, o3tl::Length::mm100), o3tl::toTwips(aRect.Top() + 2, o3tl::Length::mm100), + 1, MOUSE_LEFT, 0); + Scheduler::ProcessEventsToIdle(); + + SdrView* pView = pViewShell->GetView(); + auto pMarkedObj = dynamic_cast<sdr::table::SdrTableObj*>(pView->GetMarkedObjectByIndex(0)); + CPPUNIT_ASSERT_EQUAL(pMarkedObj, pTableObject); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testPostKeyEventInvalidation) +{ + // Load a document and begin text edit on the first slide. + SdXImpressDocument* pXImpressDocument = createDoc("2slides.odp"); + CPPUNIT_ASSERT_EQUAL(0, pXImpressDocument->getPart()); + ViewCallback aView1; + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdrView* pView = pViewShell->GetView(); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_F2); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_F2); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(pView->GetTextEditObject()); + + // Create a second view and begin text edit there as well, in parallel. + SfxLokHelper::createView(); + pXImpressDocument->initializeForTiledRendering({}); + ViewCallback aView2; + pXImpressDocument->setPart(1); + sd::ViewShell* pViewShell2 = pXImpressDocument->GetDocShell()->GetViewShell(); + SdrView* pView2 = pViewShell2->GetView(); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_F2); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_F2); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(pView2->GetTextEditObject()); + + // Now go left with the cursor in the second view and watch for + // invalidations. + aView2.m_bTilesInvalidated = false; + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_LEFT); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_LEFT); + Scheduler::ProcessEventsToIdle(); + // This failed: moving the cursor caused unexpected invalidation. + CPPUNIT_ASSERT(!aView2.m_bTilesInvalidated); +} + +/** + * tests a cut/paste bug around bullet items in a list + */ +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testTdf103083) +{ + // Load the document. + SdXImpressDocument* pXImpressDocument = createDoc("tdf103083.fodp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + + SdrObject* pObject1 = pActualPage->GetObj(1); + CPPUNIT_ASSERT_EQUAL(SdrObjKind::OutlineText, pObject1->GetObjIdentifier()); + SdrTextObj* pTextObject = static_cast<SdrTextObj*>(pObject1); + + SdrView* pView = pViewShell->GetView(); + + // select contents of bullet item + ::tools::Rectangle aRect = pTextObject->GetCurrentBoundRect(); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, + o3tl::toTwips(aRect.Left() + 2, o3tl::Length::mm100), o3tl::toTwips(aRect.Top() + 2, o3tl::Length::mm100), + 1, MOUSE_LEFT, 0); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, + o3tl::toTwips(aRect.Left() + 2, o3tl::Length::mm100), o3tl::toTwips(aRect.Top() + 2, o3tl::Length::mm100), + 1, MOUSE_LEFT, 0); + Scheduler::ProcessEventsToIdle(); + pView->SdrBeginTextEdit(pTextObject); + CPPUNIT_ASSERT(pView->GetTextEditObject()); + EditView& rEditView = pView->GetTextEditOutlinerView()->GetEditView(); + rEditView.SetSelection(ESelection(2, 0, 2, 33)); // start para, start char, end para, end char. + CPPUNIT_ASSERT_EQUAL(OUString("They have all the same formatting"), rEditView.GetSelected()); + SdrOutliner* pOutliner = pView->GetTextEditOutliner(); + CPPUNIT_ASSERT_EQUAL(OUString("No-Logo Content~LT~Gliederung 2"), + pOutliner->GetStyleSheet(2)->GetName()); + const EditTextObject& aEdit = pTextObject->GetOutlinerParaObject()->GetTextObject(); + const SvxNumBulletItem* pNumFmt = aEdit.GetParaAttribs(2).GetItem(EE_PARA_NUMBULLET); + SvxNumberFormat aNumFmt(pNumFmt->GetNumRule().GetLevel(2)); + + // cut contents of bullet item + dispatchCommand(mxComponent, ".uno:Cut", uno::Sequence<beans::PropertyValue>()); + + CPPUNIT_ASSERT(pView->GetTextEditObject()); + EditView& rEditView2 = pView->GetTextEditOutlinerView()->GetEditView(); + rEditView2.SetSelection(ESelection(2, 0, 2, 10)); // start para, start char, end para, end char. + CPPUNIT_ASSERT_EQUAL(OUString(), rEditView2.GetSelected()); + + // paste contents of bullet item + dispatchCommand(mxComponent, ".uno:Paste", uno::Sequence<beans::PropertyValue>()); + + // send an ESC key to trigger the commit of the edit to the main model + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::ESCAPE); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::ESCAPE); + Scheduler::ProcessEventsToIdle(); + + pView->SdrBeginTextEdit(pTextObject); + CPPUNIT_ASSERT(pView->GetTextEditObject()); + pOutliner = pView->GetTextEditOutliner(); + EditView& rEditView3 = pView->GetTextEditOutlinerView()->GetEditView(); + rEditView3.SetSelection(ESelection(2, 0, 2, 33)); // start para, start char, end para, end char. + CPPUNIT_ASSERT_EQUAL(OUString("They have all the same formatting"), rEditView3.GetSelected()); + CPPUNIT_ASSERT_EQUAL(OUString("No-Logo Content~LT~Gliederung 2"), + pOutliner->GetStyleSheet(2)->GetName()); + + const EditTextObject& aEdit2 = pTextObject->GetOutlinerParaObject()->GetTextObject(); + const SvxNumBulletItem* pNumFmt2 = aEdit2.GetParaAttribs(2).GetItem(EE_PARA_NUMBULLET); + SvxNumberFormat aNumFmt2(pNumFmt2->GetNumRule().GetLevel(2)); + + bool bEqual(aNumFmt2 == aNumFmt); + CPPUNIT_ASSERT_MESSAGE("Bullet properties changed after paste", bEqual); +} + +/** + * tests a clone-formatting bug around table cell attributes + */ +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testTdf104405) +{ + // Load the document. + SdXImpressDocument* pXImpressDocument = createDoc("tdf104405.fodp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(2); + auto pTableObject = dynamic_cast<sdr::table::SdrTableObj*>(pObject); + CPPUNIT_ASSERT(pTableObject); + + // select the middle cell + SdrView* pView = pViewShell->GetView(); + pView->MarkObj(pTableObject, pView->GetSdrPageView()); + pTableObject->setActiveCell(sdr::table::CellPos(2,1)); + pView->SdrBeginTextEdit(pTableObject); + EditView& rEditView = pView->GetTextEditOutlinerView()->GetEditView(); + rEditView.SetSelection(ESelection(0, 0, 0, 3)); // start para, start char, end para, end char. + + // trigger the clone-formatting/paintbrush command to copy formatting contents of cell + uno::Sequence aArgs{ comphelper::makePropertyValue("PersistentCopy", true) }; + dispatchCommand(mxComponent, ".uno:FormatPaintbrush", aArgs); + + // now click on the table + pView->MarkObj(pTableObject, pView->GetSdrPageView()); + pTableObject->setActiveCell(sdr::table::CellPos(0,0)); + pView->SdrEndTextEdit(false); + pView->SdrBeginTextEdit(pTableObject); + EditView& rEditView2 = pView->GetTextEditOutlinerView()->GetEditView(); + rEditView2.SetSelection(ESelection(0, 0, 0, 3)); // start para, start char, end para, end char. + ::tools::Rectangle aRect = pTableObject->GetCurrentBoundRect(); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, + o3tl::toTwips(aRect.Left(), o3tl::Length::mm100), o3tl::toTwips(aRect.Top(), o3tl::Length::mm100), + 1, MOUSE_LEFT, 0); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, + o3tl::toTwips(aRect.Left(), o3tl::Length::mm100), o3tl::toTwips(aRect.Top(), o3tl::Length::mm100), + 1, MOUSE_LEFT, 0); + + Scheduler::ProcessEventsToIdle(); + + // check that the first cell has acquired the resulting vertical style + xmlDocUniquePtr pXmlDoc = parseXmlDump(); + // the following name has a compiler-dependent part + CPPUNIT_ASSERT_EQUAL( + OUString("2"), + getXPath( + pXmlDoc, + "/SdDrawDocument/SdrModel/maPages/SdPage/SdrPage/SdrObjList/SdrTableObj/SdrTableObjImpl" + "/TableModel/Cell[1]/DefaultProperties/SfxItemSet/SdrTextVertAdjustItem"_ostr, + "value"_ostr)); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testTdf81754) +{ + SdXImpressDocument* pXImpressDocument = createDoc("tdf81754.pptx"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(1); + + SdrTextObj* pTextObj = static_cast<SdrTextObj*>(pObject); + SdrView* pView = pViewShell->GetView(); + pView->MarkObj(pTextObj, pView->GetSdrPageView()); + SfxStringItem aInputString(SID_ATTR_CHAR, "x"); + pViewShell->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR, + SfxCallMode::SYNCHRON, { &aInputString }); + + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0); + Scheduler::ProcessEventsToIdle(); + + // now save, reload, and assert that we did not lose the edit + saveAndReload("Impress Office Open XML"); + + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + uno::Reference<text::XTextRange> xShape(xPage->getByIndex(1), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(u"Somethingxx"_ustr, xShape->getString()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testTdf105502) +{ + // Load the document. + SdXImpressDocument* pXImpressDocument = createDoc("tdf105502.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + sd::Window* pWindow = pViewShell->GetActiveWindow(); + CPPUNIT_ASSERT(pWindow); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(0); + auto pTableObject = dynamic_cast<sdr::table::SdrTableObj*>(pObject); + CPPUNIT_ASSERT(pTableObject); + + // Select the first row. + sd::View* pView = pViewShell->GetView(); + pView->MarkObj(pObject, pView->GetSdrPageView()); + pView->SdrBeginTextEdit(pObject); + rtl::Reference<sdr::SelectionController> xSelectionController(pView->getSelectionController()); + CPPUNIT_ASSERT(xSelectionController.is()); + SfxRequest aRequest(*pViewShell->GetViewFrame(), SID_TABLE_SELECT_ROW); + xSelectionController->Execute(aRequest); + + // Assert that the A1:B1 selection succeeded. + CPPUNIT_ASSERT(xSelectionController->hasSelectedCells()); + sdr::table::CellPos aFirstCell; + sdr::table::CellPos aLastCell; + xSelectionController->getSelectedCells(aFirstCell, aLastCell); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aFirstCell.mnCol); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aFirstCell.mnRow); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), aLastCell.mnCol); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aLastCell.mnRow); + + // Grow font size for the selection. + dispatchCommand(mxComponent, ".uno:Grow", {}); + + // Assert that the selected A1 has now a larger font than the unselected + // A2. + xmlDocUniquePtr pXmlDoc = parseXmlDump(); + sal_Int32 nA1Height = getXPath(pXmlDoc, "//Cell[1]/SdrText/OutlinerParaObject/EditTextObject/ContentInfo/SfxItemSet/SvxFontHeightItem[1]"_ostr, "height"_ostr).toInt32(); + sal_Int32 nA2Height = getXPath(pXmlDoc, "//Cell[3]/SdrText/OutlinerParaObject/EditTextObject/ContentInfo/attribs[1]/SvxFontHeightItem"_ostr, "height"_ostr).toInt32(); + // This failed when FuText::ChangeFontSize() never did "continue" in the + // text loop, instead of doing so depending on what IsInSelection() returns. + CPPUNIT_ASSERT(nA1Height > nA2Height); + + // Check that selection remains the same + CPPUNIT_ASSERT(xSelectionController->hasSelectedCells()); + xSelectionController->getSelectedCells(aFirstCell, aLastCell); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aFirstCell.mnCol); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aFirstCell.mnRow); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), aLastCell.mnCol); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aLastCell.mnRow); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testCommentCallbacks) +{ + // Load the document. + // Set the tiled annotations off + comphelper::LibreOfficeKit::setTiledAnnotations(false); + + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp", comphelper::InitPropertySequence( + { + {".uno:Author", uno::Any(OUString("LOK User1"))}, + })); + ViewCallback aView1; + int nView1 = SfxLokHelper::getView(); + + SfxLokHelper::createView(); + uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence( + { + {".uno:Author", uno::Any(OUString("LOK User2"))}, + })); + pXImpressDocument->initializeForTiledRendering(aArgs); + ViewCallback aView2; + int nView2 = SfxLokHelper::getView(); + + SfxLokHelper::setView(nView1); + + // Add a new comment + aArgs = comphelper::InitPropertySequence( + { + {"Text", uno::Any(OUString("Comment"))}, + }); + dispatchCommand(mxComponent, ".uno:InsertAnnotation", aArgs); + + // We received a LOK_CALLBACK_COMMENT callback with comment 'Add' action + CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView1.m_aCommentCallbackResult.get<std::string>("action")); + CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView2.m_aCommentCallbackResult.get<std::string>("action")); + int nComment1 = aView1.m_aCommentCallbackResult.get<int>("id"); + CPPUNIT_ASSERT_EQUAL(nComment1, aView2.m_aCommentCallbackResult.get<int>("id")); + css::util::DateTime aDateTime; + OUString aDateTimeString = OUString::createFromAscii(aView1.m_aCommentCallbackResult.get<std::string>("dateTime")); + CPPUNIT_ASSERT(utl::ISO8601parseDateTime(aDateTimeString, aDateTime)); + CPPUNIT_ASSERT_EQUAL(std::string("LOK User1"), aView1.m_aCommentCallbackResult.get<std::string>("author")); + CPPUNIT_ASSERT_EQUAL(std::string("LOK User1"), aView2.m_aCommentCallbackResult.get<std::string>("author")); + CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView1.m_aCommentCallbackResult.get<std::string>("text")); + CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView2.m_aCommentCallbackResult.get<std::string>("text")); + CPPUNIT_ASSERT(!aView1.m_aCommentCallbackResult.get<std::string>("parthash").empty()); + CPPUNIT_ASSERT(!aView2.m_aCommentCallbackResult.get<std::string>("parthash").empty()); + + // Reply to a just added comment + SfxLokHelper::setView(nView2); + aArgs = comphelper::InitPropertySequence( + { + {"Id", uno::Any(OUString::number(nComment1))}, + {"Text", uno::Any(OUString("Reply to comment"))}, + }); + dispatchCommand(mxComponent, ".uno:ReplyToAnnotation", aArgs); + + // We received a LOK_CALLBACK_COMMENT callback with comment 'Modify' action + CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView1.m_aCommentCallbackResult.get<std::string>("action")); + CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView2.m_aCommentCallbackResult.get<std::string>("action")); + CPPUNIT_ASSERT_EQUAL(nComment1, aView1.m_aCommentCallbackResult.get<int>("id")); + CPPUNIT_ASSERT_EQUAL(nComment1, aView2.m_aCommentCallbackResult.get<int>("id")); + CPPUNIT_ASSERT_EQUAL(std::string("LOK User2"), aView1.m_aCommentCallbackResult.get<std::string>("author")); + CPPUNIT_ASSERT_EQUAL(std::string("LOK User2"), aView2.m_aCommentCallbackResult.get<std::string>("author")); + OUString aReplyTextView1 = OUString::createFromAscii(aView1.m_aCommentCallbackResult.get<std::string>("text")); + OUString aReplyTextView2 = OUString::createFromAscii(aView2.m_aCommentCallbackResult.get<std::string>("text")); + CPPUNIT_ASSERT(aReplyTextView1.startsWith("Reply to LOK User1")); + CPPUNIT_ASSERT(aReplyTextView1.endsWith("Reply to comment")); + CPPUNIT_ASSERT(aReplyTextView2.startsWith("Reply to LOK User1")); + CPPUNIT_ASSERT(aReplyTextView2.endsWith("Reply to comment")); + CPPUNIT_ASSERT(!aView1.m_aCommentCallbackResult.get<std::string>("parthash").empty()); + CPPUNIT_ASSERT(!aView2.m_aCommentCallbackResult.get<std::string>("parthash").empty()); + + // Edit this annotation now + aArgs = comphelper::InitPropertySequence( + { + {"Id", uno::Any(OUString::number(nComment1))}, + {"Text", uno::Any(OUString("Edited comment"))}, + }); + dispatchCommand(mxComponent, ".uno:EditAnnotation", aArgs); + + // We received a LOK_CALLBACK_COMMENT callback with comment 'Modify' action + CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView1.m_aCommentCallbackResult.get<std::string>("action")); + CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView2.m_aCommentCallbackResult.get<std::string>("action")); + CPPUNIT_ASSERT_EQUAL(nComment1, aView1.m_aCommentCallbackResult.get<int>("id")); + CPPUNIT_ASSERT_EQUAL(nComment1, aView2.m_aCommentCallbackResult.get<int>("id")); + CPPUNIT_ASSERT(!aView1.m_aCommentCallbackResult.get<std::string>("parthash").empty()); + CPPUNIT_ASSERT(!aView2.m_aCommentCallbackResult.get<std::string>("parthash").empty()); + CPPUNIT_ASSERT_EQUAL(std::string("Edited comment"), aView1.m_aCommentCallbackResult.get<std::string>("text")); + CPPUNIT_ASSERT_EQUAL(std::string("Edited comment"), aView2.m_aCommentCallbackResult.get<std::string>("text")); + + // Delete the comment + aArgs = comphelper::InitPropertySequence( + { + {"Id", uno::Any(OUString::number(nComment1))}, + }); + dispatchCommand(mxComponent, ".uno:DeleteAnnotation", aArgs); + + // We received a LOK_CALLBACK_COMMENT callback with comment 'Remove' action + CPPUNIT_ASSERT_EQUAL(std::string("Remove"), aView1.m_aCommentCallbackResult.get<std::string>("action")); + CPPUNIT_ASSERT_EQUAL(std::string("Remove"), aView2.m_aCommentCallbackResult.get<std::string>("action")); + CPPUNIT_ASSERT_EQUAL(nComment1, aView1.m_aCommentCallbackResult.get<int>("id")); + CPPUNIT_ASSERT_EQUAL(nComment1, aView2.m_aCommentCallbackResult.get<int>("id")); + + comphelper::LibreOfficeKit::setTiledAnnotations(true); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testCommentChangeImpress) +{ + uno::Sequence<beans::PropertyValue> aArgs; + + // Load the document. + // Set the tiled annotations off + comphelper::LibreOfficeKit::setTiledAnnotations(false); + + createDoc("dummy.odp", comphelper::InitPropertySequence( + { + {".uno:Author", uno::Any(OUString("LOK User1"))}, + })); + + ViewCallback aView1; + + // Add a new comment + aArgs = comphelper::InitPropertySequence( + { + {"Text", uno::Any(OUString("Comment"))}, + }); + dispatchCommand(mxComponent, ".uno:InsertAnnotation", aArgs); + + CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView1.m_aCommentCallbackResult.get<std::string>("action")); + + int nComment1 = aView1.m_aCommentCallbackResult.get<int>("id"); + + CPPUNIT_ASSERT(!aView1.m_aCommentCallbackResult.get<std::string>("parthash").empty()); + CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView1.m_aCommentCallbackResult.get<std::string>("text")); + CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 0, 0"), aView1.m_aCommentCallbackResult.get<std::string>("rectangle")); + + // Edit this annotation now + aArgs = comphelper::InitPropertySequence( + { + {"Id", uno::Any(OUString::number(nComment1))}, + {"PositionX", uno::Any(sal_Int32(10))}, + {"PositionY", uno::Any(sal_Int32(20))} + }); + dispatchCommand(mxComponent, ".uno:EditAnnotation", aArgs); + + CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView1.m_aCommentCallbackResult.get<std::string>("action")); + CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView1.m_aCommentCallbackResult.get<std::string>("text")); + CPPUNIT_ASSERT_EQUAL(std::string("10, 20, 0, 0"), aView1.m_aCommentCallbackResult.get<std::string>("rectangle")); + + comphelper::LibreOfficeKit::setTiledAnnotations(true); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testCommentChangeDraw) +{ + uno::Sequence<beans::PropertyValue> aArgs; + + // Load the document. + // Set the tiled annotations off + comphelper::LibreOfficeKit::setTiledAnnotations(false); + + createDoc("dummy.odg", comphelper::InitPropertySequence( + { + {".uno:Author", uno::Any(OUString("LOK User1"))}, + })); + + ViewCallback aView1; + + // Add a new comment + aArgs = comphelper::InitPropertySequence( + { + {"Text", uno::Any(OUString("Comment"))}, + }); + dispatchCommand(mxComponent, ".uno:InsertAnnotation", aArgs); + + CPPUNIT_ASSERT_EQUAL(std::string("Add"), aView1.m_aCommentCallbackResult.get<std::string>("action")); + + int nComment1 = aView1.m_aCommentCallbackResult.get<int>("id"); + + CPPUNIT_ASSERT(!aView1.m_aCommentCallbackResult.get<std::string>("parthash").empty()); + CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView1.m_aCommentCallbackResult.get<std::string>("text")); + CPPUNIT_ASSERT_EQUAL(std::string("0, 0, 0, 0"), aView1.m_aCommentCallbackResult.get<std::string>("rectangle")); + + // Edit this annotation now + aArgs = comphelper::InitPropertySequence( + { + {"Id", uno::Any(OUString::number(nComment1))}, + {"PositionX", uno::Any(sal_Int32(10))}, + {"PositionY", uno::Any(sal_Int32(20))} + }); + dispatchCommand(mxComponent, ".uno:EditAnnotation", aArgs); + + CPPUNIT_ASSERT_EQUAL(std::string("Modify"), aView1.m_aCommentCallbackResult.get<std::string>("action")); + CPPUNIT_ASSERT_EQUAL(std::string("Comment"), aView1.m_aCommentCallbackResult.get<std::string>("text")); + CPPUNIT_ASSERT_EQUAL(std::string("10, 20, 0, 0"), aView1.m_aCommentCallbackResult.get<std::string>("rectangle")); + + comphelper::LibreOfficeKit::setTiledAnnotations(true); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testMultiViewInsertDeletePage) +{ + // Load the document. + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + ViewCallback aView1; + int nView1 = SfxLokHelper::getView(); + uno::Sequence<beans::PropertyValue> aArgs; + SdDrawDocument* pDoc = pXImpressDocument->GetDocShell()->GetDoc(); + + // Create second view + SfxLokHelper::createView(); + pXImpressDocument->initializeForTiledRendering(aArgs); + ViewCallback aView2; + int nView2 = SfxLokHelper::getView(); + + // the document has 8 slides + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(8), pDoc->GetSdPageCount(PageKind::Standard)); + + // Switch to 5th page in 2nd view + pXImpressDocument->setPart(4); + + // Insert slide in 1st view + SfxLokHelper::setView(nView1); + dispatchCommand(mxComponent, ".uno:InsertPage", aArgs); + + // See if the current slide number changed in 2nd view too + SfxLokHelper::setView(nView2); + CPPUNIT_ASSERT_EQUAL(5, pXImpressDocument->getPart()); + + // Delete the page in 1st view now + SfxLokHelper::setView(nView1); + dispatchCommand(mxComponent, ".uno:DeletePage", aArgs); + + // See if current slide number changed in 2nd view too + SfxLokHelper::setView(nView2); + CPPUNIT_ASSERT_EQUAL(4, pXImpressDocument->getPart()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testMultiViewInsertDeletePage2) +{ + // Load the document. + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + ViewCallback aView1; + int nView1 = SfxLokHelper::getView(); + uno::Sequence<beans::PropertyValue> aArgs; + SdDrawDocument* pDoc = pXImpressDocument->GetDocShell()->GetDoc(); + + // Create second view + SfxLokHelper::createView(); + pXImpressDocument->initializeForTiledRendering(aArgs); + ViewCallback aView2; + int nView2 = SfxLokHelper::getView(); + + // the document has 8 slides + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(8), pDoc->GetSdPageCount(PageKind::Standard)); + + // Switch to 5th page in 2nd view + pXImpressDocument->setPart(4); + + // Begin text edit on the only object on the slide. + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject1 = pActualPage->GetObj(0); + CPPUNIT_ASSERT(pObject1 != nullptr); + CPPUNIT_ASSERT_EQUAL(SdrObjKind::TitleText, pObject1->GetObjIdentifier()); + SdrTextObj* pTextObject = static_cast<SdrTextObj*>(pObject1); + + // Double-click outside the text to enter edit mode. + const ::tools::Rectangle aRect = pTextObject->GetCurrentBoundRect(); + const auto cornerX = o3tl::toTwips(aRect.Left() + (aRect.getOpenWidth() / 4), o3tl::Length::mm100); + const auto cornerY = o3tl::toTwips(aRect.Top() + (aRect.getOpenHeight() / 4), o3tl::Length::mm100); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, + cornerX, cornerY, + 2, MOUSE_LEFT, 0); + pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, + cornerX, cornerY, + 2, MOUSE_LEFT, 0); + Scheduler::ProcessEventsToIdle(); + + // We must be in text editing mode and have cursor visible. + CPPUNIT_ASSERT(pViewShell->GetView()->IsTextEdit()); + + // Insert slide in 1st view + SfxLokHelper::setView(nView1); + dispatchCommand(mxComponent, ".uno:InsertPage", aArgs); + + // See if the current slide number changed in 2nd view too + SfxLokHelper::setView(nView2); + CPPUNIT_ASSERT_EQUAL(5, pXImpressDocument->getPart()); + + // Delete the page in 1st view now + SfxLokHelper::setView(nView1); + dispatchCommand(mxComponent, ".uno:DeletePage", aArgs); + + // See if current slide number changed in 2nd view too + SfxLokHelper::setView(nView2); + CPPUNIT_ASSERT_EQUAL(4, pXImpressDocument->getPart()); + + // We must be still in text editing mode and have cursor visible. + CPPUNIT_ASSERT(pViewShell->GetView()->IsTextEdit()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testDisableUndoRepair) +{ + // Load the document. + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + + // Create View 1 + SfxViewShell* pView1 = SfxViewShell::Current(); + sd::ViewShell* pViewShell1 = pXImpressDocument->GetDocShell()->GetViewShell(); + int nView1 = SfxLokHelper::getView(); + + // Create View 2 + SfxLokHelper::createView(); + SfxViewShell* pView2 = SfxViewShell::Current(); + sd::ViewShell* pViewShell2 = pXImpressDocument->GetDocShell()->GetViewShell(); + int nView2 = SfxLokHelper::getView(); + + // Check UNDO is disabled + { + std::unique_ptr<SfxPoolItem> pItem1; + std::unique_ptr<SfxPoolItem> pItem2; + CPPUNIT_ASSERT_EQUAL(SfxItemState::DISABLED, pView1->GetViewFrame().GetBindings().QueryState(SID_UNDO, pItem1)); + CPPUNIT_ASSERT_EQUAL(SfxItemState::DISABLED, pView2->GetViewFrame().GetBindings().QueryState(SID_UNDO, pItem2)); + } + + // Insert a character in the first view. + SfxLokHelper::setView(nView1); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'h', 0); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'h', 0); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(pViewShell1->GetView()->IsTextEdit()); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::ESCAPE); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::ESCAPE); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(!pViewShell1->GetView()->IsTextEdit()); + + // Check + { + std::unique_ptr<SfxPoolItem> xItem1; + pView1->GetViewFrame().GetBindings().QueryState(SID_UNDO, xItem1); + const auto* pUInt32Item1 = dynamic_cast<const SfxUInt32Item*>(xItem1.get()); + CPPUNIT_ASSERT(!pUInt32Item1); + + std::unique_ptr<SfxPoolItem> xItem2; + pView2->GetViewFrame().GetBindings().QueryState(SID_UNDO, xItem2); + const auto* pUInt32Item2 = dynamic_cast<const SfxUInt32Item*>(xItem2.get()); + CPPUNIT_ASSERT(pUInt32Item2); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(SID_REPAIRPACKAGE), pUInt32Item2->GetValue()); + } + + // Insert a character in the second view. + SfxLokHelper::setView(nView2); + pXImpressDocument->setPart(1); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'c', 0); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'c', 0); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(pViewShell2->GetView()->IsTextEdit()); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::ESCAPE); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::ESCAPE); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(!pViewShell2->GetView()->IsTextEdit()); + + // Check + { + std::unique_ptr<SfxPoolItem> xItem1; + pView1->GetViewFrame().GetBindings().QueryState(SID_UNDO, xItem1); + const SfxUInt32Item* pUInt32Item = dynamic_cast<const SfxUInt32Item*>(xItem1.get()); + CPPUNIT_ASSERT(pUInt32Item); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(SID_REPAIRPACKAGE), pUInt32Item->GetValue()); + + std::unique_ptr<SfxPoolItem> xItem2; + pView2->GetViewFrame().GetBindings().QueryState(SID_UNDO, xItem2); + CPPUNIT_ASSERT(!dynamic_cast< const SfxUInt32Item* >(xItem2.get())); + } +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testDocumentRepair) +{ + // Create two views. + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + CPPUNIT_ASSERT(pXImpressDocument); + + // view #1 + SfxViewShell* pView1 = SfxViewShell::Current(); + + // view #2 + SfxLokHelper::createView(); + SfxViewShell* pView2 = SfxViewShell::Current(); + int nView2 = SfxLokHelper::getView(); + sd::ViewShell* pViewShell2 = pXImpressDocument->GetDocShell()->GetViewShell(); + + CPPUNIT_ASSERT(pView1 != pView2); + { + std::unique_ptr<SfxBoolItem> pItem1; + pView1->GetViewFrame().GetBindings().QueryState(SID_DOC_REPAIR, pItem1); + CPPUNIT_ASSERT(pItem1); + CPPUNIT_ASSERT_EQUAL(false, pItem1->GetValue()); + + std::unique_ptr<SfxBoolItem> pItem2; + pView2->GetViewFrame().GetBindings().QueryState(SID_DOC_REPAIR, pItem2); + CPPUNIT_ASSERT(pItem2); + CPPUNIT_ASSERT_EQUAL(false, pItem2->GetValue()); + } + + // Insert a character in the second view. + SfxLokHelper::setView(nView2); + pXImpressDocument->setPart(1); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'c', 0); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'c', 0); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(pViewShell2->GetView()->IsTextEdit()); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::ESCAPE); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::ESCAPE); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(!pViewShell2->GetView()->IsTextEdit()); + + { + std::unique_ptr<SfxBoolItem> pItem1; + pView1->GetViewFrame().GetBindings().QueryState(SID_DOC_REPAIR, pItem1); + CPPUNIT_ASSERT(pItem1); + CPPUNIT_ASSERT_EQUAL(true, pItem1->GetValue()); + + std::unique_ptr<SfxBoolItem> pItem2; + pView2->GetViewFrame().GetBindings().QueryState(SID_DOC_REPAIR, pItem2); + CPPUNIT_ASSERT(pItem2); + CPPUNIT_ASSERT_EQUAL(true, pItem2->GetValue()); + } +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testLanguageStatus) +{ + // Load the document. + createDoc("dummy.odp"); + SfxViewShell* pView1 = SfxViewShell::Current(); + SfxLokHelper::createView(); + SfxViewShell* pView2 = SfxViewShell::Current(); + { + std::unique_ptr<SfxPoolItem> xItem1; + std::unique_ptr<SfxPoolItem> xItem2; + pView1->GetViewFrame().GetBindings().QueryState(SID_LANGUAGE_STATUS, xItem1); + pView2->GetViewFrame().GetBindings().QueryState(SID_LANGUAGE_STATUS, xItem2); + auto pStringItem = dynamic_cast<const SfxStringItem*>(xItem1.get()); + CPPUNIT_ASSERT(pStringItem); + + CPPUNIT_ASSERT_EQUAL(OUString("English (USA);en-US"), pStringItem->GetValue()); + + CPPUNIT_ASSERT(dynamic_cast< const SfxStringItem* >(xItem2.get())); + } +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testLanguageAllText) +{ + // Load the document, which has a single shape, with Hungarian text. + createDoc("language-all-text.odp"); + + // Set the language to English for all text. + uno::Sequence<beans::PropertyValue> aArgs = comphelper::InitPropertySequence({ + { "Language", uno::Any(OUString("Default_English (USA)")) }, + }); + dispatchCommand(mxComponent, ".uno:LanguageStatus", aArgs); + + // Assert that the shape text language was changed. + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + uno::Reference<text::XTextRange> xShape(xPage->getByIndex(0), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xRun(xShape, uno::UNO_QUERY_THROW); + lang::Locale aLocale; + xRun->getPropertyValue("CharLocale") >>= aLocale; + // Without the accompanying fix in place, this test would have failed with 'Expected: en; + // Actual: hu', as the shape text language was not set. + CPPUNIT_ASSERT_EQUAL(OUString("en"), aLocale.Language); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testDefaultView) +{ + // Load the document with notes view. + SdXImpressDocument* pXImpressDocument = createDoc("notes-view.odp"); + sd::ViewShell* pView = pXImpressDocument->GetDocShell()->GetViewShell(); + { + std::unique_ptr<SfxBoolItem> pImpressView; + std::unique_ptr<SfxBoolItem> pNotesView; + pView->GetViewFrame()->GetBindings().QueryState(SID_NORMAL_MULTI_PANE_GUI, pImpressView); + pView->GetViewFrame()->GetBindings().QueryState(SID_NOTES_MODE, pNotesView); + CPPUNIT_ASSERT(pImpressView); + CPPUNIT_ASSERT(pNotesView); + CPPUNIT_ASSERT_EQUAL(true, pImpressView->GetValue()); + CPPUNIT_ASSERT_EQUAL(false, pNotesView->GetValue()); + } +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testIMESupport) +{ + // Load the document with notes view. + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + VclPtr<vcl::Window> pDocWindow = pXImpressDocument->getDocWindow(); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdrObject* pObject = pViewShell->GetActualPage()->GetObj(0); + SdrTextObj* pTextObj = static_cast<SdrTextObj*>(pObject); + SdrView* pView = pViewShell->GetView(); + pView->MarkObj(pTextObj, pView->GetSdrPageView()); + SfxStringItem aInputString(SID_ATTR_CHAR, "x"); + pViewShell->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR, + SfxCallMode::SYNCHRON, { &aInputString }); + + // sequence of chinese IME compositions when 'nihao' is typed in an IME + const std::vector<OString> aUtf8Inputs{ "年"_ostr, "你"_ostr, "你好"_ostr, "你哈"_ostr, "你好"_ostr, "你好"_ostr }; + std::vector<OUString> aInputs; + std::transform(aUtf8Inputs.begin(), aUtf8Inputs.end(), + std::back_inserter(aInputs), [](OString aInput) { + return OUString::fromUtf8(aInput); + }); + for (const auto& aInput: aInputs) + { + pDocWindow->PostExtTextInputEvent(VclEventId::ExtTextInput, aInput); + } + pDocWindow->PostExtTextInputEvent(VclEventId::EndExtTextInput, ""); + + // the cursor should be at position 3rd + EditView& rEditView = pView->GetTextEditOutlinerView()->GetEditView(); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(3), rEditView.GetSelection().nStartPos); + + ESelection aWordSelection(0, 0, 0, 3); // start para, start char, end para, end char. + rEditView.SetSelection(aWordSelection); + // content contains only the last IME composition, not all + CPPUNIT_ASSERT_EQUAL(OUString("x" + aInputs[aInputs.size() - 1]), rEditView.GetSelected()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testTdf115783) +{ + // Load the document. + SdXImpressDocument* pXImpressDocument = createDoc("tdf115783.fodp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(0); + auto pTableObject = dynamic_cast<sdr::table::SdrTableObj*>(pObject); + CPPUNIT_ASSERT(pTableObject); + SdrView* pView = pViewShell->GetView(); + pView->MarkObj(pTableObject, pView->GetSdrPageView()); + + // Create a cell selection and set font height. + // Go to the end of the B1 cell. + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_LEFT); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_LEFT); + // Create a B1->C1 cell selection. + const int nShiftRight = KEY_SHIFT + KEY_RIGHT; + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, nShiftRight); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, nShiftRight); + uno::Sequence<beans::PropertyValue> aArgs = comphelper::InitPropertySequence({ + { "FontHeight.Height", uno::Any(static_cast<float>(12)) }, + }); + dispatchCommand(mxComponent, ".uno:FontHeight", aArgs); + + // Create a text selection on the B1 cell. + pTableObject->setActiveCell(sdr::table::CellPos(1, 0)); + pView->SdrBeginTextEdit(pTableObject); + EditView& rEditView = pView->GetTextEditOutlinerView()->GetEditView(); + // Start para, start char, end para, end char. + rEditView.SetSelection(ESelection(0, 0, 0, 5)); + CPPUNIT_ASSERT_EQUAL(OUString("hello"), rEditView.GetSelected()); + + // Copy selection, paste at the start of the cell. + aArgs = {}; + dispatchCommand(mxComponent, ".uno:Copy", aArgs); + rEditView.SetSelection(ESelection(0, 0, 0, 0)); + aArgs = {}; + dispatchCommand(mxComponent, ".uno:Paste", aArgs); + pView->SdrEndTextEdit(); + + // And now verify that the cell has the correct font size. + uno::Reference<table::XCellRange> xTable = pTableObject->getTable(); + CPPUNIT_ASSERT(xTable.is()); + uno::Reference<text::XTextRange> xCell(xTable->getCellByPosition(1, 0), uno::UNO_QUERY); + CPPUNIT_ASSERT(xCell.is()); + uno::Reference<container::XEnumerationAccess> xText(xCell->getText(), uno::UNO_QUERY); + CPPUNIT_ASSERT(xText.is()); + uno::Reference<container::XEnumerationAccess> xParagraph( + xText->createEnumeration()->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT(xParagraph.is()); + uno::Reference<text::XTextRange> xPortion(xParagraph->createEnumeration()->nextElement(), + uno::UNO_QUERY); + CPPUNIT_ASSERT(xPortion.is()); + // This failed, it was only "hello" as the paragraph had 2 portions: a + // "hello" with 12pt size and a "hello" with 18pt. + CPPUNIT_ASSERT_EQUAL(OUString("hellohello"), xPortion->getString()); + uno::Reference<beans::XPropertySet> xPropertySet(xPortion, uno::UNO_QUERY); + int nHeight = xPropertySet->getPropertyValue("CharHeight").get<float>(); + // Make sure that the single font size for the cell is the expected one. + CPPUNIT_ASSERT_EQUAL(12, nHeight); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testPasteTextOnSlide) +{ + // Load the document. + SdXImpressDocument* pXImpressDocument = createDoc("paste_text_onslide.odp"); + CPPUNIT_ASSERT(pXImpressDocument); + + // select second text object + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::TAB); + Scheduler::ProcessEventsToIdle(); + + // step into text editing + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '1', 0); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, '1', 0); + Scheduler::ProcessEventsToIdle(); + + // select full text + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_LEFT | KEY_SHIFT); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_LEFT | KEY_SHIFT); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_LEFT | KEY_SHIFT); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_LEFT | KEY_SHIFT); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_LEFT | KEY_SHIFT); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_LEFT | KEY_SHIFT); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_LEFT | KEY_SHIFT); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_LEFT | KEY_SHIFT); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_LEFT | KEY_SHIFT); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_LEFT | KEY_SHIFT); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_LEFT | KEY_SHIFT); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_LEFT | KEY_SHIFT); + Scheduler::ProcessEventsToIdle(); + + // Copy some text + dispatchCommand(mxComponent, ".uno:Copy", uno::Sequence<beans::PropertyValue>()); + + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::ESCAPE); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::ESCAPE); + Scheduler::ProcessEventsToIdle(); + + // Paste onto the slide + dispatchCommand(mxComponent, ".uno:Paste", uno::Sequence<beans::PropertyValue>()); + + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::ESCAPE); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::ESCAPE); + Scheduler::ProcessEventsToIdle(); + + // Check the position of the newly added text shape, created for pasted text + SdPage* pActualPage = pXImpressDocument->GetDocShell()->GetViewShell()->GetActualPage(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pActualPage->GetObjCount()); + SdrObject* pObject = pActualPage->GetObj(2); + CPPUNIT_ASSERT(pObject); + SdrTextObj* pTextObj = DynCastSdrTextObj(pObject); + CPPUNIT_ASSERT(pTextObj); + CPPUNIT_ASSERT_EQUAL(SdrObjKind::Text, pTextObj->GetObjIdentifier()); + const Point aPos = pTextObj->GetLastBoundRect().TopLeft(); + CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(0), aPos.getX()); + CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(0), aPos.getY()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testTdf115873) +{ + // Initialize the navigator. + SdXImpressDocument* pXImpressDocument = createDoc("tdf115873.fodp"); + SfxViewShell* pViewShell = SfxViewShell::Current(); + CPPUNIT_ASSERT(pViewShell); + SfxBindings& rBindings = pViewShell->GetViewFrame().GetBindings(); + auto xNavigator = std::make_unique<SdNavigatorWin>(nullptr, &rBindings, nullptr); + xNavigator->InitTreeLB(pXImpressDocument->GetDoc()); + SdPageObjsTLV& rObjects = xNavigator->GetObjects(); + rObjects.SelectEntry(u"Slide 1"); + rObjects.Select(); + sd::ViewShell* pSdViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdrView* pSdrView = pSdViewShell->GetView(); + pSdrView->UnmarkAllObj(pSdrView->GetSdrPageView()); + + // Make sure that no shapes are selected. + const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList(); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rMarkList.GetMarkCount()); + + // Single-click with the mouse. + MouseEvent aMouseEvent(Point(0, 0), /*nClicks=*/1, MouseEventModifiers::NONE, MOUSE_LEFT); + rObjects.MousePressHdl(aMouseEvent); + rObjects.SelectEntry(u"Rectangle"); + rObjects.Select(); + rObjects.MouseReleaseHdl(aMouseEvent); + Scheduler::ProcessEventsToIdle(); + // This failed, single-click did not result in a shape selection (only + // double-click did). + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rMarkList.GetMarkCount()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testTdf115873Group) +{ + // Initialize the navigator. + SdXImpressDocument* pXImpressDocument = createDoc("tdf115873-group.fodp"); + SfxViewShell* pViewShell = SfxViewShell::Current(); + CPPUNIT_ASSERT(pViewShell); + SfxBindings& rBindings = pViewShell->GetViewFrame().GetBindings(); + auto xNavigator = std::make_unique<SdNavigatorWin>(nullptr, &rBindings, nullptr); + xNavigator->InitTreeLB(pXImpressDocument->GetDoc()); + SdPageObjsTLV& rObjects = xNavigator->GetObjects(); + // This failed, Fill() and IsEqualToDoc() were out of sync for group + // shapes. + CPPUNIT_ASSERT(rObjects.IsEqualToDoc(pXImpressDocument->GetDoc())); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testCutSelectionChange) +{ + // Load the document. + SdXImpressDocument* pXImpressDocument = createDoc("cut_selection_change.odp"); + CPPUNIT_ASSERT(pXImpressDocument); + + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + setupLibreOfficeKitViewCallback(pViewShell->GetViewShellBase()); + Scheduler::ProcessEventsToIdle(); + + // Select first text object + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::TAB); + Scheduler::ProcessEventsToIdle(); + + // step into text editing + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '1', 0); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, '1', 0); + Scheduler::ProcessEventsToIdle(); + + // select some text + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_LEFT | KEY_SHIFT); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_LEFT | KEY_SHIFT); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_LEFT | KEY_SHIFT); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_LEFT | KEY_SHIFT); + Scheduler::ProcessEventsToIdle(); + + // Check that we have a selection before cutting + CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), m_aSelection.size()); + + // Cut the selected text + dispatchCommand(mxComponent, ".uno:Cut", uno::Sequence<beans::PropertyValue>()); + + // Selection is removed + CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(0), m_aSelection.size()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testGetViewRenderState) +{ + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + int nFirstViewId = SfxLokHelper::getView(); + ViewCallback aView1; + CPPUNIT_ASSERT_EQUAL(";Default"_ostr, pXImpressDocument->getViewRenderState()); + // Create a second view + SfxLokHelper::createView(); + ViewCallback aView2; + CPPUNIT_ASSERT_EQUAL(";Default"_ostr, pXImpressDocument->getViewRenderState()); + // Set to dark scheme + { + uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence( + { + { "NewTheme", uno::Any(OUString("Dark")) }, + } + ); + dispatchCommand(mxComponent, ".uno:ChangeTheme", aPropertyValues); + } + CPPUNIT_ASSERT_EQUAL(";Dark"_ostr, pXImpressDocument->getViewRenderState()); + // Switch back to the first view, and check that the options string is the same + SfxLokHelper::setView(nFirstViewId); + CPPUNIT_ASSERT_EQUAL(";Default"_ostr, pXImpressDocument->getViewRenderState()); +} + +// Helper function to get a tile to a bitmap and check the pixel color +static void assertTilePixelColor(SdXImpressDocument* pXImpressDocument, int nPixelX, int nPixelY, Color aColor) +{ + size_t nCanvasSize = 1024; + size_t nTileSize = 256; + std::vector<unsigned char> aPixmap(nCanvasSize * nCanvasSize * 4, 0); + ScopedVclPtrInstance<VirtualDevice> pDevice(DeviceFormat::WITHOUT_ALPHA); + pDevice->SetBackground(Wallpaper(COL_TRANSPARENT)); + pDevice->SetOutputSizePixelScaleOffsetAndLOKBuffer(Size(nCanvasSize, nCanvasSize), + Fraction(1.0), Point(), aPixmap.data()); + pXImpressDocument->paintTile(*pDevice, nCanvasSize, nCanvasSize, 0, 0, 15360, 7680); + pDevice->EnableMapMode(false); + Bitmap aBitmap = pDevice->GetBitmap(Point(0, 0), Size(nTileSize, nTileSize)); + BitmapScopedReadAccess pAccess(aBitmap); + Color aActualColor(pAccess->GetPixel(nPixelX, nPixelY)); + CPPUNIT_ASSERT_EQUAL(aColor, aActualColor); +} + +// Test that changing the theme in one view doesn't change it in the other view +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testThemeViewSeparation) +{ + Color aDarkColor(0x1c, 0x1c, 0x1c); + // Add a minimal dark scheme + { + svtools::EditableColorConfig aColorConfig; + svtools::ColorConfigValue aValue; + aValue.bIsVisible = true; + aValue.nColor = aDarkColor; + aColorConfig.SetColorValue(svtools::DOCCOLOR, aValue); + aColorConfig.AddScheme(u"Dark"_ustr); + } + // Add a minimal light scheme + { + svtools::EditableColorConfig aColorConfig; + svtools::ColorConfigValue aValue; + aValue.bIsVisible = true; + aValue.nColor = COL_WHITE; + aColorConfig.SetColorValue(svtools::DOCCOLOR, aValue); + aColorConfig.AddScheme(u"Light"_ustr); + } + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + int nFirstViewId = SfxLokHelper::getView(); + ViewCallback aView1; + // Switch first view to light scheme + { + uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence( + { + { "NewTheme", uno::Any(OUString("Light")) }, + } + ); + dispatchCommand(mxComponent, ".uno:ChangeTheme", aPropertyValues); + } + // First view is at light scheme + assertTilePixelColor(pXImpressDocument, 255, 255, COL_WHITE); + // Create second view + SfxLokHelper::createView(); + int nSecondViewId = SfxLokHelper::getView(); + ViewCallback aView2; + // Set second view to dark scheme + { + uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence( + { + { "NewTheme", uno::Any(OUString("Dark")) }, + } + ); + dispatchCommand(mxComponent, ".uno:ChangeTheme", aPropertyValues); + } + assertTilePixelColor(pXImpressDocument, 255, 255, aDarkColor); + // First view still in light scheme + SfxLokHelper::setView(nFirstViewId); + assertTilePixelColor(pXImpressDocument, 255, 255, COL_WHITE); + // Second view still in dark scheme + SfxLokHelper::setView(nSecondViewId); + assertTilePixelColor(pXImpressDocument, 255, 255, Color(0x1c, 0x1c, 0x1c)); + // Switch second view back to light scheme + { + uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence( + { + { "NewTheme", uno::Any(OUString("Light")) }, + } + ); + dispatchCommand(mxComponent, ".uno:ChangeTheme", aPropertyValues); + } + // Now in light scheme + assertTilePixelColor(pXImpressDocument, 255, 255, COL_WHITE); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testRegenerateDiagram) +{ + // Load the document. + SdXImpressDocument* pXImpressDocument = createDoc("regenerate-diagram.pptx"); + CPPUNIT_ASSERT(pXImpressDocument); + + SdPage* pActualPage = pXImpressDocument->GetDocShell()->GetViewShell()->GetActualPage(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), pActualPage->GetObj(0)->GetSubList()->GetObjCount()); + + // For new Diagram functionality entering group using UI is not allowed as long + // as the group shape is a diagram. Do the same as before done by triggering UI + // events directly in the model + // Remove and free top-left entry (Box showing "A") + pActualPage->GetObj(0)->GetSubList()->RemoveObject(1); + + // select diagram + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::TAB); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::TAB); + Scheduler::ProcessEventsToIdle(); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pActualPage->GetObj(0)->GetSubList()->GetObjCount()); + + // regenerate diagram + dispatchCommand(mxComponent, ".uno:RegenerateDiagram", uno::Sequence<beans::PropertyValue>()); + + // diagram content (child shape count) should be the same as in the beginning + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), pActualPage->GetObj(0)->GetSubList()->GetObjCount()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testInsertDeletePageInvalidation) +{ + // Load the document. + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + ViewCallback aView1; + CPPUNIT_ASSERT_EQUAL(8, pXImpressDocument->getParts()); + + // Insert slide + aView1.m_bTilesInvalidated = false; + aView1.m_aInvalidations.clear(); + dispatchCommand(mxComponent, ".uno:InsertPage", uno::Sequence<beans::PropertyValue>()); + CPPUNIT_ASSERT(aView1.m_bTilesInvalidated); + CPPUNIT_ASSERT_EQUAL(9, pXImpressDocument->getParts()); + CPPUNIT_ASSERT_EQUAL(size_t(9), aView1.m_aInvalidations.size()); + + // Delete slide + aView1.m_bTilesInvalidated = false; + aView1.m_aInvalidations.clear(); + dispatchCommand(mxComponent, ".uno:DeletePage", uno::Sequence<beans::PropertyValue>()); + CPPUNIT_ASSERT(aView1.m_bTilesInvalidated); + CPPUNIT_ASSERT_EQUAL(8, pXImpressDocument->getParts()); + CPPUNIT_ASSERT_EQUAL(size_t(8), aView1.m_aInvalidations.size()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testSpellOnlineRenderParameter) +{ + // Load the document. + SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); + bool bSet = pXImpressDocument->GetDoc()->GetOnlineSpell(); + + uno::Sequence<beans::PropertyValue> aPropertyValues = + { + comphelper::InitPropertySequence({ { ".uno:SpellOnline", uno::Any(!bSet) } }), + }; + pXImpressDocument->initializeForTiledRendering(aPropertyValues); + CPPUNIT_ASSERT_EQUAL(!bSet, pXImpressDocument->GetDoc()->GetOnlineSpell()); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testSlideDuplicateUndo) +{ + // Create two views. + SdXImpressDocument* pXImpressDocument = createDoc("duplicate-undo.odp"); + int nView0 = SfxLokHelper::getView(); + SfxLokHelper::createView(); + pXImpressDocument->initializeForTiledRendering({}); + int nView1 = SfxLokHelper::getView(); + SfxLokHelper::setView(nView0); + + // Switch to the 3rd slide on view 0, and start text editing. + { + pXImpressDocument->setPart(2); + sd::ViewShell* pViewShell0 = pXImpressDocument->GetDocShell()->GetViewShell(); + SdrView* pView = pViewShell0->GetView(); + SdPage* pActualPage = pViewShell0->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(1); + SdrTextObj* pTextObj = static_cast<SdrTextObj*>(pObject); + pView->MarkObj(pTextObj, pView->GetSdrPageView()); + SfxStringItem aInputString(SID_ATTR_CHAR, "x"); + pViewShell0->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR, + SfxCallMode::SYNCHRON, { &aInputString }); + CPPUNIT_ASSERT(pView->IsTextEdit()); + CPPUNIT_ASSERT(pView->GetTextEditPageView()); + } + + // Duplicate the first slide on view 1 and undo it. + SfxLokHelper::setView(nView1); + dispatchCommand(mxComponent, ".uno:DuplicatePage", {}); + pXImpressDocument->setPart(0, /*bAllowChangeFocus=*/false); + pXImpressDocument->setPart(1, /*bAllowChangeFocus=*/false); + SfxLokHelper::setView(nView0); + pXImpressDocument->setPart(0, /*bAllowChangeFocus=*/false); + pXImpressDocument->setPart(3, /*bAllowChangeFocus=*/false); + SfxLokHelper::setView(nView1); + pXImpressDocument->getUndoManager()->undo(); + // Without the accompanying fix in place, this would have tried to access the outdated page view + // pointer, potentially leading to a crash. + pXImpressDocument->setPart(2, /*bAllowChangeFocus=*/false); + + // Make sure that view 0 now doesn't have an outdated page view pointer. + SfxLokHelper::setView(nView0); + sd::ViewShell* pViewShell0 = pXImpressDocument->GetDocShell()->GetViewShell(); + SdrView* pView0 = pViewShell0->GetView(); + CPPUNIT_ASSERT(!pView0->GetTextEditPageView()); +} + +namespace +{ + +void lcl_extractHandleParameters(std::string_view selection, sal_uInt32& id, sal_uInt32& x, sal_uInt32& y) +{ + OString extraInfo( selection.substr(selection.find("{")) ); + std::stringstream aStream((std::string(extraInfo))); + boost::property_tree::ptree aTree; + boost::property_tree::read_json(aStream, aTree); + boost::property_tree::ptree + handle0 = aTree + .get_child("handles") + .get_child("kinds") + .get_child("rectangle") + .get_child("1") + .begin()->second; + id = handle0.get_child("id").get_value<int>(); + x = handle0.get_child("point").get_child("x").get_value<int>(); + y = handle0.get_child("point").get_child("y").get_value<int>(); +} + +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testMoveShapeHandle) +{ + SdXImpressDocument* pXImpressDocument = createDoc("shape.odp"); + ViewCallback aView1; + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pPage = pViewShell->GetActualPage(); + SdrObject* pObject = pPage->GetObj(0); + SdrView* pView = pViewShell->GetView(); + pView->MarkObj(pObject, pView->GetSdrPageView()); + Scheduler::ProcessEventsToIdle(); + + CPPUNIT_ASSERT(!aView1.m_ShapeSelection.isEmpty()); + { + sal_uInt32 id, x, y; + lcl_extractHandleParameters(aView1.m_ShapeSelection, id, x ,y); + sal_uInt32 oldX = x; + sal_uInt32 oldY = y; + uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence( + { + {"HandleNum", uno::Any(id)}, + {"NewPosX", uno::Any(x+1)}, + {"NewPosY", uno::Any(y+1)} + })); + dispatchCommand(mxComponent, ".uno:MoveShapeHandle", aPropertyValues); + CPPUNIT_ASSERT(!aView1.m_ShapeSelection.isEmpty()); + lcl_extractHandleParameters(aView1.m_ShapeSelection, id, x ,y); + CPPUNIT_ASSERT_EQUAL(x-1, oldX); + CPPUNIT_ASSERT_EQUAL(y-1, oldY); + } +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testPasteUndo) +{ + // Given a document with a textbox, containing "world": + SdXImpressDocument* pXImpressDocument = createDoc("paste-undo.fodp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(0); + SdrView* pView = pViewShell->GetView(); + pView->MarkObj(pObject, pView->GetSdrPageView()); + pView->SdrBeginTextEdit(pObject); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_HOME); + pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_HOME); + EditView& rEditView = pView->GetTextEditOutlinerView()->GetEditView(); + ESelection aWordSelection(0, 0, 0, 1); // "w" of "world" + rEditView.SetSelection(aWordSelection); + dispatchCommand(mxComponent, ".uno:Cut", {}); + + // When undoing a paste: + dispatchCommand(mxComponent, ".uno:Paste", {}); + dispatchCommand(mxComponent, ".uno:Undo", {}); + + // Then make sure the cursor position is still at the beginning: + ESelection aSelection = rEditView.GetSelection(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 0 + // - Actual : 4 + // i.e. the cursor position after undo was at the end of the line, not at the start, as + // expected. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aSelection.nStartPos); +} + +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testShapeEditInMultipleViews) +{ + SdXImpressDocument* pXImpressDocument = createDoc("TextBoxAndRect.odg"); + pXImpressDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>()); + SdDrawDocument* pDocument = pXImpressDocument->GetDoc(); + + // Create view 1 + const int nView1 = SfxLokHelper::getView(); + sd::ViewShell* pViewShell1 = pXImpressDocument->GetDocShell()->GetViewShell(); + SdrView* pView1 = pViewShell1->GetView(); + Scheduler::ProcessEventsToIdle(); + + // Create view 2 + SfxLokHelper::createView(); + const int nView2 = SfxLokHelper::getView(); + CPPUNIT_ASSERT(nView1 != nView2); + + sd::ViewShell* pViewShell2 = pXImpressDocument->GetDocShell()->GetViewShell(); + SdrView* pView2 = pViewShell2->GetView(); + Scheduler::ProcessEventsToIdle(); + + // Switch to view 1 + SfxLokHelper::setView(nView1); + + SdPage* pPage1 = pViewShell1->GetActualPage(); + + SdrObject* pTextBoxObject = pPage1->GetObj(0); + CPPUNIT_ASSERT_EQUAL(OUString("Text Box"), pTextBoxObject->GetName()); + + SdrObject* pRectangleObject = pPage1->GetObj(1); + CPPUNIT_ASSERT_EQUAL(OUString("Rect"), pRectangleObject->GetName()); + + SdrObject* pTableObject = pPage1->GetObj(2); + CPPUNIT_ASSERT_EQUAL(OUString("Table1"), pTableObject->GetName()); + + // Scenario 1 + // 2 shapes - "Text Box" and "Rect" + // View1 - "Text Box" enters text edit mode, View 2 - moves the "Rect" around + { + sd::UndoManager* pUndoManager = pDocument->GetUndoManager(); + CPPUNIT_ASSERT_EQUAL(size_t(0), pUndoManager->GetUndoActionCount()); + + pView1->SdrBeginTextEdit(pTextBoxObject); + CPPUNIT_ASSERT_EQUAL(true, pView1->IsTextEdit()); + CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit()); + + // Local undo count for View1 is 0 + CPPUNIT_ASSERT_EQUAL(size_t(0), pView1->getViewLocalUndoManager()->GetUndoActionCount()); + // Write 'test' in View1 + SfxStringItem aInputString(SID_ATTR_CHAR, "test"); + pViewShell1->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR, SfxCallMode::SYNCHRON, { &aInputString }); + // Local undo count for View1 is now 1 + CPPUNIT_ASSERT_EQUAL(size_t(1), pView1->getViewLocalUndoManager()->GetUndoActionCount()); + + // Mark rectangle object + pView2->MarkObj(pRectangleObject, pView2->GetSdrPageView()); + + // Check the initial position of the object + tools::Rectangle aRectangle = pRectangleObject->GetLogicRect(); + CPPUNIT_ASSERT_EQUAL(6250L, aRectangle.TopLeft().X()); + CPPUNIT_ASSERT_EQUAL(7000L, aRectangle.TopLeft().Y()); + CPPUNIT_ASSERT_EQUAL(6501L, aRectangle.GetWidth()); + CPPUNIT_ASSERT_EQUAL(4501L, aRectangle.GetHeight()); + + // On View2 - Move handle 0 on the shape to a new position - resize + Point aNewPosition = aRectangle.TopLeft() + Point(-1250, -1000); + pView2->MoveShapeHandle(0, aNewPosition, -1); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(size_t(1), pUndoManager->GetUndoActionCount()); + + // Check the object has a new size + aRectangle = pRectangleObject->GetLogicRect(); + CPPUNIT_ASSERT_EQUAL(5000L, aRectangle.TopLeft().X()); + CPPUNIT_ASSERT_EQUAL(6000L, aRectangle.TopLeft().Y()); + CPPUNIT_ASSERT_EQUAL(7751L, aRectangle.GetWidth()); + CPPUNIT_ASSERT_EQUAL(5501L, aRectangle.GetHeight()); + + // View1 is still in text edit mode... + CPPUNIT_ASSERT_EQUAL(true, pView1->IsTextEdit()); + CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit()); + + // On View2 - relative move the shape to a different position + pView2->MoveMarkedObj(Size(1000, 2000), /*bCopy=*/false); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(size_t(2), pUndoManager->GetUndoActionCount()); + + // Check the object is at a different position + aRectangle = pRectangleObject->GetLogicRect(); + CPPUNIT_ASSERT_EQUAL(6000L, aRectangle.TopLeft().X()); + CPPUNIT_ASSERT_EQUAL(8000L, aRectangle.TopLeft().Y()); + CPPUNIT_ASSERT_EQUAL(7751L, aRectangle.GetWidth()); + CPPUNIT_ASSERT_EQUAL(5501L, aRectangle.GetHeight()); + + // View1 is still in text edit mode... + CPPUNIT_ASSERT_EQUAL(true, pView1->IsTextEdit()); + CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit()); + + // End Text edit - check undo count increase from 2 -> 3 + CPPUNIT_ASSERT_EQUAL(size_t(2), pUndoManager->GetUndoActionCount()); + pView1->SdrEndTextEdit(); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(size_t(3), pUndoManager->GetUndoActionCount()); + + // Check that both views exited the text edit mode + CPPUNIT_ASSERT_EQUAL(false, pView1->IsTextEdit()); + CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit()); + } + + // Scenario 2 + // 1 shapes - "Text Box" + // View1 - "Text Box" enters text edit mode, View 2 - moves the "Text Box" around + { + sd::UndoManager* pUndoManager = pDocument->GetUndoManager(); + CPPUNIT_ASSERT_EQUAL(size_t(3), pUndoManager->GetUndoActionCount()); + + pView1->SdrBeginTextEdit(pTextBoxObject); + CPPUNIT_ASSERT_EQUAL(true, pView1->IsTextEdit()); + CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit()); + + // Local undo count for View1 is 0 + CPPUNIT_ASSERT_EQUAL(size_t(0), pView1->getViewLocalUndoManager()->GetUndoActionCount()); + // Write 'test' in View1 + SfxStringItem aInputString(SID_ATTR_CHAR, "test"); + pViewShell1->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR, SfxCallMode::SYNCHRON, { &aInputString }); + // Local undo count for View1 is now 1 + CPPUNIT_ASSERT_EQUAL(size_t(1), pView1->getViewLocalUndoManager()->GetUndoActionCount()); + + // Mark rectangle object + pView2->MarkObj(pTextBoxObject, pView2->GetSdrPageView()); + + // Check the initial position of the object + tools::Rectangle aRectangle = pTextBoxObject->GetLogicRect(); + CPPUNIT_ASSERT_EQUAL(2250L, aRectangle.TopLeft().X()); + CPPUNIT_ASSERT_EQUAL(2000L, aRectangle.TopLeft().Y()); + CPPUNIT_ASSERT_EQUAL(4501L, aRectangle.GetWidth()); + CPPUNIT_ASSERT_EQUAL(2001L, aRectangle.GetHeight()); + + // On View2 - Move handle 0 on the shape to a new position - resize + Point aNewPosition = aRectangle.TopLeft() + Point(-1250, -1000); + pView2->MoveShapeHandle(0, aNewPosition, -1); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(size_t(4), pUndoManager->GetUndoActionCount()); + + // Check the object has a new size + aRectangle = pTextBoxObject->GetLogicRect(); + CPPUNIT_ASSERT_EQUAL(1000L, aRectangle.TopLeft().X()); + CPPUNIT_ASSERT_EQUAL(1000L, aRectangle.TopLeft().Y()); + CPPUNIT_ASSERT_EQUAL(4990L, aRectangle.GetWidth()); + CPPUNIT_ASSERT_EQUAL(2175L, aRectangle.GetHeight()); + + // View1 is still in text edit mode... + CPPUNIT_ASSERT_EQUAL(true, pView1->IsTextEdit()); + CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit()); + + // On View2 - relative move the shape to a different position + pView2->MoveMarkedObj(Size(1000, 2000), /*bCopy=*/false); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(size_t(5), pUndoManager->GetUndoActionCount()); + + // Check the object is at a different position + aRectangle = pTextBoxObject->GetLogicRect(); + CPPUNIT_ASSERT_EQUAL(2000L, aRectangle.TopLeft().X()); + CPPUNIT_ASSERT_EQUAL(3000L, aRectangle.TopLeft().Y()); + CPPUNIT_ASSERT_EQUAL(4990L, aRectangle.GetWidth()); + CPPUNIT_ASSERT_EQUAL(2175L, aRectangle.GetHeight()); + + // View1 is still in text edit mode... + CPPUNIT_ASSERT_EQUAL(true, pView1->IsTextEdit()); + CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit()); + + // End Text edit - check undo count increase from 5 -> 6 + CPPUNIT_ASSERT_EQUAL(size_t(5), pUndoManager->GetUndoActionCount()); + pView1->SdrEndTextEdit(); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(size_t(6), pUndoManager->GetUndoActionCount()); + + // Check that both views exited the text edit mode + CPPUNIT_ASSERT_EQUAL(false, pView1->IsTextEdit()); + CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit()); + } + + // Scenario 3 + // 1 shapes - "Table1" + // View1 - "Table1" enters text edit mode, View 2 - moves the "Table1" around + { + sd::UndoManager* pUndoManager = pDocument->GetUndoManager(); + CPPUNIT_ASSERT_EQUAL(size_t(6), pUndoManager->GetUndoActionCount()); + + pView1->SdrBeginTextEdit(pTableObject); + CPPUNIT_ASSERT_EQUAL(true, pView1->IsTextEdit()); + CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit()); + + // Local undo count for View1 is 0 + CPPUNIT_ASSERT_EQUAL(size_t(0), pView1->getViewLocalUndoManager()->GetUndoActionCount()); + // Write 'test' in View1 + SfxStringItem aInputString(SID_ATTR_CHAR, "test"); + pViewShell1->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR, SfxCallMode::SYNCHRON, { &aInputString }); + // Local undo count for View1 is now 1 + CPPUNIT_ASSERT_EQUAL(size_t(1), pView1->getViewLocalUndoManager()->GetUndoActionCount()); + + // Mark rectangle object + pView2->MarkObj(pTableObject, pView2->GetSdrPageView()); + + // Check the initial position of the table + tools::Rectangle aRectangle = pTableObject->GetLogicRect(); + CPPUNIT_ASSERT_EQUAL(2919L, aRectangle.TopLeft().X()); + CPPUNIT_ASSERT_EQUAL(18063L, aRectangle.TopLeft().Y()); + CPPUNIT_ASSERT_EQUAL(14099L, aRectangle.GetWidth()); + CPPUNIT_ASSERT_EQUAL(5999L, aRectangle.GetHeight()); + + // On View2 - relative move the shape to a different position + pView2->MoveMarkedObj(Size(1000, 2000), /*bCopy=*/false); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(size_t(7), pUndoManager->GetUndoActionCount()); + + // Check the object is at a different position + aRectangle = pTableObject->GetLogicRect(); + CPPUNIT_ASSERT_EQUAL(3919L, aRectangle.TopLeft().X()); + CPPUNIT_ASSERT_EQUAL(20063L, aRectangle.TopLeft().Y()); + CPPUNIT_ASSERT_EQUAL(14099L, aRectangle.GetWidth()); + CPPUNIT_ASSERT_EQUAL(5999L, aRectangle.GetHeight()); + + // View1 is still in text edit mode... + CPPUNIT_ASSERT_EQUAL(true, pView1->IsTextEdit()); + CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit()); + + // End Text edit - check undo count increase from 7 -> 8 + CPPUNIT_ASSERT_EQUAL(size_t(7), pUndoManager->GetUndoActionCount()); + pView1->SdrEndTextEdit(); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(size_t(8), pUndoManager->GetUndoActionCount()); + + // Check that both views exited the text edit mode + CPPUNIT_ASSERT_EQUAL(false, pView1->IsTextEdit()); + CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit()); + } +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |