android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / doc / docdesc.cxx
blob57e561e1f444e0a80667939acffa92b7d80faba1
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 <cmdid.h>
21 #include <init.hxx>
22 #include <editeng/lrspitem.hxx>
23 #include <editeng/ulspitem.hxx>
24 #include <editeng/paperinf.hxx>
25 #include <editeng/frmdiritem.hxx>
26 #include <sfx2/bindings.hxx>
27 #include <sfx2/dispatch.hxx>
28 #include <tools/globname.hxx>
29 #include <sal/log.hxx>
30 #include <osl/diagnose.h>
31 #include <unotools/localedatawrapper.hxx>
32 #include <fmtfsize.hxx>
33 #include <fmthdft.hxx>
34 #include <fmtcntnt.hxx>
35 #include <ftninfo.hxx>
36 #include <fesh.hxx>
37 #include <ndole.hxx>
38 #include <mdiexp.hxx>
39 #include <doc.hxx>
40 #include <IDocumentUndoRedo.hxx>
41 #include <IDocumentFieldsAccess.hxx>
42 #include <DocumentContentOperationsManager.hxx>
43 #include <IDocumentState.hxx>
44 #include <IDocumentLayoutAccess.hxx>
45 #include <rootfrm.hxx>
46 #include <poolfmt.hxx>
47 #include <docsh.hxx>
48 #include <ftnidx.hxx>
49 #include <fmtftn.hxx>
50 #include <txtftn.hxx>
51 #include <fldbas.hxx>
52 #include <strings.hrc>
53 #include <hints.hxx>
54 #include <SwUndoPageDesc.hxx>
55 #include <pagedeschint.hxx>
56 #include <tgrditem.hxx>
57 #include <unotools/configmgr.hxx>
58 #include <unotools/syslocale.hxx>
59 #include <svx/swframetypes.hxx>
60 #include <o3tl/unit_conversion.hxx>
62 #include <com/sun/star/embed/XEmbeddedObject.hpp>
64 using namespace com::sun::star;
66 static void lcl_DefaultPageFormat( sal_uInt16 nPoolFormatId,
67 SwFrameFormat &rFormat1,
68 SwFrameFormat &rFormat2,
69 SwFrameFormat &rFormat3,
70 SwFrameFormat &rFormat4)
72 // --> #i41075# Printer on demand
73 // This function does not require a printer anymore.
74 // The default page size is obtained from the application
75 //locale
77 SwFormatFrameSize aFrameSize( SwFrameSize::Fixed );
78 const Size aPhysSize = SvxPaperInfo::GetDefaultPaperSize();
79 aFrameSize.SetSize( aPhysSize );
81 // Prepare for default margins.
82 // Margins have a default minimum size.
83 // If the printer forces a larger margins, that's ok too.
84 // The HTML page desc had A4 as page size always.
85 // This has been changed to take the page size from the printer.
86 // Unfortunately, the margins of the HTML page desc are smaller than
87 // the margins used here in general, so one extra case is required.
88 // In the long term, this needs to be changed to always keep the
89 // margins from the page desc.
90 sal_Int32 nMinTop, nMinBottom, nMinLeft, nMinRight;
91 if( RES_POOLPAGE_HTML == nPoolFormatId )
93 nMinRight = nMinTop = nMinBottom = o3tl::toTwips(1, o3tl::Length::cm);
94 nMinLeft = o3tl::toTwips(2, o3tl::Length::cm);
96 else if (!utl::ConfigManager::IsFuzzing() && MeasurementSystem::Metric == SvtSysLocale().GetLocaleData().getMeasurementSystemEnum() )
98 nMinTop = nMinBottom = nMinLeft = nMinRight = o3tl::toTwips(2, o3tl::Length::cm);
100 else
102 nMinTop = nMinBottom = o3tl::toTwips(1, o3tl::Length::in); // as in MS Word
103 nMinLeft = nMinRight = o3tl::toTwips(1.25, o3tl::Length::in);
106 // set margins
107 SvxLRSpaceItem aLR( RES_LR_SPACE );
108 SvxULSpaceItem aUL( RES_UL_SPACE );
110 aUL.SetUpper( o3tl::narrowing<sal_uInt16>(nMinTop) );
111 aUL.SetLower( o3tl::narrowing<sal_uInt16>(nMinBottom) );
112 aLR.SetRight( nMinRight );
113 aLR.SetLeft( nMinLeft );
115 rFormat1.SetFormatAttr( aFrameSize );
116 rFormat1.SetFormatAttr( aLR );
117 rFormat1.SetFormatAttr( aUL );
119 rFormat2.SetFormatAttr( aFrameSize );
120 rFormat2.SetFormatAttr( aLR );
121 rFormat2.SetFormatAttr( aUL );
123 rFormat3.SetFormatAttr( aFrameSize );
124 rFormat3.SetFormatAttr( aLR );
125 rFormat3.SetFormatAttr( aUL );
127 rFormat4.SetFormatAttr( aFrameSize );
128 rFormat4.SetFormatAttr( aLR );
129 rFormat4.SetFormatAttr( aUL );
132 static void lcl_DescSetAttr( const SwFrameFormat &rSource, SwFrameFormat &rDest,
133 const bool bPage = true )
135 // We should actually use ItemSet's Intersect here, but that doesn't work
136 // correctly if we have different WhichRanges.
138 // Take over the attributes which are of interest.
139 sal_uInt16 const aIdArr[] = {
140 RES_FRM_SIZE, RES_UL_SPACE, // [83..86
141 RES_BACKGROUND, RES_SHADOW, // [99..101
142 RES_COL, RES_COL, // [103
143 RES_TEXTGRID, RES_TEXTGRID, // [109
144 RES_FRAMEDIR, RES_FRAMEDIR, // [114
145 RES_HEADER_FOOTER_EAT_SPACING, RES_HEADER_FOOTER_EAT_SPACING, // [115
146 RES_BACKGROUND_FULL_SIZE, RES_BACKGROUND_FULL_SIZE, // [131
147 RES_RTL_GUTTER, RES_RTL_GUTTER, // [132
148 RES_UNKNOWNATR_CONTAINER, RES_UNKNOWNATR_CONTAINER, // [143
150 // take over DrawingLayer FillStyles
151 XATTR_FILL_FIRST, XATTR_FILL_LAST, // [1014
155 const SfxPoolItem* pItem;
156 for( sal_uInt16 n = 0; aIdArr[ n ]; n += 2 )
158 for( sal_uInt16 nId = aIdArr[ n ]; nId <= aIdArr[ n+1]; ++nId )
160 // #i45539#
161 // bPage == true:
162 // All in aIdArr except from RES_HEADER_FOOTER_EAT_SPACING
163 // bPage == false:
164 // All in aIdArr except from RES_COL and RES_PAPER_BIN:
165 bool bExecuteId(true);
167 if(bPage)
169 // When Page
170 switch(nId)
172 // All in aIdArr except from RES_HEADER_FOOTER_EAT_SPACING
173 case RES_HEADER_FOOTER_EAT_SPACING:
174 // take out SvxBrushItem; it's the result of the fallback
175 // at SwFormat::GetItemState and not really in state SfxItemState::SET
176 case RES_BACKGROUND:
177 bExecuteId = false;
178 break;
179 default:
180 break;
183 else
185 // When not Page
186 switch(nId)
188 // When not Page: All in aIdArr except these:
189 case RES_COL:
190 case RES_PAPER_BIN:
191 case RES_BACKGROUND_FULL_SIZE:
192 case RES_RTL_GUTTER:
193 bExecuteId = false;
194 break;
195 default:
196 break;
200 if(bExecuteId)
202 if (SfxItemState::SET == rSource.GetItemState(nId, false, &pItem))
204 rDest.SetFormatAttr(*pItem);
206 else
208 rDest.ResetFormatAttr(nId);
214 // Transmit pool and help IDs too
215 rDest.SetPoolFormatId( rSource.GetPoolFormatId() );
216 rDest.SetPoolHelpId( rSource.GetPoolHelpId() );
217 rDest.SetPoolHlpFileId( rSource.GetPoolHlpFileId() );
220 namespace
222 SwFrameFormat& getFrameFormat(SwPageDesc &rDesc, bool bLeft, bool bFirst)
224 if (bFirst)
226 if (bLeft)
227 return rDesc.GetFirstLeft();
228 return rDesc.GetFirstMaster();
230 return rDesc.GetLeft();
233 const SwFrameFormat& getConstFrameFormat(const SwPageDesc &rDesc, bool bLeft, bool bFirst)
235 return getFrameFormat(const_cast<SwPageDesc&>(rDesc), bLeft, bFirst);
239 void SwDoc::CopyMasterHeader(const SwPageDesc &rChged, const SwFormatHeader &rHead, SwPageDesc &rDesc, bool bLeft, bool bFirst)
241 assert(bLeft || bFirst);
242 SwFrameFormat& rDescFrameFormat = getFrameFormat(rDesc, bLeft, bFirst);
243 if (bFirst && bLeft)
245 // special case: always shared with something
246 rDescFrameFormat.SetFormatAttr( rChged.IsFirstShared()
247 ? rDesc.GetLeft().GetHeader()
248 : rDesc.GetFirstMaster().GetHeader());
250 else if ((bFirst ? rChged.IsFirstShared() : rChged.IsHeaderShared())
251 || !rHead.IsActive())
253 // Left or first shares the header with the Master.
254 rDescFrameFormat.SetFormatAttr( rDesc.GetMaster().GetHeader() );
256 else if ( rHead.IsActive() )
257 { // Left or first gets its own header if the Format doesn't already have one.
258 // If it already has one and it points to the same Section as the
259 // Right one, it needs to get an own Header.
260 // The content is evidently copied.
261 const SwFormatHeader &rFormatHead = rDescFrameFormat.GetHeader();
262 if ( !rFormatHead.IsActive() )
264 SwFormatHeader aHead( getIDocumentLayoutAccess().MakeLayoutFormat( RndStdIds::HEADERL, nullptr ) );
265 rDescFrameFormat.SetFormatAttr( aHead );
266 // take over additional attributes (margins, borders ...)
267 ::lcl_DescSetAttr( *rHead.GetHeaderFormat(), *aHead.GetHeaderFormat(), false);
269 else
271 const SwFormatContent &aCnt = rFormatHead.GetHeaderFormat()->GetContent();
273 if (!aCnt.GetContentIdx())
275 const SwFrameFormat& rChgedFrameFormat = getConstFrameFormat(rChged, bLeft, bFirst);
276 rDescFrameFormat.SetFormatAttr( rChgedFrameFormat.GetHeader() );
278 else
280 const SwFrameFormat *pRight = rHead.GetHeaderFormat();
281 if (!pRight)
282 return;
283 const SwFormatContent &aRCnt = pRight->GetContent();
285 if ((*aRCnt.GetContentIdx() == *aCnt.GetContentIdx()) ||
286 // The ContentIdx is _always_ different when called from
287 // SwDocStyleSheet::SetItemSet, because it deep-copies the
288 // PageDesc. So check if it was previously shared.
289 (bFirst ? rDesc.IsFirstShared() : rDesc.IsHeaderShared()))
291 SwFrameFormat *pFormat = new SwFrameFormat( GetAttrPool(),
292 bFirst ? "First header" : "Left header",
293 GetDfltFrameFormat() );
294 ::lcl_DescSetAttr( *pRight, *pFormat, false );
295 // The section which the right header attribute is pointing
296 // is copied, and the Index to the StartNode is set to
297 // the left or first header attribute.
298 SwStartNode* pSttNd = SwNodes::MakeEmptySection( GetNodes().GetEndOfAutotext(), SwHeaderStartNode );
299 SwNodeRange aRange( aRCnt.GetContentIdx()->GetNode(), SwNodeOffset(0),
300 *aRCnt.GetContentIdx()->GetNode().EndOfSectionNode() );
301 GetNodes().Copy_( aRange, *pSttNd->EndOfSectionNode(), false );
302 GetDocumentContentOperationsManager().CopyFlyInFlyImpl(aRange, nullptr, *pSttNd);
303 SwPaM const source(aRange.aStart, aRange.aEnd);
304 SwPosition dest(*pSttNd);
305 sw::CopyBookmarks(source, dest);
306 pFormat->SetFormatAttr( SwFormatContent( pSttNd ) );
307 rDescFrameFormat.SetFormatAttr( SwFormatHeader( pFormat ) );
309 else
310 ::lcl_DescSetAttr( *pRight,
311 *const_cast<SwFrameFormat*>(rFormatHead.GetHeaderFormat()), false );
317 void SwDoc::CopyMasterFooter(const SwPageDesc &rChged, const SwFormatFooter &rFoot, SwPageDesc &rDesc, bool bLeft, bool bFirst)
319 assert(bLeft || bFirst);
320 SwFrameFormat& rDescFrameFormat = getFrameFormat(rDesc, bLeft, bFirst);
321 if (bFirst && bLeft)
323 // special case: always shared with something
324 rDescFrameFormat.SetFormatAttr( rChged.IsFirstShared()
325 ? rDesc.GetLeft().GetFooter()
326 : rDesc.GetFirstMaster().GetFooter());
328 else if ((bFirst ? rChged.IsFirstShared() : rChged.IsFooterShared())
329 || !rFoot.IsActive())
331 // Left or first shares the Header with the Master.
332 rDescFrameFormat.SetFormatAttr( rDesc.GetMaster().GetFooter() );
334 else if ( rFoot.IsActive() )
335 { // Left or first gets its own Footer if the Format does not already have one.
336 // If the Format already has a Footer and it points to the same section as the Right one,
337 // it needs to get an own one.
338 // The content is evidently copied.
339 const SwFormatFooter &rFormatFoot = rDescFrameFormat.GetFooter();
340 if ( !rFormatFoot.IsActive() )
342 SwFormatFooter aFoot( getIDocumentLayoutAccess().MakeLayoutFormat( RndStdIds::FOOTER, nullptr ) );
343 rDescFrameFormat.SetFormatAttr( aFoot );
344 // Take over additional attributes (margins, borders ...).
345 ::lcl_DescSetAttr( *rFoot.GetFooterFormat(), *aFoot.GetFooterFormat(), false);
347 else
349 const SwFormatContent &aLCnt = rFormatFoot.GetFooterFormat()->GetContent();
350 if( !aLCnt.GetContentIdx() )
352 const SwFrameFormat& rChgedFrameFormat = getConstFrameFormat(rChged, bLeft, bFirst);
353 rDescFrameFormat.SetFormatAttr( rChgedFrameFormat.GetFooter() );
355 else
357 const SwFrameFormat *pRight = rFoot.GetFooterFormat();
358 if (!pRight)
359 return;
360 const SwFormatContent &aRCnt = pRight->GetContent();
362 if ((*aRCnt.GetContentIdx() == *aLCnt.GetContentIdx()) ||
363 // The ContentIdx is _always_ different when called from
364 // SwDocStyleSheet::SetItemSet, because it deep-copies the
365 // PageDesc. So check if it was previously shared.
366 (bFirst ? rDesc.IsFirstShared() : rDesc.IsFooterShared()))
368 SwFrameFormat *pFormat = new SwFrameFormat( GetAttrPool(),
369 bFirst ? "First footer" : "Left footer",
370 GetDfltFrameFormat() );
371 ::lcl_DescSetAttr( *pRight, *pFormat, false );
372 // The section to which the right footer attribute is pointing
373 // is copied, and the Index to the StartNode is set to
374 // the left footer attribute.
375 SwStartNode* pSttNd = SwNodes::MakeEmptySection( GetNodes().GetEndOfAutotext(), SwFooterStartNode );
376 SwNodeRange aRange( aRCnt.GetContentIdx()->GetNode(), SwNodeOffset(0),
377 *aRCnt.GetContentIdx()->GetNode().EndOfSectionNode() );
378 GetNodes().Copy_( aRange, *pSttNd->EndOfSectionNode(), false );
379 GetDocumentContentOperationsManager().CopyFlyInFlyImpl(aRange, nullptr, *pSttNd);
380 SwPaM const source(aRange.aStart, aRange.aEnd);
381 SwPosition dest(*pSttNd);
382 sw::CopyBookmarks(source, dest);
383 pFormat->SetFormatAttr( SwFormatContent( pSttNd ) );
384 rDescFrameFormat.SetFormatAttr( SwFormatFooter( pFormat ) );
386 else
387 ::lcl_DescSetAttr( *pRight,
388 *const_cast<SwFrameFormat*>(rFormatFoot.GetFooterFormat()), false );
394 void SwDoc::ChgPageDesc( size_t i, const SwPageDesc &rChged )
396 assert(i < m_PageDescs.size() && "PageDescs is out of range.");
398 SwPageDesc& rDesc = *m_PageDescs[i];
399 SwRootFrame* pTmpRoot = getIDocumentLayoutAccess().GetCurrentLayout();
401 if (GetIDocumentUndoRedo().DoesUndo())
403 // Stash header formats as needed.
404 const SwFormatHeader& rLeftHead = rChged.GetLeft().GetHeader();
405 const SwFormatHeader& rFirstMasterHead = rChged.GetFirstMaster().GetHeader();
406 const SwFormatHeader& rFirstLeftHead = rChged.GetFirstLeft().GetHeader();
407 const bool bStashLeftHead = !rDesc.IsHeaderShared() && rChged.IsHeaderShared();
408 const bool bStashFirstMasterHead = !rDesc.IsFirstShared() && rChged.IsFirstShared();
409 const bool bStashFirstLeftHead = (!rDesc.IsHeaderShared() && rChged.IsHeaderShared()) || (!rDesc.IsFirstShared() && rChged.IsFirstShared());
410 if (bStashLeftHead && rLeftHead.GetRegisteredIn() && !rDesc.HasStashedFormat(true, true, false))
411 rDesc.StashFrameFormat(rChged.GetLeft(), true, true, false);
412 if (bStashFirstMasterHead && rFirstMasterHead.GetRegisteredIn() && !rDesc.HasStashedFormat(true, false, true))
413 rDesc.StashFrameFormat(rChged.GetFirstMaster(), true, false, true);
414 if (bStashFirstLeftHead && rFirstLeftHead.GetRegisteredIn() && !rDesc.HasStashedFormat(true, true, true))
415 rDesc.StashFrameFormat(rChged.GetFirstLeft(), true, true, true);
417 // Stash footer formats as needed.
418 const SwFormatFooter& rLeftFoot = rChged.GetLeft().GetFooter();
419 const SwFormatFooter& rFirstMasterFoot = rChged.GetFirstMaster().GetFooter();
420 const SwFormatFooter& rFirstLeftFoot = rChged.GetFirstLeft().GetFooter();
421 const bool bStashLeftFoot = !rDesc.IsFooterShared() && rChged.IsFooterShared();
422 const bool bStashFirstMasterFoot = !rDesc.IsFirstShared() && rChged.IsFirstShared();
423 const bool bStashFirstLeftFoot = (!rDesc.IsFooterShared() && rChged.IsFooterShared()) || (!rDesc.IsFirstShared() && rChged.IsFirstShared());
424 if (bStashLeftFoot && rLeftFoot.GetRegisteredIn() && !rDesc.HasStashedFormat(false, true, false))
425 rDesc.StashFrameFormat(rChged.GetLeft(), false, true, false);
426 if (bStashFirstMasterFoot && rFirstMasterFoot.GetRegisteredIn() && !rDesc.HasStashedFormat(false, false, true))
427 rDesc.StashFrameFormat(rChged.GetFirstMaster(), false, false, true);
428 if (bStashFirstLeftFoot && rFirstLeftFoot.GetRegisteredIn() && !rDesc.HasStashedFormat(false, true, true))
429 rDesc.StashFrameFormat(rChged.GetFirstLeft(), false, true, true);
431 GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoPageDesc>(rDesc, rChged, this));
433 else
435 SwUndoId nBeingUndone(SwUndoId::EMPTY);
436 GetIDocumentUndoRedo().GetFirstRedoInfo(nullptr, &nBeingUndone);
437 if (SwUndoId::HEADER_FOOTER == nBeingUndone)
439 // The last format change is currently being undone. Remove header/footer and corresponding nodes.
440 auto rDescMasterHeaderFormat = rDesc.GetMaster().GetFormatAttr(RES_HEADER);
441 auto rDescLeftHeaderFormat = rDesc.GetLeft().GetFormatAttr(RES_HEADER);
442 auto rDescFirstLeftHeaderFormat = rDesc.GetFirstLeft().GetFormatAttr(RES_HEADER);
443 auto rDescMasterFooterFormat = rDesc.GetMaster().GetFormatAttr(RES_FOOTER);
444 auto rDescLeftFooterFormat = rDesc.GetLeft().GetFormatAttr(RES_FOOTER);
445 auto rDescFirstLeftFooterFormat = rDesc.GetFirstLeft().GetFormatAttr(RES_FOOTER);
447 auto rChgedMasterHeaderFormat = rChged.GetMaster().GetFormatAttr(RES_HEADER);
448 auto rChgedLeftHeaderFormat = rChged.GetLeft().GetFormatAttr(RES_HEADER);
449 auto rChgedFirstLeftHeaderFormat = rChged.GetFirstLeft().GetFormatAttr(RES_HEADER);
450 auto rChgedMasterFooterFormat = rChged.GetMaster().GetFormatAttr(RES_FOOTER);
451 auto rChgedLeftFooterFormat = rChged.GetLeft().GetFormatAttr(RES_FOOTER);
452 auto rChgedFirstLeftFooterFormat = rChged.GetFirstLeft().GetFormatAttr(RES_FOOTER);
454 rDesc.GetMaster().ResetFormatAttr(RES_HEADER);
455 rDesc.GetLeft().ResetFormatAttr(RES_HEADER);
456 rDesc.GetFirstLeft().ResetFormatAttr(RES_HEADER);
457 rDesc.GetMaster().ResetFormatAttr(RES_FOOTER);
458 rDesc.GetLeft().ResetFormatAttr(RES_FOOTER);
459 rDesc.GetFirstLeft().ResetFormatAttr(RES_FOOTER);
461 auto lDelHFFormat = [this](SwClient* pToRemove, SwFrameFormat* pFormat)
463 // Code taken from lcl_DelHFFormat
464 pFormat->Remove(pToRemove);
465 SwFormatContent& rCnt = const_cast<SwFormatContent&>(pFormat->GetContent());
466 if (rCnt.GetContentIdx())
468 SwNode* pNode = nullptr;
470 SwNodeIndex aIdx(*rCnt.GetContentIdx(), 0);
471 pNode = &aIdx.GetNode();
472 SwNodeOffset nEnd = pNode->EndOfSectionIndex();
473 while (aIdx < nEnd)
475 if (pNode->IsContentNode() &&
476 static_cast<SwContentNode*>(pNode)->HasWriterListeners())
478 SwCursorShell* pShell = SwIterator<SwCursorShell, SwContentNode>(*static_cast<SwContentNode*>(pNode)).First();
479 if (pShell)
481 pShell->ParkCursor(aIdx.GetNode());
482 aIdx = nEnd - 1;
485 ++aIdx;
486 pNode = &aIdx.GetNode();
489 rCnt.SetNewContentIdx(nullptr);
491 ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
493 assert(pNode);
494 getIDocumentContentOperations().DeleteSection(pNode);
496 delete pFormat;
499 if (rDescMasterHeaderFormat.GetHeaderFormat() && rDescMasterHeaderFormat != rChgedMasterHeaderFormat)
500 lDelHFFormat(&rDescMasterHeaderFormat, rDescMasterHeaderFormat.GetHeaderFormat());
501 else if (rDescLeftHeaderFormat.GetHeaderFormat() && rDescLeftHeaderFormat != rChgedLeftHeaderFormat)
502 lDelHFFormat(&rDescLeftHeaderFormat, rDescLeftHeaderFormat.GetHeaderFormat());
503 else if (rDescFirstLeftHeaderFormat.GetHeaderFormat() && rDescFirstLeftHeaderFormat != rChgedFirstLeftHeaderFormat)
504 lDelHFFormat(&rDescFirstLeftHeaderFormat, rDescFirstLeftHeaderFormat.GetHeaderFormat());
506 else if (rDescMasterFooterFormat.GetFooterFormat() && rDescMasterFooterFormat != rChgedMasterFooterFormat)
507 lDelHFFormat(&rDescMasterFooterFormat, rDescMasterFooterFormat.GetFooterFormat());
508 else if (rDescLeftFooterFormat.GetFooterFormat() && rDescLeftFooterFormat != rChgedLeftFooterFormat)
509 lDelHFFormat(&rDescLeftFooterFormat, rDescLeftFooterFormat.GetFooterFormat());
510 else if (rDescFirstLeftFooterFormat.GetFooterFormat() && rDescFirstLeftFooterFormat != rChgedFirstLeftFooterFormat)
511 lDelHFFormat(&rDescFirstLeftFooterFormat, rDescFirstLeftFooterFormat.GetFooterFormat());
514 ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
516 // Mirror at first if needed.
517 if ( rChged.GetUseOn() == UseOnPage::Mirror )
518 const_cast<SwPageDesc&>(rChged).Mirror();
519 else
521 // Or else transfer values from Master to Left
522 ::lcl_DescSetAttr(rChged.GetMaster(),
523 const_cast<SwPageDesc&>(rChged).GetLeft());
525 ::lcl_DescSetAttr(rChged.GetMaster(),
526 const_cast<SwPageDesc&>(rChged).GetFirstMaster());
527 ::lcl_DescSetAttr(rChged.GetLeft(),
528 const_cast<SwPageDesc&>(rChged).GetFirstLeft());
530 // Take over NumType.
531 if( rChged.GetNumType().GetNumberingType() != rDesc.GetNumType().GetNumberingType() )
533 rDesc.SetNumType( rChged.GetNumType() );
534 // Notify page number fields that NumFormat has changed
535 getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::PageNumber )->UpdateFields();
536 getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::RefPageGet )->UpdateFields();
538 // If the numbering scheme has changed we could have QuoVadis/ErgoSum texts
539 // that refer to a changed page, so we invalidate foot notes.
540 SwFootnoteIdxs& rFootnoteIdxs = GetFootnoteIdxs();
541 for( SwFootnoteIdxs::size_type nPos = 0; nPos < rFootnoteIdxs.size(); ++nPos )
543 SwTextFootnote *pTextFootnote = rFootnoteIdxs[ nPos ];
544 const SwFormatFootnote &rFootnote = pTextFootnote->GetFootnote();
545 pTextFootnote->SetNumber(rFootnote.GetNumber(), rFootnote.GetNumberRLHidden(), rFootnote.GetNumStr());
549 // Take over orientation
550 rDesc.SetLandscape( rChged.GetLandscape() );
552 // Synch header.
553 const SwFormatHeader& rMasterHead = rChged.GetMaster().GetHeader();
554 rDesc.GetMaster().SetFormatAttr( rMasterHead );
555 const bool bRestoreStashedLeftHead = rDesc.IsHeaderShared() && !rChged.IsHeaderShared();
556 const bool bRestoreStashedFirstMasterHead = rDesc.IsFirstShared() && !rChged.IsFirstShared();
557 const bool bRestoreStashedFirstLeftHead = (rDesc.IsHeaderShared() && !rChged.IsHeaderShared()) || (rDesc.IsFirstShared() && !rChged.IsFirstShared());
558 const SwFrameFormat* pStashedLeftFormat = bRestoreStashedLeftHead ? rChged.GetStashedFrameFormat(true, true, false) : nullptr;
559 const SwFrameFormat* pStashedFirstMasterFormat = bRestoreStashedFirstMasterHead ? rChged.GetStashedFrameFormat(true, false, true) : nullptr;
560 const SwFrameFormat* pStashedFirstLeftFormat = bRestoreStashedFirstLeftHead ? rChged.GetStashedFrameFormat(true, true, true) : nullptr;
561 CopyMasterHeader(rChged, pStashedLeftFormat ? pStashedLeftFormat->GetHeader() : rMasterHead, rDesc, true, false); // Copy left header
562 CopyMasterHeader(rChged, pStashedFirstMasterFormat ? pStashedFirstMasterFormat->GetHeader() : rMasterHead, rDesc, false, true); // Copy first master
563 CopyMasterHeader(rChged, pStashedFirstLeftFormat ? pStashedFirstLeftFormat->GetHeader() : rMasterHead, rDesc, true, true); // Copy first left
565 if (pStashedLeftFormat)
566 rDesc.RemoveStashedFormat(true, true, false);
568 if (pStashedFirstMasterFormat)
569 rDesc.RemoveStashedFormat(true, false, true);
571 if (pStashedFirstLeftFormat)
572 rDesc.RemoveStashedFormat(true, true, true);
574 rDesc.ChgHeaderShare( rChged.IsHeaderShared() );
576 // Synch Footer.
577 const SwFormatFooter& rMasterFoot = rChged.GetMaster().GetFooter();
578 rDesc.GetMaster().SetFormatAttr( rMasterFoot );
579 const bool bRestoreStashedLeftFoot = rDesc.IsFooterShared() && !rChged.IsFooterShared();
580 const bool bRestoreStashedFirstMasterFoot = rDesc.IsFirstShared() && !rChged.IsFirstShared();
581 const bool bRestoreStashedFirstLeftFoot = (rDesc.IsFooterShared() && !rChged.IsFooterShared()) || (rDesc.IsFirstShared() && !rChged.IsFirstShared());
582 const SwFrameFormat* pStashedLeftFoot = bRestoreStashedLeftFoot ? rChged.GetStashedFrameFormat(false, true, false) : nullptr;
583 const SwFrameFormat* pStashedFirstMasterFoot = bRestoreStashedFirstMasterFoot ? rChged.GetStashedFrameFormat(false, false, true) : nullptr;
584 const SwFrameFormat* pStashedFirstLeftFoot = bRestoreStashedFirstLeftFoot ? rChged.GetStashedFrameFormat(false, true, true) : nullptr;
585 CopyMasterFooter(rChged, pStashedLeftFoot ? pStashedLeftFoot->GetFooter() : rMasterFoot, rDesc, true, false); // Copy left footer
586 CopyMasterFooter(rChged, pStashedFirstMasterFoot ? pStashedFirstMasterFoot->GetFooter() : rMasterFoot, rDesc, false, true); // Copy first master
587 CopyMasterFooter(rChged, pStashedFirstLeftFoot ? pStashedFirstLeftFoot->GetFooter() : rMasterFoot, rDesc, true, true); // Copy first left
589 if (pStashedLeftFormat)
590 rDesc.RemoveStashedFormat(false, true, false);
592 if (pStashedFirstMasterFoot)
593 rDesc.RemoveStashedFormat(false, false, true);
595 if (pStashedFirstLeftFoot)
596 rDesc.RemoveStashedFormat(false, true, true);
598 rDesc.ChgFooterShare( rChged.IsFooterShared() );
599 // there is just one first shared flag for both header and footer?
600 rDesc.ChgFirstShare( rChged.IsFirstShared() );
602 if ( rDesc.GetName() != rChged.GetName() )
603 rDesc.SetName( rChged.GetName() );
605 // A RegisterChange is triggered, if necessary
606 rDesc.SetRegisterFormatColl( rChged.GetRegisterFormatColl() );
608 // If UseOn or the Follow change, the paragraphs need to know about it.
609 bool bUseOn = false;
610 bool bFollow = false;
611 if (rDesc.GetUseOn() != rChged.GetUseOn())
613 rDesc.SetUseOn( rChged.GetUseOn() );
614 bUseOn = true;
616 if (rDesc.GetFollow() != rChged.GetFollow())
618 if (rChged.GetFollow() == &rChged)
620 if (rDesc.GetFollow() != &rDesc)
622 rDesc.SetFollow( &rDesc );
623 bFollow = true;
626 else
628 rDesc.SetFollow( rChged.m_pFollow );
629 bFollow = true;
633 if ( (bUseOn || bFollow) && pTmpRoot)
634 // Inform layout!
636 for( auto aLayout : GetAllLayouts() )
637 aLayout->AllCheckPageDescs();
640 // Take over the page attributes.
641 ::lcl_DescSetAttr( rChged.GetMaster(), rDesc.GetMaster() );
642 ::lcl_DescSetAttr( rChged.GetLeft(), rDesc.GetLeft() );
643 ::lcl_DescSetAttr( rChged.GetFirstMaster(), rDesc.GetFirstMaster() );
644 ::lcl_DescSetAttr( rChged.GetFirstLeft(), rDesc.GetFirstLeft() );
646 // If the FootnoteInfo changes, the pages are triggered.
647 if( !(rDesc.GetFootnoteInfo() == rChged.GetFootnoteInfo()) )
649 rDesc.SetFootnoteInfo( rChged.GetFootnoteInfo() );
650 sw::PageFootnoteHint aHint;
651 rDesc.GetMaster().CallSwClientNotify(aHint);
652 rDesc.GetLeft().CallSwClientNotify(aHint);
653 rDesc.GetFirstMaster().CallSwClientNotify(aHint);
654 rDesc.GetFirstLeft().CallSwClientNotify(aHint);
656 getIDocumentState().SetModified();
658 SfxBindings* pBindings =
659 ( GetDocShell() && GetDocShell()->GetDispatcher() ) ? GetDocShell()->GetDispatcher()->GetBindings() : nullptr;
660 if ( pBindings )
662 pBindings->Invalidate( SID_ATTR_PAGE_COLUMN );
663 pBindings->Invalidate( SID_ATTR_PAGE );
664 pBindings->Invalidate( SID_ATTR_PAGE_SIZE );
665 pBindings->Invalidate( SID_ATTR_PAGE_ULSPACE );
666 pBindings->Invalidate( SID_ATTR_PAGE_LRSPACE );
669 //h/f of first-left page must not be unique but same as first master or left
670 assert((rDesc.IsFirstShared())
671 ? rDesc.GetFirstLeft().GetHeader().GetHeaderFormat() == rDesc.GetLeft().GetHeader().GetHeaderFormat()
672 : rDesc.GetFirstLeft().GetHeader().GetHeaderFormat() == rDesc.GetFirstMaster().GetHeader().GetHeaderFormat());
673 assert((rDesc.IsFirstShared())
674 ? rDesc.GetFirstLeft().GetFooter().GetFooterFormat() == rDesc.GetLeft().GetFooter().GetFooterFormat()
675 : rDesc.GetFirstLeft().GetFooter().GetFooterFormat() == rDesc.GetFirstMaster().GetFooter().GetFooterFormat());
678 /// All descriptors whose Follow point to the to-be-deleted have to be adapted.
679 // #i7983#
680 void SwDoc::PreDelPageDesc(SwPageDesc const * pDel)
682 if (nullptr == pDel)
683 return;
685 // mba: test iteration as clients are removed while iteration
686 SwPageDescHint aHint( m_PageDescs[0] );
687 pDel->CallSwClientNotify( aHint );
689 bool bHasLayout = getIDocumentLayoutAccess().HasLayout();
690 if ( mpFootnoteInfo->DependsOn( pDel ) )
692 mpFootnoteInfo->ChgPageDesc( m_PageDescs[0] );
693 if ( bHasLayout )
695 for( auto aLayout : GetAllLayouts() )
696 aLayout->CheckFootnotePageDescs(false);
699 else if ( mpEndNoteInfo->DependsOn( pDel ) )
701 mpEndNoteInfo->ChgPageDesc( m_PageDescs[0] );
702 if ( bHasLayout )
704 for( auto aLayout : GetAllLayouts() )
705 aLayout->CheckFootnotePageDescs(true);
709 for (SwPageDesc* pPageDesc : m_PageDescs)
711 if (pPageDesc->GetFollow() == pDel)
713 pPageDesc->SetFollow(nullptr);
714 if( bHasLayout )
716 for( auto aLayout : GetAllLayouts() )
717 aLayout->AllCheckPageDescs();
723 void SwDoc::BroadcastStyleOperation(const OUString& rName, SfxStyleFamily eFamily,
724 SfxHintId nOp)
726 if (mpDocShell)
728 SfxStyleSheetBasePool * pPool = mpDocShell->GetStyleSheetPool();
730 if (pPool)
732 SfxStyleSheetBase* pBase = pPool->Find(rName, eFamily);
734 if (pBase != nullptr)
735 pPool->Broadcast(SfxStyleSheetHint( nOp, *pBase ));
740 void SwDoc::DelPageDesc( size_t i, bool bBroadcast )
742 OSL_ENSURE(i < m_PageDescs.size(), "PageDescs is out of range.");
743 OSL_ENSURE( i != 0, "You cannot delete the default Pagedesc.");
744 if ( i == 0 )
745 return;
747 SwPageDesc &rDel = *m_PageDescs[i];
749 if (bBroadcast)
750 BroadcastStyleOperation(rDel.GetName(), SfxStyleFamily::Page,
751 SfxHintId::StyleSheetErased);
753 if (GetIDocumentUndoRedo().DoesUndo())
755 GetIDocumentUndoRedo().AppendUndo(
756 std::make_unique<SwUndoPageDescDelete>(rDel, this));
759 PreDelPageDesc(&rDel); // #i7983#
761 m_PageDescs.erase(m_PageDescs.begin() + i);
762 getIDocumentState().SetModified();
765 SwPageDesc* SwDoc::MakePageDesc(const OUString &rName, const SwPageDesc *pCpy,
766 bool bRegardLanguage, bool bBroadcast)
768 SwPageDesc *pNew;
769 if( pCpy )
771 pNew = new SwPageDesc( *pCpy );
772 pNew->SetName( rName );
773 if( rName != pCpy->GetName() )
775 pNew->SetPoolFormatId( USHRT_MAX );
776 pNew->SetPoolHelpId( USHRT_MAX );
777 pNew->SetPoolHlpFileId( UCHAR_MAX );
780 else
782 pNew = new SwPageDesc( rName, GetDfltFrameFormat(), this );
783 // Set the default page format.
784 lcl_DefaultPageFormat( USHRT_MAX, pNew->GetMaster(), pNew->GetLeft(), pNew->GetFirstMaster(), pNew->GetFirstLeft() );
786 SvxFrameDirection aFrameDirection = bRegardLanguage ?
787 GetDefaultFrameDirection(GetAppLanguage())
788 : SvxFrameDirection::Horizontal_LR_TB;
790 pNew->GetMaster().SetFormatAttr( SvxFrameDirectionItem(aFrameDirection, RES_FRAMEDIR) );
791 pNew->GetLeft().SetFormatAttr( SvxFrameDirectionItem(aFrameDirection, RES_FRAMEDIR) );
792 pNew->GetFirstMaster().SetFormatAttr( SvxFrameDirectionItem(aFrameDirection, RES_FRAMEDIR) );
793 pNew->GetFirstLeft().SetFormatAttr( SvxFrameDirectionItem(aFrameDirection, RES_FRAMEDIR) );
796 std::pair<SwPageDescs::const_iterator, bool> res = m_PageDescs.push_back( pNew );
797 SAL_WARN_IF(!res.second, "sw", "MakePageDesc called with existing name" );
799 if (bBroadcast)
800 BroadcastStyleOperation(rName, SfxStyleFamily::Page,
801 SfxHintId::StyleSheetCreated);
803 if (GetIDocumentUndoRedo().DoesUndo())
805 GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoPageDescCreate>(pNew, this));
808 getIDocumentState().SetModified();
809 return pNew;
812 void SwDoc::PrtOLENotify( bool bAll )
814 SwFEShell *pShell = nullptr;
816 SwViewShell *pSh = getIDocumentLayoutAccess().GetCurrentViewShell();
817 if ( pSh )
819 for(SwViewShell& rShell : pSh->GetRingContainer())
821 if(auto pFEShell = dynamic_cast<SwFEShell*>( &rShell))
823 pShell = pFEShell;
824 break;
829 if ( !pShell )
831 // This doesn't make sense without a Shell and thus without a client, because
832 // the communication about size changes is implemented by these components.
833 // Because we don't have a Shell we remember this unfortunate situation
834 // in the document,
835 // which is made up for later on when creating the first Shell.
836 mbOLEPrtNotifyPending = true;
837 if ( bAll )
838 mbAllOLENotify = true;
840 else
842 if ( mbAllOLENotify )
843 bAll = true;
845 mbOLEPrtNotifyPending = mbAllOLENotify = false;
847 std::unique_ptr<SwOLENodes> pNodes = SwContentNode::CreateOLENodesArray( *GetDfltGrfFormatColl(), !bAll );
848 if ( pNodes )
850 ::StartProgress( STR_STATSTR_SWGPRTOLENOTIFY,
851 0, pNodes->size(), GetDocShell());
852 getIDocumentLayoutAccess().GetCurrentLayout()->StartAllAction();
854 for( SwOLENodes::size_type i = 0; i < pNodes->size(); ++i )
856 ::SetProgressState( i, GetDocShell() );
858 SwOLENode* pOLENd = (*pNodes)[i];
859 pOLENd->SetOLESizeInvalid( false );
861 // At first load the Infos and see if it's not already in the exclude list.
862 SvGlobalName aName;
864 svt::EmbeddedObjectRef& xObj = pOLENd->GetOLEObj().GetObject();
865 if ( xObj.is() )
866 aName = SvGlobalName( xObj->getClassID() );
867 else // Not yet loaded
869 // TODO/LATER: retrieve ClassID of an unloaded object
870 // aName = ????
873 bool bFound = false;
874 for ( std::vector<SvGlobalName>::size_type j = 0;
875 j < pGlobalOLEExcludeList->size() && !bFound;
876 ++j )
878 bFound = (*pGlobalOLEExcludeList)[j] == aName;
880 if ( bFound )
881 continue;
883 // We don't know it, so the object has to be loaded.
884 // If it doesn't want to be informed
885 if ( xObj.is() )
887 pGlobalOLEExcludeList->push_back( aName );
890 pNodes.reset();
891 getIDocumentLayoutAccess().GetCurrentLayout()->EndAllAction();
892 ::EndProgress( GetDocShell() );
897 IMPL_LINK_NOARG( SwDoc, DoUpdateModifiedOLE, Timer *, void )
899 SwFEShell* pSh = static_cast<SwFEShell*>(GetEditShell());
900 if (!pSh)
901 return;
903 mbOLEPrtNotifyPending = mbAllOLENotify = false;
905 std::unique_ptr<SwOLENodes> pNodes = SwContentNode::CreateOLENodesArray( *GetDfltGrfFormatColl(), true );
906 if( !pNodes )
907 return;
909 ::StartProgress( STR_STATSTR_SWGPRTOLENOTIFY,
910 0, pNodes->size(), GetDocShell());
911 getIDocumentLayoutAccess().GetCurrentLayout()->StartAllAction();
912 SwUpdateAttr aHint(0,0,0);
913 for( SwOLENodes::size_type i = 0; i < pNodes->size(); ++i )
915 ::SetProgressState( i, GetDocShell() );
917 SwOLENode* pOLENd = (*pNodes)[i];
918 pOLENd->SetOLESizeInvalid( false );
920 // We don't know it, so the object has to be loaded.
921 // If it doesn't want to be informed
922 if( pOLENd->GetOLEObj().GetOleRef().is() ) // Broken?
924 pOLENd->UpdateAttr(aHint);
927 getIDocumentLayoutAccess().GetCurrentLayout()->EndAllAction();
928 ::EndProgress( GetDocShell() );
931 static SwPageDesc* lcl_FindPageDesc( const SwPageDescs *pPageDescs,
932 size_t *pPos, const OUString &rName )
934 SwPageDesc* res = nullptr;
935 SwPageDescs::const_iterator it = pPageDescs->find( rName );
936 if( it != pPageDescs->end() )
938 res = *it;
939 if( pPos )
940 *pPos = std::distance( pPageDescs->begin(), it );
942 else if( pPos )
943 *pPos = SIZE_MAX;
944 return res;
947 SwPageDesc* SwDoc::FindPageDesc( const OUString & rName, size_t* pPos ) const
949 return lcl_FindPageDesc( &m_PageDescs, pPos, rName );
952 bool SwDoc::ContainsPageDesc( const SwPageDesc *pDesc, size_t* pPos ) const
954 if( pDesc == nullptr )
955 return false;
956 if( !m_PageDescs.contains( const_cast <SwPageDesc*>( pDesc ) ) ) {
957 if( pPos )
958 *pPos = SIZE_MAX;
959 return false;
961 if( ! pPos )
962 return true;
964 SwPageDesc* desc = lcl_FindPageDesc(
965 &m_PageDescs, pPos, pDesc->GetName() );
966 SAL_WARN_IF( desc != pDesc, "sw", "SwPageDescs container is broken!" );
967 return true;
970 void SwDoc::DelPageDesc( const OUString & rName, bool bBroadcast )
972 size_t nI;
974 if (FindPageDesc(rName, &nI))
975 DelPageDesc(nI, bBroadcast);
978 void SwDoc::ChgPageDesc( const OUString & rName, const SwPageDesc & rDesc)
980 size_t nI;
982 if (FindPageDesc(rName, &nI))
983 ChgPageDesc(nI, rDesc);
987 * The HTML import cannot resist changing the page descriptions, I don't
988 * know why. This function is meant to check the page descriptors for invalid
989 * values.
991 void SwDoc::CheckDefaultPageFormat()
993 for ( size_t i = 0; i < GetPageDescCnt(); ++i )
995 SwPageDesc& rDesc = GetPageDesc( i );
997 SwFrameFormat& rMaster = rDesc.GetMaster();
998 SwFrameFormat& rLeft = rDesc.GetLeft();
1000 const SwFormatFrameSize& rMasterSize = rMaster.GetFrameSize();
1001 const SwFormatFrameSize& rLeftSize = rLeft.GetFrameSize();
1003 const bool bSetSize = INVALID_TWIPS == rMasterSize.GetWidth() ||
1004 INVALID_TWIPS == rMasterSize.GetHeight() ||
1005 INVALID_TWIPS == rLeftSize.GetWidth() ||
1006 INVALID_TWIPS == rLeftSize.GetHeight();
1008 if ( bSetSize )
1009 lcl_DefaultPageFormat( rDesc.GetPoolFormatId(), rDesc.GetMaster(), rDesc.GetLeft(), rDesc.GetFirstMaster(), rDesc.GetFirstLeft() );
1013 void SwDoc::SetDefaultPageMode(bool bSquaredPageMode)
1015 if( !bSquaredPageMode == !IsSquaredPageMode() )
1016 return;
1018 const SwTextGridItem& rGrid = GetDefault( RES_TEXTGRID );
1019 SwTextGridItem aNewGrid = rGrid;
1020 aNewGrid.SetSquaredMode(bSquaredPageMode);
1021 aNewGrid.Init();
1022 SetDefault(aNewGrid);
1024 for ( size_t i = 0; i < GetPageDescCnt(); ++i )
1026 SwPageDesc& rDesc = GetPageDesc( i );
1028 SwFrameFormat& rMaster = rDesc.GetMaster();
1029 SwFrameFormat& rLeft = rDesc.GetLeft();
1031 SwTextGridItem aGrid(rMaster.GetFormatAttr(RES_TEXTGRID));
1032 aGrid.SwitchPaperMode( bSquaredPageMode );
1033 rMaster.SetFormatAttr(aGrid);
1034 rLeft.SetFormatAttr(aGrid);
1038 bool SwDoc::IsSquaredPageMode() const
1040 const SwTextGridItem& rGrid = GetDefault( RES_TEXTGRID );
1041 return rGrid.IsSquaredMode();
1044 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */