Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  viewsh.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 <vcl/themecolors.hxx>
#include <officecfg/Office/Common.hxx>
#include <config_wasm_strip.h>

#include <com/sun/star/accessibility/XAccessible.hpp>
#include <sfx2/viewfrm.hxx>
#include <sfx2/progress.hxx>
#include <svx/srchdlg.hxx>
#include <sfx2/viewsh.hxx>
#include <sfx2/ipclient.hxx>
#include <sal/log.hxx>
#include <drawdoc.hxx>
#include <swwait.hxx>
#include <crsrsh.hxx>
#include <doc.hxx>
#include <IDocumentDeviceAccess.hxx>
#include <IDocumentDrawModelAccess.hxx>
#include <IDocumentOutlineNodes.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <IDocumentState.hxx>
#include <rootfrm.hxx>
#include <pagefrm.hxx>
#include <viewimp.hxx>
#include <frmtool.hxx>
#include <viewopt.hxx>
#include <dview.hxx>
#include <swregion.hxx>
#include <hints.hxx>
#include <docufld.hxx>
#include <txtfrm.hxx>
#include <layact.hxx>
#include <mdiexp.hxx>
#include <fntcache.hxx>
#include <ptqueue.hxx>
#include <docsh.hxx>
#include <bookmark.hxx>
#include <ndole.hxx>
#include <ndindex.hxx>
#include <accmap.hxx>
#include <vcl/bitmapex.hxx>
#include <accessibilityoptions.hxx>
#include <strings.hrc>
#include <bitmaps.hlst>
#include <pagepreviewlayout.hxx>
#include <sortedobjs.hxx>
#include <anchoredobject.hxx>
#include <DocumentSettingManager.hxx>
#include <DocumentRedlineManager.hxx>
#include <DocumentLayoutManager.hxx>

#include <unotxdoc.hxx>
#include <view.hxx>
#include <PostItMgr.hxx>
#include <unotools/configmgr.hxx>
#include <vcl/virdev.hxx>
#include <vcl/svapp.hxx>
#include <svx/sdrpaintwindow.hxx>
#include <svx/sdrpagewindow.hxx>
#include <svx/svdpagv.hxx>
#include <comphelper/lok.hxx>
#include <sfx2/lokhelper.hxx>
#include <tools/UnitConversion.hxx>

#if !HAVE_FEATURE_DESKTOP
#include <vcl/sysdata.hxx>
#endif

#include <frameformats.hxx>
#include <fmtcntnt.hxx>

bool SwViewShell::sbLstAct = false;
ShellResource *SwViewShell::spShellRes = nullptr;

static tools::DeleteOnDeinit<std::shared_ptr<weld::Window>>& getCareDialog()
{
    static tools::DeleteOnDeinit<std::shared_ptr<weld::Window>> spCareDialog {}; ///< Avoid this window.
    return spCareDialog;
}

static bool bInSizeNotify = false;


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

void SwViewShell::SetShowHeaderFooterSeparator( FrameControlType eControl, bool bShow ) {

    //tdf#118621 - Optionally disable floating header/footer menu
    if ( bShow )
        bShow = GetViewOptions()->IsUseHeaderFooterMenu();

    if ( eControl == FrameControlType::Header )
        mbShowHeaderSeparator = bShow;
    else
        mbShowFooterSeparator = bShow;
}

void SwViewShell::ToggleHeaderFooterEdit()
{
    mbHeaderFooterEdit = !mbHeaderFooterEdit;
    if ( !mbHeaderFooterEdit )
    {
        SetShowHeaderFooterSeparator( FrameControlType::Header, false );
        SetShowHeaderFooterSeparator( FrameControlType::Footer, false );
    }

    // Avoid corner case
    if ( ( GetViewOptions()->IsUseHeaderFooterMenu() ) &&
         ( !IsShowHeaderFooterSeparator( FrameControlType::Header ) &&
           !IsShowHeaderFooterSeparator( FrameControlType::Footer ) ) )
    {
        mbHeaderFooterEdit = false;
    }

    InvalidatePageAndHFSubsidiaryLines();
}

// Invalidate Subsidiary Lines around headers/footers and page frames to repaint
void SwViewShell::InvalidatePageAndHFSubsidiaryLines()
{
    RectangleVector aInvalidRects;
    SwPageFrame *pPg = static_cast<SwPageFrame*>(GetLayout()->Lower());
    while (pPg)
    {
        pPg->AddSubsidiaryLinesBounds(*this, aInvalidRects);
        pPg = static_cast<SwPageFrame*>(pPg->GetNext());
    }

    for (const auto &rRect : aInvalidRects)
        GetWin()->Invalidate(rRect);
}

void SwViewShell::setOutputToWindow(bool bOutputToWindow)
{
    mbOutputToWindow = bOutputToWindow;
}

bool SwViewShell::isOutputToWindow() const
{
    return mbOutputToWindow;
}

void SwViewShell::dumpAsXml(xmlTextWriterPtr pWriter) const
{
    (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwViewShell"));
    if (mpOpt)
    {
        mpOpt->dumpAsXml(pWriter);
    }
    (void)xmlTextWriterEndElement(pWriter);
}

static void
lcl_PaintTransparentFormControls(SwViewShell const & rShell, SwRect const& rRect)
{
    // Direct paint has been performed: the background of transparent child
    // windows has been painted, so need to paint the child windows now.
    if (rShell.GetWin())
    {
        vcl::Window& rWindow = *(rShell.GetWin());
        const tools::Rectangle aRectanglePixel(rShell.GetOut()->LogicToPixel(rRect.SVRect()));
        PaintTransparentChildren(rWindow, aRectanglePixel);
    }
}

// #i72754# 2nd set of Pre/PostPaints
// This time it uses the lock counter (mPrePostPaintRegions empty/non-empty) to allow only one activation
// and deactivation and mpPrePostOutDev to remember the OutDev from the BeginDrawLayers
// call. That way, all places where paint take place can be handled the same way, even
// when calling other paint methods. This is the case at the places where SW paints
// buffered into VDevs to avoid flicker. It is in general problematic and should be
// solved once using the BufferedOutput functionality of the DrawView.

void SwViewShell::PrePaint()
{
    // forward PrePaint event from VCL Window to DrawingLayer
    if(HasDrawView())
    {
        Imp()->GetDrawView()->PrePaint();
    }
}

void SwViewShell::DLPrePaint2(const vcl::Region& rRegion)
{
    if(mPrePostPaintRegions.empty())
    {
        mPrePostPaintRegions.push( rRegion );
        // #i75172# ensure DrawView to use DrawingLayer bufferings
        if ( !HasDrawView() )
            MakeDrawView();

        // Prefer window; if not available, get mpOut (e.g. printer)
        const bool bWindow = GetWin() && !comphelper::LibreOfficeKit::isActive() && !isOutputToWindow();
        mpPrePostOutDev = bWindow ? GetWin()->GetOutDev() : GetOut();

        // #i74769# use SdrPaintWindow now direct
        mpTargetPaintWindow = Imp()->GetDrawView()->BeginDrawLayers(mpPrePostOutDev, rRegion);
        assert(mpTargetPaintWindow && "BeginDrawLayers: Got no SdrPaintWindow (!)");

        // #i74769# if prerender, save OutDev and redirect to PreRenderDevice
        if(mpTargetPaintWindow->GetPreRenderDevice())
        {
            mpBufferedOut = mpOut;
            mpOut = &(mpTargetPaintWindow->GetTargetOutputDevice());
        }
        else if (isOutputToWindow())
            // In case mpOut is used without buffering and we're not printing, need to set clipping.
            mpOut->SetClipRegion(rRegion);

        // remember original paint MapMode for wrapped FlyFrame paints
        maPrePostMapMode = mpOut->GetMapMode();
    }
    else
    {
        // region needs to be updated to the given one
        if( mPrePostPaintRegions.top() != rRegion )
            Imp()->GetDrawView()->UpdateDrawLayersRegion(mpPrePostOutDev, rRegion);
        mPrePostPaintRegions.push( rRegion );
    }
}

void SwViewShell::DLPostPaint2(bool bPaintFormLayer)
{
    OSL_ENSURE(!mPrePostPaintRegions.empty(), "SwViewShell::DLPostPaint2: Pre/PostPaint encapsulation broken (!)");

    if( mPrePostPaintRegions.size() > 1 )
    {
        vcl::Region current = std::move(mPrePostPaintRegions.top());
        mPrePostPaintRegions.pop();
        if( current != mPrePostPaintRegions.top())
            Imp()->GetDrawView()->UpdateDrawLayersRegion(mpPrePostOutDev, mPrePostPaintRegions.top());
        return;
    }
    mPrePostPaintRegions.pop(); // clear
    if(nullptr != mpTargetPaintWindow)
    {
        // #i74769# restore buffered OutDev
        if(mpTargetPaintWindow->GetPreRenderDevice())
        {
            mpOut = mpBufferedOut;
        }

        // #i74769# use SdrPaintWindow now direct
        SwViewObjectContactRedirector aSwRedirector(*this);
        Imp()->GetDrawView()->EndDrawLayers(*mpTargetPaintWindow, bPaintFormLayer, &aSwRedirector);
        mpTargetPaintWindow = nullptr;
    }
}
// end of Pre/PostPaints

void SwViewShell::StartAllAction()
{
    for (SwViewShell & rCurrentShell : GetRingContainer())
    {
        rCurrentShell.StartAction();
    }
}

void SwViewShell::EndAllAction()
{
    for (SwViewShell & rCurrentShell : GetRingContainer())
    {
        rCurrentShell.EndAction();
    }
}

void SwViewShell::StartAction()
{
    if (!mnStartAction++)
        ImplStartAction();
}

void SwViewShell::EndAction(const bool bIdleEnd)
{
    if (0 == (mnStartAction - 1))
        ImplEndAction(bIdleEnd);
    --mnStartAction;
}

void SwViewShell::ImplEndAction( const bool bIdleEnd )
{
    // Nothing to do for the printer?
    if ( !GetWin() || IsPreview() )
    {
        mbPaintWorks = true;
        UISizeNotify();
        // tdf#101464 print preview may generate events if another view shell
        // performs layout...
#if !ENABLE_WASM_STRIP_ACCESSIBILITY
        if (IsPreview() && Imp()->IsAccessible())
        {
            Imp()->FireAccessibleEvents();
        }
#endif
        return;
    }

    mbInEndAction = true;
    //will this put the EndAction of the last shell in the sequence?

    SwViewShell::sbLstAct = true;
    for(SwViewShell& rShell : GetRingContainer())
    {
        if(&rShell != this && rShell.ActionPend())
        {
            SwViewShell::sbLstAct = false;
            break;
        }
    }

    const bool bIsShellForCheckViewLayout = ( this == GetLayout()->GetCurrShell() );

    CurrShell aCurr( this );
    if ( Imp()->HasDrawView() && !Imp()->GetDrawView()->areMarkHandlesHidden() )
        Imp()->StartAction();

    if ( Imp()->HasPaintRegion() && Imp()->GetPaintRegion()->GetOrigin() != VisArea() )
        Imp()->DeletePaintRegion();

    const bool bExtraData = ::IsExtraData( *GetDoc() );

    if ( !bIdleEnd )
    {
        SwLayAction aAction( GetLayout(), Imp() );
        aAction.SetComplete( false );
        if ( mnLockPaint )
            aAction.SetPaint( false );
        aAction.SetInputType( VclInputFlags::KEYBOARD );
        aAction.Action(GetWin()->GetOutDev());
    }

    if ( bIsShellForCheckViewLayout )
        GetLayout()->CheckViewLayout( GetViewOptions(), &maVisArea );

    //If we don't call Paints, we wait for the Paint of the system.
    //Then the clipping is set correctly; e.g. shifting of a Draw object
    if ( Imp()->HasPaintRegion()     ||
         maInvalidRect.HasArea() ||
         bExtraData )
    {
        if ( !mnLockPaint )
        {
            SolarMutexGuard aGuard;

            bool bPaintsFromSystem = maInvalidRect.HasArea();
            GetWin()->PaintImmediately();
            if ( maInvalidRect.HasArea() )
            {
                if ( bPaintsFromSystem )
                    Imp()->AddPaintRect( maInvalidRect );

                ResetInvalidRect();
                bPaintsFromSystem = true;
            }
            mbPaintWorks = true;

            std::optional<SwRegionRects> oRegion = Imp()->TakePaintRegion();

            //JP 27.11.97: what hid the selection, must also Show it,
            //             else we get Paint errors!
            // e.g. additional mode, page half visible vertically, in the
            // middle a selection and with another cursor jump to left
            // right border. Without ShowCursor the selection disappears.
            bool bShowCursor = oRegion && dynamic_cast<const SwCursorShell*>(this) !=  nullptr;
            if( bShowCursor )
                static_cast<SwCursorShell*>(this)->HideCursors();

            if ( oRegion )
            {
                SwRootFrame* pCurrentLayout = GetLayout();

                oRegion->LimitToOrigin();
                oRegion->Compress( SwRegionRects::CompressFuzzy );

                while ( !oRegion->empty() )
                {
                    SwRect aRect( oRegion->back() );
                    oRegion->pop_back();

                    if (GetWin()->SupportsDoubleBuffering())
                        InvalidateWindows(aRect);
                    else
                    {
                        // #i75172# begin DrawingLayer paint
                        // need to do begin/end DrawingLayer preparation for each single rectangle of the
                        // repaint region. I already tried to prepare only once for the whole Region. This
                        // seems to work (and does technically) but fails with transparent objects. Since the
                        // region given to BeginDrawLayers() defines the clip region for DrawingLayer paint,
                        // transparent objects in the single rectangles will indeed be painted multiple times.
                        if (!comphelper::LibreOfficeKit::isActive())
                        {
                            DLPrePaint2(vcl::Region(aRect.SVRect()));
                        }

                        if ( bPaintsFromSystem )
                            PaintDesktop(*GetOut(), aRect);
                        if (!comphelper::LibreOfficeKit::isActive())
                            pCurrentLayout->PaintSwFrame( *mpOut, aRect );
                        else
                            pCurrentLayout->GetCurrShell()->InvalidateWindows(aRect);

                        // #i75172# end DrawingLayer paint
                        if (!comphelper::LibreOfficeKit::isActive())
                        {
                            DLPostPaint2(true);
                        }
                    }

                    lcl_PaintTransparentFormControls(*this, aRect); // i#107365
                }
            }
            if( bShowCursor )
                static_cast<SwCursorShell*>(this)->ShowCursors( true );
        }
        else
        {
            Imp()->DeletePaintRegion();
            mbPaintWorks =  true;
        }
    }
    else
        mbPaintWorks = true;

    mbInEndAction = false;
    SwViewShell::sbLstAct = false;
    Imp()->EndAction();

    //We artificially end the action here to enable the automatic scrollbars
    //to adjust themselves correctly
    //EndAction sends a Notify, and that must call Start-/EndAction to
    //adjust the scrollbars correctly
    --mnStartAction;
    UISizeNotify();
    ++mnStartAction;

#if !ENABLE_WASM_STRIP_ACCESSIBILITY
    if( Imp()->IsAccessible() )
        Imp()->FireAccessibleEvents();
#endif
}

void SwViewShell::ImplStartAction()
{
    mbPaintWorks = false;
    Imp()->StartAction();
}

void SwViewShell::ImplLockPaint()
{
    if ( GetWin() && GetWin()->IsVisible() && !comphelper::LibreOfficeKit::isActive())
        GetWin()->EnablePaint( false ); //Also cut off the controls.
    Imp()->LockPaint();
}

void SwViewShell::ImplUnlockPaint(std::vector<LockPaintReason>& rReasons, bool bVirDev)
{
    CurrShell aCurr( this );
    if ( GetWin() && GetWin()->IsVisible() )
    {
        if ( (bInSizeNotify || bVirDev ) && VisArea().HasArea() && !comphelper::LibreOfficeKit::isActive())
        {
            //Refresh with virtual device to avoid flickering.
            VclPtrInstance<VirtualDevice> pVout( *mpOut );
            pVout->SetMapMode( mpOut->GetMapMode() );
            Size aSize( VisArea().SSize() );
            aSize.AdjustWidth(20 );
            aSize.AdjustHeight(20 );
            if( pVout->SetOutputSize( aSize ) )
            {
                GetWin()->EnablePaint( true );
                GetWin()->Validate();

                Imp()->UnlockPaint();
                if (mpOut->IsLineColor())
                    pVout->SetLineColor( mpOut->GetLineColor() );
                else
                    pVout->SetLineColor();
                if (mpOut->IsFillColor())
                    pVout->SetFillColor( mpOut->GetFillColor() );
                else
                    pVout->SetFillColor();

                // #i72754# start Pre/PostPaint encapsulation before mpOut is changed to the buffering VDev
                const vcl::Region aRepaintRegion(VisArea().SVRect());
                DLPrePaint2(aRepaintRegion);

                OutputDevice *pOld = mpOut;
                mpOut = pVout.get();
                Paint(*mpOut, VisArea().SVRect());
                mpOut = pOld;
                mpOut->DrawOutDev( VisArea().Pos(), aSize,
                                  VisArea().Pos(), aSize, *pVout );

                // #i72754# end Pre/PostPaint encapsulation when mpOut is back and content is painted
                DLPostPaint2(true);

                lcl_PaintTransparentFormControls(*this, VisArea()); // fdo#63949
            }
            else
            {
                Imp()->UnlockPaint();
                GetWin()->EnablePaint( true );
                InvalidateAll(rReasons);
            }
            pVout.disposeAndClear();
        }
        else
        {
            Imp()->UnlockPaint();
            GetWin()->EnablePaint( true );
            InvalidateAll(rReasons);
        }
    }
    else
        Imp()->UnlockPaint();
}

namespace
{
    std::string_view to_string(LockPaintReason eReason)
    {
        switch(eReason)
        {
            case LockPaintReason::ViewLayout:
                return "ViewLayout";
            case LockPaintReason::OuterResize:
                return "OuterResize";
            case LockPaintReason::Undo:
                return "Undo";
            case LockPaintReason::Redo:
                return "Redo";
            case LockPaintReason::OutlineFolding:
                return "OutlineFolding";
            case LockPaintReason::EndSdrCreate:
                return "EndSdrCreate";
            case LockPaintReason::SwLayIdle:
                return "SwLayIdle";
            case LockPaintReason::InvalidateLayout:
                return "InvalidateLayout";
            case LockPaintReason::StartDrag:
                return "StartDrag";
            case LockPaintReason::DataChanged:
                return "DataChanged";
            case LockPaintReason::InsertFrame:
                return "InsertFrame";
            case LockPaintReason::GotoPage:
                return "GotoPage";
            case LockPaintReason::InsertGraphic:
                return "InsertGraphic";
            case LockPaintReason::SetZoom:
                return "SetZoom";
            case LockPaintReason::ExampleFrame:
                return "ExampleFram";
        }
        return "";
    };
}

void SwViewShell::InvalidateAll(std::vector<LockPaintReason>& rReasons)
{
    assert(!rReasons.empty() && "there must be a reason to InvalidateAll");

    for (const auto& reason : rReasons)
        SAL_INFO("sw.core""InvalidateAll because of: " << to_string(reason));

    if (comphelper::LibreOfficeKit::isActive())
    {
        // https://github.com/CollaboraOnline/online/issues/6379
        // ditch OuterResize as a reason to invalidate all in the online case
        std::erase(rReasons, LockPaintReason::OuterResize);
    }

    if (!rReasons.empty())
        GetWin()->Invalidate(InvalidateFlags::Children);
    rReasons.clear();
}

bool SwViewShell::AddPaintRect( const SwRect & rRect )
{
    bool bRet = false;
    for(SwViewShell& rSh : GetRingContainer())
    {
        if( rSh.Imp() )
        {
            if ( rSh.IsPreview() && rSh.GetWin() )
                ::RepaintPagePreview( &rSh, rRect );
            else
                bRet |= rSh.Imp()->AddPaintRect( rRect );
        }
    }
    return bRet;
}

void SwViewShell::InvalidateWindows( const SwRect &rRect )
{
    if ( Imp()->IsCalcLayoutProgress() )
        return;

    if(comphelper::LibreOfficeKit::isActive())
    {
        // If we are inside tiled painting, invalidations are ignored.
        // Ignore them right now to save work, but also to avoid the problem
        // that this state could be reset before FlushPendingLOKInvalidateTiles()
        // gets called.
        if(comphelper::LibreOfficeKit::isTiledPainting())
            return;
        // First collect all invalidations and perform them only later,
        // otherwise the number of Invalidate() calls would be at least
        // O(n^2) if not worse. The problem is that if any change in a document
        // is made, SwEditShell::EndAllAction() is called, which calls EndAction()
        // for every view. And every view does it own handling of paint rectangles,
        // and then calls InvalidateWindows() based on that. On then this code
        // would call Invalidate() for all views for each rectangle.
        // So collect the rectangles, avoid duplicates (which there usually will
        // be many because of the repetitions), FlushPendingLOKInvalidateTiles()
        // will collect all rectangles from all related views, compress them
        // and only with those relatively few rectangle it'd call Invalidate()
        // for all views.
        Imp()->AddPendingLOKInvalidation(rRect);
        return;
    }

    for(SwViewShell& rSh : GetRingContainer())
    {
        if ( rSh.GetWin() )
        {
            if ( rSh.IsPreview() )
                ::RepaintPagePreview( &rSh, rRect );
            // In case of tiled rendering, invalidation is wanted even if
            // the rectangle is outside the visual area.
            else if ( rSh.VisArea().Overlaps( rRect ) || comphelper::LibreOfficeKit::isActive() )
                rSh.GetWin()->Invalidate( rRect.SVRect() );
        }
    }
}

void SwViewShell::FlushPendingLOKInvalidateTiles()
{
    assert(comphelper::LibreOfficeKit::isActive());
    SwRegionRects rects;
    for(SwViewShell& rSh : GetRingContainer())
    {
        std::vector<SwRect> tmpRects = rSh.Imp()->TakePendingLOKInvalidations();
        rects.insert( rects.end(), tmpRects.begin(), tmpRects.end());
    }
    rects.Compress( SwRegionRects::CompressFuzzy );
    if(rects.empty())
        return;
    // This is basically the loop from SwViewShell::InvalidateWindows().
    for(SwViewShell& rSh : GetRingContainer())
    {
        if ( rSh.GetWin() )
        {
            if ( rSh.IsPreview() )
            {
                forconst SwRect& rect : rects )
                    ::RepaintPagePreview( &rSh, rect );
            }
            else
            {
                forconst SwRect& rect : rects )
                    rSh.GetWin()->Invalidate( rect.SVRect() );
            }
        }
    }
}

const SwRect& SwViewShell::VisArea() const
{
    // when using the tiled rendering, consider the entire document as our
    // visible area
    return comphelper::LibreOfficeKit::isActive()? GetLayout()->getFrameArea(): maVisArea;
}

void SwViewShell::MakeVisible( const SwRect &rRect, ScrollSizeMode eScrollSizeMode )
{
    if ( !(!VisArea().Contains( rRect ) || IsScrollMDI( *this, rRect ) || GetCareDialog(*this)) )
        return;

    if ( IsViewLocked() )
        return;

    if( mpWin )
    {
        const SwFrame* pRoot = GetLayout();
        int nLoopCnt = 3;
        tools::Long nOldH;
        do{
            nOldH = pRoot->getFrameArea().Height();
            SwViewShell::StartAction();
            ScrollMDI( *this, rRect, USHRT_MAX, USHRT_MAX, eScrollSizeMode );
            SwViewShell::EndAction(); // DO NOT call virtual here!
        } while( nOldH != pRoot->getFrameArea().Height() && nLoopCnt-- );
    }
#if OSL_DEBUG_LEVEL > 0
    else
    {
        //MA: 04. Nov. 94, no one needs this, does one?
        OSL_ENSURE( false"Is MakeVisible still needed for printers?" );
    }

#endif
}

weld::Window* SwViewShell::CareChildWin(SwViewShell const & rVSh)
{
    if (!rVSh.mpSfxViewShell)
        return nullptr;
#if HAVE_FEATURE_DESKTOP
    const sal_uInt16 nId = SvxSearchDialogWrapper::GetChildWindowId();
    SfxViewFrame& rVFrame = rVSh.mpSfxViewShell->GetViewFrame();
    SfxChildWindow* pChWin = rVFrame.GetChildWindow( nId );
    if (!pChWin)
        return nullptr;
    weld::DialogController* pController = pChWin->GetController().get();
    if (!pController)
        return nullptr;
    weld::Window* pWin = pController->getDialog();
    if (pWin && pWin->get_visible())
        return pWin;
#endif
    return nullptr;
}

Point SwViewShell::GetPagePos( sal_uInt16 nPageNum ) const
{
    return GetLayout()->GetPagePos( nPageNum );
}

sal_uInt16 SwViewShell::GetNumPages() const
{
    //It is possible that no layout exists when the method from
    //root-Ctor is called.
    return GetLayout() ? GetLayout()->GetPageNum() : 0;
}

bool SwViewShell::IsDummyPage( sal_uInt16 nPageNum ) const
{
    return GetLayout() && GetLayout()->IsDummyPage( nPageNum );
}

/**
 * Forces update of each field.
 * It notifies all fields with pNewHt. If that is 0 (default), the field
 * type is sent (???).
 * @param[in] bCloseDB Passed in to GetDoc()->UpdateFields. [TODO] Purpose???
 */

void SwViewShell::UpdateFields(bool bCloseDB, bool bSetModified)
{
    CurrShell aCurr( this );

    StartAction();

    GetDoc()->getIDocumentFieldsAccess().UpdateFields(bCloseDB, bSetModified);

    EndAction();
}

void SwViewShell::UpdateOleObjectPreviews()
{
    SwDoc* pDoc = GetDoc();
    for(sw::SpzFrameFormat* pFormat: *pDoc->GetSpzFrameFormats())
    {
        if (pFormat->Which() != RES_FLYFRMFMT)
        {
            continue;
        }

        const SwNodeIndex* pNodeIndex = pFormat->GetContent().GetContentIdx();
        if (!pNodeIndex || !pNodeIndex->GetNodes().IsDocNodes())
        {
            continue;
        }

        SwNode* pNode = pDoc->GetNodes()[pNodeIndex->GetIndex() + 1];
        SwOLENode* pOleNode = pNode->GetOLENode();
        if (!pOleNode)
        {
            continue;
        }

        SwOLEObj& rOleObj = pOleNode->GetOLEObj();
        svt::EmbeddedObjectRef& rObject = rOleObj.GetObject();
        rObject.UpdateReplacement( true );
        // Trigger the repaint.
        pOleNode->SetChanged();
    }
}

/** update all charts for which any table exists */
void SwViewShell::UpdateAllCharts()
{
    CurrShell aCurr( this );
    // Start-/EndAction handled in the SwDoc-Method!
    GetDoc()->UpdateAllCharts();
}

bool SwViewShell::HasCharts() const
{
    bool bRet = false;
    SwNodeIndex aIdx( *GetDoc()->GetNodes().GetEndOfAutotext().
                        StartOfSectionNode(), 1 );
    while (aIdx.GetNode().GetStartNode())
    {
        ++aIdx;
        const SwOLENode *pNd = aIdx.GetNode().GetOLENode();
        if( pNd && !pNd->GetChartTableName().isEmpty() )
        {
            bRet = true;
            break;
        }
    }
    return bRet;
}

void SwViewShell::LayoutIdle()
{
    if( !mpOpt->IsIdle() || !GetWin() || HasDrawViewDrag() )
        return;

    //No idle when printing is going on.
    for(const SwViewShell& rSh : GetRingContainer())
    {
        if ( !rSh.GetWin() )
            return;
    }

    CurrShell aCurr( this );

#ifdef DBG_UTIL
    // If Test5 has been set, the IdleFormatter is disabled.
    if( mpOpt->IsTest5() )
        return;
#endif

    {
        // Preserve top of the text frame cache.
        SwSaveSetLRUOfst aSaveLRU;
        // #125243# there are lots of stacktraces indicating that Imp() returns NULL
        // this SwViewShell seems to be invalid - but it's not clear why
        // this return is only a workaround!
        OSL_ENSURE(Imp(), "SwViewShell already deleted?");
        if(!Imp())
            return;
        SwLayIdle aIdle( GetLayout(), Imp() );
    }
}

static void lcl_InvalidateAllContent( SwViewShell& rSh, SwInvalidateFlags nInv )
{
    rSh.StartAction();
    rSh.GetLayout()->InvalidateAllContent( nInv );
    rSh.EndAction();

    rSh.GetDoc()->getIDocumentState().SetModified();
}

/** local method to invalidate/re-calculate positions of floating screen
 *  objects (Writer fly frame and drawing objects), which are anchored
 *  to paragraph or to character. #i11860#
 */

static void lcl_InvalidateAllObjPos( SwViewShell &_rSh )
{
    _rSh.StartAction();

    _rSh.GetLayout()->InvalidateAllObjPos();

    _rSh.EndAction();

    _rSh.GetDoc()->getIDocumentState().SetModified();
}

void SwViewShell::SetParaSpaceMax( bool bNew )
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if( rIDSA.get(DocumentSettingId::PARA_SPACE_MAX) != bNew )
    {
        SwWait aWait( *GetDoc()->GetDocShell(), true );
        rIDSA.set(DocumentSettingId::PARA_SPACE_MAX, bNew );
        const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
        lcl_InvalidateAllContent( *this,  nInv );
    }
}

void SwViewShell::SetParaSpaceMaxAtPages( bool bNew )
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if( rIDSA.get(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES) != bNew )
    {
        SwWait aWait( *GetDoc()->GetDocShell(), true );
        rIDSA.set(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES, bNew );
        const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
        lcl_InvalidateAllContent( *this,  nInv );
    }
}

void SwViewShell::SetTabCompat( bool bNew )
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if( rIDSA.get(DocumentSettingId::TAB_COMPAT) != bNew  )
    {
        SwWait aWait( *GetDoc()->GetDocShell(), true );
        rIDSA.set(DocumentSettingId::TAB_COMPAT, bNew );
        const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
        lcl_InvalidateAllContent( *this, nInv );
    }
}

void SwViewShell::SetAddExtLeading( bool bNew )
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if ( rIDSA.get(DocumentSettingId::ADD_EXT_LEADING) != bNew )
    {
        SwWait aWait( *GetDoc()->GetDocShell(), true );
        rIDSA.set(DocumentSettingId::ADD_EXT_LEADING, bNew );
        SwDrawModel* pTmpDrawModel = getIDocumentDrawModelAccess().GetDrawModel();
        if ( pTmpDrawModel )
            pTmpDrawModel->SetAddExtLeading( bNew );
        const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
        lcl_InvalidateAllContent( *this, nInv );
    }
}

/** Sets if paragraph and table spacing is added at bottom of table cells.
 * #106629#
 * @param[in] (bool) setting of the new value
 */

void SwViewShell::SetAddParaSpacingToTableCells( bool _bAddParaSpacingToTableCells )
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if (rIDSA.get(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS) != _bAddParaSpacingToTableCells
        || rIDSA.get(DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS) != _bAddParaSpacingToTableCells)
    {
        SwWait aWait( *GetDoc()->GetDocShell(), true );
        rIDSA.set(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS, _bAddParaSpacingToTableCells );
        // note: the dialog can't change the value to indeterminate, so only false/false and true/true
        rIDSA.set(DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS, _bAddParaSpacingToTableCells );
        const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea;
        lcl_InvalidateAllContent( *this, nInv );
    }
}

/**
 * Sets if former formatting of text lines with proportional line spacing should used.
 * #i11859#
 * @param[in] (bool) setting of the new value
 */

void SwViewShell::SetUseFormerLineSpacing( bool _bUseFormerLineSpacing )
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if ( rIDSA.get(DocumentSettingId::OLD_LINE_SPACING) != _bUseFormerLineSpacing )
    {
        SwWait aWait( *GetDoc()->GetDocShell(), true );
        rIDSA.set(DocumentSettingId::OLD_LINE_SPACING, _bUseFormerLineSpacing );
        const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea;
        lcl_InvalidateAllContent( *this, nInv );
    }
}

/**
 * Sets IDocumentSettingAccess if former object positioning should be used.
 * #i11860#
 * @param[in] (bool) setting the new value
 */

void SwViewShell::SetUseFormerObjectPositioning( bool _bUseFormerObjPos )
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if ( rIDSA.get(DocumentSettingId::USE_FORMER_OBJECT_POS) != _bUseFormerObjPos )
    {
        SwWait aWait( *GetDoc()->GetDocShell(), true );
        rIDSA.set(DocumentSettingId::USE_FORMER_OBJECT_POS, _bUseFormerObjPos );
        lcl_InvalidateAllObjPos( *this );
    }
}

// #i28701#
void SwViewShell::SetConsiderWrapOnObjPos( bool _bConsiderWrapOnObjPos )
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if ( rIDSA.get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) != _bConsiderWrapOnObjPos )
    {
        SwWait aWait( *GetDoc()->GetDocShell(), true );
        rIDSA.set(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION, _bConsiderWrapOnObjPos );
        lcl_InvalidateAllObjPos( *this );
    }
}

void SwViewShell::SetUseFormerTextWrapping( bool _bUseFormerTextWrapping )
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if ( rIDSA.get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING) != _bUseFormerTextWrapping )
    {
        SwWait aWait( *GetDoc()->GetDocShell(), true );
        rIDSA.set(DocumentSettingId::USE_FORMER_TEXT_WRAPPING, _bUseFormerTextWrapping );
        const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
        lcl_InvalidateAllContent( *this, nInv );
    }
}

// #i45491#
void SwViewShell::SetDoNotJustifyLinesWithManualBreak( bool _bDoNotJustifyLinesWithManualBreak )
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if ( rIDSA.get(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK) != _bDoNotJustifyLinesWithManualBreak )
    {
        SwWait aWait( *GetDoc()->GetDocShell(), true );
        rIDSA.set(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK, _bDoNotJustifyLinesWithManualBreak );
        const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
        lcl_InvalidateAllContent( *this, nInv );
    }
}

void SwViewShell::SetProtectForm( bool _bProtectForm )
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    rIDSA.set(DocumentSettingId::PROTECT_FORM, _bProtectForm );
}

void SwViewShell::SetMsWordCompTrailingBlanks( bool _bMsWordCompTrailingBlanks )
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if (rIDSA.get(DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS) != _bMsWordCompTrailingBlanks)
    {
        SwWait aWait(*GetDoc()->GetDocShell(), true);
        rIDSA.set(DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS, _bMsWordCompTrailingBlanks);
        const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Size | SwInvalidateFlags::Table | SwInvalidateFlags::Section;
        lcl_InvalidateAllContent(*this, nInv);
    }
}

void SwViewShell::SetSubtractFlysAnchoredAtFlys(bool bSubtractFlysAnchoredAtFlys)
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    rIDSA.set(DocumentSettingId::SUBTRACT_FLYS, bSubtractFlysAnchoredAtFlys);
}

void SwViewShell::SetEmptyDbFieldHidesPara(bool bEmptyDbFieldHidesPara)
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if (rIDSA.get(DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA) == bEmptyDbFieldHidesPara)
        return;

    SwWait aWait(*GetDoc()->GetDocShell(), true);
    rIDSA.set(DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA, bEmptyDbFieldHidesPara);
    SwViewShell::StartAction();
    GetDoc()->getIDocumentState().SetModified();
    for (auto const & pFieldType : *GetDoc()->getIDocumentFieldsAccess().GetFieldTypes())
    {
        if(pFieldType->Which() == SwFieldIds::Database)
            pFieldType->UpdateFields();
    }
    SwViewShell::EndAction();
}

void SwViewShell::SetNoGapAfterNoteNumber(bool bNew)
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if (rIDSA.get(DocumentSettingId::NO_GAP_AFTER_NOTE_NUMBER) != bNew)
    {
        SwWait aWait(*GetDoc()->GetDocShell(), true);
        rIDSA.set(DocumentSettingId::NO_GAP_AFTER_NOTE_NUMBER, bNew);
        const SwInvalidateFlags nInv = SwInvalidateFlags::Size | SwInvalidateFlags::Pos | SwInvalidateFlags::PrtArea;
        lcl_InvalidateAllContent(*this, nInv);
    }
}

void SwViewShell::SetTabsRelativeToIndent(bool bNew)
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if (rIDSA.get(DocumentSettingId::TABS_RELATIVE_TO_INDENT) != bNew)
    {
        SwWait aWait(*GetDoc()->GetDocShell(), true);
        rIDSA.set(DocumentSettingId::TABS_RELATIVE_TO_INDENT, bNew);
        const SwInvalidateFlags nInv = SwInvalidateFlags::Size | SwInvalidateFlags::Section | SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table | SwInvalidateFlags::Pos;
        lcl_InvalidateAllContent(*this, nInv);
    }
}

void SwViewShell::SetTabOverMargin(bool bNew)
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if (rIDSA.get(DocumentSettingId::TAB_OVER_MARGIN) != bNew)
    {
        SwWait aWait(*GetDoc()->GetDocShell(), true);
        rIDSA.set(DocumentSettingId::TAB_OVER_MARGIN, bNew);
        const SwInvalidateFlags nInv = SwInvalidateFlags::Size | SwInvalidateFlags::Section | SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table | SwInvalidateFlags::Pos;
        lcl_InvalidateAllContent(*this, nInv);
    }
}

void SwViewShell::SetDoNotMirrorRtlDrawObjs(bool bDoNotMirrorRtlDrawObjs)
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if (rIDSA.get(DocumentSettingId::DO_NOT_MIRROR_RTL_DRAW_OBJS) != bDoNotMirrorRtlDrawObjs)
    {
        SwWait aWait(*GetDoc()->GetDocShell(), true);
        rIDSA.set(DocumentSettingId::DO_NOT_MIRROR_RTL_DRAW_OBJS, bDoNotMirrorRtlDrawObjs);
        lcl_InvalidateAllObjPos(*this);
    }
}

void SwViewShell::SetContinuousEndnotes(bool bContinuousEndnotes)
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if (rIDSA.get(DocumentSettingId::CONTINUOUS_ENDNOTES) != bContinuousEndnotes)
    {
        SwWait aWait(*GetDoc()->GetDocShell(), true);
        rIDSA.set(DocumentSettingId::CONTINUOUS_ENDNOTES, bContinuousEndnotes);
        SwViewShell::StartAction();
        GetLayout()->RemoveFootnotes(/*pPage=*/nullptr, /*pPageOnly=*/false, /*bEndNotes=*/true);
        SwViewShell::EndAction();
        GetDoc()->getIDocumentState().SetModified();
    }
}

void SwViewShell::SetMsWordCompGridMetrics(bool _bMsWordCompGridMetrics)
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if (rIDSA.get(DocumentSettingId::MS_WORD_COMP_GRID_METRICS) != _bMsWordCompGridMetrics)
    {
        SwWait aWait(*GetDoc()->GetDocShell(), true);
        rIDSA.set(DocumentSettingId::MS_WORD_COMP_GRID_METRICS, _bMsWordCompGridMetrics);
        const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Pos
                                       | SwInvalidateFlags::Size | SwInvalidateFlags::Table
                                       | SwInvalidateFlags::Section;
        lcl_InvalidateAllContent(*this, nInv);
    }
}

void SwViewShell::SetIgnoreTabsAndBlanksForLineCalculation(bool val)
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if (rIDSA.get(DocumentSettingId::IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION) != val)
    {
        SwWait aWait(*GetDoc()->GetDocShell(), true);
        rIDSA.set(DocumentSettingId::IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION, val);
        const SwInvalidateFlags nInv = SwInvalidateFlags::Size | SwInvalidateFlags::Section
                                        | SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table
                                        | SwInvalidateFlags::Pos;
        lcl_InvalidateAllContent(*this, nInv);
    }
}

void SwViewShell::SetMsWordUlTrailSpace(bool val)
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if (rIDSA.get(DocumentSettingId::MS_WORD_UL_TRAIL_SPACE) != val)
    {
        SwWait aWait(*GetDoc()->GetDocShell(), true);
        rIDSA.set(DocumentSettingId::MS_WORD_UL_TRAIL_SPACE, val);
        const SwInvalidateFlags nInv = SwInvalidateFlags::Size;
        lcl_InvalidateAllContent(*this, nInv);
    }
}

void SwViewShell::SetBalanceSpacesAndIdeographicSpaces(bool bValue)
{
    IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess();
    if (rIDSA.get(DocumentSettingId::BALANCE_SPACES_AND_IDEOGRAPHIC_SPACES) != bValue)
    {
        SwWait aWait(*GetDoc()->GetDocShell(), true);
        rIDSA.set(DocumentSettingId::BALANCE_SPACES_AND_IDEOGRAPHIC_SPACES, bValue);
        const SwInvalidateFlags nInv
            = SwInvalidateFlags::Size | SwInvalidateFlags::Pos | SwInvalidateFlags::PrtArea;
        lcl_InvalidateAllContent(*this, nInv);
    }
}

