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.stahl@allotropia.de>
diff --git a/sw/source/uibase/docvw/FrameControlsManager.cxx b/sw/source/uibase/docvw/FrameControlsManager.cxx
index bb2733a..03252fa 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 24f4102..07ce071 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 d91f35e..54d8136 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);