/* -*- 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 .
*/
SwTextNode const& GetAttrMerged(SfxItemSet & rFormatSet,
SwTextNode const& rNode, SwRootFrame const*const pLayout)
{
rNode.SwContentNode::GetAttr(rFormatSet); if (pLayout && pLayout->HasMergedParas())
{ auto pFrame = static_cast<SwTextFrame*>(rNode.getLayoutFrame(pLayout)); if (sw::MergedPara const*const pMerged = pFrame ? pFrame->GetMergedPara() : nullptr)
{ if (pMerged->pFirstNode != &rNode)
{
rFormatSet.ClearItem(RES_PAGEDESC);
rFormatSet.ClearItem(RES_BREAK);
static_assert(RES_PAGEDESC + 1 == sal_uInt16(RES_BREAK), "first-node items must be adjacent");
SfxItemSetFixed<RES_PAGEDESC, RES_BREAK> firstSet(*rFormatSet.GetPool());
pMerged->pFirstNode->SwContentNode::GetAttr(firstSet);
rFormatSet.Put(firstSet);
} if (pMerged->pParaPropsNode != &rNode)
{ for (sal_uInt16 i = RES_PARATR_BEGIN; i != RES_FRMATR_END; ++i)
{ if (i != RES_PAGEDESC && i != RES_BREAK)
{
rFormatSet.ClearItem(i);
}
} for (sal_uInt16 i = XATTR_FILL_FIRST; i <= XATTR_FILL_LAST; ++i)
{
rFormatSet.ClearItem(i);
}
SfxItemSetFixed<RES_PARATR_BEGIN, RES_PAGEDESC,
RES_BREAK+1, RES_FRMATR_END,
XATTR_FILL_FIRST, XATTR_FILL_LAST+1>
propsSet(*rFormatSet.GetPool());
pMerged->pParaPropsNode->SwContentNode::GetAttr(propsSet);
rFormatSet.Put(propsSet); return *pMerged->pParaPropsNode;
} // keep all the CHRATR/UNKNOWNATR anyway...
}
} return rNode;
}
} // namespace sw
/// Switches width and height of the text frame void SwTextFrame::SwapWidthAndHeight()
{
{
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
/** * Calculates the coordinates of a rectangle when switching from * horizontal to vertical layout.
*/ void SwTextFrame::SwitchHorizontalToVertical( SwRect& rRect ) const
{ // calc offset inside frame
tools::Long nOfstX, nOfstY; if ( IsVertLR() )
{ if (IsVertLRBT())
{ // X and Y offsets here mean the position of the point that will be the top left corner // after the switch.
nOfstX = rRect.Left() + rRect.Width() - getFrameArea().Left();
nOfstY = rRect.Top() - getFrameArea().Top();
} else
{
nOfstX = rRect.Left() - getFrameArea().Left();
nOfstY = rRect.Top() - getFrameArea().Top();
}
} else
{
nOfstX = rRect.Left() - getFrameArea().Left();
nOfstY = rRect.Top() + rRect.Height() - getFrameArea().Top();
}
/** * Calculates the coordinates of a point when switching from * horizontal to vertical layout.
*/ void SwTextFrame::SwitchHorizontalToVertical( Point& rPoint ) const
{ if (IsVertLRBT())
{ // The horizontal origo is the top left corner, the LRBT origo is the // bottom left corner. Finally x and y has to be swapped.
SAL_WARN_IF(!mbIsSwapped, "sw.core", "SwTextFrame::SwitchHorizontalToVertical, IsVertLRBT, not swapped");
Point aPoint(rPoint);
rPoint.setX(getFrameArea().Left() + (aPoint.Y() - getFrameArea().Top())); // This would be bottom - x delta, but bottom is top + height, finally // width (and not height), as it's swapped.
rPoint.setY(getFrameArea().Top() + getFrameArea().Width()
- (aPoint.X() - getFrameArea().Left())); return;
}
/** * Calculates the a limit value when switching from * horizontal to vertical layout.
*/
tools::Long SwTextFrame::SwitchHorizontalToVertical( tools::Long nLimit ) const
{
Point aTmp( 0, nLimit );
SwitchHorizontalToVertical( aTmp ); return aTmp.X();
}
/** * Calculates the coordinates of a rectangle when switching from * vertical to horizontal layout.
*/ void SwTextFrame::SwitchVerticalToHorizontal( SwRect& rRect ) const
{
tools::Long nOfstX;
/** * Calculates the coordinates of a point when switching from * vertical to horizontal layout.
*/ void SwTextFrame::SwitchVerticalToHorizontal( Point& rPoint ) const
{
tools::Long nOfstX;
// calc offset inside frame if ( IsVertLR() ) // X offset is Y - left.
nOfstX = rPoint.X() - getFrameArea().Left(); else
{ // X offset is right - X. if ( mbIsSwapped )
nOfstX = getFrameArea().Left() + getFrameArea().Height() - rPoint.X(); else
nOfstX = getFrameArea().Left() + getFrameArea().Width() - rPoint.X();
}
tools::Long nOfstY; if (IsVertLRBT())
{ // Y offset is bottom - Y. if (mbIsSwapped)
nOfstY = getFrameArea().Top() + getFrameArea().Width() - rPoint.Y(); else
nOfstY = getFrameArea().Top() + getFrameArea().Height() - rPoint.Y();
} else // Y offset is Y - top.
nOfstY = rPoint.Y() - getFrameArea().Top();
/** * Calculates the a limit value when switching from * vertical to horizontal layout.
*/
tools::Long SwTextFrame::SwitchVerticalToHorizontal( tools::Long nLimit ) const
{
Point aTmp( nLimit, 0 );
SwitchVerticalToHorizontal( aTmp ); return aTmp.Y();
}
void SwTextFrame::Init()
{
OSL_ENSURE( !IsLocked(), "+SwTextFrame::Init: this is locked." ); if( !IsLocked() )
{
ClearPara();
SetHasRotatedPortions(false); // set flags directly to save a ResetPreps call, // and thereby an unnecessary GetPara call // don't set bOrphan, bLocked or bWait to false! // bOrphan = bFlag7 = bFlag8 = false;
}
}
void RemoveFootnotesForNode(
SwRootFrame const& rLayout, SwTextNode const& rTextNode,
std::vector<std::pair<sal_Int32, sal_Int32>> const*const pExtents)
{ if (pExtents && pExtents->empty())
{ return; // nothing to do
} const SwFootnoteIdxs &rFootnoteIdxs = rTextNode.GetDoc().GetFootnoteIdxs();
size_t nPos = 0;
SwNodeOffset const nIndex = rTextNode.GetIndex();
rFootnoteIdxs.SeekEntry( rTextNode, &nPos ); if (nPos < rFootnoteIdxs.size())
{ while (nPos > 0 && rTextNode == (rFootnoteIdxs[ nPos ]->GetTextNode()))
--nPos; if (nPos || rTextNode != (rFootnoteIdxs[ nPos ]->GetTextNode()))
++nPos;
}
size_t iter(0); for ( ; nPos < rFootnoteIdxs.size(); ++nPos)
{
SwTextFootnote* pTextFootnote = rFootnoteIdxs[ nPos ]; if (pTextFootnote->GetTextNode().GetIndex() > nIndex) break; if (pExtents)
{ while ((*pExtents)[iter].second <= pTextFootnote->GetStart())
{
++iter; if (iter == pExtents->size())
{ return;
}
} if (pTextFootnote->GetStart() < (*pExtents)[iter].first)
{ continue;
}
}
pTextFootnote->DelFrames(&rLayout);
}
}
} // namespace sw
void SwTextFrame::DestroyImpl()
{ // Remove associated SwParaPortion from s_pTextCache
ClearPara();
assert(!GetDoc().IsInDtor()); // this shouldn't be happening with ViewShell owning layout if (!GetDoc().IsInDtor() && HasFootnote())
{ if (m_pMergedPara)
{
SwTextNode const* pNode(nullptr); for (autoconst& e : m_pMergedPara->extents)
{ if (e.pNode != pNode)
{
pNode = e.pNode; // sw_redlinehide: not sure if it's necessary to check // if the nodes are still alive here, which would require // accessing WriterMultiListener::m_vDepends
sw::RemoveFootnotesForNode(*getRootFrame(), *pNode, nullptr);
}
}
} else
{
SwTextNode *const pNode(static_cast<SwTextNode*>(GetDep())); if (pNode)
{
sw::RemoveFootnotesForNode(*getRootFrame(), *pNode, nullptr);
}
}
}
if (!GetDoc().IsInDtor())
{ if (SwView* pView = GetActiveView())
pView->GetEditWin().GetFrameControlsManager().RemoveControls(this);
}
SwTextNode const* SwTextFrame::GetTextNodeForParaProps() const
{ // FIXME can GetPara be 0 ? yes... this is needed in SwContentNotify::SwContentNotify() which is called before any formatting is started //nope assert(GetPara());
sw::MergedPara const*const pMerged(GetMergedPara()); if (pMerged)
{ // assert(pMerged->pFirstNode == pMerged->pParaPropsNode); // surprising news! return pMerged->pParaPropsNode;
} else returnstatic_cast<SwTextNode const*>(SwFrame::GetDep());
}
// TODO: what is the above check good for and can it be removed? return IsHiddenNowImpl();
}
bool SwTextFrame::IsHiddenNowImpl() const
{ if (SwContentFrame::IsHiddenNow()) returntrue;
bool bHiddenCharsHidePara(false); bool bHiddenParaField(false); if (m_pMergedPara)
{
TextFrameIndex nHiddenStart(COMPLETE_STRING);
TextFrameIndex nHiddenEnd(0); bool hasHidden{false}; if (autoconst pScriptInfo = GetScriptInfo())
{
hasHidden = pScriptInfo->GetBoundsOfHiddenRange(TextFrameIndex(0),
nHiddenStart, nHiddenEnd);
} else// ParaPortion is created in Format, but this is called earlier
{
SwScriptInfo aInfo;
aInfo.InitScriptInfoHidden(*m_pMergedPara->pFirstNode, m_pMergedPara.get());
hasHidden = aInfo.GetBoundsOfHiddenRange(TextFrameIndex(0),
nHiddenStart, nHiddenEnd);
} if ((TextFrameIndex(0) == nHiddenStart
&& TextFrameIndex(GetText().getLength()) <= nHiddenEnd) // special case: GetBoundsOfHiddenRange doesn't assign! // but it does return that there *is* something hidden, in case // the frame is empty then the whole thing must be hidden
|| (hasHidden && m_pMergedPara->mergedText.isEmpty()))
{
bHiddenCharsHidePara = true;
}
sw::MergedAttrIter iter(*this);
SwTextNode const* pNode(nullptr); int nNewResultWeight = 0; for (SwTextAttr const* pHint = iter.NextAttr(&pNode); pHint; pHint = iter.NextAttr(&pNode))
{ if (pHint->Which() == RES_TXTATR_FIELD)
{ // see also SwpHints::CalcHiddenParaField() const SwFormatField& rField = pHint->GetFormatField(); int nCurWeight = pNode->GetDoc().FieldCanHideParaWeight(rField.GetField()->GetTyp()->Which()); if (nCurWeight > nNewResultWeight)
{
nNewResultWeight = nCurWeight;
bHiddenParaField = pNode->GetDoc().FieldHidesPara(*rField.GetField());
} elseif (nCurWeight == nNewResultWeight && bHiddenParaField)
{ // Currently, for both supported hiding types (HiddenPara, Database), "Don't hide" // takes precedence - i.e., if there's a "Don't hide" field of that weight, we only // care about fields of higher weight.
bHiddenParaField = pNode->GetDoc().FieldHidesPara(*rField.GetField());
}
}
}
} else
{
bHiddenCharsHidePara = static_cast<SwTextNode const*>(SwFrame::GetDep())->HasHiddenCharAttribute( true );
bHiddenParaField = static_cast<SwTextNode const*>(SwFrame::GetDep())->IsHiddenByParaField();
} if (bHiddenCharsHidePara && GetDoc().getIDocumentSettingAccess().get(
DocumentSettingId::APPLY_PARAGRAPH_MARK_FORMAT_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH))
{ // apparently in Word it's always the last para marker that determines hidden? // even in case when they are merged by delete redline (it's obvious when they are merged by hidden-attribute
SwTextNode const*const pNode{ m_pMergedPara
? m_pMergedPara->pLastNode
: static_cast<SwTextNode const*>(SwFrame::GetDep()) }; // Word ignores hidden formatting on the cell end marker bool isLastInCell{false}; if (SwLayoutFrame const*const pCellFrame{FindCellFrame(this)})
{
SwContentFrame const* pNext{GetNextContentFrame()}; // skip frame in hidden section ("this" is *not* in hidden section!) while (pNext && pNext->SwContentFrame::IsHiddenNow())
{
pNext = pNext->GetNextContentFrame();
}
isLastInCell = pNext == nullptr || !pCellFrame->IsAnLower(pNext);
} if (!isLastInCell)
{
SwFormatAutoFormat const& rListAutoFormat{pNode->GetAttr(RES_PARATR_LIST_AUTOFMT)};
std::shared_ptr<SfxItemSet> const pSet{rListAutoFormat.GetStyleHandle()};
SvxCharHiddenItem const* pItem{pSet ? pSet->GetItemIfSet(RES_CHRATR_HIDDEN) : nullptr}; if (!pItem)
{ // don't use node's mpAttrSet, it doesn't apply to para marker
SwFormatColl const*const pStyle{pNode->GetFormatColl()}; if (pStyle)
{
pItem = &pStyle->GetFormatAttr(RES_CHRATR_HIDDEN);
}
} if (!pItem || !pItem->GetValue())
{
bHiddenCharsHidePara = false;
}
}
} const SwViewShell* pVsh = getRootFrame()->GetCurrShell();
if (
( bHiddenParaField &&
( !pVsh->GetViewOptions()->IsShowHiddenPara() &&
!pVsh->GetViewOptions()->IsFieldName() ) ) ||
( bHiddenCharsHidePara &&
!pVsh->GetViewOptions()->IsShowHiddenChar() ) )
{ // in order to put the cursor in the body text, one paragraph must // be visible - check this for the 1st body paragraph if (IsInDocBody() && FindPrevCnt() == nullptr)
{ for (SwContentFrame const* pNext = FindNextCnt(true);
pNext != nullptr; pNext = pNext->FindNextCnt(true))
{ if (!pNext->IsHiddenNow()) returntrue;
}
SAL_INFO("sw.core", "unhiding one body paragraph"); returnfalse;
} returntrue;
}
}
returnfalse;
}
/// Removes Textfrm's attachments, when it's hidden void SwTextFrame::HideHidden()
{
OSL_ENSURE( !GetFollow() && IsHiddenNow(), "HideHidden on visible frame of hidden frame has follow" );
/** * as-character anchored graphics, which are used for a graphic bullet list. * As long as these graphic bullet list aren't imported, do not hide a * at-character anchored object, if * (a) the document is an imported WW8 document - * checked by checking certain compatibility options - * (b) the paragraph is the last content in the document and * (c) the anchor character is an as-character anchored graphic.
*/ bool sw_HideObj( const SwTextFrame& _rFrame, const RndStdIds _eAnchorType,
SwFormatAnchor const& rFormatAnchor,
SwAnchoredObject* _pAnchoredObj )
{ bool bRet( true );
/** * Hide/show objects * * Method hides respectively shows objects, which are anchored at paragraph, * at/as a character of the paragraph, corresponding to the paragraph and * paragraph portion visibility. * * - is called from HideHidden() - should hide objects in hidden paragraphs and * - from Format_() - should hide/show objects in partly visible paragraphs
*/ void SwTextFrame::HideAndShowObjects()
{ if ( GetDrawObjs() )
{ if ( IsHiddenNow() )
{ // complete paragraph is hidden. Thus, hide all objects for (SwAnchoredObject* i : *GetDrawObjs())
{
SdrObject* pObj = i->DrawObj();
SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall()); // under certain conditions const RndStdIds eAnchorType( pContact->GetAnchorId() ); if ((eAnchorType != RndStdIds::FLY_AT_CHAR) ||
sw_HideObj(*this, eAnchorType, pContact->GetAnchorFormat(),
i ))
{
pContact->MoveObjToInvisibleLayer( pObj );
}
}
} else
{ // paragraph is visible, but can contain hidden text portion. // first we check if objects are allowed to be hidden: const SwViewShell* pVsh = getRootFrame()->GetCurrShell(); constbool bShouldBeHidden = !pVsh || !pVsh->GetWin() ||
!pVsh->GetViewOptions()->IsShowHiddenChar();
// Thus, show all objects, which are anchored at paragraph and // hide/show objects, which are anchored at/as character, according // to the visibility of the anchor character. for (SwAnchoredObject* i : *GetDrawObjs())
{
SdrObject* pObj = i->DrawObj();
SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall()); // Determine anchor type only once const RndStdIds eAnchorType( pContact->GetAnchorId() );
if (eAnchorType == RndStdIds::FLY_AT_PARA)
{
pContact->MoveObjToVisibleLayer( pObj );
} elseif ((eAnchorType == RndStdIds::FLY_AT_CHAR) ||
(eAnchorType == RndStdIds::FLY_AS_CHAR))
{
sal_Int32 nHiddenStart;
sal_Int32 nHiddenEnd; const SwFormatAnchor& rAnchorFormat = pContact->GetAnchorFormat(); const SwNode* pNode = rAnchorFormat.GetAnchorNode(); // When the object was already removed from text, but the layout hasn't been // updated yet, this can be nullptr: if (!pNode) continue;
SwScriptInfo::GetBoundsOfHiddenRange(
*pNode->GetTextNode(),
rAnchorFormat.GetAnchorContentOffset(), nHiddenStart, nHiddenEnd); // Under certain conditions if ( nHiddenStart != COMPLETE_STRING && bShouldBeHidden &&
sw_HideObj(*this, eAnchorType, rAnchorFormat, i))
{
pContact->MoveObjToInvisibleLayer( pObj );
} else
pContact->MoveObjToVisibleLayer( pObj );
} else
{
OSL_FAIL( " - object not anchored at/inside paragraph!?" );
}
}
}
}
if (IsFollow())
{
SwTextFrame *pMaster = FindMaster();
OSL_ENSURE(pMaster, "SwTextFrame without master"); if (pMaster)
pMaster->HideAndShowObjects();
}
}
/** * Returns the first possible break point in the current line. * This method is used in SwTextFrame::Format() to decide whether the previous * line has to be formatted as well. * nFound is <= nEndLine.
*/
--> --------------------
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.