void SwViewShell::Reformat()
{
    SwWait aWait( *GetDoc()->GetDocShell(), true );

    // we go for safe: get rid of the old font information,
    // when the printer resolution or zoom factor changes.
    // Init() and Reformat() are the safest locations.
    pFntCache->Flush( );

    if( GetLayout()->IsCallbackActionEnabled() )
    {
        SwViewShell::StartAction();
        GetLayout()->InvalidateAllContent( SwInvalidateFlags::Size | SwInvalidateFlags::Pos | SwInvalidateFlags::PrtArea );
        SwViewShell::EndAction();
    }
}

void SwViewShell::ChgNumberDigits()
{
    SdrModel* pTmpDrawModel = getIDocumentDrawModelAccess().GetDrawModel();
    if ( pTmpDrawModel )
           pTmpDrawModel->ReformatAllTextObjects();
    Reformat();
}

void SwViewShell::CalcLayout()
{
    // extremely likely to be a Bad Idea to call this without StartAction
    // (except the Page Preview apparently only has a non-subclassed ViewShell)
    assert((typeid(*this) == typeid(SwViewShell)) || mnStartAction);

    CurrShell aCurr( this );
    SwWait aWait( *GetDoc()->GetDocShell(), true );

    // Preserve top of the text frame cache.
    SwSaveSetLRUOfst aSaveLRU;

    //switch on Progress when none is running yet.
    const bool bEndProgress = SfxProgress::GetActiveProgress( GetDoc()->GetDocShell() ) == nullptr;
    if ( bEndProgress )
    {
        tools::Long nEndPage = GetLayout()->GetPageNum();
        nEndPage += nEndPage * 10 / 100;
        ::StartProgress( STR_STATSTR_REFORMAT, 0, nEndPage, GetDoc()->GetDocShell() );
    }

    SwLayAction aAction( GetLayout(), Imp() );
    aAction.SetPaint( false );
    aAction.SetStatBar( true );
    aAction.SetCalcLayout( true );
    aAction.SetReschedule( true );
    GetDoc()->getIDocumentFieldsAccess().LockExpFields();
    aAction.Action(GetOut());
    GetDoc()->getIDocumentFieldsAccess().UnlockExpFields();

    //the SetNewFieldLst() on the Doc was cut off and must be fetched again
    //(see flowfrm.cxx, txtfld.cxx)
    if ( aAction.IsExpFields() )
    {
        aAction.Reset();
        aAction.SetPaint( false );
        aAction.SetStatBar( true );
        aAction.SetReschedule( true );

        GetDoc()->getIDocumentFieldsAccess().UpdatePageFields(0);
        GetDoc()->getIDocumentFieldsAccess().UpdateExpFields(nullptr, true);

        aAction.Action(GetOut());
    }

    if ( VisArea().HasArea() )
        InvalidateWindows( VisArea() );
    if ( bEndProgress )
        ::EndProgress( GetDoc()->GetDocShell() );
}

void SwViewShell::SetFirstVisPageInvalid()
{
    for(SwViewShell& rSh : GetRingContainer())
    {
        if ( rSh.Imp() )
            rSh.Imp()->SetFirstVisPageInvalid();
    }
}

void SwViewShell::SizeChgNotify()
{
    if ( !mpWin )
        mbDocSizeChgd = true;
    else if( ActionPend() || Imp()->IsCalcLayoutProgress() || mbPaintInProgress )
    {
        mbDocSizeChgd = true;

        if ( !Imp()->IsCalcLayoutProgress() && dynamic_cast<const SwCursorShell*>( this ) !=  nullptr )
        {
            PageNumNotify(*this);

            if (SfxViewShell* pNotifySh = comphelper::LibreOfficeKit::isActive() ? GetSfxViewShell() : nullptr)
            {
                Size aDocSize = GetDocSize();
                OString sPayload = OString::number(aDocSize.Width() + 2 * DOCUMENTBORDER) +
                    ", " + OString::number(aDocSize.Height() + 2 * DOCUMENTBORDER);

                SwXTextDocument* pModel = comphelper::getFromUnoTunnel<SwXTextDocument>(pNotifySh->GetCurrentDocument());
                SfxLokHelper::notifyDocumentSizeChanged(pNotifySh, sPayload, pModel);
            }
        }
    }
    else
    {
        mbDocSizeChgd = false;
        ::SizeNotify( *this, GetDocSize() );
    }
}

void SwViewShell::VisPortChgd( const SwRect &rRect)
{
    OSL_ENSURE( GetWin(), "VisPortChgd without Window." );

    if ( rRect == VisArea() )
        return;

    // Is someone spuriously rescheduling again?
    SAL_WARN_IF(mbInEndAction, "sw.core""Scrolling during EndAction");

    //First get the old visible page, so we don't have to look
    //for it afterwards.
    const SwFrame *pOldPage = Imp()->GetFirstVisPage(GetWin()->GetOutDev());

    const SwRect aPrevArea( VisArea() );
    const bool bFull = aPrevArea.IsEmpty();
    maVisArea = rRect;
    SetFirstVisPageInvalid();

    //When there a PaintRegion still exists and the VisArea has changed,
    //the PaintRegion is at least by now obsolete. The PaintRegion can
    //have been created by RootFrame::PaintSwFrame.
    if ( !mbInEndAction &&
         Imp()->HasPaintRegion() && Imp()->GetPaintRegion()->GetOrigin() != VisArea() )
        Imp()->DeletePaintRegion();

    CurrShell aCurr( this );

    bool bScrolled = false;

    SwPostItMgr* pPostItMgr = GetPostItMgr();

    if ( bFull )
        GetWin()->Invalidate();
    else
    {
        //Calculate amount to be scrolled.
        const tools::Long nXDiff = aPrevArea.Left() - VisArea().Left();
        const tools::Long nYDiff = aPrevArea.Top()  - VisArea().Top();

        if( !nXDiff && !GetViewOptions()->getBrowseMode() &&
            (!Imp()->HasDrawView() || !Imp()->GetDrawView()->IsGridVisible() ) )
        {
            // If possible, don't scroll the application background
            // (PaintDesktop).  Also limit the left and right side of
            // the scroll range to the pages.
            const SwPageFrame *pPage = static_cast<SwPageFrame*>(GetLayout()->Lower());
            if ( pPage->getFrameArea().Top() > pOldPage->getFrameArea().Top() )
                pPage = static_cast<const SwPageFrame*>(pOldPage);
            SwRect aBoth( VisArea() );
            aBoth.Union( aPrevArea );
            const SwTwips nBottom = aBoth.Bottom();
            SwTwips nMinLeft = SAL_MAX_INT32;
            SwTwips nMaxRight= 0;

            const bool bBookMode = GetViewOptions()->IsViewLayoutBookMode();

            while ( pPage && pPage->getFrameArea().Top() <= nBottom )
            {
                SwRect aPageRect( pPage->GetBoundRect(GetWin()->GetOutDev()) );
                if ( bBookMode )
                {
                    const SwPageFrame& rFormatPage = pPage->GetFormatPage();
                    aPageRect.SSize( rFormatPage.GetBoundRect(GetWin()->GetOutDev()).SSize() );
                }

                // #i9719# - consider new border and shadow width
                if ( aPageRect.Overlaps( aBoth ) )
                {
                    SwTwips nPageLeft = 0;
                    SwTwips nPageRight = 0;
                    const sw::sidebarwindows::SidebarPosition aSidebarPos = pPage->SidebarPosition();

                    if( aSidebarPos != sw::sidebarwindows::SidebarPosition::NONE )
                    {
                        nPageLeft = aPageRect.Left();
                        nPageRight = aPageRect.Right();
                    }

                    if( nPageLeft < nMinLeft )
                        nMinLeft = nPageLeft;
                    if( nPageRight > nMaxRight )
                        nMaxRight = nPageRight;
                    //match with the draw objects
                    //take nOfst into account as the objects have been
                    //selected and have handles attached.
                    if ( pPage->GetSortedObjs() )
                    {
                        const tools::Long nOfst = GetOut()->PixelToLogic(
                            Size(Imp()->GetDrawView()->GetMarkHdlSizePixel()/2,0)).Width();
                        for (SwAnchoredObject* pObj : *pPage->GetSortedObjs())
                        {
                            // ignore objects that are not actually placed on the page
                            if (pObj->IsFormatPossible())
                            {
                                const tools::Rectangle aBound = pObj->GetObjRect().SVRect();
                                if (aBound.Left() != FAR_AWAY) {
                                    // OD 03.03.2003 #107927# - use correct datatype
                                    const SwTwips nL = std::max( SwTwips(0), SwTwips(aBound.Left() - nOfst) );
                                    if ( nL < nMinLeft )
                                        nMinLeft = nL;
                                    if( aBound.Right() + nOfst > nMaxRight )
                                        nMaxRight = aBound.Right() + nOfst;
                                }
                            }
                        }
                    }
                }
                pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
            }
            tools::Rectangle aRect( aPrevArea.SVRect() );
            aRect.SetLeft( nMinLeft );
            aRect.SetRight( nMaxRight );
            if( VisArea().Overlaps( aPrevArea ) && !mnLockPaint )
            {
                bScrolled = true;
                maVisArea.Pos() = aPrevArea.Pos();
                if ( SmoothScroll( nXDiff, nYDiff, &aRect ) )
                    return;
                maVisArea.Pos() = rRect.Pos();
            }
            else if (!comphelper::LibreOfficeKit::isActive())
                GetWin()->Invalidate( aRect );
        }
        else if ( !mnLockPaint ) //will be released in Unlock
        {
            if( VisArea().Overlaps( aPrevArea ) )
            {
                bScrolled = true;
                maVisArea.Pos() = aPrevArea.Pos();
                if ( SmoothScroll( nXDiff, nYDiff, nullptr ) )
                    return;
                maVisArea.Pos() = rRect.Pos();
            }
            else
                GetWin()->Invalidate();
        }
    }

    // When tiled rendering, the map mode of the window is disabled, avoid
    // enabling it here.
    if (!comphelper::LibreOfficeKit::isActive())
    {
        Point aPt( VisArea().Pos() );
        aPt.setX( -aPt.X() ); aPt.setY( -aPt.Y() );
        MapMode aMapMode( GetWin()->GetMapMode() );
        aMapMode.SetOrigin( aPt );
        GetWin()->SetMapMode( aMapMode );
    }

    if ( HasDrawView() )
    {
        Imp()->GetDrawView()->VisAreaChanged( GetWin()->GetOutDev() );
        Imp()->GetDrawView()->SetActualWin( GetWin()->GetOutDev() );
    }
    GetWin()->PaintImmediately();

    if ( pPostItMgr ) // #i88070#
    {
        pPostItMgr->Rescale();
        pPostItMgr->CalcRects();
        pPostItMgr->LayoutPostIts();
    }

    if ( !bScrolled && pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() )
        pPostItMgr->CorrectPositions();

#if !ENABLE_WASM_STRIP_ACCESSIBILITY
    if( Imp()->IsAccessible() )
        Imp()->UpdateAccessible();
#endif
}

bool SwViewShell::SmoothScroll( tools::Long lXDiff, tools::Long lYDiff, const tools::Rectangle *pRect )
{
#if !defined(MACOSX) && !defined(ANDROID) && !defined(IOS)
    // #i98766# - disable smooth scrolling for Mac

    const sal_uLong nBitCnt = mpOut->GetBitCount();
    tools::Long lMult = 1, lMax = LONG_MAX;
    if ( nBitCnt == 16 )
    {
        lMax = 7000;
        lMult = 2;
    }
    if ( nBitCnt == 24 )
    {
        lMax = 5000;
        lMult = 6;
    }
    else if ( nBitCnt == 1 )
    {
        lMax = 3000;
        lMult = 12;
    }

    // #i75172# isolated static conditions
    const bool bOnlyYScroll(!lXDiff && std::abs(lYDiff) != 0 && std::abs(lYDiff) < lMax);
    const bool bAllowedWithChildWindows(GetWin()->GetWindowClipRegionPixel().IsNull());
    const bool bSmoothScrollAllowed(bOnlyYScroll && mbEnableSmooth && GetViewOptions()->IsSmoothScroll() &&  bAllowedWithChildWindows);

    if(bSmoothScrollAllowed)
    {
        Imp()->m_bStopSmooth = false;

        const SwRect aOldVis( VisArea() );

        //create virtual device and set.
        const Size aPixSz = GetWin()->PixelToLogic(Size(1,1));
        VclPtrInstance<VirtualDevice> pVout( *GetWin()->GetOutDev() );
        pVout->SetLineColor( GetWin()->GetOutDev()->GetLineColor() );
        pVout->SetFillColor( GetWin()->GetOutDev()->GetFillColor() );
        MapMode aMapMode( GetWin()->GetMapMode() );
        pVout->SetMapMode( aMapMode );
        Size aSize( maVisArea.Width()+2*aPixSz.Width(), std::abs(lYDiff)+(2*aPixSz.Height()) );
        if ( pRect )
            aSize.setWidth( std::min(aSize.Width(), pRect->GetWidth()+2*aPixSz.Width()) );
        if ( pVout->SetOutputSize( aSize ) )
        {
            mnLockPaint++;

            //First Paint everything in the virtual device.
            SwRect aRect( VisArea() );
            aRect.Height( aSize.Height() );
            if ( pRect )
            {
                aRect.Pos().setX( std::max(aRect.Left(),pRect->Left()-aPixSz.Width()) );
                aRect.Right( std::min(aRect.Right()+2*aPixSz.Width(), pRect->Right()+aPixSz.Width()));
            }
            else
                aRect.AddWidth(2*aPixSz.Width() );
            aRect.Pos().setY( lYDiff < 0 ? aOldVis.Bottom() - aPixSz.Height()
                                         : aRect.Top() - aSize.Height() + aPixSz.Height() );
            aRect.Pos().setX( std::max( tools::Long(0), aRect.Left()-aPixSz.Width() ) );
            aRect.Pos()  = GetWin()->PixelToLogic( GetWin()->LogicToPixel( aRect.Pos()));
            aRect.SSize( GetWin()->PixelToLogic( GetWin()->LogicToPixel( aRect.SSize())) );
            maVisArea = aRect;
            const Point aPt( -aRect.Left(), -aRect.Top() );
            aMapMode.SetOrigin( aPt );
            pVout->SetMapMode( aMapMode );
            OutputDevice *pOld = mpOut;
            mpOut = pVout.get();

            {
                // #i75172# To get a clean repaint, a new ObjectContact is needed here. Without, the
                // repaint would not be correct since it would use the wrong DrawPage visible region.
                // This repaint IS about painting something currently outside the visible part (!).
                // For that purpose, AddDeviceToPaintView is used which creates a new SdrPageViewWindow
                // and all the necessary stuff. It's not cheap, but necessary here. Alone because repaint
                // target really is NOT the current window.
                // Also will automatically NOT use PreRendering and overlay (since target is VirtualDevice)
                if(!HasDrawView())
                    MakeDrawView();
                SdrView* pDrawView = GetDrawView();
                pDrawView->AddDeviceToPaintView(*pVout, nullptr);

                // clear mpWin during DLPrePaint2 to get paint preparation for mpOut, but set it again
                // immediately afterwards. There are many decisions in SW which imply that Printing
                // is used when mpWin == 0 (wrong but widely used).
                vcl::Window* pOldWin = mpWin;
                mpWin = nullptr;
                DLPrePaint2(vcl::Region(aRect.SVRect()));
                mpWin = pOldWin;

                // SW paint stuff
                PaintDesktop(*GetOut(), aRect);
                SwViewShell::sbLstAct = true;
                GetLayout()->PaintSwFrame( *GetOut(), aRect );
                SwViewShell::sbLstAct = false;

                // end paint and destroy ObjectContact again
                DLPostPaint2(true);
                pDrawView->DeleteDeviceFromPaintView(*pVout);
            }

            mpOut = pOld;
            maVisArea = aOldVis;

            //Now shift in parts and copy the new Pixel from the virtual device.

            // ??????????????????????
            // or is it better to get the scrollfactor from the User
            // as option?
            // ??????????????????????
            tools::Long lMaDelta = aPixSz.Height();
            if ( std::abs(lYDiff) > ( maVisArea.Height() / 3 ) )
                lMaDelta *= 6;
            else
                lMaDelta *= 2;

            lMaDelta *= lMult;

            if ( lYDiff < 0 )
                lMaDelta = -lMaDelta;

            tools::Long lDiff = lYDiff;
            while ( lDiff )
            {
                tools::Long lScroll;
                if ( Imp()->m_bStopSmooth || std::abs(lDiff) <= std::abs(lMaDelta) )
                {
                    lScroll = lDiff;
                    lDiff = 0;
                }
                else
                {
                    lScroll = lMaDelta;
                    lDiff -= lMaDelta;
                }

                const SwRect aTmpOldVis = VisArea();
                maVisArea.Pos().AdjustY( -lScroll );
                maVisArea.Pos() = GetWin()->PixelToLogic( GetWin()->LogicToPixel( VisArea().Pos()));
                lScroll = aTmpOldVis.Top() - VisArea().Top();
                if ( pRect )
                {
                    tools::Rectangle aTmp( aTmpOldVis.SVRect() );
                    aTmp.SetLeft( pRect->Left() );
                    aTmp.SetRight( pRect->Right() );
                    GetWin()->Scroll( 0, lScroll, aTmp, ScrollFlags::Children);
                }
                else
                    GetWin()->Scroll( 0, lScroll, ScrollFlags::Children );

                const Point aTmpPt( -VisArea().Left(), -VisArea().Top() );
                MapMode aTmpMapMode( GetWin()->GetMapMode() );
                aTmpMapMode.SetOrigin( aTmpPt );
                GetWin()->SetMapMode( aTmpMapMode );

                if ( Imp()->HasDrawView() )
                    Imp()->GetDrawView()->VisAreaChanged( GetWin()->GetOutDev() );

                SetFirstVisPageInvalid();
                if ( !Imp()->m_bStopSmooth )
                {
                    const bool bScrollDirectionIsUp(lScroll > 0);
                    Imp()->m_aSmoothRect = VisArea();

                    if(bScrollDirectionIsUp)
                    {
                        Imp()->m_aSmoothRect.Bottom( VisArea().Top() + lScroll + aPixSz.Height());
                    }
                    else
                    {
                        Imp()->m_aSmoothRect.Top( VisArea().Bottom() + lScroll - aPixSz.Height());
                    }

                    Imp()->m_bSmoothUpdate = true;
                    GetWin()->PaintImmediately();
                    Imp()->m_bSmoothUpdate = false;

                    if(!Imp()->m_bStopSmooth)
                    {
                            // start paint on logic base
                            const tools::Rectangle aTargetLogic(Imp()->m_aSmoothRect.SVRect());
                            DLPrePaint2(vcl::Region(aTargetLogic));

                            // get target rectangle in discrete pixels
                            OutputDevice& rTargetDevice = mpTargetPaintWindow->GetTargetOutputDevice();
                            const tools::Rectangle aTargetPixel(rTargetDevice.LogicToPixel(aTargetLogic));

                            // get source top-left in discrete pixels
                            const Point aSourceTopLeft(pVout->LogicToPixel(aTargetLogic.TopLeft()));

                            // switch off MapModes
                            const bool bMapModeWasEnabledDest(rTargetDevice.IsMapModeEnabled());
                            const bool bMapModeWasEnabledSource(pVout->IsMapModeEnabled());
                            rTargetDevice.EnableMapMode(false);
                            pVout->EnableMapMode(false);

                            rTargetDevice.DrawOutDev(
                                aTargetPixel.TopLeft(), aTargetPixel.GetSize(), // dest
                                aSourceTopLeft, aTargetPixel.GetSize(), // source
                                *pVout);

                            // restore MapModes
                            rTargetDevice.EnableMapMode(bMapModeWasEnabledDest);
                            pVout->EnableMapMode(bMapModeWasEnabledSource);

                            // end paint on logoc base
                            DLPostPaint2(true);
                    }
                    else
                        --mnLockPaint;
                }
            }
            pVout.disposeAndClear();
            GetWin()->PaintImmediately();
            if ( !Imp()->m_bStopSmooth )
                --mnLockPaint;
            SetFirstVisPageInvalid();
            return true;
        }
        pVout.disposeAndClear();
    }
#endif

    maVisArea.Pos().AdjustX( -lXDiff );
    maVisArea.Pos().AdjustY( -lYDiff );
    if ( pRect )
        GetWin()->Scroll( lXDiff, lYDiff, *pRect, ScrollFlags::Children);
    else
        GetWin()->Scroll( lXDiff, lYDiff, ScrollFlags::Children);
    return false;
}

void SwViewShell::PaintDesktop(const vcl::RenderContext& rRenderContext, const SwRect &rRect)
{
    if ( !GetWin() && !GetOut()->GetConnectMetaFile() )
        return;                     //for the printer we don't do anything here.

    if(comphelper::LibreOfficeKit::isActive())
        return;

    //Catch exceptions, so that it doesn't look so surprising.
    //Can e.g. happen during Idle.
    //Unfortunately we must at any rate Paint the rectangles next to the pages,
    //as these are not painted at VisPortChgd.
    bool bBorderOnly = false;
    const SwRootFrame *pRoot = GetLayout();
    if ( rRect.Top() > pRoot->getFrameArea().Bottom() )
    {
        const SwFrame *pPg = pRoot->Lower();
        while ( pPg && pPg->GetNext() )
            pPg = pPg->GetNext();
        if ( !pPg || !pPg->getFrameArea().Overlaps( VisArea() ) )
            bBorderOnly = true;
    }

    const bool bBookMode = GetViewOptions()->IsViewLayoutBookMode();

    SwRegionRects aRegion( rRect );

    //mod #i6193: remove sidebar area to avoid flickering
    const SwPostItMgr* pPostItMgr = GetPostItMgr();
    const SwTwips nSidebarWidth = pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() ?
                                  pPostItMgr->GetSidebarWidth() + pPostItMgr->GetSidebarBorderWidth() :
                                  0;

    if ( bBorderOnly )
    {
        const SwFrame *pPage =pRoot->Lower();
        SwRect aLeft( rRect ), aRight( rRect );
        while ( pPage )
        {
            tools::Long nTmp = pPage->getFrameArea().Left();
            if ( nTmp < aLeft.Right() )
                aLeft.Right( nTmp );
            nTmp = pPage->getFrameArea().Right();
            if ( nTmp > aRight.Left() )
            {
                aRight.Left( nTmp + nSidebarWidth );
            }
            pPage = pPage->GetNext();
        }
        aRegion.clear();
        if ( aLeft.HasArea() )
            aRegion.push_back( aLeft );
        if ( aRight.HasArea() )
            aRegion.push_back( aRight );
    }
    else
    {
        const SwFrame *pPage = Imp()->GetFirstVisPage(&rRenderContext);
        const SwTwips nBottom = rRect.Bottom();
        while ( pPage && !aRegion.empty() &&
                (pPage->getFrameArea().Top() <= nBottom) )
        {
            SwRect aPageRect( pPage->getFrameArea() );
            if ( bBookMode )
            {
                const SwPageFrame& rFormatPage = static_cast<const SwPageFrame*>(pPage)->GetFormatPage();
                aPageRect.SSize( rFormatPage.getFrameArea().SSize() );
            }

            const bool bSidebarRight =
                static_cast<const SwPageFrame*>(pPage)->SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT;
            aPageRect.Pos().AdjustX( -(bSidebarRight ? 0 : nSidebarWidth) );
            aPageRect.AddWidth(nSidebarWidth );

            if ( aPageRect.Overlaps( rRect ) )
                aRegion -= aPageRect;

            pPage = pPage->GetNext();
        }
    }
    if ( !aRegion.empty() )
        PaintDesktop_(aRegion);
}

// PaintDesktop is split in two, this part is also used by PreviewPage
void SwViewShell::PaintDesktop_(const SwRegionRects &rRegion)
{
    if (DrawAppBackgroundBitmap(GetOut(), rRegion.GetOrigin()))
        return;

    // OD 2004-04-23 #116347#
    GetOut()->Push( vcl::PushFlags::FILLCOLOR|vcl::PushFlags::LINECOLOR );
    GetOut()->SetLineColor();

    for ( auto &rRgn : rRegion )
    {
        const tools::Rectangle aRectangle(rRgn.SVRect());

        // #i93170#
        // Here we have a real Problem. On the one hand we have the buffering for paint
        // and overlay which needs an embracing pair of DLPrePaint2/DLPostPaint2 calls,
        // on the other hand the MapMode is not set correctly when this code is executed.
--> --------------------

--> maximum size reached

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

Messung V0.5
C=91 H=93 G=91

¤ Dauer der Verarbeitung: 0.34 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge