diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sw/source/core/doc/doc.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/doc/doc.cxx')
-rw-r--r-- | sw/source/core/doc/doc.cxx | 1830 |
1 files changed, 1830 insertions, 0 deletions
diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx new file mode 100644 index 000000000..800c26458 --- /dev/null +++ b/sw/source/core/doc/doc.cxx @@ -0,0 +1,1830 @@ +/* -*- 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 <config_features.h> + +#include <doc.hxx> +#include <com/sun/star/script/vba/XVBAEventProcessor.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <DocumentFieldsManager.hxx> +#include <DocumentSettingManager.hxx> +#include <DocumentDrawModelManager.hxx> +#include <DocumentTimerManager.hxx> +#include <DocumentDeviceManager.hxx> +#include <DocumentChartDataProviderManager.hxx> +#include <DocumentLinksAdministrationManager.hxx> +#include <DocumentListItemsManager.hxx> +#include <DocumentListsManager.hxx> +#include <DocumentOutlineNodesManager.hxx> +#include <DocumentContentOperationsManager.hxx> +#include <DocumentRedlineManager.hxx> +#include <DocumentStatisticsManager.hxx> +#include <DocumentStateManager.hxx> +#include <DocumentStylePoolManager.hxx> +#include <DocumentLayoutManager.hxx> +#include <DocumentExternalDataManager.hxx> +#include <UndoManager.hxx> +#include <dbmgr.hxx> +#include <hintids.hxx> + +#include <comphelper/random.hxx> +#include <tools/multisel.hxx> +#include <rtl/ustring.hxx> +#include <svl/poolitem.hxx> +#include <unotools/syslocale.hxx> +#include <editeng/keepitem.hxx> +#include <editeng/formatbreakitem.hxx> +#include <editeng/pbinitem.hxx> +#include <unotools/localedatawrapper.hxx> + +#include <swatrset.hxx> +#include <swmodule.hxx> +#include <fmtrfmrk.hxx> +#include <fmtinfmt.hxx> +#include <fmtfld.hxx> +#include <txtfld.hxx> +#include <dbfld.hxx> +#include <txtinet.hxx> +#include <txtrfmrk.hxx> +#include <frmatr.hxx> +#include <pagefrm.hxx> +#include <rootfrm.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <swundo.hxx> +#include <UndoCore.hxx> +#include <UndoTable.hxx> +#include <pagedesc.hxx> +#include <doctxm.hxx> +#include <poolfmt.hxx> +#include <SwGrammarMarkUp.hxx> +#include <scriptinfo.hxx> +#include <mdiexp.hxx> +#include <docary.hxx> +#include <printdata.hxx> +#include <strings.hrc> +#include <SwUndoTOXChange.hxx> +#include <unocrsr.hxx> +#include <docfld.hxx> +#include <docufld.hxx> +#include <viewsh.hxx> +#include <shellres.hxx> +#include <txtfrm.hxx> +#include <attrhint.hxx> + +#include <vector> +#include <map> +#include <osl/diagnose.h> +#include <osl/interlck.h> +#include <vbahelper/vbaaccesshelper.hxx> +#include <editeng/langitem.hxx> +#include <calbck.hxx> +#include <crsrsh.hxx> + +/* @@@MAINTAINABILITY-HORROR@@@ + Probably unwanted dependency on SwDocShell +*/ +#include <docsh.hxx> + +using namespace ::com::sun::star; + +sal_Int32 SwDoc::acquire() +{ + assert(mReferenceCount >= 0); + return osl_atomic_increment(&mReferenceCount); +} + +sal_Int32 SwDoc::release() +{ + assert(mReferenceCount >= 1); + auto x = osl_atomic_decrement(&mReferenceCount); + if (x == 0) + delete this; + return x; +} + +sal_Int32 SwDoc::getReferenceCount() const +{ + assert(mReferenceCount >= 0); + return mReferenceCount; +} + +::sw::MetaFieldManager & SwDoc::GetMetaFieldManager() +{ + return *m_pMetaFieldManager; +} + +::sw::UndoManager & SwDoc::GetUndoManager() +{ + return *m_pUndoManager; +} + +::sw::UndoManager const & SwDoc::GetUndoManager() const +{ + return *m_pUndoManager; +} + + +IDocumentUndoRedo & SwDoc::GetIDocumentUndoRedo() +{ + return *m_pUndoManager; +} + +IDocumentUndoRedo const & SwDoc::GetIDocumentUndoRedo() const +{ + return *m_pUndoManager; +} + +/* IDocumentDrawModelAccess */ +IDocumentDrawModelAccess const & SwDoc::getIDocumentDrawModelAccess() const +{ + return GetDocumentDrawModelManager(); +} + +IDocumentDrawModelAccess & SwDoc::getIDocumentDrawModelAccess() +{ + return GetDocumentDrawModelManager(); +} + +::sw::DocumentDrawModelManager const & SwDoc::GetDocumentDrawModelManager() const +{ + return *m_pDocumentDrawModelManager; +} + +::sw::DocumentDrawModelManager & SwDoc::GetDocumentDrawModelManager() +{ + return *m_pDocumentDrawModelManager; +} + +/* IDocumentSettingAccess */ +IDocumentSettingAccess const & SwDoc::getIDocumentSettingAccess() const +{ + return GetDocumentSettingManager(); +} + +IDocumentSettingAccess & SwDoc::getIDocumentSettingAccess() +{ + return GetDocumentSettingManager(); +} + +::sw::DocumentSettingManager & SwDoc::GetDocumentSettingManager() +{ + return *m_pDocumentSettingManager; +} + +::sw::DocumentSettingManager const & SwDoc::GetDocumentSettingManager() const +{ + return *m_pDocumentSettingManager; +} + +sal_uInt32 SwDoc::getRsid() const +{ + return mnRsid; +} + +void SwDoc::setRsid( sal_uInt32 nVal ) +{ + static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr); + + sal_uInt32 nIncrease = 0; + if (!bHack) + { + // Increase the rsid with a random number smaller than 2^17. This way we + // expect to be able to edit a document 2^12 times before rsid overflows. + // start from 1 to ensure the new rsid is not the same + nIncrease = comphelper::rng::uniform_uint_distribution(1, (1 << 17) - 1); + } + mnRsid = nVal + nIncrease; +} + +sal_uInt32 SwDoc::getRsidRoot() const +{ + return mnRsidRoot; +} + +void SwDoc::setRsidRoot( sal_uInt32 nVal ) +{ + mnRsidRoot = nVal; +} + +/* IDocumentChartDataProviderAccess */ +IDocumentChartDataProviderAccess const & SwDoc::getIDocumentChartDataProviderAccess() const +{ + return *m_pDocumentChartDataProviderManager; +} + +IDocumentChartDataProviderAccess & SwDoc::getIDocumentChartDataProviderAccess() +{ + return *m_pDocumentChartDataProviderManager; +} + +// IDocumentDeviceAccess +IDocumentDeviceAccess const & SwDoc::getIDocumentDeviceAccess() const +{ + return *m_pDeviceAccess; +} + +IDocumentDeviceAccess & SwDoc::getIDocumentDeviceAccess() +{ + return *m_pDeviceAccess; +} + +//IDocumentTimerAccess +IDocumentTimerAccess const & SwDoc::getIDocumentTimerAccess() const +{ + return *m_pDocumentTimerManager; +} + +IDocumentTimerAccess & SwDoc::getIDocumentTimerAccess() +{ + return *m_pDocumentTimerManager; +} + +// IDocumentLinksAdministration +IDocumentLinksAdministration const & SwDoc::getIDocumentLinksAdministration() const +{ + return *m_pDocumentLinksAdministrationManager; +} + +IDocumentLinksAdministration & SwDoc::getIDocumentLinksAdministration() +{ + return *m_pDocumentLinksAdministrationManager; +} + +::sw::DocumentLinksAdministrationManager const & SwDoc::GetDocumentLinksAdministrationManager() const +{ + return *m_pDocumentLinksAdministrationManager; +} + +::sw::DocumentLinksAdministrationManager & SwDoc::GetDocumentLinksAdministrationManager() +{ + return *m_pDocumentLinksAdministrationManager; +} + +//IDocumentListItems +IDocumentListItems const & SwDoc::getIDocumentListItems() const +{ + return *m_pDocumentListItemsManager; +} + +//IDocumentListItems +IDocumentListItems & SwDoc::getIDocumentListItems() +{ + return *m_pDocumentListItemsManager; +} + +//IDocumentListsAccess +IDocumentListsAccess const & SwDoc::getIDocumentListsAccess() const +{ + return *m_pDocumentListsManager; +} + +IDocumentListsAccess & SwDoc::getIDocumentListsAccess() +{ + return *m_pDocumentListsManager; +} + +//IDocumentOutlinesNodes +IDocumentOutlineNodes const & SwDoc::getIDocumentOutlineNodes() const +{ + return *m_pDocumentOutlineNodesManager; +} + +IDocumentOutlineNodes & SwDoc::getIDocumentOutlineNodes() +{ + return *m_pDocumentOutlineNodesManager; +} + +//IDocumentContentOperations +IDocumentContentOperations const & SwDoc::getIDocumentContentOperations() const +{ + return *m_pDocumentContentOperationsManager; +} + +IDocumentContentOperations & SwDoc::getIDocumentContentOperations() +{ + return *m_pDocumentContentOperationsManager; +} + +::sw::DocumentContentOperationsManager const & SwDoc::GetDocumentContentOperationsManager() const +{ + return *m_pDocumentContentOperationsManager; +} +::sw::DocumentContentOperationsManager & SwDoc::GetDocumentContentOperationsManager() +{ + return *m_pDocumentContentOperationsManager; +} + +//IDocumentRedlineAccess +IDocumentRedlineAccess const & SwDoc::getIDocumentRedlineAccess() const +{ + return *m_pDocumentRedlineManager; +} + +IDocumentRedlineAccess& SwDoc::getIDocumentRedlineAccess() +{ + return *m_pDocumentRedlineManager; +} + +::sw::DocumentRedlineManager const & SwDoc::GetDocumentRedlineManager() const +{ + return *m_pDocumentRedlineManager; +} + +::sw::DocumentRedlineManager& SwDoc::GetDocumentRedlineManager() +{ + return *m_pDocumentRedlineManager; +} + +//IDocumentFieldsAccess + +IDocumentFieldsAccess const & SwDoc::getIDocumentFieldsAccess() const +{ + return *m_pDocumentFieldsManager; +} + +IDocumentFieldsAccess & SwDoc::getIDocumentFieldsAccess() +{ + return *m_pDocumentFieldsManager; +} + +::sw::DocumentFieldsManager & SwDoc::GetDocumentFieldsManager() +{ + return *m_pDocumentFieldsManager; +} + +//IDocumentStatistics +IDocumentStatistics const & SwDoc::getIDocumentStatistics() const +{ + return *m_pDocumentStatisticsManager; +} + +IDocumentStatistics & SwDoc::getIDocumentStatistics() +{ + return *m_pDocumentStatisticsManager; +} + +::sw::DocumentStatisticsManager const & SwDoc::GetDocumentStatisticsManager() const +{ + return *m_pDocumentStatisticsManager; +} + +::sw::DocumentStatisticsManager & SwDoc::GetDocumentStatisticsManager() +{ + return *m_pDocumentStatisticsManager; +} + +//IDocumentState +IDocumentState const & SwDoc::getIDocumentState() const +{ + return *m_pDocumentStateManager; +} + +IDocumentState & SwDoc::getIDocumentState() +{ + return *m_pDocumentStateManager; +} + +//IDocumentLayoutAccess +IDocumentLayoutAccess const & SwDoc::getIDocumentLayoutAccess() const +{ + return *m_pDocumentLayoutManager; +} + +IDocumentLayoutAccess & SwDoc::getIDocumentLayoutAccess() +{ + return *m_pDocumentLayoutManager; +} + +::sw::DocumentLayoutManager const & SwDoc::GetDocumentLayoutManager() const +{ + return *m_pDocumentLayoutManager; +} + +::sw::DocumentLayoutManager & SwDoc::GetDocumentLayoutManager() +{ + return *m_pDocumentLayoutManager; +} + +//IDocumentStylePoolAccess +IDocumentStylePoolAccess const & SwDoc::getIDocumentStylePoolAccess() const +{ + return *m_pDocumentStylePoolManager; +} + +IDocumentStylePoolAccess & SwDoc::getIDocumentStylePoolAccess() +{ + return *m_pDocumentStylePoolManager; +} + +//IDocumentExternalData +IDocumentExternalData const & SwDoc::getIDocumentExternalData() const +{ + return *m_pDocumentExternalDataManager; +} + +IDocumentExternalData & SwDoc::getIDocumentExternalData() +{ + return *m_pDocumentExternalDataManager; +} + +/* Implementations the next Interface here */ + +/* + * Document editing (Doc-SS) to fill the document + * by the RTF parser and for the EditShell. + */ +void SwDoc::ChgDBData(const SwDBData& rNewData) +{ + if( rNewData != maDBData ) + { + maDBData = rNewData; + getIDocumentState().SetModified(); + if (m_pDBManager) + m_pDBManager->CommitLastRegistrations(); + } + getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::DatabaseName)->UpdateFields(); +} + +namespace { + +struct PostItField_ : public SetGetExpField +{ + PostItField_( const SwNodeIndex& rNdIdx, const SwTextField* pField ) + : SetGetExpField( rNdIdx, pField, nullptr ) {} + + sal_uInt16 GetPageNo( const StringRangeEnumerator &rRangeEnum, + const o3tl::sorted_vector< sal_Int32 > &rPossiblePages, + sal_uInt16& rVirtPgNo, sal_uInt16& rLineNo ); + + const SwPostItField* GetPostIt() const + { + return static_cast<const SwPostItField*>( GetTextField()->GetFormatField().GetField() ); + } +}; + +} + +sal_uInt16 PostItField_::GetPageNo( + const StringRangeEnumerator &rRangeEnum, + const o3tl::sorted_vector< sal_Int32 > &rPossiblePages, + /* out */ sal_uInt16& rVirtPgNo, /* out */ sal_uInt16& rLineNo ) +{ + //Problem: If a PostItField is contained in a Node that is represented + //by more than one layout instance, + //we have to decide whether it should be printed once or n-times. + //Probably only once. For the page number we don't select a random one, + //but the PostIt's first occurrence in the selected area. + rVirtPgNo = 0; + SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(GetTextField()->GetTextNode()); + for( SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() ) + { + TextFrameIndex const nPos = pFrame->MapModelToView( + &GetTextField()->GetTextNode(), GetContent()); + if( pFrame->GetOffset() > nPos || + (pFrame->HasFollow() && pFrame->GetFollow()->GetOffset() <= nPos) ) + continue; + sal_uInt16 nPgNo = pFrame->GetPhyPageNum(); + if( rRangeEnum.hasValue( nPgNo, &rPossiblePages )) + { + rLineNo = o3tl::narrowing<sal_uInt16>(pFrame->GetLineCount( nPos ) + + pFrame->GetAllLines() - pFrame->GetThisLines()); + rVirtPgNo = pFrame->GetVirtPageNum(); + return nPgNo; + } + } + return 0; +} + +bool sw_GetPostIts(const IDocumentFieldsAccess& rIDFA, SetGetExpFields* pSrtLst) +{ + SwFieldType* pFieldType = rIDFA.GetSysFieldType(SwFieldIds::Postit); + assert(pFieldType); + + std::vector<SwFormatField*> vFields; + pFieldType->GatherFields(vFields); + if(pSrtLst) + for(auto pField: vFields) + { + auto pTextField = pField->GetTextField(); + SwNodeIndex aIdx(pTextField->GetTextNode()); + std::unique_ptr<PostItField_> pNew(new PostItField_(aIdx, pTextField)); + pSrtLst->insert(std::move(pNew)); + + } + return vFields.size()>0; +} + +static void lcl_FormatPostIt( + IDocumentContentOperations* pIDCO, + SwPaM& aPam, + const SwPostItField* pField, + bool bNewPage, bool bIsFirstPostIt, + sal_uInt16 nPageNo, sal_uInt16 nLineNo ) +{ + static char const sTmp[] = " : "; + + assert(SwViewShell::GetShellRes()); + + if (bNewPage) + { + pIDCO->InsertPoolItem( aPam, SvxFormatBreakItem( SvxBreak::PageAfter, RES_BREAK ) ); + pIDCO->SplitNode( *aPam.GetPoint(), false ); + } + else if (!bIsFirstPostIt) + { + // add an empty line between different notes + pIDCO->SplitNode( *aPam.GetPoint(), false ); + pIDCO->SplitNode( *aPam.GetPoint(), false ); + } + + OUString aStr( SwViewShell::GetShellRes()->aPostItPage ); + aStr += sTmp + + OUString::number( nPageNo ) + + " "; + if( nLineNo ) + { + aStr += SwViewShell::GetShellRes()->aPostItLine; + aStr += sTmp + + OUString::number( nLineNo ) + + " "; + } + aStr += SwViewShell::GetShellRes()->aPostItAuthor; + aStr += sTmp + pField->GetPar1() + " "; + SvtSysLocale aSysLocale; + aStr += /*(LocaleDataWrapper&)*/aSysLocale.GetLocaleData().getDate( pField->GetDate() ); + if(pField->GetResolved()) + aStr += " " + SwResId(STR_RESOLVED); + pIDCO->InsertString( aPam, aStr ); + + pIDCO->SplitNode( *aPam.GetPoint(), false ); + aStr = pField->GetPar2(); +#if defined(_WIN32) + // Throw out all CR in Windows + aStr = aStr.replaceAll("\r", ""); +#endif + pIDCO->InsertString( aPam, aStr ); +} + +/// provide the paper tray to use according to the page style in use, +/// but do that only if the respective item is NOT just the default item +static sal_Int32 lcl_GetPaperBin( const SwPageFrame *pStartFrame ) +{ + sal_Int32 nRes = -1; + + const SwFrameFormat &rFormat = pStartFrame->GetPageDesc()->GetMaster(); + const SfxPoolItem *pItem = nullptr; + SfxItemState eState = rFormat.GetItemState( RES_PAPER_BIN, false, &pItem ); + const SvxPaperBinItem *pPaperBinItem = dynamic_cast< const SvxPaperBinItem * >(pItem); + if (eState > SfxItemState::DEFAULT && pPaperBinItem) + nRes = pPaperBinItem->GetValue(); + + return nRes; +} + +namespace +{ +// tdf#:114663 Translates a range string from user input (with page numbering possibly not +// taking blank pages into account) to equivalent string which references physical page numbers. +// rUIPages2PhyPagesMap must contain a contiguous sequence of UI page numbers +OUString UIPages2PhyPages(const OUString& rUIPageRange, const std::map< sal_Int32, sal_Int32 >& rUIPages2PhyPagesMap) +{ + if (rUIPages2PhyPagesMap.empty()) + return OUString(); + auto iMin = rUIPages2PhyPagesMap.begin(); + const sal_Int32 nUIPageMin = iMin->first, nPhyPageMin = iMin->second; + auto iMax = rUIPages2PhyPagesMap.rbegin(); + const sal_Int32 nUIPageMax = iMax->first, nPhyPageMax = iMax->second; + OUStringBuffer aOut(rUIPageRange.getLength()); + OUStringBuffer aNumber(16); + const sal_Unicode* pInput = rUIPageRange.getStr(); + while (*pInput) + { + while (*pInput >= '0' && *pInput <= '9') + aNumber.append(*pInput++); + if (!aNumber.isEmpty()) + { + sal_Int32 nNumber = aNumber.makeStringAndClear().toInt32(); + if (nNumber < nUIPageMin) + nNumber = nPhyPageMin-1; + else if (nNumber > nUIPageMax) + nNumber = nPhyPageMax+1; + else + nNumber = rUIPages2PhyPagesMap.at(nNumber); + aOut.append(nNumber); + } + + while (*pInput && (*pInput < '0' || *pInput > '9')) + aOut.append(*pInput++); + } + + return aOut.makeStringAndClear(); +} +} + +// tdf#52316 remove blank pages from page count and actual page number +void SwDoc::CalculateNonBlankPages( + const SwRootFrame& rLayout, + sal_uInt16& nDocPageCount, + sal_uInt16& nActualPage) +{ + sal_uInt16 nDocPageCountWithBlank = nDocPageCount; + sal_uInt16 nActualPageWithBlank = nActualPage; + sal_uInt16 nPageNum = 1; + const SwPageFrame *pStPage = dynamic_cast<const SwPageFrame*>( rLayout.Lower() ); + while (pStPage && nPageNum <= nDocPageCountWithBlank) + { + if ( pStPage->getFrameArea().Height() == 0 ) + { + --nDocPageCount; + if (nPageNum <= nActualPageWithBlank) + --nActualPage; + } + ++nPageNum; + pStPage = static_cast<const SwPageFrame*>(pStPage->GetNext()); + } +} + +void SwDoc::CalculatePagesForPrinting( + const SwRootFrame& rLayout, + /* out */ SwRenderData &rData, + const SwPrintUIOptions &rOptions, + bool bIsPDFExport, + sal_Int32 nDocPageCount ) +{ + const sal_Int64 nContent = rOptions.getIntValue( "PrintContent", 0 ); + const bool bPrintSelection = nContent == 2; + + // properties to take into account when calculating the set of pages + // (PDF export UI does not allow for selecting left or right pages only) + bool bPrintLeftPages = bIsPDFExport || rOptions.IsPrintLeftPages(); + bool bPrintRightPages = bIsPDFExport || rOptions.IsPrintRightPages(); + // #i103700# printing selections should not allow for automatic inserting empty pages + bool bPrintEmptyPages = !bPrintSelection && rOptions.IsPrintEmptyPages( bIsPDFExport ); + + std::map< sal_Int32, sal_Int32 > &rPrinterPaperTrays = rData.GetPrinterPaperTrays(); + o3tl::sorted_vector< sal_Int32 > &rValidPages = rData.GetValidPagesSet(); + // Map page numbers from user input (possibly ignoring blanks) to physical page numbers + std::map< sal_Int32, sal_Int32 > aUIPages2PhyPagesMap; + rValidPages.clear(); + + sal_Int32 nPageNum = 1, nUIPageNum = 1; + const SwPageFrame *pStPage = dynamic_cast<const SwPageFrame*>( rLayout.Lower() ); + while (pStPage && nPageNum <= nDocPageCount) + { + const bool bNonEmptyPage = pStPage->getFrameArea().Height() != 0; + const bool bPrintThisPage = + ( (bPrintRightPages && pStPage->OnRightPage()) || + (bPrintLeftPages && !pStPage->OnRightPage()) ) && + ( bPrintEmptyPages || bNonEmptyPage ); + + if (bPrintThisPage) + { + rValidPages.insert( nPageNum ); + rPrinterPaperTrays[ nPageNum ] = lcl_GetPaperBin( pStPage ); + } + + if ( bPrintEmptyPages || bNonEmptyPage ) + { + aUIPages2PhyPagesMap[nUIPageNum++] = nPageNum; + } + ++nPageNum; + pStPage = static_cast<const SwPageFrame*>(pStPage->GetNext()); + } + + // now that we have identified the valid pages for printing according + // to the print settings we need to get the PageRange to use and + // use both results to get the actual pages to be printed + // (post-it settings need to be taken into account later on!) + + // get PageRange value to use + OUString aPageRange; + // #i116085# - adjusting fix for i113919 + if ( !bIsPDFExport ) + { + // PageContent : + // 0 -> print all pages (default if aPageRange is empty) + // 1 -> print range according to PageRange + // 2 -> print selection + if (1 == nContent) + aPageRange = rOptions.getStringValue( "PageRange" ); + + if (2 == nContent) + { + // note that printing selections is actually implemented by copying + // the selection to a new temporary document and printing all of that one. + // Thus for Writer "PrintContent" must never be 2. + // See SwXTextDocument::GetRenderDoc for evaluating if a selection is to be + // printed and for creating the temporary document. + } + + // please note + } + if (aPageRange.isEmpty()) // empty string -> print all + { + // set page range to print to 'all pages' + aPageRange = OUString::number( 1 ) + "-" + OUString::number( nDocPageCount ); + } + else + { + // Convert page numbers from user input to physical page numbers + aPageRange = UIPages2PhyPages(aPageRange, aUIPages2PhyPagesMap); + } + rData.SetPageRange( aPageRange ); + + // get vector of pages to print according to PageRange and valid pages set from above + // (result may be an empty vector, for example if the range string is not correct) + // If excluding empty pages, allow range to specify range of printable pages + StringRangeEnumerator::getRangesFromString( aPageRange, rData.GetPagesToPrint(), + 1, nDocPageCount, 0, &rData.GetValidPagesSet() ); +} + +void SwDoc::UpdatePagesForPrintingWithPostItData( + /* out */ SwRenderData &rData, + const SwPrintUIOptions &rOptions, + sal_Int32 nDocPageCount ) +{ + + SwPostItMode nPostItMode = static_cast<SwPostItMode>( rOptions.getIntValue( "PrintAnnotationMode", 0 ) ); + assert((nPostItMode == SwPostItMode::NONE || rData.HasPostItData()) + && "print post-its without post-it data?"); + const SetGetExpFields::size_type nPostItCount = + rData.HasPostItData() ? rData.m_pPostItFields->size() : 0; + if (nPostItMode == SwPostItMode::NONE || nPostItCount <= 0) + return; + + CurrShell aCurr( rData.m_pPostItShell.get() ); + + // clear document and move to end of it + SwDoc & rPostItDoc(*rData.m_pPostItShell->GetDoc()); + SwPaM aPam(rPostItDoc.GetNodes().GetEndOfContent()); + aPam.Move( fnMoveBackward, GoInDoc ); + aPam.SetMark(); + aPam.Move( fnMoveForward, GoInDoc ); + rPostItDoc.getIDocumentContentOperations().DeleteRange( aPam ); + + const StringRangeEnumerator aRangeEnum( rData.GetPageRange(), 1, nDocPageCount, 0 ); + + // For mode SwPostItMode::EndPage: + // maps a physical page number to the page number in post-it document that holds + // the first post-it for that physical page . Needed to relate the correct start frames + // from the post-it doc to the physical page of the document + std::map< sal_Int32, sal_Int32 > aPostItLastStartPageNum; + + // add all post-its on valid pages within the page range to the + // temporary post-it document. + // Since the array of post-it fields is sorted by page and line number we will + // already get them in the correct order + sal_uInt16 nVirtPg = 0, nLineNo = 0, nLastPageNum = 0, nPhyPageNum = 0; + bool bIsFirstPostIt = true; + for (SetGetExpFields::size_type i = 0; i < nPostItCount; ++i) + { + PostItField_& rPostIt = static_cast<PostItField_&>(*(*rData.m_pPostItFields)[ i ]); + nLastPageNum = nPhyPageNum; + nPhyPageNum = rPostIt.GetPageNo( + aRangeEnum, rData.GetValidPagesSet(), nVirtPg, nLineNo ); + if (nPhyPageNum) + { + // need to insert a page break? + // In SwPostItMode::EndPage mode for each document page the following + // post-it page needs to start on a new page + const bool bNewPage = nPostItMode == SwPostItMode::EndPage && + !bIsFirstPostIt && nPhyPageNum != nLastPageNum; + + lcl_FormatPostIt( &rData.m_pPostItShell->GetDoc()->getIDocumentContentOperations(), aPam, + rPostIt.GetPostIt(), bNewPage, bIsFirstPostIt, nVirtPg, nLineNo ); + bIsFirstPostIt = false; + + if (nPostItMode == SwPostItMode::EndPage) + { + // get the correct number of current pages for the post-it document + rData.m_pPostItShell->CalcLayout(); + const sal_Int32 nPages = rData.m_pPostItShell->GetPageCount(); + aPostItLastStartPageNum[ nPhyPageNum ] = nPages; + } + } + } + + // format post-it doc to get correct number of pages + rData.m_pPostItShell->CalcLayout(); + + SwRootFrame* pPostItRoot = rData.m_pPostItShell->GetLayout(); + //tdf#103313 print dialog maxes out cpu as Idles never get to + //complete this postitshell's desire to complete formatting + pPostItRoot->ResetIdleFormat(); + + const sal_Int32 nPostItDocPageCount = rData.m_pPostItShell->GetPageCount(); + + if (nPostItMode == SwPostItMode::Only || nPostItMode == SwPostItMode::EndDoc) + { + // now add those post-it pages to the vector of pages to print + // or replace them if only post-its should be printed + + if (nPostItMode == SwPostItMode::Only) + { + // no document page to be printed + rData.GetPagesToPrint().clear(); + } + + // now we just need to add the post-it pages to be printed to the + // end of the vector of pages to print + sal_Int32 nPageNum = 0; + const SwPageFrame * pPageFrame = static_cast<SwPageFrame*>(pPostItRoot->Lower()); + while( pPageFrame && nPageNum < nPostItDocPageCount ) + { + ++nPageNum; + // negative page number indicates page is from the post-it doc + rData.GetPagesToPrint().push_back( -nPageNum ); + pPageFrame = static_cast<const SwPageFrame*>(pPageFrame->GetNext()); + } + OSL_ENSURE( nPageNum == nPostItDocPageCount, "unexpected number of pages" ); + } + else if (nPostItMode == SwPostItMode::EndPage) + { + // the next step is to find all the pages from the post-it + // document that should be printed for a given physical page + // of the document + + std::vector< sal_Int32 > aTmpPagesToPrint; + sal_Int32 nLastPostItPage(0); + const size_t nNum = rData.GetPagesToPrint().size(); + for (size_t i = 0 ; i < nNum; ++i) + { + // add the physical page to print from the document + const sal_Int32 nPhysPage = rData.GetPagesToPrint()[i]; + aTmpPagesToPrint.push_back( nPhysPage ); + + // add the post-it document pages to print, i.e those + // post-it pages that have the data for the above physical page + std::map<sal_Int32, sal_Int32>::const_iterator const iter( + aPostItLastStartPageNum.find(nPhysPage)); + if (iter != aPostItLastStartPageNum.end()) + { + for (sal_Int32 j = nLastPostItPage + 1; + j <= iter->second; ++j) + { + // negative page number indicates page is from the + aTmpPagesToPrint.push_back(-j); // post-it document + } + nLastPostItPage = iter->second; + } + } + + // finally we need to assign those vectors to the resulting ones. + // swapping the data should be more efficient than assigning since + // we won't need the temporary vectors anymore + rData.GetPagesToPrint().swap( aTmpPagesToPrint ); + } + +} + +void SwDoc::CalculatePagePairsForProspectPrinting( + const SwRootFrame& rLayout, + /* out */ SwRenderData &rData, + const SwPrintUIOptions &rOptions, + sal_Int32 nDocPageCount ) +{ + std::map< sal_Int32, sal_Int32 > &rPrinterPaperTrays = rData.GetPrinterPaperTrays(); + o3tl::sorted_vector< sal_Int32 > &rValidPagesSet = rData.GetValidPagesSet(); + std::vector< std::pair< sal_Int32, sal_Int32 > > &rPagePairs = rData.GetPagePairsForProspectPrinting(); + std::map< sal_Int32, const SwPageFrame * > validStartFrames; + + rPagePairs.clear(); + rValidPagesSet.clear(); + + OUString aPageRange; + // PageContent : + // 0 -> print all pages (default if aPageRange is empty) + // 1 -> print range according to PageRange + // 2 -> print selection + const sal_Int64 nContent = rOptions.getIntValue( "PrintContent", 0 ); + if (nContent == 1) + aPageRange = rOptions.getStringValue( "PageRange" ); + if (aPageRange.isEmpty()) // empty string -> print all + { + // set page range to print to 'all pages' + aPageRange = OUString::number( 1 ) + "-" + OUString::number( nDocPageCount ); + } + StringRangeEnumerator aRange( aPageRange, 1, nDocPageCount, 0 ); + + if ( aRange.size() <= 0) + return; + + const SwPageFrame *pStPage = dynamic_cast<const SwPageFrame*>( rLayout.Lower() ); + for ( sal_Int32 i = 1; pStPage && i < nDocPageCount; ++i ) + pStPage = static_cast<const SwPageFrame*>(pStPage->GetNext()); + if ( !pStPage ) // Then it was that + return; + + // currently for prospect printing all pages are valid to be printed + // thus we add them all to the respective map and set for later use + sal_Int32 nPageNum = 0; + const SwPageFrame *pPageFrame = dynamic_cast<const SwPageFrame*>( rLayout.Lower() ); + while( pPageFrame && nPageNum < nDocPageCount ) + { + ++nPageNum; + rValidPagesSet.insert( nPageNum ); + validStartFrames[ nPageNum ] = pPageFrame; + pPageFrame = static_cast<const SwPageFrame*>(pPageFrame->GetNext()); + + rPrinterPaperTrays[ nPageNum ] = lcl_GetPaperBin( pStPage ); + } + OSL_ENSURE( nPageNum == nDocPageCount, "unexpected number of pages" ); + + // properties to take into account when calculating the set of pages + // Note: here bPrintLeftPages and bPrintRightPages refer to the (virtual) resulting pages + // of the prospect! + bool bPrintLeftPages = rOptions.IsPrintLeftPages(); + bool bPrintRightPages = rOptions.IsPrintRightPages(); + bool bPrintProspectRTL = rOptions.getIntValue( "PrintProspectRTL", 0 ) != 0; + + // get pages for prospect printing according to the 'PageRange' + // (duplicates and any order allowed!) + std::vector< sal_Int32 > aPagesToPrint; + StringRangeEnumerator::getRangesFromString( + aPageRange, aPagesToPrint, 1, nDocPageCount, 0 ); + + if (aPagesToPrint.empty()) + return; + + // now fill the vector for calculating the page pairs with the start frames + // from the above obtained vector + std::vector< const SwPageFrame * > aVec; + for (sal_Int32 nPage : aPagesToPrint) + { + const SwPageFrame *pFrame = validStartFrames[ nPage ]; + aVec.push_back( pFrame ); + } + + // just one page is special ... + if ( 1 == aVec.size() ) + aVec.insert( aVec.begin() + 1, nullptr ); // insert a second empty page + else + { + // now extend the number of pages to fit a multiple of 4 + // (4 'normal' pages are needed for a single prospect paper + // with back and front) + while( aVec.size() & 3 ) + aVec.push_back( nullptr ); + } + + // make sure that all pages are in correct order + std::vector< const SwPageFrame * >::size_type nSPg = 0; + std::vector< const SwPageFrame * >::size_type nEPg = aVec.size(); + sal_Int32 nStep = 1; + if ( 0 == (nEPg & 1 )) // there are no uneven ones! + --nEPg; + + if ( !bPrintLeftPages ) + ++nStep; + else if ( !bPrintRightPages ) + { + ++nStep; + ++nSPg; + --nEPg; + } + + // the number of 'virtual' pages to be printed + sal_Int32 nCntPage = (( nEPg - nSPg ) / ( 2 * nStep )) + 1; + + for ( sal_Int32 nPrintCount = 0; nSPg < nEPg && + nPrintCount < nCntPage; ++nPrintCount ) + { + pStPage = aVec[ nSPg ]; + const SwPageFrame* pNxtPage = nEPg < aVec.size() ? aVec[ nEPg ] : nullptr; + + short nRtlOfs = bPrintProspectRTL ? 1 : 0; + if ( 0 == (( nSPg + nRtlOfs) & 1 ) ) // switch for odd number in LTR, even number in RTL + { + const SwPageFrame* pTmp = pStPage; + pStPage = pNxtPage; + pNxtPage = pTmp; + } + + sal_Int32 nFirst = -1, nSecond = -1; + for ( int nC = 0; nC < 2; ++nC ) + { + sal_Int32 nPage = -1; + if ( pStPage ) + nPage = pStPage->GetPhyPageNum(); + if (nC == 0) + nFirst = nPage; + else + nSecond = nPage; + + pStPage = pNxtPage; + } + rPagePairs.emplace_back(nFirst, nSecond ); + + nSPg = nSPg + nStep; + nEPg = nEPg - nStep; + } + OSL_ENSURE( size_t(nCntPage) == rPagePairs.size(), "size mismatch for number of page pairs" ); + + // luckily prospect printing does not make use of post-its so far, + // thus we are done here. +} + +/// @return the reference in the doc for the name +const SwFormatRefMark* SwDoc::GetRefMark( std::u16string_view rName ) const +{ + for (const SfxPoolItem* pItem : GetAttrPool().GetItemSurrogates(RES_TXTATR_REFMARK)) + { + auto pFormatRef = dynamic_cast<const SwFormatRefMark*>(pItem); + if(!pFormatRef) + continue; + + const SwTextRefMark* pTextRef = pFormatRef->GetTextRefMark(); + if( pTextRef && &pTextRef->GetTextNode().GetNodes() == &GetNodes() && + rName == pFormatRef->GetRefName() ) + return pFormatRef; + } + return nullptr; +} + +/// @return the RefMark per index - for Uno +const SwFormatRefMark* SwDoc::GetRefMark( sal_uInt16 nIndex ) const +{ + const SwFormatRefMark* pRet = nullptr; + + sal_uInt32 nCount = 0; + for (const SfxPoolItem* pItem : GetAttrPool().GetItemSurrogates(RES_TXTATR_REFMARK)) + { + auto pRefMark = dynamic_cast<const SwFormatRefMark*>(pItem); + if( !pRefMark ) + continue; + const SwTextRefMark* pTextRef = pRefMark->GetTextRefMark(); + if( pTextRef && &pTextRef->GetTextNode().GetNodes() == &GetNodes() ) + { + if(nCount == nIndex) + { + pRet = pRefMark; + break; + } + nCount++; + } + } + return pRet; +} + +/// @return the names of all set references in the Doc +//JP 24.06.96: If the array pointer is 0, then just return whether a RefMark is set in the Doc +// OS 25.06.96: From now on we always return the reference count +sal_uInt16 SwDoc::GetRefMarks( std::vector<OUString>* pNames ) const +{ + sal_uInt16 nCount = 0; + for (const SfxPoolItem* pItem : GetAttrPool().GetItemSurrogates(RES_TXTATR_REFMARK)) + { + auto pRefMark = dynamic_cast<const SwFormatRefMark*>(pItem); + if( !pRefMark ) + continue; + const SwTextRefMark* pTextRef = pRefMark->GetTextRefMark(); + if( pTextRef && &pTextRef->GetTextNode().GetNodes() == &GetNodes() ) + { + if( pNames ) + { + OUString aTmp(pRefMark->GetRefName()); + pNames->insert(pNames->begin() + nCount, aTmp); + } + ++nCount; + } + } + + return nCount; +} + +static bool lcl_SpellAndGrammarAgain( SwNode* pNd, void* pArgs ) +{ + SwTextNode *pTextNode = pNd->GetTextNode(); + bool bOnlyWrong = *static_cast<sal_Bool*>(pArgs); + if( pTextNode ) + { + if( bOnlyWrong ) + { + if( pTextNode->GetWrong() && + pTextNode->GetWrong()->InvalidateWrong() ) + pTextNode->SetWrongDirty(SwTextNode::WrongState::TODO); + if( pTextNode->GetGrammarCheck() && + pTextNode->GetGrammarCheck()->InvalidateWrong() ) + pTextNode->SetGrammarCheckDirty( true ); + } + else + { + pTextNode->SetWrongDirty(SwTextNode::WrongState::TODO); + if( pTextNode->GetWrong() ) + pTextNode->GetWrong()->SetInvalid( 0, COMPLETE_STRING ); + pTextNode->SetGrammarCheckDirty( true ); + if( pTextNode->GetGrammarCheck() ) + pTextNode->GetGrammarCheck()->SetInvalid( 0, COMPLETE_STRING ); + } + } + return true; +} + +static bool lcl_CheckSmartTagsAgain( SwNode* pNd, void* ) +{ + SwTextNode *pTextNode = pNd->GetTextNode(); + if( pTextNode ) + { + pTextNode->SetSmartTagDirty( true ); + pTextNode->ClearSmartTags(); + } + return true; +} + +/** + * Re-trigger spelling in the idle handler. + * + * @param bInvalid if <true>, the WrongLists in all nodes are invalidated + * and the SpellInvalid flag is set on all pages. + * @param bOnlyWrong controls whether only the areas with wrong words are + * checked or the whole area. + * @param bSmartTags ??? + */ +void SwDoc::SpellItAgainSam( bool bInvalid, bool bOnlyWrong, bool bSmartTags ) +{ + o3tl::sorted_vector<SwRootFrame*> aAllLayouts = GetAllLayouts(); + assert(getIDocumentLayoutAccess().GetCurrentLayout() && "SpellAgain: Where's my RootFrame?"); + if( bInvalid ) + { + for ( auto aLayout : aAllLayouts ) + { + aLayout->AllInvalidateSmartTagsOrSpelling(bSmartTags); + aLayout->SetNeedGrammarCheck(true); + } + if ( bSmartTags ) + GetNodes().ForEach( lcl_CheckSmartTagsAgain, &bOnlyWrong ); + GetNodes().ForEach( lcl_SpellAndGrammarAgain, &bOnlyWrong ); + } + + for ( auto aLayout : aAllLayouts ) + aLayout->SetIdleFlags(); +} + +void SwDoc::InvalidateAutoCompleteFlag() +{ + SwRootFrame* pTmpRoot = getIDocumentLayoutAccess().GetCurrentLayout(); + if( !pTmpRoot ) + return; + + o3tl::sorted_vector<SwRootFrame*> aAllLayouts = GetAllLayouts(); + for( auto aLayout : aAllLayouts ) + aLayout->AllInvalidateAutoCompleteWords(); + for( SwNodeOffset nNd(1), nCnt = GetNodes().Count(); nNd < nCnt; ++nNd ) + { + SwTextNode* pTextNode = GetNodes()[ nNd ]->GetTextNode(); + if ( pTextNode ) pTextNode->SetAutoCompleteWordDirty( true ); + } + + for( auto aLayout : aAllLayouts ) + aLayout->SetIdleFlags(); +} + +const SwFormatINetFormat* SwDoc::FindINetAttr( std::u16string_view rName ) const +{ + for (const SfxPoolItem* pItem : GetAttrPool().GetItemSurrogates(RES_TXTATR_INETFMT)) + { + auto pFormatItem = dynamic_cast<const SwFormatINetFormat*>(pItem); + if( !pFormatItem || pFormatItem->GetName() != rName ) + continue; + const SwTextINetFormat* pTextAttr = pFormatItem->GetTextINetFormat(); + if( !pTextAttr ) + continue; + const SwTextNode* pTextNd = pTextAttr->GetpTextNode(); + if( pTextNd && &pTextNd->GetNodes() == &GetNodes() ) + { + return pFormatItem; + } + } + return nullptr; +} + +void SwDoc::Summary(SwDoc& rExtDoc, sal_uInt8 nLevel, sal_uInt8 nPara, bool bImpress) +{ + const SwOutlineNodes& rOutNds = GetNodes().GetOutLineNds(); + if (rOutNds.empty()) + return; + + ::StartProgress( STR_STATSTR_SUMMARY, 0, rOutNds.size(), GetDocShell() ); + SwNodeIndex aEndOfDoc( rExtDoc.GetNodes().GetEndOfContent(), -1 ); + for( SwOutlineNodes::size_type i = 0; i < rOutNds.size(); ++i ) + { + ::SetProgressState( static_cast<tools::Long>(i), GetDocShell() ); + const SwNodeOffset nIndex = rOutNds[ i ]->GetIndex(); + + const int nLvl = GetNodes()[ nIndex ]->GetTextNode()->GetAttrOutlineLevel()-1; + if( nLvl > nLevel ) + continue; + SwNodeOffset nEndOfs(1); + sal_uInt8 nWish = nPara; + SwNodeOffset nNextOutNd = i + 1 < rOutNds.size() ? + rOutNds[ i + 1 ]->GetIndex() : GetNodes().Count(); + bool bKeep = false; + while( ( nWish || bKeep ) && nIndex + nEndOfs < nNextOutNd && + GetNodes()[ nIndex + nEndOfs ]->IsTextNode() ) + { + SwTextNode* pTextNode = GetNodes()[ nIndex+nEndOfs ]->GetTextNode(); + if (pTextNode->GetText().getLength() && nWish) + --nWish; + bKeep = pTextNode->GetSwAttrSet().GetKeep().GetValue(); + ++nEndOfs; + } + + SwNodeRange aRange( *rOutNds[ i ], SwNodeOffset(0), *rOutNds[ i ], nEndOfs ); + GetNodes().Copy_( aRange, aEndOfDoc ); + } + const SwTextFormatColls *pColl = rExtDoc.GetTextFormatColls(); + for( SwTextFormatColls::size_type i = 0; i < pColl->size(); ++i ) + (*pColl)[ i ]->ResetFormatAttr( RES_PAGEDESC, RES_BREAK ); + SwNodeIndex aIndx( rExtDoc.GetNodes().GetEndOfExtras() ); + ++aEndOfDoc; + while( aIndx < aEndOfDoc ) + { + bool bDelete = false; + SwNode *pNode = &aIndx.GetNode(); + if( pNode->IsTextNode() ) + { + SwTextNode *pNd = pNode->GetTextNode(); + if( pNd->HasSwAttrSet() ) + pNd->ResetAttr( RES_PAGEDESC, RES_BREAK ); + if( bImpress ) + { + SwTextFormatColl* pMyColl = pNd->GetTextColl(); + + const sal_uInt16 nHeadLine = o3tl::narrowing<sal_uInt16>( + !pMyColl->IsAssignedToListLevelOfOutlineStyle() + ? RES_POOLCOLL_HEADLINE2 + : RES_POOLCOLL_HEADLINE1 ); + pMyColl = rExtDoc.getIDocumentStylePoolAccess().GetTextCollFromPool( nHeadLine ); + pNd->ChgFormatColl( pMyColl ); + } + if( !pNd->Len() && + pNd->StartOfSectionIndex()+SwNodeOffset(2) < pNd->EndOfSectionIndex() ) + { + bDelete = true; + rExtDoc.GetNodes().Delete( aIndx ); + } + } + if( !bDelete ) + ++aIndx; + } + ::EndProgress( GetDocShell() ); +} + +namespace +{ +void RemoveOrDeleteContents(SwTextNode* pTextNd, IDocumentContentOperations& xOperations) +{ + SwPaM aPam(*pTextNd, 0, *pTextNd, pTextNd->GetText().getLength()); + + // Remove hidden paragraph or delete contents: + // Delete contents if + // 1. removing the paragraph would result in an empty section or + // 2. if the paragraph is the last paragraph in the section and + // there is no paragraph in front of the paragraph: + if ((SwNodeOffset(2) == pTextNd->EndOfSectionIndex() - pTextNd->StartOfSectionIndex()) + || (SwNodeOffset(1) == pTextNd->EndOfSectionIndex() - pTextNd->GetIndex() + && !pTextNd->GetNodes()[pTextNd->GetIndex() - 1]->GetTextNode())) + { + xOperations.DeleteRange(aPam); + } + else + { + aPam.DeleteMark(); + xOperations.DelFullPara(aPam); + } +} +// Returns if the data was actually modified +bool HandleHidingField(SwFormatField& rFormatField, const SwNodes& rNodes, + IDocumentContentOperations& xOperations) +{ + if( !rFormatField.GetTextField() ) + return false; + SwTextNode* pTextNd = rFormatField.GetTextField()->GetpTextNode(); + if( pTextNd + && pTextNd->GetpSwpHints() && pTextNd->IsHiddenByParaField() + && &pTextNd->GetNodes() == &rNodes) + { + RemoveOrDeleteContents(pTextNd, xOperations); + return true; + } + return false; +} +} + +// The greater the returned value, the more weight has this field type on deciding the final +// paragraph state +int SwDoc::FieldCanHideParaWeight(SwFieldIds eFieldId) const +{ + switch (eFieldId) + { + case SwFieldIds::HiddenPara: + return 20; + case SwFieldIds::Database: + return GetDocumentSettingManager().get(DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA) + ? 10 + : 0; + default: + return 0; + } +} + +bool SwDoc::FieldHidesPara(const SwField& rField) const +{ + switch (rField.GetTyp()->Which()) + { + case SwFieldIds::HiddenPara: + return static_cast<const SwHiddenParaField&>(rField).IsHidden(); + case SwFieldIds::Database: + return FieldCanHideParaWeight(SwFieldIds::Database) + && rField.ExpandField(true, nullptr).isEmpty(); + default: + return false; + } +} + +/// Remove the invisible content from the document e.g. hidden areas, hidden paragraphs +// Returns if the data was actually modified +bool SwDoc::RemoveInvisibleContent() +{ + bool bRet = false; + GetIDocumentUndoRedo().StartUndo( SwUndoId::UI_DELETE_INVISIBLECNTNT, nullptr ); + + { + class FieldTypeGuard : public SwClient + { + public: + explicit FieldTypeGuard(SwFieldType* pType) + : SwClient(pType) + { + } + const SwFieldType* get() const + { + return static_cast<const SwFieldType*>(GetRegisteredIn()); + } + }; + // Removing some nodes for one SwFieldIds::Database type might remove the type from + // document's field types, invalidating iterators. So, we need to create own list of + // matching types prior to processing them. + std::vector<std::unique_ptr<FieldTypeGuard>> aHidingFieldTypes; + for (std::unique_ptr<SwFieldType> const & pType : *getIDocumentFieldsAccess().GetFieldTypes()) + { + if (FieldCanHideParaWeight(pType->Which())) + aHidingFieldTypes.push_back(std::make_unique<FieldTypeGuard>(pType.get())); + } + for (const auto& pTypeGuard : aHidingFieldTypes) + { + if (const SwFieldType* pType = pTypeGuard->get()) + { + std::vector<SwFormatField*> vFields; + pType->GatherFields(vFields); + for(auto pFormatField: vFields) + bRet |= HandleHidingField(*pFormatField, GetNodes(), getIDocumentContentOperations()); + } + } + } + + // Remove any hidden paragraph (hidden text attribute) + for( SwNodeOffset n = GetNodes().Count(); n; ) + { + SwTextNode* pTextNd = GetNodes()[ --n ]->GetTextNode(); + if ( pTextNd ) + { + bool bRemoved = false; + if ( pTextNd->HasHiddenCharAttribute( true ) ) + { + bRemoved = true; + bRet = true; + + if (SwNodeOffset(2) == pTextNd->EndOfSectionIndex() - pTextNd->StartOfSectionIndex()) + { + SwFrameFormat *const pFormat = pTextNd->StartOfSectionNode()->GetFlyFormat(); + if (nullptr != pFormat) + { + // remove hidden text frame + getIDocumentLayoutAccess().DelLayoutFormat(pFormat); + } + else + { + // default, remove hidden paragraph + RemoveOrDeleteContents(pTextNd, getIDocumentContentOperations()); + } + } + else + { + // default, remove hidden paragraph + RemoveOrDeleteContents(pTextNd, getIDocumentContentOperations()); + } + } + else if ( pTextNd->HasHiddenCharAttribute( false ) ) + { + bRemoved = true; + bRet = true; + SwScriptInfo::DeleteHiddenRanges( *pTextNd ); + } + + // Footnotes/Frames may have been removed, therefore we have + // to reset n: + if ( bRemoved ) + { + // [n] has to be inside [0 .. GetNodes().Count()] range + if (n > GetNodes().Count()) + n = GetNodes().Count(); + } + } + } + + { + // Delete/empty all hidden areas + o3tl::sorted_vector<SwSectionFormat*> aSectFormats; + SwSectionFormats& rSectFormats = GetSections(); + + for( SwSectionFormats::size_type n = rSectFormats.size(); n; ) + { + SwSectionFormat* pSectFormat = rSectFormats[ --n ]; + // don't add sections in Undo/Redo + if( !pSectFormat->IsInNodesArr()) + continue; + SwSection* pSect = pSectFormat->GetSection(); + if( pSect->CalcHiddenFlag() ) + { + SwSection* pParent = pSect, *pTmp; + while( nullptr != (pTmp = pParent->GetParent() )) + { + if( pTmp->IsHiddenFlag() ) + pSect = pTmp; + pParent = pTmp; + } + + aSectFormats.insert( pSect->GetFormat() ); + } + if( !pSect->GetCondition().isEmpty() ) + { + SwSectionData aSectionData( *pSect ); + aSectionData.SetCondition( OUString() ); + aSectionData.SetHidden( false ); + UpdateSection( n, aSectionData ); + } + } + + auto n = aSectFormats.size(); + + if( 0 != n ) + { + while( n ) + { + SwSectionFormat* pSectFormat = aSectFormats[ --n ]; + SwSectionNode* pSectNd = pSectFormat->GetSectionNode(); + if( pSectNd ) + { + bRet = true; + SwPaM aPam( *pSectNd ); + + if( pSectNd->StartOfSectionNode()->StartOfSectionIndex() == + pSectNd->GetIndex() - 1 && + pSectNd->StartOfSectionNode()->EndOfSectionIndex() == + pSectNd->EndOfSectionIndex() + 1 ) + { + // only delete the content + SwContentNode* pCNd = GetNodes().GoNext( + &aPam.GetPoint()->nNode ); + aPam.GetPoint()->nContent.Assign( pCNd, 0 ); + aPam.SetMark(); + aPam.GetPoint()->nNode = *pSectNd->EndOfSectionNode(); + pCNd = SwNodes::GoPrevious( + &aPam.GetPoint()->nNode ); + aPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() ); + + getIDocumentContentOperations().DeleteRange( aPam ); + } + else + { + // delete the whole section + aPam.SetMark(); + aPam.GetPoint()->nNode = *pSectNd->EndOfSectionNode(); + getIDocumentContentOperations().DelFullPara( aPam ); + } + + } + } + } + } + + if( bRet ) + getIDocumentState().SetModified(); + GetIDocumentUndoRedo().EndUndo( SwUndoId::UI_DELETE_INVISIBLECNTNT, nullptr ); + return bRet; +} + +bool SwDoc::HasInvisibleContent() const +{ + std::vector<SwFormatField*> vFields; + getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::HiddenPara)->GatherFields(vFields); + if(vFields.size()) + return true; + + // Search for any hidden paragraph (hidden text attribute) + for( SwNodeOffset n = GetNodes().Count()-SwNodeOffset(1); n; --n) + { + SwTextNode* pTextNd = GetNodes()[ n ]->GetTextNode(); + if ( pTextNd && + ( pTextNd->HasHiddenCharAttribute( true ) || pTextNd->HasHiddenCharAttribute( false ) ) ) + return true; + } + + for(auto pSectFormat : GetSections()) + { + // don't add sections in Undo/Redo + if( !pSectFormat->IsInNodesArr()) + continue; + SwSection* pSect = pSectFormat->GetSection(); + if( pSect->IsHidden() ) + return true; + } + return false; +} + +bool SwDoc::RestoreInvisibleContent() +{ + SwUndoId nLastUndoId(SwUndoId::EMPTY); + if (GetIDocumentUndoRedo().GetLastUndoInfo(nullptr, & nLastUndoId) + && (SwUndoId::UI_DELETE_INVISIBLECNTNT == nLastUndoId)) + { + GetIDocumentUndoRedo().Undo(); + GetIDocumentUndoRedo().ClearRedo(); + return true; + } + return false; +} + +bool SwDoc::ConvertFieldsToText(SwRootFrame const& rLayout) +{ + bool bRet = false; + getIDocumentFieldsAccess().LockExpFields(); + GetIDocumentUndoRedo().StartUndo( SwUndoId::UI_REPLACE, nullptr ); + + const SwFieldTypes* pMyFieldTypes = getIDocumentFieldsAccess().GetFieldTypes(); + const SwFieldTypes::size_type nCount = pMyFieldTypes->size(); + //go backward, field types are removed + for(SwFieldTypes::size_type nType = nCount; nType > 0; --nType) + { + const SwFieldType *pCurType = (*pMyFieldTypes)[nType - 1].get(); + + if ( SwFieldIds::Postit == pCurType->Which() ) + continue; + + std::vector<SwFormatField*> vFieldFormats; + pCurType->GatherFields(vFieldFormats, false); + for(const auto& rpFieldFormat : vFieldFormats) + { + const SwTextField *pTextField = rpFieldFormat->GetTextField(); + // skip fields that are currently not in the document + // e.g. fields in undo or redo array + + bool bSkip = !pTextField || + !pTextField->GetpTextNode()->GetNodes().IsDocNodes(); + + if (!bSkip) + { + bool bInHeaderFooter = IsInHeaderFooter(SwNodeIndex(*pTextField->GetpTextNode())); + const SwFormatField& rFormatField = pTextField->GetFormatField(); + const SwField* pField = rFormatField.GetField(); + + //#i55595# some fields have to be excluded in headers/footers + SwFieldIds nWhich = pField->GetTyp()->Which(); + if(!bInHeaderFooter || + (nWhich != SwFieldIds::PageNumber && + nWhich != SwFieldIds::Chapter && + nWhich != SwFieldIds::GetExp&& + nWhich != SwFieldIds::SetExp&& + nWhich != SwFieldIds::Input&& + nWhich != SwFieldIds::RefPageGet&& + nWhich != SwFieldIds::RefPageSet)) + { + OUString sText = pField->ExpandField(true, &rLayout); + + // database fields should not convert their command into text + if( SwFieldIds::Database == pCurType->Which() && !static_cast<const SwDBField*>(pField)->IsInitialized()) + sText.clear(); + + SwPaM aInsertPam(*pTextField->GetpTextNode(), pTextField->GetStart()); + aInsertPam.SetMark(); + + // go to the end of the field + const SwTextField *pFieldAtEnd = sw::DocumentFieldsManager::GetTextFieldAtPos(*aInsertPam.End()); + if (pFieldAtEnd && pFieldAtEnd->Which() == RES_TXTATR_INPUTFIELD) + { + SwPosition &rEndPos = *aInsertPam.GetPoint(); + rEndPos.nContent = SwCursorShell::EndOfInputFieldAtPos( *aInsertPam.End() ); + } + else + { + aInsertPam.Move(); + } + + // first insert the text after field to keep the field's attributes, + // then delete the field + if (!sText.isEmpty()) + { + // to keep the position after insert + SwPaM aDelPam( *aInsertPam.GetMark(), *aInsertPam.GetPoint() ); + aDelPam.Move( fnMoveBackward ); + aInsertPam.DeleteMark(); + + getIDocumentContentOperations().InsertString( aInsertPam, sText ); + + aDelPam.Move(); + // finally remove the field + getIDocumentContentOperations().DeleteAndJoin( aDelPam ); + } + else + { + getIDocumentContentOperations().DeleteAndJoin( aInsertPam ); + } + + bRet = true; + } + } + } + } + + if( bRet ) + getIDocumentState().SetModified(); + GetIDocumentUndoRedo().EndUndo( SwUndoId::UI_REPLACE, nullptr ); + getIDocumentFieldsAccess().UnlockExpFields(); + return bRet; + +} + +bool SwDoc::IsInsTableFormatNum() const +{ + return SW_MOD()->IsInsTableFormatNum(GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE)); +} + +bool SwDoc::IsInsTableChangeNumFormat() const +{ + return SW_MOD()->IsInsTableChangeNumFormat(GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE)); +} + +bool SwDoc::IsInsTableAlignNum() const +{ + return SW_MOD()->IsInsTableAlignNum(GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE)); +} + +bool SwDoc::IsSplitVerticalByDefault() const +{ + return SW_MOD()->IsSplitVerticalByDefault(GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE)); +} + +void SwDoc::SetSplitVerticalByDefault(bool value) +{ + SW_MOD()->SetSplitVerticalByDefault(GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE), value); +} + +/// Set up the InsertDB as Undo table +void SwDoc::AppendUndoForInsertFromDB( const SwPaM& rPam, bool bIsTable ) +{ + if( bIsTable ) + { + const SwTableNode* pTableNd = rPam.GetPoint()->nNode.GetNode().FindTableNode(); + if( pTableNd ) + { + std::unique_ptr<SwUndoCpyTable> pUndo(new SwUndoCpyTable(*this)); + pUndo->SetTableSttIdx( pTableNd->GetIndex() ); + GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) ); + } + } + else if( rPam.HasMark() ) + { + std::unique_ptr<SwUndoCpyDoc> pUndo(new SwUndoCpyDoc( rPam )); + pUndo->SetInsertRange( rPam, false ); + GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) ); + } +} + +void SwDoc::ChangeTOX(SwTOXBase & rTOX, const SwTOXBase & rNew) +{ + assert(dynamic_cast<const SwTOXBaseSection*>(&rTOX)); + SwTOXBaseSection& rTOXSect(static_cast<SwTOXBaseSection&>(rTOX)); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( + std::make_unique<SwUndoTOXChange>(*this, rTOXSect, rNew)); + } + + rTOX = rNew; + + // note: do not Update the ToX here - the caller will do it, with a ViewShell! +} + +OUString SwDoc::GetPaMDescr(const SwPaM & rPam) +{ + if (&rPam.GetNode() == &rPam.GetNode(false)) + { + SwTextNode * pTextNode = rPam.GetNode().GetTextNode(); + + if (nullptr != pTextNode) + { + const sal_Int32 nStart = rPam.Start()->nContent.GetIndex(); + const sal_Int32 nEnd = rPam.End()->nContent.GetIndex(); + + return SwResId(STR_START_QUOTE) + + ShortenString(pTextNode->GetText().copy(nStart, nEnd - nStart), + nUndoStringLength, + SwResId(STR_LDOTS)) + + SwResId(STR_END_QUOTE); + } + } + else + { + return SwResId(STR_PARAGRAPHS); + } + + return "??"; +} + +bool SwDoc::ContainsHiddenChars() const +{ + for( SwNodeOffset n = GetNodes().Count(); n; ) + { + SwNode* pNd = GetNodes()[ --n ]; + if ( pNd->IsTextNode() && pNd->GetTextNode()->HasHiddenCharAttribute( false ) ) + return true; + } + + return false; +} + +std::shared_ptr<SwUnoCursor> SwDoc::CreateUnoCursor( const SwPosition& rPos, bool bTableCursor ) +{ + std::shared_ptr<SwUnoCursor> pNew; + if( bTableCursor ) + pNew = std::make_shared<SwUnoTableCursor>(rPos); + else + pNew = std::make_shared<SwUnoCursor>(rPos); + + mvUnoCursorTable.push_back( pNew ); + return pNew; +} + +void SwDoc::ChkCondColls() +{ + for (SwTextFormatColls::size_type n = 0; n < mpTextFormatCollTable->size(); ++n) + { + SwTextFormatColl *pColl = (*mpTextFormatCollTable)[n]; + if (RES_CONDTXTFMTCOLL == pColl->Which()) + pColl->CallSwClientNotify( SwAttrHint() ); + } +} + +uno::Reference< script::vba::XVBAEventProcessor > const & +SwDoc::GetVbaEventProcessor() +{ +#if HAVE_FEATURE_SCRIPTING + if( !mxVbaEvents.is() && mpDocShell && ooo::vba::isAlienWordDoc( *mpDocShell ) ) + { + try + { + uno::Reference< frame::XModel > xModel( mpDocShell->GetModel(), uno::UNO_SET_THROW ); + uno::Sequence< uno::Any > aArgs{ uno::Any(xModel) }; + mxVbaEvents.set( ooo::vba::createVBAUnoAPIServiceWithArgs( mpDocShell, "com.sun.star.script.vba.VBATextEventProcessor" , aArgs ), uno::UNO_QUERY_THROW ); + } + catch( uno::Exception& ) + { + } + } +#endif + return mxVbaEvents; +} + +void SwDoc::SetMissingDictionaries( bool bIsMissing ) +{ + if (!bIsMissing) + meDictionaryMissing = MissingDictionary::False; + else if (meDictionaryMissing == MissingDictionary::Undefined) + meDictionaryMissing = MissingDictionary::True; +}; + +void SwDoc::SetLanguage(const LanguageType eLang, const sal_uInt16 nId) +{ + mpAttrPool->SetPoolDefaultItem(SvxLanguageItem(eLang, nId)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |