Files
odfstudio/sd/qa/unit/uiimpress.cxx
T
Armin Le Grand (collabora) 5519a3d407 Correct StyleSheet handling when cloning to different Model II
Until now the 'local' StyleSheet got set, but that may
not be the same as the original. It was/gets identified just
by searching by name and type, not comparing content.

What to do? We could...

(a) the Style-Friendly way:
 - check if StyleSheet is identical
  - if not, create a new in-between StyleSheet hosting missing Items
  - if yes, use, done.

(b) the pragmatic/practical way:
 - Just hard-attribute the Items that are detected as different
   similar to what BurnInStyleSheetAttributes does/did, but only
   for a view differing Items

(b) is the most simple for now, but will lead to more hard
attributes. The other possibilities will be better in the
long term. For now, I will use (b).

Note that there are more cases in that VERY complex and grown
stuff emerging from SdDrawDocument::PasteBookmarkAsPage. More
things will need to be fixed, see this as a 1st step.

Needed to adapt postProcessAfterCloneToDifferentModel due to
UT testTdf96206 failing, see comment there for details.

That 1st implementation showed weaknesses with those Items
critical and only on MasterPages, so decided to give up on
that and implement ContentCompare to SdPage::Equals. That
was easier than thought: No parameter needed, only used by
InsertBookmarkAsPage_FindDuplicateLayouts::operator(). Thus,
SdPage::Equals needs no change, just SdrObject::Equals.

Due to still problems with Items corrected in Objects on
MasterPages I will for now exclude this.

Could now isolate remaining problems, these are defaults
and/or PresObj things on MasterPages. Important is that I can
completely correct all Items for all Objects in
postProcessAfterCloneToDifferentModel. I can react to these
false-positives in the ContentCompare in SdrObject::Equals.

Signed-off-by: Armin Le Grand (collabora) <Armin.LeGrand@collabora.com>
Change-Id: I10e17c8d6a893dbe92ab716182f07bafce1f3284
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/6595
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Armin Le Grand <armin.legrand@collabora.com>
(cherry picked from commit 92ffaeac04c5c8586006b026f29ce12fba3674f1)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/211729
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
2026-10-05 08:52:54 +02:00

2873 lines
129 KiB
C++

/* -*- 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 "sdmodeltestbase.hxx"
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/uno/Reference.hxx>
#include <com/sun/star/drawing/LineStyle.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/XDrawView.hpp>
#include <com/sun/star/drawing/XDrawPage.hpp>
#include <com/sun/star/drawing/XMasterPageTarget.hpp>
#include <com/sun/star/style/ParagraphAdjust.hpp>
#include <com/sun/star/table/XMergeableCell.hpp>
#include <com/sun/star/text/WritingMode2.hpp>
#include <com/sun/star/view/XSelectionSupplier.hpp>
#include <comphelper/propertysequence.hxx>
#include <editeng/adjustitem.hxx>
#include <editeng/editobj.hxx>
#include <editeng/editview.hxx>
#include <editeng/eeitem.hxx>
#include <editeng/flditem.hxx>
#include <editeng/outliner.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/request.hxx>
#include <sfx2/viewfrm.hxx>
#include <svl/intitem.hxx>
#include <svl/srchitem.hxx>
#include <svx/svxids.hrc>
#include <svx/svdoashp.hxx>
#include <svx/svdorect.hxx>
#include <svx/svdotable.hxx>
#include <svx/xlineit0.hxx>
#include <svx/xfillit0.hxx>
#include <svx/xflclit.hxx>
#include <svx/xflgrit.hxx>
#include <svx/xlndsit.hxx>
#include <svx/xlnedwit.hxx>
#include <svx/xlnstwit.hxx>
#include <SlideSorterViewShell.hxx>
#include <SlideSorter.hxx>
#include <controller/SlsClipboard.hxx>
#include <controller/SlideSorterController.hxx>
#include <controller/SlsPageSelector.hxx>
#include <sdmod.hxx>
#include <svl/stritem.hxx>
#include <undo/undomanager.hxx>
#include <vcl/scheduler.hxx>
#include <docmodel/uno/UnoComplexColor.hxx>
#include <comphelper/propertyvalue.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include <docmodel/uno/UnoTheme.hxx>
#include <docmodel/theme/Theme.hxx>
#include <drawdoc.hxx>
#include <DrawDocShell.hxx>
#include <ViewShell.hxx>
#include <OutlineView.hxx>
#include <Window.hxx>
#include <app.hrc>
#include <sdpage.hxx>
#include <vcl/bitmap.hxx>
#include <vcl/transfer.hxx>
#include <unomodel.hxx>
#include <osl/thread.hxx>
#include <slideshow.hxx>
#include <sdresid.hxx>
#include <strings.hrc>
#include <unopage.hxx>
using namespace ::com::sun::star;
/// Impress UI tests.
class SdUiImpressTest : public SdModelTestBase
{
public:
SdUiImpressTest()
: SdModelTestBase(u"/sd/qa/unit/data/"_ustr)
{
}
void checkCurrentPageNumber(sal_uInt16 nNum);
void insertStringToObject(sal_uInt16 nObj, std::u16string_view rStr, bool bUseEscape);
sd::slidesorter::SlideSorterViewShell*
getSlideSorterViewShell(const css::uno::Reference<css::lang::XComponent>& xComp = nullptr);
void lcl_search(const OUString& rKey, bool bFindAll = false, bool bBackwards = false);
// Opens a new presentation in Outline view, with one slide per title.
OutlinerView* createOutlineView(std::initializer_list<std::u16string_view> aTitles);
// Sends keys to the Outline view, where postKeyEvent() does not reach.
void typeOutlineKey(sal_uInt16 nKey);
void typeOutlineString(std::u16string_view aStr);
};
void SdUiImpressTest::typeOutlineKey(sal_uInt16 nKey)
{
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pImpressDocument->GetDocShell()->GetViewShell();
pViewShell->KeyInput(KeyEvent(0, vcl::KeyCode(nKey)), pViewShell->GetActiveWindow());
Scheduler::ProcessEventsToIdle();
}
void SdUiImpressTest::typeOutlineString(std::u16string_view aStr)
{
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pImpressDocument->GetDocShell()->GetViewShell();
for (const char16_t c : aStr)
pViewShell->KeyInput(KeyEvent(c, vcl::KeyCode()), pViewShell->GetActiveWindow());
Scheduler::ProcessEventsToIdle();
}
OutlinerView* SdUiImpressTest::createOutlineView(std::initializer_list<std::u16string_view> aTitles)
{
createSdImpressDoc();
dispatchCommand(mxComponent, u".uno:OutlineMode"_ustr, {});
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
CPPUNIT_ASSERT(pImpressDocument);
sd::ViewShell* pViewShell = pImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT_EQUAL(sd::ViewShell::ST_OUTLINE, pViewShell->GetShellType());
auto pView = static_cast<sd::SimpleOutlinerView*>(pViewShell->GetView());
OutlinerView* pOutlinerView = pView->GetViewByWindow(pViewShell->GetActiveWindow());
CPPUNIT_ASSERT(pOutlinerView);
bool bFirst = true;
for (const std::u16string_view& aTitle : aTitles)
{
if (!std::exchange(bFirst, false))
typeOutlineKey(KEY_RETURN);
typeOutlineString(aTitle);
}
CPPUNIT_ASSERT_EQUAL(sal_uInt16(aTitles.size()),
pImpressDocument->GetDoc()->GetSdPageCount(PageKind::Standard));
return pOutlinerView;
}
void SdUiImpressTest::checkCurrentPageNumber(sal_uInt16 nNum)
{
uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawView> xDrawView(xModel->getCurrentController(), uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xPage(xDrawView->getCurrentPage(), uno::UNO_SET_THROW);
uno::Reference<beans::XPropertySet> xPropertySet(xPage, uno::UNO_QUERY);
sal_uInt16 nPageNumber;
xPropertySet->getPropertyValue(u"Number"_ustr) >>= nPageNumber;
CPPUNIT_ASSERT_EQUAL(nNum, nPageNumber);
}
void SdUiImpressTest::insertStringToObject(sal_uInt16 nObj, std::u16string_view rStr,
bool bUseEscape)
{
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SdPage* pPage = pViewShell->GetActualPage();
SdrObject* pShape = pPage->GetObj(nObj);
CPPUNIT_ASSERT_MESSAGE("No Shape", pShape);
SdrView* pView = pViewShell->GetView();
pView->MarkObj(pShape, pView->GetSdrPageView());
Scheduler::ProcessEventsToIdle();
CPPUNIT_ASSERT(!pView->IsTextEdit());
typeString(pImpressDocument, rStr);
CPPUNIT_ASSERT(pView->IsTextEdit());
if (bUseEscape)
{
typeKey(pImpressDocument, KEY_ESCAPE);
CPPUNIT_ASSERT(!pView->IsTextEdit());
}
}
sd::slidesorter::SlideSorterViewShell*
SdUiImpressTest::getSlideSorterViewShell(const css::uno::Reference<css::lang::XComponent>& xComp)
{
auto pXImpressDocument
= dynamic_cast<SdXImpressDocument*>(xComp.is() ? xComp.get() : mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
sd::slidesorter::SlideSorterViewShell* pSSVS = nullptr;
// Same as in sd/qa/unit/misc-tests.cxx
for (int i = 0; i < 1000; i++)
{
// Process all Tasks - slide sorter is created here
Scheduler::ProcessEventsToIdle();
if ((pSSVS = sd::slidesorter::SlideSorterViewShell::GetSlideSorter(
pViewShell->GetViewShellBase()))
!= nullptr)
break;
osl::Thread::wait(std::chrono::milliseconds(100));
}
CPPUNIT_ASSERT(pSSVS);
return pSSVS;
}
void SdUiImpressTest::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, u".uno:ExecuteSearch"_ustr, aPropertyValues);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testDocumentStructureTransformExtractSlide)
{
createSdImpressDoc("odp/tdf161430.odp");
static constexpr OUString aJson = uR"json(
{
"Transforms": {
"SlideCommands": [
{"JumpToSlideByName": "Slide 3"},
{"MoveSlide": 0},
{"RenameSlide": "Slide3-Renamed"},
{"DeleteSlide": 2},
{"JumpToSlide": 2},
{"DeleteSlide": ""},
{"JumpToSlide": 1},
{"DuplicateSlide": ""},
{"RenameSlide": "Slide1-Duplicated"},
{"InsertMasterSlide": 1},
{"RenameSlide": "SlideInserted-1"},
{"ChangeLayout": 18},
{"JumpToSlide": "last"},
{"InsertMasterSlideByName": "Topic Separator white"},
{"RenameSlide": "SlideInserted-Name"},
{"ChangeLayoutByName": "AUTOLAYOUT_TITLE_2CONTENT"},
{"SetText.0": "first"},
{"SetText.1": "second"},
{"SetText.2": "third"},
{"DuplicateSlide": 1},
{"MoveSlide.2": 6}
]
}
}
)json"_ustr;
//transform
uno::Sequence<css::beans::PropertyValue> aArgs = {
comphelper::makePropertyValue(u"DataJson"_ustr, aJson),
};
dispatchCommand(mxComponent, u".uno:TransformDocumentStructure"_ustr, aArgs);
//extract
tools::JsonWriter aJsonWriter;
std::string_view aCommand(".uno:ExtractDocumentStructure?filter=slides");
auto pXPresDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
pXPresDocument->getCommandValues(aJsonWriter, aCommand);
OString aExpectedStr
= "{ \"DocStructure\": { \"SlideCount\": 7, \"MasterSlideCount\": 8, \"MasterSlides\": { "
"\"MasterSlide 0\": { \"Name\": \"Topic_Separator_Purple\"}, \"MasterSlide 1\": { "
"\"Name\": \"Content_sidebar_White\"}, \"MasterSlide 2\": { \"Name\": \"Topic Separator "
"white\"}, \"MasterSlide 3\": { \"Name\": \"Content_sidebar_White_\"}, \"MasterSlide "
"4\": { \"Name\": \"Topic_Separator_Purple_\"}, \"MasterSlide 5\": { \"Name\": "
"\"Content_White_Purple_Sidebar\"}, \"MasterSlide 6\": { \"Name\": \"Default 1\"}, "
"\"MasterSlide 7\": { \"Name\": \"Default 1_\"}}, \"Slides\": { \"Slide 0\": { "
"\"SlideName\": \"Slide3-Renamed\", \"MasterSlideName\": "
"\"Content_White_Purple_Sidebar\", \"LayoutId\": 3, \"LayoutName\": "
"\"AUTOLAYOUT_TITLE_2CONTENT\", \"ObjectCount\": 4, \"Objects\": { \"Objects 0\": { "
"\"TextCount\": 1, \"Texts\": { \"Text 0\": { \"ParaCount\": 1, \"Paragraphs\": [ "
"\"Friendly Open Source Project\"]}}}, \"Objects 1\": { }, \"Objects 2\": { "
"\"TextCount\": 1, \"Texts\": { \"Text 0\": { \"ParaCount\": 9, \"Paragraphs\": [ \"Real "
"Open Source\", \"100% open-source code\", \"Built with LibreOffice technology\", "
"\"Built with Free Software technology stacks: primarily C++\", \"Runs best on Linux\", "
"\"Open Development\", \"Anyone can contribute & participate\", \"Follow commits and "
"tickets\", \"Public community calls - forum has details\"]}}}, \"Objects 3\": { "
"\"TextCount\": 1, \"Texts\": { \"Text 0\": { \"ParaCount\": 5, \"Paragraphs\": [ "
"\"Focus:\", \"a non-renewable resource.\", \"Office Productivity & Documents\", "
"\"Excited about migrating your\\u0001documents\", \"Grateful to our partners for "
"solving\\u0001other problems.\"]}}}}}, \"Slide 1\": { \"SlideName\": \"Slide 2\", "
"\"MasterSlideName\": \"Topic_Separator_Purple\", \"LayoutId\": 3, \"LayoutName\": "
"\"AUTOLAYOUT_TITLE_2CONTENT\", \"ObjectCount\": 1, \"Objects\": { \"Objects 0\": { "
"\"TextCount\": 1, \"Texts\": { \"Text 0\": { \"ParaCount\": 3, \"Paragraphs\": [ "
"\"Collabora Online\", \"\", \"Powerful Online Collaboration\"]}}}}}, \"Slide 2\": { "
"\"SlideName\": \"Slide1-Duplicated\", \"MasterSlideName\": \"Topic_Separator_Purple\", "
"\"LayoutId\": 3, \"LayoutName\": \"AUTOLAYOUT_TITLE_2CONTENT\", \"ObjectCount\": 1, "
"\"Objects\": { \"Objects 0\": { \"TextCount\": 1, \"Texts\": { \"Text 0\": { "
"\"ParaCount\": 3, \"Paragraphs\": [ \"Collabora Online\", \"\", \"Powerful Online "
"Collaboration\"]}}}}}, \"Slide 3\": { \"SlideName\": \"SlideInserted-1\", "
"\"MasterSlideName\": \"Content_sidebar_White\", \"LayoutId\": 18, \"LayoutName\": "
"\"AUTOLAYOUT_TITLE_4CONTENT\", \"ObjectCount\": 5, \"Objects\": { \"Objects 0\": { "
"\"TextCount\": 1, \"Texts\": { \"Text 0\": { \"ParaCount\": 1, \"Paragraphs\": [ "
"\"Click to add Title\"]}}}, \"Objects 1\": { \"TextCount\": 1, \"Texts\": { \"Text 0\": "
"{ \"ParaCount\": 1, \"Paragraphs\": [ \"Click to add Text\"]}}}, \"Objects 2\": { "
"\"TextCount\": 1, \"Texts\": { \"Text 0\": { \"ParaCount\": 1, \"Paragraphs\": [ "
"\"Click to add Text\"]}}}, \"Objects 3\": { \"TextCount\": 1, \"Texts\": { \"Text 0\": "
"{ \"ParaCount\": 1, \"Paragraphs\": [ \"Click to add Text\"]}}}, \"Objects 4\": { "
"\"TextCount\": 1, \"Texts\": { \"Text 0\": { \"ParaCount\": 1, \"Paragraphs\": [ "
"\"Click to add Text\"]}}}}}, \"Slide 4\": { \"SlideName\": \"Slide 5\", "
"\"MasterSlideName\": \"Topic_Separator_Purple\", \"LayoutId\": 3, \"LayoutName\": "
"\"AUTOLAYOUT_TITLE_2CONTENT\", \"ObjectCount\": 1, \"Objects\": { \"Objects 0\": { "
"\"TextCount\": 1, \"Texts\": { \"Text 0\": { \"ParaCount\": 1, \"Paragraphs\": [ \"With "
"thanks to our Partners, Customers & Community !\"]}}}}}, \"Slide 5\": { \"SlideName\": "
"\"SlideInserted-Name\", \"MasterSlideName\": \"Topic Separator white\", \"LayoutId\": "
"3, \"LayoutName\": \"AUTOLAYOUT_TITLE_2CONTENT\", \"ObjectCount\": 3, \"Objects\": { "
"\"Objects 0\": { \"TextCount\": 1, \"Texts\": { \"Text 0\": { \"ParaCount\": 1, "
"\"Paragraphs\": [ \"first\"]}}}, \"Objects 1\": { \"TextCount\": 1, \"Texts\": { \"Text "
"0\": { \"ParaCount\": 1, \"Paragraphs\": [ \"second\"]}}}, \"Objects 2\": { "
"\"TextCount\": 1, \"Texts\": { \"Text 0\": { \"ParaCount\": 1, \"Paragraphs\": [ "
"\"third\"]}}}}}, \"Slide 6\": { \"SlideName\": \"Slide 7\", \"MasterSlideName\": "
"\"Topic_Separator_Purple\", \"LayoutId\": 3, \"LayoutName\": "
"\"AUTOLAYOUT_TITLE_2CONTENT\", \"ObjectCount\": 1, \"Objects\": { \"Objects 0\": { "
"\"TextCount\": 1, \"Texts\": { \"Text 0\": { \"ParaCount\": 3, \"Paragraphs\": [ "
"\"Collabora Online\", \"\", \"Powerful Online Collaboration\"]}}}}}}}}"_ostr;
CPPUNIT_ASSERT_EQUAL(aExpectedStr, aJsonWriter.finishAndGetAsOString());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testDocumentStructureUnoCommand)
{
// 1. Create a document;
// 2. Check that its first slide has two objects (the default title + content placeholders);
// 3. Perform a "TransformDocumentStructure" with a "UnoCommand" calling ".uno:SelectAll" and
// ".uno:Cut";
// 4. Check that the first slide has no objects now.
createSdImpressDoc();
// Let comphelper::dispatchCommand (in SfxLokHelper::dispatchUnoCommand) find the frame
auto xDesktop = frame::Desktop::create(comphelper::getProcessComponentContext());
auto pImpressDocument = static_cast<SdXImpressDocument*>(mxComponent.get());
auto pFrame = pImpressDocument->GetDocShell()->GetFrame();
CPPUNIT_ASSERT(pFrame);
xDesktop->setActiveFrame(pFrame->GetFrame().GetFrameInterface());
CPPUNIT_ASSERT_EQUAL(sal_Int32(2),
pImpressDocument->getSdDrawPages()->getDrawPageByIndex(0)->getCount());
static constexpr OUString aJson = uR"json(
{
"UnoCommand": {
"name": ".uno:SelectAll"
},
"UnoCommand": {
"name": ".uno:Cut"
}
}
)json"_ustr;
dispatchCommand(mxComponent, u".uno:TransformDocumentStructure"_ustr,
{ comphelper::makePropertyValue(u"DataJson"_ustr, aJson) });
CPPUNIT_ASSERT_EQUAL(sal_Int32(0),
pImpressDocument->getSdDrawPages()->getDrawPageByIndex(0)->getCount());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf111522)
{
// Load the document and create two new windows.
createSdImpressDoc("tdf111522.odp");
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_NEWWINDOW, SfxCallMode::SYNCHRON);
sd::ViewShell* pViewShell1 = pImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell1);
pViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_NEWWINDOW, SfxCallMode::SYNCHRON);
sd::ViewShell* pViewShell2 = pImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell2);
CPPUNIT_ASSERT(pViewShell1 != pViewShell2);
// Have slide 1 in window 1, slide 2 in window 2.
SfxRequest aRequest(*pViewShell2->GetViewFrame(), SID_SWITCHPAGE);
aRequest.AppendItem(SfxUInt32Item(ID_VAL_WHATPAGE, 1));
aRequest.AppendItem(
SfxUInt32Item(ID_VAL_WHATKIND, static_cast<sal_uInt32>(PageKind::Standard)));
pViewShell2->ExecuteSlot(aRequest, /*bAsync=*/false);
// Start text edit in window 1.
SdPage* pPage1 = pViewShell1->GetActualPage();
SdrObject* pShape1 = pPage1->GetObj(0);
SdrView* pView1 = pViewShell1->GetView();
pView1->MarkObj(pShape1, pView1->GetSdrPageView());
pView1->SdrBeginTextEdit(pShape1);
CPPUNIT_ASSERT(pView1->IsTextEdit());
// Move the shape in window 2 & undo.
SdPage* pPage2 = pViewShell2->GetActualPage();
CPPUNIT_ASSERT(pPage1 != pPage2);
SdrObject* pShape2 = pPage2->GetObj(0);
SdrView* pView2 = pViewShell2->GetView();
pView2->MarkObj(pShape2, pView2->GetSdrPageView());
pView2->MoveMarkedObj(Size(1, 1), /*bCopy=*/false);
// Without the accompanying fix in place, this test would have failed with an assertion failure
// in SdrObjEditView::SdrEndTextEdit() as mpOldTextEditUndoManager was not nullptr.
pViewShell2->GetViewFrame()->GetDispatcher()->Execute(SID_UNDO, SfxCallMode::SYNCHRON);
// Rotate the shape in window 2 & undo.
pView2->MarkObj(pShape2, pView2->GetSdrPageView());
pView2->RotateMarkedObj(pShape2->GetLastBoundRect().Center(), /*nAngle=*/45_deg100);
// Without the accompanying fix in place, this test would have failed with an assertion failure
// in SdrObjEditView::SdrEndTextEdit() as mpOldTextEditUndoManager was not nullptr.
pViewShell2->GetViewFrame()->GetDispatcher()->Execute(SID_UNDO, SfxCallMode::SYNCHRON);
// Start text edit in window 2.
// tdf#125824
pView2->MarkObj(pShape2, pView2->GetSdrPageView());
pView2->SdrBeginTextEdit(pShape2);
CPPUNIT_ASSERT(pView2->IsTextEdit());
// Write 'test' inside the shape
SfxStringItem aInputString(SID_ATTR_CHAR, u"test"_ustr);
pViewShell2->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR, SfxCallMode::SYNCHRON,
{ &aInputString });
CPPUNIT_ASSERT(pView2->GetTextEditObject());
EditView& rEditView = pView2->GetTextEditOutlinerView()->GetEditView();
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), rEditView.GetSelection().start.nIndex);
pView2->SdrEndTextEdit();
// Without the accompanying fix in place, this test would have failed with an assertion failure
// in SdrObjEditView::SdrEndTextEdit() as mpOldTextEditUndoManager was not nullptr.
pViewShell2->GetViewFrame()->GetDispatcher()->Execute(SID_UNDO, SfxCallMode::SYNCHRON);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf126197)
{
// Load the document and create two new windows.
createSdImpressDoc("tdf126197.odp");
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_NEWWINDOW, SfxCallMode::SYNCHRON);
sd::ViewShell* pViewShell1 = pImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell1);
pViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_NEWWINDOW, SfxCallMode::SYNCHRON);
sd::ViewShell* pViewShell2 = pImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell2);
CPPUNIT_ASSERT(pViewShell1 != pViewShell2);
// Start text edit in window 1.
SdPage* pPage1 = pViewShell1->GetActualPage();
SdrObject* pShape1 = pPage1->GetObj(0);
SdrView* pView1 = pViewShell1->GetView();
pView1->MarkObj(pShape1, pView1->GetSdrPageView());
pView1->SdrBeginTextEdit(pShape1);
CPPUNIT_ASSERT(pView1->IsTextEdit());
SdPage* pPage2 = pViewShell2->GetActualPage();
CPPUNIT_ASSERT_EQUAL(pPage1, pPage2);
SdrObject* pShape2 = pPage2->GetObj(0);
CPPUNIT_ASSERT_EQUAL(pShape1, pShape2);
SdrView* pView2 = pViewShell2->GetView();
pView2->MarkObj(pShape2, pView2->GetSdrPageView());
// Without the accompanying fix in place, this test would have failed with an assertion failure
// in SdrObjEditView::SdrEndTextEdit()
pViewShell2->GetViewFrame()->GetDispatcher()->Execute(SID_DELETE, SfxCallMode::SYNCHRON);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf124708)
{
createSdImpressDoc("tdf124708.ppt");
dispatchCommand(mxComponent, u".uno:NextPage"_ustr, {});
checkCurrentPageNumber(2);
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SdPage* pActualPage = pViewShell->GetActualPage();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(16), pActualPage->GetObjCount());
dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
// Without the fix in place, this test would have crashed here
dispatchCommand(mxComponent, u".uno:Delete"_ustr, {});
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pActualPage->GetObjCount());
dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(16), pActualPage->GetObjCount());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf159666)
{
createSdDrawDoc("tdf159666.odg");
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SdPage* pActualPage = pViewShell->GetActualPage();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(12), pActualPage->GetObjCount());
// Without the fix in place, this test would have crashed here
dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
dispatchCommand(mxComponent, u".uno:Delete"_ustr, {});
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pActualPage->GetObjCount());
dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(12), pActualPage->GetObjCount());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf143412)
{
createSdImpressDoc();
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SdPage* pActualPage = pViewShell->GetActualPage();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pActualPage->GetObjCount());
OUString aImageURL = createFileURL(u"tdf143412.svg");
uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence({
{ "FileName", uno::Any(aImageURL) },
}));
dispatchCommand(mxComponent, u".uno:InsertGraphic"_ustr, aArgs);
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pActualPage->GetObjCount());
// Without the fix in place, this test would have crashed
// Check that converting an image to the different options doesn't crash
dispatchCommand(mxComponent, u".uno:ChangeBezier"_ustr, {});
dispatchCommand(mxComponent, u".uno:ChangePolygon"_ustr, {});
dispatchCommand(mxComponent, u".uno:convert_to_contour"_ustr, {});
dispatchCommand(mxComponent, u".uno:ConvertInto3D"_ustr, {});
dispatchCommand(mxComponent, u".uno:ConvertInto3DLatheFast"_ustr, {});
dispatchCommand(mxComponent, u".uno:ConvertIntoBitmap"_ustr, {});
dispatchCommand(mxComponent, u".uno:ConvertIntoMetaFile"_ustr, {});
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pActualPage->GetObjCount());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf155211_dashed_line)
{
createSdImpressDoc();
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SdPage* pActualPage = pViewShell->GetActualPage();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pActualPage->GetObjCount());
OUString aImageURL = createFileURL(u"tdf155211_dashed_line.svg");
uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence({
{ "FileName", uno::Any(aImageURL) },
}));
dispatchCommand(mxComponent, u".uno:InsertGraphic"_ustr, aArgs);
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pActualPage->GetObjCount());
// split the (auto-selected) svg
dispatchCommand(mxComponent, u".uno:Break"_ustr, {});
SdrObject* pObject = pActualPage->GetObj(2);
const XLineStyleItem& rStyleItem = pObject->GetMergedItem(XATTR_LINESTYLE);
// tdf#115162: Without the fix in place, this test would have failed with
// - Expected: 2 (LineStyle_DASH)
// - Actual : 1 (LineStyle_SOLID)
CPPUNIT_ASSERT_EQUAL(drawing::LineStyle_DASH, rStyleItem.GetValue());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf169813_prevent_unintended_dashed_line)
{
createSdImpressDoc();
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SdPage* pActualPage = pViewShell->GetActualPage();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pActualPage->GetObjCount());
OUString aImageURL = createFileURL(u"tdf169813_prevent_unintended_dashed_line.svg");
uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence({
{ "FileName", uno::Any(aImageURL) },
}));
dispatchCommand(mxComponent, u".uno:InsertGraphic"_ustr, aArgs);
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pActualPage->GetObjCount());
// split the (auto-selected) svg
dispatchCommand(mxComponent, u".uno:Break"_ustr, {});
SdrObject* pObject = pActualPage->GetObj(3);
const XLineStyleItem& rStyleItem = pObject->GetMergedItem(XATTR_LINESTYLE);
// tdf#169813: Without the fix in place, this test would have failed with
// - Expected: 0 (LineStyle_NONE)
// - Actual : 2 (LineStyle_DASH)
CPPUNIT_ASSERT_EQUAL(drawing::LineStyle_NONE, rStyleItem.GetValue());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf148629_disabled_demote_command)
{
createSdImpressDoc();
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
CPPUNIT_ASSERT(pXImpressDocument);
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
// Start text edit of the empty content shape
SdPage* pActualPage = pViewShell->GetActualPage();
pActualPage->SetAutoLayout(AUTOLAYOUT_TITLE_CONTENT, true);
insertStringToObject(1, u"List Item", /*bUseEscape*/ false);
// Check that the demote command is enabled
std::unique_ptr<SfxPoolItem> pItem;
CPPUNIT_ASSERT_EQUAL(
SfxItemState::DEFAULT,
pViewShell->GetViewFrame()->GetBindings().QueryState(SID_OUTLINE_RIGHT, pItem));
// Start text edit of the empty title shape
typeKey(pXImpressDocument, KEY_ESCAPE);
insertStringToObject(0, u"Title", /*bUseEscape*/ false);
// Without the fix in place, this test would have failed with:
// - Expected: 1 (SfxItemState::DISABLED)
// - Actual : 32 (SfxItemState::DEFAULT)
// i.e. the demote command was not disabled
CPPUNIT_ASSERT_EQUAL(
SfxItemState::DISABLED,
pViewShell->GetViewFrame()->GetBindings().QueryState(SID_OUTLINE_RIGHT, pItem));
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf162455)
{
createSdImpressDoc();
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SdPage* pActualPage = pViewShell->GetActualPage();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pActualPage->GetObjCount());
OUString aImageURL = createFileURL(u"tdf162455.svg");
uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence({
{ "FileName", uno::Any(aImageURL) },
}));
dispatchCommand(mxComponent, u".uno:InsertGraphic"_ustr, aArgs);
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pActualPage->GetObjCount());
// split the (auto-selected) svg up
dispatchCommand(mxComponent, u".uno:Break"_ustr, {});
// Get the newly created shape that has the text '100' in it
uno::Reference<beans::XPropertySet> xShape(getShapeFromPage(4, 0));
uno::Reference<text::XTextRange> xParagraph1(getParagraphFromShape(0, xShape));
uno::Reference<text::XTextRange> xRun(getRunFromParagraph(0, xParagraph1));
CPPUNIT_ASSERT_EQUAL(u"100"_ustr, xRun->getString());
uno::Reference<beans::XPropertySet> xPropSet1(xRun, uno::UNO_QUERY);
double fFontSize1 = xPropSet1->getPropertyValue(u"CharHeight"_ustr).get<double>();
/* before this fix the font sizes were way too small
- Expected: 7.5
- Actual : 0.300000011920929 */
CPPUNIT_ASSERT_DOUBLES_EQUAL(7.5, fFontSize1, 0.01);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testSetHyperlinkKeepSelection)
{
// Given an Impress doc with a rectangle shape, in text edit mode, with "f" typed and
// selected:
createSdImpressDoc();
auto* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
SdrView* pView = pViewShell->GetView();
SdPage* pPage = pViewShell->GetActualPage();
rtl::Reference<SdrRectObj> pRect
= new SdrRectObj(pView->getSdrModelFromSdrView(), tools::Rectangle(1000, 1000, 5000, 5000));
pPage->NbcInsertObject(pRect.get());
pView->MarkObj(pRect.get(), pView->GetSdrPageView());
pView->SdrBeginTextEdit(pRect.get());
CPPUNIT_ASSERT(pView->IsTextEdit());
SfxStringItem aInputString(SID_ATTR_CHAR, u"f"_ustr);
pViewShell->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR, SfxCallMode::SYNCHRON,
{ &aInputString });
OutlinerView* pOlView = pView->GetTextEditOutlinerView();
CPPUNIT_ASSERT(pOlView);
pOlView->SetSelection(ESelection(0, 0, 0, 1));
CPPUNIT_ASSERT(pOlView->HasSelection());
// When dispatching .uno:SetHyperlink with Hyperlink.Text differing from the selection,
// but marked as a hint:
uno::Sequence<beans::PropertyValue> aArgs = {
comphelper::makePropertyValue(u"Hyperlink.Text"_ustr, uno::Any(u"mytext"_ustr)),
comphelper::makePropertyValue(u"Hyperlink.TextIsHint"_ustr, uno::Any(true)),
comphelper::makePropertyValue(u"Hyperlink.URL"_ustr,
uno::Any(u"http://www.example.com"_ustr)),
};
dispatchCommand(mxComponent, u".uno:SetHyperlink"_ustr, aArgs);
// Then make sure the previously-selected character is preserved as the URL field's
// displayed text, not replaced by Hyperlink.Text:
pView->SdrEndTextEdit();
const OutlinerParaObject* pOPO = pRect->GetOutlinerParaObject();
CPPUNIT_ASSERT(pOPO);
const SvxFieldData* pField
= pOPO->GetTextObject().GetFieldData(0, 0, css::text::textfield::Type::URL);
auto* pURLField = dynamic_cast<const SvxURLField*>(pField);
CPPUNIT_ASSERT(pURLField);
// Without the accompanying fix in place, this test would have failed with:
// - Expected: f
// - Actual : mytext
// i.e. the selected character was lost, the provided text hint was used.
CPPUNIT_ASSERT_EQUAL(u"f"_ustr, pURLField->GetRepresentation());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testSlidePasteSizeMismatch)
{
// Given a 4:3 presentation, with the first slide selected:
createSdImpressDoc("odp/4-3.odp");
sd::slidesorter::controller::SlideSorterController& rSrcCtl
= getSlideSorterViewShell()->GetSlideSorter().GetController();
auto pSrcImpress = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdPage* pSrcFirst = pSrcImpress->GetDoc()->GetSdPage(0, PageKind::Standard);
rSrcCtl.GetPageSelector().DeselectAllPages();
rSrcCtl.GetPageSelector().SelectPage(pSrcFirst);
// When copying that slide and pasting it into a 16:9 presentation:
rSrcCtl.GetClipboard().DoCopy();
// Disable internal paste to hit the clipboard save + load code-path.
SdModule::get()->pTransferClip = nullptr;
mxComponent2 = loadFromDesktop(createFileURL(u"odp/16-9.odp"),
u"com.sun.star.presentation.PresentationDocument"_ustr);
auto* pDstImpress = dynamic_cast<SdXImpressDocument*>(mxComponent2.get());
SdDrawDocument* pDstDoc = pDstImpress->GetDoc();
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1), pDstDoc->GetSdPageCount(PageKind::Standard));
sd::slidesorter::SlideSorterViewShell* pDstSSVS = getSlideSorterViewShell(mxComponent2);
sd::slidesorter::controller::SlideSorterController& rDstCtl
= pDstSSVS->GetSlideSorter().GetController();
SdPage* pDstLast = pDstDoc->GetSdPage(0, PageKind::Standard);
rDstCtl.GetPageSelector().DeselectAllPages();
rDstCtl.GetPageSelector().SelectPage(pDstLast);
rDstCtl.GetClipboard().PasteSlidesFromSystemClipboard();
// Then make sure paste results in 2 slides:
sal_uInt16 nActualPageCount = pDstDoc->GetSdPageCount(PageKind::Standard);
// Without the accompanying fix in place, this test would have failed with:
// - Expected: 2
// - Actual : 1
// i.e. an unexpected non-async dialog popped up, which gets cancelled in silent mode, so the
// paste fails.
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(2), nActualPageCount);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf96206)
{
// Copying/pasting slide referring to a non-default master with a text duplicated the master
createSdImpressDoc("odp/tdf96206.odp");
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
const sal_uInt16 nMasterPageCnt1 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), nMasterPageCnt1);
rSSController.GetClipboard().DoCopy();
rSSController.GetClipboard().DoPaste();
const sal_uInt16 nMasterPageCnt2 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(nMasterPageCnt1, nMasterPageCnt2);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testDocumentCut)
{
// Test cutting slides and verifying the document state afterwards
createSdImpressDoc("odp/tdf96206.odp");
// Get the slide sorter and controller
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
// Get document and initial page count
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
// Get initial page count
const sal_uInt16 nInitialPageCount = pDoc->GetSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT(nInitialPageCount > 0);
// Select all slides
rSSController.GetPageSelector().SelectAllPages();
// Check that slides are selected
CPPUNIT_ASSERT(rSSController.GetPageSelector().GetSelectedPageCount() > 0);
// Cut the selected slides
rSSController.GetClipboard().DoCut();
// Paste the cut slides
rSSController.GetClipboard().DoPaste();
// After pasting, we should have at least the initial number of pages
const sal_uInt16 nPageCountAfterPaste = pDoc->GetSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT(nPageCountAfterPaste >= nInitialPageCount);
// Verify that master page count remains unchanged throughout the operation
const sal_uInt16 nMasterPageCount = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), nMasterPageCount);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf96708)
{
createSdImpressDoc("odp/tdf96708.odp");
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
auto& rPageSelector = rSSController.GetPageSelector();
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
const sal_uInt16 nMasterPageCnt1 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(4), nMasterPageCnt1);
rSSController.GetClipboard().DoCopy();
rPageSelector.SelectAllPages();
// Now wait for timers to trigger creation of auto-layout
osl::Thread::wait(std::chrono::milliseconds(100));
Scheduler::ProcessEventsToIdle();
rSSController.GetClipboard().DoPaste();
const sal_uInt16 nMasterPageCnt2 = pDoc->GetMasterSdPageCount(PageKind::Standard);
//FIXME: tdf#151802: Number of master pages should be 4, it's 5 instead
// CPPUNIT_ASSERT_EQUAL(nMasterPageCnt1, nMasterPageCnt2);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(5), nMasterPageCnt2);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf45617_default_master)
{
// Copying/pasting slide referring to a master page.
createSdImpressDoc("odp/tdf96206.odp");
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
const sal_uInt16 nMasterPageCnt1 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), nMasterPageCnt1);
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
const sal_uInt16 nMasterPageCnt2 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(nMasterPageCnt1 + 1), nMasterPageCnt2);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf45617)
{
// Copying/pasting slide referring to a master page.
createSdImpressDoc("odp/tdf96708.odp");
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
const sal_uInt16 nMasterPageCnt1 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(4), nMasterPageCnt1);
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
const sal_uInt16 nMasterPageCnt2 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(nMasterPageCnt1 + 1), nMasterPageCnt2);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf45617_test_master_name)
{
// Copying/pasting slide referring to a master page.
createSdImpressDoc("odp/tdf96708.odp");
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
// Get the master page name
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
SdPage* pMasterPage = pDoc->GetMasterSdPage(0, PageKind::Standard);
OUString aMasterPageName = pMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"Master0"_ustr, aMasterPageName);
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
SdPage* pNewMasterPage = pDoc->GetMasterSdPage(4, PageKind::Standard);
OUString aNewMasterPageName = pNewMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"1_Master0"_ustr, aNewMasterPageName);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf45617_test_default_master_name)
{
// Copying/pasting slide referring to a master page.
createSdImpressDoc();
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
// Get the master page name
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
SdPage* pMasterPage = pDoc->GetMasterSdPage(0, PageKind::Standard);
OUString aMasterPageName = pMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"Default"_ustr, aMasterPageName);
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
SdPage* pNewMasterPage = pDoc->GetMasterSdPage(0, PageKind::Standard);
OUString aNewMasterPageName = pNewMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"1_Default"_ustr, aNewMasterPageName);
rSSController.GetClipboard().DoPaste(true);
SdPage* pNewMasterPage2 = pDoc->GetMasterSdPage(1, PageKind::Standard);
OUString aNewMasterPageName2 = pNewMasterPage2->GetName();
CPPUNIT_ASSERT_EQUAL(u"2_Default"_ustr, aNewMasterPageName2);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf45617_basic_master_name)
{
// Basic test for copying/pasting slide referring to a master page
createSdImpressDoc("odp/tdf96708.odp");
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
SdPage* pMasterPage = pDoc->GetMasterSdPage(0, PageKind::Standard);
OUString aMasterPageName = pMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"Master0"_ustr, aMasterPageName);
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
SdPage* pNewMasterPage = pDoc->GetMasterSdPage(4, PageKind::Standard);
OUString aNewMasterPageName = pNewMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"1_Master0"_ustr, aNewMasterPageName);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf45617_leading_underscore_master_name)
{
// Test master page name with underscore at first position
createSdImpressDoc("odp/tdf96708.odp");
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
SdPage* pMasterPage = pDoc->GetMasterSdPage(0, PageKind::Standard);
// Rename the master page with leading underscore
pDoc->RenameLayoutTemplate(pMasterPage->GetLayoutName(), "_Master0");
OUString aMasterPageName = pMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"_Master0"_ustr, aMasterPageName);
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
SdPage* pNewMasterPage = pDoc->GetMasterSdPage(4, PageKind::Standard);
OUString aNewMasterPageName = pNewMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"1__Master0"_ustr, aNewMasterPageName);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf45617_middle_underscore_master_name)
{
// Test master page name with underscore in the middle
createSdImpressDoc("odp/tdf96708.odp");
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
SdPage* pMasterPage = pDoc->GetMasterSdPage(0, PageKind::Standard);
// Rename the master page with middle underscore
pDoc->RenameLayoutTemplate(pMasterPage->GetLayoutName(), "Master_0");
OUString aMasterPageName = pMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"Master_0"_ustr, aMasterPageName);
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
SdPage* pNewMasterPage = pDoc->GetMasterSdPage(4, PageKind::Standard);
OUString aNewMasterPageName = pNewMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"1_Master_0"_ustr, aNewMasterPageName);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf45617_trailing_underscore_master_name)
{
// Test master page name with underscore at the end
createSdImpressDoc("odp/tdf96708.odp");
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
SdPage* pMasterPage = pDoc->GetMasterSdPage(0, PageKind::Standard);
// Rename the master page with trailing underscore
pDoc->RenameLayoutTemplate(pMasterPage->GetLayoutName(), "Master0_");
OUString aMasterPageName = pMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"Master0_"_ustr, aMasterPageName);
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
SdPage* pNewMasterPage = pDoc->GetMasterSdPage(4, PageKind::Standard);
OUString aNewMasterPageName = pNewMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"1_Master0_"_ustr, aNewMasterPageName);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf45617_space_in_master_name)
{
// Test master page name with space in the middle
createSdImpressDoc("odp/tdf96708.odp");
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
SdPage* pMasterPage = pDoc->GetMasterSdPage(0, PageKind::Standard);
// Rename the master page with space in the middle
pDoc->RenameLayoutTemplate(pMasterPage->GetLayoutName(), "Master 0");
OUString aMasterPageName = pMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"Master 0"_ustr, aMasterPageName);
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
SdPage* pNewMasterPage = pDoc->GetMasterSdPage(4, PageKind::Standard);
OUString aNewMasterPageName = pNewMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"1_Master 0"_ustr, aNewMasterPageName);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf45617_Double_Copy)
{
// Test master page name with double copy
createSdImpressDoc();
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
// Set edit master page mode
rSSController.ChangeEditMode(EditMode::MasterPage);
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
// Get the master page name
const sal_uInt16 nMasterPageCnt1 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), nMasterPageCnt1);
SdPage* pMasterPage = pDoc->GetMasterSdPage(0, PageKind::Standard);
// Rename the master page with master name
pDoc->RenameLayoutTemplate(pMasterPage->GetLayoutName(), "master");
OUString aMasterPageName = pMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"master"_ustr, aMasterPageName);
// Reselect the master page
rSSController.GetPageSelector().DeselectAllPages();
rSSController.GetPageSelector().SelectPage(pMasterPage);
// Copy and paste the master page
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
const sal_uInt16 nMasterPageCnt2 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), nMasterPageCnt2);
SdPage* pNewMasterPage = pDoc->GetMasterSdPage(1, PageKind::Standard);
OUString aNewMasterPageName = pNewMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"1_master"_ustr, aNewMasterPageName);
// Reselect the master page
rSSController.GetPageSelector().DeselectAllPages();
rSSController.GetPageSelector().SelectPage(pMasterPage);
// Copy again
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
const sal_uInt16 nMasterPageCnt3 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(3), nMasterPageCnt3);
SdPage* pNewMasterPage2 = pDoc->GetMasterSdPage(2, PageKind::Standard);
OUString aNewMasterPageName2 = pNewMasterPage2->GetName();
CPPUNIT_ASSERT_EQUAL(u"2_master"_ustr, aNewMasterPageName2);
// Reselect the master page
rSSController.GetPageSelector().DeselectAllPages();
rSSController.GetPageSelector().SelectPage(pMasterPage);
// Copy again
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
const sal_uInt16 nMasterPageCnt4 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(4), nMasterPageCnt4);
SdPage* pNewMasterPage3 = pDoc->GetMasterSdPage(3, PageKind::Standard);
OUString aNewMasterPageName3 = pNewMasterPage3->GetName();
CPPUNIT_ASSERT_EQUAL(u"3_master"_ustr, aNewMasterPageName3);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf45617_Double_Copy_Default)
{
// Test master page name with double copy
createSdImpressDoc();
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
// Set edit master page mode
rSSController.ChangeEditMode(EditMode::MasterPage);
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
// Get the master page name
const sal_uInt16 nMasterPageCnt1 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), nMasterPageCnt1);
SdPage* pMasterPage = pDoc->GetMasterSdPage(0, PageKind::Standard);
// Rename the master page with default name
pDoc->RenameLayoutTemplate(pMasterPage->GetLayoutName(), "Default");
OUString aMasterPageName = pMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"Default"_ustr, aMasterPageName);
// Reselect the master page
rSSController.GetPageSelector().DeselectAllPages();
rSSController.GetPageSelector().SelectPage(pMasterPage);
// Copy and paste the master page
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
const sal_uInt16 nMasterPageCnt2 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(2), nMasterPageCnt2);
SdPage* pNewMasterPage = pDoc->GetMasterSdPage(1, PageKind::Standard);
OUString aNewMasterPageName = pNewMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"1_Default"_ustr, aNewMasterPageName);
// Reselect the master page
rSSController.GetPageSelector().DeselectAllPages();
rSSController.GetPageSelector().SelectPage(pMasterPage);
// Copy again
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
const sal_uInt16 nMasterPageCnt3 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(3), nMasterPageCnt3);
SdPage* pNewMasterPage2 = pDoc->GetMasterSdPage(2, PageKind::Standard);
OUString aNewMasterPageName2 = pNewMasterPage2->GetName();
CPPUNIT_ASSERT_EQUAL(u"2_Default"_ustr, aNewMasterPageName2);
// Reselect the master page
rSSController.GetPageSelector().DeselectAllPages();
rSSController.GetPageSelector().SelectPage(pMasterPage);
// Copy again
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
const sal_uInt16 nMasterPageCnt4 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(4), nMasterPageCnt4);
SdPage* pNewMasterPage3 = pDoc->GetMasterSdPage(3, PageKind::Standard);
OUString aNewMasterPageName3 = pNewMasterPage3->GetName();
CPPUNIT_ASSERT_EQUAL(u"3_Default"_ustr, aNewMasterPageName3);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf45617_Double_Copy_CopiedPage)
{
// Test master page name with double copy for copied page which doesn't have a normal page created
createSdImpressDoc("odp/tdf96708.odp");
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
// Set edit master page mode
rSSController.ChangeEditMode(EditMode::MasterPage);
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
// Get the master page name
const sal_uInt16 nMasterPageCnt1 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(4), nMasterPageCnt1);
SdPage* pMasterPage = pDoc->GetMasterSdPage(3, PageKind::Standard);
OUString aMasterPageName = pMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"Master3"_ustr, aMasterPageName);
// Reselect the master page
rSSController.GetPageSelector().DeselectAllPages();
rSSController.GetPageSelector().SelectPage(pMasterPage);
// Copy and paste the master page
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
const sal_uInt16 nMasterPageCnt2 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(5), nMasterPageCnt2);
SdPage* pNewMasterPage = pDoc->GetMasterSdPage(4, PageKind::Standard);
OUString aNewMasterPageName = pNewMasterPage->GetName();
CPPUNIT_ASSERT_EQUAL(u"1_Master3"_ustr, aNewMasterPageName);
// Reselect the master page
rSSController.GetPageSelector().DeselectAllPages();
rSSController.GetPageSelector().SelectPage(pNewMasterPage);
// Copy again
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
const sal_uInt16 nMasterPageCnt3 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(6), nMasterPageCnt3);
SdPage* pNewMasterPage2 = pDoc->GetMasterSdPage(5, PageKind::Standard);
OUString aNewMasterPageName2 = pNewMasterPage2->GetName();
CPPUNIT_ASSERT_EQUAL(u"2_Master3"_ustr, aNewMasterPageName2);
// Reselect the master page
rSSController.GetPageSelector().DeselectAllPages();
rSSController.GetPageSelector().SelectPage(pNewMasterPage2);
// Copy again
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
const sal_uInt16 nMasterPageCnt4 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(7), nMasterPageCnt4);
SdPage* pNewMasterPage3 = pDoc->GetMasterSdPage(6, PageKind::Standard);
OUString aNewMasterPageName3 = pNewMasterPage3->GetName();
CPPUNIT_ASSERT_EQUAL(u"3_Master3"_ustr, aNewMasterPageName3);
// Reselect the master page
rSSController.GetPageSelector().DeselectAllPages();
rSSController.GetPageSelector().SelectPage(pNewMasterPage);
// Copy again
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
const sal_uInt16 nMasterPageCnt5 = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(8), nMasterPageCnt5);
SdPage* pNewMasterPage4 = pDoc->GetMasterSdPage(7, PageKind::Standard);
OUString aNewMasterPageName4 = pNewMasterPage4->GetName();
CPPUNIT_ASSERT_EQUAL(u"4_Master3"_ustr, aNewMasterPageName4);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testUndoMergeMasterPage)
{
// Test undo for merging master pages only
createSdImpressDoc("odp/tdf96708.odp");
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
// Get document and check initial master page count
SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
const sal_uInt16 nInitialMasterPageCount = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(4), nInitialMasterPageCount);
// Copy and paste master page only
rSSController.GetClipboard().DoCopy(true);
rSSController.GetClipboard().DoPaste(true);
// Check that a master page was added
const sal_uInt16 nAfterPasteMasterPageCount = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(nInitialMasterPageCount + 1),
nAfterPasteMasterPageCount);
// Undo the master page merge
dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
// Check that the master page count is back to the initial value
const sal_uInt16 nAfterUndoMasterPageCount = pDoc->GetMasterSdPageCount(PageKind::Standard);
CPPUNIT_ASSERT_EQUAL(nInitialMasterPageCount, nAfterUndoMasterPageCount);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf139996)
{
createSdImpressDoc();
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
auto& rPageSelector = rSSController.GetPageSelector();
CPPUNIT_ASSERT_EQUAL(1, rPageSelector.GetSelectedPageCount());
rPageSelector.DeselectAllPages();
CPPUNIT_ASSERT_EQUAL(0, rPageSelector.GetSelectedPageCount());
// Without the fix in place, this test would have crashed here
dispatchCommand(mxComponent, u".uno:MovePageUp"_ustr, {});
dispatchCommand(mxComponent, u".uno:MovePageDown"_ustr, {});
dispatchCommand(mxComponent, u".uno:MovePageTop"_ustr, {});
dispatchCommand(mxComponent, u".uno:MovePageBottom"_ustr, {});
CPPUNIT_ASSERT_EQUAL(0, rPageSelector.GetSelectedPageCount());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf128651)
{
// Error was, that undo and redo changes size of the shape. Affected actions were e.g.
// extrusion on/off, shadow on/off, changes on line or fill attributes.
// All these actions do not change the snap rectangle.
createSdImpressDoc("tdf128651_CustomShapeUndo.odp");
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SdPage* pActualPage = pViewShell->GetActualPage();
SdrObject* pObject = pActualPage->GetObj(0);
auto pCustomShape = dynamic_cast<SdrObjCustomShape*>(pObject);
CPPUNIT_ASSERT_MESSAGE("No Shape", pCustomShape);
const sal_Int32 nOrigWidth(pCustomShape->GetSnapRect().GetWidth());
SdDrawDocument* pDocument = pXImpressDocument->GetDoc();
sd::UndoManager* pUndoManager = pDocument->GetUndoManager();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pUndoManager->GetUndoActionCount());
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pUndoManager->GetRedoActionCount());
SdrView* pView = pViewShell->GetView();
pView->MarkObj(pCustomShape, pView->GetSdrPageView());
pViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_EXTRUSION_TOGGLE,
SfxCallMode::SYNCHRON);
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pUndoManager->GetUndoActionCount());
pViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_UNDO, SfxCallMode::SYNCHRON);
const sal_Int32 nUndoWidth(pCustomShape->GetSnapRect().GetWidth());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Undo changes width", nOrigWidth, nUndoWidth);
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pUndoManager->GetRedoActionCount());
pViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_REDO, SfxCallMode::SYNCHRON);
const sal_Int32 nRedoWidth(pCustomShape->GetSnapRect().GetWidth());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Redo changes width", nUndoWidth, nRedoWidth);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf126605)
{
createSdImpressDoc();
dispatchCommand(mxComponent, u".uno:InsertPage"_ustr, {});
insertStringToObject(0, u"Test", /*bUseEscape*/ false);
uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(1),
uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
uno::Reference<text::XText> xText
= uno::Reference<text::XTextRange>(xShape, uno::UNO_QUERY_THROW)->getText();
CPPUNIT_ASSERT_MESSAGE("Not a text shape", xText.is());
uno::Reference<container::XEnumerationAccess> paraEnumAccess(xText, uno::UNO_QUERY);
uno::Reference<container::XEnumeration> paraEnum(paraEnumAccess->createEnumeration());
// Get first paragraph
uno::Reference<text::XTextRange> xParagraph(paraEnum->nextElement(), uno::UNO_QUERY_THROW);
uno::Reference<beans::XPropertySet> xPropSet(xParagraph, uno::UNO_QUERY_THROW);
sal_Int16 nWritingMode = 0;
xPropSet->getPropertyValue(u"WritingMode"_ustr) >>= nWritingMode;
CPPUNIT_ASSERT_EQUAL(text::WritingMode2::LR_TB, nWritingMode);
// Without the fix in place, this test would have crashed here
dispatchCommand(mxComponent, u".uno:ParaRightToLeft"_ustr, {});
xPropSet->getPropertyValue(u"WritingMode"_ustr) >>= nWritingMode;
CPPUNIT_ASSERT_EQUAL(text::WritingMode2::RL_TB, nWritingMode);
dispatchCommand(mxComponent, u".uno:ParaLeftToRight"_ustr, {});
xPropSet->getPropertyValue(u"WritingMode"_ustr) >>= nWritingMode;
CPPUNIT_ASSERT_EQUAL(text::WritingMode2::LR_TB, nWritingMode);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, tdf139269_prevent_pasting_into_readonly_master_objects)
{
createSdImpressDoc();
insertStringToObject(0, u"Test", /*bUseEscape*/ false);
dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});
dispatchCommand(mxComponent, u".uno:SlideMasterPage"_ustr, {});
// Use tab key to select the first object and try to type something to go
// into edit mode although it's not possible to add text to it
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
typeKey(pXImpressDocument, KEY_TAB);
typeString(pXImpressDocument, u"test");
dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
uno::Reference<drawing::XMasterPagesSupplier> xMasterPagesSupplier(mxComponent,
uno::UNO_QUERY_THROW);
uno::Reference<drawing::XDrawPages> xMasterPages(xMasterPagesSupplier->getMasterPages());
CPPUNIT_ASSERT(xMasterPages.is());
uno::Reference<drawing::XDrawPage> xDrawPage(xMasterPages->getByIndex(0), uno::UNO_QUERY);
uno::Reference<text::XTextRange> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
// Without the fix in place, this test would have failed with
// - Expected: Click to edit the title text format
// - Actual : Click to edit the title text formatTest
CPPUNIT_ASSERT_EQUAL(u"Click to edit the title text format"_ustr, xShape->getString());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf100950)
{
createSdImpressDoc();
dispatchCommand(mxComponent, u".uno:InsertPage"_ustr, {});
dispatchCommand(mxComponent, u".uno:InsertPage"_ustr, {});
insertStringToObject(0, u"Test", /*bUseEscape*/ true);
dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
auto& rSSController = pSSVS->GetSlideSorter().GetController();
auto& rPageSelector = rSSController.GetPageSelector();
// Without the fix in place, this test would have failed here
CPPUNIT_ASSERT(rPageSelector.IsPageSelected(2));
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf130581_undo_hide_show_slide)
{
createSdImpressDoc();
// Hide slide and check the number of available undo actions
dispatchCommand(mxComponent, u".uno:ShowSlide"_ustr, {});
dispatchCommand(mxComponent, u".uno:HideSlide"_ustr, {});
// There should be a single undo action, i.e., hide slide
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDocument = pXImpressDocument->GetDoc();
sd::UndoManager* pUndoManager = pDocument->GetUndoManager();
// Check if there is the correct undo action, i.e., hide slide
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pUndoManager->GetUndoActionCount());
CPPUNIT_ASSERT_EQUAL(SdResId(STR_UNDO_HIDE_SLIDE), pUndoManager->GetUndoActionComment());
sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell();
// Check if the page is actually hidden
auto& rSSController = pSSVS->GetSlideSorter().GetController();
auto& rPageSelector = rSSController.GetPageSelector();
CPPUNIT_ASSERT_EQUAL(true, rPageSelector.IsPageExcluded(0));
// Undo hide slide action and check the number of available redo actions
// including the correct undo action, i.e., hide slide
dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pUndoManager->GetRedoActionCount());
CPPUNIT_ASSERT_EQUAL(SdResId(STR_UNDO_HIDE_SLIDE), pUndoManager->GetRedoActionComment());
CPPUNIT_ASSERT_EQUAL(false, rPageSelector.IsPageExcluded(0));
// Show slide and check the number of available undo actions
dispatchCommand(mxComponent, u".uno:Redo"_ustr, {});
CPPUNIT_ASSERT_EQUAL(true, rPageSelector.IsPageExcluded(0));
dispatchCommand(mxComponent, u".uno:ShowSlide"_ustr, {});
// There should be two undo actions, i.e., show and hide slide
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pUndoManager->GetUndoActionCount());
CPPUNIT_ASSERT_EQUAL(SdResId(STR_UNDO_SHOW_SLIDE), pUndoManager->GetUndoActionComment());
CPPUNIT_ASSERT_EQUAL(false, rPageSelector.IsPageExcluded(0));
// Undo show slide and check the number of available undo/redo actions
dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
// There should be one undo action, i.e., hide slide, and one redo action, i.e., show slide
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pUndoManager->GetUndoActionCount());
CPPUNIT_ASSERT_EQUAL(SdResId(STR_UNDO_HIDE_SLIDE), pUndoManager->GetUndoActionComment());
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pUndoManager->GetRedoActionCount());
CPPUNIT_ASSERT_EQUAL(SdResId(STR_UNDO_SHOW_SLIDE), pUndoManager->GetRedoActionComment());
CPPUNIT_ASSERT_EQUAL(true, rPageSelector.IsPageExcluded(0));
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf129346)
{
createSdImpressDoc();
dispatchCommand(mxComponent, u".uno:DiaMode"_ustr, {});
checkCurrentPageNumber(1);
dispatchCommand(mxComponent, u".uno:InsertPage"_ustr, {});
checkCurrentPageNumber(2);
dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
checkCurrentPageNumber(1);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testmoveSlides)
{
createSdImpressDoc();
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
uno::Sequence<beans::PropertyValue> aArgs(
comphelper::InitPropertySequence({ { "PageName", uno::Any(u"Test 1"_ustr) },
{ "WhatLayout", uno::Any(sal_Int32(1)) },
{ "IsPageBack", uno::Any(false) },
{ "IsPageObj", uno::Any(false) } }));
dispatchCommand(mxComponent, u".uno:InsertPage"_ustr, aArgs);
checkCurrentPageNumber(2);
CPPUNIT_ASSERT_EQUAL(u"Test 1"_ustr, pViewShell->GetActualPage()->GetName());
aArgs = comphelper::InitPropertySequence({ { "PageName", uno::Any(u"Test 2"_ustr) },
{ "WhatLayout", uno::Any(sal_Int32(1)) },
{ "IsPageBack", uno::Any(false) },
{ "IsPageObj", uno::Any(false) } });
dispatchCommand(mxComponent, u".uno:InsertPage"_ustr, aArgs);
checkCurrentPageNumber(3);
CPPUNIT_ASSERT_EQUAL(u"Test 2"_ustr, pViewShell->GetActualPage()->GetName());
// Move slide 'Test 2' up
for (size_t i = 2; i > 0; --i)
{
dispatchCommand(mxComponent, u".uno:MovePageUp"_ustr, {});
checkCurrentPageNumber(i);
CPPUNIT_ASSERT_EQUAL(u"Test 2"_ustr, pViewShell->GetActualPage()->GetName());
}
// Move slide 'Test 2' down
for (size_t i = 2; i < 4; ++i)
{
dispatchCommand(mxComponent, u".uno:MovePageDown"_ustr, {});
checkCurrentPageNumber(i);
CPPUNIT_ASSERT_EQUAL(u"Test 2"_ustr, pViewShell->GetActualPage()->GetName());
}
// Move slide 'Test 2' to the top
dispatchCommand(mxComponent, u".uno:MovePageFirst"_ustr, {});
checkCurrentPageNumber(1);
CPPUNIT_ASSERT_EQUAL(u"Test 2"_ustr, pViewShell->GetActualPage()->GetName());
// Move slide 'Test 2' to the bottom
dispatchCommand(mxComponent, u".uno:MovePageLast"_ustr, {});
checkCurrentPageNumber(3);
CPPUNIT_ASSERT_EQUAL(u"Test 2"_ustr, pViewShell->GetActualPage()->GetName());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf68320_hidden_pages_total_slide_count)
{
createSdImpressDoc();
dispatchCommand(mxComponent, u".uno:InsertPage"_ustr, {});
dispatchCommand(mxComponent, u".uno:HideSlide"_ustr, {});
dispatchCommand(mxComponent, u".uno:InsertPage"_ustr, {});
checkCurrentPageNumber(3);
insertStringToObject(0, u"Pages: ", /*bUseEscape*/ false);
dispatchCommand(mxComponent, u".uno:InsertPagesField"_ustr, {});
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
typeString(pXImpressDocument, u"/");
dispatchCommand(mxComponent, u".uno:InsertPageField"_ustr, {});
dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});
uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence(
{ { "SelectedFormat", uno::Any(static_cast<sal_uInt32>(SotClipboardFormatId::STRING)) } });
// Paste as Unformatted text in order to get the field's values
dispatchCommand(mxComponent, u".uno:ClipboardFormatItems"_ustr, aPropertyValues);
uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(2),
uno::UNO_QUERY);
uno::Reference<text::XTextRange> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
// Without the fix in place, this test would have failed with
// - Expected: Pages: 3/3
// - Actual : Pages: 2/3
CPPUNIT_ASSERT_EQUAL(u"Pages: 3/3"_ustr, xShape->getString());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf148620)
{
createSdImpressDoc();
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
uno::UNO_QUERY);
uno::Reference<text::XTextRange> xShape(xDrawPage->getByIndex(1), uno::UNO_QUERY);
CPPUNIT_ASSERT_EQUAL(u""_ustr, xShape->getString());
insertStringToObject(1, u"one", /*bUseEscape*/ false);
typeKey(pXImpressDocument, KEY_RETURN);
typeString(pXImpressDocument, u"two");
typeKey(pXImpressDocument, KEY_RETURN);
typeString(pXImpressDocument, u"three");
typeKey(pXImpressDocument, KEY_RETURN);
typeString(pXImpressDocument, u"four");
typeKey(pXImpressDocument, KEY_RETURN);
typeString(pXImpressDocument, u"five");
typeKey(pXImpressDocument, KEY_RETURN);
typeString(pXImpressDocument, u"six");
CPPUNIT_ASSERT_EQUAL(u"One\nTwo\nThree\nFour\nFive\nsix"_ustr, xShape->getString());
uno::Sequence<beans::PropertyValue> aArgs(
comphelper::InitPropertySequence({ { "KeyModifier", uno::Any(sal_Int32(0)) } }));
dispatchCommand(mxComponent, u".uno:OutlineUp"_ustr, aArgs);
CPPUNIT_ASSERT_EQUAL(u"One\nTwo\nThree\nFour\nsix\nFive"_ustr, xShape->getString());
dispatchCommand(mxComponent, u".uno:OutlineUp"_ustr, aArgs);
CPPUNIT_ASSERT_EQUAL(u"One\nTwo\nThree\nsix\nFour\nFive"_ustr, xShape->getString());
dispatchCommand(mxComponent, u".uno:OutlineUp"_ustr, aArgs);
CPPUNIT_ASSERT_EQUAL(u"One\nTwo\nsix\nThree\nFour\nFive"_ustr, xShape->getString());
dispatchCommand(mxComponent, u".uno:OutlineUp"_ustr, aArgs);
CPPUNIT_ASSERT_EQUAL(u"One\nsix\nTwo\nThree\nFour\nFive"_ustr, xShape->getString());
dispatchCommand(mxComponent, u".uno:OutlineUp"_ustr, aArgs);
CPPUNIT_ASSERT_EQUAL(u"six\nOne\nTwo\nThree\nFour\nFive"_ustr, xShape->getString());
dispatchCommand(mxComponent, u".uno:OutlineDown"_ustr, aArgs);
CPPUNIT_ASSERT_EQUAL(u"One\nsix\nTwo\nThree\nFour\nFive"_ustr, xShape->getString());
dispatchCommand(mxComponent, u".uno:OutlineDown"_ustr, aArgs);
CPPUNIT_ASSERT_EQUAL(u"One\nTwo\nsix\nThree\nFour\nFive"_ustr, xShape->getString());
dispatchCommand(mxComponent, u".uno:OutlineDown"_ustr, aArgs);
CPPUNIT_ASSERT_EQUAL(u"One\nTwo\nThree\nsix\nFour\nFive"_ustr, xShape->getString());
dispatchCommand(mxComponent, u".uno:OutlineDown"_ustr, aArgs);
CPPUNIT_ASSERT_EQUAL(u"One\nTwo\nThree\nFour\nsix\nFive"_ustr, xShape->getString());
dispatchCommand(mxComponent, u".uno:OutlineDown"_ustr, aArgs);
CPPUNIT_ASSERT_EQUAL(u"One\nTwo\nThree\nFour\nFive\nsix"_ustr, xShape->getString());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf141703)
{
createSdImpressDoc();
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
{ { "Rows", uno::Any(sal_Int32(2)) }, { "Columns", uno::Any(sal_Int32(2)) } }));
dispatchCommand(mxComponent, u".uno:InsertTable"_ustr, aArgs);
// Move to A1 using Alt + Tab and write 'A'
for (int i = 0; i < 3; i++)
{
pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_SHIFT | KEY_TAB);
pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_SHIFT | KEY_TAB);
Scheduler::ProcessEventsToIdle();
}
typeString(pXImpressDocument, u"A");
// Move to A2 with Tab and write 'B'
typeKey(pXImpressDocument, KEY_TAB);
typeString(pXImpressDocument, u"B");
typeKey(pXImpressDocument, KEY_ESCAPE);
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SdPage* pActualPage = pViewShell->GetActualPage();
auto pTableObject = dynamic_cast<sdr::table::SdrTableObj*>(pActualPage->GetObj(2));
CPPUNIT_ASSERT(pTableObject);
uno::Reference<css::table::XTable> xTable(pTableObject->getTable(), uno::UNO_SET_THROW);
uno::Reference<css::table::XMergeableCell> xCellA1(xTable->getCellByPosition(0, 0),
uno::UNO_QUERY_THROW);
uno::Reference<css::table::XMergeableCell> xCellA2(xTable->getCellByPosition(1, 0),
uno::UNO_QUERY_THROW);
uno::Reference<text::XText> xTextA1
= uno::Reference<text::XTextRange>(xCellA1, uno::UNO_QUERY_THROW)->getText();
// Without the fix in place, this test would have failed with
// - Expected: A
// - Actual :
CPPUNIT_ASSERT_EQUAL(u"A"_ustr, xTextA1->getString());
uno::Reference<text::XText> xTextA2
= uno::Reference<text::XTextRange>(xCellA2, uno::UNO_QUERY_THROW)->getText();
CPPUNIT_ASSERT_EQUAL(u"B"_ustr, xTextA2->getString());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf164855)
{
createSdImpressDoc();
uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
{ { "Rows", uno::Any(sal_Int32(2)) }, { "Columns", uno::Any(sal_Int32(2)) } }));
dispatchCommand(mxComponent, u".uno:InsertTable"_ustr, aArgs);
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SdPage* pActualPage = pViewShell->GetActualPage();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pActualPage->GetObjCount());
auto pTableObject = dynamic_cast<sdr::table::SdrTableObj*>(pActualPage->GetObj(2));
CPPUNIT_ASSERT(pTableObject);
const EditTextObject& rEdit
= pTableObject->getText(0)->GetOutlinerParaObject()->GetTextObject();
const SfxItemSet& rParaAttribs = rEdit.GetParaAttribs(0);
auto pAdjust = rParaAttribs.GetItem(EE_PARA_JUST);
CPPUNIT_ASSERT_EQUAL(SvxAdjust::ParaStart, pAdjust->GetAdjust());
// Without the fix in place, this test would have crashed here
dispatchCommand(mxComponent, u".uno:RightPara"_ustr, {});
const EditTextObject& rEdit2
= pTableObject->getText(0)->GetOutlinerParaObject()->GetTextObject();
const SfxItemSet& rParaAttribs2 = rEdit2.GetParaAttribs(0);
pAdjust = rParaAttribs2.GetItem(EE_PARA_JUST);
CPPUNIT_ASSERT_EQUAL(SvxAdjust::Right, pAdjust->GetAdjust());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf127481)
{
createSdImpressDoc();
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SdPage* pActualPage = pViewShell->GetActualPage();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pActualPage->GetObjCount());
uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
{ { "Rows", uno::Any(sal_Int32(1)) }, { "Columns", uno::Any(sal_Int32(1)) } }));
dispatchCommand(mxComponent, u".uno:InsertTable"_ustr, aArgs);
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pActualPage->GetObjCount());
dispatchCommand(mxComponent, u".uno:DuplicatePage"_ustr, aArgs);
checkCurrentPageNumber(2);
pActualPage = pViewShell->GetActualPage();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pActualPage->GetObjCount());
auto pTableObject = dynamic_cast<sdr::table::SdrTableObj*>(pActualPage->GetObj(2));
CPPUNIT_ASSERT(pTableObject);
//without the fix, it would crash here
pViewShell->GetView()->SdrBeginTextEdit(pTableObject);
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pActualPage->GetObjCount());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testPageFillColor)
{
// Load the document and create two new windows.
createSdImpressDoc("tdf126197.odp");
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
// Set FillPageColor
uno::Sequence<beans::PropertyValue> aPropertyValues = {
comphelper::makePropertyValue(u"FillColor"_ustr, static_cast<sal_Int32>(0xff0000)),
};
dispatchCommand(mxComponent, u".uno:FillPageColor"_ustr, aPropertyValues);
SdPage* pPage = pViewShell->getCurrentPage();
const SfxItemSet& rPageAttr = pPage->getSdrPageProperties().GetItemSet();
const XFillStyleItem* pFillStyle = rPageAttr.GetItem(XATTR_FILLSTYLE);
drawing::FillStyle eXFS = pFillStyle->GetValue();
CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_SOLID, eXFS);
Color aColor = rPageAttr.GetItem(XATTR_FILLCOLOR)->GetColorValue();
CPPUNIT_ASSERT_EQUAL(COL_LIGHTRED, aColor);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testPageFillGradient)
{
// Load the document and create two new windows.
createSdImpressDoc("tdf126197.odp");
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
// Set FillPageColor
uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence({
{ "FillPageGradientJSON",
uno::Any(u"{\"style\":\"LINEAR\",\"startcolor\":\"ff0000\",\"endcolor\":\"0000ff\","
"\"angle\":\"300\",\"border\":\"0\",\"x\":\"0\",\"y\":\"0\",\"intensstart\":"
"\"100\",\"intensend\":\"100\",\"stepcount\":\"0\"}"_ustr) },
}));
dispatchCommand(mxComponent, u".uno:FillPageGradient"_ustr, aPropertyValues);
SdPage* pPage = pViewShell->getCurrentPage();
const SfxItemSet& rPageAttr = pPage->getSdrPageProperties().GetItemSet();
const XFillStyleItem* pFillStyle = rPageAttr.GetItem(XATTR_FILLSTYLE);
drawing::FillStyle eXFS = pFillStyle->GetValue();
CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_GRADIENT, eXFS);
basegfx::BGradient aGradient(rPageAttr.GetItem(XATTR_FILLGRADIENT)->GetGradientValue());
const basegfx::BColorStops& rColorStops(aGradient.GetColorStops());
CPPUNIT_ASSERT_EQUAL(size_t(2), rColorStops.size());
CPPUNIT_ASSERT_EQUAL(0.0, rColorStops.getStopOffset(0));
CPPUNIT_ASSERT_EQUAL(COL_LIGHTRED, Color(rColorStops.getStopColor(0)));
CPPUNIT_ASSERT(basegfx::fTools::equal(rColorStops.getStopOffset(1), 1.0));
CPPUNIT_ASSERT_EQUAL(COL_LIGHTBLUE, Color(rColorStops.getStopColor(1)));
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf134053)
{
// Error was, that dashes and dots were longer than in MS Office.
createSdImpressDoc("pptx/tdf134053_dashdot.pptx");
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SdPage* pActualPage = pViewShell->GetActualPage();
SdrObject* pShape = pActualPage->GetObj(0);
CPPUNIT_ASSERT_MESSAGE("No Shape", pShape);
SdDrawDocument* pDocument = pXImpressDocument->GetDoc();
sd::UndoManager* pUndoManager = pDocument->GetUndoManager();
// tdf#114613: Without the fix in place, this test would have failed with
// - Expected: 0
// - Actual : 8
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pUndoManager->GetUndoActionCount());
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pUndoManager->GetRedoActionCount());
XDash dash = pShape->GetMergedItem(XATTR_LINEDASH).GetDashValue();
// Because 0% is not possible as dash length (as of June 2020) 1% is used in the fix.
CPPUNIT_ASSERT_EQUAL_MESSAGE("Distance", 399.0, dash.GetDistance());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Dot length", 301.0, dash.GetDotLen());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Dash length", 1.0, dash.GetDashLen());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testSpellOnlineParameter)
{
createSdImpressDoc();
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
bool bSet = pImpressDocument->GetDoc()->GetOnlineSpell();
uno::Sequence<beans::PropertyValue> params(
comphelper::InitPropertySequence({ { "Enable", uno::Any(!bSet) } }));
dispatchCommand(mxComponent, u".uno:SpellOnline"_ustr, params);
CPPUNIT_ASSERT_EQUAL(!bSet, pImpressDocument->GetDoc()->GetOnlineSpell());
// set the same state as now and we don't expect any change (no-toggle)
params = comphelper::InitPropertySequence({ { "Enable", uno::Any(!bSet) } });
dispatchCommand(mxComponent, u".uno:SpellOnline"_ustr, params);
CPPUNIT_ASSERT_EQUAL(!bSet, pImpressDocument->GetDoc()->GetOnlineSpell());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf38669)
{
createSdImpressDoc();
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
CPPUNIT_ASSERT(pImpressDocument);
// Insert shape with ctrl key
uno::Sequence<beans::PropertyValue> aArgs(
comphelper::InitPropertySequence({ { "KeyModifier", uno::Any(KEY_MOD1) } }));
dispatchCommand(mxComponent, u".uno:BasicShapes.rectangle"_ustr, aArgs);
uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
uno::UNO_QUERY);
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xDrawPage->getCount());
typeString(pImpressDocument, u"°");
uno::Reference<text::XTextRange> xShape(xDrawPage->getByIndex(2), uno::UNO_QUERY);
// Without the fix in place, this test would have failed with:
// - Expected: °
// - Actual : ㅀ
CPPUNIT_ASSERT_EQUAL(u"°"_ustr, xShape->getString());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf151417)
{
createSdImpressDoc();
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
CPPUNIT_ASSERT(pImpressDocument);
uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<container::XIndexAccess> xDraws = xDrawPagesSupplier->getDrawPages();
CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xDraws->getCount());
uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
uno::UNO_QUERY);
CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xDrawPage->getCount());
uno::Sequence<beans::PropertyValue> aArgs(
comphelper::InitPropertySequence({ { "KeyModifier", uno::Any(KEY_MOD1) } }));
// Without the fix in place, this test would have crashed here
dispatchCommand(mxComponent, u".uno:Edit"_ustr, aArgs);
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xDrawPage->getCount());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf96454_formatted_start_end_arrow_sizes)
{
createSdImpressDoc();
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
CPPUNIT_ASSERT(pImpressDocument);
// Retrieve default style sheet
auto pSSPool = pImpressDocument->GetDocShell()->GetStyleSheetPool();
CPPUNIT_ASSERT(pSSPool);
auto pSheet = pSSPool->Find(SdResId(STR_STANDARD_STYLESHEET_NAME), SfxStyleFamily::Para);
CPPUNIT_ASSERT(pSheet);
// Override the default line start/end arrow widths in the style sheet
SfxItemSet& rISet = pSheet->GetItemSet();
rISet.Put(XLineStartWidthItem(300));
rISet.Put(XLineEndWidthItem(400));
// Insert a line with end arrow via Ctrl key
dispatchCommand(mxComponent, u".uno:LineArrowEnd"_ustr,
comphelper::InitPropertySequence({ { "KeyModifier", uno::Any(KEY_MOD1) } }));
// Retrieve the first draw page and check presence of the newly inserted line
uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
uno::UNO_QUERY);
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xDrawPage->getCount());
// Retrieve start/end line widths
uno::Reference<beans::XPropertySet> xPropSet(xDrawPage->getByIndex(2), uno::UNO_QUERY);
sal_uInt32 nStartWidth = 0;
xPropSet->getPropertyValue(u"LineStartWidth"_ustr) >>= nStartWidth;
// Without the fix in place, this test would have failed with
// - Expected: 300
// - Actual : 200
// i.e. the start arrow width was not retrieved from the style sheet
CPPUNIT_ASSERT_EQUAL(sal_uInt32(300), nStartWidth);
// Without the fix in place, this test would have failed with
// - Expected: 400
// - Actual : 200
// i.e. the end arrow width was not retrieved from the style sheet
sal_uInt32 nEndWidth = 0;
xPropSet->getPropertyValue(u"LineEndWidth"_ustr) >>= nEndWidth;
CPPUNIT_ASSERT_EQUAL(sal_uInt32(400), nEndWidth);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf126823_default_start_end_arrow_sizes)
{
createSdImpressDoc();
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
CPPUNIT_ASSERT(pImpressDocument);
// Insert a line with end arrow via Ctrl key
dispatchCommand(mxComponent, u".uno:LineArrowEnd"_ustr,
comphelper::InitPropertySequence({ { "KeyModifier", uno::Any(KEY_MOD1) } }));
// Retrieve the first draw page and check presence of the newly inserted line
uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
uno::UNO_QUERY);
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xDrawPage->getCount());
// Retrieve start/end line widths
uno::Reference<beans::XPropertySet> xPropSet(xDrawPage->getByIndex(2), uno::UNO_QUERY);
sal_uInt32 nStartWidth = 0;
xPropSet->getPropertyValue(u"LineStartWidth"_ustr) >>= nStartWidth;
sal_uInt32 nEndWidth = 0;
xPropSet->getPropertyValue(u"LineEndWidth"_ustr) >>= nEndWidth;
// Without the fix in place, this test would have failed with
// - Expected: 200
// - Actual : 300
// i.e. the start/end arrow widths are not equal
CPPUNIT_ASSERT_EQUAL(nStartWidth, nEndWidth);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf123841)
{
// To check if selecting unfilled rectangle produces unfilled rectangle
createSdImpressDoc();
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
CPPUNIT_ASSERT(pImpressDocument);
uno::Sequence<beans::PropertyValue> aArgs(
comphelper::InitPropertySequence({ { "KeyModifier", uno::Any(KEY_MOD1) } }));
dispatchCommand(mxComponent, u".uno:Rect_Unfilled"_ustr, aArgs);
uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
uno::UNO_QUERY);
CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xDrawPage->getCount());
for (int i = 0; i < 3; i++)
{
uno::Reference<beans::XPropertySet> XPropSet(xDrawPage->getByIndex(i), uno::UNO_QUERY);
drawing::FillStyle eFillStyle = drawing::FillStyle_NONE;
XPropSet->getPropertyValue(u"FillStyle"_ustr) >>= eFillStyle;
// Without the fix in place, this test would have failed
// with drawing::FillStyle_NONE != drawing::FillStyle_SOLID
CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_NONE, eFillStyle);
}
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testSearchAllInDocumentAndNotes)
{
// tdf#142478
// "find all" produces a crash when the search string exists in notes
// and the document
createSdImpressDoc("odp/search-all-notes.odp");
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
lcl_search(u"Crash"_ustr, /*bFindAll=*/true, /*bBackwards=*/true);
}
#if !defined(_WIN32) && !defined(MACOSX)
// for some reason, the search for "second" (or "Second") didn't return page 2 in WIN and MACOS
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf123658_SearchAfterSlideChange)
{
createSdImpressDoc("odp/tdf123658_SearchAfterSlideChange.odp");
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
lcl_search(u"second"_ustr);
checkCurrentPageNumber(2);
pXImpressDocument->setPart(0); // Switch to 1st page
lcl_search(u"of"_ustr);
// Instead of finding this on the 1st page (or on the 2nd page would be acceptable too)
// it was going to the third page.
checkCurrentPageNumber(1);
}
#endif
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf142589)
{
createSdImpressDoc();
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SfxRequest aRequest(*pViewShell->GetViewFrame(), SID_PRESENTATION);
pImpressDocument->GetDoc()->getPresentationSettings().mbCustomShow = true;
pImpressDocument->GetDoc()->getPresentationSettings().mbStartCustomShow = true;
sd::slideshowhelp::ShowSlideShow(aRequest, *pImpressDocument->GetDoc());
CPPUNIT_ASSERT_EQUAL(false, pImpressDocument->GetDoc()->getPresentationSettings().mbCustomShow);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testCharColorTheme)
{
// Given an Impress document with a shape, with its text selected:
createSdImpressDoc();
uno::Reference<drawing::XDrawPagesSupplier> xPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xPage(xPagesSupplier->getDrawPages()->getByIndex(0),
uno::UNO_QUERY);
uno::Reference<text::XTextRange> xShape(xPage->getByIndex(0), uno::UNO_QUERY);
{
uno::Reference<text::XSimpleText> xText = xShape->getText();
xText->insertString(xText->getStart(), u"test"_ustr, false);
}
uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
uno::Reference<view::XSelectionSupplier> xController(xModel->getCurrentController(),
uno::UNO_QUERY);
xController->select(uno::Any(xShape));
Scheduler::ProcessEventsToIdle();
dispatchCommand(mxComponent, u".uno:Text"_ustr, {});
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SdrView* pView = pViewShell->GetView();
CPPUNIT_ASSERT(pView->IsTextEdit());
dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
// When picking a theme color on the sidebar:
{
model::ComplexColor aComplexColor;
aComplexColor.setThemeColor(model::ThemeColorType::Accent1);
aComplexColor.addTransformation({ model::TransformationType::LumMod, 2000 });
aComplexColor.addTransformation({ model::TransformationType::LumOff, 8000 });
// When setting the fill color of that shape, with theme metadata & effects:
uno::Sequence<beans::PropertyValue> aColorArgs = {
comphelper::makePropertyValue(u"Color.Color"_ustr,
sal_Int32(0xdae3f3)), // 80% light blue
comphelper::makePropertyValue(
u"Color.ComplexColor"_ustr,
uno::Any(model::color::createXComplexColor(aComplexColor))),
};
dispatchCommand(mxComponent, u".uno:Color"_ustr, aColorArgs);
}
// Then make sure the theme "metadata" is set in the document model:
pView->EndTextEditCurrentView();
CPPUNIT_ASSERT(!pView->IsTextEdit());
uno::Reference<container::XEnumerationAccess> xShapeParaAccess(xShape, uno::UNO_QUERY);
uno::Reference<container::XEnumerationAccess> xPara(
xShapeParaAccess->createEnumeration()->nextElement(), uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xPortion(xPara->createEnumeration()->nextElement(),
uno::UNO_QUERY);
{
uno::Reference<util::XComplexColor> xComplexColor;
CPPUNIT_ASSERT(xPortion->getPropertyValue(u"CharComplexColor"_ustr) >>= xComplexColor);
CPPUNIT_ASSERT(xComplexColor.is());
auto aComplexColor = model::color::getFromXComplexColor(xComplexColor);
CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent1, aComplexColor.getThemeColorType());
CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod,
aComplexColor.getTransformations()[0].meType);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2000),
aComplexColor.getTransformations()[0].mnValue);
CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff,
aComplexColor.getTransformations()[1].meType);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(8000),
aComplexColor.getTransformations()[1].mnValue);
}
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testFillColorTheme)
{
// Given an Impress document with a selected shape:
createSdImpressDoc();
uno::Reference<drawing::XDrawPagesSupplier> xPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xPage(xPagesSupplier->getDrawPages()->getByIndex(0),
uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xShape(xPage->getByIndex(0), uno::UNO_QUERY);
uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
uno::Reference<view::XSelectionSupplier> xController(xModel->getCurrentController(),
uno::UNO_QUERY);
xController->select(uno::Any(xShape));
// Change fill color
{
model::ComplexColor aComplexColor;
aComplexColor.setThemeColor(model::ThemeColorType::Accent1);
aComplexColor.addTransformation({ model::TransformationType::LumMod, 4000 });
aComplexColor.addTransformation({ model::TransformationType::LumOff, 6000 });
// When setting the fill color of that shape, with theme metadata & effects:
uno::Sequence<beans::PropertyValue> aColorArgs = {
comphelper::makePropertyValue(u"FillColor.Color"_ustr, sal_Int32(0xed7d31)), // orange
comphelper::makePropertyValue(
u"FillColor.ComplexColor"_ustr,
uno::Any(model::color::createXComplexColor(aComplexColor))), // accent 1
};
dispatchCommand(mxComponent, u".uno:FillColor"_ustr, aColorArgs);
}
// Then make sure the theme index is not lost when the sidebar sets it:
{
uno::Reference<util::XComplexColor> xComplexColor;
CPPUNIT_ASSERT(xShape->getPropertyValue(u"FillComplexColor"_ustr) >>= xComplexColor);
CPPUNIT_ASSERT(xComplexColor.is());
auto aComplexColor = model::color::getFromXComplexColor(xComplexColor);
CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent1, aComplexColor.getThemeColorType());
CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod,
aComplexColor.getTransformations()[0].meType);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4000),
aComplexColor.getTransformations()[0].mnValue);
CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff,
aComplexColor.getTransformations()[1].meType);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(6000),
aComplexColor.getTransformations()[1].mnValue);
}
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf163805)
{
createSdImpressDoc();
uno::Reference<beans::XPropertySet> xShape(getShapeFromPage(0, 0));
drawing::FillStyle eFillStyle;
Color aColor;
CPPUNIT_ASSERT(xShape->getPropertyValue(u"FillStyle"_ustr) >>= eFillStyle);
CPPUNIT_ASSERT_EQUAL(int(drawing::FillStyle_NONE), static_cast<int>(eFillStyle));
CPPUNIT_ASSERT(xShape->getPropertyValue(u"FillColor"_ustr) >>= aColor);
CPPUNIT_ASSERT_EQUAL(Color(0x729fcf), aColor);
uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
uno::Reference<view::XSelectionSupplier> xController(xModel->getCurrentController(),
uno::UNO_QUERY);
xController->select(uno::Any(xShape));
uno::Sequence<beans::PropertyValue> aColorArgs
= { comphelper::makePropertyValue(u"FillColor.Color"_ustr, sal_Int32(0x800000)) };
dispatchCommand(mxComponent, u".uno:FillColor"_ustr, aColorArgs);
CPPUNIT_ASSERT(xShape->getPropertyValue(u"FillStyle"_ustr) >>= eFillStyle);
// Without the fix in place, this test would have failed with
// - Expected: 1
// - Actual : 0
CPPUNIT_ASSERT_EQUAL(int(drawing::FillStyle_SOLID), static_cast<int>(eFillStyle));
CPPUNIT_ASSERT(xShape->getPropertyValue(u"FillColor"_ustr) >>= aColor);
CPPUNIT_ASSERT_EQUAL(COL_RED, aColor);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testFillColorNoColor)
{
// Given an empty Impress document:
createSdImpressDoc();
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SfxDispatcher* pDispatcher = pViewShell->GetViewFrame()->GetDispatcher();
// When dispatching a fill color that only has a fill style (no color), then make sure we don't
// crash:
XFillStyleItem aXFillStyleItem(drawing::FillStyle_NONE);
pDispatcher->ExecuteList(SID_ATTR_FILL_COLOR, SfxCallMode::RECORD, { &aXFillStyleItem });
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf153161)
{
createSdImpressDoc("odp/tdf153161_FlushToSave.odp");
uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
uno::UNO_QUERY);
uno::Reference<text::XTextRange> xShape(xDrawPage->getByIndex(1), uno::UNO_QUERY);
OUString sOldText(xShape->getString());
CPPUNIT_ASSERT(sOldText.startsWith(u"在没有版本控制系统的时期"));
// Type something, getting into text editing mode (appending) automatically
insertStringToObject(1, u"Foo Bar", /*bUseEscape*/ false);
saveAndReload(TestFilter::ODP);
xDrawPagesSupplier.set(mxComponent, uno::UNO_QUERY);
xDrawPage.set(xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY);
xShape.set(xDrawPage->getByIndex(1), uno::UNO_QUERY);
OUString sExpectedText = sOldText + "Foo Bar";
CPPUNIT_ASSERT_EQUAL(sExpectedText, xShape->getString());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf148810)
{
createSdImpressDoc("pptx/tdf148810_PARA_OUTLLEVEL.pptx");
// type something to get into text editing mode (instead of shape selection).
insertStringToObject(1, u"x", /*bUseEscape*/ false);
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
typeKey(pXImpressDocument, KEY_HOME);
typeKey(pXImpressDocument, KEY_BACKSPACE);
uno::Reference<beans::XPropertySet> xShape(getShapeFromPage(1, 0));
uno::Reference<text::XTextRange> xParagraph(getParagraphFromShape(0, xShape));
uno::Reference<beans::XPropertySet> xPropSet(xParagraph, uno::UNO_QUERY_THROW);
sal_Int16 nNumberingLevel = -1;
xPropSet->getPropertyValue(u"NumberingLevel"_ustr) >>= nNumberingLevel;
CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nNumberingLevel);
dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
nNumberingLevel = -1;
xPropSet->getPropertyValue(u"NumberingLevel"_ustr) >>= nNumberingLevel;
// Without the fix in place, this test would have failed with
// - Expected: 0
// - Actual : -1
CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nNumberingLevel);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf127696)
{
createSdImpressDoc();
dispatchCommand(mxComponent, u".uno:InsertPage"_ustr, {});
insertStringToObject(0, u"Test", /*bUseEscape*/ false);
dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
dispatchCommand(mxComponent, u".uno:OutlineFont"_ustr, {});
// Save it as PPTX and load it again.
saveAndReload(TestFilter::PPTX);
uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(1),
uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
uno::Reference<text::XText> xText
= uno::Reference<text::XTextRange>(xShape, uno::UNO_QUERY_THROW)->getText();
CPPUNIT_ASSERT_MESSAGE("Not a text shape", xText.is());
uno::Reference<container::XEnumerationAccess> paraEnumAccess(xText, uno::UNO_QUERY);
uno::Reference<container::XEnumeration> paraEnum(paraEnumAccess->createEnumeration());
uno::Reference<text::XTextRange> xParagraph(paraEnum->nextElement(), uno::UNO_QUERY_THROW);
uno::Reference<container::XEnumerationAccess> runEnumAccess(xParagraph, uno::UNO_QUERY);
uno::Reference<container::XEnumeration> runEnum = runEnumAccess->createEnumeration();
uno::Reference<text::XTextRange> xRun(runEnum->nextElement(), uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xPropSet(xRun, uno::UNO_QUERY_THROW);
bool bContoured = false;
xPropSet->getPropertyValue(u"CharContoured"_ustr) >>= bContoured;
CPPUNIT_ASSERT(bContoured);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testThemeShapeInsert)
{
// Given a document with a theme, accent1 color is set to 0x000004:
createSdImpressDoc();
uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
uno::UNO_QUERY);
uno::Reference<drawing::XMasterPageTarget> xMasterPageTarget(xDrawPage, uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xMasterPage(xMasterPageTarget->getMasterPage(),
uno::UNO_QUERY);
auto pTheme = std::make_shared<model::Theme>("mytheme");
auto pColorSet = std::make_shared<model::ColorSet>("mycolorscheme");
pColorSet->add(model::ThemeColorType::Dark1, 0x0);
pColorSet->add(model::ThemeColorType::Light1, 0x1);
pColorSet->add(model::ThemeColorType::Dark2, 0x2);
pColorSet->add(model::ThemeColorType::Light2, 0x3);
pColorSet->add(model::ThemeColorType::Accent1, 0x4);
pColorSet->add(model::ThemeColorType::Accent2, 0x5);
pColorSet->add(model::ThemeColorType::Accent3, 0x6);
pColorSet->add(model::ThemeColorType::Accent4, 0x7);
pColorSet->add(model::ThemeColorType::Accent5, 0x8);
pColorSet->add(model::ThemeColorType::Accent6, 0x9);
pColorSet->add(model::ThemeColorType::Hyperlink, 0xa);
pColorSet->add(model::ThemeColorType::FollowedHyperlink, 0xb);
pTheme->setColorSet(pColorSet);
xMasterPage->setPropertyValue("Theme", uno::Any(model::theme::createXTheme(pTheme)));
// When inserting a shape:
uno::Sequence<beans::PropertyValue> aArgs = {
comphelper::makePropertyValue("CreateDirectly", true),
};
dispatchCommand(mxComponent, ".uno:BasicShapes.round-rectangle", aArgs);
// Then make sure that the fill color of the last shape is the accent1 color:
sal_Int32 nShapeIndex = xDrawPage->getCount() - 1;
uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(nShapeIndex), uno::UNO_QUERY);
sal_Int32 nFillColor{};
xShape->getPropertyValue("FillColor") >>= nFillColor;
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0x4), nFillColor);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf166647_userpaint)
{
// The document contains two shapes on layer DrawnInSlideshow and is empty besides that. The
// running slideshow is displayed in window mode, otherwise its additional window would be
// suppressed by the test environment.
createSdImpressDoc("odp/tdf166647_userpaint.odp");
auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
CPPUNIT_ASSERT(pXImpressDocument);
// Go in slideshow mode and back to edit mode
dispatchCommand(mxComponent, u".uno:Presentation"_ustr, {});
typeKey(pXImpressDocument, KEY_ESCAPE);
// Count shapes. Error was, that the shapes were duplicated and thus count was 4.
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
CPPUNIT_ASSERT_EQUAL(size_t(2), pViewShell->GetActualPage()->GetObjCount());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf130586)
{
createSdImpressDoc();
checkCurrentPageNumber(1);
dispatchCommand(mxComponent, u".uno:InsertPage"_ustr, {});
checkCurrentPageNumber(2);
dispatchCommand(mxComponent, u".uno:AssignLayout?WhatLayout:long=1"_ustr, {});
checkCurrentPageNumber(2);
// Undo x2 (undo layout change, then undo insert slide)
dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
checkCurrentPageNumber(2);
dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
checkCurrentPageNumber(1);
// Redo x2 (redo insert slide, then redo layout change)
dispatchCommand(mxComponent, u".uno:Redo"_ustr, {});
checkCurrentPageNumber(2);
dispatchCommand(mxComponent, u".uno:Redo"_ustr, {});
// Without the fix, this would fail with
// - Expected: 2
// - Actual : 1
checkCurrentPageNumber(2);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf168835)
{
createSdImpressDoc("pptx/tdf168835.pptx");
checkCurrentPageNumber(1);
dispatchCommand(mxComponent, u".uno:InsertPage"_ustr, {});
checkCurrentPageNumber(2);
insertStringToObject(0, u"Title of the second slide", /*bUseEscape*/ true);
uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(1),
uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
uno::Reference<text::XTextRange> xParagraph(getParagraphFromShape(0, xShape));
CPPUNIT_ASSERT_EQUAL(u"Title of the second slide"_ustr, xParagraph->getString());
CPPUNIT_ASSERT_EQUAL(44.0f, xShape->getPropertyValue(u"CharHeight"_ustr).get<float>());
CPPUNIT_ASSERT_EQUAL(sal_Int16(style::ParagraphAdjust_LEFT),
xShape->getPropertyValue(u"ParaAdjust"_ustr).get<sal_Int16>());
CPPUNIT_ASSERT_EQUAL(u"Arial"_ustr,
xShape->getPropertyValue(u"CharFontName"_ustr).get<OUString>());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testNumToBullet)
{
// Given a document with a shape, 2nd paragraph is a numbering:
createSdImpressDoc("odp/num-to-bullet.odp");
sd::ViewShell* pViewShell = getSdDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SdPage* pPage = pViewShell->GetActualPage();
SdrObject* pShape = pPage->GetObj(0);
CPPUNIT_ASSERT(pShape);
SdrView* pView = pViewShell->GetView();
pView->MarkObj(pShape, pView->GetSdrPageView());
Scheduler::ProcessEventsToIdle();
CPPUNIT_ASSERT(!pView->IsTextEdit());
// When turning the numbering to a bullet:
// Start text edit:
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
typeString(pImpressDocument, u"x");
CPPUNIT_ASSERT(pView->IsTextEdit());
// Do the switch:
dispatchCommand(mxComponent, u".uno:DefaultBullet"_ustr, {});
// End text edit:
typeKey(pImpressDocument, KEY_ESCAPE);
// Then make sure we switch to a bullet and not toggle off the numbering:
CPPUNIT_ASSERT(!pView->IsTextEdit());
uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xParagraph(getParagraphFromShape(1, xShape),
uno::UNO_QUERY);
// Check that list level is 1 & level 1 numbering type is a bullet:
sal_Int16 nNumberingLevel{};
xParagraph->getPropertyValue(u"NumberingLevel"_ustr) >>= nNumberingLevel;
// Without the accompanying fix in place, this test would have failed with:
// - Expected: 1
// - Actual : 0
// i.e. list level was -1 (toggle off) instead of switch to bullet.
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(1), nNumberingLevel);
uno::Reference<container::XIndexAccess> xNumberingRules;
xParagraph->getPropertyValue(u"NumberingRules"_ustr) >>= xNumberingRules;
comphelper::SequenceAsHashMap aNumberingRule(xNumberingRules->getByIndex(1));
sal_Int16 nNumberingType = 0;
aNumberingRule[u"NumberingType"_ustr] >>= nNumberingType;
// Bullet and not numbering (ARABIC):
CPPUNIT_ASSERT_EQUAL(style::NumberingType::CHAR_SPECIAL, nNumberingType);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testBulletOffOn)
{
// Given a document with a shape, last paragraph it has a bullet:
createSdImpressDoc("odp/bullet-off-on.odp");
sd::ViewShell* pViewShell = getSdDocShell()->GetViewShell();
CPPUNIT_ASSERT(pViewShell);
SdPage* pPage = pViewShell->GetActualPage();
SdrObject* pShape = pPage->GetObj(0);
CPPUNIT_ASSERT(pShape);
SdrView* pView = pViewShell->GetView();
pView->MarkObj(pShape, pView->GetSdrPageView());
Scheduler::ProcessEventsToIdle();
CPPUNIT_ASSERT(!pView->IsTextEdit());
// When turning the bullet off & then back on again:
// Start text edit:
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
typeString(pImpressDocument, u"x");
CPPUNIT_ASSERT(pView->IsTextEdit());
// Toggle off:
dispatchCommand(mxComponent, u".uno:DefaultBullet"_ustr, {});
// Toggle on:
dispatchCommand(mxComponent, u".uno:DefaultBullet"_ustr, {});
// End text edit:
typeKey(pImpressDocument, KEY_ESCAPE);
// Then make sure the result is Level 1 from the master page:
CPPUNIT_ASSERT(!pView->IsTextEdit());
uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
// 5th, last paragraph.
uno::Reference<beans::XPropertySet> xParagraph(getParagraphFromShape(4, xShape),
uno::UNO_QUERY);
uno::Reference<container::XIndexAccess> xNumberingRules;
xParagraph->getPropertyValue(u"NumberingRules"_ustr) >>= xNumberingRules;
// Level 1.
comphelper::SequenceAsHashMap aNumberingRule(xNumberingRules->getByIndex(0));
sal_Int32 nLeftMargin = 0;
aNumberingRule[u"LeftMargin"_ustr] >>= nLeftMargin;
sal_Int32 nFirstLineOffset = 0;
aNumberingRule[u"FirstLineOffset"_ustr] >>= nFirstLineOffset;
// Without the accompanying fix in place, this test would have failed with:
// - Expected: 300
// - Actual : 0
// i.e. the indent was 0cm, even if Level1 and Level2 had other values.
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(300), nLeftMargin + nFirstLineOffset);
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testPasteInTextEditWithAnimationNode)
{
createSdImpressDoc();
// Give the slide an (empty) animation node, so the paragraph removal that the
// paste below performs is reported to the animation sequence.
uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawView> xDrawView(xModel->getCurrentController(), uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage(xDrawView->getCurrentPage(), uno::UNO_SET_THROW);
uno::Reference<animations::XAnimationNodeSupplier> xAnimNodeSupplier(xDrawPage,
uno::UNO_QUERY_THROW);
CPPUNIT_ASSERT(xAnimNodeSupplier->getAnimationNode().is());
// Type a word into the title placeholder, staying in text edit.
insertStringToObject(0, u"blah", /*bUseEscape*/ false);
// Select and copy it, then put the caret at the end so the paste appends.
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});
typeKey(pImpressDocument, KEY_END);
// Without the accompanying fix, this paste asserts in a dbgutil build: the
// paragraph removal probes the shape text through the UNO forwarder, forcing
// a text frame layout recompute while the EditEngine layout is suspended.
dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
// The word got appended to itself.
sd::ViewShell* pViewShell = pImpressDocument->GetDocShell()->GetViewShell();
SdrView* pView = pViewShell->GetView();
dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
EditView& rEditView = pView->GetTextEditOutlinerView()->GetEditView();
CPPUNIT_ASSERT_EQUAL(u"blahblah"_ustr, rEditView.GetSelected());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testUndoRestoresDeletedPlaceholderText)
{
// Given a slide whose title placeholder was typed into:
createSdImpressDoc();
auto* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
sd::View* pView = pViewShell->GetView();
SdrObject* pTitle = pViewShell->GetActualPage()->GetObj(0);
CPPUNIT_ASSERT(pTitle);
pView->MarkObj(pTitle, pView->GetSdrPageView());
pView->SdrBeginTextEdit(pTitle);
pView->GetTextEditOutlinerView()->GetEditView().SetSelection(ESelection::All());
pView->GetTextEditOutlinerView()->GetEditView().InsertText(u"Typed"_ustr);
pView->SdrEndTextEdit();
CPPUNIT_ASSERT_EQUAL(u"Typed"_ustr,
pTitle->GetOutlinerParaObject()->GetTextObject().GetText(0));
// When deleting all of that text, which puts the placeholder's prompt back:
pView->SdrBeginTextEdit(pTitle);
pView->GetTextEditOutlinerView()->GetEditView().SetSelection(ESelection::All());
pView->GetTextEditOutlinerView()->GetEditView().InsertText(OUString());
pView->SdrEndTextEdit();
CPPUNIT_ASSERT(pTitle->IsEmptyPresObj());
// Then one undo brings the text back. Without the fix the deletion was not undoable at all: the
// prompt goes in before svx captures the text change, which then looks like no change.
dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
CPPUNIT_ASSERT_EQUAL(u"Typed"_ustr,
pTitle->GetOutlinerParaObject()->GetTextObject().GetText(0));
CPPUNIT_ASSERT(!pTitle->IsEmptyPresObj());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf166401_imageFillsAPlaceholderHoldingText)
{
// Given a slide whose picture placeholder holds text, so an outliner object represents it:
createSdImpressDoc("pptx/pic-placeholder-with-text.pptx");
auto* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
sd::View* pView = pViewShell->GetView();
SdrObject* pText = pViewShell->GetActualPage()->GetObj(0);
CPPUNIT_ASSERT_EQUAL(SdrObjKind::OutlineText, pText->GetObjIdentifier());
// When an image is put into it, which is what it is a placeholder for:
pView->MarkObj(pText, pView->GetSdrPageView());
Graphic aGraphic(Bitmap(Size(16, 16), vcl::PixelFormat::N24_BPP));
sal_Int8 nAction = DND_ACTION_LINK;
pView->InsertGraphic(aGraphic, nAction, pText->GetSnapRect().Center(), pText, nullptr);
// Then a graphic object represents it, still as the picture placeholder, and the text it held
// has given way to the image.
SdrObject* pFilled = pViewShell->GetActualPage()->GetObj(0);
CPPUNIT_ASSERT_EQUAL(SdrObjKind::Graphic, pFilled->GetObjIdentifier());
CPPUNIT_ASSERT(!pFilled->HasText());
// The shape type is what the page answers for the object, so it states the identity.
auto xPage = mxComponent.queryThrow<drawing::XDrawPagesSupplier>()
->getDrawPages()
->getByIndex(0)
.queryThrow<drawing::XDrawPage>();
auto xShape = xPage->getByIndex(0).queryThrow<drawing::XShape>();
CPPUNIT_ASSERT_EQUAL(u"com.sun.star.presentation.GraphicObjectShape"_ustr,
xShape->getShapeType());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf166401_textGivenThroughTheApi)
{
// Given a slide with an empty picture placeholder:
createSdImpressDoc("pptx/picture-placeholder-custom-prompt.pptx");
auto xPage = mxComponent.queryThrow<drawing::XDrawPagesSupplier>()
->getDrawPages()
->getByIndex(0)
.queryThrow<drawing::XDrawPage>();
// When text reaches it without any editing, which is the route a script takes:
xPage->getByIndex(0).queryThrow<text::XTextRange>()->setString(u"Given through the API"_ustr);
Scheduler::ProcessEventsToIdle();
// Then an outliner object represents it, as it does for text that arrives by any other route,
// and the placeholder is still the picture one. Without the fix the placeholder went on
// standing for itself, and the text was painted the way a prompt is - unwrapped.
auto xShape = xPage->getByIndex(0).queryThrow<drawing::XShape>();
CPPUNIT_ASSERT_EQUAL(u"com.sun.star.presentation.OutlinerShape"_ustr, xShape->getShapeType());
CPPUNIT_ASSERT_EQUAL(u"com.sun.star.presentation.GraphicObjectShape"_ustr,
xShape.queryThrow<beans::XPropertySet>()
->getPropertyValue(u"PlaceholderShapeType"_ustr)
.get<OUString>());
CPPUNIT_ASSERT_EQUAL(u"Given through the API"_ustr,
xShape.queryThrow<text::XTextRange>()->getString());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf166401_theEditedObjectStaysWhileEditing)
{
// Given an empty picture placeholder in text edit, with text typed into it:
createSdImpressDoc("pptx/picture-placeholder-custom-prompt.pptx");
auto* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
sd::View* pView = pViewShell->GetView();
SdrObject* pEdited = pViewShell->GetActualPage()->GetObj(0);
pView->MarkObj(pEdited, pView->GetSdrPageView());
pView->SdrBeginTextEdit(pEdited);
CPPUNIT_ASSERT(pView->IsTextEdit());
pView->GetTextEditOutlinerView()->GetEditView().SetSelection(ESelection::All());
pView->GetTextEditOutlinerView()->GetEditView().InsertText(u"While editing"_ustr);
// When something asks that shape for its text through UNO, which is what another view does and
// which marks the object as no longer empty while the edit is still open:
auto xPage = mxComponent.queryThrow<drawing::XDrawPagesSupplier>()
->getDrawPages()
->getByIndex(0)
.queryThrow<drawing::XDrawPage>();
xPage->getByIndex(0).queryThrow<text::XTextRange>()->getString();
Scheduler::ProcessEventsToIdle();
// Then the object the edit view is working on is still the one on the page. Switching what
// represents the placeholder here took it away mid-typing: the edit was lost and editeng
// aborted on its undo manager.
CPPUNIT_ASSERT_EQUAL(pEdited, pViewShell->GetActualPage()->GetObj(0));
if (pView->IsTextEdit())
pView->SdrEndTextEdit();
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf166401_anEditElsewhereIsLeftAlone)
{
// Given two slides with a picture placeholder each, one of them in text edit with text typed
// into it:
createSdImpressDoc("pptx/picture-placeholder-custom-prompt.pptx");
dispatchCommand(mxComponent, u".uno:DuplicatePage"_ustr, {});
Scheduler::ProcessEventsToIdle();
auto* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
sd::View* pView = pViewShell->GetView();
SdrPage* pEditedPage = pViewShell->GetActualPage();
SdrObject* pEdited = pEditedPage->GetObj(0);
pView->MarkObj(pEdited, pView->GetSdrPageView());
pView->SdrBeginTextEdit(pEdited);
CPPUNIT_ASSERT(pView->IsTextEdit());
pView->GetTextEditOutlinerView()->GetEditView().SetSelection(ESelection::All());
pView->GetTextEditOutlinerView()->GetEditView().InsertText(u"While editing"_ustr);
// When another view asks that object for its text, which writes the typing back and marks it
// no longer empty while the edit is still open:
auto xPages = mxComponent.queryThrow<drawing::XDrawPagesSupplier>()->getDrawPages();
xPages->getByIndex(pEditedPage->GetPageNum() / 2)
.queryThrow<drawing::XShapes>()
->getByIndex(0)
.queryThrow<text::XTextRange>()
->getString();
// and text then reaches the placeholder on the other slide, the pass that switches what
// represents a placeholder runs over every page - and the object in text edit is not the one
// that asked for it. That is what two views editing one document look like from here.
CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xPages->getCount());
const sal_Int32 nElsewhere = pEditedPage->GetPageNum() / 2 == 0 ? 1 : 0;
auto xElsewherePage = xPages->getByIndex(nElsewhere).queryThrow<drawing::XShapes>();
xElsewherePage->getByIndex(0).queryThrow<text::XTextRange>()->setString(
u"Given elsewhere"_ustr);
Scheduler::ProcessEventsToIdle();
// Then that one is switched, so the pass did run - and the one being edited is still the object
// the edit view holds. Taking it away mid-typing lost the edit and aborted editeng on its undo
// manager, and the pass had only the object that asked for it to go by. The shape is asked
// again, since a UNO shape keeps the type it was made with.
CPPUNIT_ASSERT_EQUAL(
u"com.sun.star.presentation.OutlinerShape"_ustr,
xElsewherePage->getByIndex(0).queryThrow<drawing::XShape>()->getShapeType());
CPPUNIT_ASSERT_EQUAL(pEdited, pEditedPage->GetObj(0));
if (pView->IsTextEdit())
pView->SdrEndTextEdit();
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testOutlineDemoteTitle)
{
OutlinerView* pOutlinerView = createOutlineView({ u"A", u"B" });
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
// Tab in front of "B" turns the title of the second slide into a paragraph of the first.
pOutlinerView->SetSelection(ESelection(1, 0, 1, 0));
typeOutlineKey(KEY_TAB);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(1),
pImpressDocument->GetDoc()->GetSdPageCount(PageKind::Standard));
CPPUNIT_ASSERT_EQUAL(sal_Int32(2), pOutlinerView->GetOutliner().GetParagraphCount());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testOutlineSelectedPages)
{
createOutlineView({ u"A", u"B" });
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pImpressDocument->GetDoc();
pDoc->GetSdPage(0, PageKind::Standard)->SetSelected(false);
pDoc->GetSdPage(1, PageKind::Standard)->SetSelected(false);
// The state of the summary slide command marks the slide of the cursor as selected.
SfxPoolItemHolder aState;
pImpressDocument->GetDocShell()->GetViewShell()->GetViewFrame()->GetDispatcher()->QueryState(
SID_SUMMARY_PAGE, aState);
CPPUNIT_ASSERT(!pDoc->GetSdPage(0, PageKind::Standard)->IsSelected());
CPPUNIT_ASSERT(pDoc->GetSdPage(1, PageKind::Standard)->IsSelected());
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testOutlineDeleteAcrossSlides)
{
// Slides "A" with the body paragraph "x", "B" and "C".
createSdImpressDoc();
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pImpressDocument->GetDoc();
auto xDrawPages = mxComponent.queryThrow<drawing::XDrawPagesSupplier>()->getDrawPages();
xDrawPages->insertNewByIndex(0);
xDrawPages->insertNewByIndex(1);
const std::u16string_view aTitles[] = { u"A", u"B", u"C" };
for (sal_uInt16 i = 0; i < std::size(aTitles); ++i)
{
SdPage* pPage = pDoc->GetSdPage(i, PageKind::Standard);
pPage->SetAutoLayout(AUTOLAYOUT_TITLE_CONTENT, true);
auto pTitle = static_cast<SdrTextObj*>(pPage->GetPresObj(PresObjKind::Title));
pTitle->SetText(OUString(aTitles[i]));
pTitle->SetEmptyPresObj(false);
}
auto pBody = static_cast<SdrTextObj*>(
pDoc->GetSdPage(0, PageKind::Standard)->GetPresObj(PresObjKind::Outline));
pBody->SetText(u"x"_ustr);
pBody->SetEmptyPresObj(false);
dispatchCommand(mxComponent, u".uno:OutlineMode"_ustr, {});
sd::ViewShell* pViewShell = pImpressDocument->GetDocShell()->GetViewShell();
CPPUNIT_ASSERT_EQUAL(sd::ViewShell::ST_OUTLINE, pViewShell->GetShellType());
auto pView = static_cast<sd::SimpleOutlinerView*>(pViewShell->GetView());
OutlinerView* pOutlinerView = pView->GetViewByWindow(pViewShell->GetActiveWindow());
CPPUNIT_ASSERT(pOutlinerView);
Outliner& rOutliner = pOutlinerView->GetOutliner();
CPPUNIT_ASSERT_EQUAL(sal_Int32(4), rOutliner.GetParagraphCount());
// Deleting from the end of "A" to the end of "B" removes the second slide only.
pOutlinerView->SetSelection(ESelection(0, 1, 2, 1));
typeOutlineKey(KEY_DELETE);
CPPUNIT_ASSERT_EQUAL(sal_Int32(2), rOutliner.GetParagraphCount());
CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), pDoc->GetSdPageCount(PageKind::Standard));
}
CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testOutlineMoveTitleUp)
{
OutlinerView* pOutlinerView = createOutlineView({ u"A", u"B", u"C" });
auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
SdDrawDocument* pDoc = pImpressDocument->GetDoc();
SdPage* pPageB = pDoc->GetSdPage(1, PageKind::Standard);
SdPage* pPageC = pDoc->GetSdPage(2, PageKind::Standard);
// Moving "C" up moves its slide in front of the slide of "B".
pOutlinerView->SetSelection(ESelection(2, 0, 2, 1));
dispatchCommand(mxComponent, u".uno:OutlineUp"_ustr, {});
CPPUNIT_ASSERT_EQUAL(u"C"_ustr, pOutlinerView->GetOutliner().GetText(
pOutlinerView->GetOutliner().GetParagraph(1)));
CPPUNIT_ASSERT_EQUAL(pPageC, pDoc->GetSdPage(1, PageKind::Standard));
CPPUNIT_ASSERT_EQUAL(pPageB, pDoc->GetSdPage(2, PageKind::Standard));
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */