sw/source/uibase/docvw/FrameControlsManager.cxx |    4 
 sw/source/uibase/docvw/HeaderFooterWin.cxx      |  135 ++++++++++++++++--------
 sw/source/uibase/inc/HeaderFooterWin.hxx        |   48 ++++++--
 3 files changed, 133 insertions(+), 54 deletions(-)

New commits:
commit 27ed81d01c9d7cb55506f86fc24268ca3589e935
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Mon Nov 14 13:14:01 2022 +0000
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Wed Nov 16 14:23:12 2022 +0100

    Resolves: tdf#147802 don't create a header/footer control for every page
    
    just create a cheaper SwHeaderFooterDashedLine and only create the
    "expensive" control on-demand if it becomes visible on-screen and
    destroy it immediately if it goes off-screen.
    
    Change-Id: Id876145130d394f55f54790d5e8399dca4f8c03e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142748
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/source/uibase/docvw/FrameControlsManager.cxx 
b/sw/source/uibase/docvw/FrameControlsManager.cxx
index bb2733aa60a3..03252faa1283 100644
--- a/sw/source/uibase/docvw/FrameControlsManager.cxx
+++ b/sw/source/uibase/docvw/FrameControlsManager.cxx
@@ -93,7 +93,7 @@ void SwFrameControlsManager::SetHeaderFooterControl( const 
SwPageFrame* pPageFra
     else
     {
         SwFrameControlPtr pNewControl =
-                std::make_shared<SwFrameControl>( 
VclPtr<SwHeaderFooterWin>::Create(
+                std::make_shared<SwFrameControl>( 
VclPtr<SwHeaderFooterDashedLine>::Create(
                                         m_pEditWin, pPageFrame, bHeader 
).get() );
         const SwViewOption* pViewOpt = 
m_pEditWin->GetView().GetWrtShell().GetViewOptions();
         pNewControl->SetReadonly( pViewOpt->IsReadonly() );
@@ -103,7 +103,7 @@ void SwFrameControlsManager::SetHeaderFooterControl( const 
SwPageFrame* pPageFra
 
     tools::Rectangle aPageRect = m_pEditWin->LogicToPixel( 
pPageFrame->getFrameArea().SVRect() );
 
-    SwHeaderFooterWin* pWin = dynamic_cast<SwHeaderFooterWin 
*>(pControl->GetWindow());
+    SwHeaderFooterDashedLine* pWin = 
dynamic_cast<SwHeaderFooterDashedLine*>(pControl->GetWindow());
     assert( pWin != nullptr) ;
     assert( pWin->IsHeader() == bHeader );
     pWin->SetOffset( aOffset, aPageRect.Left(), aPageRect.Right() );
diff --git a/sw/source/uibase/docvw/HeaderFooterWin.cxx 
b/sw/source/uibase/docvw/HeaderFooterWin.cxx
index 24f41021e832..07ce07197846 100644
--- a/sw/source/uibase/docvw/HeaderFooterWin.cxx
+++ b/sw/source/uibase/docvw/HeaderFooterWin.cxx
@@ -160,26 +160,89 @@ void 
SwFrameButtonPainter::PaintButton(drawinglayer::primitive2d::Primitive2DCon
                 new 
drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aPolygon, aLineColor)));
 }
 
-SwHeaderFooterWin::SwHeaderFooterWin( SwEditWin* pEditWin, const SwFrame 
*pFrame, bool bHeader ) :
-    SwFrameMenuButtonBase(pEditWin, pFrame, 
"modules/swriter/ui/hfmenubutton.ui", "HFMenuButton"),
+SwHeaderFooterDashedLine::SwHeaderFooterDashedLine(SwEditWin* pEditWin, const 
SwFrame *pFrame, bool bHeader)
+    : SwDashedLine(pEditWin, &SwViewOption::GetHeaderFooterMarkColor)
+    , m_pEditWin(pEditWin)
+    , m_pFrame(pFrame)
+    , m_bIsHeader(bHeader)
+{
+}
+
+bool SwHeaderFooterDashedLine::IsOnScreen()
+{
+    tools::Rectangle aBounds(GetPosPixel(), GetSizePixel());
+    tools::Rectangle aVisArea = 
GetEditWin()->LogicToPixel(GetEditWin()->GetView().GetVisArea());
+    return aBounds.Overlaps(aVisArea);
+}
+
+void SwHeaderFooterDashedLine::EnsureWin()
+{
+    if (!m_pWin)
+    {
+        m_pWin = VclPtr<SwHeaderFooterWin>::Create(m_pEditWin, m_pFrame, 
m_bIsHeader);
+        m_pWin->SetZOrder(this, ZOrderFlags::Before);
+    }
+}
+
+void SwHeaderFooterDashedLine::ShowAll(bool bShow)
+{
+    Show(bShow);
+    if (!m_pWin && IsOnScreen())
+        EnsureWin();
+    if (m_pWin)
+        m_pWin->ShowAll(bShow);
+}
+
+void SwHeaderFooterDashedLine::SetReadonly(bool bReadonly)
+{
+    ShowAll(!bReadonly);
+}
+
+bool SwHeaderFooterDashedLine::Contains(const Point &rDocPt) const
+{
+    if (m_pWin && m_pWin->Contains(rDocPt))
+        return true;
+
+    ::tools::Rectangle aLineRect(GetPosPixel(), GetSizePixel());
+    return aLineRect.Contains(rDocPt);
+}
+
+void SwHeaderFooterDashedLine::SetOffset(Point aOffset, tools::Long 
nXLineStart, tools::Long nXLineEnd)
+{
+    Point aLinePos(nXLineStart, aOffset.Y());
+    Size aLineSize(nXLineEnd - nXLineStart, 1);
+    SetPosSizePixel(aLinePos, aLineSize);
+
+    bool bOnScreen = IsOnScreen();
+    if (!m_pWin && bOnScreen)
+    {
+        EnsureWin();
+        m_pWin->ShowAll(true);
+    }
+    else if (m_pWin && !bOnScreen)
+        m_pWin.disposeAndClear();
+
+    if (m_pWin)
+        m_pWin->SetOffset(aOffset);
+}
+
+SwHeaderFooterWin::SwHeaderFooterWin(SwEditWin* pEditWin, const SwFrame 
*pFrame, bool bHeader ) :
+    InterimItemWindow(pEditWin, "modules/swriter/ui/hfmenubutton.ui", 
"HFMenuButton"),
     m_xMenuButton(m_xBuilder->weld_menu_button("menubutton")),
     m_xPushButton(m_xBuilder->weld_button("button")),
+    m_pEditWin(pEditWin),
+    m_pFrame(pFrame),
     m_bIsHeader( bHeader ),
-    m_pLine( nullptr ),
     m_bIsAppearing( false ),
     m_nFadeRate( 100 ),
     m_aFadeTimer("SwHeaderFooterWin m_aFadeTimer")
 {
     m_xVirDev = m_xMenuButton->create_virtual_device();
-    SetVirDevFont();
+    SwFrameMenuButtonBase::SetVirDevFont(*m_xVirDev);
 
     m_xPushButton->connect_clicked(LINK(this, SwHeaderFooterWin, ClickHdl));
     m_xMenuButton->connect_selected(LINK(this, SwHeaderFooterWin, SelectHdl));
 
-    // Create the line control
-    m_pLine = VclPtr<SwDashedLine>::Create(GetEditWin(), 
&SwViewOption::GetHeaderFooterMarkColor);
-    m_pLine->SetZOrder(this, ZOrderFlags::Before);
-
     // set the PopupMenu
     // Rewrite the menu entries' text
     if (m_bIsHeader)
@@ -204,20 +267,21 @@ SwHeaderFooterWin::~SwHeaderFooterWin( )
 
 void SwHeaderFooterWin::dispose()
 {
-    m_pLine.disposeAndClear();
     m_xPushButton.reset();
     m_xMenuButton.reset();
+    m_pEditWin.clear();
     m_xVirDev.disposeAndClear();
-    SwFrameMenuButtonBase::dispose();
+    InterimItemWindow::dispose();
 }
 
-void SwHeaderFooterWin::SetOffset(Point aOffset, tools::Long nXLineStart, 
tools::Long nXLineEnd)
+void SwHeaderFooterWin::SetOffset(Point aOffset)
 {
     // Compute the text to show
-    const SwPageDesc* pDesc = GetPageFrame()->GetPageDesc();
-    bool bIsFirst = !pDesc->IsFirstShared() && GetPageFrame()->OnFirstPage();
-    bool bIsLeft  = !pDesc->IsHeaderShared() && !GetPageFrame()->OnRightPage();
-    bool bIsRight = !pDesc->IsHeaderShared() && GetPageFrame()->OnRightPage();
+    const SwPageFrame* pPageFrame = 
SwFrameMenuButtonBase::GetPageFrame(m_pFrame);
+    const SwPageDesc* pDesc = pPageFrame->GetPageDesc();
+    bool bIsFirst = !pDesc->IsFirstShared() && pPageFrame->OnFirstPage();
+    bool bIsLeft  = !pDesc->IsHeaderShared() && !pPageFrame->OnRightPage();
+    bool bIsRight = !pDesc->IsHeaderShared() && pPageFrame->OnRightPage();
     m_sLabel = SwResId(STR_HEADER_TITLE);
     if (!m_bIsHeader)
         m_sLabel = bIsFirst ? SwResId(STR_FIRST_FOOTER_TITLE)
@@ -259,13 +323,6 @@ void SwHeaderFooterWin::SetOffset(Point aOffset, 
tools::Long nXLineStart, tools:
 
     m_xVirDev->SetOutputSizePixel(aBoxSize);
     PaintButton();
-
-    double nYLinePos = aBoxPos.Y();
-    if (!m_bIsHeader)
-        nYLinePos += aBoxSize.Height();
-    Point aLinePos(nXLineStart, nYLinePos);
-    Size aLineSize(nXLineEnd - nXLineStart, 1);
-    m_pLine->SetPosSizePixel(aLinePos, aLineSize);
 }
 
 void SwHeaderFooterWin::ShowAll(bool bShow)
@@ -284,11 +341,7 @@ void SwHeaderFooterWin::ShowAll(bool bShow)
 bool SwHeaderFooterWin::Contains( const Point &rDocPt ) const
 {
     ::tools::Rectangle aRect(GetPosPixel(), GetSizePixel());
-    if (aRect.Contains(rDocPt))
-        return true;
-
-    ::tools::Rectangle aLineRect(m_pLine->GetPosPixel(), 
m_pLine->GetSizePixel());
-    return aLineRect.Contains(rDocPt);
+    return aRect.Contains(rDocPt);
 }
 
 void SwHeaderFooterWin::PaintButton()
@@ -399,16 +452,17 @@ bool SwHeaderFooterWin::IsEmptyHeaderFooter( ) const
 {
     bool bResult = true;
 
-    if (!GetPageFrame())
+    const SwPageFrame* pPageFrame = 
SwFrameMenuButtonBase::GetPageFrame(m_pFrame);
+    if (!pPageFrame)
     {
         return bResult;
     }
 
     // Actually check it
-    const SwPageDesc* pDesc = GetPageFrame()->GetPageDesc();
+    const SwPageDesc* pDesc = pPageFrame->GetPageDesc();
 
-    bool const bFirst(GetPageFrame()->OnFirstPage());
-    const SwFrameFormat *const pFormat = (GetPageFrame()->OnRightPage())
+    bool const bFirst(pPageFrame->OnFirstPage());
+    const SwFrameFormat *const pFormat = (pPageFrame->OnRightPage())
         ? pDesc->GetRightFormat(bFirst)
         : pDesc->GetLeftFormat(bFirst);
 
@@ -425,10 +479,11 @@ bool SwHeaderFooterWin::IsEmptyHeaderFooter( ) const
 
 void SwHeaderFooterWin::ExecuteCommand(std::string_view rIdent)
 {
-    SwView& rView = GetEditWin()->GetView();
+    SwView& rView = m_pEditWin->GetView();
     SwWrtShell& rSh = rView.GetWrtShell();
 
-    const OUString& rStyleName = GetPageFrame()->GetPageDesc()->GetName();
+    const SwPageFrame* pPageFrame = 
SwFrameMenuButtonBase::GetPageFrame(m_pFrame);
+    const OUString& rStyleName = pPageFrame->GetPageDesc()->GetName();
     if (rIdent == "edit")
     {
         OString sPageId = m_bIsHeader ? OString("header") : OString("footer");
@@ -436,7 +491,7 @@ void SwHeaderFooterWin::ExecuteCommand(std::string_view 
rIdent)
     }
     else if (rIdent == "borderback")
     {
-        const SwPageDesc* pDesc = GetPageFrame()->GetPageDesc();
+        const SwPageDesc* pDesc = pPageFrame->GetPageDesc();
         const SwFrameFormat& rMaster = pDesc->GetMaster();
         SwFrameFormat* pHFFormat = const_cast< SwFrameFormat* >( 
rMaster.GetFooter().GetFooterFormat() );
         if ( m_bIsHeader )
@@ -487,17 +542,13 @@ void SwHeaderFooterWin::ExecuteCommand(std::string_view 
rIdent)
     }
 }
 
-void SwHeaderFooterWin::SetReadonly( bool bReadonly )
-{
-    ShowAll( !bReadonly );
-}
-
 IMPL_LINK_NOARG(SwHeaderFooterWin, ClickHdl, weld::Button&, void)
 {
-    SwView& rView = GetEditWin()->GetView();
+    SwView& rView = m_pEditWin->GetView();
     SwWrtShell& rSh = rView.GetWrtShell();
 
-    const OUString& rStyleName = GetPageFrame()->GetPageDesc()->GetName();
+    const SwPageFrame* pPageFrame = 
SwFrameMenuButtonBase::GetPageFrame(m_pFrame);
+    const OUString& rStyleName = pPageFrame->GetPageDesc()->GetName();
     rSh.ChangeHeaderOrFooter( rStyleName, m_bIsHeader, true, false );
 
     m_xPushButton->hide();
@@ -520,12 +571,10 @@ IMPL_LINK_NOARG(SwHeaderFooterWin, FadeHandler, Timer *, 
void)
     if (m_nFadeRate != 100 && !IsVisible())
     {
         Show();
-        m_pLine->Show();
     }
     else if (m_nFadeRate == 100 && IsVisible())
     {
         Show(false);
-        m_pLine->Show(false);
     }
     else
         PaintButton();
diff --git a/sw/source/uibase/inc/HeaderFooterWin.hxx 
b/sw/source/uibase/inc/HeaderFooterWin.hxx
index d91f35edcc74..54d8136f69fe 100644
--- a/sw/source/uibase/inc/HeaderFooterWin.hxx
+++ b/sw/source/uibase/inc/HeaderFooterWin.hxx
@@ -10,6 +10,7 @@
 #define INCLUDED_SW_SOURCE_UIBASE_INC_HEADERFOOTERWIN_HXX
 
 #include "edtwin.hxx"
+#include "DashedLine.hxx"
 #include "FrameControl.hxx"
 #include <vcl/timer.hxx>
 #include <drawinglayer/primitive2d/Primitive2DContainer.hxx>
@@ -26,39 +27,68 @@ public:
                             const tools::Rectangle& rRect, bool bOnTop);
 };
 
+class SwHeaderFooterWin;
+
 /** Class for the header and footer separator control window.
 
     This control is showing the header / footer style name and provides
     a few useful actions to the user.
   */
-class SwHeaderFooterWin final : public SwFrameMenuButtonBase
+class SwHeaderFooterDashedLine : public SwDashedLine, public ISwFrameControl
+{
+private:
+    VclPtr<SwHeaderFooterWin> m_pWin;
+    VclPtr<SwEditWin> m_pEditWin;
+    const SwFrame* m_pFrame;
+    bool m_bIsHeader;
+
+    void EnsureWin();
+
+    bool IsOnScreen();
+
+public:
+    SwHeaderFooterDashedLine(SwEditWin* pEditWin, const SwFrame *pFrame, bool 
bIsHeader);
+
+    virtual ~SwHeaderFooterDashedLine() override { disposeOnce(); }
+    virtual void dispose() override { m_pWin.disposeAndClear(); 
m_pEditWin.clear(); SwDashedLine::dispose(); }
+
+    virtual const SwFrame* GetFrame() override { return m_pFrame; }
+    virtual SwEditWin* GetEditWin() override { return m_pEditWin; }
+    virtual void ShowAll(bool bShow) override;
+    virtual bool Contains(const Point &rDocPt) const override;
+    virtual void SetReadonly(bool bReadonly) override;
+
+    void SetOffset( Point aOffset, tools::Long nXLineStart, tools::Long 
nXLineEnd );
+    bool IsHeader() const { return m_bIsHeader; };
+};
+
+class SwHeaderFooterWin final : public InterimItemWindow
 {
     std::unique_ptr<weld::MenuButton> m_xMenuButton;
     std::unique_ptr<weld::Button> m_xPushButton;
+    VclPtr<SwEditWin>     m_pEditWin;
+    VclPtr<VirtualDevice> m_xVirDev;
+    const SwFrame*        m_pFrame;
     OUString              m_sLabel;
     bool                  m_bIsHeader;
-    VclPtr<vcl::Window>   m_pLine;
     bool                  m_bIsAppearing;
     int                   m_nFadeRate;
     Timer                 m_aFadeTimer;
 
 public:
-    SwHeaderFooterWin( SwEditWin *pEditWin, const SwFrame *pFrame, bool 
bHeader );
+    SwHeaderFooterWin(SwEditWin *pEditWin, const SwFrame *pFrame, bool 
bHeader);
     virtual ~SwHeaderFooterWin( ) override;
     virtual void dispose() override;
 
-    void SetOffset( Point aOffset, tools::Long nXLineStart, tools::Long 
nXLineEnd );
-
-    virtual void ShowAll( bool bShow ) override;
-    virtual bool Contains( const Point &rDocPt ) const override;
+    void SetOffset(Point aOffset);
+    void ShowAll(bool bShow);
+    bool Contains(const Point &rDocPt) const;
 
     bool IsHeader() const { return m_bIsHeader; };
     bool IsEmptyHeaderFooter( ) const;
 
     void ExecuteCommand(std::string_view rIdent);
 
-    void SetReadonly( bool bReadonly ) override;
-
 private:
     DECL_LINK(FadeHandler, Timer *, void);
     DECL_LINK(ClickHdl, weld::Button&, void);

Reply via email to