/* -*- 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SwEndNoteInfo& SwEndNoteInfo::operator=(const SwEndNoteInfo& rInfo) { m_pTextFormatColl = rInfo.m_pTextFormatColl; m_pPageDesc = rInfo.m_pPageDesc; m_pCharFormat = rInfo.m_pCharFormat; m_pAnchorFormat = rInfo.m_pAnchorFormat; m_aDepends.EndListeningAll(); m_aDepends.StartListening(m_pTextFormatColl); m_aDepends.StartListening(m_pPageDesc); m_aDepends.StartListening(m_pCharFormat); m_aDepends.StartListening(m_pAnchorFormat); m_aFormat = rInfo.m_aFormat; m_nFootnoteOffset = rInfo.m_nFootnoteOffset; m_bEndNote = rInfo.m_bEndNote; m_sPrefix = rInfo.m_sPrefix; m_sSuffix = rInfo.m_sSuffix; return *this; } bool SwEndNoteInfo::operator==( const SwEndNoteInfo& rInfo ) const { return m_pTextFormatColl == rInfo.m_pTextFormatColl && m_pPageDesc == rInfo.m_pPageDesc && m_pCharFormat == rInfo.m_pCharFormat && m_pAnchorFormat == rInfo.m_pAnchorFormat && m_aFormat.GetNumberingType() == rInfo.m_aFormat.GetNumberingType() && m_nFootnoteOffset == rInfo.m_nFootnoteOffset && m_bEndNote == rInfo.m_bEndNote && m_sPrefix == rInfo.m_sPrefix && m_sSuffix == rInfo.m_sSuffix; } SwEndNoteInfo::SwEndNoteInfo(const SwEndNoteInfo& rInfo) : SwClient(nullptr), m_aDepends(*this), m_pTextFormatColl(rInfo.m_pTextFormatColl), m_pPageDesc(rInfo.m_pPageDesc), m_pCharFormat(rInfo.m_pCharFormat), m_pAnchorFormat(rInfo.m_pAnchorFormat), m_sPrefix( rInfo.m_sPrefix ), m_sSuffix( rInfo.m_sSuffix ), m_bEndNote( true ), m_aFormat( rInfo.m_aFormat ), m_nFootnoteOffset( rInfo.m_nFootnoteOffset ) { m_aDepends.StartListening(m_pTextFormatColl); m_aDepends.StartListening(m_pPageDesc); m_aDepends.StartListening(m_pCharFormat); m_aDepends.StartListening(m_pAnchorFormat); } SwEndNoteInfo::SwEndNoteInfo() : SwClient(nullptr), m_aDepends(*this), m_pTextFormatColl(nullptr), m_pPageDesc(nullptr), m_pCharFormat(nullptr), m_pAnchorFormat(nullptr), m_bEndNote( true ), m_nFootnoteOffset( 0 ) { m_aFormat.SetNumberingType(SVX_NUM_ROMAN_LOWER); } SwPageDesc* SwEndNoteInfo::GetPageDesc(SwDoc& rDoc) const { if(!m_pPageDesc) { m_pPageDesc = rDoc.getIDocumentStylePoolAccess().GetPageDescFromPool( static_cast( m_bEndNote ? RES_POOLPAGE_ENDNOTE : RES_POOLPAGE_FOOTNOTE ) ); m_aDepends.StartListening(m_pPageDesc); } return m_pPageDesc; } bool SwEndNoteInfo::KnowsPageDesc() const { return m_pPageDesc != nullptr; } bool SwEndNoteInfo::DependsOn(const SwPageDesc* pDesc) const { return m_pPageDesc == pDesc; } void SwEndNoteInfo::ChgPageDesc(SwPageDesc* pDesc) { m_aDepends.EndListening(m_pPageDesc); m_pPageDesc = pDesc; m_aDepends.StartListening(m_pPageDesc); } void SwEndNoteInfo::SetFootnoteTextColl(SwTextFormatColl& rFormat) { m_aDepends.EndListening(m_pTextFormatColl); m_pTextFormatColl = &rFormat; m_aDepends.StartListening(m_pTextFormatColl); } SwCharFormat* SwEndNoteInfo::GetCharFormat(SwDoc& rDoc) const { auto pCharFormatFromDoc = rDoc.getIDocumentStylePoolAccess().GetCharFormatFromPool( static_cast( m_bEndNote ? RES_POOLCHR_ENDNOTE : RES_POOLCHR_FOOTNOTE ) ); if (m_pCharFormat != pCharFormatFromDoc) { m_aDepends.EndListening(m_pCharFormat); m_aDepends.StartListening(pCharFormatFromDoc); m_pCharFormat = pCharFormatFromDoc; } return m_pCharFormat; } namespace { void lcl_ResetPoolIdForDocAndSync(const sal_uInt16 nId, SwCharFormat* pFormat, const SwEndNoteInfo& rInfo) { auto pDoc = pFormat->GetDoc(); if(!pDoc) return; for(auto pDocFormat : *pDoc->GetCharFormats()) { if(pDocFormat == pFormat) pDocFormat->SetPoolFormatId(nId); else if(pDocFormat->GetPoolFormatId() == nId) pDocFormat->SetPoolFormatId(0); } rInfo.GetCharFormat(*pDoc); rInfo.GetAnchorCharFormat(*pDoc); } } void SwEndNoteInfo::SetCharFormat(SwCharFormat* pFormat) { lcl_ResetPoolIdForDocAndSync( static_cast(m_bEndNote ? RES_POOLCHR_ENDNOTE : RES_POOLCHR_FOOTNOTE), pFormat, *this); } SwCharFormat* SwEndNoteInfo::GetAnchorCharFormat(SwDoc& rDoc) const { auto pAnchorFormatFromDoc = rDoc.getIDocumentStylePoolAccess().GetCharFormatFromPool( static_cast( m_bEndNote ? RES_POOLCHR_ENDNOTE_ANCHOR : RES_POOLCHR_FOOTNOTE_ANCHOR ) ); if(m_pAnchorFormat != pAnchorFormatFromDoc) { m_aDepends.EndListening(m_pAnchorFormat); m_aDepends.StartListening(pAnchorFormatFromDoc); m_pAnchorFormat = pAnchorFormatFromDoc; } return m_pAnchorFormat; } void SwEndNoteInfo::SetAnchorCharFormat(SwCharFormat* pFormat) { lcl_ResetPoolIdForDocAndSync( static_cast(m_bEndNote ? RES_POOLCHR_ENDNOTE_ANCHOR : RES_POOLCHR_FOOTNOTE_ANCHOR), pFormat, *this); } SwCharFormat* SwEndNoteInfo::GetCurrentCharFormat(const bool bAnchor) const { return bAnchor ? m_pAnchorFormat : m_pCharFormat; } void SwEndNoteInfo::SwClientNotify( const SwModify& rModify, const SfxHint& rHint) { if (auto pLegacyHint = dynamic_cast(&rHint)) { const sal_uInt16 nWhich = pLegacyHint->m_pOld ? pLegacyHint->m_pOld->Which() : pLegacyHint->m_pNew ? pLegacyHint->m_pNew->Which() : 0 ; if (RES_ATTRSET_CHG == nWhich || RES_FMT_CHG == nWhich) { auto pFormat = GetCurrentCharFormat(m_pCharFormat == nullptr); if (!pFormat || !m_aDepends.IsListeningTo(pFormat) || pFormat->IsFormatInDTOR()) return; SwDoc* pDoc = pFormat->GetDoc(); SwFootnoteIdxs& rFootnoteIdxs = pDoc->GetFootnoteIdxs(); for( size_t nPos = 0; nPos < rFootnoteIdxs.size(); ++nPos ) { SwTextFootnote *pTextFootnote = rFootnoteIdxs[ nPos ]; const SwFormatFootnote &rFootnote = pTextFootnote->GetFootnote(); if ( rFootnote.IsEndNote() == m_bEndNote ) { pTextFootnote->SetNumber(rFootnote.GetNumber(), rFootnote.GetNumberRLHidden(), rFootnote.GetNumStr()); } } } else CheckRegistration( pLegacyHint->m_pOld ); } else if (auto pModifyChangedHint = dynamic_cast(&rHint)) { auto pNew = const_cast(pModifyChangedHint->m_pNew); if(m_pAnchorFormat == &rModify) m_pAnchorFormat = static_cast(pNew); else if(m_pCharFormat == &rModify) m_pCharFormat = static_cast(pNew); else if(m_pPageDesc == &rModify) m_pPageDesc = static_cast(pNew); else if(m_pTextFormatColl == &rModify) m_pTextFormatColl = static_cast(pNew); } } SwFootnoteInfo& SwFootnoteInfo::operator=(const SwFootnoteInfo& rInfo) { SwEndNoteInfo::operator=(rInfo); m_aQuoVadis = rInfo.m_aQuoVadis; m_aErgoSum = rInfo.m_aErgoSum; m_ePos = rInfo.m_ePos; m_eNum = rInfo.m_eNum; return *this; } bool SwFootnoteInfo::operator==( const SwFootnoteInfo& rInfo ) const { return m_ePos == rInfo.m_ePos && m_eNum == rInfo.m_eNum && SwEndNoteInfo::operator==(rInfo) && m_aQuoVadis == rInfo.m_aQuoVadis && m_aErgoSum == rInfo.m_aErgoSum; } SwFootnoteInfo::SwFootnoteInfo(const SwFootnoteInfo& rInfo) : SwEndNoteInfo( rInfo ), m_aQuoVadis( rInfo.m_aQuoVadis ), m_aErgoSum( rInfo.m_aErgoSum ), m_ePos( rInfo.m_ePos ), m_eNum( rInfo.m_eNum ) { m_bEndNote = false; } SwFootnoteInfo::SwFootnoteInfo() : SwEndNoteInfo(), m_ePos( FTNPOS_PAGE ), m_eNum( FTNNUM_DOC ) { m_aFormat.SetNumberingType(SVX_NUM_ARABIC); m_bEndNote = false; } void SwDoc::SetFootnoteInfo(const SwFootnoteInfo& rInfo) { SwRootFrame* pTmpRoot = getIDocumentLayoutAccess().GetCurrentLayout(); if( GetFootnoteInfo() == rInfo ) return; const SwFootnoteInfo &rOld = GetFootnoteInfo(); if (GetIDocumentUndoRedo().DoesUndo()) { GetIDocumentUndoRedo().AppendUndo( std::make_unique(rOld, this) ); } bool bFootnotePos = rInfo.m_ePos != rOld.m_ePos; bool bFootnoteDesc = rOld.m_ePos == FTNPOS_CHAPTER && rInfo.GetPageDesc( *this ) != rOld.GetPageDesc( *this ); bool bExtra = rInfo.m_aQuoVadis != rOld.m_aQuoVadis || rInfo.m_aErgoSum != rOld.m_aErgoSum || rInfo.m_aFormat.GetNumberingType() != rOld.m_aFormat.GetNumberingType() || rInfo.GetPrefix() != rOld.GetPrefix() || rInfo.GetSuffix() != rOld.GetSuffix(); SwCharFormat *pOldChrFormat = rOld.GetCharFormat( *this ), *pNewChrFormat = rInfo.GetCharFormat( *this ); bool bFootnoteChrFormats = pOldChrFormat != pNewChrFormat; *mpFootnoteInfo = rInfo; if (pTmpRoot) { o3tl::sorted_vector aAllLayouts = GetAllLayouts(); if ( bFootnotePos ) for( auto aLayout : aAllLayouts ) aLayout->AllRemoveFootnotes(); else { for( auto aLayout : aAllLayouts ) aLayout->UpdateFootnoteNums(); if ( bFootnoteDesc ) for( auto aLayout : aAllLayouts ) aLayout->CheckFootnotePageDescs(false); if ( bExtra ) { // For messages regarding ErgoSum etc. we save the extra code and use the // available methods. SwFootnoteIdxs& rFootnoteIdxs = GetFootnoteIdxs(); for( size_t nPos = 0; nPos < rFootnoteIdxs.size(); ++nPos ) { SwTextFootnote *pTextFootnote = rFootnoteIdxs[ nPos ]; const SwFormatFootnote &rFootnote = pTextFootnote->GetFootnote(); if ( !rFootnote.IsEndNote() ) pTextFootnote->SetNumber(rFootnote.GetNumber(), rFootnote.GetNumberRLHidden(), rFootnote.GetNumStr()); } } } } if( FTNNUM_PAGE != rInfo.m_eNum ) GetFootnoteIdxs().UpdateAllFootnote(); else if( bFootnoteChrFormats ) { SwFormatChg aOld( pOldChrFormat ); SwFormatChg aNew( pNewChrFormat ); mpFootnoteInfo->ModifyNotification( &aOld, &aNew ); } // #i81002# no update during loading if ( !IsInReading() ) { getIDocumentFieldsAccess().UpdateRefFields(); } getIDocumentState().SetModified(); } void SwDoc::SetEndNoteInfo(const SwEndNoteInfo& rInfo) { SwRootFrame* pTmpRoot = getIDocumentLayoutAccess().GetCurrentLayout(); if( GetEndNoteInfo() == rInfo ) return; if(GetIDocumentUndoRedo().DoesUndo()) { GetIDocumentUndoRedo().AppendUndo( std::make_unique( GetEndNoteInfo(), this ) ); } bool bNumChg = rInfo.m_nFootnoteOffset != GetEndNoteInfo().m_nFootnoteOffset; // this seems to be an optimization: UpdateAllFootnote() is only called // if the offset changes; if the offset is the same, // but type/prefix/suffix changes, just set new numbers. bool const bExtra = !bNumChg && ( (rInfo.m_aFormat.GetNumberingType() != GetEndNoteInfo().m_aFormat.GetNumberingType()) || (rInfo.GetPrefix() != GetEndNoteInfo().GetPrefix()) || (rInfo.GetSuffix() != GetEndNoteInfo().GetSuffix()) ); bool bFootnoteDesc = rInfo.GetPageDesc( *this ) != GetEndNoteInfo().GetPageDesc( *this ); SwCharFormat *pOldChrFormat = GetEndNoteInfo().GetCharFormat( *this ), *pNewChrFormat = rInfo.GetCharFormat( *this ); bool bFootnoteChrFormats = pOldChrFormat != pNewChrFormat; *mpEndNoteInfo = rInfo; if ( pTmpRoot ) { if ( bFootnoteDesc ) { for( auto aLayout : GetAllLayouts() ) aLayout->CheckFootnotePageDescs(true); } if ( bExtra ) { // For messages regarding ErgoSum etc. we save the extra code and use the // available methods. SwFootnoteIdxs& rFootnoteIdxs = GetFootnoteIdxs(); for( size_t nPos = 0; nPos < rFootnoteIdxs.size(); ++nPos ) { SwTextFootnote *pTextFootnote = rFootnoteIdxs[ nPos ]; const SwFormatFootnote &rFootnote = pTextFootnote->GetFootnote(); if ( rFootnote.IsEndNote() ) pTextFootnote->SetNumber(rFootnote.GetNumber(), rFootnote.GetNumberRLHidden(), rFootnote.GetNumStr()); } } } if( bNumChg ) GetFootnoteIdxs().UpdateAllFootnote(); else if( bFootnoteChrFormats ) { SwFormatChg aOld( pOldChrFormat ); SwFormatChg aNew( pNewChrFormat ); mpEndNoteInfo->ModifyNotification( &aOld, &aNew ); } // #i81002# no update during loading if ( !IsInReading() ) { getIDocumentFieldsAccess().UpdateRefFields(); } getIDocumentState().SetModified(); } bool SwDoc::SetCurFootnote( const SwPaM& rPam, const OUString& rNumStr, bool bIsEndNote) { SwFootnoteIdxs& rFootnoteArr = GetFootnoteIdxs(); SwRootFrame* pTmpRoot = getIDocumentLayoutAccess().GetCurrentLayout(); const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End(); const sal_uLong nSttNd = pStt->nNode.GetIndex(); const sal_Int32 nSttCnt = pStt->nContent.GetIndex(); const sal_uLong nEndNd = pEnd->nNode.GetIndex(); const sal_Int32 nEndCnt = pEnd->nContent.GetIndex(); size_t nPos = 0; rFootnoteArr.SeekEntry( pStt->nNode, &nPos ); std::unique_ptr pUndo; if (GetIDocumentUndoRedo().DoesUndo()) { GetIDocumentUndoRedo().ClearRedo(); // AppendUndo far below, so leave it pUndo.reset(new SwUndoChangeFootNote( rPam, rNumStr, bIsEndNote )); } bool bChg = false; bool bTypeChgd = false; const size_t nPosSave = nPos; while( nPos < rFootnoteArr.size() ) { SwTextFootnote* pTextFootnote = rFootnoteArr[ nPos++ ]; sal_uLong nIdx = SwTextFootnote_GetIndex(pTextFootnote); if( nIdx >= nEndNd && ( nIdx != nEndNd || nEndCnt < pTextFootnote->GetStart() ) ) continue; if( nIdx > nSttNd || ( nIdx == nSttNd && nSttCnt <= pTextFootnote->GetStart() ) ) { const SwFormatFootnote& rFootnote = pTextFootnote->GetFootnote(); if( rFootnote.GetNumStr() != rNumStr || rFootnote.IsEndNote() != bIsEndNote ) { bChg = true; if ( pUndo ) { pUndo->GetHistory().Add( *pTextFootnote ); } pTextFootnote->SetNumber(rFootnote.GetNumber(), rFootnote.GetNumberRLHidden(), rNumStr); if( rFootnote.IsEndNote() != bIsEndNote ) { const_cast(rFootnote).SetEndNote( bIsEndNote ); bTypeChgd = true; pTextFootnote->CheckCondColl(); //#i11339# dispose UNO wrapper when a footnote is changed to an endnote or vice versa const_cast(rFootnote).InvalidateFootnote(); } } } } nPos = nPosSave; // There are more in the front! while( nPos ) { SwTextFootnote* pTextFootnote = rFootnoteArr[ --nPos ]; sal_uLong nIdx = SwTextFootnote_GetIndex(pTextFootnote); if( nIdx <= nSttNd && ( nIdx != nSttNd || nSttCnt > pTextFootnote->GetStart() ) ) continue; if( nIdx < nEndNd || ( nIdx == nEndNd && nEndCnt >= pTextFootnote->GetStart() ) ) { const SwFormatFootnote& rFootnote = pTextFootnote->GetFootnote(); if( rFootnote.GetNumStr() != rNumStr || rFootnote.IsEndNote() != bIsEndNote ) { bChg = true; if ( pUndo ) { pUndo->GetHistory().Add( *pTextFootnote ); } pTextFootnote->SetNumber(rFootnote.GetNumber(), rFootnote.GetNumberRLHidden(), rNumStr); if( rFootnote.IsEndNote() != bIsEndNote ) { const_cast(rFootnote).SetEndNote( bIsEndNote ); bTypeChgd = true; pTextFootnote->CheckCondColl(); } } } } // Who needs to be triggered? if( bChg ) { if( pUndo ) { GetIDocumentUndoRedo().AppendUndo(std::move(pUndo)); } if ( bTypeChgd ) rFootnoteArr.UpdateAllFootnote(); if( FTNNUM_PAGE != GetFootnoteInfo().m_eNum ) { if ( !bTypeChgd ) rFootnoteArr.UpdateAllFootnote(); } else if( pTmpRoot ) { for( auto aLayout : GetAllLayouts() ) aLayout->UpdateFootnoteNums(); } getIDocumentState().SetModified(); } return bChg; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */