1
0
Fork 0
libreoffice/sw/source/core/tox/ToxTabStopTokenHandler.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

168 lines
6.2 KiB
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/.
*/
#include <ToxTabStopTokenHandler.hxx>
#include <editeng/tstpitem.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/boxitem.hxx>
#include <cntfrm.hxx>
#include <fmtfsize.hxx>
#include <fmtpdsc.hxx>
#include <frmfmt.hxx>
#include <frmatr.hxx>
#include <frmtool.hxx>
#include <ndtxt.hxx>
#include <pagedesc.hxx>
#include <pagefrm.hxx>
#include <swrect.hxx>
#include <tox.hxx>
namespace sw {
DefaultToxTabStopTokenHandler::DefaultToxTabStopTokenHandler(SwNodeOffset indexOfSectionNode,
const SwPageDesc& defaultPageDescription,
bool tabPositionIsRelativeToParagraphIndent,
TabStopReferencePolicy referencePolicy)
: mIndexOfSectionNode(indexOfSectionNode),
mDefaultPageDescription(defaultPageDescription),
mTabPositionIsRelativeToParagraphIndent(tabPositionIsRelativeToParagraphIndent),
mTabStopReferencePolicy(referencePolicy)
{
}
ToxTabStopTokenHandler::HandledTabStopToken
DefaultToxTabStopTokenHandler::HandleTabStopToken(
const SwFormToken& aToken, const SwTextNode& targetNode) const
{
HandledTabStopToken result;
if (aToken.bWithTab) { // #i21237#
result.text = "\t";
}
// check whether a tab adjustment has been specified.
if (SvxTabAdjust::End > aToken.eTabAlign) {
SvxTextLeftMarginItem const& rTextLeftMargin(
targetNode.SwContentNode::GetAttr(RES_MARGIN_TEXTLEFT));
tools::Long nTabPosition = aToken.nTabStopPosition;
if (!mTabPositionIsRelativeToParagraphIndent && rTextLeftMargin.ResolveTextLeft({}) != 0)
{
nTabPosition -= rTextLeftMargin.ResolveTextLeft({});
}
result.tabStop = SvxTabStop(nTabPosition, aToken.eTabAlign, cDfltDecimalChar, aToken.cTabFillChar);
return result;
}
// note: this will be filled later by CalcEndStop()
result.tabStop = SvxTabStop(0, SvxTabAdjust::Right, cDfltDecimalChar, aToken.cTabFillChar);
return result;
}
auto DefaultToxTabStopTokenHandler::CalcEndStop(SwTextNode const& rNode,
SwRootFrame const*const pLayout) const -> tools::Long
{
tools::Long nRightMargin;
if (CanUseLayoutRectangle(rNode, pLayout))
{
// in case it's in a header, any frame should do
SwContentFrame const*const pFrame(rNode.getLayoutFrame(pLayout));
assert(pFrame); // created in SwTOXBaseSection::Update()
SwRectFnSet const fnRect(pFrame->GetUpper());
SwRect rect = pFrame->getFramePrintArea();
if (fnRect.GetWidth(rect) == 0) // typically it's newly created
{
if (pFrame->GetUpper()->IsSctFrame())
{ // this is set in SwSectionFrame::Init()
rect = pFrame->GetUpper()->GetUpper()->getFramePrintArea();
assert(fnRect.GetWidth(rect) != 0);
}
else if (pFrame->GetUpper()->IsColBodyFrame())
{
SwFrame const*const pColFrame(pFrame->GetUpper()->GetUpper());
assert(pColFrame->IsColumnFrame());
rect = pColFrame->getFrameArea();
// getFramePrintArea() is not valid yet, manually subtract...
// (it can have a border too!)
SwBorderAttrAccess access(SwFrame::GetCache(), pColFrame);
SwBorderAttrs const& rAttrs(*access.Get());
auto const nLeft(rAttrs.CalcLeft(pColFrame));
auto const nRight(rAttrs.CalcRight(pColFrame));
fnRect.SetWidth(rect, fnRect.GetWidth(rect) - nLeft - nRight);
assert(fnRect.GetWidth(rect) != 0);
}
else assert(false);
}
nRightMargin = fnRect.GetWidth(rect);
}
else
{
nRightMargin = CalculatePageMarginFromPageDescription(rNode);
}
//#i24363# tab stops relative to indent
if (mTabStopReferencePolicy == TABSTOPS_RELATIVE_TO_INDENT) {
// left margin of paragraph style
SvxFirstLineIndentItem const& rFirstLine(
rNode.GetTextColl()->GetFirstLineIndent());
SvxTextLeftMarginItem const& rTextLeftMargin(
rNode.GetTextColl()->GetTextLeftMargin());
nRightMargin -= rTextLeftMargin.ResolveLeft(rFirstLine, /*metrics*/ {});
nRightMargin -= rFirstLine.ResolveTextFirstLineOffset(/*metrics*/ {});
}
return nRightMargin - 1; // subtract 1 twip to avoid equal for TabOverMargin
}
tools::Long
DefaultToxTabStopTokenHandler::CalculatePageMarginFromPageDescription(const SwTextNode& targetNode) const
{
SwNodeOffset nPgDescNdIdx = targetNode.GetIndex() + 1;
const SwPageDesc *pPageDesc = targetNode.FindPageDesc(&nPgDescNdIdx);
if (!pPageDesc || nPgDescNdIdx < mIndexOfSectionNode) {
// Use default page description, if none is found or the found one is given by a Node before the
// table-of-content section.
pPageDesc = &mDefaultPageDescription;
}
const SwFrameFormat& rPgDscFormat = pPageDesc->GetMaster();
tools::Long result = rPgDscFormat.GetFrameSize().GetWidth()
- rPgDscFormat.GetLRSpace().ResolveLeft({})
- rPgDscFormat.GetLRSpace().ResolveRight({});
// Also consider borders
const SvxBoxItem& rBox = rPgDscFormat.GetBox();
result -= rBox.CalcLineSpace(SvxBoxItemLine::LEFT) + rBox.CalcLineSpace(SvxBoxItemLine::RIGHT);
return result;
}
/*static*/ bool
DefaultToxTabStopTokenHandler::CanUseLayoutRectangle(const SwTextNode& targetNode, const SwRootFrame *currentLayout)
{
const SwPageDesc* pageDescription =
targetNode.SwContentNode::GetAttr(RES_PAGEDESC).GetPageDesc();
if (!pageDescription) {
return true;
}
const SwFrame* pFrame = targetNode.getLayoutFrame(currentLayout);
if (!pFrame) {
return false;
}
pFrame = pFrame->FindPageFrame();
if (!pFrame) {
return false;
}
const SwPageFrame* pageFrame = static_cast<const SwPageFrame*>(pFrame);
return pageDescription == pageFrame->GetPageDesc();
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */