Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/sd/qa/unit/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 57 kB image not shown  

Quelle  misc-tests.cxx   Sprache: 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 <officecfg/Office/Common.hxx>

#include "sdmodeltestbase.hxx"

#include <com/sun/star/uno/Reference.hxx>

#include <com/sun/star/awt/Gradient.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/TextVerticalAdjust.hpp>
#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
#include <com/sun/star/drawing/XDrawPages.hpp>
#include <com/sun/star/drawing/XDrawPage.hpp>
#include <com/sun/star/drawing/XShapes.hpp>
#include <com/sun/star/graphic/XGraphic.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/table/XTable.hpp>
#include <com/sun/star/table/XMergeableCellRange.hpp>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <com/sun/star/view/XSelectionSupplier.hpp>

#include <comphelper/sequence.hxx>
#include <comphelper/propertysequence.hxx>
#include <DrawDocShell.hxx>
#include <drawdoc.hxx>
#include <vcl/scheduler.hxx>
#include <svx/sdr/table/tablecontroller.hxx>
#include <sfx2/request.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svxids.hrc>
#include <editeng/eeitem.hxx>
#include <editeng/adjustitem.hxx>
#include <editeng/outlobj.hxx>
#include <editeng/editobj.hxx>
#include <comphelper/base64.hxx>
#include <docmodel/uno/UnoGradientTools.hxx>
#include <undo/undomanager.hxx>
#include <GraphicViewShell.hxx>
#include <sdpage.hxx>
#include <app.hrc>
#include <DrawViewShell.hxx>
#include <LayerTabBar.hxx>
#include <vcl/event.hxx>
#include <vcl/keycodes.hxx>
#include <svx/svdoashp.hxx>
#include <tools/gen.hxx>
#include <svx/view3d.hxx>
#include <svx/scene3d.hxx>
#include <svx/sdmetitm.hxx>
#include <svx/xfillit0.hxx>
#include <svx/xbtmpit.hxx>
#include <unomodel.hxx>

using namespace ::com::sun::star;

/// Impress miscellaneous tests.
class SdMiscTest : public SdModelTestBase
{
public:
    SdMiscTest()
        : SdModelTestBase(u"/sd/qa/unit/data/"_ustr)
    {
    }

    void testTdf99396();
    void testTableObjectUndoTest();
    void testFillColor();
    void testFillGradient();
    void testTdf44774();
    void testTdf38225();
    void testTdf101242_ODF_no_settings();
    void testTdf101242_ODF_add_settings();
    void testTdf101242_settings_keep();
    void testTdf101242_settings_remove();
    void testTdf119392();
    void testTdf67248();
    void testTdf119956();
    void testTdf120527();
    void testTextColumns();
    void testTdf98839_ShearVFlipH();
    void testTdf130988();
    void testTdf131033();
    void testTdf129898LayerDrawnInSlideshow();
    void testTdf136956();
    void testTdf39519();
    void testTdf164284();
    void testEncodedTableStyles();
    void testTdf157117();
    void testPageBackgroundImages();

    CPPUNIT_TEST_SUITE(SdMiscTest);
    CPPUNIT_TEST(testTdf99396);
    CPPUNIT_TEST(testTableObjectUndoTest);
    CPPUNIT_TEST(testFillColor);
    CPPUNIT_TEST(testFillGradient);
    CPPUNIT_TEST(testTdf44774);
    CPPUNIT_TEST(testTdf38225);
    CPPUNIT_TEST(testTdf101242_ODF_no_settings);
    CPPUNIT_TEST(testTdf101242_ODF_add_settings);
    CPPUNIT_TEST(testTdf101242_settings_keep);
    CPPUNIT_TEST(testTdf101242_settings_remove);
    CPPUNIT_TEST(testTdf119392);
    CPPUNIT_TEST(testTdf67248);
    CPPUNIT_TEST(testTdf119956);
    CPPUNIT_TEST(testTdf120527);
    CPPUNIT_TEST(testTextColumns);
    CPPUNIT_TEST(testTdf98839_ShearVFlipH);
    CPPUNIT_TEST(testTdf130988);
    CPPUNIT_TEST(testTdf131033);
    CPPUNIT_TEST(testTdf129898LayerDrawnInSlideshow);
    CPPUNIT_TEST(testTdf136956);
    CPPUNIT_TEST(testTdf39519);
    CPPUNIT_TEST(testTdf164284);
    CPPUNIT_TEST(testEncodedTableStyles);
    CPPUNIT_TEST(testTdf157117);
    CPPUNIT_TEST(testPageBackgroundImages);
    CPPUNIT_TEST_SUITE_END();
};

void SdMiscTest::testTdf99396()
{
    // Load the document and select the table.
    createSdImpressDoc("tdf99396.odp");

    SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);
    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();

    SdPage* pPage = pViewShell->GetActualPage();
    SdrObject* pObject = pPage->GetObj(0);
    SdrView* pView = pViewShell->GetView();
    pView->MarkObj(pObject, pView->GetSdrPageView());

    SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
    // Make sure that the undo stack is empty.
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pDoc->GetUndoManager()->GetUndoActionCount());

    // Set the vertical alignment of the cells to bottom.
    sdr::table::SvxTableController* pTableController
        = dynamic_cast<sdr::table::SvxTableController*>(pView->getSelectionController().get());
    CPPUNIT_ASSERT(pTableController);
    SfxRequest aRequest(*pViewShell->GetViewFrame(), SID_TABLE_VERT_BOTTOM);
    pTableController->Execute(aRequest);
    // This was 0, it wasn't possible to undo a vertical alignment change.
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDoc->GetUndoManager()->GetUndoActionCount());
}

void SdMiscTest::testTableObjectUndoTest()
{
    // See tdf#99396 for the issue

    // Load the document and select the table.
    createSdImpressDoc("tdf99396.odp");
    SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);
    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
    SdPage* pPage = pViewShell->GetActualPage();
    auto pTableObject = dynamic_cast<sdr::table::SdrTableObj*>(pPage->GetObj(0));
    CPPUNIT_ASSERT(pTableObject);
    SdrView* pView = pViewShell->GetView();
    pView->MarkObj(pTableObject, pView->GetSdrPageView());

    SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
    // Make sure that the undo stack is empty.
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pDoc->GetUndoManager()->GetUndoActionCount());

    // Set horizontal and vertical adjustment during text edit.
    pView->SdrBeginTextEdit(pTableObject);
    CPPUNIT_ASSERT(pView->GetTextEditObject());
    {
        SfxRequest aRequest(*pViewShell->GetViewFrame(), SID_ATTR_PARA_ADJUST_RIGHT);
        SfxItemSet aEditAttr(pDoc->GetPool());
        pView->GetAttributes(aEditAttr);
        SfxItemSet aNewAttr(*(aEditAttr.GetPool()), aEditAttr.GetRanges());
        aNewAttr.Put(SvxAdjustItem(SvxAdjust::Right, EE_PARA_JUST));
        aRequest.Done(aNewAttr);
        const SfxItemSet* pArgs = aRequest.GetArgs();
        pView->SetAttributes(*pArgs);
    }
    const auto& pLocalUndoManager = pView->getViewLocalUndoManager();
    CPPUNIT_ASSERT_EQUAL(size_t(1), pLocalUndoManager->GetUndoActionCount());
    CPPUNIT_ASSERT_EQUAL(u"Apply attributes"_ustr, pLocalUndoManager->GetUndoActionComment());
    {
        auto pTableController
            = dynamic_cast<sdr::table::SvxTableController*>(pView->getSelectionController().get());
        CPPUNIT_ASSERT(pTableController);
        SfxRequest aRequest(*pViewShell->GetViewFrame(), SID_TABLE_VERT_BOTTOM);
        pTableController->Execute(aRequest);
    }
    // Global change "Format cell" is applied only - Change the vertical alignment to "Bottom"
    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetUndoManager()->GetUndoActionCount());
    CPPUNIT_ASSERT_EQUAL(u"Format cell"_ustr, pDoc->GetUndoManager()->GetUndoActionComment());

    pView->SdrEndTextEdit();

    // End of text edit, so the text edit action is added to the undo stack
    CPPUNIT_ASSERT_EQUAL(size_t(2), pDoc->GetUndoManager()->GetUndoActionCount());
    CPPUNIT_ASSERT_EQUAL(u"Edit text of Table"_ustr,
                         pDoc->GetUndoManager()->GetUndoActionComment(0));
    CPPUNIT_ASSERT_EQUAL(u"Format cell"_ustr, pDoc->GetUndoManager()->GetUndoActionComment(1));

    // Check that the result is what we expect.
    {
        uno::Reference<table::XTable> xTable = pTableObject->getTable();
        uno::Reference<beans::XPropertySet> xCell(xTable->getCellByPosition(0, 0), uno::UNO_QUERY);
        drawing::TextVerticalAdjust eAdjust = xCell->getPropertyValue(u"TextVerticalAdjust"_ustr)
                                                  .get<drawing::TextVerticalAdjust>();
        CPPUNIT_ASSERT_EQUAL(int(drawing::TextVerticalAdjust_BOTTOM), static_cast<int>(eAdjust));
    }
    {
        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::Right, pAdjust->GetAdjust());
    }

    // Now undo.
    pXImpressDocument->GetDocShell()->GetUndoManager()->Undo();

    // Undoing the last action - one left
    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetUndoManager()->GetUndoActionCount());
    CPPUNIT_ASSERT_EQUAL(u"Format cell"_ustr, pDoc->GetUndoManager()->GetUndoActionComment(0));

    // Check again that the result is what we expect.
    {
        uno::Reference<table::XTable> xTable = pTableObject->getTable();
        uno::Reference<beans::XPropertySet> xCell(xTable->getCellByPosition(0, 0), uno::UNO_QUERY);
        drawing::TextVerticalAdjust eAdjust = xCell->getPropertyValue(u"TextVerticalAdjust"_ustr)
                                                  .get<drawing::TextVerticalAdjust>();
        // This failed: Undo() did not change it from drawing::TextVerticalAdjust_BOTTOM.
        CPPUNIT_ASSERT_EQUAL(int(drawing::TextVerticalAdjust_TOP), static_cast<int>(eAdjust));
    }
    {
        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::Center, pAdjust->GetAdjust());
    }

    Scheduler::ProcessEventsToIdle();
    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetUndoManager()->GetUndoActionCount());
    CPPUNIT_ASSERT_EQUAL(u"Format cell"_ustr, pDoc->GetUndoManager()->GetUndoActionComment(0));

    /*
     * now test tdf#103950 - Undo does not revert bundled font size changes for table cells
     */

    pTableObject = dynamic_cast<sdr::table::SdrTableObj*>(pPage->GetObj(0));
    pView->MarkObj(pTableObject, pView->GetSdrPageView()); // select table
    {
        SfxRequest aRequest(*pViewShell->GetViewFrame(), SID_GROW_FONT_SIZE);
        static_cast<sd::DrawViewShell*>(pViewShell)->ExecChar(aRequest);
    }
    Scheduler::ProcessEventsToIdle();
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pDoc->GetUndoManager()->GetUndoActionCount());
    CPPUNIT_ASSERT_EQUAL(u"Apply attributes to Table"_ustr,
                         pDoc->GetUndoManager()->GetUndoActionComment(0));
    CPPUNIT_ASSERT_EQUAL(u"Grow font size"_ustr, pDoc->GetUndoManager()->GetUndoActionComment(1));
    CPPUNIT_ASSERT_EQUAL(u"Format cell"_ustr, pDoc->GetUndoManager()->GetUndoActionComment(2));
}

void SdMiscTest::testFillColor()
{
    // Test if setting the shape fill color from color to transparent automatically turns off the fill style to none
    createSdImpressDoc();
    uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<drawing::XDrawPages> xDrawPages = xDrawPagesSupplier->getDrawPages();
    // Insert a new page.
    uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->insertNewByIndex(0),
                                                 uno::UNO_SET_THROW);
    uno::Reference<drawing::XShapes> xShapes(xDrawPage, uno::UNO_QUERY_THROW);
    // Create a rectangle
    uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
    CPPUNIT_ASSERT(xFactory.is());
    uno::Reference<drawing::XShape> xShape1(
        xFactory->createInstance(u"com.sun.star.drawing.RectangleShape"_ustr),
        uno::UNO_QUERY_THROW);
    uno::Reference<beans::XPropertySet> xPropSet(xShape1, uno::UNO_QUERY_THROW);
    // Set FillStyle and FillColor
    xPropSet->setPropertyValue(u"FillStyle"_ustr, uno::Any(drawing::FillStyle_SOLID));
    xPropSet->setPropertyValue(u"FillColor"_ustr, uno::Any(COL_RED));
    // Add the rectangle to the page.
    xShapes->add(xShape1);

    // Retrieve the shape and check FillStyle and FillGradient
    uno::Reference<container::XIndexAccess> xIndexAccess(xDrawPage, uno::UNO_QUERY_THROW);
    uno::Reference<beans::XPropertySet> xPropSet2(xIndexAccess->getByIndex(0),
                                                  uno::UNO_QUERY_THROW);
    drawing::FillStyle eFillStyle;
    Color aColor;
    CPPUNIT_ASSERT(xPropSet2->getPropertyValue(u"FillStyle"_ustr) >>= eFillStyle);
    CPPUNIT_ASSERT_EQUAL(int(drawing::FillStyle_SOLID), static_cast<int>(eFillStyle));
    CPPUNIT_ASSERT(xPropSet2->getPropertyValue(u"FillColor"_ustr) >>= aColor);

    CPPUNIT_ASSERT_EQUAL(COL_RED, aColor);

    // Setup transparent color and check fill styles
    uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
    uno::Reference<view::XSelectionSupplier> xSelectionSupplier(xModel->getCurrentController(),
                                                                uno::UNO_QUERY);

    xSelectionSupplier->select(uno::Any(xShape1));
    CPPUNIT_ASSERT(xSelectionSupplier->getSelection().hasValue());

    const char arguments[] = "{"
                             "\"FillColor.Color\":{"
                             "\"type\":\"long\","
                             "\"value\":-1"
                             "}}";

    dispatchCommand(mxComponent, u".uno:FillColor"_ustr,
                    comphelper::containerToSequence(comphelper::JsonToPropertyValues(arguments)));

    uno::Reference<container::XIndexAccess> xIndexAccess2(xDrawPage, uno::UNO_QUERY_THROW);
    uno::Reference<beans::XPropertySet> xPropSet3(xIndexAccess2->getByIndex(0),
                                                  uno::UNO_QUERY_THROW);
    drawing::FillStyle eFillStyle2;
    CPPUNIT_ASSERT(xPropSet3->getPropertyValue(u"FillStyle"_ustr) >>= eFillStyle2);
    CPPUNIT_ASSERT_EQUAL(int(drawing::FillStyle_NONE), static_cast<int>(eFillStyle2));
}

void SdMiscTest::testFillGradient()
{
    createSdImpressDoc();
    uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<drawing::XDrawPages> xDrawPages = xDrawPagesSupplier->getDrawPages();
    // Insert a new page.
    uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->insertNewByIndex(0),
                                                 uno::UNO_SET_THROW);
    uno::Reference<drawing::XShapes> xShapes(xDrawPage, uno::UNO_QUERY_THROW);
    // Create a rectangle
    uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
    CPPUNIT_ASSERT(xFactory.is());
    uno::Reference<drawing::XShape> xShape1(
        xFactory->createInstance(u"com.sun.star.drawing.RectangleShape"_ustr),
        uno::UNO_QUERY_THROW);
    uno::Reference<beans::XPropertySet> xPropSet(xShape1, uno::UNO_QUERY_THROW);
    // Set FillStyle and FillGradient
    awt::Gradient aGradient;
    aGradient.StartColor = sal_Int32(COL_LIGHTRED);
    aGradient.EndColor = sal_Int32(COL_LIGHTGREEN);
    xPropSet->setPropertyValue(u"FillStyle"_ustr, uno::Any(drawing::FillStyle_GRADIENT));
    xPropSet->setPropertyValue(u"FillGradient"_ustr, uno::Any(aGradient));
    // Add the rectangle to the page.
    xShapes->add(xShape1);

    // Retrieve the shape and check FillStyle and FillGradient
    uno::Reference<container::XIndexAccess> xIndexAccess(xDrawPage, uno::UNO_QUERY_THROW);
    uno::Reference<beans::XPropertySet> xPropSet2(xIndexAccess->getByIndex(0),
                                                  uno::UNO_QUERY_THROW);
    drawing::FillStyle eFillStyle;
    awt::Gradient2 aGradient2;
    CPPUNIT_ASSERT(xPropSet2->getPropertyValue(u"FillStyle"_ustr) >>= eFillStyle);
    CPPUNIT_ASSERT_EQUAL(int(drawing::FillStyle_GRADIENT), static_cast<int>(eFillStyle));
    CPPUNIT_ASSERT(xPropSet2->getPropertyValue(u"FillGradient"_ustr) >>= aGradient2);

    // MCGR: Use the completely imported gradient to check for correctness
    const basegfx::BColorStops aColorStops
        = model::gradient::getColorStopsFromUno(aGradient2.ColorStops);

    CPPUNIT_ASSERT_EQUAL(size_t(2), aColorStops.size());
    CPPUNIT_ASSERT_EQUAL(0.0, aColorStops[0].getStopOffset());
    CPPUNIT_ASSERT_EQUAL(COL_LIGHTRED, Color(aColorStops[0].getStopColor()));
    CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[1].getStopOffset(), 1.0));
    CPPUNIT_ASSERT_EQUAL(COL_LIGHTGREEN, Color(aColorStops[1].getStopColor()));
}

void SdMiscTest::testTdf44774()
{
    createSdDrawDoc();
    SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);
    sd::DrawDocShell* pDocShell = pXImpressDocument->GetDocShell();

    SfxStyleSheetBasePool* pSSPool = pDocShell->GetStyleSheetPool();

    // Create a new style with an empty name, like what happens in UI when creating a new style
    SfxStyleSheetBase& rStyleA
        = pSSPool->Make(u""_ustr, SfxStyleFamily::Para, SfxStyleSearchBits::UserDefined);
    // Assign a new name, which does not yet set its ApiName
    rStyleA.SetName(u"StyleA"_ustr);
    // Create another style
    SfxStyleSheetBase& rStyleB
        = pSSPool->Make(u"StyleB"_ustr, SfxStyleFamily::Para, SfxStyleSearchBits::UserDefined);
    // ... and set its parent to the first one
    rStyleB.SetParent(u"StyleA"_ustr);

    // Now save the file and reload
    saveAndReload(u"draw8"_ustr);
    pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);
    pDocShell = pXImpressDocument->GetDocShell();
    pSSPool = pDocShell->GetStyleSheetPool();

    SfxStyleSheetBase* pStyle = pSSPool->Find(u"StyleB"_ustr, SfxStyleFamily::Para);
    CPPUNIT_ASSERT(pStyle);
    // The parent set in StyleB used to reset, because parent style's msApiName was empty
    CPPUNIT_ASSERT_EQUAL(u"StyleA"_ustr, pStyle->GetParent());
}

void SdMiscTest::testTdf38225()
{
    createSdImpressDoc();
    SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);
    sd::DrawDocShell* pDocShell = pXImpressDocument->GetDocShell();

    SfxStyleSheetBasePool* pSSPool = pDocShell->GetStyleSheetPool();

    // Create a new style with a name
    pSSPool->Make(u"StyleWithName1"_ustr, SfxStyleFamily::Para, SfxStyleSearchBits::UserDefined);

    // Now save the file and reload
    saveAndReload(u"draw8"_ustr);
    pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);
    pDocShell = pXImpressDocument->GetDocShell();
    pSSPool = pDocShell->GetStyleSheetPool();

    SfxStyleSheetBase* pStyle = pSSPool->Find(u"StyleWithName1"_ustr, SfxStyleFamily::Para);
    CPPUNIT_ASSERT(pStyle);

    // Rename the style
    CPPUNIT_ASSERT(pStyle->SetName(u"StyleWithName2"_ustr));

    // Save the file and reload again
    saveAndReload(u"draw8"_ustr);
    pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);
    pDocShell = pXImpressDocument->GetDocShell();
    pSSPool = pDocShell->GetStyleSheetPool();

    // The problem was that the style kept the old name upon reloading
    pStyle = pSSPool->Find(u"StyleWithName1"_ustr, SfxStyleFamily::Para);
    CPPUNIT_ASSERT(!pStyle);
    pStyle = pSSPool->Find(u"StyleWithName2"_ustr, SfxStyleFamily::Para);
    CPPUNIT_ASSERT(pStyle);
}

void SdMiscTest::testTdf120527()
{
    createSdImpressDoc();

    // Load a bitmap into the bitmap table.
    uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
    CPPUNIT_ASSERT(xFactory.is());
    uno::Reference<container::XNameContainer> xBitmaps(
        xFactory->createInstance(u"com.sun.star.drawing.BitmapTable"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT(xBitmaps.is());
    OUString aGraphicURL = createFileURL(u"tdf120527.jpg");
    xBitmaps->insertByName(u"test"_ustr, uno::Any(aGraphicURL));

    // Create a graphic.
    uno::Reference<drawing::XShape> xShape(
        xFactory->createInstance(u"com.sun.star.drawing.GraphicObjectShape"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT(xShape.is());
    uno::Reference<beans::XPropertySet> xShapeProperySet(xShape, uno::UNO_QUERY);
    CPPUNIT_ASSERT(xShapeProperySet.is());
    xShapeProperySet->setPropertyValue(u"GraphicURL"_ustr, xBitmaps->getByName(u"test"_ustr));

    // Insert it.
    uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
    CPPUNIT_ASSERT(xDrawPagesSupplier.is());
    uno::Reference<drawing::XDrawPages> xDrawPages = xDrawPagesSupplier->getDrawPages();
    CPPUNIT_ASSERT(xDrawPages.is());
    uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY);
    CPPUNIT_ASSERT(xDrawPage.is());
    // This failed with a lang.IllegalArgumentException.
    xDrawPage->add(xShape);

    // Verify that the graphic was actually consumed.
    uno::Reference<graphic::XGraphic> xGraphic;
    xShapeProperySet->getPropertyValue(u"Graphic"_ustr) >>= xGraphic;
    CPPUNIT_ASSERT(xGraphic.is());
}

// Testing document model part of editengine-columns
void SdMiscTest::testTextColumns()
{
    createSdImpressDoc();
    uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<drawing::XDrawPages> xDrawPages = xDrawPagesSupplier->getDrawPages();
    // Insert a new page.
    uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->insertNewByIndex(0),
                                                 uno::UNO_SET_THROW);
    uno::Reference<drawing::XShapes> xShapes(xDrawPage, uno::UNO_QUERY_THROW);

    {
        // Create a text shape
        uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
        CPPUNIT_ASSERT(xFactory.is());
        uno::Reference<drawing::XShape> xShape(
            xFactory->createInstance(u"com.sun.star.drawing.TextShape"_ustr), uno::UNO_QUERY_THROW);
        uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY_THROW);

        // Add the shape to the page.
        xShapes->add(xShape);

        // Set up columns
        auto pTextObj = DynCastSdrTextObj(SdrObject::getSdrObjectFromXShape(xShape));
        CPPUNIT_ASSERT(pTextObj);
        pTextObj->SetMergedItem(SfxInt16Item(SDRATTR_TEXTCOLUMNS_NUMBER, 2));
        pTextObj->SetMergedItem(SdrMetricItem(SDRATTR_TEXTCOLUMNS_SPACING, 1000));
    }

    {
        // Retrieve the shape and check columns
        uno::Reference<container::XIndexAccess> xIndexAccess(xDrawPage, uno::UNO_QUERY_THROW);
        uno::Reference<drawing::XShape> xShape(xIndexAccess->getByIndex(0), uno::UNO_QUERY_THROW);

        auto pTextObj = DynCastSdrTextObj(SdrObject::getSdrObjectFromXShape(xShape));
        CPPUNIT_ASSERT(pTextObj);

        CPPUNIT_ASSERT_EQUAL(sal_Int16(2), pTextObj->GetTextColumnsNumber());
        CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), pTextObj->GetTextColumnsSpacing());
    }
}

/// Draw miscellaneous tests.

// Since LO 6.2 the visible/printable/locked information for layers is always
// written as ODF attributes draw:display and draw:protected. It is only read from
// there, if the config items VisibleLayers, PrintableLayers and LockedLayers do
// not exist. The user option WriteLayerStateAsConfigItem can be set to 'true' to
// write these config items in addition to the ODF attributes for to produce
// documents for older LO versions or Apache OpenOffice. With value 'false' no
// config items are written. The 'testTdf101242_xyz' tests combine source
// files with and without config items with option values 'true' and 'false'.

void SdMiscTest::testTdf101242_ODF_add_settings()
{
    // Loads a document, which has the visible/printable/locked information for layers
    // only in the ODF attributes draw:display and draw:protected. The resaved document
    // should still have the ODF attributes and in addition the config items in settings.xml.
    // "Load" is needed for to handle layers, simple "loadURL" does not work.
    createSdDrawDoc("tdf101242_ODF.odg");

    // Saving including items in settings.xml
    std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
        comphelper::ConfigurationChanges::create());
    officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::set(true, pBatch);
    pBatch->commit();
    save(u"draw8"_ustr);

    // Verify, that the saved document still has the ODF attributes
    xmlDocUniquePtr pXmlDoc = parseExport(u"styles.xml"_ustr);
    CPPUNIT_ASSERT_MESSAGE("Failed to get 'styles.xml'", pXmlDoc);
    static constexpr OString sPathStart(
        "/office:document-styles/office:master-styles/draw:layer-set/draw:layer"_ostr);
    assertXPath(pXmlDoc,
                sPathStart + "[@draw:name='backgroundobjects' and @draw:protected='true']");
    assertXPath(pXmlDoc, sPathStart + "[@draw:name='controls' and @draw:display='screen']");
    assertXPath(pXmlDoc, sPathStart + "[@draw:name='measurelines' and @draw:display='printer']");

    // Verify, that the saved document has got the items in settings.xml
    xmlDocUniquePtr pXmlDoc2 = parseExport(u"settings.xml"_ustr);
    CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc2);
    static constexpr OString sPathStart2("/office:document-settings/office:settings/"
                                         "config:config-item-set[@config:name='ooo:view-settings']/"
                                         "config:config-item-map-indexed[@config:name='Views']/"
                                         "config:config-item-map-entry"_ostr);
    // Value is a bitfield with first Byte in order '* * * measurelines controls backgroundobjects background layout'
    // The first three bits depend on initialization and may change. The values in file are Base64 encoded.
    OUString sBase64;
    uno::Sequence<sal_Int8> aDecodedSeq;
    sBase64 = getXPathContent(pXmlDoc2,
                              sPathStart2 + "/config:config-item[@config:name='VisibleLayers']");
    CPPUNIT_ASSERT_MESSAGE("Item VisibleLayers does not exists.", !sBase64.isEmpty());
    comphelper::Base64::decode(aDecodedSeq, sBase64);
    CPPUNIT_ASSERT_EQUAL(0x0F, static_cast<sal_uInt8>(aDecodedSeq[0]) & 0x1F);

    sBase64 = getXPathContent(pXmlDoc2,
                              sPathStart2 + "/config:config-item[@config:name='PrintableLayers']");
    CPPUNIT_ASSERT_MESSAGE("Item PrintableLayers does not exists.", !sBase64.isEmpty());
    comphelper::Base64::decode(aDecodedSeq, sBase64);
    CPPUNIT_ASSERT_EQUAL(0x17, static_cast<sal_uInt8>(aDecodedSeq[0]) & 0x1F);

    sBase64 = getXPathContent(pXmlDoc2,
                              sPathStart2 + "/config:config-item[@config:name='LockedLayers']");
    CPPUNIT_ASSERT_MESSAGE("Item LockedLayers does not exists.", !sBase64.isEmpty());
    comphelper::Base64::decode(aDecodedSeq, sBase64);
    CPPUNIT_ASSERT_EQUAL(0x04, static_cast<sal_uInt8>(aDecodedSeq[0]) & 0x1F);
}

void SdMiscTest::testTdf101242_ODF_no_settings()
{
    // Loads a document, which has the visible/printable/locked information for layers
    // only in the ODF attributes draw:display and draw:protected. The resave document
    // should have only the ODF attributes and no config items in settings.xml.
    createSdDrawDoc("tdf101242_ODF.odg");

    // Saving without items in settings.xml
    std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
        comphelper::ConfigurationChanges::create());
    officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::set(false, pBatch);
    pBatch->commit();
    save(u"draw8"_ustr);

    // Verify, that the saved document still has the ODF attributes
    xmlDocUniquePtr pXmlDoc = parseExport(u"styles.xml"_ustr);
    CPPUNIT_ASSERT_MESSAGE("Failed to get 'styles.xml'", pXmlDoc);
    static constexpr OString sPathStart(
        "/office:document-styles/office:master-styles/draw:layer-set/draw:layer"_ostr);
    assertXPath(pXmlDoc,
                sPathStart + "[@draw:name='backgroundobjects' and @draw:protected='true']");
    assertXPath(pXmlDoc, sPathStart + "[@draw:name='controls' and @draw:display='screen']");
    assertXPath(pXmlDoc, sPathStart + "[@draw:name='measurelines' and @draw:display='printer']");

    // Verify, that the saved document has no layer items in settings.xml
    xmlDocUniquePtr pXmlDoc2 = parseExport(u"settings.xml"_ustr);
    CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc2);
    static constexpr OString sPathStart2("/office:document-settings/office:settings/"
                                         "config:config-item-set[@config:name='ooo:view-settings']/"
                                         "config:config-item-map-indexed[@config:name='Views']/"
                                         "config:config-item-map-entry"_ostr);
    assertXPath(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='VisibleLayers']", 0);
    assertXPath(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='PrintableLayers']", 0);
    assertXPath(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='LockedLayers']", 0);
}

void SdMiscTest::testTdf101242_settings_keep()
{
    // Loads a document, which has the visible/printable/locked information for layers
    // only in the config items in settings.xml. That is the case for all old documents.
    // The resaved document should have the ODF attributes draw:display and draw:protected
    // and should still have these config items in settings.xml.
    createSdDrawDoc("tdf101242_settings.odg");

    // Saving including items in settings.xml
    std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
        comphelper::ConfigurationChanges::create());
    officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::set(true, pBatch);
    pBatch->commit();
    save(u"draw8"_ustr);

    // Verify, that the saved document has the ODF attributes
    xmlDocUniquePtr pXmlDoc = parseExport(u"styles.xml"_ustr);
    CPPUNIT_ASSERT_MESSAGE("Failed to get 'styles.xml'", pXmlDoc);
    static constexpr OString sPathStart(
        "/office:document-styles/office:master-styles/draw:layer-set/draw:layer"_ostr);
    assertXPath(pXmlDoc,
                sPathStart + "[@draw:name='backgroundobjects' and @draw:protected='true']");
    assertXPath(pXmlDoc, sPathStart + "[@draw:name='controls' and @draw:display='screen']");
    assertXPath(pXmlDoc, sPathStart + "[@draw:name='measurelines' and @draw:display='printer']");

    // Verify, that the saved document still has the items in settings.xml
    xmlDocUniquePtr pXmlDoc2 = parseExport(u"settings.xml"_ustr);
    CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc2);
    static constexpr OString sPathStart2("/office:document-settings/office:settings/"
                                         "config:config-item-set[@config:name='ooo:view-settings']/"
                                         "config:config-item-map-indexed[@config:name='Views']/"
                                         "config:config-item-map-entry"_ostr);
    // Value is a bitfield with first Byte in order '* * * measurelines controls backgroundobjects background layout'
    // The first three bits depend on initialization and may change. The values in file are Base64 encoded.
    OUString sBase64;
    uno::Sequence<sal_Int8> aDecodedSeq;
    sBase64 = getXPathContent(pXmlDoc2,
                              sPathStart2 + "/config:config-item[@config:name='VisibleLayers']");
    CPPUNIT_ASSERT_MESSAGE("Item VisibleLayers does not exists.", !sBase64.isEmpty());
    comphelper::Base64::decode(aDecodedSeq, sBase64);
    CPPUNIT_ASSERT_EQUAL(0x0F, static_cast<sal_uInt8>(aDecodedSeq[0]) & 0x1F);

    sBase64 = getXPathContent(pXmlDoc2,
                              sPathStart2 + "/config:config-item[@config:name='PrintableLayers']");
    CPPUNIT_ASSERT_MESSAGE("Item PrintableLayers does not exists.", !sBase64.isEmpty());
    comphelper::Base64::decode(aDecodedSeq, sBase64);
    CPPUNIT_ASSERT_EQUAL(0x17, static_cast<sal_uInt8>(aDecodedSeq[0]) & 0x1F);

    sBase64 = getXPathContent(pXmlDoc2,
                              sPathStart2 + "/config:config-item[@config:name='LockedLayers']");
    CPPUNIT_ASSERT_MESSAGE("Item LockedLayers does not exists.", !sBase64.isEmpty());
    comphelper::Base64::decode(aDecodedSeq, sBase64);
    CPPUNIT_ASSERT_EQUAL(0x04, static_cast<sal_uInt8>(aDecodedSeq[0]) & 0x1F);
}

void SdMiscTest::testTdf101242_settings_remove()
{
    // Loads a document, which has the visible/printable/locked information for layers
    // only in the config items in settings.xml. That is the case for all old documents.
    // The resaved document should have only the ODF attributes draw:display and draw:protected
    // and should have no config items in settings.xml.
    createSdDrawDoc("tdf101242_settings.odg");

    // Saving without config items in settings.xml
    std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
        comphelper::ConfigurationChanges::create());
    officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::set(false, pBatch);
    pBatch->commit();
    save(u"draw8"_ustr);

    // Verify, that the saved document has the ODF attributes
    xmlDocUniquePtr pXmlDoc = parseExport(u"styles.xml"_ustr);
    CPPUNIT_ASSERT_MESSAGE("Failed to get 'styles.xml'", pXmlDoc);
    static constexpr OString sPathStart(
        "/office:document-styles/office:master-styles/draw:layer-set/draw:layer"_ostr);
    assertXPath(pXmlDoc,
                sPathStart + "[@draw:name='backgroundobjects' and @draw:protected='true']");
    assertXPath(pXmlDoc, sPathStart + "[@draw:name='controls' and @draw:display='screen']");
    assertXPath(pXmlDoc, sPathStart + "[@draw:name='measurelines' and @draw:display='printer']");

    // Verify, that the saved document has no layer items in settings.xml
    xmlDocUniquePtr pXmlDoc2 = parseExport(u"settings.xml"_ustr);
    CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc2);
    static constexpr OString sPathStart2("/office:document-settings/office:settings/"
                                         "config:config-item-set[@config:name='ooo:view-settings']/"
                                         "config:config-item-map-indexed[@config:name='Views']/"
                                         "config:config-item-map-entry"_ostr);
    assertXPath(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='VisibleLayers']", 0);
    assertXPath(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='PrintableLayers']", 0);
    assertXPath(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='LockedLayers']", 0);
}

void SdMiscTest::testTdf119392()
{
    // Loads a document which has two user layers "V--" and "V-L". Inserts a new layer "-P-" between them.
    // Checks, that the bitfields in the saved file have the bits in the correct order, in case
    // option WriteLayerAsConfigItem is true and the config items are written.
    std::shared_ptr<comphelper::ConfigurationChanges> batch(
        comphelper::ConfigurationChanges::create());
    officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::set(true, batch);
    batch->commit();

    createSdDrawDoc("tdf119392_InsertLayer.odg");
    SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);
    // Insert layer "-P-", not visible, printable, not locked
    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
    SdrView* pView = pViewShell->GetView();
    pView->InsertNewLayer(u"-P-"_ustr, 6); // 0..4 standard layer, 5 layer "V--"
    SdrPageView* pPageView = pView->GetSdrPageView();
    pPageView->SetLayerVisible(u"-P-"_ustr, false);
    pPageView->SetLayerPrintable(u"-P-"_ustr, true);
    pPageView->SetLayerLocked(u"-P-"_ustr, false);
    save(u"draw8"_ustr);

    // Verify correct bit order in bitfield in the config items in settings.xml
    xmlDocUniquePtr pXmlDoc = parseExport(u"settings.xml"_ustr);
    CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc);
    static constexpr OString sPathStart("/office:document-settings/office:settings/"
                                        "config:config-item-set[@config:name='ooo:view-settings']/"
                                        "config:config-item-map-indexed[@config:name='Views']/"
                                        "config:config-item-map-entry"_ostr);
    // First Byte is in order 'V-L -P- V-- measurelines controls backgroundobjects background layout'
    // Bits need to be: visible=10111111=0xbf=191 printable=01011111=0x5f=95 locked=10000000=0x80=128
    // The values in file are Base64 encoded.
    OUString sBase64;
    uno::Sequence<sal_Int8> aDecodedSeq;
    sBase64 = getXPathContent(pXmlDoc,
                              sPathStart + "/config:config-item[@config:name='VisibleLayers']");
    CPPUNIT_ASSERT_MESSAGE("Item VisibleLayers does not exists.", !sBase64.isEmpty());
    comphelper::Base64::decode(aDecodedSeq, sBase64);
    CPPUNIT_ASSERT_EQUAL(0xbF,
                         static_cast<sal_uInt8>(aDecodedSeq[0])
                             & 0xff); // & 0xff forces unambiguous types for CPPUNIT_ASSERT_EQUAL

    sBase64 = getXPathContent(pXmlDoc,
                              sPathStart + "/config:config-item[@config:name='PrintableLayers']");
    CPPUNIT_ASSERT_MESSAGE("Item PrintableLayers does not exists.", !sBase64.isEmpty());
    comphelper::Base64::decode(aDecodedSeq, sBase64);
    CPPUNIT_ASSERT_EQUAL(0x5f, static_cast<sal_uInt8>(aDecodedSeq[0]) & 0xff);

    sBase64
        = getXPathContent(pXmlDoc, sPathStart + "/config:config-item[@config:name='LockedLayers']");
    CPPUNIT_ASSERT_MESSAGE("Item LockedLayers does not exists.", !sBase64.isEmpty());
    comphelper::Base64::decode(aDecodedSeq, sBase64);
    CPPUNIT_ASSERT_EQUAL(0x80, static_cast<sal_uInt8>(aDecodedSeq[0]) & 0xff);
}

void SdMiscTest::testTdf67248()
{
    // The document tdf67248.odg has been created with a German UI. It has a user layer named "Background".
    // On opening the user layer must still exists. The error was, that it was merged into the standard
    // layer "background".
    createSdDrawDoc("tdf67248.odg");
    SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);
    SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
    SdrLayerAdmin& rLayerAdmin = pDoc->GetLayerAdmin();
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(6), rLayerAdmin.GetLayerCount());
}

void SdMiscTest::testTdf119956()
{
    createSdDrawDoc("tdf119956.odg");
    SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);
    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();

    sd::GraphicViewShell* pGraphicViewShell = static_cast<sd::GraphicViewShell*>(pViewShell);
    CPPUNIT_ASSERT(pGraphicViewShell);
    sd::LayerTabBar* pLayerTabBar = pGraphicViewShell->GetLayerTabControl();
    CPPUNIT_ASSERT(pLayerTabBar);
    pLayerTabBar->StateChanged(StateChangedType::InitShow);

    // Alt+Click sets a tab in edit mode, so that you can rename it.
    // The error was, that Alt+Click on a tab, which was not the current tab, did not set the clicked tab
    // as current tab. As a result, the entered text was applied to the wrong tab.

    // The test document has the layer tabs "layout", "controls", "measurelines" and "Layer4" in this order
    // The "pagePos" is 0, 1, 2, 3
    // Make sure, that tab "layout" is the current tab.
    MouseEvent aSyntheticMouseEvent;
    if (pLayerTabBar->GetCurPagePos() != 0)
    {
        sal_uInt16 nIdOfTabPos0(pLayerTabBar->GetPageId(0));
        tools::Rectangle aTabPos0Rect(pLayerTabBar->GetPageRect(nIdOfTabPos0));
        aSyntheticMouseEvent
            = MouseEvent(aTabPos0Rect.Center(), 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT, 0);
        pLayerTabBar->MouseButtonDown(aSyntheticMouseEvent);
    }
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), pLayerTabBar->GetCurPagePos());

    // Alt+Click on tab "Layer4"
    sal_uInt16 nIdOfTabPos3(pLayerTabBar->GetPageId(3));
    tools::Rectangle aTabPos3Rect(pLayerTabBar->GetPageRect(nIdOfTabPos3));
    aSyntheticMouseEvent = MouseEvent(aTabPos3Rect.Center(), 1, MouseEventModifiers::SYNTHETIC,
                                      MOUSE_LEFT, KEY_MOD2);
    pLayerTabBar->MouseButtonDown(aSyntheticMouseEvent);

    // Make sure, tab 3 is current tab now.
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(3), pLayerTabBar->GetCurPagePos());
}

void SdMiscTest::testTdf98839_ShearVFlipH()
{
    // Loads a document with a sheared shape and mirrors it
    createSdDrawDoc("tdf98839_ShearVFlipH.odg");
    SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);
    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
    SdPage* pPage = pViewShell->GetActualPage();
    SdrObjCustomShape* pShape = static_cast<SdrObjCustomShape*>(pPage->GetObj(0));
    pShape->Mirror(Point(4000, 2000), Point(4000, 10000));

    // Save and examine attribute draw:transform
    save(u"draw8"_ustr);
    xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
    CPPUNIT_ASSERT_MESSAGE("Failed to get 'content.xml'", pXmlDoc);
    static constexpr OString sPathStart(
        "/office:document-content/office:body/office:drawing/draw:page"_ostr);
    assertXPath(pXmlDoc, sPathStart);
    const OUString sTransform = getXPath(pXmlDoc, sPathStart + "/draw:custom-shape""transform");

    // Error was, that the shear angle had a wrong sign.
    CPPUNIT_ASSERT_MESSAGE("expected: draw:transform='skewX (-0.64350...)",
                           sTransform.startsWith("skewX (-"));
}

void SdMiscTest::testTdf130988()
{
    createSdDrawDoc("tdf130988_3D_create_lathe.odg");
    SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);

    //emulate command .uno:ConvertInto3DLathe
    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
    E3dView* pView = pViewShell->GetView();
    pView->MarkNextObj();
    pView->ConvertMarkedObjTo3D(false, basegfx::B2DPoint(8000.0, -3000.0),
                                basegfx::B2DPoint(3000.0, -8000.0));
    E3dScene* pObj
        = dynamic_cast<E3dScene*>(pView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj());
    CPPUNIT_ASSERT(pObj);

    // Error was, that the created 3D object had a wrong path. Instead examining
    // the path directly, I use the scene distance, because that is easier. The
    // scene distance is calculated from the object while creating.
    const double fDistance = pObj->GetDistance();
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("D3DSceneDistance", 7071.0, fDistance, 0.5);
}

void SdMiscTest::testTdf131033()
{
    createSdDrawDoc("tdf131033_3D_SceneSizeIn2d.odg");
    SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);

    // The document contains a polygon, so that emulate command .uno:ConvertInto3DLathe
    // by direct call of ConvertMarkedObjTo3D works.
    // It produces a rotation around a vertical axis, which is far away from the
    // generating shape.
    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
    E3dView* pView = pViewShell->GetView();
    pView->MarkNextObj();
    pView->ConvertMarkedObjTo3D(false, basegfx::B2DPoint(11000.0, -5000.0),
                                basegfx::B2DPoint(11000.0, -9000.0));
    E3dScene* pObj
        = dynamic_cast<E3dScene*>(pView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj());
    CPPUNIT_ASSERT(pObj);

    // Error was, that the 2D representation of the scene did not contain the default 20°
    // rotation of the new scene around x-axis and therefore was not high enough.
    const double fSnapRectHeight = pObj->GetSnapRect().getOpenHeight();
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("2D height", 7096.0, fSnapRectHeight, 1.0);
}

void SdMiscTest::testTdf129898LayerDrawnInSlideshow()
{
    // Versions LO 6.2 to 6.4 have produced files, where the layer DrawnInSlideshow has
    // got visible=false and printable=false attributes. Those files should be repaired now.
    createSdImpressDoc("tdf129898_faulty_DrawnInSlideshow.odp");
    SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);
    SdDrawDocument* pDoc = pXImpressDocument->GetDoc();

    // Verify model
    static constexpr OUString sName = u"DrawnInSlideshow"_ustr;
    SdrLayerAdmin& rLayerAdmin = pDoc->GetLayerAdmin();
    SdrLayer* pLayer = rLayerAdmin.GetLayer(sName);
    CPPUNIT_ASSERT_MESSAGE("No layer DrawnInSlideshow", pLayer);
    CPPUNIT_ASSERT(pLayer->IsVisibleODF());
    CPPUNIT_ASSERT(pLayer->IsPrintableODF());

    // Verify view
    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
    SdrPageView* pPageView = pViewShell->GetView()->GetSdrPageView();
    CPPUNIT_ASSERT(pPageView->IsLayerVisible(sName));
    CPPUNIT_ASSERT(pPageView->IsLayerPrintable(sName));
}

void SdMiscTest::testTdf136956()
{
    createSdImpressDoc("odp/cellspan.odp");
    SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);

    SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
    const SdrPage* pPage = pDoc->GetPage(1);
    sdr::table::SdrTableObj* pTableObj = dynamic_cast<sdr::table::SdrTableObj*>(pPage->GetObj(0));
    CPPUNIT_ASSERT(pTableObj);
    uno::Reference<table::XTable> xTable(pTableObj->getTable(), uno::UNO_SET_THROW);

    uno::Reference<css::table::XMergeableCellRange> xRange(
        xTable->createCursorByRange(xTable->getCellRangeByPosition(0, 0, 3, 2)),
        uno::UNO_QUERY_THROW);

    // 4x3 Table before merge.
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable->getColumnCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable->getRowCount());

    xRange->merge();

    // 1x1 Table after merge.
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable->getColumnCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable->getRowCount());

    pXImpressDocument->GetDocShell()->GetUndoManager()->Undo();

    // 4x3 Table after undo. Undo crashed before.
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable->getColumnCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable->getRowCount());
}

void SdMiscTest::testTdf39519()
{
    createSdImpressDoc();
    SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);

    // Change the name of the first page in the newly created document
    SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
    SdPage* pPage = static_cast<SdPage*>(pDoc->GetPage(1));
    pPage->SetName(u"Test"_ustr);

    // Insert a bookmark as a new page using the same name
    std::vector<OUString> aBookmarkList = { u"Test"_ustr };
    pDoc->CopyOrMovePagesWithinDocument(aBookmarkList, nullptr, 2, false);

    // Check if the copied page has a different name
    SdPage* pCopiedPage = static_cast<SdPage*>(pDoc->GetPage(2));
    // Without the fix in place, the names of the pages would not be different
    CPPUNIT_ASSERT(pCopiedPage->GetName() != pPage->GetName());
}

void SdMiscTest::testTdf164284()
{
    createSdImpressDoc();
    SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);

    // Change the name of the first page in the newly created document
    SdDrawDocument* pDoc = pXImpressDocument->GetDoc();
    SdPage* pPage = static_cast<SdPage*>(pDoc->GetPage(1));
    pPage->SetName(u"Test"_ustr);

    // Move a bookmark as a page using the same name
    pDoc->DoMakePageObjectsNamesUnique(false);
    std::vector<OUString> aBookmarkList = { u"Test"_ustr };
    pDoc->CopyOrMovePagesWithinDocument(aBookmarkList, nullptr, 2, true);

    // Check if the moved page has the same name
    SdPage* pMovedPage = static_cast<SdPage*>(pDoc->GetPage(2));
    // Without the fix in place, the names of the pages would be different
    CPPUNIT_ASSERT_EQUAL(pPage->GetName(), pMovedPage->GetName());
}

void SdMiscTest::testEncodedTableStyles()
{
    // Silence unrelated failure:
    // Error: element "table:table-template" is missing "first-row-start-column" attribute
    skipValidation();

    createSdDrawDoc();

    {
        uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(mxComponent,
                                                                             uno::UNO_QUERY_THROW);
        uno::Reference<css::lang::XSingleServiceFactory> xTableStyleFamily(
            xStyleFamiliesSupplier->getStyleFamilies()->getByName(u"table"_ustr),
            uno::UNO_QUERY_THROW);
        uno::Reference<css::lang::XSingleServiceFactory> xCellStyleFamily(
            xStyleFamiliesSupplier->getStyleFamilies()->getByName(u"cell"_ustr),
            uno::UNO_QUERY_THROW);

        uno::Reference<style::XStyle> xTableStyle(xTableStyleFamily->createInstance(),
                                                  uno::UNO_QUERY_THROW);
        uno::Reference<style::XStyle> xCellStyle(xCellStyleFamily->createInstance(),
                                                 uno::UNO_QUERY_THROW);

        uno::Reference<container::XNameContainer>(xTableStyleFamily, uno::UNO_QUERY_THROW)
            ->insertByName(u"table_1"_ustr, uno::Any(xTableStyle));
        uno::Reference<container::XNameContainer>(xCellStyleFamily, uno::UNO_QUERY_THROW)
            ->insertByName(u"table-body_1"_ustr, uno::Any(xCellStyle));
        uno::Reference<container::XNameReplace>(xTableStyle, uno::UNO_QUERY_THROW)
            ->replaceByName(u"body"_ustr, uno::Any(xCellStyle));
    }

    saveAndReload(u"draw8"_ustr);

    {
        uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(mxComponent,
                                                                             uno::UNO_QUERY_THROW);
        uno::Reference<container::XNameAccess> xTableStyleFamily(
            xStyleFamiliesSupplier->getStyleFamilies()->getByName(u"table"_ustr),
            uno::UNO_QUERY_THROW);
        // Such style used to be exported as "table_5f_1" instead.
        CPPUNIT_ASSERT(xTableStyleFamily->hasByName(u"table_1"_ustr));

        uno::Reference<container::XNameAccess> xTableStyle(
            xTableStyleFamily->getByName(u"table_1"_ustr), uno::UNO_QUERY_THROW);
        uno::Reference<style::XStyle> xCellStyle(xTableStyle->getByName(u"body"_ustr),
                                                 uno::UNO_QUERY);
        // Such style used to not be found by the table style, as it was
        // searching for "table-body_5f_1" instead of "table-body_1".
        CPPUNIT_ASSERT(xCellStyle.is());
        CPPUNIT_ASSERT_EQUAL(u"table-body_1"_ustr, xCellStyle->getName());
    }
}

void SdMiscTest::testTdf157117()
{
    createSdImpressDoc();
    SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pXImpressDocument);
    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();

    // insert two pages to make a total of 3 pages
    dispatchCommand(mxComponent, u".uno:InsertPage"_ustr, {});
    dispatchCommand(mxComponent, u".uno:InsertPage"_ustr, {});

    // assert the document has 3 standard pages
    SdDrawDocument* pDocument = pXImpressDocument->GetDoc();
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(3), pDocument->GetSdPageCount(PageKind::Standard));

    // alternate page insert method
    //    uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
    //    uno::Reference<drawing::XDrawPages> xDrawPages = xDrawPagesSupplier->getDrawPages();
    //    xDrawPages->insertNewByIndex(0);
    //    xDrawPages->insertNewByIndex(0);
    //    CPPUNIT_ASSERT_EQUAL(xDrawPages->getCount(), 3);

    // move to the last page
    dispatchCommand(mxComponent, u".uno:LastPage"_ustr, {});

    SdPage* pPage = pViewShell->GetActualPage();
    auto nPageNum = pPage->GetPageNum();
    // assert move to last page
    CPPUNIT_ASSERT_EQUAL(2, (nPageNum - 1) / 2);

    // delete the last page
    dispatchCommand(mxComponent, u".uno:DeletePage"_ustr, {});
    pPage = pViewShell->GetActualPage();
    nPageNum = pPage->GetPageNum();

    // Check that the new last page is moved to. Before, the first page was always moved to when
    // the last page was deleted.
    CPPUNIT_ASSERT_EQUAL(1, (nPageNum - 1) / 2);
}

void SdMiscTest::testPageBackgroundImages()
{
    // Create empty document
    createSdDrawDoc();

    auto pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
    CPPUNIT_ASSERT(pViewShell);

    auto* pDrawViewShell = dynamic_cast<sd::DrawViewShell*>(pViewShell);
    CPPUNIT_ASSERT(pDrawViewShell);

    SdDrawDocument* pDocument = pXImpressDocument->GetDocShell()->GetDoc();
    CPPUNIT_ASSERT(pDocument);

    // Check we have 1 Page
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), pDocument->GetSdPageCount(PageKind::Standard));

    // Add 3 pages
    dispatchCommand(mxComponent, u".uno:InsertPage"_ustr, {});
    dispatchCommand(mxComponent, u".uno:InsertPage"_ustr, {});
    dispatchCommand(mxComponent, u".uno:InsertPage"_ustr, {});

    // Check we have 4 Pages now
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(4), pDocument->GetSdPageCount(PageKind::Standard));

    // Add a background graphic to page 1
    {
        CPPUNIT_ASSERT_EQUAL(true, pDrawViewShell->SwitchPage(0));
        uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence({
            { "FileName", uno::Any(createFileURL(u"TestImage1.png")) },
        }));

        dispatchCommand(mxComponent, u".uno:SelectBackground"_ustr, aArgs);
    }

    // Add a background graphic to page 2
    {
        CPPUNIT_ASSERT_EQUAL(true, pDrawViewShell->SwitchPage(1));
        uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence({
            { "FileName", uno::Any(createFileURL(u"TestImage2.png")) },
        }));

        dispatchCommand(mxComponent, u".uno:SelectBackground"_ustr, aArgs);
    }

    // Add a background graphic to page 3
    {
        CPPUNIT_ASSERT_EQUAL(true, pDrawViewShell->SwitchPage(2));
        uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence({
            { "FileName", uno::Any(createFileURL(u"TestImage3.png")) },
        }));

        dispatchCommand(mxComponent, u".uno:SelectBackground"_ustr, aArgs);
    }

    // Add a background graphic to page 4
    {
        CPPUNIT_ASSERT_EQUAL(true, pDrawViewShell->SwitchPage(3));
        uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence({
            { "FileName", uno::Any(createFileURL(u"TestImage4.png")) },
        }));

        dispatchCommand(mxComponent, u".uno:SelectBackground"_ustr, aArgs);
    }

    // Store graphic names
    std::unordered_set<OUString> aGraphicNames;

    // Check page 1
    {
        CPPUNIT_ASSERT_EQUAL(true, pDrawViewShell->SwitchPage(0));
        SdPage* pPage = pViewShell->GetActualPage();

        SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aMergedAttr(pDocument->GetPool());
        SdStyleSheet* pStyleSheet = pPage->getPresentationStyle(HID_PSEUDOSHEET_BACKGROUND);
        sd::MergePageBackgroundFilling(pPage, pStyleSheet, false, aMergedAttr);

        // Style should be "BITMAP"
        CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_BITMAP,
                             aMergedAttr.Get(XATTR_FILLSTYLE).GetValue());
        auto aItem = aMergedAttr.Get<XFillBitmapItem>(XATTR_FILLBITMAP);
        aGraphicNames.insert(aItem.GetName());
    }

    // Check page 2
    {
        CPPUNIT_ASSERT_EQUAL(true, pDrawViewShell->SwitchPage(1));
        SdPage* pPage = pViewShell->GetActualPage();

        // Style should be "BITMAP"
        SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aMergedAttr(pDocument->GetPool());
        SdStyleSheet* pStyleSheet = pPage->getPresentationStyle(HID_PSEUDOSHEET_BACKGROUND);
        sd::MergePageBackgroundFilling(pPage, pStyleSheet, false, aMergedAttr);

        CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_BITMAP,
                             aMergedAttr.Get(XATTR_FILLSTYLE).GetValue());
        auto aItem = aMergedAttr.Get<XFillBitmapItem>(XATTR_FILLBITMAP);
        aGraphicNames.insert(aItem.GetName());
    }

    // Check page 3
    {
        CPPUNIT_ASSERT_EQUAL(true, pDrawViewShell->SwitchPage(2));
        SdPage* pPage = pViewShell->GetActualPage();

        // Style should be "BITMAP"
        SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aMergedAttr(pDocument->GetPool());
        SdStyleSheet* pStyleSheet = pPage->getPresentationStyle(HID_PSEUDOSHEET_BACKGROUND);
        sd::MergePageBackgroundFilling(pPage, pStyleSheet, false, aMergedAttr);

        CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_BITMAP,
                             aMergedAttr.Get(XATTR_FILLSTYLE).GetValue());
        auto aItem = aMergedAttr.Get<XFillBitmapItem>(XATTR_FILLBITMAP);
        aGraphicNames.insert(aItem.GetName());
    }

    // Check page 4
    {
        CPPUNIT_ASSERT_EQUAL(true, pDrawViewShell->SwitchPage(3));
        SdPage* pPage = pViewShell->GetActualPage();

        SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aMergedAttr(pDocument->GetPool());
        SdStyleSheet* pStyleSheet = pPage->getPresentationStyle(HID_PSEUDOSHEET_BACKGROUND);
        sd::MergePageBackgroundFilling(pPage, pStyleSheet, false, aMergedAttr);

        // Style should be "BITMAP"
        CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_BITMAP,
                             aMergedAttr.Get(XATTR_FILLSTYLE).GetValue());
        auto aItem = aMergedAttr.Get<XFillBitmapItem>(XATTR_FILLBITMAP);
        aGraphicNames.insert(aItem.GetName());
    }

    // Size of graphic names should be 4 - this means each page has a unique name
    CPPUNIT_ASSERT_EQUAL(size_t(4), aGraphicNames.size());
    // Check none of the graphic names is empty
    for (OUString const& rName : aGraphicNames)
        CPPUNIT_ASSERT(!rName.isEmpty());
}

CPPUNIT_TEST_SUITE_REGISTRATION(SdMiscTest);

CPPUNIT_PLUGIN_IMPLEMENT();

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=93 H=98 G=95

¤ Dauer der Verarbeitung: 0.20 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.