// NOTE: call <SwSectionFrame::Init()> directly after creation of a new section // frame and its insert in the layout. void SwSectionFrame::Init()
{
assert(GetUpper() && "SwSectionFrame::Init before insertion?!");
SwRectFnSet aRectFnSet(this);
tools::Long nWidth = aRectFnSet.GetWidth(GetUpper()->getFramePrintArea());
void SwSectionFrame::DestroyImpl()
{ if( GetFormat() && !GetFormat()->GetDoc().IsInDtor() )
{
SwRootFrame *pRootFrame = getRootFrame(); if( pRootFrame )
pRootFrame->RemoveFromList( this ); if( IsFollow() )
{
SwSectionFrame *pMaster = FindMaster(); if( pMaster )
{
PROTOCOL( this, PROT::Section, DbgAction::DelFollow, pMaster )
pMaster->SetFollow( GetFollow() ); // A Master always grabs the space until the lower edge of his // Upper. If he doesn't have a Follow anymore, he can // release it, which is why the Size of the Master is // invalidated. if( !GetFollow() )
pMaster->InvalidateSize();
}
} #ifdefined DBG_UTIL elseif( HasFollow() )
{
PROTOCOL( this, PROT::Section, DbgAction::DelMaster, GetFollow() )
} #endif
}
// If we are destroyed immediately anyway, we don't need // to put us into the list if( bRemove )
{ // If we already were half dead before this DelEmpty, // we are likely in the list and have to remove us from // it if( !m_pSection && getRootFrame() )
getRootFrame()->RemoveFromList( this );
} elseif( getRootFrame() )
{
getRootFrame()->InsertEmptySct( this );
}
m_pSection = nullptr; // like this a reanimation is virtually impossible though
}
SwPageFrame *pPage = FindPageFrame();
InvalidatePage( pPage );
SwFrame *pFrame = GetNext();
SwFrame* pPrepFrame = nullptr; while( pFrame && pFrame->IsSctFrame() && !static_cast<SwSectionFrame*>(pFrame)->GetSection() )
pFrame = pFrame->GetNext(); if( pFrame )
{ // The former successor might have calculated a gap to the predecessor // which is now obsolete since he becomes the first
pFrame->InvalidatePrt_();
pFrame->InvalidatePos_(); if( pFrame->IsSctFrame() )
pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny(); if ( pFrame && pFrame->IsContentFrame() )
{
pFrame->InvalidatePage( pPage ); if( IsInFootnote() && !GetIndPrev() )
pPrepFrame = pFrame;
}
} else
{
InvalidateNextPos(); // Someone has to take over the retouching: predecessor or Upper
pFrame = GetPrev(); if ( nullptr != pFrame )
{
pFrame->SetRetouche();
pFrame->Prepare( PrepareHint::WidowsOrphans ); if ( pFrame->IsContentFrame() )
pFrame->InvalidatePage( pPage );
} // If I am (was) the only FlowFrame in my Upper, then he has to take over // the retouching. // Furthermore a blank page could have emerged else
{ SwRootFrame *pRoot = static_cast<SwRootFrame*>(pPage->GetUpper());
pRoot->SetSuperfluous();
GetUpper()->SetCompletePaint();
}
} // First remove, then shrink Upper
SwLayoutFrame *pUp = GetUpper(); if( bRemove )
{
RemoveFromLayout(); if( pUp && !pUp->Lower() && pUp->IsFootnoteFrame() && !pUp->IsColLocked() &&
pUp->GetUpper() )
{
pUp->Cut();
SwFrame::DestroyFrame(pUp);
pUp = nullptr;
}
} if( pPrepFrame )
pPrepFrame->Prepare( PrepareHint::FootnoteInvalidation ); if ( !pUp ) return;
void SwSectionFrame::Paste( SwFrame* pParent, SwFrame* pSibling )
{
OSL_ENSURE( pParent, "No parent for Paste()." );
OSL_ENSURE( pParent->IsLayoutFrame(), "Parent is ContentFrame." );
OSL_ENSURE( pParent != this, "I'm my own parent." );
OSL_ENSURE( pSibling != this, "I'm my own neighbour." );
OSL_ENSURE( !GetPrev() && !GetUpper(), "I am still registered somewhere." );
// Add to the tree
SwSectionFrame* pSect = pParent->FindSctFrame(); // Assure that parent is not inside a table frame, which is inside the found section frame. if ( pSect )
{
SwTabFrame* pTableFrame = pParent->FindTabFrame(); if ( pTableFrame &&
pSect->IsAnLower( pTableFrame ) )
{
pSect = nullptr;
}
}
SwRectFnSet aRectFnSet(pParent); if( pSect && HasToBreak( pSect ) )
{ if( pParent->IsColBodyFrame() ) // dealing with a single-column area
{ // If we are coincidentally at the end of a column, pSibling // has to point to the first frame of the next column in order // for the content of the next column to be moved correctly to the // newly created pSect by the InsertGroup
SwColumnFrame *pCol = static_cast<SwColumnFrame*>(pParent->GetUpper()); while( !pSibling && nullptr != ( pCol = static_cast<SwColumnFrame*>(pCol->GetNext()) ) )
pSibling = static_cast<SwLayoutFrame*>(pCol->Lower())->Lower(); if( pSibling )
{ // Even worse: every following column content has to // be attached to the pSibling-chain in order to be // taken along
SwFrame *pTmp = pSibling; while ( nullptr != ( pCol = static_cast<SwColumnFrame*>(pCol->GetNext()) ) )
{ while ( pTmp->GetNext() )
pTmp = pTmp->GetNext();
SwFrame* pSave = ::SaveContent( pCol ); if (pSave)
::RestoreContent( pSave, pSibling->GetUpper(), pTmp );
}
}
}
pParent = pSect;
pSect = new SwSectionFrame( *static_cast<SwSectionFrame*>(pParent)->GetSection(), pParent ); // if pParent is decomposed into two parts, its Follow has to be attached // to the new second part
pSect->SetFollow( static_cast<SwSectionFrame*>(pParent)->GetFollow() ); static_cast<SwSectionFrame*>(pParent)->SetFollow( nullptr ); if( pSect->GetFollow() )
pParent->InvalidateSize_();
/** |*DividesaSectionFrameintotwoparts.Thecontentofthesecondone |*startsafterpFrameStartAfter;thecreatedsecondsectionframeitself |*isputafterpFramePutAfter. |*IfpFrameStartAfterisnullptr,thesplithappensatthestart. |*Thisisrequiredwheninsertinganinnersection,becausetheMoveFwd |*cannothavethedesiredeffectwithinaframeoratablecell. |*Splittingatthestart/endmakessense,becausetheemptyframewould |*beremovedaftertheInsertCnt_finished.
|*/
SwSectionFrame* SwSectionFrame::SplitSect( SwFrame* pFrameStartAfter, SwFrame* pFramePutAfter )
{
assert(!pFrameStartAfter || IsAnLower(pFrameStartAfter));
SwFrame* pSav; if (pFrameStartAfter)
{
pSav = pFrameStartAfter->FindNext(); // If pFrameStartAfter is a complex object like table, and it has no next, // its FindNext may return its own last subframe. In this case, assume that // we are at the end. if (pSav && pFrameStartAfter->IsLayoutFrame()) if (static_cast<SwLayoutFrame*>(pFrameStartAfter)->IsAnLower(pSav))
pSav = nullptr;
} else
{
pSav = ContainsAny();
} if (pSav && !IsAnLower(pSav))
pSav = nullptr; // we are at the very end
// Put the content aside if (pSav)
pSav = ::SaveContent( this, pSav );
// Create a new SctFrame, not as a Follower/master if (!pFramePutAfter)
pFramePutAfter = this;
SwSectionFrame* pNew = new SwSectionFrame( *GetSection(), this );
pNew->InsertBehind( pFramePutAfter->GetUpper(), pFramePutAfter );
pNew->Init();
SwRectFnSet aRectFnSet(this);
aRectFnSet.MakePos( *pNew, nullptr, pFramePutAfter, true ); // OD 25.03.2003 #108339# - restore content: // determine layout frame for restoring content after the initialization // of the section frame. In the section initialization the columns are // created. if (pSav)
{
SwLayoutFrame* pLay = pNew; // Search for last layout frame, e.g. for columned sections.
SwFrame* pLower = pLay->Lower(); while( pLower && pLower->IsLayoutFrame() )
{
pLay = static_cast<SwLayoutFrame*>(pLower);
pLower = pLay->Lower();
}
::RestoreContent( pSav, pLay, nullptr );
}
InvalidateSize_(); if( HasFollow() )
{
pNew->SetFollow( GetFollow() );
SetFollow( nullptr );
} return pNew;
}
/** |*MoveContentiscalledfordestroyingaSectionFrames,dueto |*thecancellationorhidingofasection,tohandlethecontent. |*IftheSectionFramehasn'tbrokenupanotherone,thenthecontent |*ismovedtotheUpper.Otherwisethecontentismovedtoanother |*SectionFrame,whichhastobepotentiallymerged.
|*/ // If a multi-column section is cancelled, the ContentFrames have to be // invalidated staticvoid lcl_InvalidateInfFlags( SwFrame* pFrame, bool bInva )
{ while ( pFrame )
{
pFrame->InvalidateInfFlags(); if( bInva )
{
pFrame->InvalidatePos_();
pFrame->InvalidateSize_();
pFrame->InvalidatePrt_();
}
pFrame = pFrame->GetNext();
}
}
// Works like SwContentFrame::ImplGetNextContentFrame, but starts with a LayoutFrame static SwContentFrame* lcl_GetNextContentFrame( const SwLayoutFrame* pLay, bool bFwd )
{ if ( bFwd )
{ if ( pLay->GetNext() && pLay->GetNext()->IsContentFrame() ) returnconst_cast<SwContentFrame*>(static_cast<const SwContentFrame*>(pLay->GetNext()));
} else
{ if ( pLay->GetPrev() && pLay->GetPrev()->IsContentFrame() ) returnconst_cast<SwContentFrame*>(static_cast<const SwContentFrame*>(pLay->GetPrev()));
}
/// Checks if pFrame has a parent that can contain a split section frame. bool CanContainSplitSection(const SwFrame* pFrame)
{ if (!pFrame->IsInTab()) returntrue;
// The frame is in a table, see if the table is in a section. bool bRet = !pFrame->FindTabFrame()->IsInSct();
if (bRet)
{ // Don't try to split if the frame itself is a section frame with // multiple columns. if (pFrame->IsSctFrame())
{ const SwFrame* pLower = pFrame->GetLower(); if (pLower && pLower->IsColumnFrame())
bRet = false;
}
}
return bRet;
}
}
void SwSectionFrame::MoveContentAndDelete( SwSectionFrame* pDel, bool bSave )
{ bool bSize = pDel->Lower() && pDel->Lower()->IsColumnFrame();
SwFrame* pPrv = pDel->GetPrev();
SwLayoutFrame* pUp = pDel->GetUpper(); // OD 27.03.2003 #i12711# - initialize local pointer variables.
SwSectionFrame* pPrvSct = nullptr;
SwSectionFrame* pNxtSct = nullptr;
SwSectionFormat* pParent = static_cast<SwSectionFormat*>(pDel->GetFormat())->GetParent(); if( pDel->IsInTab() && pParent )
{
SwTabFrame *pTab = pDel->FindTabFrame(); // If we are within a table, we can only have broken up sections that // are inside as well, but not a section that contains the whole table. if( pTab->IsInSct() && pParent == pTab->FindSctFrame()->GetFormat() )
pParent = nullptr;
} // If our Format has a parent, we have probably broken up another // SectionFrame, which has to be checked. To do so we first acquire the // succeeding and the preceding ContentFrame, let's see if they // lay in the SectionFrames. // OD 27.03.2003 #i12711# - check, if previous and next section belonging // together and can be joined, *not* only if deleted section contains content. if ( pParent )
{
SwFrame* pPrvContent = lcl_GetNextContentFrame( pDel, false );
pPrvSct = pPrvContent ? pPrvContent->FindSctFrame() : nullptr;
SwFrame* pNxtContent = lcl_GetNextContentFrame( pDel, true );
pNxtSct = pNxtContent ? pNxtContent->FindSctFrame() : nullptr;
} else
{
pParent = nullptr;
pPrvSct = pNxtSct = nullptr;
}
// Now the content is put aside and the frame is destroyed
SwFrame *pSave = bSave ? ::SaveContent( pDel ) : nullptr; bool bOldFootnote = true; if( pSave && pUp->IsFootnoteFrame() )
{
bOldFootnote = static_cast<SwFootnoteFrame*>(pUp)->IsColLocked(); static_cast<SwFootnoteFrame*>(pUp)->ColLock();
}
pDel->DelEmpty( true );
SwFrame::DestroyFrame(pDel); if( pParent )
{ // Search for the appropriate insert position if( pNxtSct && pNxtSct->GetFormat() == pParent )
{ // Here we can insert ourselves at the beginning
pUp = FirstLeaf( pNxtSct );
pPrv = nullptr; if( pPrvSct && ( pPrvSct->GetFormat() != pParent ) )
pPrvSct = nullptr; // In order that nothing is merged
} elseif( pPrvSct && pPrvSct->GetFormat() == pParent )
{ // Wonderful, here we can insert ourselves at the end
pUp = pPrvSct;
SwFrame* pLower = pUp->Lower(); if( pLower && pLower->IsColumnFrame() )
{
pUp = static_cast<SwLayoutFrame*>(pUp->GetLastLower()); // The body of the last column
pUp = static_cast<SwLayoutFrame*>(pUp->Lower());
} // In order to perform the insertion after the last one
pPrv = pUp->GetLastLower();
pPrvSct = nullptr; // Such that nothing is merged
} else
{ if( pSave )
{ // Following situations: before and after the section-to-be // deleted there is the section boundary of the enclosing // section, or another (sibling) section connects subsequently, // that derives from the same Parent. // In that case, there's not (yet) a part of our parent available // that can store the content, so we create it here.
pPrvSct = new SwSectionFrame( *pParent->GetSection(), pUp );
pPrvSct->InsertBehind( pUp, pPrv );
pPrvSct->Init();
SwRectFnSet aRectFnSet(pUp);
aRectFnSet.MakePos( *pPrvSct, pUp, pPrv, true );
pUp = FirstLeaf( pPrvSct );
pPrv = nullptr;
}
pPrvSct = nullptr; // Such that nothing will be merged
}
} // The content is going to be inserted... if( pSave )
{
lcl_InvalidateInfFlags( pSave, bSize );
::RestoreContent( pSave, pUp, pPrv );
pUp->FindPageFrame()->InvalidateContent(); if( !bOldFootnote ) static_cast<SwFootnoteFrame*>(pUp)->ColUnlock();
} // Now two parts of the superior section could possibly be merged if( pPrvSct && !pPrvSct->IsJoinLocked() )
{
OSL_ENSURE( pNxtSct, "MoveContent: No Merge" );
pPrvSct->MergeNext( pNxtSct );
}
}
if (getFrameArea().Height() == 0)
{ // SwLayoutFrame::MakeAll() is not called for to-be-deleted // section frames (which would invalidate the position of the // next frame via the SwLayNotify dtor), so call it manually. if (SwFrame* pNext = GetNext())
pNext->InvalidatePos();
}
}
if (!GetPrev() && !IsFollow() && IsInDocBody() && IsHiddenNow())
{ // This may be the first frame on a page, and it may had moved to that page because its // content required that (a page break in the first paragraph, or a tall first line, or // "do not break paragraph" setting, or the like). Try to move back, to allow following // frames to move back, if possible. Sections cannot move back; workaround by a call to // GetPrevSctLeaf(), which may return a candidate upper frame on a previous page, or it // may create a new master for this at the end of the previous page. Cut and paste this // appropriately; then drop the temporary, if needed. if (SwLayoutFrame* moveBackPos = GetPrevSctLeaf())
{ if (moveBackPos->IsColBodyFrame())
{
moveBackPos = moveBackPos->GetUpper()->GetUpper();
}
SwLayoutFrame* newUpper = moveBackPos;
SwFrame* newSibling = nullptr; constbool temporaryMasterCreated = IsFollow(); if (temporaryMasterCreated)
{
assert(moveBackPos == &GetPrecede()->GetFrame());
newUpper = moveBackPos->GetUpper();
newSibling = moveBackPos->GetNext(); // actually, will be also nullptr
} if (newUpper != GetUpper())
{ // Can't use MoveSubTree, because the move needs to fire events to re-layout
Cut();
Paste(newUpper, newSibling);
} if (temporaryMasterCreated)
{
moveBackPos->Cut();
DestroyFrame(moveBackPos);
}
assert(!IsFollow());
}
}
LockJoin(); // I don't let myself to be destroyed on the way
if (GetFollow() && IsHiddenNow())
{ // Merge all the follows of this hidden section while (auto* follow = GetFollow())
{
MergeNext(follow); if (GetFollow() == follow) // failed to merge break; // avoid endless loop
}
}
// OD 2004-03-15 #116561# - In online layout join the follows, if section // can grow. const SwViewShell *pSh = getRootFrame()->GetCurrShell();
// Split sections inside table cells: need to merge all follows of the // section here, as later we won't attempt doing so. bool bCanContainSplitSection = false; if (IsInTab() && GetUpper())
bCanContainSplitSection = CanContainSplitSection(GetUpper());
// A section with Follow uses all the space until the lower edge of the // Upper. If it moves, its size can grow or decrease... if( !isFrameAreaPositionValid() && ToMaximize( false ) )
{
setFrameAreaSizeValid(false);
}
if (IsInTab())
{ // In case the section is in a table, then calculate the lower right // now. Just setting the valid size flag of the lower to false may not // be enough, as lcl_RecalcRow() can call // SwFrame::ValidateThisAndAllLowers(), and then we don't attempt // calculating the proper position of the lower.
SwFrame* pLower = Lower(); if (pLower && !pLower->isFrameAreaPositionValid())
pLower->Calc(pRenderContext);
}
void SwSectionFrame::CollectEndnotes( SwLayouter* pLayouter )
{
OSL_ENSURE( IsColLocked(), "CollectEndnotes: You love the risk?" ); // i73332: Section in footnode does not have columns!
SwFrame* pLower = Lower();
OSL_ENSURE( (pLower && pLower->IsColumnFrame()) || GetUpper()->IsFootnoteFrame(), "Where's my column?" );
SwSectionFrame* pSect = this;
SwFootnoteFrame* pFootnote; bool bEmpty = false; // pSect is the last sectionfrm without endnotes or the this-pointer // the first sectionfrm with endnotes may be destroyed, when the endnotes // is cutted while( nullptr != (pFootnote = lcl_FindEndnote( pSect, bEmpty, pLayouter )) )
pLayouter->CollectEndnote( pFootnote ); if( pLayouter->HasEndnotes() )
lcl_ColumnRefresh( this, true );
}
// OD 18.09.2002 #100522# // Determine, if height has changed. // Note: In vertical layout the height equals the width value. bool bHeightChanged = aRectFnSet.IsVert() ?
(aOldSz.Width() != getFramePrintArea().Width()) :
(aOldSz.Height() != getFramePrintArea().Height()); // Last but not least we have changed the height again, thus the inner // layout (columns) is calculated and the content as well. // OD 18.09.2002 #100522# // calculate content, only if height has changed. // OD 03.11.2003 #i19737# - restriction of content calculation too strong. // If an endnote has an incorrect position or a follow section contains // no content except footnotes/endnotes, the content has also been calculated. if ( !(( bHeightChanged || bExtraCalc ) && Lower()) ) return;
void SwSectionFrame::SimpleFormat()
{ if ( IsJoinLocked() || IsColLocked() ) return;
LockJoin();
SwRectFnSet aRectFnSet(this); if( GetPrev() || GetUpper() )
{ // assure notifications on position changes. const SwLayNotify aNotify( this );
aRectFnSet.MakePos( *this, GetUpper(), GetPrev(), false );
setFrameAreaPositionValid(true);
}
SwTwips nDeadLine = aRectFnSet.GetPrtBottom(*GetUpper()); // OD 22.10.2002 #97265# - call always method <lcl_ColumnRefresh(..)>, in // order to get calculated lowers, not only if there space left in its upper. if (aRectFnSet.BottomDist(getFrameArea(), nDeadLine) >= 0)
{
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.SetBottom( aFrm, nDeadLine );
}
// #i40147# - helper class to perform extra section format // to position anchored objects and to keep the position of whose objects locked. class ExtraFormatToPositionObjs
{ private:
SwSectionFrame* mpSectFrame; bool mbExtraFormatPerformed;
aRectFnSet.SetYMargins( *mpSectFrame, nTopMargin, 0 ); // #i59789# // suppress formatting, if printing area of section is too narrow if ( aRectFnSet.GetHeight(mpSectFrame->getFramePrintArea()) <= 0 )
{ return;
}
mpSectFrame->ChgLowersProp( aOldSectPrtSize );
// format column frames and its body and footnote container
SwColumnFrame* pColFrame = static_cast<SwColumnFrame*>(mpSectFrame->Lower()); while ( pColFrame )
{
pColFrame->Calc(pRenderContext); if (SwFrame* pColLower = pColFrame->Lower())
{
pColLower->Calc(pRenderContext); if ( pColLower->GetNext() )
{
pColLower->GetNext()->Calc(pRenderContext);
}
}
// unlock position of lower floating screen objects for the extra format // #i81555# // Section frame can already have changed the page and its content // can still be on the former page. // Thus, initialize objects via lower-relationship
InitObjs( *mpSectFrame );
// format content - first with collecting its foot-/endnotes before content // format, second without collecting its foot-/endnotes.
::CalcContent( mpSectFrame );
::CalcContent( mpSectFrame, true );
// keep locked position of lower floating screen objects
SwPageFrame* pPageFrame = mpSectFrame->FindPageFrame();
SwSortedObjs* pObjs = pPageFrame ? pPageFrame->GetSortedObjs() : nullptr; if ( pObjs )
{ for (SwAnchoredObject* pAnchoredObj : *pObjs)
{ if ( mpSectFrame->IsAnLower( pAnchoredObj->GetAnchorFrame() ) )
{
pAnchoredObj->SetKeepPosLocked( true );
}
}
}
mbExtraFormatPerformed = true;
}
};
}
/// "formats" the frame; Frame and PrtArea void SwSectionFrame::Format( vcl::RenderContext* pRenderContext, const SwBorderAttrs *pAttr )
{ if( !m_pSection ) // via DelEmpty
{ #ifdef DBG_UTIL
OSL_ENSURE( getRootFrame()->IsInDelList( this ), "SectionFrame without Section" ); #endif
setFrameAreaPositionValid(true);
setFrameAreaSizeValid(true);
setFramePrintAreaValid(true); return;
}
// The size is only determined by the content, if the SectFrame does not have a // Follow. Otherwise it fills (occupies) the Upper down to the lower edge. // It is not responsible for the text flow, but the content is. bool bMaximize = ToMaximize( false );
// OD 2004-05-17 #i28701# - If the wrapping style has to be considered // on object positioning, an extra formatting has to be performed // to determine the correct positions the floating screen objects. // #i40147# // use new helper class <ExtraFormatToPositionObjs>. // This class additionally keep the locked position of the objects // and releases this position lock keeping on destruction.
ExtraFormatToPositionObjs aExtraFormatToPosObjs( *this ); if ( !bMaximize &&
GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) &&
!GetFormat()->GetBalancedColumns().GetValue() )
{
aExtraFormatToPosObjs.FormatSectionToPositionObjs();
}
// Column widths have to be adjusted before calling CheckClipping. // CheckClipping can cause the formatting of the lower frames // which still have a width of 0. constbool bHasColumns = Lower() && Lower()->IsColumnFrame(); if ( bHasColumns && Lower()->GetNext() )
AdjustColumns( nullptr, false );
// OD 15.10.2002 #103517# - allow grow in online layout // Thus, set <..IsBrowseMode()> as parameter <bGrow> on calling // method <CheckClipping(..)>. const SwViewShell *pSh = getRootFrame()->GetCurrShell();
CheckClipping( pSh && pSh->GetViewOptions()->getBrowseMode(), bMaximize );
bMaximize = ToMaximize( false );
setFrameAreaSizeValid(true);
}
// Check the width of the columns and adjust if necessary if ( bHasColumns && ! Lower()->GetNext() && bMaximize ) static_cast<SwColumnFrame*>(Lower())->Lower()->Calc(pRenderContext);
if ( !bMaximize )
{
SwTwips nRemaining = aRectFnSet.GetTopMargin(*this);
SwFrame *pFrame = m_pLower; if( pFrame )
{ if( pFrame->IsColumnFrame() && pFrame->GetNext() )
{ // #i61435# // suppress formatting, if upper frame has height <= 0 if ( aRectFnSet.GetHeight(GetUpper()->getFrameArea()) > 0 )
{
FormatWidthCols( *pAttr, nRemaining, MINLAY );
} // #126020# - adjust check for empty section // #130797# - correct fix #126020# while( HasFollow() && !GetFollow()->ContainsContent() &&
!GetFollow()->ContainsAny( true ) )
{
SwFrame* pOld = GetFollow();
GetFollow()->DelEmpty( false ); if( pOld == GetFollow() ) break;
}
bMaximize = ToMaximize( false );
nRemaining += aRectFnSet.GetHeight(pFrame->getFrameArea());
} else
{ if( pFrame->IsColumnFrame() )
{
pFrame->Calc(pRenderContext);
pFrame = static_cast<SwColumnFrame*>(pFrame)->Lower();
pFrame->Calc(pRenderContext);
pFrame = static_cast<SwLayoutFrame*>(pFrame)->Lower();
CalcFootnoteContent();
} // If we are in a columned frame which calls a CalcContent // in the FormatWidthCols, the content might need calculating if( pFrame && !pFrame->isFrameAreaDefinitionValid() && IsInFly() &&
FindFlyFrame()->IsColLocked() )
::CalcContent( this );
nRemaining += InnerHeight();
bMaximize = HasFollow();
}
}
if (m_pLower && (!m_pLower->IsColumnFrame() || !m_pLower->GetNext()))
{ // If a single-column section just created the space that // was requested by the "undersized" paragraphs, then they // have to be invalidated and calculated, so they fully cover it
pFrame = m_pLower; if( pFrame->IsColumnFrame() )
{
pFrame->InvalidateSize_();
pFrame->InvalidatePos_();
pFrame->Calc(pRenderContext);
pFrame = static_cast<SwColumnFrame*>(pFrame)->Lower();
pFrame->Calc(pRenderContext);
pFrame = static_cast<SwLayoutFrame*>(pFrame)->Lower();
CalcFootnoteContent();
} bool bUnderSz = false; while( pFrame )
{ if( pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsUndersized() )
{
pFrame->Prepare( PrepareHint::AdjustSizeWithoutFormatting );
bUnderSz = true;
}
pFrame = pFrame->GetNext();
} if( bUnderSz && !IsContentLocked() )
::CalcContent( this );
}
}
}
// Do not exceed the lower edge of the Upper. // Do not extend below the lower edge with Sections with Follows if ( GetUpper() )
CheckClipping( true, bMaximize ); if( !bOldLock )
ColUnlock();
tools::Long nDiff = nOldHeight - aRectFnSet.GetHeight(getFrameArea());
if( nDiff > 0 )
{ if( !GetNext() )
SetRetouche(); // Take over the retouching ourselves if( GetUpper() && !GetUpper()->IsFooterFrame() )
GetUpper()->Shrink( nDiff );
}
/// Returns the next layout sheet where the frame can be moved in. /// New pages are created only if specified by the parameter.
SwLayoutFrame *SwFrame::GetNextSctLeaf( MakePageType eMakePage )
{ // Attention: Nested sections are currently not supported
// Shortcuts for "columned" sections, if we're not in the last column // Can we slide to the next column of the section? if( IsColBodyFrame() && GetUpper()->GetNext() ) returnstatic_cast<SwLayoutFrame*>(static_cast<SwLayoutFrame*>(GetUpper()->GetNext())->Lower()); if( GetUpper()->IsColBodyFrame() && GetUpper()->GetUpper()->GetNext() ) returnstatic_cast<SwLayoutFrame*>(static_cast<SwLayoutFrame*>(GetUpper()->GetUpper()->GetNext())->Lower()); // Inside a table-in-section, or sections of headers/footers, there can be only // one column shift be made, one of the above shortcuts should have applied! if( !CanContainSplitSection(GetUpper()) || FindFooterOrHeader() ) return nullptr;
// Always end up in the same section: Body again inside Body etc. constbool bBody = IsInDocBody(); constbool bFootnotePage = FindPageFrame()->IsFootnotePage();
// The "pLayLeaf is in a table" case is rejected by default, so that it // can't happen that we try to move a table to one of its own cells. bool bLayLeafTableAllowed = false;
SwLayoutFrame *pLayLeaf;
SwLayoutFrame* pCellLeaf = nullptr; if (GetUpper()->IsInTab())
{ if (IsTabFrame())
{ return nullptr; // table in section in table: split disabled for now
} // We are *in* a table (not an outermost SwTabFrame), see if there // is a follow cell frame created already.
pCellLeaf = GetNextCellLeaf(); if (!pCellLeaf)
{
SAL_WARN("sw.layout", "section is in table, but the table is not split"); return nullptr;
}
}
// A shortcut for TabFrames such that not all cells need to be visited if( bWrongPage )
pLayLeaf = nullptr; elseif( IsTabFrame() )
{
SwFrame *const pTmpCnt = static_cast<SwTabFrame*>(this)->FindLastContentOrTable();
pLayLeaf = pTmpCnt ? pTmpCnt->GetUpper() : nullptr;
} elseif (pCellLeaf && CanContainSplitSection(this))
{ // This frame is in a table-not-in-section, its follow should be // inserted under the follow of the frame's cell.
pLayLeaf = pCellLeaf; if (pLayLeaf->FindTabFrame() == FindTabFrame())
SAL_WARN("sw.layout", "my table frame and my follow's table frame is the same"); // In this case pLayLeaf pointing to an in-table frame is OK.
bLayLeafTableAllowed = true;
} else
{
pLayLeaf = GetNextLayoutLeaf(); if( IsColumnFrame() )
{ while( pLayLeaf && static_cast<SwColumnFrame*>(this)->IsAnLower( pLayLeaf ) )
pLayLeaf = pLayLeaf->GetNextLayoutLeaf();
}
}
SwLayoutFrame *pOldLayLeaf = nullptr; // Such that in case of newly // created pages, the search is // not started over at the beginning
while( true )
{ if( pLayLeaf )
{ // A layout leaf was found, let's see whether it can store me or // another SectionFrame can be inserted here, or we have to continue // searching
SwPageFrame* pNxtPg = pLayLeaf->FindPageFrame(); if ( !bFootnotePage && pNxtPg->IsFootnotePage() )
{ // If I reached the end note pages it's over
pLayLeaf = nullptr; continue;
} // Once inBody always inBody, don't step into tables-in-sections and not into other sections if ( (bBody && !pLayLeaf->IsInDocBody()) ||
(IsInFootnote() != pLayLeaf->IsInFootnote() ) ||
(pLayLeaf->IsInTab() && !bLayLeafTableAllowed) ||
( pLayLeaf->IsInSct() && ( !pSect->HasFollow()
|| pSect->GetFollow() != pLayLeaf->FindSctFrame() ) ) )
{ // Rejected - try again.
pOldLayLeaf = pLayLeaf;
pLayLeaf = pLayLeaf->GetNextLayoutLeaf(); continue;
} // Page desc is never wrong in case of sections-in-tables: in that // case pLayLeaf points to our section's cell's follow, which is // fine to be on the same page. New page creation is handled when // creating / moving the cell frame. // It doesn't make sense to move to a page that starts with break? if (pNxtPg != FindPageFrame() // tdf#156725 not between columns!
&& !FindFlyFrame() // tdf#156419 linked fly frames don't care!
&& (WrongPageDesc(pNxtPg) || HasPageBreakBefore(*pNxtPg))
&& !bLayLeafTableAllowed)
{ if( bWrongPage ) break; // there's a column between me and my right page
pLayLeaf = nullptr;
bWrongPage = true;
pOldLayLeaf = nullptr; continue;
}
} // There is no further LayoutFrame that fits, so a new page // has to be created, although new pages are worthless within a frame elseif( !pSect->IsInFly() &&
( eMakePage == MAKEPAGE_APPEND || eMakePage == MAKEPAGE_INSERT ) )
{
InsertPage(pOldLayLeaf ? pOldLayLeaf->FindPageFrame() : FindPageFrame(), false ); // and again the whole thing if (pCellLeaf && CanContainSplitSection(this)) // GetNextLayoutLeaf() would refer to the next cell in the same // row, avoid that. pCellLeaf points to the correct cell in the // follow table, and in the next round it'll be used, as we now // have a next page.
pLayLeaf = pCellLeaf; else
pLayLeaf = pOldLayLeaf ? pOldLayLeaf : GetNextLayoutLeaf(); continue;
} break;
}
if( pLayLeaf )
{ // We have found the suitable layout sheet. If there (in the sheet) is // already a Follow of our section, we take its first layout sheet, // otherwise it is time to create a section follow
SwSectionFrame* pNew = nullptr;
// This can be omitted if existing Follows were cut short
SwFrame* pFirst = pLayLeaf->Lower(); // Here SectionFrames that are to be deleted must be ignored while( pFirst && pFirst->IsSctFrame() && !static_cast<SwSectionFrame*>(pFirst)->GetSection() )
pFirst = pFirst->GetNext(); if( pFirst && pFirst->IsSctFrame() && pSect->GetFollow() == pFirst )
pNew = pSect->GetFollow(); elseif( MAKEPAGE_NOSECTION == eMakePage ) return pLayLeaf; elseif (pSect->GetSection())
{
pNew = new SwSectionFrame( *pSect, false );
pNew->InsertBefore( pLayLeaf, pLayLeaf->Lower() );
pNew->Init();
SwRectFnSet aRectFnSet(pNew);
aRectFnSet.MakePos( *pNew, pLayLeaf, nullptr, true );
#ifndef NDEBUG
{ // sanity check the parents of the new frame vs. the old frame
SwFrame * pTmp = pNew; auto iter(parents.begin()); if (parents.size() >= 2 &&
parents[0]->IsBodyFrame() && parents[1]->IsColumnFrame())
{ // this only inserts section frame - remove column
assert(parents[2]->IsSctFrame() || IsSctFrame()); if (parents[2]->IsSctFrame())
std::advance(iter, +2); else
pTmp = pTmp->GetUpper();
} elseif (IsBodyFrame() && parents.size() >= 1
&& parents[0]->IsColumnFrame())
{ // same as above, special case: "this" is the body frame
assert(parents[1]->IsSctFrame());
std::advance(iter, +1);
} elseif (IsSctFrame()) // special case: "this" is the section
{
pTmp = pTmp->GetUpper();
}
for ( ; iter != parents.end(); ++iter)
{ if (pTmp->IsPageFrame())
{ if ((*iter)->IsColumnFrame() &&
(iter + 1) != parents.end() && (*(iter + 1))->IsBodyFrame())
{ // page style has columns - evidently these are break; // added later?
}
assert(!pTmp->IsPageFrame());
}
assert(pTmp->GetType() == (*iter)->GetType()); // for cell frames and table frames: // 1) there may be multiple follow frames of the old one // 2) the new frame may be identical to the old one // (not sure if this is allowed, but it happens now // for the outer table of a nested table) if (pTmp->IsCellFrame())
{
SwCellFrame const*const pNewF(static_cast<SwCellFrame*>(pTmp));
SwCellFrame const*const pOldF(static_cast<SwCellFrame*>(*iter)); bool bFollowFound(false); for (SwCellFrame const* pOldIter = pOldF;
pOldIter; pOldIter = pOldIter->GetFollowCell())
{ if (pOldIter == pNewF)
{
bFollowFound = true; break;
}
}
assert(bFollowFound);
} elseif (pTmp->IsFlowFrame())
{
SwFlowFrame const*const pNewF(SwFlowFrame::CastFlowFrame(pTmp));
SwFlowFrame const*const pOldF(SwFlowFrame::CastFlowFrame(*iter)); bool bFollowFound(false); for (SwFlowFrame const* pOldIter = pOldF;
pOldIter; pOldIter = pOldIter->GetFollow())
{ if (pOldIter == pNewF)
{
bFollowFound = true; break;
}
}
assert(bFollowFound);
}
pTmp = pTmp->GetUpper();
}
assert(pTmp == nullptr /* SwFlyAtContentFrame case */
|| pTmp->IsPageFrame() // usual case // the new page has columns, but the old page did not
|| (pTmp->IsColumnFrame() && pTmp->GetUpper()->IsBodyFrame()
&& pTmp->GetUpper()->GetUpper()->IsPageFrame()));
} #endif
// If our section frame has a successor then that has to be // moved behind the new Follow of the section frames
SwFrame* pTmp = pSect->GetNext(); if( pTmp && pTmp != pSect->GetFollow() )
{
SwFlowFrame* pNxt;
SwContentFrame* pNxtContent = nullptr; if( pTmp->IsContentFrame() )
{
pNxt = static_cast<SwContentFrame*>(pTmp);
pNxtContent = static_cast<SwContentFrame*>(pTmp);
} else
{
pNxtContent = static_cast<SwLayoutFrame*>(pTmp)->ContainsContent(); if( pTmp->IsSctFrame() )
pNxt = static_cast<SwSectionFrame*>(pTmp); else
{
assert(pTmp->IsTabFrame());
pNxt = static_cast<SwTabFrame*>(pTmp);
} while( !pNxtContent && nullptr != ( pTmp = pTmp->GetNext() ) )
{ if( pTmp->IsContentFrame() )
pNxtContent = static_cast<SwContentFrame*>(pTmp); else
pNxtContent = static_cast<SwLayoutFrame*>(pTmp)->ContainsContent();
}
} if( pNxtContent )
{
SwFootnoteBossFrame* pOldBoss = pSect->FindFootnoteBossFrame( true ); if( pOldBoss == pNxtContent->FindFootnoteBossFrame( true ) )
{
SwSaveFootnoteHeight aHeight( pOldBoss,
pOldBoss->getFrameArea().Top() + pOldBoss->getFrameArea().Height() );
pSect->GetUpper()->MoveLowerFootnotes( pNxtContent, pOldBoss,
pLayLeaf->FindFootnoteBossFrame( true ), false );
}
}
pNxt->MoveSubTree( pLayLeaf, pNew->GetNext() );
} if( pNew->GetFollow() )
pNew->SimpleFormat();
} // The wanted layout sheet is now the first of the determined SctFrames:
pLayLeaf = pNew ? FirstLeaf(pNew) : nullptr;
} return pLayLeaf;
}
/// Returns the preceding layout sheet where the frame can be moved into
SwLayoutFrame *SwFrame::GetPrevSctLeaf()
{
PROTOCOL_ENTER( this, PROT::Leaf, DbgAction::PrevSect, GetUpper()->FindSctFrame() )
SwLayoutFrame* pCol; // ColumnFrame always contain a BodyFrame now if( IsColBodyFrame() )
pCol = GetUpper(); elseif( GetUpper()->IsColBodyFrame() )
pCol = GetUpper()->GetUpper(); else
pCol = nullptr; bool bJump = false; if( pCol )
{ if( pCol->GetPrev() )
{ do
{
pCol = static_cast<SwLayoutFrame*>(pCol->GetPrev()); // Is there any content? if( static_cast<SwLayoutFrame*>(pCol->Lower())->Lower() )
{ if( bJump ) // Did we skip a blank page?
SwFlowFrame::SetMoveBwdJump( true ); returnstatic_cast<SwLayoutFrame*>(pCol->Lower()); // The columnm body
}
bJump = true;
} while( pCol->GetPrev() );
// We get here when all columns are empty, pCol is now the // first column, we need the body though
pCol = static_cast<SwLayoutFrame*>(pCol->Lower());
} else
pCol = nullptr;
}
if( bJump ) // Did we skip a blank page?
SwFlowFrame::SetMoveBwdJump( true );
SwSectionFrame *pSect = FindSctFrame(); if (!pCol && pSect && IsInTab() && CanContainSplitSection(this))
{ // We don't have a previous section yet, and we're in a // section-in-table. if (SwFlowFrame* pPrecede = pSect->GetPrecede())
{ // Our section has a precede, work with that. if (pPrecede->GetFrame().IsLayoutFrame())
pCol = static_cast<SwLayoutFrame*>(&pPrecede->GetFrame());
}
}
// Within sections in tables or section in headers/footers there can // be only one column change be made, one of the above shortcuts should // have applied, also when the section has a pPrev. // Now we even consider an empty column...
OSL_ENSURE( pSect, "GetNextSctLeaf: Missing SectionFrame" ); if (!pSect || (IsInTab() && !IsTabFrame()) || FindFooterOrHeader()) return pCol;
// === IMPORTANT === // Precondition, which needs to be hold, is that the <this> frame can be // inside a table, but then the found section frame <pSect> is also inside // this table.
// #i95698# // A table cell containing directly a section does not break - see lcl_FindSectionsInRow(..) // Thus, a table inside a section, which is inside another table can only // flow backward in the columns of its section. // Note: The table cell, which contains the section, can not have a master table cell. if ( IsTabFrame() && pSect->IsInTab() )
{ return pCol;
}
/// checks whether the SectionFrame is still able to grow, as case may be the environment has to be asked bool SwSectionFrame::Growable() const
{
SwRectFnSet aRectFnSet(this); if( aRectFnSet.YDiff( lcl_DeadLine( this ),
aRectFnSet.GetBottom(getFrameArea()) ) > 0 ) returntrue;
SwFrame* pLower = Lower(); if( pLower && pLower->IsColumnFrame() && pLower->GetNext() )
{
SwFrame* pTmp = pLower; do
{
pTmp->InvalidateSize_();
pTmp = pTmp->GetNext();
} while ( pTmp );
InvalidateSize_();
} if( GetNext() )
{ // Own height changed, need to invalidate the position of // next frames.
SwFrame *pFrame = GetNext(); while( pFrame && pFrame->IsSctFrame() && !static_cast<SwSectionFrame*>(pFrame)->GetSection() )
{ // Invalidate all in-between frames, otherwise position // calculation (which only looks back to one relative // frame) will have an incorrect result.
InvalidateFramePos(pFrame, bInCalcContent);
pFrame = pFrame->GetNext();
} if( pFrame )
{
InvalidateFramePos(pFrame, bInCalcContent);
}
} // #i28701# - Due to the new object positioning // the frame on the next page/column can flow backward (e.g. it // was moved forward due to the positioning of its objects ). // Thus, invalivate this next frame, if document compatibility // option 'Consider wrapping style influence on object positioning' is ON. elseif ( GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) )
{
InvalidateNextPos();
}
} return nGrow;
}
if ( Lower()->IsColumnFrame() && Lower()->GetNext() && // FootnoteAtEnd
!GetSection()->GetFormat()->GetBalancedColumns().GetValue() )
{ // With column bases the format takes over the control of the // growth (because of the balance) if ( !bTst )
InvalidateSize(); return nDist;
} elseif( !bTst )
{ const SvxGraphicPosition ePos =
GetAttrSet()->GetBackground().GetGraphicPos(); if ( GPOS_RT < ePos && GPOS_TILED != ePos )
{
SetCompletePaint();
InvalidatePage();
}
// We do not allow a section frame to shrink the its upper // footer frame. This is because in the calculation of a // footer frame, the content of the section frame is _not_ // calculated. If there is a fly frame overlapping with the // footer frame, the section frame is not affected by this // during the calculation of the footer frame size. // The footer frame does not grow in its FormatSize function // but during the calculation of the content of the section // frame. The section frame grows until some of its text is // located on top of the fly frame. The next call of CalcContent // tries to shrink the section and here it would also shrink // the footer. This may not happen, because shrinking the footer // would cause the top of the section frame to overlap with the // fly frame again, this would result in a perfect loop. if( GetUpper() && !GetUpper()->IsFooterFrame() )
GetUpper()->Shrink( nDist, bTst );
/* |*WhenareFrameswithinaSectionFramesmoveable? |*IftheyarenotinthelastcolumnofaSectionFramesyet, |*ifthereisnoFollow, |*iftheSectionFramecannotgrowanymore,thenitgetsmorecomplicated, |*inthatcaseitdependsonwhethertheSectionFramecanfindanext |*layoutsheet.In(columnbased/chained)Flysthisischeckedvia |*GetNextLayout,intablesandheaders/footersthereisnone,howeverinthe |*DocBodyandinfootnotesthereisalwaysone. |* |*ThisroutineisusedintheTextFormattertodecidedwhetherit'sallowedto |*createa(paragraph-)Followorwhethertheparagraphhastosticktogether
|*/ bool SwSectionFrame::MoveAllowed( const SwFrame* pFrame) const
{ // Is there a Follow or is the Frame not in the last column? if( HasFollow() || ( pFrame->GetUpper()->IsColBodyFrame() &&
pFrame->GetUpper()->GetUpper()->GetNext() ) ) returntrue; if( pFrame->IsInFootnote() )
{ if( IsInFootnote() )
{ if( GetUpper()->IsInSct() )
{ if( Growable() ) returnfalse; return GetUpper()->FindSctFrame()->MoveAllowed( this );
} else returntrue;
} // The content of footnote inside a columned sectionfrm is moveable // except in the last column const SwLayoutFrame *pLay = pFrame->FindFootnoteFrame()->GetUpper()->GetUpper(); if( pLay->IsColumnFrame() && pLay->GetNext() )
{ // The first paragraph in the first footnote in the first column // in the sectionfrm at the top of the page is not moveable, // if the columnbody is empty. bool bRet = false; if( pLay->GetIndPrev() || pFrame->GetIndPrev() ||
pFrame->FindFootnoteFrame()->GetPrev() )
bRet = true; else
{ const SwLayoutFrame* pBody = static_cast<const SwColumnFrame*>(pLay)->FindBodyCont(); if( pBody && pBody->Lower() )
bRet = true;
} if( bRet && ( IsFootnoteAtEnd() || !Growable() ) ) returntrue;
}
} // Or can the section still grow? if( !IsColLocked() && Growable() ) returnfalse; // Now it has to be examined whether there is a layout sheet wherein // a section Follow can be created if( !CanContainSplitSection(this) || ( !IsInDocBody() && FindFooterOrHeader() ) ) returnfalse; // It doesn't work in table-in-sections/nested tables/headers/footers if( IsInFly() ) // In column based or chained frames return nullptr != const_cast<SwFrame*>(static_cast<SwFrame const *>(GetUpper()))->GetNextLeaf( MAKEPAGE_NONE ); returntrue;
}
/** Called for a frame inside a section with no direct previous frame (or only previousemptysectionframes)thepreviousframeoftheoutersectionis returned,iftheframeisthefirstflowingcontentofthissection.
Note:Foraframeinsideatableframe,whichisinsideasectionframe, NULLisreturned.
*/
SwFrame* SwFrame::GetIndPrev_() const
{
SwFrame *pRet = nullptr; // #i79774# // Do not assert, if the frame has a direct previous frame, because it // could be an empty section frame. The caller has to assure, that the // frame has no direct previous frame or only empty section frames as // previous frames.
OSL_ENSURE( /*!pPrev &&*/ IsInSct(), "Why?" ); const SwFrame* pSct = GetUpper(); if( !pSct ) return nullptr; if( pSct->IsSctFrame() )
pRet = pSct->GetIndPrev(); elseif( pSct->IsColBodyFrame() && (pSct = pSct->GetUpper()->GetUpper())->IsSctFrame() )
{ // Do not return the previous frame of the outer section, if in one // of the previous columns is content. const SwFrame* pCol = GetUpper()->GetUpper()->GetPrev(); while( pCol )
{
assert(pCol->IsColumnFrame()); const SwFrame* pLower = pCol->GetLower();
assert(pLower && pLower->IsBodyFrame()); if( static_cast<const SwLayoutFrame*>(pLower)->Lower() ) return nullptr;
pCol = pCol->GetPrev();
}
pRet = pSct->GetIndPrev();
}
// skip empty section frames while( pRet && pRet->IsSctFrame() && !static_cast<SwSectionFrame*>(pRet)->GetSection() )
pRet = pRet->GetIndPrev(); return pRet;
}
SwFrame* SwFrame::GetIndNext_()
{
OSL_ENSURE( !mpNext && IsInSct(), "Why?" );
SwFrame* pSct = GetUpper(); if( !pSct ) return nullptr; if( pSct->IsSctFrame() ) return pSct->GetIndNext(); if( pSct->IsColBodyFrame() && (pSct = pSct->GetUpper()->GetUpper())->IsSctFrame() )
{ // We can only return the successor of the SectionFrames if there is no // content in the successive columns
SwFrame* pCol = GetUpper()->GetUpper()->GetNext(); while( pCol )
{
assert(pCol->IsColumnFrame());
assert(pCol->GetLower() && pCol->GetLower()->IsBodyFrame()); if( static_cast<SwLayoutFrame*>(static_cast<SwLayoutFrame*>(pCol)->Lower())->Lower() ) return nullptr;
pCol = pCol->GetNext();
} return pSct->GetIndNext();
} return nullptr;
}
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.