/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
staticvoid lcl_DefaultPageFormat( sal_uInt16 nPoolFormatId,
SwFrameFormat &rFormat1,
SwFrameFormat &rFormat2,
SwFrameFormat &rFormat3,
SwFrameFormat &rFormat4)
{ // --> #i41075# Printer on demand // This function does not require a printer anymore. // The default page size is obtained from the application //locale
// Prepare for default margins. // Margins have a default minimum size. // If the printer forces a larger margins, that's ok too. // The HTML page desc had A4 as page size always. // This has been changed to take the page size from the printer. // Unfortunately, the margins of the HTML page desc are smaller than // the margins used here in general, so one extra case is required. // In the long term, this needs to be changed to always keep the // margins from the page desc.
sal_Int32 nMinTop, nMinBottom, nMinLeft, nMinRight; if( RES_POOLPAGE_HTML == nPoolFormatId )
{
nMinRight = nMinTop = nMinBottom = o3tl::toTwips(1, o3tl::Length::cm);
nMinLeft = o3tl::toTwips(2, o3tl::Length::cm);
} elseif (!comphelper::IsFuzzing() && MeasurementSystem::Metric == SvtSysLocale().GetLocaleData().getMeasurementSystemEnum() )
{
nMinTop = nMinBottom = nMinLeft = nMinRight = o3tl::toTwips(2, o3tl::Length::cm);
} else
{
nMinTop = nMinBottom = o3tl::toTwips(1, o3tl::Length::in); // as in MS Word
nMinLeft = nMinRight = o3tl::toTwips(1.25, o3tl::Length::in);
}
staticvoid lcl_DescSetAttr( const SwFrameFormat &rSource, SwFrameFormat &rDest, constbool bPage = true )
{ // We should actually use ItemSet's Intersect here, but that doesn't work // correctly if we have different WhichRanges.
// Take over the attributes which are of interest.
sal_uInt16 const aIdArr[] = {
RES_FRM_SIZE, RES_UL_SPACE, // [83..86
RES_BACKGROUND, RES_SHADOW, // [99..101
RES_COL, RES_COL, // [103
RES_TEXTGRID, RES_TEXTGRID, // [109
RES_FRAMEDIR, RES_FRAMEDIR, // [114
RES_HEADER_FOOTER_EAT_SPACING, RES_HEADER_FOOTER_EAT_SPACING, // [115
RES_BACKGROUND_FULL_SIZE, RES_BACKGROUND_FULL_SIZE, // [131
RES_RTL_GUTTER, RES_RTL_GUTTER, // [132
RES_UNKNOWNATR_CONTAINER, RES_UNKNOWNATR_CONTAINER, // [143
// take over DrawingLayer FillStyles
XATTR_FILL_FIRST, XATTR_FILL_LAST, // [1014
0};
const SfxPoolItem* pItem; for( sal_uInt16 n = 0; aIdArr[ n ]; n += 2 )
{ for( sal_uInt16 nId = aIdArr[ n ]; nId <= aIdArr[ n+1]; ++nId )
{ // #i45539# // bPage == true: // All in aIdArr except from RES_HEADER_FOOTER_EAT_SPACING // bPage == false: // All in aIdArr except from RES_COL and RES_PAPER_BIN: bool bExecuteId(true);
if(bPage)
{ // When Page switch(nId)
{ // All in aIdArr except from RES_HEADER_FOOTER_EAT_SPACING case RES_HEADER_FOOTER_EAT_SPACING: // take out SvxBrushItem; it's the result of the fallback // at SwFormat::GetItemState and not really in state SfxItemState::SET case RES_BACKGROUND:
bExecuteId = false; break; default: break;
}
} else
{ // When not Page switch(nId)
{ // When not Page: All in aIdArr except these: case RES_COL: case RES_PAPER_BIN: case RES_BACKGROUND_FULL_SIZE: case RES_RTL_GUTTER:
bExecuteId = false; break; default: break;
}
}
// Transmit pool and help IDs too
rDest.SetPoolFormatId( rSource.GetPoolFormatId() );
rDest.SetPoolHelpId( rSource.GetPoolHelpId() );
rDest.SetPoolHlpFileId( rSource.GetPoolHlpFileId() );
}
void SwDoc::CopyMasterHeader(const SwPageDesc &rChged, const SwFormatHeader &rHead, SwPageDesc &rDesc, bool bLeft, bool bFirst)
{
assert(bLeft || bFirst);
SwFrameFormat& rDescFrameFormat = getFrameFormat(rDesc, bLeft, bFirst); if (bFirst && bLeft)
{ // special case: always shared with something
rDescFrameFormat.SetFormatAttr( rChged.IsFirstShared()
? rDesc.GetLeft().GetHeader()
: rDesc.GetFirstMaster().GetHeader());
} elseif ((bFirst ? rChged.IsFirstShared() : rChged.IsHeaderShared())
|| !rHead.IsActive())
{ // Left or first shares the header with the Master.
rDescFrameFormat.SetFormatAttr( rDesc.GetMaster().GetHeader() );
} elseif ( rHead.IsActive() )
{ // Left or first gets its own header if the Format doesn't already have one. // If it already has one and it points to the same Section as the // Right one, it needs to get an own Header. // The content is evidently copied. const SwFormatHeader &rFormatHead = rDescFrameFormat.GetHeader(); if ( !rFormatHead.IsActive() )
{
SwFormatHeader aHead( getIDocumentLayoutAccess().MakeLayoutFormat( RndStdIds::HEADERL, nullptr ) );
rDescFrameFormat.SetFormatAttr( aHead ); // take over additional attributes (margins, borders ...)
::lcl_DescSetAttr( *rHead.GetHeaderFormat(), *aHead.GetHeaderFormat(), false);
} else
{ const SwFormatContent &aCnt = rFormatHead.GetHeaderFormat()->GetContent();
if ((*aRCnt.GetContentIdx() == *aCnt.GetContentIdx()) || // The ContentIdx is _always_ different when called from // SwDocStyleSheet::SetItemSet, because it deep-copies the // PageDesc. So check if it was previously shared.
(bFirst ? rDesc.IsFirstShared() : rDesc.IsHeaderShared()))
{
SwFrameFormat *pFormat = new SwFrameFormat( GetAttrPool(),
UIName(bFirst ? u"First header"_ustr : u"Left header"_ustr),
GetDfltFrameFormat() );
::lcl_DescSetAttr( *pRight, *pFormat, false ); // The section which the right header attribute is pointing // is copied, and the Index to the StartNode is set to // the left or first header attribute.
SwStartNode* pSttNd = SwNodes::MakeEmptySection( GetNodes().GetEndOfAutotext(), SwHeaderStartNode );
SwNodeRange aRange( aRCnt.GetContentIdx()->GetNode(), SwNodeOffset(0),
*aRCnt.GetContentIdx()->GetNode().EndOfSectionNode() );
GetNodes().Copy_( aRange, *pSttNd->EndOfSectionNode(), false );
GetDocumentContentOperationsManager().CopyFlyInFlyImpl(aRange, nullptr, *pSttNd);
SwPaM const source(aRange.aStart, aRange.aEnd);
SwPosition dest(*pSttNd);
sw::CopyBookmarks(source, dest);
pFormat->SetFormatAttr( SwFormatContent( pSttNd ) );
rDescFrameFormat.SetFormatAttr( SwFormatHeader( pFormat ) );
} else
::lcl_DescSetAttr( *pRight,
*const_cast<SwFrameFormat*>(rFormatHead.GetHeaderFormat()), false );
}
}
}
}
void SwDoc::CopyMasterFooter(const SwPageDesc &rChged, const SwFormatFooter &rFoot, SwPageDesc &rDesc, bool bLeft, bool bFirst)
{
assert(bLeft || bFirst);
SwFrameFormat& rDescFrameFormat = getFrameFormat(rDesc, bLeft, bFirst); if (bFirst && bLeft)
{ // special case: always shared with something
rDescFrameFormat.SetFormatAttr( rChged.IsFirstShared()
? rDesc.GetLeft().GetFooter()
: rDesc.GetFirstMaster().GetFooter());
} elseif ((bFirst ? rChged.IsFirstShared() : rChged.IsFooterShared())
|| !rFoot.IsActive())
{ // Left or first shares the Header with the Master.
rDescFrameFormat.SetFormatAttr( rDesc.GetMaster().GetFooter() );
} elseif ( rFoot.IsActive() )
{ // Left or first gets its own Footer if the Format does not already have one. // If the Format already has a Footer and it points to the same section as the Right one, // it needs to get an own one. // The content is evidently copied. const SwFormatFooter &rFormatFoot = rDescFrameFormat.GetFooter(); if ( !rFormatFoot.IsActive() )
{
SwFormatFooter aFoot( getIDocumentLayoutAccess().MakeLayoutFormat( RndStdIds::FOOTER, nullptr ) );
rDescFrameFormat.SetFormatAttr( aFoot ); // Take over additional attributes (margins, borders ...).
::lcl_DescSetAttr( *rFoot.GetFooterFormat(), *aFoot.GetFooterFormat(), false);
} else
{ const SwFormatContent &aLCnt = rFormatFoot.GetFooterFormat()->GetContent(); if( !aLCnt.GetContentIdx() )
{ const SwFrameFormat& rChgedFrameFormat = getConstFrameFormat(rChged, bLeft, bFirst);
rDescFrameFormat.SetFormatAttr( rChgedFrameFormat.GetFooter() );
} else
{ const SwFrameFormat *pRight = rFoot.GetFooterFormat(); if (!pRight) return; const SwFormatContent &aRCnt = pRight->GetContent();
if ((*aRCnt.GetContentIdx() == *aLCnt.GetContentIdx()) || // The ContentIdx is _always_ different when called from // SwDocStyleSheet::SetItemSet, because it deep-copies the // PageDesc. So check if it was previously shared.
(bFirst ? rDesc.IsFirstShared() : rDesc.IsFooterShared()))
{
SwFrameFormat *pFormat = new SwFrameFormat( GetAttrPool(),
UIName(bFirst ? u"First footer"_ustr : u"Left footer"_ustr),
GetDfltFrameFormat() );
::lcl_DescSetAttr( *pRight, *pFormat, false ); // The section to which the right footer attribute is pointing // is copied, and the Index to the StartNode is set to // the left footer attribute.
SwStartNode* pSttNd = SwNodes::MakeEmptySection( GetNodes().GetEndOfAutotext(), SwFooterStartNode );
SwNodeRange aRange( aRCnt.GetContentIdx()->GetNode(), SwNodeOffset(0),
*aRCnt.GetContentIdx()->GetNode().EndOfSectionNode() );
GetNodes().Copy_( aRange, *pSttNd->EndOfSectionNode(), false );
GetDocumentContentOperationsManager().CopyFlyInFlyImpl(aRange, nullptr, *pSttNd);
SwPaM const source(aRange.aStart, aRange.aEnd);
SwPosition dest(*pSttNd);
sw::CopyBookmarks(source, dest);
pFormat->SetFormatAttr( SwFormatContent( pSttNd ) );
rDescFrameFormat.SetFormatAttr( SwFormatFooter( pFormat ) );
} else
::lcl_DescSetAttr( *pRight,
*const_cast<SwFrameFormat*>(rFormatFoot.GetFooterFormat()), false );
}
}
}
}
void SwDoc::ChgPageDesc( size_t i, const SwPageDesc &rChged )
{
assert(i < m_PageDescs.size() && "PageDescs is out of range.");
// tdf#141613 FIXME: Disable redoing header/footer changes for now. // The proper solution would be to write a SwUndoHeaderFooter class // to represent the addition of a header or footer to the current page.
GetIDocumentUndoRedo().ClearRedo();
}
}
::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
// Mirror at first if needed. if ( rChged.GetUseOn() == UseOnPage::Mirror ) const_cast<SwPageDesc&>(rChged).Mirror(); else
{ // Or else transfer values from Master to Left
::lcl_DescSetAttr(rChged.GetMaster(), const_cast<SwPageDesc&>(rChged).GetLeft());
}
::lcl_DescSetAttr(rChged.GetMaster(), const_cast<SwPageDesc&>(rChged).GetFirstMaster());
::lcl_DescSetAttr(rChged.GetLeft(), const_cast<SwPageDesc&>(rChged).GetFirstLeft());
// Take over NumType. if( rChged.GetNumType().GetNumberingType() != rDesc.GetNumType().GetNumberingType() )
{
rDesc.SetNumType( rChged.GetNumType() ); // Notify page number fields that NumFormat has changed
getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::PageNumber )->UpdateFields();
getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::RefPageGet )->UpdateFields();
// If the numbering scheme has changed we could have QuoVadis/ErgoSum texts // that refer to a changed page, so we invalidate foot notes.
SwFootnoteIdxs& rFootnoteIdxs = GetFootnoteIdxs(); for( SwFootnoteIdxs::size_type nPos = 0; nPos < rFootnoteIdxs.size(); ++nPos )
{
SwTextFootnote *pTextFootnote = rFootnoteIdxs[ nPos ]; const SwFormatFootnote &rFootnote = pTextFootnote->GetFootnote();
pTextFootnote->SetNumber(rFootnote.GetNumber(), rFootnote.GetNumberRLHidden(), rFootnote.GetNumStr());
}
}
// Take over orientation
rDesc.SetLandscape( rChged.GetLandscape() );
if (pStashedLeftFoot)
rDesc.RemoveStashedFormat(false, true, false);
if (pStashedFirstMasterFoot)
rDesc.RemoveStashedFormat(false, false, true);
if (pStashedFirstLeftFoot)
rDesc.RemoveStashedFormat(false, true, true);
rDesc.ChgFooterShare( rChged.IsFooterShared() ); // there is just one first shared flag for both header and footer?
rDesc.ChgFirstShare( rChged.IsFirstShared() );
if ( rDesc.GetName() != rChged.GetName() )
rDesc.SetName( rChged.GetName() );
// A RegisterChange is triggered, if necessary
rDesc.SetRegisterFormatColl( rChged.GetRegisterFormatColl() );
// If UseOn or the Follow change, the paragraphs need to know about it. bool bUseOn = false; bool bFollow = false; if (rDesc.GetUseOn() != rChged.GetUseOn())
{
rDesc.SetUseOn( rChged.GetUseOn() );
bUseOn = true;
} if (rDesc.GetFollow() != rChged.GetFollow())
{ if (rChged.GetFollow() == &rChged)
{ if (rDesc.GetFollow() != &rDesc)
{
rDesc.SetFollow( &rDesc );
bFollow = true;
}
} else
{
rDesc.SetFollow( rChged.m_pFollow );
bFollow = true;
}
}
if ( (bUseOn || bFollow) && pTmpRoot) // Inform layout!
{ for( auto aLayout : GetAllLayouts() )
aLayout->AllCheckPageDescs();
}
// Take over the page attributes.
::lcl_DescSetAttr( rChged.GetMaster(), rDesc.GetMaster() );
::lcl_DescSetAttr( rChged.GetLeft(), rDesc.GetLeft() );
::lcl_DescSetAttr( rChged.GetFirstMaster(), rDesc.GetFirstMaster() );
::lcl_DescSetAttr( rChged.GetFirstLeft(), rDesc.GetFirstLeft() );
// If the FootnoteInfo changes, the pages are triggered. if( !(rDesc.GetFootnoteInfo() == rChged.GetFootnoteInfo()) )
{
rDesc.SetFootnoteInfo( rChged.GetFootnoteInfo() );
sw::PageFootnoteHint aHint;
rDesc.GetMaster().CallSwClientNotify(aHint);
rDesc.GetLeft().CallSwClientNotify(aHint);
rDesc.GetFirstMaster().CallSwClientNotify(aHint);
rDesc.GetFirstLeft().CallSwClientNotify(aHint);
}
getIDocumentState().SetModified();
//h/f of first-left page must not be unique but same as first master or left
assert((rDesc.IsFirstShared())
? rDesc.GetFirstLeft().GetHeader().GetHeaderFormat() == rDesc.GetLeft().GetHeader().GetHeaderFormat()
: rDesc.GetFirstLeft().GetHeader().GetHeaderFormat() == rDesc.GetFirstMaster().GetHeader().GetHeaderFormat());
assert((rDesc.IsFirstShared())
? rDesc.GetFirstLeft().GetFooter().GetFooterFormat() == rDesc.GetLeft().GetFooter().GetFooterFormat()
: rDesc.GetFirstLeft().GetFooter().GetFooterFormat() == rDesc.GetFirstMaster().GetFooter().GetFooterFormat());
}
/// All descriptors whose Follow point to the to-be-deleted have to be adapted. // #i7983# void SwDoc::PreDelPageDesc(SwPageDesc const * pDel)
{ if (nullptr == pDel) return;
// mba: test iteration as clients are removed while iteration
SwPageDescHint aHint( m_PageDescs[0] );
pDel->CallSwClientNotify( aHint );
void SwDoc::DelPageDesc( size_t i, bool bBroadcast )
{
OSL_ENSURE(i < m_PageDescs.size(), "PageDescs is out of range.");
OSL_ENSURE( i != 0, "You cannot delete the default Pagedesc."); if ( i == 0 ) return;
SwPageDesc &rDel = *m_PageDescs[i];
if (bBroadcast)
BroadcastStyleOperation(rDel.GetName(), SfxStyleFamily::Page,
SfxHintId::StyleSheetErased);
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().AppendUndo(
std::make_unique<SwUndoPageDescDelete>(rDel, *this));
}
std::pair<SwPageDescs::const_iterator, bool> res = m_PageDescs.push_back( pNew );
SAL_WARN_IF(!res.second, "sw", "MakePageDesc called with existing name" );
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoPageDescCreate>(pNew, *this));
}
getIDocumentState().SetModified(); return pNew;
}
void SwDoc::PrtOLENotify( bool bAll )
{
SwFEShell *pShell = nullptr;
{
SwViewShell *pSh = getIDocumentLayoutAccess().GetCurrentViewShell(); if ( pSh )
{ for(SwViewShell& rShell : pSh->GetRingContainer())
{ if(auto pFEShell = dynamic_cast<SwFEShell*>( &rShell))
{
pShell = pFEShell; break;
}
}
}
} if ( !pShell )
{ // This doesn't make sense without a Shell and thus without a client, because // the communication about size changes is implemented by these components. // Because we don't have a Shell we remember this unfortunate situation // in the document, // which is made up for later on when creating the first Shell.
mbOLEPrtNotifyPending = true; if ( bAll )
mbAllOLENotify = true;
} else
{ if ( mbAllOLENotify )
bAll = true;
// We don't know it, so the object has to be loaded. // If it doesn't want to be informed if ( xObj.is() )
{
pGlobalOLEExcludeList->push_back( aName );
}
}
pNodes.reset();
getIDocumentLayoutAccess().GetCurrentLayout()->EndAllAction();
::EndProgress( GetDocShell() );
}
}
}
// We don't know it, so the object has to be loaded. // If it doesn't want to be informed if( pOLENd->GetOLEObj().GetOleRef().is() ) // Broken?
{
pOLENd->UpdateAttr(aHint);
}
}
getIDocumentLayoutAccess().GetCurrentLayout()->EndAllAction();
::EndProgress( GetDocShell() );
}
if (FindPageDesc(rName, &nI))
ChgPageDesc(nI, rDesc);
}
/* * The HTML import cannot resist changing the page descriptions, I don't * know why. This function is meant to check the page descriptors for invalid * values.
*/ void SwDoc::CheckDefaultPageFormat()
{ for ( size_t i = 0; i < GetPageDescCnt(); ++i )
{
SwPageDesc& rDesc = GetPageDesc( i );
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.