tdf#91920 sw page gutter margin: handle mirrored margins
[LibreOffice.git] / sw / source / core / layout / pagedesc.cxx
blob2e472d10ad144d30ace8272a2fba7a593fac98c1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <libxml/xmlwriter.h>
22 #include <editeng/pbinitem.hxx>
23 #include <editeng/ulspitem.hxx>
24 #include <editeng/boxitem.hxx>
25 #include <editeng/brushitem.hxx>
26 #include <editeng/shaditem.hxx>
27 #include <editeng/frmdiritem.hxx>
28 #include <sal/log.hxx>
29 #include <fmtclds.hxx>
30 #include <fmtfsize.hxx>
31 #include <pagefrm.hxx>
32 #include <pagedesc.hxx>
33 #include <swtable.hxx>
34 #include <frmatr.hxx>
35 #include <frmtool.hxx>
36 #include <doc.hxx>
37 #include <node.hxx>
38 #include <strings.hrc>
39 #include <IDocumentLayoutAccess.hxx>
40 #include <IDocumentStylePoolAccess.hxx>
41 #include <poolfmt.hxx>
42 #include <calbck.hxx>
43 #include <hints.hxx>
45 SwPageDesc::SwPageDesc(const OUString& rName, SwFrameFormat *pFormat, SwDoc *const pDoc)
46 : SwModify()
47 , m_StyleName( rName )
48 , m_Master( pDoc->GetAttrPool(), rName, pFormat )
49 , m_Left( pDoc->GetAttrPool(), rName, pFormat )
50 , m_FirstMaster( pDoc->GetAttrPool(), rName, pFormat )
51 , m_FirstLeft( pDoc->GetAttrPool(), rName, pFormat )
52 , m_aDepends(*this)
53 , m_pTextFormatColl(nullptr)
54 , m_pFollow( this )
55 , m_nRegHeight( 0 )
56 , m_nRegAscent( 0 )
57 , m_nVerticalAdjustment( drawing::TextVerticalAdjust_TOP )
58 , m_eUse( UseOnPage::All | UseOnPage::HeaderShare | UseOnPage::FooterShare | UseOnPage::FirstShare )
59 , m_IsLandscape( false )
60 , m_IsHidden( false )
61 , m_pdList( nullptr )
65 SwPageDesc::SwPageDesc( const SwPageDesc &rCpy )
66 : SwModify()
67 , BroadcasterMixin()
68 , m_StyleName( rCpy.GetName() )
69 , m_NumType( rCpy.GetNumType() )
70 , m_Master( rCpy.GetMaster() )
71 , m_Left( rCpy.GetLeft() )
72 , m_FirstMaster( rCpy.GetFirstMaster() )
73 , m_FirstLeft( rCpy.GetFirstLeft() )
74 , m_aDepends(*this)
75 , m_pTextFormatColl(nullptr)
76 , m_pFollow( rCpy.m_pFollow )
77 , m_nRegHeight( rCpy.GetRegHeight() )
78 , m_nRegAscent( rCpy.GetRegAscent() )
79 , m_nVerticalAdjustment( rCpy.GetVerticalAdjustment() )
80 , m_eUse( rCpy.ReadUseOn() )
81 , m_IsLandscape( rCpy.GetLandscape() )
82 , m_IsHidden( rCpy.IsHidden() )
83 , m_IsFootnoteInfo( rCpy.GetFootnoteInfo() )
84 , m_pdList( nullptr )
86 if (rCpy.m_pTextFormatColl && rCpy.m_aDepends.IsListeningTo(rCpy.m_pTextFormatColl))
88 m_pTextFormatColl = rCpy.m_pTextFormatColl;
89 m_aDepends.StartListening(const_cast<SwTextFormatColl*>(m_pTextFormatColl));
93 SwPageDesc & SwPageDesc::operator = (const SwPageDesc & rSrc)
95 if(this == &rSrc)
96 return *this;
98 m_StyleName = rSrc.m_StyleName;
99 m_NumType = rSrc.m_NumType;
100 m_Master = rSrc.m_Master;
101 m_Left = rSrc.m_Left;
102 m_FirstMaster = rSrc.m_FirstMaster;
103 m_FirstLeft = rSrc.m_FirstLeft;
104 m_aDepends.EndListeningAll();
105 if (rSrc.m_pTextFormatColl && rSrc.m_aDepends.IsListeningTo(rSrc.m_pTextFormatColl))
107 m_pTextFormatColl = rSrc.m_pTextFormatColl;
108 m_aDepends.StartListening(const_cast<SwTextFormatColl*>(m_pTextFormatColl));
110 else
111 m_pTextFormatColl = nullptr;
113 if (rSrc.m_pFollow == &rSrc)
114 m_pFollow = this;
115 else
116 m_pFollow = rSrc.m_pFollow;
118 m_nRegHeight = rSrc.m_nRegHeight;
119 m_nRegAscent = rSrc.m_nRegAscent;
120 m_nVerticalAdjustment = rSrc.m_nVerticalAdjustment;
121 m_eUse = rSrc.m_eUse;
122 m_IsLandscape = rSrc.m_IsLandscape;
123 return *this;
126 SwPageDesc::~SwPageDesc()
130 bool SwPageDesc::SetName( const OUString& rNewName )
132 bool renamed = true;
133 if (m_pdList) {
134 SwPageDescs::iterator it = m_pdList->find_( m_StyleName );
135 if( m_pdList->end() == it ) {
136 SAL_WARN( "sw", "SwPageDesc not found in expected m_pdList" );
137 return false;
139 renamed = m_pdList->m_PosIndex.modify( it,
140 change_name( rNewName ), change_name( m_StyleName ) );
142 else
143 m_StyleName = rNewName;
144 return renamed;
147 /// Only the margin is mirrored.
148 /// Attributes like borders and so on are copied 1:1.
149 void SwPageDesc::Mirror()
151 //Only the margins are mirrored, all other values are just copied.
152 SvxLRSpaceItem aLR( RES_LR_SPACE );
153 const SvxLRSpaceItem &rLR = m_Master.GetLRSpace();
154 aLR.SetLeft( rLR.GetRight() );
155 aLR.SetRight( rLR.GetLeft() );
156 aLR.SetRightGutterMargin(rLR.GetGutterMargin());
158 SfxItemSet aSet( *m_Master.GetAttrSet().GetPool(),
159 m_Master.GetAttrSet().GetRanges() );
160 aSet.Put( aLR );
161 aSet.Put( m_Master.GetFrameSize() );
162 aSet.Put( m_Master.GetPaperBin() );
163 aSet.Put( m_Master.GetULSpace() );
164 aSet.Put( m_Master.GetBox() );
165 aSet.Put( *m_Master.makeBackgroundBrushItem() );
166 aSet.Put( m_Master.GetShadow() );
167 aSet.Put( m_Master.GetCol() );
168 aSet.Put( m_Master.GetFrameDir() );
169 m_Left.SetFormatAttr( aSet );
172 void SwPageDesc::ResetAllAttr()
174 SwFrameFormat& rFormat = GetMaster();
176 // #i73790# - method renamed
177 rFormat.ResetAllFormatAttr();
178 rFormat.SetFormatAttr( SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR) );
181 // gets information from Modify
182 bool SwPageDesc::GetInfo( SfxPoolItem & rInfo ) const
184 if (!m_Master.GetInfo(rInfo))
185 return false; // found
186 if (!m_Left.GetInfo(rInfo))
187 return false ;
188 if ( !m_FirstMaster.GetInfo( rInfo ) )
189 return false;
190 return m_FirstLeft.GetInfo( rInfo );
193 /// set the style for the grid alignment
194 void SwPageDesc::SetRegisterFormatColl(const SwTextFormatColl* pFormat)
196 if(pFormat != m_pTextFormatColl)
198 m_aDepends.EndListeningAll();
199 m_pTextFormatColl = pFormat;
200 m_aDepends.StartListening(const_cast<SwTextFormatColl*>(m_pTextFormatColl));
201 RegisterChange();
205 /// retrieve the style for the grid alignment
206 const SwTextFormatColl* SwPageDesc::GetRegisterFormatColl() const
208 if (!m_aDepends.IsListeningTo(m_pTextFormatColl))
209 m_pTextFormatColl = nullptr;
210 return m_pTextFormatColl;
213 /// notify all affected page frames
214 void SwPageDesc::RegisterChange()
216 // #117072# - During destruction of the document <SwDoc>
217 // the page description is modified. Thus, do nothing, if the document
218 // is in destruction respectively if no viewshell exists.
219 SwDoc* pDoc = GetMaster().GetDoc();
220 if ( !pDoc || pDoc->IsInDtor() )
222 return;
224 SwViewShell* pSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
225 if ( !pSh )
227 return;
230 m_nRegHeight = 0;
232 SwIterator<SwFrame,SwFormat> aIter( GetMaster() );
233 for( SwFrame* pLast = aIter.First(); pLast; pLast = aIter.Next() )
235 if( pLast->IsPageFrame() )
236 static_cast<SwPageFrame*>(pLast)->PrepareRegisterChg();
240 SwIterator<SwFrame,SwFormat> aIter( GetLeft() );
241 for( SwFrame* pLast = aIter.First(); pLast; pLast = aIter.Next() )
243 if( pLast->IsPageFrame() )
244 static_cast<SwPageFrame*>(pLast)->PrepareRegisterChg();
248 SwIterator<SwFrame,SwFormat> aIter( GetFirstMaster() );
249 for( SwFrame* pLast = aIter.First(); pLast; pLast = aIter.Next() )
251 if( pLast->IsPageFrame() )
252 static_cast<SwPageFrame*>(pLast)->PrepareRegisterChg();
256 SwIterator<SwFrame,SwFormat> aIter( GetFirstLeft() );
257 for( SwFrame* pLast = aIter.First(); pLast; pLast = aIter.Next() )
259 if( pLast->IsPageFrame() )
260 static_cast<SwPageFrame*>(pLast)->PrepareRegisterChg();
265 /// special handling if the style of the grid alignment changes
266 void SwPageDesc::SwClientNotify(const SwModify& rModify, const SfxHint& rHint)
268 if(auto pLegacyHint = dynamic_cast<const sw::LegacyModifyHint*>(&rHint))
270 const sal_uInt16 nWhich = pLegacyHint->m_pOld
271 ? pLegacyHint->m_pOld->Which()
272 : pLegacyHint->m_pNew
273 ? pLegacyHint->m_pNew->Which()
274 : 0;
275 NotifyClients(pLegacyHint->m_pOld, pLegacyHint->m_pNew);
276 if((RES_ATTRSET_CHG == nWhich)
277 || (RES_FMT_CHG == nWhich)
278 || isCHRATR(nWhich)
279 || (RES_PARATR_LINESPACING == nWhich))
280 RegisterChange();
282 else if (auto pModifyChangedHint = dynamic_cast<const sw::ModifyChangedHint*>(&rHint))
284 if(m_pTextFormatColl == &rModify)
285 m_pTextFormatColl = static_cast<const SwTextFormatColl*>(pModifyChangedHint->m_pNew);
286 else
287 assert(false);
291 static const SwFrame* lcl_GetFrameOfNode( const SwNode& rNd )
293 const SwModify* pMod;
294 SwFrameType nFrameType = FRM_CNTNT;
296 if( rNd.IsContentNode() )
298 pMod = &static_cast<const SwContentNode&>(rNd);
300 else if( rNd.IsTableNode() )
302 pMod = static_cast<const SwTableNode&>(rNd).GetTable().GetFrameFormat();
303 nFrameType = SwFrameType::Tab;
305 else
306 pMod = nullptr;
308 Point aNullPt;
309 std::pair<Point, bool> const tmp(aNullPt, false);
310 return pMod ? ::GetFrameOfModify(nullptr, *pMod, nFrameType, nullptr, &tmp)
311 : nullptr;
314 const SwPageDesc* SwPageDesc::GetPageDescOfNode(const SwNode& rNd)
316 const SwPageDesc* pRet = nullptr;
317 const SwFrame* pChkFrame = lcl_GetFrameOfNode( rNd );
318 if (pChkFrame && nullptr != (pChkFrame = pChkFrame->FindPageFrame()))
319 pRet = static_cast<const SwPageFrame*>(pChkFrame)->GetPageDesc();
320 return pRet;
323 const SwFrameFormat* SwPageDesc::GetPageFormatOfNode( const SwNode& rNd,
324 bool bCheckForThisPgDc ) const
326 // which PageDescFormat is valid for this node?
327 const SwFrameFormat* pRet;
328 const SwFrame* pChkFrame = lcl_GetFrameOfNode( rNd );
330 if( pChkFrame && nullptr != ( pChkFrame = pChkFrame->FindPageFrame() ))
332 const SwPageDesc* pPd = bCheckForThisPgDc ? this :
333 static_cast<const SwPageFrame*>(pChkFrame)->GetPageDesc();
334 pRet = &pPd->GetMaster();
335 OSL_ENSURE( static_cast<const SwPageFrame*>(pChkFrame)->GetPageDesc() == pPd, "Wrong node for detection of page format!" );
336 // this page is assigned to which format?
337 if( !pChkFrame->KnowsFormat(*pRet) )
339 pRet = &pPd->GetLeft();
340 OSL_ENSURE( pChkFrame->KnowsFormat(*pRet), "Wrong node for detection of page format!" );
343 else
344 pRet = &GetMaster();
345 return pRet;
348 bool SwPageDesc::IsFollowNextPageOfNode( const SwNode& rNd ) const
350 bool bRet = false;
351 if( GetFollow() && this != GetFollow() )
353 const SwFrame* pChkFrame = lcl_GetFrameOfNode( rNd );
354 if( pChkFrame && nullptr != ( pChkFrame = pChkFrame->FindPageFrame() ) &&
355 pChkFrame->IsPageFrame() &&
356 ( !pChkFrame->GetNext() || GetFollow() ==
357 static_cast<const SwPageFrame*>(pChkFrame->GetNext())->GetPageDesc() ))
358 // the page on which the follow points was found
359 bRet = true;
361 return bRet;
364 SwFrameFormat *SwPageDesc::GetLeftFormat(bool const bFirst)
366 return (UseOnPage::Left & m_eUse)
367 ? (bFirst ? &m_FirstLeft : &m_Left)
368 : nullptr;
371 SwFrameFormat *SwPageDesc::GetRightFormat(bool const bFirst)
373 return (UseOnPage::Right & m_eUse)
374 ? (bFirst ? &m_FirstMaster : &m_Master)
375 : nullptr;
378 bool SwPageDesc::IsFirstShared() const
380 return bool(m_eUse & UseOnPage::FirstShare);
383 void SwPageDesc::ChgFirstShare( bool bNew )
385 if ( bNew )
386 m_eUse |= UseOnPage::FirstShare;
387 else
388 m_eUse &= UseOnPage::NoFirstShare;
391 // Page styles
392 static const char* STR_POOLPAGE[] =
394 STR_POOLPAGE_STANDARD,
395 STR_POOLPAGE_FIRST,
396 STR_POOLPAGE_LEFT,
397 STR_POOLPAGE_RIGHT,
398 STR_POOLPAGE_JAKET,
399 STR_POOLPAGE_REGISTER,
400 STR_POOLPAGE_HTML,
401 STR_POOLPAGE_FOOTNOTE,
402 STR_POOLPAGE_ENDNOTE,
403 STR_POOLPAGE_LANDSCAPE
406 SwPageDesc* SwPageDesc::GetByName(SwDoc& rDoc, const OUString& rName)
408 const size_t nDCount = rDoc.GetPageDescCnt();
410 for( size_t i = 0; i < nDCount; i++ )
412 SwPageDesc* pDsc = &rDoc.GetPageDesc( i );
413 if(pDsc->GetName() == rName)
415 return pDsc;
419 for (size_t i = 0; i < SAL_N_ELEMENTS(STR_POOLPAGE); ++i)
421 if (rName == SwResId(STR_POOLPAGE[i]))
423 return rDoc.getIDocumentStylePoolAccess().GetPageDescFromPool( static_cast< sal_uInt16 >(
424 i + RES_POOLPAGE_BEGIN) );
428 return nullptr;
431 void SwPageDesc::dumpAsXml(xmlTextWriterPtr pWriter) const
433 xmlTextWriterStartElement(pWriter, BAD_CAST("SwPageDesc"));
434 xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
435 xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("m_StyleName"), "%s",
436 BAD_CAST(m_StyleName.toUtf8().getStr()));
437 xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("m_pFollow"), "%p", m_pFollow);
438 xmlTextWriterWriteFormatAttribute(
439 pWriter, BAD_CAST("m_eUse"), "0x%s",
440 BAD_CAST(OString::number(static_cast<int>(m_eUse), 16).getStr()));
442 xmlTextWriterStartElement(pWriter, BAD_CAST("m_Master"));
443 m_Master.dumpAsXml(pWriter);
444 xmlTextWriterEndElement(pWriter);
446 xmlTextWriterStartElement(pWriter, BAD_CAST("m_Left"));
447 m_Left.dumpAsXml(pWriter);
448 xmlTextWriterEndElement(pWriter);
450 xmlTextWriterStartElement(pWriter, BAD_CAST("m_FirstMaster"));
451 m_FirstMaster.dumpAsXml(pWriter);
452 xmlTextWriterEndElement(pWriter);
454 xmlTextWriterStartElement(pWriter, BAD_CAST("m_FirstLeft"));
455 m_FirstLeft.dumpAsXml(pWriter);
456 xmlTextWriterEndElement(pWriter);
458 xmlTextWriterEndElement(pWriter);
461 SwPageFootnoteInfo::SwPageFootnoteInfo()
462 : m_nMaxHeight( 0 )
463 , m_nLineWidth(10)
464 , m_eLineStyle( SvxBorderLineStyle::SOLID )
465 , m_Width( 25, 100 )
466 , m_nTopDist( 57 ) //1mm
467 , m_nBottomDist( 57 )
469 m_eAdjust = SvxFrameDirection::Horizontal_RL_TB == GetDefaultFrameDirection(GetAppLanguage()) ?
470 css::text::HorizontalAdjust_RIGHT :
471 css::text::HorizontalAdjust_LEFT;
474 SwPageFootnoteInfo::SwPageFootnoteInfo( const SwPageFootnoteInfo &rCpy )
475 : m_nMaxHeight(rCpy.GetHeight())
476 , m_nLineWidth(rCpy.m_nLineWidth)
477 , m_eLineStyle(rCpy.m_eLineStyle)
478 , m_LineColor(rCpy.m_LineColor)
479 , m_Width(rCpy.GetWidth())
480 , m_eAdjust(rCpy.GetAdj())
481 , m_nTopDist(rCpy.GetTopDist())
482 , m_nBottomDist(rCpy.GetBottomDist())
486 SwPageFootnoteInfo &SwPageFootnoteInfo::operator=( const SwPageFootnoteInfo& rCpy )
488 m_nMaxHeight = rCpy.GetHeight();
489 m_nLineWidth = rCpy.m_nLineWidth;
490 m_eLineStyle = rCpy.m_eLineStyle;
491 m_LineColor = rCpy.m_LineColor;
492 m_Width = rCpy.GetWidth();
493 m_eAdjust = rCpy.GetAdj();
494 m_nTopDist = rCpy.GetTopDist();
495 m_nBottomDist = rCpy.GetBottomDist();
496 return *this;
499 bool SwPageFootnoteInfo::operator==( const SwPageFootnoteInfo& rCmp ) const
501 return m_nMaxHeight == rCmp.GetHeight()
502 && m_nLineWidth == rCmp.m_nLineWidth
503 && m_eLineStyle == rCmp.m_eLineStyle
504 && m_LineColor == rCmp.m_LineColor
505 && m_Width == rCmp.GetWidth()
506 && m_eAdjust == rCmp.GetAdj()
507 && m_nTopDist == rCmp.GetTopDist()
508 && m_nBottomDist== rCmp.GetBottomDist();
511 SwPageDescExt::SwPageDescExt(const SwPageDesc & rPageDesc, SwDoc *const pDoc)
512 : m_PageDesc(rPageDesc)
513 , m_pDoc(pDoc)
515 SetPageDesc(rPageDesc);
518 SwPageDescExt::SwPageDescExt(const SwPageDescExt & rSrc)
519 : m_PageDesc(rSrc.m_PageDesc)
520 , m_pDoc(rSrc.m_pDoc)
522 SetPageDesc(rSrc.m_PageDesc);
525 SwPageDescExt::~SwPageDescExt()
529 OUString const & SwPageDescExt::GetName() const
531 return m_PageDesc.GetName();
534 void SwPageDescExt::SetPageDesc(const SwPageDesc & rPageDesc)
536 m_PageDesc = rPageDesc;
538 if (m_PageDesc.GetFollow())
539 m_sFollow = m_PageDesc.GetFollow()->GetName();
542 SwPageDescExt & SwPageDescExt::operator = (const SwPageDesc & rSrc)
544 SetPageDesc(rSrc);
546 return *this;
549 SwPageDescExt & SwPageDescExt::operator = (const SwPageDescExt & rSrc)
551 operator=(rSrc.m_PageDesc);
552 return *this;
555 SwPageDescExt::operator SwPageDesc() const
557 SwPageDesc aResult(m_PageDesc);
559 SwPageDesc * pPageDesc = m_pDoc->FindPageDesc(m_sFollow);
561 if ( nullptr != pPageDesc )
562 aResult.SetFollow(pPageDesc);
564 return aResult;
567 SwPageDescs::SwPageDescs()
568 : m_PosIndex( m_Array.get<0>() )
569 , m_NameIndex( m_Array.get<1>() )
573 SwPageDescs::~SwPageDescs()
575 for(const_iterator it = begin(); it != end(); ++it)
576 delete *it;
579 SwPageDescs::iterator SwPageDescs::find_(const OUString &name) const
581 ByName::iterator it = m_NameIndex.find( name );
582 return m_Array.iterator_to( *it );
585 std::pair<SwPageDescs::const_iterator,bool> SwPageDescs::push_back( const value_type& x )
587 // SwPageDesc is not already in a SwPageDescs list!
588 assert( x->m_pdList == nullptr );
590 std::pair<iterator,bool> res = m_PosIndex.push_back( x );
591 if( res.second )
592 x->m_pdList = this;
593 return res;
596 void SwPageDescs::erase( const value_type& x )
598 // SwPageDesc is not in this SwPageDescs list!
599 assert( x->m_pdList == this );
601 iterator const ret = find_( x->GetName() );
602 if (ret != end())
603 m_PosIndex.erase( ret );
604 else
605 SAL_WARN( "sw", "SwPageDesc is not in SwPageDescs m_pdList!" );
606 x->m_pdList = nullptr;
609 void SwPageDescs::erase( const_iterator const& position )
611 // SwPageDesc is not in this SwPageDescs list!
612 assert( (*position)->m_pdList == this );
614 (*position)->m_pdList = nullptr;
615 m_PosIndex.erase( position );
618 void SwPageDescs::erase( size_type index_ )
620 erase( begin() + index_ );
623 void SwPageDescs::dumpAsXml(xmlTextWriterPtr pWriter) const
625 xmlTextWriterStartElement(pWriter, BAD_CAST("SwPageDescs"));
627 for (const auto& pPageDesc : m_PosIndex)
629 pPageDesc->dumpAsXml(pWriter);
632 xmlTextWriterEndElement(pWriter);
635 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */