Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/sd/source/ui/unoidl/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 211 kB image not shown  

Quelle  unomodel.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/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <memory>

#include <com/sun/star/presentation/XPresentation2.hpp>

#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/LineStyle.hpp>
#include <com/sun/star/lang/DisposedException.hpp>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
#include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
#include <com/sun/star/lang/Locale.hpp>
#include <com/sun/star/awt/XDevice.hpp>
#include <com/sun/star/document/IndexedPropertyValues.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/util/XTheme.hpp>
#include <com/sun/star/animations/AnimationFill.hpp>
#include <com/sun/star/animations/AnimationRestart.hpp>
#include <com/sun/star/animations/AnimationEndSync.hpp>
#include <com/sun/star/animations/AnimationCalcMode.hpp>
#include <com/sun/star/animations/AnimationAdditiveMode.hpp>
#include <com/sun/star/animations/AnimationNodeType.hpp>
#include <com/sun/star/animations/AnimationTransformType.hpp>
#include <com/sun/star/animations/AnimationColorSpace.hpp>
#include <com/sun/star/animations/Event.hpp>
#include <com/sun/star/animations/EventTrigger.hpp>
#include <com/sun/star/animations/Timing.hpp>
#include <com/sun/star/animations/TransitionType.hpp>
#include <com/sun/star/animations/TransitionSubType.hpp>
#include <com/sun/star/animations/ValuePair.hpp>
#include <com/sun/star/animations/XAnimate.hpp>
#include <com/sun/star/animations/XAnimateMotion.hpp>
#include <com/sun/star/animations/XAnimateColor.hpp>
#include <com/sun/star/animations/XAnimateTransform.hpp>
#include <com/sun/star/animations/XIterateContainer.hpp>
#include <com/sun/star/animations/XTimeContainer.hpp>
#include <com/sun/star/animations/XTransitionFilter.hpp>
#include <com/sun/star/presentation/EffectNodeType.hpp>
#include <com/sun/star/presentation/EffectPresetClass.hpp>
#include <com/sun/star/presentation/ParagraphTarget.hpp>
#include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
#include <com/sun/star/presentation/TextAnimationType.hpp>


#include <com/sun/star/embed/Aspects.hpp>

#include <animations/animationnodehelper.hxx>

#include <officecfg/Office/Common.hxx>
#include <officecfg/Office/Impress.hxx>
#include <comphelper/dispatchcommand.hxx>
#include <comphelper/indexedpropertyvalues.hxx>
#include <comphelper/lok.hxx>
#include <comphelper/propertysequence.hxx>
#include <comphelper/propertyvalue.hxx>
#include <comphelper/sequence.hxx>
#include <comphelper/servicehelper.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/profilezone.hxx>

#include <sal/log.hxx>
#include <editeng/unofield.hxx>
#include <notifydocumentevent.hxx>
#include <tpaction.hxx>
#include <unomodel.hxx>
#include "unopool.hxx"
#include <sfx2/lokhelper.hxx>
#include <sfx2/dispatch.hxx>
#include <vcl/svapp.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>

#include <editeng/UnoForbiddenCharsTable.hxx>
#include <svx/svdoutl.hxx>
#include <o3tl/any.hxx>
#include <o3tl/safeint.hxx>
#include <o3tl/string_view.hxx>
#include <o3tl/test_info.hxx>
#include <o3tl/unit_conversion.hxx>
#include <svx/UnoNamespaceMap.hxx>
#include <svx/svdlayer.hxx>
#include <svx/svdsob.hxx>
#include <svx/svdundo.hxx>
#include <svx/svdomedia.hxx>
#include <svx/unoapi.hxx>
#include <svx/unofill.hxx>
#include <svx/sdrpagewindow.hxx>
#include <svx/sdrpaintwindow.hxx>
#include <editeng/fontitem.hxx>
#include <toolkit/awt/vclxdevice.hxx>
#include <svx/svdpool.hxx>
#include <svx/svdpagv.hxx>
#include <svtools/unoimap.hxx>
#include <svx/unoshape.hxx>
#include <editeng/unonrule.hxx>
#include <editeng/eeitem.hxx>
#include <unotools/datetime.hxx>
#include <sax/tools/converter.hxx>
#include <xmloff/autolayout.hxx>
#include <xmloff/xmltoken.hxx>
#include <rtl/math.hxx>
#include <tools/helpers.hxx>
#include <tools/json_writer.hxx>

// Support creation of GraphicStorageHandler and EmbeddedObjectResolver
#include <svx/xmleohlp.hxx>
#include <svx/xmlgrhlp.hxx>
#include <DrawDocShell.hxx>
#include <ViewShellBase.hxx>
#include "UnoDocumentSettings.hxx"

#include <Annotation.hxx>
#include <drawdoc.hxx>
#include <sdmod.hxx>
#include <sdresid.hxx>
#include <sdpage.hxx>

#include <strings.hrc>
#include <strings.hxx>
#include <unolayer.hxx>
#include <unopage.hxx>
#include "unocpres.hxx"
#include "unoobj.hxx"
#include <stlpool.hxx>
#include "unopback.hxx"
#include <unokywds.hxx>

#include <FrameView.hxx>
#include <ClientView.hxx>
#include <DrawViewShell.hxx>
#include <ViewShell.hxx>
#include <Window.hxx>
#include <optsitem.hxx>
#include <SlideshowLayerRenderer.hxx>

#include <vcl/pdfextoutdevdata.hxx>
#include <vcl/pdf/PDFNote.hxx>

#include <com/sun/star/presentation/AnimationSpeed.hpp>
#include <com/sun/star/presentation/ClickAction.hpp>
#include <svx/sdr/contact/viewobjectcontact.hxx>
#include <svx/sdr/contact/viewcontact.hxx>
#include <svx/sdr/contact/displayinfo.hxx>

#include <com/sun/star/office/XAnnotation.hpp>
#include <com/sun/star/office/XAnnotationAccess.hpp>
#include <com/sun/star/office/XAnnotationEnumeration.hpp>
#include <com/sun/star/geometry/RealPoint2D.hpp>
#include <com/sun/star/util/DateTime.hpp>

#include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>

#include <sfx2/lokcomponenthelpers.hxx>
#include <sfx2/LokControlHandler.hxx>
#include <tools/gen.hxx>
#include <tools/debug.hxx>
#include <tools/urlobj.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <tools/UnitConversion.hxx>
#include <svx/ColorSets.hxx>
#include <docmodel/theme/Theme.hxx>

#include <frozen/bits/defines.h>
#include <frozen/bits/elsa_std.h>
#include <frozen/unordered_map.h>
#include <SlideSorter.hxx>
#include <SlideSorterViewShell.hxx>
#include <controller/SlideSorterController.hxx>
#include <controller/SlsPageSelector.hxx>

#include <app.hrc>

using namespace ::cppu;
using namespace ::com::sun::star;
using namespace ::sd;

const TranslateId aTypeResIds[SdLinkTargetType::Count] =
{
    STR_SD_PAGE,            // SdLinkTargetType::Page
    STR_NOTES_MODE,         // SdLinkTargetType::Notes
    STR_HANDOUT,            // SdLinkTargetType::Handout
    STR_MASTERPAGE_NAME,    // SdLinkTargetType::MasterPage
};

TranslateId SdTPAction::GetClickActionSdResId( presentation::ClickAction eCA )
{
    switch( eCA )
    {
        case presentation::ClickAction_NONE:             return STR_CLICK_ACTION_NONE;
        case presentation::ClickAction_PREVPAGE:         return STR_CLICK_ACTION_PREVPAGE;
        case presentation::ClickAction_NEXTPAGE:         return STR_CLICK_ACTION_NEXTPAGE;
        case presentation::ClickAction_FIRSTPAGE:        return STR_CLICK_ACTION_FIRSTPAGE;
        case presentation::ClickAction_LASTPAGE:         return STR_CLICK_ACTION_LASTPAGE;
        case presentation::ClickAction_BOOKMARK:         return STR_CLICK_ACTION_BOOKMARK;
        case presentation::ClickAction_DOCUMENT:         return STR_CLICK_ACTION_DOCUMENT;
        case presentation::ClickAction_PROGRAM:          return STR_CLICK_ACTION_PROGRAM;
        case presentation::ClickAction_MACRO:            return STR_CLICK_ACTION_MACRO;
        case presentation::ClickAction_SOUND:            return STR_CLICK_ACTION_SOUND;
        case presentation::ClickAction_VERB:             return STR_CLICK_ACTION_VERB;
        case presentation::ClickAction_STOPPRESENTATION: return STR_CLICK_ACTION_STOPPRESENTATION;
        default: OSL_FAIL( "No StringResource for ClickAction available!" );
    }
    return {};
}

class SdUnoForbiddenCharsTable : public SvxUnoForbiddenCharsTable,
                                 public SfxListener
{
public:
    explicit SdUnoForbiddenCharsTable(SdrModel* pModel);
    virtual ~SdUnoForbiddenCharsTable() override;

    // SfxListener
    virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) noexcept override;
protected:
    virtual void onChange() override;

private:
    SdrModel*   mpModel;
};

namespace {

class SlideBackgroundInfo
{
public:
    SlideBackgroundInfo(const uno::Reference<drawing::XDrawPage>& xDrawPage,
                        const uno::Reference<drawing::XDrawPage>& xMasterPage);
    bool slideHasOwnBackground() const { return mbIsCustom; }
    bool hasBackground() const { return bHasBackground; }
    bool isSolidColor() const { return mbIsSolidColor; }
    ::Color getFillColor() const;
    sal_Int32 getFillTransparency() const;
    OString getFillColorAsRGBA() const;
private:
    bool getFillStyleImpl(const uno::Reference<drawing::XDrawPage>& xDrawPage);
private:
    uno::Reference<beans::XPropertySet> mxBackground;
    bool mbIsCustom;
    bool bHasBackground;
    bool mbIsSolidColor;
    drawing::FillStyle maFillStyle;
};

SlideBackgroundInfo::SlideBackgroundInfo(
        const uno::Reference<drawing::XDrawPage>& xDrawPage,
        const uno::Reference<drawing::XDrawPage>& xMasterPage)
    : mbIsCustom(false)
    , bHasBackground(false)
    , mbIsSolidColor(false)
    , maFillStyle(drawing::FillStyle_NONE)
{
    mbIsCustom = getFillStyleImpl(xDrawPage);
    bHasBackground = mbIsCustom;
    if (!bHasBackground)
    {
        bHasBackground = getFillStyleImpl(xMasterPage);
    }
    if (bHasBackground)
    {
        if (maFillStyle == drawing::FillStyle_SOLID)
        {
            OUString sGradientName;
            mxBackground->getPropertyValue("FillTransparenceGradientName") >>= sGradientName;
            if (sGradientName.isEmpty())
            {
                mbIsSolidColor = true;
            }
        }
    }
}

sal_Int32 SlideBackgroundInfo::getFillTransparency() const
{
    if (!mxBackground.is())
        return 0;
    sal_Int32 nFillTransparency = 0;
    mxBackground->getPropertyValue("FillTransparence") >>= nFillTransparency;
    return nFillTransparency;
}

::Color SlideBackgroundInfo::getFillColor() const
{
    if (!mxBackground.is())
        return {};
    if (sal_Int32 nFillColor; mxBackground->getPropertyValue("FillColor") >>= nFillColor)
    {
        return ::Color(ColorTransparency, nFillColor & 0xffffff);
    }
    return {};
}

OString SlideBackgroundInfo::getFillColorAsRGBA() const
{
    ::Color aColor = getFillColor();
    OString sColor = aColor.AsRGBHEXString().toUtf8();
    sal_uInt32 nAlpha = std::round((100 - getFillTransparency()) * 255 / 100.0);
    std::stringstream ss;
    ss << std::hex << std::uppercase << std::setfill ('0') << std::setw(2) << nAlpha;
    sColor += ss.str().c_str();
    return sColor;
}

bool SlideBackgroundInfo::getFillStyleImpl(const uno::Reference<drawing::XDrawPage>&&nbsp;xDrawPage)
{
    if( xDrawPage.is() )
    {
        uno::Reference< beans::XPropertySet > xPropSet( xDrawPage, uno::UNO_QUERY );
        if( xPropSet.is() )
        {
            uno::Reference< beans::XPropertySet > xBackground;
            if (xPropSet->getPropertySetInfo()->hasPropertyByName("Background"))
                xPropSet->getPropertyValue( "Background" ) >>= xBackground;
            if( xBackground.is() )
            {
                drawing::FillStyle aFillStyle;
                if( xBackground->getPropertyValue( "FillStyle" ) >>= aFillStyle )
                {
                    maFillStyle = aFillStyle;
                    if (aFillStyle != drawing::FillStyle_NONE)
                    {
                        mxBackground = std::move(xBackground);
                        return true;
                    }
                }
            }
        }
    }
    return false;
}

using namespace ::css::animations;
using namespace ::css::beans;
using namespace ::css::container;
using namespace ::css::uno;
using namespace ::xmloff::token;
using namespace ::css::presentation;

template <typename T, std::size_t N>
constexpr auto mapEnumToString(std::pair<T, std::string_view> const (&items)[N])
{
    return frozen::make_unordered_map<T, std::string_view, N>(items);
}

constexpr auto constTransitionTypeToString = mapEnumToString<sal_Int16>({
    { animations::TransitionType::BARWIPE, "BarWipe" }, // Wipe
    { animations::TransitionType::PINWHEELWIPE, "PineWheelWipe" }, // Wheel
    { animations::TransitionType::SLIDEWIPE, "SlideWipe" }, // Cover, Uncover
    { animations::TransitionType::RANDOMBARWIPE, "RandomBarWipe" }, // Bars
    { animations::TransitionType::CHECKERBOARDWIPE, "CheckerBoardWipe" }, // Checkers
    { animations::TransitionType::FOURBOXWIPE, "FourBoxWipe" }, // Shape
    { animations::TransitionType::IRISWIPE, "IrisWipe" }, // Box
    { animations::TransitionType::FANWIPE, "FanWipe" }, // Wedge
    { animations::TransitionType::BLINDSWIPE, "BlindWipe"}, // Venetian
    { animations::TransitionType::FADE, "Fade"},
    { animations::TransitionType::DISSOLVE, "Dissolve"},
    { animations::TransitionType::PUSHWIPE, "PushWipe"}, // Comb
    { animations::TransitionType::ELLIPSEWIPE, "EllipseWipe"}, // Shape
    { animations::TransitionType::BARNDOORWIPE, "BarnDoorWipe"}, // Split
    { animations::TransitionType::WATERFALLWIPE, "WaterfallWipe"}, // Diagonal
    { animations::TransitionType::MISCSHAPEWIPE, "MiscShapeWipe"},
    { animations::TransitionType::ZOOM, "Zoom"}
});

constexpr auto constTransitionSubTypeToString = mapEnumToString<sal_Int16>({
    { animations::TransitionSubType::LEFTTORIGHT, "LeftToRight" },
    { animations::TransitionSubType::TOPTOBOTTOM, "TopToBottom" },
    { animations::TransitionSubType::EIGHTBLADE, "8Blade" },
    { animations::TransitionSubType::FOURBLADE, "4Blade" },
    { animations::TransitionSubType::THREEBLADE, "3Blade" },
    { animations::TransitionSubType::TWOBLADEVERTICAL, "2BladeVertical" },
    { animations::TransitionSubType::ONEBLADE, "1Blade" },
    { animations::TransitionSubType::FROMTOPLEFT, "FromTopLeft" },
    { animations::TransitionSubType::FROMTOPRIGHT, "FromTopRight"},
    { animations::TransitionSubType::FROMBOTTOMLEFT, "FromBottomLeft"},
    { animations::TransitionSubType::FROMBOTTOMRIGHT, "FromBottomRight"},
    { animations::TransitionSubType::VERTICAL, "Vertical"},
    { animations::TransitionSubType::HORIZONTAL, "Horizontal"},
    { animations::TransitionSubType::DOWN, "Down"},
    { animations::TransitionSubType::ACROSS, "Across"},
    { animations::TransitionSubType::CORNERSOUT, "CornersOut"},
    { animations::TransitionSubType::DIAMOND, "Diamond"},
    { animations::TransitionSubType::CIRCLE, "Circle"},
    { animations::TransitionSubType::RECTANGLE, "Rectangle"},
    { animations::TransitionSubType::CENTERTOP, "CenterTop"},
    { animations::TransitionSubType::CROSSFADE, "CrossFade"},
    { animations::TransitionSubType::FADEOVERCOLOR, "FadeOverColor"},
    { animations::TransitionSubType::FROMLEFT, "FromLeft"},
    { animations::TransitionSubType::FROMRIGHT, "FromRight"},
    { animations::TransitionSubType::FROMTOP, "FromTop"},
    { animations::TransitionSubType::HORIZONTALLEFT, "HorizontalLeft"},
    { animations::TransitionSubType::HORIZONTALRIGHT, "HorizontalRight"},
    { animations::TransitionSubType::COMBVERTICAL, "CombVertical"},
    { animations::TransitionSubType::COMBHORIZONTAL, "CombHorizontal"},
    { animations::TransitionSubType::TOPLEFT, "TopLeft"},
    { animations::TransitionSubType::TOPRIGHT, "TopRight"},
    { animations::TransitionSubType::BOTTOMRIGHT, "BottomRight"},
    { animations::TransitionSubType::BOTTOMLEFT, "BottomLeft"},
    { animations::TransitionSubType::TOPCENTER, "TopCenter"},
    { animations::TransitionSubType::RIGHTCENTER, "RightCenter"},
    { animations::TransitionSubType::BOTTOMCENTER, "BottomCenter"},
    { animations::TransitionSubType::FANOUTHORIZONTAL, "FanOutHorizontal"},
    { animations::TransitionSubType::CORNERSIN, "CornersIn"},
    { animations::TransitionSubType::HEART, "Heart"},
    { animations::TransitionSubType::ROTATEIN, "RotateIn"}
});

constexpr auto constAnimationNodeTypeToString = mapEnumToString<sal_Int16>({
    { AnimationNodeType::ANIMATE, "Animate" },
    { AnimationNodeType::ANIMATECOLOR, "AnimateColor" },
    { AnimationNodeType::ANIMATEMOTION, "AnimateMotion" },
    { AnimationNodeType::ANIMATEPHYSICS, "Animate" },
    { AnimationNodeType::ANIMATETRANSFORM, "AnimateTransform" },
    { AnimationNodeType::AUDIO, "Audio" },
    { AnimationNodeType::COMMAND, "Command" },
    { AnimationNodeType::CUSTOM, "Custom" },
    { AnimationNodeType::ITERATE, "Iterate" },
    { AnimationNodeType::PAR, "Par" },
    { AnimationNodeType::SEQ, "Seq" },
    { AnimationNodeType::SET, "Set" },
    { AnimationNodeType::TRANSITIONFILTER, "TransitionFilter" },
});

constexpr auto constFillToString = mapEnumToString<sal_Int16>({
    { AnimationFill::DEFAULT"Default" },
    { AnimationFill::REMOVE, "Remove" },
    { AnimationFill::FREEZE, "Freeze" },
    { AnimationFill::HOLD, "Hold" },
    { AnimationFill::TRANSITION, "Transition" },
    { AnimationFill::AUTO"Auto" },
});

constexpr auto constRestartToString = mapEnumToString<sal_Int16>({
    { AnimationRestart::DEFAULT"Default" },
    { AnimationRestart::ALWAYS, "Always" },
    { AnimationRestart::WHEN_NOT_ACTIVE, "WhenNotActive" },
    { AnimationRestart::NEVER, "Never" },
});

constexpr auto constEndSyncToString = mapEnumToString<sal_Int16>({
    { AnimationEndSync::FIRST, "First" },
    { AnimationEndSync::LAST, "Last" },
    { AnimationEndSync::ALL, "All" },
    { AnimationEndSync::MEDIA, "Media" },
});

constexpr auto constCalcModeToString = mapEnumToString<sal_Int16>({
    { AnimationCalcMode::DISCRETE, "Discrete" },
    { AnimationCalcMode::LINEAR, "Linear" },
    { AnimationCalcMode::PACED, "Paced" },
    { AnimationCalcMode::SPLINE, "Spline" },
});

constexpr auto constAdditiveModeToString = mapEnumToString<sal_Int16>({
    { AnimationAdditiveMode::BASE, "Base" },
    { AnimationAdditiveMode::SUM, "Sum" },
    { AnimationAdditiveMode::REPLACE, "Replace" },
    { AnimationAdditiveMode::MULTIPLY, "Multiply" },
    { AnimationAdditiveMode::NONE, "None" },
});

constexpr auto constEffectPresetClassToString = mapEnumToString<sal_Int16>({
    { EffectPresetClass::CUSTOM, "Custom" },
    { EffectPresetClass::ENTRANCE, "Entrance" },
    { EffectPresetClass::EXIT"Exit" },
    { EffectPresetClass::EMPHASIS, "Emphasis" },
    { EffectPresetClass::MOTIONPATH, "MotionPath" },
    { EffectPresetClass::OLEACTION, "OleAction" },
    { EffectPresetClass::MEDIACALL, "MediaCall" },
});

constexpr auto constEffectNodeTypeToString = mapEnumToString<sal_Int16>({
    { EffectNodeType::DEFAULT"Default" },
    { EffectNodeType::ON_CLICK, "OnClick" },
    { EffectNodeType::WITH_PREVIOUS, "WithPrevious" },
    { EffectNodeType::AFTER_PREVIOUS, "AfterPrevious" },
    { EffectNodeType::MAIN_SEQUENCE, "MainSequence" },
    { EffectNodeType::TIMING_ROOT, "TimingRoot" },
    { EffectNodeType::INTERACTIVE_SEQUENCE, "InteractiveSequence" },
});

constexpr auto constEventTriggerToString = mapEnumToString<sal_Int16>({
    { EventTrigger::BEGIN_EVENT, "BeginEvent" },
    { EventTrigger::END_EVENT, "EndEvent" },
    { EventTrigger::NONE, "None" },
    { EventTrigger::ON_BEGIN, "OnBegin" },
    { EventTrigger::ON_CLICK, "OnClick" },
    { EventTrigger::ON_DBL_CLICK, "OnDblClick" },
    { EventTrigger::ON_END, "OnEnd" },
    { EventTrigger::ON_MOUSE_ENTER, "OnMouseEnter" },
    { EventTrigger::ON_MOUSE_LEAVE, "OnMouseLeave" },
    { EventTrigger::ON_NEXT, "OnNext" },
    { EventTrigger::ON_PREV, "OnPrev" },
    { EventTrigger::ON_STOP_AUDIO, "OnStopAudio" },
    { EventTrigger::REPEAT, "Repeat" },
});

constexpr auto constTimingToString = mapEnumToString<Timing>({
    { Timing_INDEFINITE, "indefinite" },
    { Timing_MEDIA, "media" },
});

constexpr auto constTransformTypeToString = mapEnumToString<sal_Int16>({
    { AnimationTransformType::TRANSLATE, "Translate" },
    { AnimationTransformType::SCALE, "Scale" },
    { AnimationTransformType::ROTATE, "Rotate" },
    { AnimationTransformType::SKEWX, "SkewX" },
    { AnimationTransformType::SKEWY, "SkewY" },
});

constexpr auto constSubItemToString = mapEnumToString<sal_Int16>({
    { ShapeAnimationSubType::AS_WHOLE, "AsWhole" },
    { ShapeAnimationSubType::ONLY_BACKGROUND, "OnlyBackground" },
    { ShapeAnimationSubType::ONLY_TEXT, "OnlyText" },
});

constexpr auto constIterateTypeToString = mapEnumToString<sal_Int16>({
    { TextAnimationType::BY_PARAGRAPH, "ByParagraph" },
    { TextAnimationType::BY_WORD, "ByWord" },
    { TextAnimationType::BY_LETTER, "ByLetter" },
});

constexpr auto constFillStyleToString = mapEnumToString<drawing::FillStyle>({
    { drawing::FillStyle_NONE, "None" },
    { drawing::FillStyle_SOLID, "Solid" },
    { drawing::FillStyle_BITMAP, "Bitmap" },
    { drawing::FillStyle_GRADIENT, "Gradient" },
    { drawing::FillStyle_HATCH, "Hatch" },
});

constexpr auto constLineStyleToString = mapEnumToString<drawing::LineStyle>({
    { drawing::LineStyle_NONE, "None" },
    { drawing::LineStyle_SOLID, "Solid" },
    { drawing::LineStyle_DASH, "Dash" },
});


constexpr auto constAttributeNameToXMLEnum
    = frozen::make_unordered_map<std::string_view, XMLTokenEnum>({
        { "X", XML_X },
        { "Y", XML_Y },
        { "Width", XML_WIDTH },
        { "Height", XML_HEIGHT },
        { "Rotate", XML_ROTATE },
        { "SkewX", XML_SKEWX },
        { "FillColor", XML_FILL_COLOR },
        { "FillStyle", XML_FILL },
        { "LineColor", XML_STROKE_COLOR },
        { "LineStyle",XML_STROKE  },
        { "CharColor", XML_COLOR },
        { "CharRotation", XML_TEXT_ROTATION_ANGLE },
        { "CharWeight", XML_FONT_WEIGHT },
        { "CharUnderline", XML_TEXT_UNDERLINE },
        { "CharFontName", XML_FONT_FAMILY },
        { "CharHeight", XML_FONT_SIZE },
        { "CharPosture", XML_FONT_STYLE },
        { "Visibility", XML_VISIBILITY },
        { "Opacity", XML_OPACITY },
        { "DimColor", XML_DIM },
});

class AnimationsExporter
{
public:
    AnimationsExporter(::tools::JsonWriter& rWriter,
                       const Reference<drawing::XDrawPage>& xDrawPage);
    void exportAnimations();
    void exportTriggers() const;
    [[nodiscard]] bool hasEffects() const { return mbHasEffects; }

private:
    void exportNode(const Reference<XAnimationNode>& xNode);
    void exportNodeImpl(const Reference<XAnimationNode>& xNode);
    void exportContainer(const Reference<XTimeContainer>& xContainer);

    void exportAnimate(const Reference<XAnimate>& xAnimate);

    void convertValue(XMLTokenEnum eAttributeName, OStringBuffer& sTmp, const Any& rValue) const;
    void convertTiming(OStringBuffer& sTmp, const Any& rValue);

    void appendTrigger(const css::uno::Any& rTarget, const OString& rTriggerHash);
    void exportTriggersImpl(const uno::Reference<drawing::XShapes>& xShapes) const;

private:
    ::tools::JsonWriter& mrWriter;
    Reference<drawing::XDrawPage> mxDrawPage;
    Reference<XPropertySet> mxPageProps;
    Reference<XAnimationNode> mxRootNode;
    bool mbHasEffects;
    std::unordered_map<SdrObject*, OString> maEventTriggerSet;
};

AnimationsExporter::AnimationsExporter(::tools::JsonWriter& rWriter,
                                       const Reference<drawing::XDrawPage>& xDrawPage)
    : mrWriter(rWriter)
    , mxDrawPage(xDrawPage)
    , mbHasEffects(false)
{
    if (!mxDrawPage.is())
        return;

    try
    {
        mxPageProps = Reference<XPropertySet>(xDrawPage, UNO_QUERY);
        if (!mxPageProps.is())
            return;

        Reference<XAnimationNodeSupplier> xAnimNodeSupplier(mxDrawPage, UNO_QUERY);
        if (!xAnimNodeSupplier.is())
            return;

        Reference<XAnimationNode> xRootNode = xAnimNodeSupplier->getAnimationNode();
        if (xRootNode.is())
        {
            // first check if there are no animations
            Reference<XEnumerationAccess> xEnumerationAccess(xRootNode, UNO_QUERY_THROW);
            Reference<XEnumeration> xEnumeration(xEnumerationAccess->createEnumeration(),
                                                 css::uno::UNO_SET_THROW);
            if (xEnumeration->hasMoreElements())
            {
                // first child node may be an empty main sequence, check this
                Reference<XAnimationNode> xMainNode(xEnumeration->nextElement(), UNO_QUERY_THROW);
                Reference<XEnumerationAccess> xMainEnumerationAccess(xMainNode, UNO_QUERY_THROW);
                Reference<XEnumeration> xMainEnumeration(
                    xMainEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW);

                // only export if the main sequence is not empty or if there are additional
                // trigger sequences
                mbHasEffects
                    = xMainEnumeration->hasMoreElements() || xEnumeration->hasMoreElements();
            }
        }
        if (mbHasEffects)
            mxRootNode = std::move(xRootNode);
    }
    catch (const RuntimeException&)
    {
        TOOLS_WARN_EXCEPTION("sd""unomodel: AnimationsExporter");
    }
}

template <typename EnumT, size_t N>
constexpr bool convertEnum(OStringBuffer& rBuffer, EnumT nValue,
                           const frozen::unordered_map<EnumT, std::string_view, N>& rMap)
{
    auto iterator = rMap.find(nValue);
    if (iterator == rMap.end())
        return false;
    rBuffer.append(iterator->second);
    return true;
}

void convertDouble(OStringBuffer& rBuffer, double fValue)
{
        ::rtl::math::doubleToStringBuffer(rBuffer, fValue, rtl_math_StringFormat_Automatic,
                                          rtl_math_DecimalPlaces_Max, '.'true);
}

void convertBool(OStringBuffer& rBuffer, bool bValue)
{
    rBuffer.append( bValue );
}

void convertPath(OStringBuffer& sTmp, const Any& rPath)
{
    OUString aStr;
    rPath >>= aStr;
    sTmp = aStr.toUtf8();
}

void convertColor(OStringBuffer& rBuffer, sal_Int32 nColor)
{
    OUStringBuffer aUBuffer;
    ::sax::Converter::convertColor(aUBuffer, nColor);
    rBuffer.append(aUBuffer.makeStringAndClear().toUtf8());
}

void convertColor(OStringBuffer& rBuffer, const Any& rValue)
{
    sal_Int32 nColor = 0;
    if (rValue >>= nColor)
    {
        convertColor(rBuffer, nColor);
    }
    else
    {
        Sequence<double> aHSL;
        if ((rValue >>= aHSL) && (aHSL.getLength() == 3))
        {
            rBuffer.append("hsl(" + OString::number(aHSL[0]) + ","
                           + OString::number(aHSL[1] * 100.0) + "%,"
                           + OString::number(aHSL[2] * 100.0) + "%)");
        }
    }
}

bool isValidNode(const Reference<XAnimationNode>& xNode)
{
    if (xNode.is())
    {
        sal_Int16 nNodeType = xNode->getType();
        auto iterator = constAnimationNodeTypeToString.find(nNodeType);
        return iterator != constAnimationNodeTypeToString.end();
    }
    return false;
}

SdrObject* getObjectForShape(uno::Reference<drawing::XShape> const& xShape)
{
    if (!xShape.is())
        return nullptr;
    SvxShape* pShape = comphelper::getFromUnoTunnel<SvxShape>(xShape);
    if (pShape)
        return pShape->GetSdrObject();
    return nullptr;
}

SdrObject* getTargetObject(const uno::Any& aTargetAny)
{
    SdrObject* pObject = nullptr;
    uno::Reference<drawing::XShape> xShape;

    if ((aTargetAny >>= xShape) && xShape.is())
    {
        pObject = getObjectForShape(xShape);
    }
    else // if target is not a shape - could be paragraph target containing a shape
    {
        presentation::ParagraphTarget aParagraphTarget;
        if ((aTargetAny >>= aParagraphTarget) && aParagraphTarget.Shape.is())
        {
            pObject = getObjectForShape(aParagraphTarget.Shape);
        }
    }

    return pObject;
}

bool isNodeTargetInShapeGroup(const Reference<XAnimationNode>& xNode)
{
    Reference<XAnimate> xAnimate(xNode, UNO_QUERY);
    if (xAnimate.is())
    {
        SdrObject* pObject = getTargetObject(xAnimate->getTarget());
        if (pObject)
            return pObject->getParentSdrObjectFromSdrObject() != nullptr;
    }
    return false;
}

bool isNodeTargetAGroup(const Reference<XAnimationNode>& xNode)
{
    Reference<XAnimate> xAnimate(xNode, UNO_QUERY);
    if (xAnimate.is())
    {
        SdrObject* pObject = getTargetObject(xAnimate->getTarget());
        if (pObject)
            return pObject->getChildrenOfSdrObject() != nullptr;
    }
    return false;
}

bool isEffectValidForTarget(const Reference<XAnimationNode>& xNode)
{
    const Sequence<NamedValue> aUserData(xNode->getUserData());
    for (const auto& rValue : aUserData)
    {
        if (!IsXMLToken(rValue.Name, XML_PRESET_ID))
            continue;

        OUString aPresetId;
        if (rValue.Value >>= aPresetId)
        {
            if (constNonValidEffectsForGroupSet.find(aPresetId.toUtf8())
                != constNonValidEffectsForGroupSet.end())
            {
                // it's in the list, so we need to check if the effect target is a group or not
                Reference<XTimeContainer> xContainer(xNode, UNO_QUERY);
                if (xContainer.is())
                {
                    Reference<XEnumerationAccess> xEnumerationAccess(xContainer, UNO_QUERY);
                    Reference<XEnumeration> xEnumeration = xEnumerationAccess->createEnumeration();

                    // target is the same for all children, check the first one
                    if (xEnumeration.is() && xEnumeration->hasMoreElements())
                    {
                        Reference<XAnimationNode> xChildNode(xEnumeration->nextElement(),
                                                             UNO_QUERY);
                        if (isNodeTargetAGroup(xChildNode))
                            return false;
                    }
                }
            }
        }
        // preset id found and checked, we can exit
        break;
    }
    return true;
}

void AnimationsExporter::exportAnimations()
{
    if (!mxDrawPage.is() || !mxPageProps.is() || !mxRootNode.is() || !hasEffects())
        return;

    if (isValidNode(mxRootNode))
    {
        auto aNode = mrWriter.startNode("root");
        exportNodeImpl(mxRootNode);
    }
}

void AnimationsExporter::exportNode(const Reference<XAnimationNode>& xNode)
{
    // afaics, when a shape is part of a group any applied effect is ignored
    // moreover, some kind of effect, like the ones based on color animations,
    // is ignored when applied to a group
    if (!isValidNode(xNode) || isNodeTargetInShapeGroup(xNode) || !isEffectValidForTarget(xNode))
        return;
    auto aStruct = mrWriter.startStruct();
    exportNodeImpl(xNode);
}

void AnimationsExporter::exportNodeImpl(const Reference<XAnimationNode>& xNode)
{
    try
    {
        std::string sId = GetInterfaceHash(xNode);
        mrWriter.put("id", sId);
        sal_Int16 nNodeType = xNode->getType();
        auto iterator = constAnimationNodeTypeToString.find(nNodeType);
        assert(iterator != constAnimationNodeTypeToString.end() && "must be previously checked with isValidNode");
        mrWriter.put("nodeName", iterator->second);

        // common properties
        OStringBuffer sTmp;
        Any aTemp;
        double fTemp = 0;
        sal_Int16 nTemp;

        aTemp = xNode->getBegin();
        if (aTemp.hasValue())
        {
            convertTiming(sTmp, aTemp);
            mrWriter.put("begin", sTmp.makeStringAndClear());
        }
        aTemp = xNode->getDuration();
        if (aTemp.hasValue())
        {
            if (aTemp >>= fTemp)
            {
                convertDouble(sTmp, fTemp);
                sTmp.append('s');
                mrWriter.put("dur", sTmp.makeStringAndClear());
            }
            else
            {
                Timing eTiming;
                if (aTemp >>= eTiming)
                {
                    mrWriter.put("dur", eTiming == Timing_INDEFINITE ? "indefinite" : "media");
                }
            }
        }
        aTemp = xNode->getEnd();
        if (aTemp.hasValue())
        {
            convertTiming(sTmp, aTemp);
            mrWriter.put("end", sTmp.makeStringAndClear());
        }
        nTemp = xNode->getFill();
        if (nTemp != AnimationFill::DEFAULT)
        {
            convertEnum(sTmp, nTemp, constFillToString);
            mrWriter.put("fill", sTmp.makeStringAndClear());
        }
        nTemp = xNode->getFillDefault();
        if (nTemp != AnimationFill::INHERIT)
        {
            convertEnum(sTmp, nTemp, constFillToString);
            mrWriter.put("fillDefault", sTmp.makeStringAndClear());
        }
        nTemp = xNode->getRestart();
        if (nTemp != AnimationRestart::DEFAULT)
        {
            convertEnum(sTmp, nTemp, constRestartToString);
            mrWriter.put("restart", sTmp.makeStringAndClear());
        }
        nTemp = xNode->getRestartDefault();
        if (nTemp != AnimationRestart::INHERIT)
        {
            convertEnum(sTmp, nTemp, constRestartToString);
            mrWriter.put("restartDefault", sTmp.makeStringAndClear());
        }
        fTemp = xNode->getAcceleration();
        if (fTemp != 0.0)
        {
            convertDouble(sTmp, fTemp);
            mrWriter.put("accelerate", sTmp.makeStringAndClear());
        }
        fTemp = xNode->getDecelerate();
        if (fTemp != 0.0)
        {
            convertDouble(sTmp, fTemp);
            mrWriter.put("decelerate", sTmp.makeStringAndClear());
        }
        bool bTemp = xNode->getAutoReverse();
        if (bTemp)
        {
            convertBool(sTmp, bTemp);
            mrWriter.put("autoreverse", sTmp.makeStringAndClear());
        }
        aTemp = xNode->getRepeatCount();
        if (aTemp.hasValue())
        {
            Timing eTiming;
            if ((aTemp >>= eTiming) && (eTiming == Timing_INDEFINITE))
            {
                mrWriter.put("repeatCount""indefinite");
            }
            else if (aTemp >>= fTemp)
            {
                convertDouble(sTmp, fTemp);
                mrWriter.put("repeatCount", sTmp.makeStringAndClear());
            }
        }
        aTemp = xNode->getRepeatDuration();
        if (aTemp.hasValue())
        {
            Timing eTiming;
            if ((aTemp >>= eTiming) && (eTiming == Timing_INDEFINITE))
            {
                mrWriter.put("repeatDur""indefinite");
            }
            else if (aTemp >>= fTemp)
            {
                convertDouble(sTmp, fTemp);
                mrWriter.put("repeatDur", sTmp.makeStringAndClear());
            }
        }
        aTemp = xNode->getEndSync();
        if (aTemp.hasValue() && (aTemp >>= nTemp))
        {
            convertEnum(sTmp, nTemp, constEndSyncToString);
            mrWriter.put("endSync", sTmp.makeStringAndClear());
        }

        sal_Int16 nContainerNodeType = EffectNodeType::DEFAULT;
        const Sequence<NamedValue> aUserData(xNode->getUserData());
        for (const auto& rValue : aUserData)
        {
            if (IsXMLToken(rValue.Name, XML_NODE_TYPE))
            {
                if ((rValue.Value >>= nContainerNodeType)
                    && (nContainerNodeType != EffectNodeType::DEFAULT))
                {
                    convertEnum(sTmp, nContainerNodeType, constEffectNodeTypeToString);
                    mrWriter.put("nodeType", sTmp.makeStringAndClear());
                }
            }
            else if (IsXMLToken(rValue.Name, XML_PRESET_ID))
            {
                OUString aPresetId;
                if (rValue.Value >>= aPresetId)
                {
                    mrWriter.put("presetId", aPresetId);
                }
            }
            else if (IsXMLToken(rValue.Name, XML_PRESET_SUB_TYPE))
            {
                OUString aPresetSubType;
                if (rValue.Value >>= aPresetSubType)
                {
                    mrWriter.put("presetSubType", aPresetSubType);
                }
            }
            else if (IsXMLToken(rValue.Name, XML_PRESET_CLASS))
            {
                sal_Int16 nEffectPresetClass = sal_uInt16(0);
                if (rValue.Value >>= nEffectPresetClass)
                {
                    convertEnum(sTmp, nEffectPresetClass, constEffectPresetClassToString);
                    mrWriter.put("presetClass", sTmp.makeStringAndClear());
                }
            }
            else if (IsXMLToken(rValue.Name, XML_MASTER_ELEMENT))
            {
                Reference<XInterface> xMaster;
                rValue.Value >>= xMaster;
                if (xMaster.is())
                {
                    const std::string aIdentifier(GetInterfaceHash(xMaster));
                    if (!aIdentifier.empty())
                        mrWriter.put("masterElement", aIdentifier);
                }
            }
            else if (IsXMLToken(rValue.Name, XML_GROUP_ID))
            {
                sal_Int32 nGroupId = 0;
                if (rValue.Value >>= nGroupId)
                    mrWriter.put("groupId", nGroupId);
            }
            else
            {
                OUString aTmp;
                if (rValue.Value >>= aTmp)
                    mrWriter.put(rValue.Name, aTmp);
            }
        }

        switch (nNodeType)
        {
            case AnimationNodeType::PAR:
            case AnimationNodeType::SEQ:
            case AnimationNodeType::ITERATE:
            {
                Reference<XTimeContainer> xContainer(xNode, UNO_QUERY_THROW);
                exportContainer(xContainer);
            }
            break;

            case AnimationNodeType::ANIMATE:
            case AnimationNodeType::SET:
            case AnimationNodeType::ANIMATEMOTION:
            case AnimationNodeType::ANIMATEPHYSICS:
            case AnimationNodeType::ANIMATECOLOR:
            case AnimationNodeType::ANIMATETRANSFORM:
            case AnimationNodeType::TRANSITIONFILTER:
            {
                Reference<XAnimate> xAnimate(xNode, UNO_QUERY_THROW);
                exportAnimate(xAnimate);
            }
            break;
            case AnimationNodeType::AUDIO:
            {
                SAL_WARN("sd""AnimationsExporter::exportNode(): Audio Node not supported.");
            }
            break;
            case AnimationNodeType::COMMAND:
            {
                SAL_WARN("sd""AnimationsExporter::exportNode(): Command Node not supported.");
            }
            break;
            default:
            {
                OSL_FAIL(
                    "sd unomodel: AnimationsExporter::exportNode(), invalid AnimationNodeType!");
            }
        }
    }
    catch (const RuntimeException&)
    {
        TOOLS_WARN_EXCEPTION("sd""unomodel: AnimationsExporter");
    }
}

void AnimationsExporter::convertTiming(OStringBuffer& sTmp, const Any& rValue)
{
    if (!rValue.hasValue())
        return;

    if (auto pSequence = o3tl::tryAccess<Sequence<Any>>(rValue))
    {
        const sal_Int32 nLength = pSequence->getLength();
        sal_Int32 nElement;
        const Any* pAny = pSequence->getConstArray();

        OStringBuffer sTmp2;

        for (nElement = 0; nElement < nLength; nElement++, pAny++)
        {
            if (!sTmp.isEmpty())
                sTmp.append(';');
            convertTiming(sTmp2, *pAny);
            sTmp.append(sTmp2);
            sTmp2.setLength(0);
        }
    }
    else if (auto x = o3tl::tryAccess<double>(rValue))
    {
        sTmp.append(*x);
        sTmp.append('s');
    }
    else if (auto pTiming = o3tl::tryAccess<Timing>(rValue))
    {
        const auto svTiming = (*pTiming == Timing_MEDIA)
                                  ? constTimingToString.at(Timing_MEDIA)
                                  : constTimingToString.at(Timing_INDEFINITE);
        sTmp.append(svTiming);
    }
    else if (auto pEvent = o3tl::tryAccess<Event>(rValue))
    {
        OStringBuffer sTmp2;

        if (pEvent->Trigger != EventTrigger::NONE)
        {
            if (pEvent->Source.hasValue())
            {
                OStringBuffer aTriggerBuffer;
                // hash must not start with a digit or on client it is parsed as a time in seconds
                aTriggerBuffer.append("id");
                anim::convertTarget(aTriggerBuffer, pEvent->Source);
                OString sTriggerHash(aTriggerBuffer.makeStringAndClear());
                sTmp.append(sTriggerHash);
                sTmp.append('.');
                appendTrigger(pEvent->Source, sTriggerHash);
            }

            convertEnum(sTmp2, pEvent->Trigger, constEventTriggerToString);

            sTmp.append(sTmp2);
            sTmp2.setLength(0);
        }

        if (pEvent->Offset.hasValue())
        {
            convertTiming(sTmp2, pEvent->Offset);

            if (!sTmp.isEmpty())
                sTmp.append('+');

            sTmp.append(sTmp2);
            sTmp2.setLength(0);
        }
    }
    else
    {
        OSL_FAIL("sd.unomodel: AnimationsExporter::convertTiming, invalid value type!");
    }
}

void AnimationsExporter::appendTrigger(const css::uno::Any& rTarget, const OString& rTriggerHash)
{
    css::uno::Reference<css::uno::XInterface> xRef;
    rTarget >>= xRef;

    uno::Reference<drawing::XShape> xShape(xRef, uno::UNO_QUERY);
    if (!xShape.is())
    {
        if (auto xParagraphTarget = o3tl::tryAccess<css::presentation::ParagraphTarget>(rTarget))
        {
            xShape = xParagraphTarget->Shape;
        }
    }
    if (xShape.is())
    {
        auto* pObject = SdrObject::getSdrObjectFromXShape(xShape);
        maEventTriggerSet[pObject] = rTriggerHash;
    }
}

void AnimationsExporter::exportTriggersImpl(const uno::Reference<drawing::XShapes>&&nbsp;xShapes) const
{
    if (!xShapes.is())
        return;

    sal_Int32 nCount = xShapes->getCount();
    for (sal_Int32 i = 0; i < nCount; ++i)
    {
        auto xObject = xShapes->getByIndex(i);
        uno::Reference<drawing::XShape> xShape(xObject, uno::UNO_QUERY);
        if (!xShape.is())
            continue;

        auto* pObject = SdrObject::getSdrObjectFromXShape(xShape);
        if (maEventTriggerSet.find(pObject) == maEventTriggerSet.end())
            continue;
        {
            auto aShape = mrWriter.startStruct();
            mrWriter.put("hash", maEventTriggerSet.at(pObject));
            {
                auto const& rRectangle = pObject->GetLogicRect();
                auto aRectangle
                    = o3tl::convert(rRectangle, o3tl::Length::mm100, o3tl::Length::twip);
                auto aRect = mrWriter.startNode("bounds");
                mrWriter.put("x", aRectangle.Left());
                mrWriter.put("y", aRectangle.Top());
                mrWriter.put("width", aRectangle.GetWidth());
                mrWriter.put("height", aRectangle.GetHeight());
            }
        }
    }
}

void AnimationsExporter::exportTriggers() const
{
    uno::Reference<drawing::XShapes> const xShapes(mxDrawPage, uno::UNO_QUERY_THROW);
    if (!xShapes.is())
        return;

    auto aTriggerList = mrWriter.startArray("triggers");
    exportTriggersImpl(xShapes);
}

void AnimationsExporter::convertValue(XMLTokenEnum eAttributeName, OStringBuffer&&nbsp;sTmp,
                                      const Any& rValue) const
{
    if (!rValue.hasValue())
        return;

    if (auto pValuePair = o3tl::tryAccess<ValuePair>(rValue))
    {
        OStringBuffer sTmp2;
        convertValue(eAttributeName, sTmp, pValuePair->First);
        sTmp.append(',');
        convertValue(eAttributeName, sTmp2, pValuePair->Second);
        sTmp.append(sTmp2);
    }
    else if (auto pSequence = o3tl::tryAccess<Sequence<Any>>(rValue))
    {
        const sal_Int32 nLength = pSequence->getLength();
        sal_Int32 nElement;
        const Any* pAny = pSequence->getConstArray();

        OStringBuffer sTmp2;

        for (nElement = 0; nElement < nLength; nElement++, pAny++)
        {
            if (!sTmp.isEmpty())
                sTmp.append(';');
            convertValue(eAttributeName, sTmp2, *pAny);
            sTmp.append(sTmp2);
            sTmp2.setLength(0);
        }
    }
    else
    {
        switch (eAttributeName)
        {
            case XML_X:
            case XML_Y:
            case XML_WIDTH:
            case XML_HEIGHT:
            case XML_ANIMATETRANSFORM:
            case XML_ANIMATEMOTION:
            case XML_ANIMATEPHYSICS:
            {
                if (auto sValue = o3tl::tryAccess<OUString>(rValue))
                {
                    sTmp.append(sValue->toUtf8());
                }
                else if (auto aValue = o3tl::tryAccess<double>(rValue))
                {
                    sTmp.append(*aValue);
                }
                else
                {
                    OSL_FAIL("sd::AnimationsExporter::convertValue(), invalid value type!");
                }
                return;
            }
            case XML_SKEWX:
            case XML_ROTATE:
            case XML_OPACITY:
            case XML_TRANSITIONFILTER:
                if (auto aValue = o3tl::tryAccess<double>(rValue))
                {
                    sTmp.append(*aValue);
                }
                break;
            case XML_TEXT_ROTATION_ANGLE:
                if (auto aValue = o3tl::tryAccess<sal_Int16>(rValue))
                {
                    // on win and armv7 platforms compiler complains
                    // that append(sal_Int16) is ambiguous
                    sTmp.append(static_cast<sal_Int32>(*aValue));
                }
                break;
            case XML_FILL_COLOR:
            case XML_STROKE_COLOR:
            case XML_DIM:
            case XML_COLOR:
            {
                convertColor(sTmp, rValue);
            }
            break;
            case XML_FILL:
                if (auto aValue = o3tl::tryAccess<drawing::FillStyle>(rValue))
                {
                    convertEnum(sTmp, *aValue, constFillStyleToString);
                }
                break;
            case XML_STROKE:
                if (auto aValue = o3tl::tryAccess<drawing::LineStyle>(rValue))
                {
                    convertEnum(sTmp, *aValue, constLineStyleToString);
                }
                break;
            case XML_FONTSIZE:
                if (auto aValue = o3tl::tryAccess<double>(rValue))
                {
                    double fValue = *aValue * 100;
                    fValue += fValue > 0 ? 0.5 : -0.5;
                    auto nValue = static_cast<sal_Int32>(fValue);
                    sTmp.append(nValue); // percent
                }
                break;
            case XML_FONT_WEIGHT:
            case XML_FONT_STYLE:
            case XML_TEXT_UNDERLINE:
                SAL_WARN("sd""AnimationsExporter::convertValue(): value type "
                                   << GetXMLToken(eAttributeName) << " not supported");
                break;
            case XML_VISIBILITY:
                if (auto aValue = o3tl::tryAccess<bool>(rValue))
                {
                    OUString sValue = *aValue ? GetXMLToken(XML_VISIBLE) : GetXMLToken(XML_HIDDEN);
                    sTmp.append(sValue.toUtf8());
                }
                break;
            default:
                OSL_FAIL("unomodel: AnimationsExporter::convertValue(), invalid AttributeName!");
        }
    }
}

void AnimationsExporter::exportContainer(const Reference<XTimeContainer>& xContainer)
{
    try
    {
        const sal_Int32 nNodeType = xContainer->getType();

        if (nNodeType == AnimationNodeType::ITERATE)
        {
            OStringBuffer sTmp;
            Reference<XIterateContainer> xIter(xContainer, UNO_QUERY_THROW);

            Any aTemp(xIter->getTarget());
            if (aTemp.hasValue())
            {
                anim::convertTarget(sTmp, aTemp);
                mrWriter.put("targetElement", sTmp.makeStringAndClear());
            }
            sal_Int16 nTemp = xIter->getSubItem();
            if (nTemp)
            {
                convertEnum(sTmp, nTemp, constSubItemToString);
                mrWriter.put("subItem", sTmp.makeStringAndClear());
            }
            nTemp = xIter->getIterateType();
            if (nTemp)
            {
                convertEnum(sTmp, nTemp, constIterateTypeToString);
                mrWriter.put("iterateType", sTmp.makeStringAndClear());
            }
            double fTemp = xIter->getIterateInterval();
            if (fTemp != 0)
            {
                OUStringBuffer buf;
                ::sax::Converter::convertDuration(buf, fTemp / (24 * 60 * 60));
                mrWriter.put("iterateInterval", sTmp.makeStringAndClear());
            }
        }

        auto anArray = mrWriter.startArray("children");

        Reference<XEnumerationAccess> xEnumerationAccess(xContainer, UNO_QUERY_THROW);
        Reference<XEnumeration> xEnumeration(xEnumerationAccess->createEnumeration(),
                                             css::uno::UNO_SET_THROW);
        while (xEnumeration->hasMoreElements())
        {
            Reference<XAnimationNode> xChildNode(xEnumeration->nextElement(), UNO_QUERY_THROW);
            exportNode(xChildNode);
        }
    }
    catch (const RuntimeException&)
    {
        TOOLS_WARN_EXCEPTION("sd""unomodel: AnimationsExporter");
    }
}

void AnimationsExporter::exportAnimate(const Reference<XAnimate>& xAnimate)
{
    try
    {
        const sal_Int16 nNodeType = xAnimate->getType();

        OStringBuffer sTmp;
        sal_Int16 nTemp;
        bool bTemp;

        Any aTemp(xAnimate->getTarget());
        if (aTemp.hasValue())
        {
            anim::convertTarget(sTmp, aTemp);
            mrWriter.put("targetElement", sTmp.makeStringAndClear());
        }
        nTemp = xAnimate->getSubItem();
        if (nTemp)
        {
            convertEnum(sTmp, nTemp, constSubItemToString);
            mrWriter.put("subItem", sTmp.makeStringAndClear());
        }

        XMLTokenEnum eAttributeName = XML_TOKEN_INVALID;
        if (nNodeType == AnimationNodeType::TRANSITIONFILTER)
        {
            eAttributeName = XML_TRANSITIONFILTER;
        }
        else if (nNodeType == AnimationNodeType::ANIMATETRANSFORM)
        {
            eAttributeName = XML_ANIMATETRANSFORM;
        }
        else if (nNodeType == AnimationNodeType::ANIMATEMOTION)
        {
            eAttributeName = XML_ANIMATEMOTION;
        }
        else if (nNodeType == AnimationNodeType::ANIMATEPHYSICS)
        {
            eAttributeName = XML_ANIMATEPHYSICS;
        }
        else
        {
            OString sTemp(xAnimate->getAttributeName().toUtf8());
            if (!sTemp.isEmpty())
            {
                auto iterator = constAttributeNameToXMLEnum.find(sTemp);
                if (iterator != constAttributeNameToXMLEnum.end())
                {
                    eAttributeName = iterator->second;
                    mrWriter.put("attributeName", sTemp);
                }
                else
                {
                    mrWriter.put("attributeName""invalid");
                }
            }
        }

        Sequence<Any> aValues(xAnimate->getValues());
        if (aValues.hasElements())
        {
            aTemp <<= aValues;
            convertValue(eAttributeName, sTmp, aTemp);
            mrWriter.put("values", sTmp.makeStringAndClear());
        }
        else
        {
            aTemp = xAnimate->getFrom();
            if (aTemp.hasValue())
            {
                convertValue(eAttributeName, sTmp, aTemp);
                mrWriter.put("from", sTmp.makeStringAndClear());
            }

            aTemp = xAnimate->getBy();
            if (aTemp.hasValue())
            {
                convertValue(eAttributeName, sTmp, aTemp);
                mrWriter.put("by", sTmp.makeStringAndClear());
            }

            aTemp = xAnimate->getTo();
            if (aTemp.hasValue())
            {
                convertValue(eAttributeName, sTmp, aTemp);
                mrWriter.put("to", sTmp.makeStringAndClear());
            }
        }

        if (nNodeType != AnimationNodeType::SET)
        {
            const Sequence<double> aKeyTimes(xAnimate->getKeyTimes());
            if (aKeyTimes.hasElements())
            {
                for (const auto& rKeyTime : aKeyTimes)
                {
                    if (!sTmp.isEmpty())
                        sTmp.append(';');

                    sTmp.append(rKeyTime);
                }
                mrWriter.put("keyTimes", sTmp.makeStringAndClear());
            }

            OUString sTemp(xAnimate->getFormula());
            if (!sTemp.isEmpty())
            {
                mrWriter.put("formula", sTemp);
            }

            if ((nNodeType != AnimationNodeType::TRANSITIONFILTER)
                && (nNodeType != AnimationNodeType::AUDIO))
            {
                // calcMode  = "discrete | linear | paced | spline"
                nTemp = xAnimate->getCalcMode();
                if (((nNodeType == AnimationNodeType::ANIMATEMOTION)
                     && (nTemp != AnimationCalcMode::PACED))
                    || ((nNodeType != AnimationNodeType::ANIMATEMOTION)
                        && (nTemp != AnimationCalcMode::LINEAR)))
                {
                    convertEnum(sTmp, nTemp, constCalcModeToString);
                    mrWriter.put("calcMode", sTmp.makeStringAndClear());
                }

                bTemp = xAnimate->getAccumulate();
                if (bTemp)
                {
                    mrWriter.put("accumulate""sum");
                }

                nTemp = xAnimate->getAdditive();
                if (nTemp != AnimationAdditiveMode::REPLACE)
                {
                    convertEnum(sTmp, nTemp, constAdditiveModeToString);
                    mrWriter.put("additive", sTmp.makeStringAndClear());
                }
            }

            const Sequence<TimeFilterPair> aTimeFilter(xAnimate->getTimeFilter());
            if (aTimeFilter.hasElements())
            {
                for (const auto& rPair : aTimeFilter)
                {
                    if (!sTmp.isEmpty())
                        sTmp.append(';');

                    sTmp.append(OString::number(rPair.Time) + ","
                                + OString::number(rPair.Progress));
                }
                mrWriter.put("keySplines", sTmp.makeStringAndClear());
            }
        }

        switch (nNodeType)
        {
            case AnimationNodeType::ANIMATEMOTION:
            {
                Reference<XAnimateMotion> xAnimateMotion(xAnimate, UNO_QUERY_THROW);

                aTemp = xAnimateMotion->getPath();
                if (aTemp.hasValue())
                {
                    convertPath(sTmp, aTemp);
                    mrWriter.put("path", sTmp.makeStringAndClear());
                }
            }
            break;
            case AnimationNodeType::ANIMATEPHYSICS:
            {
                SAL_WARN(
                    "sd",
                    "unomodel: AnimationsExporter::exportAnimate(): AnimatePhysics not supported");
            }
            break;
            case AnimationNodeType::ANIMATECOLOR:
            {
                Reference<XAnimateColor> xAnimateColor(xAnimate, UNO_QUERY_THROW);

                nTemp = xAnimateColor->getColorInterpolation();
                mrWriter.put("colorInterpolation",
                             (nTemp == AnimationColorSpace::RGB) ? "rgb" : "hsl");

                bTemp = xAnimateColor->getDirection();
                mrWriter.put("colorInterpolationDirection",
                             bTemp ? "clockwise" : "counterClockwise");
            }
            break;
            case AnimationNodeType::ANIMATETRANSFORM:
            {
                mrWriter.put("attributeName""transform");

                Reference<XAnimateTransform> xTransform(xAnimate, UNO_QUERY_THROW);
                nTemp = xTransform->getTransformType();
                convertEnum(sTmp, nTemp, constTransformTypeToString);
                mrWriter.put("transformType", sTmp.makeStringAndClear());
            }
            break;
            case AnimationNodeType::TRANSITIONFILTER:
            {
                Reference<XTransitionFilter> xTransitionFilter(xAnimate, UNO_QUERY);

                sal_Int16 nTransition = xTransitionFilter->getTransition();
                convertEnum(sTmp, nTransition, constTransitionTypeToString);
                mrWriter.put("transitionType", sTmp.makeStringAndClear());

                sal_Int16 nSubtype = xTransitionFilter->getSubtype();
                if (nSubtype != TransitionSubType::DEFAULT)
                {
                    convertEnum(sTmp, nSubtype, constTransitionSubTypeToString);
                    mrWriter.put("transitionSubType", sTmp.makeStringAndClear());
                }

                bTemp = xTransitionFilter->getMode();
                if (!bTemp)
                    mrWriter.put("transitionMode""out");

                bTemp = xTransitionFilter->getDirection();
                if (!bTemp)
                    mrWriter.put("transitionDirection""reverse");

                if ((nTransition == TransitionType::FADE)
                    && ((nSubtype == TransitionSubType::FADETOCOLOR)
                        || (nSubtype == TransitionSubType::FADEFROMCOLOR)))
                {
                    sal_Int32 nColor = xTransitionFilter->getFadeColor();
                    convertColor(sTmp, nColor);
                    mrWriter.put("transitionFadeColor", sTmp.makeStringAndClear());
                }
            }
            break;
            default:
            {
                SAL_WARN("sd",
                         "unomodel: AnimationsExporter::exportAnimate(): not supported node type: "
                             << nNodeType);
            }
        }
    }
    catch (const Exception&)
    {
        TOOLS_WARN_EXCEPTION("sd""unomodel: AnimationsExporter");
    }
}

void GetDocStructureSlides(::tools::JsonWriter& rJsonWriter, const SdXImpressDocument* pDoc,
                           const std::map<OUString, OUString>& rArguments)
{
    auto it = rArguments.find(u"filter"_ustr);
    if (it != rArguments.end())
    {
        // If filter is present but we are filtering not to slide information
        if (!it->second.equals(u"slides"_ustr))
            return;
    }

    sal_uInt16 nPageCount = pDoc->GetDoc()->GetSdPageCount(PageKind::Standard);
    sal_uInt16 nMasterPageCount = pDoc->GetDoc()->GetMasterSdPageCount(PageKind::Standard);

    rJsonWriter.put("SlideCount", nPageCount);
    rJsonWriter.put("MasterSlideCount", nMasterPageCount);

    // write data of every master slide
    if (nMasterPageCount > 0)
    {
        auto aMasterPagesNode = rJsonWriter.startNode("MasterSlides");
        for (int nMPId = 0; nMPId < nMasterPageCount; nMPId++)
        {
            auto aMasterPageNode = rJsonWriter.startNode("MasterSlide " + std::to_string(nMPId));
            const OUString& aMName
                = pDoc->GetDoc()->GetMasterSdPage(nMPId, PageKind::Standard)->GetName();
            rJsonWriter.put("Name", aMName);
        }
    }

    // write data of every slide
    if (nPageCount > 0)
    {
        auto aPagesNode = rJsonWriter.startNode("Slides");
        for (int nPId = 0; nPId < nPageCount; nPId++)
        {
            auto aPageNode = rJsonWriter.startNode("Slide " + std::to_string(nPId));
            SdPage* pPageStandard = pDoc->GetDoc()->GetSdPage(nPId, PageKind::Standard);

            // Slide Name
            rJsonWriter.put("SlideName", pPageStandard->GetName());

            // MasterSlide Name
            const FmFormPage* pMasterPage
                = dynamic_cast<const FmFormPage*>(&pPageStandard->TRG_GetMasterPage());

            if (pMasterPage)
            {
                rJsonWriter.put("MasterSlideName", pMasterPage->GetName());
            }

            // Layout id, and name.
            AutoLayout nLayout = pPageStandard->GetAutoLayout();
            rJsonWriter.put("LayoutId"static_cast<int>(nLayout));
            rJsonWriter.put("LayoutName", SdPage::autoLayoutToString(nLayout));

            // Every Objects in the page
            int nObjCount = pPageStandard->GetObjCount();
            rJsonWriter.put("ObjectCount", nObjCount);

            if (nObjCount > 0)
            {
                auto aObjectsNode = rJsonWriter.startNode("Objects");
                for (int nOId = 0; nOId < nObjCount; nOId++)
                {
                    auto aObjectNode = rJsonWriter.startNode("Objects " + std::to_string(nOId));
                    SdrObject* pSdrObj = pPageStandard->GetObj(nOId);
                    SdrTextObj* pSdrTxtObj = DynCastSdrTextObj(pSdrObj);
                    if (pSdrTxtObj && pSdrTxtObj->HasText())
                    {
                        sal_Int32 nTextCount = pSdrTxtObj->getTextCount();
                        rJsonWriter.put("TextCount", nTextCount);
                        if (nTextCount > 0)
                        {
                            auto aTextsNode = rJsonWriter.startNode("Texts");
                            for (int nTId = 0; nTId < nTextCount; nTId++)
                            {
                                auto aTextNode
                                    = rJsonWriter.startNode("Text " + std::to_string(nTId));
                                SdrText* pSdrTxt = pSdrTxtObj->getText(nTId);
                                OutlinerParaObject* pOutlinerParaObject
                                    = pSdrTxt->GetOutlinerParaObject();

                                sal_Int32 nParaCount
                                    = pOutlinerParaObject->GetTextObject().GetParagraphCount();

                                rJsonWriter.put("ParaCount", nParaCount);
                                auto aParasNode = rJsonWriter.startArray("Paragraphs");
                                for (int nParaId = 0; nParaId < nParaCount; nParaId++)
                                {
                                    OUString aParaStr(
                                        pOutlinerParaObject->GetTextObject().GetText(nParaId));

                                    rJsonWriter.putSimpleValue(aParaStr);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

// end anonymous namespace

SdUnoForbiddenCharsTable::SdUnoForbiddenCharsTable( SdrModel* pModel )
: SvxUnoForbiddenCharsTable( pModel->GetForbiddenCharsTable() ), mpModel( pModel )
{
    StartListening( *pModel );
}

void SdUnoForbiddenCharsTable::onChange()
{
    if( mpModel )
    {
        mpModel->ReformatAllTextObjects();
    }
}

SdUnoForbiddenCharsTable::~SdUnoForbiddenCharsTable()
{
    SolarMutexGuard g;

    if( mpModel )
        EndListening( *mpModel );
}

void SdUnoForbiddenCharsTable::Notify( SfxBroadcaster&, const SfxHint& rHint ) noexcept
{
    if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
        return;
    const SdrHint* pSdrHint = static_cast<const SdrHint*>( &rHint );
    if( SdrHintKind::ModelCleared == pSdrHint->GetKind() )
    {
        mpModel = nullptr;
    }
}

const sal_uInt16 WID_MODEL_LANGUAGE           =  1;
const sal_uInt16 WID_MODEL_TABSTOP            =  2;
const sal_uInt16 WID_MODEL_VISAREA            =  3;
const sal_uInt16 WID_MODEL_MAPUNIT            =  4;
const sal_uInt16 WID_MODEL_FORBCHARS          =  5;
const sal_uInt16 WID_MODEL_CONTFOCUS          =  6;
const sal_uInt16 WID_MODEL_DSGNMODE           =  7;
const sal_uInt16 WID_MODEL_BASICLIBS          =  8;
const sal_uInt16 WID_MODEL_RUNTIMEUID         =  9;
const sal_uInt16 WID_MODEL_BUILDID            = 10;
const sal_uInt16 WID_MODEL_HASVALIDSIGNATURES = 11;
const sal_uInt16 WID_MODEL_DIALOGLIBS         = 12;
const sal_uInt16 WID_MODEL_FONTS              = 13;
const sal_uInt16 WID_MODEL_INTEROPGRABBAG     = 14;
const sal_uInt16 WID_MODEL_THEME = 15;
const sal_uInt16 WID_MODEL_ALLOWLINKUPDATE    = 16;

static const SvxItemPropertySet* ImplGetDrawModelPropertySet()
{
    // Attention: the first parameter HAS TO BE sorted!!!
    const static SfxItemPropertyMapEntry aDrawModelPropertyMap_Impl[] =
    {
        { u"BuildId"_ustr,                WID_MODEL_BUILDID,            ::cppu::UnoType<OUString>::get(),                      0, 0},
        { sUNO_Prop_CharLocale,           WID_MODEL_LANGUAGE,           ::cppu::UnoType<lang::Locale>::get(),                                  0, 0},
        { sUNO_Prop_TabStop,              WID_MODEL_TABSTOP,            ::cppu::UnoType<sal_Int32>::get(),                                     0, 0},
        { sUNO_Prop_VisibleArea,          WID_MODEL_VISAREA,            ::cppu::UnoType<awt::Rectangle>::get(),                                0, 0},
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=96 H=96 G=95

¤ Dauer der Verarbeitung: 0.21 Sekunden  ¤

*© 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.