IASS: Added SdrObject Insert/Remove suppport

Change-Id: I7f6aad0ec12de3c3b2677f1ca07e8efd5a881982
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163797
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
diff --git a/sd/source/ui/slideshow/slideshowimpl.cxx b/sd/source/ui/slideshow/slideshowimpl.cxx
index 61e8bcf..12a8cc3 100644
--- a/sd/source/ui/slideshow/slideshowimpl.cxx
+++ b/sd/source/ui/slideshow/slideshowimpl.cxx
@@ -565,6 +565,8 @@ SlideshowImpl::SlideshowImpl( const Reference< XPresentation2 >& xPresentation, 
, mnEndShowEvent(nullptr)
, mnContextMenuEvent(nullptr)
, mnEventObjectChange(nullptr)
, mnEventObjectInserted(nullptr)
, mnEventObjectRemoved(nullptr)
, mnEventPageOrderChange(nullptr)
, mxPresentation( xPresentation )
, mxListenerProxy()
@@ -658,6 +660,10 @@ void SlideshowImpl::disposing(std::unique_lock<std::mutex>&)
        Application::RemoveUserEvent( mnContextMenuEvent );
    if( mnEventObjectChange )
        Application::RemoveUserEvent( mnEventObjectChange );
    if( mnEventObjectInserted )
        Application::RemoveUserEvent( mnEventObjectInserted );
    if( mnEventObjectRemoved )
        Application::RemoveUserEvent( mnEventObjectRemoved );
    if( mnEventPageOrderChange )
        Application::RemoveUserEvent( mnEventPageOrderChange );

@@ -3305,53 +3311,104 @@ void SlideshowImpl::AsyncNotifyEvent(
    const uno::Reference< css::drawing::XDrawPage >& rXCurrentSlide,
    const SdrHintKind eHintKind)
{
    if (SdrHintKind::ObjectChange == eHintKind)
    switch (eHintKind)
    {
        mnEventObjectChange = nullptr;

        // refresh single slide
        gotoSlide(rXCurrentSlide);
    }
    else if (SdrHintKind::PageOrderChange == eHintKind)
    {
        mnEventPageOrderChange = nullptr;

        // order of pages (object pages or master pages) changed (Insert/Remove/ChangePos)
        // rXCurrentSlide is the current slide before the change.
        Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW );
        Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
        const sal_Int32 nNewSlideCount(xSlides.is() ? xSlides->getCount() : 0);

        if (nNewSlideCount != mpSlideController->getSlideNumberCount())
        case SdrHintKind::ObjectInserted:
        {
            // need to reinitialize AnimationSlideController
            OUString aPresSlide( maPresSettings.maPresPage );
            createSlideList( maPresSettings.mbAll, aPresSlide );
        }
            mnEventObjectInserted = nullptr;

        // Check if current slide before change is still valid (maybe removed)
        const sal_Int32 nSlideCount(mpSlideController->getSlideNumberCount());
        bool bSlideStillValid(false);

        for (sal_Int32 nSlide(0); !bSlideStillValid && nSlide < nSlideCount; nSlide++)
        {
            if (rXCurrentSlide == mpSlideController->getSlideByNumber(nSlide))
            {
                bSlideStillValid = true;
            }
        }

        if(bSlideStillValid)
        {
            // stay on that slide
            // refresh single slide
            gotoSlide(rXCurrentSlide);
            break;
        }
        else
        case SdrHintKind::ObjectRemoved:
        {
            // not possible to stay on that slide, go to 1st slide (kinda restart)
            gotoFirstSlide();
            mnEventObjectRemoved = nullptr;

            // refresh single slide
            gotoSlide(rXCurrentSlide);
            break;
        }
        case SdrHintKind::ObjectChange:
        {
            mnEventObjectChange = nullptr;

            // refresh single slide
            gotoSlide(rXCurrentSlide);
            break;
        }
        case SdrHintKind::PageOrderChange:
        {
            mnEventPageOrderChange = nullptr;

            // order of pages (object pages or master pages) changed (Insert/Remove/ChangePos)
            // rXCurrentSlide is the current slide before the change.
            Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW );
            Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
            const sal_Int32 nNewSlideCount(xSlides.is() ? xSlides->getCount() : 0);

            if (nNewSlideCount != mpSlideController->getSlideNumberCount())
            {
                // need to reinitialize AnimationSlideController
                OUString aPresSlide( maPresSettings.maPresPage );
                createSlideList( maPresSettings.mbAll, aPresSlide );
            }

            // Check if current slide before change is still valid (maybe removed)
            const sal_Int32 nSlideCount(mpSlideController->getSlideNumberCount());
            bool bSlideStillValid(false);

            for (sal_Int32 nSlide(0); !bSlideStillValid && nSlide < nSlideCount; nSlide++)
            {
                if (rXCurrentSlide == mpSlideController->getSlideByNumber(nSlide))
                {
                    bSlideStillValid = true;
                }
            }

            if(bSlideStillValid)
            {
                // stay on that slide
                gotoSlide(rXCurrentSlide);
            }
            else
            {
                // not possible to stay on that slide, go to 1st slide (kinda restart)
                gotoFirstSlide();
            }
            break;
        }
        default:
            break;
    }
}

bool SlideshowImpl::isCurrentSlideInvolved(const SdrHint& rHint)
{
    // get current slide
    uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide());
    if (!XCurrentSlide.is())
        return false;

    SdrPage* pCurrentSlide(GetSdrPageFromXDrawPage(XCurrentSlide));
    if (nullptr == pCurrentSlide)
        return false;

    const SdrPage* pHintPage(rHint.GetPage());
    if (nullptr == pHintPage)
        return false;

    if (pHintPage->IsMasterPage())
    {
        if (pCurrentSlide->TRG_HasMasterPage())
        {
            // current slide uses MasterPage on which the change happened
            return pHintPage == &pCurrentSlide->TRG_GetMasterPage();
        }
    }

    // object on current slide was changed
    return pHintPage == pCurrentSlide;
}

void SlideshowImpl::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
@@ -3372,75 +3429,84 @@ void SlideshowImpl::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
        // no SlideShow instance or not running, nothing to do
        return;

    const SdrHintKind eHintKind(static_cast<const SdrHint&>(rHint).GetKind());
    const SdrHint& rSdrHint(static_cast<const SdrHint&>(rHint));
    const SdrHintKind eHintKind(rSdrHint.GetKind());

    if (SdrHintKind::ObjectChange == eHintKind)
    switch (eHintKind)
    {
        if (nullptr != mnEventObjectChange)
            // avoid multiple events
            return;

        // Object changed, object & involved page included in rHint.
        uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide());
        if (!XCurrentSlide.is())
            return;

        SdrPage* pCurrentSlide(GetSdrPageFromXDrawPage(XCurrentSlide));
        if (nullptr == pCurrentSlide)
            return;

        const SdrPage* pHintPage(static_cast<const SdrHint&>(rHint).GetPage());
        if (nullptr == pHintPage)
            return;

        bool bCurrentSlideIsInvolved(false);

        if (pHintPage->IsMasterPage())
        case SdrHintKind::ObjectInserted:
        {
            if (pCurrentSlide->TRG_HasMasterPage())
            {
                // current slide uses MasterPage on which the change happened
                bCurrentSlideIsInvolved = (pHintPage == &pCurrentSlide->TRG_GetMasterPage());
            }
            if (nullptr != mnEventObjectChange)
                // avoid multiple events
                return;

            if (!isCurrentSlideInvolved(rSdrHint))
                // nothing to do when current slide is not involved
                return;

            // Refresh current slide
            uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide());
            mnEventObjectInserted = AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide, eHintKind);
            break;
        }
        else
        case SdrHintKind::ObjectRemoved:
        {
            // object on current slide was changed
            bCurrentSlideIsInvolved = (pHintPage == pCurrentSlide);
            if (nullptr != mnEventObjectRemoved)
                // avoid multiple events
                return;

            if (!isCurrentSlideInvolved(rSdrHint))
                // nothing to do when current slide is not involved
                return;

            // Refresh current slide
            uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide());
            mnEventObjectRemoved = AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide, eHintKind);
            break;
        }
        case SdrHintKind::ObjectChange:
        {
            if (nullptr != mnEventObjectChange)
                // avoid multiple events
                return;

        if (!bCurrentSlideIsInvolved)
            // nothing to do when current slide is not involved
            return;
            if (!isCurrentSlideInvolved(rSdrHint))
                // nothing to do when current slide is not involved
                return;

        // Refresh current slide. Need to do that asynchronous, else e.g.
        // text edit changes EditEngine/Outliner are not progressed far
        // enough (ObjectChanged broadcast which we are in here seems
        // to early for some cases)
        mnEventObjectChange = AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide, eHintKind);
            // Refresh current slide. Need to do that asynchronous, else e.g.
            // text edit changes EditEngine/Outliner are not progressed far
            // enough (ObjectChanged broadcast which we are in here seems
            // to early for some cases)
            uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide());
            mnEventObjectChange = AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide, eHintKind);
            break;
        }
        case SdrHintKind::PageOrderChange:
        {
            // Unfortunately we get multiple events, e.g. when drag/drop position change in
            // slide sorter on left side of EditView. This includes some with page number +1,
            // then again -1 (it's a position change). Problem is that in-between already
            // a re-schedule seems to happen, so indeed AsyncNotifyEvent will change to +1/-1
            // already. Since we get even more, at least try to take the last one. I found no
            // good solution yet for this.
            if (nullptr != mnEventPageOrderChange)
                Application::RemoveUserEvent( mnEventPageOrderChange );

            // order of pages (object pages or master pages) changed (Insert/Remove/ChangePos)
            uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide());
            mnEventPageOrderChange = AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide, eHintKind);
            break;
        }
        case SdrHintKind::ModelCleared:
        {
            // immediately end presentation
            endPresentation();
            break;
        }
        default:
            break;
    }
    else if (SdrHintKind::PageOrderChange == eHintKind)
    {
        // Unfortunately we get multiple events, e.g. when drag/drop position change in
        // slide sorter on left side of EditView. This includes some with page number +1,
        // then again -1 (it's a position change). Problem is that in-between already
        // a re-schedule seems to happen, so indeed AsyncNotifyEvent will change to +1/-1
        // already. Since we get even more, at least try to take the last one. I found no
        // good solution yet for this.
        if (nullptr != mnEventPageOrderChange)
            Application::RemoveUserEvent( mnEventPageOrderChange );

        // order of pages (object pages or master pages) changed (Insert/Remove/ChangePos)
        uno::Reference< css::drawing::XDrawPage > XCurrentSlide(getCurrentSlide());
        mnEventPageOrderChange = AsyncUpdateSlideshow_Impl::AsyncUpdateSlideshow(this, XCurrentSlide, eHintKind);
    }
    else if (SdrHintKind::ModelCleared == eHintKind)
    {
        // immediately end presentation
        endPresentation();
    }

    // maybe need to add reactions here to other Hint-Types
}

Reference< XSlideShow > SAL_CALL SlideshowImpl::getSlideShow()
diff --git a/sd/source/ui/slideshow/slideshowimpl.hxx b/sd/source/ui/slideshow/slideshowimpl.hxx
index 80e44cb..7d0d759 100644
--- a/sd/source/ui/slideshow/slideshowimpl.hxx
+++ b/sd/source/ui/slideshow/slideshowimpl.hxx
@@ -214,6 +214,9 @@ private:

    virtual ~SlideshowImpl() override;

    // helper to check if given hint is associated with CurrentSlide
    bool isCurrentSlideInvolved(const SdrHint& rHint);

    // override WeakComponentImplHelperBase::disposing()
    // This function is called upon disposing the component,
    // if your component needs special work when it becomes
@@ -353,6 +356,8 @@ private:
    ImplSVEvent * mnEndShowEvent;
    ImplSVEvent * mnContextMenuEvent;
    ImplSVEvent * mnEventObjectChange;
    ImplSVEvent * mnEventObjectInserted;
    ImplSVEvent * mnEventObjectRemoved;
    ImplSVEvent * mnEventPageOrderChange;

    css::uno::Reference< css::presentation::XPresentation2 > mxPresentation;