tdf#125522: Mail merge: Hidden text frames are not completely removed
[LibreOffice.git] / sw / source / core / doc / doc.cxx
blob7828fba9e62c06e57c18d2729151583a5e9995dc
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 <config_features.h>
22 #include <doc.hxx>
23 #include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
24 #include <com/sun/star/frame/XModel.hpp>
25 #include <DocumentFieldsManager.hxx>
26 #include <DocumentSettingManager.hxx>
27 #include <DocumentDrawModelManager.hxx>
28 #include <DocumentTimerManager.hxx>
29 #include <DocumentDeviceManager.hxx>
30 #include <DocumentChartDataProviderManager.hxx>
31 #include <DocumentLinksAdministrationManager.hxx>
32 #include <DocumentListItemsManager.hxx>
33 #include <DocumentListsManager.hxx>
34 #include <DocumentOutlineNodesManager.hxx>
35 #include <DocumentContentOperationsManager.hxx>
36 #include <DocumentRedlineManager.hxx>
37 #include <DocumentStatisticsManager.hxx>
38 #include <DocumentStateManager.hxx>
39 #include <DocumentStylePoolManager.hxx>
40 #include <DocumentLayoutManager.hxx>
41 #include <DocumentExternalDataManager.hxx>
42 #include <UndoManager.hxx>
43 #include <dbmgr.hxx>
44 #include <hintids.hxx>
45 #include <tools/globname.hxx>
46 #include <svx/svxids.hrc>
48 #include <comphelper/random.hxx>
49 #include <tools/urlobj.hxx>
50 #include <tools/poly.hxx>
51 #include <tools/multisel.hxx>
52 #include <rtl/ustring.hxx>
53 #include <vcl/virdev.hxx>
54 #include <svl/itemiter.hxx>
55 #include <svl/poolitem.hxx>
56 #include <unotools/syslocale.hxx>
57 #include <sfx2/printer.hxx>
58 #include <editeng/keepitem.hxx>
59 #include <editeng/formatbreakitem.hxx>
60 #include <sfx2/linkmgr.hxx>
61 #include <svx/svdmodel.hxx>
62 #include <editeng/pbinitem.hxx>
63 #include <unotools/charclass.hxx>
64 #include <unotools/localedatawrapper.hxx>
65 #include <vcl/timer.hxx>
67 #include <swatrset.hxx>
68 #include <swmodule.hxx>
69 #include <fmtpdsc.hxx>
70 #include <fmtanchr.hxx>
71 #include <fmtrfmrk.hxx>
72 #include <fmtinfmt.hxx>
73 #include <fmtfld.hxx>
74 #include <txtfld.hxx>
75 #include <dbfld.hxx>
76 #include <txtinet.hxx>
77 #include <txtrfmrk.hxx>
78 #include <frmatr.hxx>
79 #include <pagefrm.hxx>
80 #include <rootfrm.hxx>
81 #include <swtable.hxx>
82 #include <pam.hxx>
83 #include <ndtxt.hxx>
84 #include <swundo.hxx>
85 #include <UndoCore.hxx>
86 #include <UndoInsert.hxx>
87 #include <UndoSplitMove.hxx>
88 #include <UndoTable.hxx>
89 #include <pagedesc.hxx>
90 #include <ndole.hxx>
91 #include <ndgrf.hxx>
92 #include <rolbck.hxx>
93 #include <doctxm.hxx>
94 #include <grfatr.hxx>
95 #include <poolfmt.hxx>
96 #include <mvsave.hxx>
97 #include <SwGrammarMarkUp.hxx>
98 #include <scriptinfo.hxx>
99 #include <acorrect.hxx>
100 #include <mdiexp.hxx>
101 #include <docstat.hxx>
102 #include <docary.hxx>
103 #include <redline.hxx>
104 #include <fldupde.hxx>
105 #include <swbaslnk.hxx>
106 #include <printdata.hxx>
107 #include <cmdid.h>
108 #include <strings.hrc>
109 #include <SwUndoTOXChange.hxx>
110 #include <unocrsr.hxx>
111 #include <docsh.hxx>
112 #include <viewopt.hxx>
113 #include <docfld.hxx>
114 #include <docufld.hxx>
115 #include <viewsh.hxx>
116 #include <shellres.hxx>
117 #include <txtfrm.hxx>
118 #include <attrhint.hxx>
119 #include <view.hxx>
121 #include <wdocsh.hxx>
122 #include <prtopt.hxx>
123 #include <wrtsh.hxx>
125 #include <vector>
126 #include <map>
127 #include <osl/diagnose.h>
128 #include <osl/interlck.h>
129 #include <vbahelper/vbaaccesshelper.hxx>
130 #include <calbck.hxx>
132 /* @@@MAINTAINABILITY-HORROR@@@
133 Probably unwanted dependency on SwDocShell
135 #include <layouter.hxx>
137 using namespace ::com::sun::star;
139 sal_Int32 SwDoc::acquire()
141 assert(mReferenceCount >= 0);
142 return osl_atomic_increment(&mReferenceCount);
145 sal_Int32 SwDoc::release()
147 assert(mReferenceCount >= 1);
148 auto x = osl_atomic_decrement(&mReferenceCount);
149 if (x == 0)
150 delete this;
151 return x;
154 sal_Int32 SwDoc::getReferenceCount() const
156 assert(mReferenceCount >= 0);
157 return mReferenceCount;
160 ::sw::MetaFieldManager & SwDoc::GetMetaFieldManager()
162 return *m_pMetaFieldManager;
165 ::sw::UndoManager & SwDoc::GetUndoManager()
167 return *m_pUndoManager;
170 ::sw::UndoManager const & SwDoc::GetUndoManager() const
172 return *m_pUndoManager;
176 IDocumentUndoRedo & SwDoc::GetIDocumentUndoRedo()
178 return *m_pUndoManager;
181 IDocumentUndoRedo const & SwDoc::GetIDocumentUndoRedo() const
183 return *m_pUndoManager;
186 /* IDocumentDrawModelAccess */
187 IDocumentDrawModelAccess const & SwDoc::getIDocumentDrawModelAccess() const
189 return GetDocumentDrawModelManager();
192 IDocumentDrawModelAccess & SwDoc::getIDocumentDrawModelAccess()
194 return GetDocumentDrawModelManager();
197 ::sw::DocumentDrawModelManager const & SwDoc::GetDocumentDrawModelManager() const
199 return *m_pDocumentDrawModelManager;
202 ::sw::DocumentDrawModelManager & SwDoc::GetDocumentDrawModelManager()
204 return *m_pDocumentDrawModelManager;
207 /* IDocumentSettingAccess */
208 IDocumentSettingAccess const & SwDoc::getIDocumentSettingAccess() const
210 return GetDocumentSettingManager();
213 IDocumentSettingAccess & SwDoc::getIDocumentSettingAccess()
215 return GetDocumentSettingManager();
218 ::sw::DocumentSettingManager & SwDoc::GetDocumentSettingManager()
220 return *m_pDocumentSettingManager;
223 ::sw::DocumentSettingManager const & SwDoc::GetDocumentSettingManager() const
225 return *m_pDocumentSettingManager;
228 sal_uInt32 SwDoc::getRsid() const
230 return mnRsid;
233 void SwDoc::setRsid( sal_uInt32 nVal )
235 static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr);
237 sal_uInt32 nIncrease = 0;
238 if (!bHack)
240 // Increase the rsid with a random number smaller than 2^17. This way we
241 // expect to be able to edit a document 2^12 times before rsid overflows.
242 // start from 1 to ensure the new rsid is not the same
243 nIncrease = comphelper::rng::uniform_uint_distribution(1, (1 << 17) - 1);
245 mnRsid = nVal + nIncrease;
248 sal_uInt32 SwDoc::getRsidRoot() const
250 return mnRsidRoot;
253 void SwDoc::setRsidRoot( sal_uInt32 nVal )
255 mnRsidRoot = nVal;
258 /* IDocumentChartDataProviderAccess */
259 IDocumentChartDataProviderAccess const & SwDoc::getIDocumentChartDataProviderAccess() const
261 return *m_pDocumentChartDataProviderManager;
264 IDocumentChartDataProviderAccess & SwDoc::getIDocumentChartDataProviderAccess()
266 return *m_pDocumentChartDataProviderManager;
269 // IDocumentDeviceAccess
270 IDocumentDeviceAccess const & SwDoc::getIDocumentDeviceAccess() const
272 return *m_pDeviceAccess;
275 IDocumentDeviceAccess & SwDoc::getIDocumentDeviceAccess()
277 return *m_pDeviceAccess;
280 //IDocumentTimerAccess
281 IDocumentTimerAccess const & SwDoc::getIDocumentTimerAccess() const
283 return *m_pDocumentTimerManager;
286 IDocumentTimerAccess & SwDoc::getIDocumentTimerAccess()
288 return *m_pDocumentTimerManager;
291 // IDocumentLinksAdministration
292 IDocumentLinksAdministration const & SwDoc::getIDocumentLinksAdministration() const
294 return *m_pDocumentLinksAdministrationManager;
297 IDocumentLinksAdministration & SwDoc::getIDocumentLinksAdministration()
299 return *m_pDocumentLinksAdministrationManager;
302 ::sw::DocumentLinksAdministrationManager const & SwDoc::GetDocumentLinksAdministrationManager() const
304 return *m_pDocumentLinksAdministrationManager;
307 ::sw::DocumentLinksAdministrationManager & SwDoc::GetDocumentLinksAdministrationManager()
309 return *m_pDocumentLinksAdministrationManager;
312 //IDocumentListItems
313 IDocumentListItems const & SwDoc::getIDocumentListItems() const
315 return *m_pDocumentListItemsManager;
318 //IDocumentListItems
319 IDocumentListItems & SwDoc::getIDocumentListItems()
321 return *m_pDocumentListItemsManager;
324 //IDocumentListsAccess
325 IDocumentListsAccess const & SwDoc::getIDocumentListsAccess() const
327 return *m_pDocumentListsManager;
330 IDocumentListsAccess & SwDoc::getIDocumentListsAccess()
332 return *m_pDocumentListsManager;
335 //IDocumentOutlinesNodes
336 IDocumentOutlineNodes const & SwDoc::getIDocumentOutlineNodes() const
338 return *m_pDocumentOutlineNodesManager;
341 IDocumentOutlineNodes & SwDoc::getIDocumentOutlineNodes()
343 return *m_pDocumentOutlineNodesManager;
346 //IDocumentContentOperations
347 IDocumentContentOperations const & SwDoc::getIDocumentContentOperations() const
349 return *m_pDocumentContentOperationsManager;
352 IDocumentContentOperations & SwDoc::getIDocumentContentOperations()
354 return *m_pDocumentContentOperationsManager;
357 ::sw::DocumentContentOperationsManager const & SwDoc::GetDocumentContentOperationsManager() const
359 return *m_pDocumentContentOperationsManager;
361 ::sw::DocumentContentOperationsManager & SwDoc::GetDocumentContentOperationsManager()
363 return *m_pDocumentContentOperationsManager;
366 //IDocumentRedlineAccess
367 IDocumentRedlineAccess const & SwDoc::getIDocumentRedlineAccess() const
369 return *m_pDocumentRedlineManager;
372 IDocumentRedlineAccess& SwDoc::getIDocumentRedlineAccess()
374 return *m_pDocumentRedlineManager;
377 ::sw::DocumentRedlineManager const & SwDoc::GetDocumentRedlineManager() const
379 return *m_pDocumentRedlineManager;
382 ::sw::DocumentRedlineManager& SwDoc::GetDocumentRedlineManager()
384 return *m_pDocumentRedlineManager;
387 //IDocumentFieldsAccess
389 IDocumentFieldsAccess const & SwDoc::getIDocumentFieldsAccess() const
391 return *m_pDocumentFieldsManager;
394 IDocumentFieldsAccess & SwDoc::getIDocumentFieldsAccess()
396 return *m_pDocumentFieldsManager;
399 ::sw::DocumentFieldsManager & SwDoc::GetDocumentFieldsManager()
401 return *m_pDocumentFieldsManager;
404 //IDocumentStatistics
405 IDocumentStatistics const & SwDoc::getIDocumentStatistics() const
407 return *m_pDocumentStatisticsManager;
410 IDocumentStatistics & SwDoc::getIDocumentStatistics()
412 return *m_pDocumentStatisticsManager;
415 ::sw::DocumentStatisticsManager const & SwDoc::GetDocumentStatisticsManager() const
417 return *m_pDocumentStatisticsManager;
420 ::sw::DocumentStatisticsManager & SwDoc::GetDocumentStatisticsManager()
422 return *m_pDocumentStatisticsManager;
425 //IDocumentState
426 IDocumentState const & SwDoc::getIDocumentState() const
428 return *m_pDocumentStateManager;
431 IDocumentState & SwDoc::getIDocumentState()
433 return *m_pDocumentStateManager;
436 //IDocumentLayoutAccess
437 IDocumentLayoutAccess const & SwDoc::getIDocumentLayoutAccess() const
439 return *m_pDocumentLayoutManager;
442 IDocumentLayoutAccess & SwDoc::getIDocumentLayoutAccess()
444 return *m_pDocumentLayoutManager;
447 ::sw::DocumentLayoutManager const & SwDoc::GetDocumentLayoutManager() const
449 return *m_pDocumentLayoutManager;
452 ::sw::DocumentLayoutManager & SwDoc::GetDocumentLayoutManager()
454 return *m_pDocumentLayoutManager;
457 //IDocumentStylePoolAccess
458 IDocumentStylePoolAccess const & SwDoc::getIDocumentStylePoolAccess() const
460 return *m_pDocumentStylePoolManager;
463 IDocumentStylePoolAccess & SwDoc::getIDocumentStylePoolAccess()
465 return *m_pDocumentStylePoolManager;
468 //IDocumentExternalData
469 IDocumentExternalData const & SwDoc::getIDocumentExternalData() const
471 return *m_pDocumentExternalDataManager;
474 IDocumentExternalData & SwDoc::getIDocumentExternalData()
476 return *m_pDocumentExternalDataManager;
479 /* Implementations the next Interface here */
482 * Document editing (Doc-SS) to fill the document
483 * by the RTF parser and for the EditShell.
485 void SwDoc::ChgDBData(const SwDBData& rNewData)
487 if( rNewData != maDBData )
489 maDBData = rNewData;
490 getIDocumentState().SetModified();
491 if (m_pDBManager)
492 m_pDBManager->CommitLastRegistrations();
494 getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::DatabaseName)->UpdateFields();
497 struct PostItField_ : public SetGetExpField
499 PostItField_( const SwNodeIndex& rNdIdx, const SwTextField* pField )
500 : SetGetExpField( rNdIdx, pField, nullptr ) {}
502 sal_uInt16 GetPageNo( const StringRangeEnumerator &rRangeEnum,
503 const std::set< sal_Int32 > &rPossiblePages,
504 sal_uInt16& rVirtPgNo, sal_uInt16& rLineNo );
506 const SwPostItField* GetPostIt() const
508 return static_cast<const SwPostItField*>( GetTextField()->GetFormatField().GetField() );
512 sal_uInt16 PostItField_::GetPageNo(
513 const StringRangeEnumerator &rRangeEnum,
514 const std::set< sal_Int32 > &rPossiblePages,
515 /* out */ sal_uInt16& rVirtPgNo, /* out */ sal_uInt16& rLineNo )
517 //Problem: If a PostItField is contained in a Node that is represented
518 //by more than one layout instance,
519 //we have to decide whether it should be printed once or n-times.
520 //Probably only once. For the page number we don't select a random one,
521 //but the PostIt's first occurrence in the selected area.
522 rVirtPgNo = 0;
523 SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(GetTextField()->GetTextNode());
524 for( SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
526 TextFrameIndex const nPos = pFrame->MapModelToView(
527 &GetTextField()->GetTextNode(), GetContent());
528 if( pFrame->GetOfst() > nPos ||
529 (pFrame->HasFollow() && pFrame->GetFollow()->GetOfst() <= nPos) )
530 continue;
531 sal_uInt16 nPgNo = pFrame->GetPhyPageNum();
532 if( rRangeEnum.hasValue( nPgNo, &rPossiblePages ))
534 rLineNo = static_cast<sal_uInt16>(pFrame->GetLineCount( nPos ) +
535 pFrame->GetAllLines() - pFrame->GetThisLines());
536 rVirtPgNo = pFrame->GetVirtPageNum();
537 return nPgNo;
540 return 0;
543 bool sw_GetPostIts(
544 IDocumentFieldsAccess const * pIDFA,
545 SetGetExpFields * pSrtLst )
547 bool bHasPostIts = false;
549 SwFieldType* pFieldType = pIDFA->GetSysFieldType( SwFieldIds::Postit );
550 assert(pFieldType);
552 if( pFieldType->HasWriterListeners() )
554 // Found modify object; insert all fields into the array
555 SwIterator<SwFormatField,SwFieldType> aIter( *pFieldType );
556 for( SwFormatField* pField = aIter.First(); pField; pField = aIter.Next() )
558 const SwTextField* pTextField;
559 if( nullptr != ( pTextField = pField->GetTextField() ) &&
560 pTextField->GetTextNode().GetNodes().IsDocNodes() )
562 bHasPostIts = true;
563 if (pSrtLst)
565 SwNodeIndex aIdx( pTextField->GetTextNode() );
566 std::unique_ptr<PostItField_> pNew(new PostItField_( aIdx, pTextField ));
567 pSrtLst->insert( std::move(pNew) );
569 else
570 break; // we just wanted to check for the existence of postits ...
575 return bHasPostIts;
578 static void lcl_FormatPostIt(
579 IDocumentContentOperations* pIDCO,
580 SwPaM& aPam,
581 const SwPostItField* pField,
582 bool bNewPage, bool bIsFirstPostIt,
583 sal_uInt16 nPageNo, sal_uInt16 nLineNo )
585 static char const sTmp[] = " : ";
587 assert(SwViewShell::GetShellRes());
589 if (bNewPage)
591 pIDCO->InsertPoolItem( aPam, SvxFormatBreakItem( SvxBreak::PageAfter, RES_BREAK ) );
592 pIDCO->SplitNode( *aPam.GetPoint(), false );
594 else if (!bIsFirstPostIt)
596 // add an empty line between different notes
597 pIDCO->SplitNode( *aPam.GetPoint(), false );
598 pIDCO->SplitNode( *aPam.GetPoint(), false );
601 OUString aStr( SwViewShell::GetShellRes()->aPostItPage );
602 aStr += sTmp;
604 aStr += OUString::number( nPageNo );
605 aStr += " ";
606 if( nLineNo )
608 aStr += SwViewShell::GetShellRes()->aPostItLine;
609 aStr += sTmp;
610 aStr += OUString::number( nLineNo );
611 aStr += " ";
613 aStr += SwViewShell::GetShellRes()->aPostItAuthor;
614 aStr += sTmp;
615 aStr += pField->GetPar1();
616 aStr += " ";
617 SvtSysLocale aSysLocale;
618 aStr += /*(LocaleDataWrapper&)*/aSysLocale.GetLocaleData().getDate( pField->GetDate() );
619 pIDCO->InsertString( aPam, aStr );
621 pIDCO->SplitNode( *aPam.GetPoint(), false );
622 aStr = pField->GetPar2();
623 #if defined(_WIN32)
624 // Throw out all CR in Windows
625 aStr = aStr.replaceAll("\r", "");
626 #endif
627 pIDCO->InsertString( aPam, aStr );
630 /// provide the paper tray to use according to the page style in use,
631 /// but do that only if the respective item is NOT just the default item
632 static sal_Int32 lcl_GetPaperBin( const SwPageFrame *pStartFrame )
634 sal_Int32 nRes = -1;
636 const SwFrameFormat &rFormat = pStartFrame->GetPageDesc()->GetMaster();
637 const SfxPoolItem *pItem = nullptr;
638 SfxItemState eState = rFormat.GetItemState( RES_PAPER_BIN, false, &pItem );
639 const SvxPaperBinItem *pPaperBinItem = dynamic_cast< const SvxPaperBinItem * >(pItem);
640 if (eState > SfxItemState::DEFAULT && pPaperBinItem)
641 nRes = pPaperBinItem->GetValue();
643 return nRes;
646 namespace
648 // tdf#:114663 Translates a range string from user input (with page numbering possibly not
649 // taking blank pages into account) to equivalent string which references physical page numbers.
650 // rUIPages2PhyPagesMap must contain a contiguous sequence of UI page numbers
651 OUString UIPages2PhyPages(const OUString& rUIPageRange, const std::map< sal_Int32, sal_Int32 >& rUIPages2PhyPagesMap)
653 if (rUIPages2PhyPagesMap.empty())
654 return OUString();
655 auto iMin = rUIPages2PhyPagesMap.begin();
656 const sal_Int32 nUIPageMin = iMin->first, nPhyPageMin = iMin->second;
657 auto iMax = rUIPages2PhyPagesMap.rbegin();
658 const sal_Int32 nUIPageMax = iMax->first, nPhyPageMax = iMax->second;
659 OUStringBuffer aOut(rUIPageRange.getLength());
660 OUStringBuffer aNumber(16);
661 const sal_Unicode* pInput = rUIPageRange.getStr();
662 while (*pInput)
664 while (*pInput >= '0' && *pInput <= '9')
665 aNumber.append(*pInput++);
666 if (!aNumber.isEmpty())
668 sal_Int32 nNumber = aNumber.makeStringAndClear().toInt32();
669 if (nNumber < nUIPageMin)
670 nNumber = nPhyPageMin-1;
671 else if (nNumber > nUIPageMax)
672 nNumber = nPhyPageMax+1;
673 else
674 nNumber = rUIPages2PhyPagesMap.at(nNumber);
675 aOut.append(nNumber);
678 while (*pInput && (*pInput < '0' || *pInput > '9'))
679 aOut.append(*pInput++);
682 return aOut.makeStringAndClear();
686 void SwDoc::CalculatePagesForPrinting(
687 const SwRootFrame& rLayout,
688 /* out */ SwRenderData &rData,
689 const SwPrintUIOptions &rOptions,
690 bool bIsPDFExport,
691 sal_Int32 nDocPageCount )
693 const sal_Int64 nContent = rOptions.getIntValue( "PrintContent", 0 );
694 const bool bPrintSelection = nContent == 4;
696 // properties to take into account when calculating the set of pages
697 // (PDF export UI does not allow for selecting left or right pages only)
698 bool bPrintLeftPages = bIsPDFExport || rOptions.IsPrintLeftPages();
699 bool bPrintRightPages = bIsPDFExport || rOptions.IsPrintRightPages();
700 // #i103700# printing selections should not allow for automatic inserting empty pages
701 bool bPrintEmptyPages = !bPrintSelection && rOptions.IsPrintEmptyPages( bIsPDFExport );
703 std::map< sal_Int32, sal_Int32 > &rPrinterPaperTrays = rData.GetPrinterPaperTrays();
704 std::set< sal_Int32 > &rValidPages = rData.GetValidPagesSet();
705 // Map page numbers from user input (possibly ignoring blanks) to physical page numbers
706 std::map< sal_Int32, sal_Int32 > aUIPages2PhyPagesMap;
707 rValidPages.clear();
709 sal_Int32 nPageNum = 1, nUIPageNum = 1;
710 const SwPageFrame *pStPage = dynamic_cast<const SwPageFrame*>( rLayout.Lower() );
711 while (pStPage && nPageNum <= nDocPageCount)
713 const bool bNonEmptyPage = pStPage->getFrameArea().Height() != 0;
714 const bool bPrintThisPage =
715 ( (bPrintRightPages && pStPage->OnRightPage()) ||
716 (bPrintLeftPages && !pStPage->OnRightPage()) ) &&
717 ( bPrintEmptyPages || bNonEmptyPage );
719 if (bPrintThisPage)
721 rValidPages.insert( nPageNum );
722 rPrinterPaperTrays[ nPageNum ] = lcl_GetPaperBin( pStPage );
725 if ( bPrintEmptyPages || bNonEmptyPage )
727 aUIPages2PhyPagesMap[nUIPageNum++] = nPageNum;
729 ++nPageNum;
730 pStPage = static_cast<const SwPageFrame*>(pStPage->GetNext());
733 // now that we have identified the valid pages for printing according
734 // to the print settings we need to get the PageRange to use and
735 // use both results to get the actual pages to be printed
736 // (post-it settings need to be taken into account later on!)
738 // get PageRange value to use
739 OUString aPageRange;
740 // #i116085# - adjusting fix for i113919
741 if ( !bIsPDFExport )
743 // PageContent :
744 // 0 -> print all pages (default if aPageRange is empty)
745 // 1 -> print range according to PageRange
746 // 2 -> print even pages
747 // 3 -> print odd pages
748 // 4 -> print selection
749 if (1 == nContent)
750 aPageRange = rOptions.getStringValue( "PageRange" );
751 if (4 == nContent)
753 // note that printing selections is actually implemented by copying
754 // the selection to a new temporary document and printing all of that one.
755 // Thus for Writer "PrintContent" must never be 4.
756 // See SwXTextDocument::GetRenderDoc for evaluating if a selection is to be
757 // printed and for creating the temporary document.
760 // please note
762 if (aPageRange.isEmpty()) // empty string -> print all
764 // set page range to print to 'all pages'
765 aPageRange = OUString::number( 1 ) + "-" + OUString::number( nDocPageCount );
767 else
769 // Convert page numbers from user input to physical page numbers
770 aPageRange = UIPages2PhyPages(aPageRange, aUIPages2PhyPagesMap);
772 rData.SetPageRange( aPageRange );
774 // get vector of pages to print according to PageRange and valid pages set from above
775 // (result may be an empty vector, for example if the range string is not correct)
776 // If excluding empty pages, allow range to specify range of printable pages
777 StringRangeEnumerator::getRangesFromString( aPageRange, rData.GetPagesToPrint(),
778 1, nDocPageCount, 0, &rData.GetValidPagesSet() );
781 void SwDoc::UpdatePagesForPrintingWithPostItData(
782 /* out */ SwRenderData &rData,
783 const SwPrintUIOptions &rOptions,
784 sal_Int32 nDocPageCount )
787 SwPostItMode nPostItMode = static_cast<SwPostItMode>( rOptions.getIntValue( "PrintAnnotationMode", 0 ) );
788 assert((nPostItMode == SwPostItMode::NONE || rData.HasPostItData())
789 && "print post-its without post-it data?");
790 const SetGetExpFields::size_type nPostItCount =
791 rData.HasPostItData() ? rData.m_pPostItFields->size() : 0;
792 if (nPostItMode == SwPostItMode::NONE || nPostItCount <= 0)
793 return;
795 SET_CURR_SHELL( rData.m_pPostItShell.get() );
797 // clear document and move to end of it
798 SwDoc & rPostItDoc(*rData.m_pPostItShell->GetDoc());
799 SwPaM aPam(rPostItDoc.GetNodes().GetEndOfContent());
800 aPam.Move( fnMoveBackward, GoInDoc );
801 aPam.SetMark();
802 aPam.Move( fnMoveForward, GoInDoc );
803 rPostItDoc.getIDocumentContentOperations().DeleteRange( aPam );
805 const StringRangeEnumerator aRangeEnum( rData.GetPageRange(), 1, nDocPageCount, 0 );
807 // For mode SwPostItMode::EndPage:
808 // maps a physical page number to the page number in post-it document that holds
809 // the first post-it for that physical page . Needed to relate the correct start frames
810 // from the post-it doc to the physical page of the document
811 std::map< sal_Int32, sal_Int32 > aPostItLastStartPageNum;
813 // add all post-its on valid pages within the page range to the
814 // temporary post-it document.
815 // Since the array of post-it fields is sorted by page and line number we will
816 // already get them in the correct order
817 sal_uInt16 nVirtPg = 0, nLineNo = 0, nLastPageNum = 0, nPhyPageNum = 0;
818 bool bIsFirstPostIt = true;
819 for (SetGetExpFields::size_type i = 0; i < nPostItCount; ++i)
821 PostItField_& rPostIt = static_cast<PostItField_&>(*(*rData.m_pPostItFields)[ i ]);
822 nLastPageNum = nPhyPageNum;
823 nPhyPageNum = rPostIt.GetPageNo(
824 aRangeEnum, rData.GetValidPagesSet(), nVirtPg, nLineNo );
825 if (nPhyPageNum)
827 // need to insert a page break?
828 // In SwPostItMode::EndPage mode for each document page the following
829 // post-it page needs to start on a new page
830 const bool bNewPage = nPostItMode == SwPostItMode::EndPage &&
831 !bIsFirstPostIt && nPhyPageNum != nLastPageNum;
833 lcl_FormatPostIt( &rData.m_pPostItShell->GetDoc()->getIDocumentContentOperations(), aPam,
834 rPostIt.GetPostIt(), bNewPage, bIsFirstPostIt, nVirtPg, nLineNo );
835 bIsFirstPostIt = false;
837 if (nPostItMode == SwPostItMode::EndPage)
839 // get the correct number of current pages for the post-it document
840 rData.m_pPostItShell->CalcLayout();
841 const sal_Int32 nPages = rData.m_pPostItShell->GetPageCount();
842 aPostItLastStartPageNum[ nPhyPageNum ] = nPages;
847 // format post-it doc to get correct number of pages
848 rData.m_pPostItShell->CalcLayout();
850 SwRootFrame* pPostItRoot = rData.m_pPostItShell->GetLayout();
851 //tdf#103313 print dialog maxes out cpu as Idles never get to
852 //complete this postitshell's desire to complete formatting
853 pPostItRoot->ResetIdleFormat();
855 const sal_Int32 nPostItDocPageCount = rData.m_pPostItShell->GetPageCount();
857 if (nPostItMode == SwPostItMode::Only || nPostItMode == SwPostItMode::EndDoc)
859 // now add those post-it pages to the vector of pages to print
860 // or replace them if only post-its should be printed
862 if (nPostItMode == SwPostItMode::Only)
864 // no document page to be printed
865 rData.GetPagesToPrint().clear();
868 // now we just need to add the post-it pages to be printed to the
869 // end of the vector of pages to print
870 sal_Int32 nPageNum = 0;
871 const SwPageFrame * pPageFrame = static_cast<SwPageFrame*>(pPostItRoot->Lower());
872 while( pPageFrame && nPageNum < nPostItDocPageCount )
874 ++nPageNum;
875 // negative page number indicates page is from the post-it doc
876 rData.GetPagesToPrint().push_back( -nPageNum );
877 pPageFrame = static_cast<const SwPageFrame*>(pPageFrame->GetNext());
879 OSL_ENSURE( nPageNum == nPostItDocPageCount, "unexpected number of pages" );
881 else if (nPostItMode == SwPostItMode::EndPage)
883 // the next step is to find all the pages from the post-it
884 // document that should be printed for a given physical page
885 // of the document
887 std::vector< sal_Int32 > aTmpPagesToPrint;
888 sal_Int32 nLastPostItPage(0);
889 const size_t nNum = rData.GetPagesToPrint().size();
890 for (size_t i = 0 ; i < nNum; ++i)
892 // add the physical page to print from the document
893 const sal_Int32 nPhysPage = rData.GetPagesToPrint()[i];
894 aTmpPagesToPrint.push_back( nPhysPage );
896 // add the post-it document pages to print, i.e those
897 // post-it pages that have the data for the above physical page
898 std::map<sal_Int32, sal_Int32>::const_iterator const iter(
899 aPostItLastStartPageNum.find(nPhysPage));
900 if (iter != aPostItLastStartPageNum.end())
902 for (sal_Int32 j = nLastPostItPage + 1;
903 j <= iter->second; ++j)
905 // negative page number indicates page is from the
906 aTmpPagesToPrint.push_back(-j); // post-it document
908 nLastPostItPage = iter->second;
912 // finally we need to assign those vectors to the resulting ones.
913 // swapping the data should be more efficient than assigning since
914 // we won't need the temporary vectors anymore
915 rData.GetPagesToPrint().swap( aTmpPagesToPrint );
920 void SwDoc::CalculatePagePairsForProspectPrinting(
921 const SwRootFrame& rLayout,
922 /* out */ SwRenderData &rData,
923 const SwPrintUIOptions &rOptions,
924 sal_Int32 nDocPageCount )
926 std::map< sal_Int32, sal_Int32 > &rPrinterPaperTrays = rData.GetPrinterPaperTrays();
927 std::set< sal_Int32 > &rValidPagesSet = rData.GetValidPagesSet();
928 std::vector< std::pair< sal_Int32, sal_Int32 > > &rPagePairs = rData.GetPagePairsForProspectPrinting();
929 std::map< sal_Int32, const SwPageFrame * > validStartFrames;
931 rPagePairs.clear();
932 rValidPagesSet.clear();
934 OUString aPageRange;
935 // PageContent :
936 // 0 -> print all pages (default if aPageRange is empty)
937 // 1 -> print range according to PageRange
938 // 2 -> print even pages
939 // 3 -> print odd pages
940 // 4 -> print selection
941 const sal_Int64 nContent = rOptions.getIntValue( "PrintContent", 0 );
942 if (nContent == 1)
943 aPageRange = rOptions.getStringValue( "PageRange" );
944 if (aPageRange.isEmpty()) // empty string -> print all
946 // set page range to print to 'all pages'
947 aPageRange = OUString::number( 1 ) + "-" + OUString::number( nDocPageCount );
949 StringRangeEnumerator aRange( aPageRange, 1, nDocPageCount, 0 );
951 if ( aRange.size() <= 0)
952 return;
954 const SwPageFrame *pStPage = dynamic_cast<const SwPageFrame*>( rLayout.Lower() );
955 for ( sal_Int32 i = 1; pStPage && i < nDocPageCount; ++i )
956 pStPage = static_cast<const SwPageFrame*>(pStPage->GetNext());
957 if ( !pStPage ) // Then it was that
958 return;
960 // currently for prospect printing all pages are valid to be printed
961 // thus we add them all to the respective map and set for later use
962 sal_Int32 nPageNum = 0;
963 const SwPageFrame *pPageFrame = dynamic_cast<const SwPageFrame*>( rLayout.Lower() );
964 while( pPageFrame && nPageNum < nDocPageCount )
966 ++nPageNum;
967 rValidPagesSet.insert( nPageNum );
968 validStartFrames[ nPageNum ] = pPageFrame;
969 pPageFrame = static_cast<const SwPageFrame*>(pPageFrame->GetNext());
971 rPrinterPaperTrays[ nPageNum ] = lcl_GetPaperBin( pStPage );
973 OSL_ENSURE( nPageNum == nDocPageCount, "unexpected number of pages" );
975 // properties to take into account when calculating the set of pages
976 // Note: here bPrintLeftPages and bPrintRightPages refer to the (virtual) resulting pages
977 // of the prospect!
978 bool bPrintLeftPages = rOptions.IsPrintLeftPages();
979 bool bPrintRightPages = rOptions.IsPrintRightPages();
980 bool bPrintProspectRTL = rOptions.getIntValue( "PrintProspectRTL", 0 ) != 0;
982 // get pages for prospect printing according to the 'PageRange'
983 // (duplicates and any order allowed!)
984 std::vector< sal_Int32 > aPagesToPrint;
985 StringRangeEnumerator::getRangesFromString(
986 aPageRange, aPagesToPrint, 1, nDocPageCount, 0 );
988 if (aPagesToPrint.empty())
989 return;
991 // now fill the vector for calculating the page pairs with the start frames
992 // from the above obtained vector
993 std::vector< const SwPageFrame * > aVec;
994 for (sal_Int32 nPage : aPagesToPrint)
996 const SwPageFrame *pFrame = validStartFrames[ nPage ];
997 aVec.push_back( pFrame );
1000 // just one page is special ...
1001 if ( 1 == aVec.size() )
1002 aVec.insert( aVec.begin() + 1, nullptr ); // insert a second empty page
1003 else
1005 // now extend the number of pages to fit a multiple of 4
1006 // (4 'normal' pages are needed for a single prospect paper
1007 // with back and front)
1008 while( aVec.size() & 3 )
1009 aVec.push_back( nullptr );
1012 // make sure that all pages are in correct order
1013 std::vector< const SwPageFrame * >::size_type nSPg = 0;
1014 std::vector< const SwPageFrame * >::size_type nEPg = aVec.size();
1015 sal_Int32 nStep = 1;
1016 if ( 0 == (nEPg & 1 )) // there are no uneven ones!
1017 --nEPg;
1019 if ( !bPrintLeftPages )
1020 ++nStep;
1021 else if ( !bPrintRightPages )
1023 ++nStep;
1024 ++nSPg;
1025 --nEPg;
1028 // the number of 'virtual' pages to be printed
1029 sal_Int32 nCntPage = (( nEPg - nSPg ) / ( 2 * nStep )) + 1;
1031 for ( sal_Int32 nPrintCount = 0; nSPg < nEPg &&
1032 nPrintCount < nCntPage; ++nPrintCount )
1034 pStPage = aVec[ nSPg ];
1035 const SwPageFrame* pNxtPage = nEPg < aVec.size() ? aVec[ nEPg ] : nullptr;
1037 short nRtlOfs = bPrintProspectRTL ? 1 : 0;
1038 if ( 0 == (( nSPg + nRtlOfs) & 1 ) ) // switch for odd number in LTR, even number in RTL
1040 const SwPageFrame* pTmp = pStPage;
1041 pStPage = pNxtPage;
1042 pNxtPage = pTmp;
1045 sal_Int32 nFirst = -1, nSecond = -1;
1046 for ( int nC = 0; nC < 2; ++nC )
1048 sal_Int32 nPage = -1;
1049 if ( pStPage )
1050 nPage = pStPage->GetPhyPageNum();
1051 if (nC == 0)
1052 nFirst = nPage;
1053 else
1054 nSecond = nPage;
1056 pStPage = pNxtPage;
1058 rPagePairs.emplace_back(nFirst, nSecond );
1060 nSPg = nSPg + nStep;
1061 nEPg = nEPg - nStep;
1063 OSL_ENSURE( size_t(nCntPage) == rPagePairs.size(), "size mismatch for number of page pairs" );
1065 // luckily prospect printing does not make use of post-its so far,
1066 // thus we are done here.
1069 /// @return the reference in the doc for the name
1070 const SwFormatRefMark* SwDoc::GetRefMark( const OUString& rName ) const
1072 for (const SfxPoolItem* pItem : GetAttrPool().GetItemSurrogates(RES_TXTATR_REFMARK))
1074 auto pFormatRef = dynamic_cast<const SwFormatRefMark*>(pItem);
1075 if(!pFormatRef)
1076 continue;
1078 const SwTextRefMark* pTextRef = pFormatRef->GetTextRefMark();
1079 if( pTextRef && &pTextRef->GetTextNode().GetNodes() == &GetNodes() &&
1080 rName == pFormatRef->GetRefName() )
1081 return pFormatRef;
1083 return nullptr;
1086 /// @return the RefMark per index - for Uno
1087 const SwFormatRefMark* SwDoc::GetRefMark( sal_uInt16 nIndex ) const
1089 const SwTextRefMark* pTextRef;
1090 const SwFormatRefMark* pRet = nullptr;
1092 sal_uInt32 nCount = 0;
1093 for (const SfxPoolItem* pItem : GetAttrPool().GetItemSurrogates(RES_TXTATR_REFMARK))
1095 auto pRefMark = dynamic_cast<const SwFormatRefMark*>(pItem);
1097 if( pRefMark &&
1098 nullptr != (pTextRef = pRefMark->GetTextRefMark()) &&
1099 &pTextRef->GetTextNode().GetNodes() == &GetNodes() )
1101 if(nCount == nIndex)
1103 pRet = pRefMark;
1104 break;
1106 nCount++;
1109 return pRet;
1112 /// @return the names of all set references in the Doc
1113 //JP 24.06.96: If the array pointer is 0, then just return whether a RefMark is set in the Doc
1114 // OS 25.06.96: From now on we always return the reference count
1115 sal_uInt16 SwDoc::GetRefMarks( std::vector<OUString>* pNames ) const
1117 const SwTextRefMark* pTextRef;
1119 sal_uInt16 nCount = 0;
1120 for (const SfxPoolItem* pItem : GetAttrPool().GetItemSurrogates(RES_TXTATR_REFMARK))
1122 auto pRefMark = dynamic_cast<const SwFormatRefMark*>(pItem);
1124 if( pRefMark &&
1125 nullptr != (pTextRef = pRefMark->GetTextRefMark()) &&
1126 &pTextRef->GetTextNode().GetNodes() == &GetNodes() )
1128 if( pNames )
1130 OUString aTmp(pRefMark->GetRefName());
1131 pNames->insert(pNames->begin() + nCount, aTmp);
1133 ++nCount;
1137 return nCount;
1140 static bool lcl_SpellAndGrammarAgain( const SwNodePtr& rpNd, void* pArgs )
1142 SwTextNode *pTextNode = rpNd->GetTextNode();
1143 bool bOnlyWrong = *static_cast<sal_Bool*>(pArgs);
1144 if( pTextNode )
1146 if( bOnlyWrong )
1148 if( pTextNode->GetWrong() &&
1149 pTextNode->GetWrong()->InvalidateWrong() )
1150 pTextNode->SetWrongDirty(SwTextNode::WrongState::TODO);
1151 if( pTextNode->GetGrammarCheck() &&
1152 pTextNode->GetGrammarCheck()->InvalidateWrong() )
1153 pTextNode->SetGrammarCheckDirty( true );
1155 else
1157 pTextNode->SetWrongDirty(SwTextNode::WrongState::TODO);
1158 if( pTextNode->GetWrong() )
1159 pTextNode->GetWrong()->SetInvalid( 0, COMPLETE_STRING );
1160 pTextNode->SetGrammarCheckDirty( true );
1161 if( pTextNode->GetGrammarCheck() )
1162 pTextNode->GetGrammarCheck()->SetInvalid( 0, COMPLETE_STRING );
1165 return true;
1168 static bool lcl_CheckSmartTagsAgain( const SwNodePtr& rpNd, void* )
1170 SwTextNode *pTextNode = rpNd->GetTextNode();
1171 if( pTextNode )
1173 pTextNode->SetSmartTagDirty( true );
1174 if( pTextNode->GetSmartTags() )
1176 pTextNode->SetSmartTags( nullptr );
1179 return true;
1183 * Re-trigger spelling in the idle handler.
1185 * @param bInvalid if <true>, the WrongLists in all nodes are invalidated
1186 * and the SpellInvalid flag is set on all pages.
1187 * @param bOnlyWrong controls whether only the areas with wrong words are
1188 * checked or the whole area.
1189 * @param bSmartTags ???
1191 void SwDoc::SpellItAgainSam( bool bInvalid, bool bOnlyWrong, bool bSmartTags )
1193 std::set<SwRootFrame*> aAllLayouts = GetAllLayouts();
1194 assert(getIDocumentLayoutAccess().GetCurrentLayout() && "SpellAgain: Where's my RootFrame?");
1195 if( bInvalid )
1197 for ( auto aLayout : aAllLayouts )
1199 aLayout->AllInvalidateSmartTagsOrSpelling(bSmartTags);
1200 aLayout->SetNeedGrammarCheck(true);
1202 if ( bSmartTags )
1203 GetNodes().ForEach( lcl_CheckSmartTagsAgain, &bOnlyWrong );
1204 GetNodes().ForEach( lcl_SpellAndGrammarAgain, &bOnlyWrong );
1207 for ( auto aLayout : aAllLayouts )
1208 aLayout->SetIdleFlags();
1211 void SwDoc::InvalidateAutoCompleteFlag()
1213 SwRootFrame* pTmpRoot = getIDocumentLayoutAccess().GetCurrentLayout();
1214 if( pTmpRoot )
1216 std::set<SwRootFrame*> aAllLayouts = GetAllLayouts();
1217 for( auto aLayout : aAllLayouts )
1218 aLayout->AllInvalidateAutoCompleteWords();
1219 for( sal_uLong nNd = 1, nCnt = GetNodes().Count(); nNd < nCnt; ++nNd )
1221 SwTextNode* pTextNode = GetNodes()[ nNd ]->GetTextNode();
1222 if ( pTextNode ) pTextNode->SetAutoCompleteWordDirty( true );
1225 for( auto aLayout : aAllLayouts )
1226 aLayout->SetIdleFlags();
1230 const SwFormatINetFormat* SwDoc::FindINetAttr( const OUString& rName ) const
1232 const SwTextINetFormat* pTextAttr;
1233 const SwTextNode* pTextNd;
1234 for (const SfxPoolItem* pItem : GetAttrPool().GetItemSurrogates(RES_TXTATR_INETFMT))
1236 auto pFormatItem = dynamic_cast<const SwFormatINetFormat*>(pItem);
1237 if( pFormatItem &&
1238 pFormatItem->GetName() == rName &&
1239 nullptr != ( pTextAttr = pFormatItem->GetTextINetFormat()) &&
1240 nullptr != ( pTextNd = pTextAttr->GetpTextNode() ) &&
1241 &pTextNd->GetNodes() == &GetNodes() )
1243 return pFormatItem;
1246 return nullptr;
1249 void SwDoc::Summary( SwDoc* pExtDoc, sal_uInt8 nLevel, sal_uInt8 nPara, bool bImpress )
1251 const SwOutlineNodes& rOutNds = GetNodes().GetOutLineNds();
1252 if( pExtDoc && !rOutNds.empty() )
1254 ::StartProgress( STR_STATSTR_SUMMARY, 0, rOutNds.size(), GetDocShell() );
1255 SwNodeIndex aEndOfDoc( pExtDoc->GetNodes().GetEndOfContent(), -1 );
1256 for( SwOutlineNodes::size_type i = 0; i < rOutNds.size(); ++i )
1258 ::SetProgressState( static_cast<long>(i), GetDocShell() );
1259 const sal_uLong nIndex = rOutNds[ i ]->GetIndex();
1261 const int nLvl = GetNodes()[ nIndex ]->GetTextNode()->GetAttrOutlineLevel()-1;
1262 if( nLvl > nLevel )
1263 continue;
1264 long nEndOfs = 1;
1265 sal_uInt8 nWish = nPara;
1266 sal_uLong nNextOutNd = i + 1 < rOutNds.size() ?
1267 rOutNds[ i + 1 ]->GetIndex() : GetNodes().Count();
1268 bool bKeep = false;
1269 while( ( nWish || bKeep ) && nIndex + nEndOfs < nNextOutNd &&
1270 GetNodes()[ nIndex + nEndOfs ]->IsTextNode() )
1272 SwTextNode* pTextNode = GetNodes()[ nIndex+nEndOfs ]->GetTextNode();
1273 if (pTextNode->GetText().getLength() && nWish)
1274 --nWish;
1275 bKeep = pTextNode->GetSwAttrSet().GetKeep().GetValue();
1276 ++nEndOfs;
1279 SwNodeRange aRange( *rOutNds[ i ], 0, *rOutNds[ i ], nEndOfs );
1280 GetNodes().Copy_( aRange, aEndOfDoc );
1282 const SwTextFormatColls *pColl = pExtDoc->GetTextFormatColls();
1283 for( SwTextFormatColls::size_type i = 0; i < pColl->size(); ++i )
1284 (*pColl)[ i ]->ResetFormatAttr( RES_PAGEDESC, RES_BREAK );
1285 SwNodeIndex aIndx( pExtDoc->GetNodes().GetEndOfExtras() );
1286 ++aEndOfDoc;
1287 while( aIndx < aEndOfDoc )
1289 SwNode *pNode;
1290 bool bDelete = false;
1291 if( (pNode = &aIndx.GetNode())->IsTextNode() )
1293 SwTextNode *pNd = pNode->GetTextNode();
1294 if( pNd->HasSwAttrSet() )
1295 pNd->ResetAttr( RES_PAGEDESC, RES_BREAK );
1296 if( bImpress )
1298 SwTextFormatColl* pMyColl = pNd->GetTextColl();
1300 const sal_uInt16 nHeadLine = static_cast<sal_uInt16>(
1301 !pMyColl->IsAssignedToListLevelOfOutlineStyle()
1302 ? RES_POOLCOLL_HEADLINE2
1303 : RES_POOLCOLL_HEADLINE1 );
1304 pMyColl = pExtDoc->getIDocumentStylePoolAccess().GetTextCollFromPool( nHeadLine );
1305 pNd->ChgFormatColl( pMyColl );
1307 if( !pNd->Len() &&
1308 pNd->StartOfSectionIndex()+2 < pNd->EndOfSectionIndex() )
1310 bDelete = true;
1311 pExtDoc->GetNodes().Delete( aIndx );
1314 if( !bDelete )
1315 ++aIndx;
1317 ::EndProgress( GetDocShell() );
1321 namespace
1323 void RemoveOrDeleteContents(SwTextNode* pTextNd, IDocumentContentOperations& xOperations)
1325 SwPaM aPam(*pTextNd, 0, *pTextNd, pTextNd->GetText().getLength());
1327 // Remove hidden paragraph or delete contents:
1328 // Delete contents if
1329 // 1. removing the paragraph would result in an empty section or
1330 // 2. if the paragraph is the last paragraph in the section and
1331 // there is no paragraph in front of the paragraph:
1332 if ((2 == pTextNd->EndOfSectionIndex() - pTextNd->StartOfSectionIndex())
1333 || (1 == pTextNd->EndOfSectionIndex() - pTextNd->GetIndex()
1334 && !pTextNd->GetNodes()[pTextNd->GetIndex() - 1]->GetTextNode()))
1336 xOperations.DeleteRange(aPam);
1338 else
1340 aPam.DeleteMark();
1341 xOperations.DelFullPara(aPam);
1344 // Returns if the data was actually modified
1345 bool HandleHidingField(SwFormatField& rFormatField, const SwNodes& rNodes,
1346 IDocumentContentOperations& xOperations)
1348 SwTextNode* pTextNd;
1349 if (rFormatField.GetTextField()
1350 && nullptr != (pTextNd = rFormatField.GetTextField()->GetpTextNode())
1351 && pTextNd->GetpSwpHints() && pTextNd->IsHiddenByParaField()
1352 && &pTextNd->GetNodes() == &rNodes)
1354 RemoveOrDeleteContents(pTextNd, xOperations);
1355 return true;
1357 return false;
1361 // The greater the returned value, the more weight has this field type on deciding the final
1362 // paragraph state
1363 int SwDoc::FieldCanHideParaWeight(SwFieldIds eFieldId) const
1365 switch (eFieldId)
1367 case SwFieldIds::HiddenPara:
1368 return 20;
1369 case SwFieldIds::Database:
1370 return GetDocumentSettingManager().get(DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA)
1371 ? 10
1372 : 0;
1373 default:
1374 return 0;
1378 bool SwDoc::FieldHidesPara(const SwField& rField) const
1380 switch (rField.GetTyp()->Which())
1382 case SwFieldIds::HiddenPara:
1383 return static_cast<const SwHiddenParaField&>(rField).IsHidden();
1384 case SwFieldIds::Database:
1385 return FieldCanHideParaWeight(SwFieldIds::Database)
1386 && rField.ExpandField(true, nullptr).isEmpty();
1387 default:
1388 return false;
1392 /// Remove the invisible content from the document e.g. hidden areas, hidden paragraphs
1393 // Returns if the data was actually modified
1394 bool SwDoc::RemoveInvisibleContent()
1396 bool bRet = false;
1397 GetIDocumentUndoRedo().StartUndo( SwUndoId::UI_DELETE_INVISIBLECNTNT, nullptr );
1400 class FieldTypeGuard : public SwClient
1402 public:
1403 explicit FieldTypeGuard(SwFieldType* pType)
1404 : SwClient(pType)
1407 const SwFieldType* get() const
1409 return static_cast<const SwFieldType*>(GetRegisteredIn());
1412 // Removing some nodes for one SwFieldIds::Database type might remove the type from
1413 // document's field types, invalidating iterators. So, we need to create own list of
1414 // matching types prior to processing them.
1415 std::vector<std::unique_ptr<FieldTypeGuard>> aHidingFieldTypes;
1416 for (std::unique_ptr<SwFieldType> const & pType : *getIDocumentFieldsAccess().GetFieldTypes())
1418 if (FieldCanHideParaWeight(pType->Which()))
1419 aHidingFieldTypes.push_back(std::make_unique<FieldTypeGuard>(pType.get()));
1421 for (const auto& pTypeGuard : aHidingFieldTypes)
1423 if (const SwFieldType* pType = pTypeGuard->get())
1425 SwIterator<SwFormatField, SwFieldType> aIter(*pType);
1426 for (SwFormatField* pFormatField = aIter.First(); pFormatField;
1427 pFormatField = aIter.Next())
1428 bRet |= HandleHidingField(*pFormatField, GetNodes(),
1429 getIDocumentContentOperations());
1434 // Remove any hidden paragraph (hidden text attribute)
1435 for( sal_uLong n = GetNodes().Count(); n; )
1437 SwTextNode* pTextNd = GetNodes()[ --n ]->GetTextNode();
1438 if ( pTextNd )
1440 bool bRemoved = false;
1441 if ( pTextNd->HasHiddenCharAttribute( true ) )
1443 bRemoved = true;
1444 bRet = true;
1446 if (2 == pTextNd->EndOfSectionIndex() - pTextNd->StartOfSectionIndex())
1448 SwFrameFormat *const pFormat = pTextNd->StartOfSectionNode()->GetFlyFormat();
1449 if (nullptr != pFormat)
1451 // remove hidden text frame
1452 getIDocumentLayoutAccess().DelLayoutFormat(pFormat);
1454 else
1456 // default, remove hidden paragraph
1457 RemoveOrDeleteContents(pTextNd, getIDocumentContentOperations());
1460 else
1462 // default, remove hidden paragraph
1463 RemoveOrDeleteContents(pTextNd, getIDocumentContentOperations());
1466 else if ( pTextNd->HasHiddenCharAttribute( false ) )
1468 bRemoved = true;
1469 bRet = true;
1470 SwScriptInfo::DeleteHiddenRanges( *pTextNd );
1473 // Footnotes/Frames may have been removed, therefore we have
1474 // to reset n:
1475 if ( bRemoved )
1477 // [n] has to be inside [0 .. GetNodes().Count()] range
1478 if (n > GetNodes().Count())
1479 n = GetNodes().Count();
1485 // Delete/empty all hidden areas
1486 o3tl::sorted_vector<SwSectionFormat*> aSectFormats;
1487 SwSectionFormats& rSectFormats = GetSections();
1489 for( SwSectionFormats::size_type n = rSectFormats.size(); n; )
1491 SwSectionFormat* pSectFormat = rSectFormats[ --n ];
1492 // don't add sections in Undo/Redo
1493 if( !pSectFormat->IsInNodesArr())
1494 continue;
1495 SwSection* pSect = pSectFormat->GetSection();
1496 if( pSect->CalcHiddenFlag() )
1498 SwSection* pParent = pSect, *pTmp;
1499 while( nullptr != (pTmp = pParent->GetParent() ))
1501 if( pTmp->IsHiddenFlag() )
1502 pSect = pTmp;
1503 pParent = pTmp;
1506 aSectFormats.insert( pSect->GetFormat() );
1508 if( !pSect->GetCondition().isEmpty() )
1510 SwSectionData aSectionData( *pSect );
1511 aSectionData.SetCondition( OUString() );
1512 aSectionData.SetHidden( false );
1513 UpdateSection( n, aSectionData );
1517 auto n = aSectFormats.size();
1519 if( 0 != n )
1521 while( n )
1523 SwSectionFormat* pSectFormat = aSectFormats[ --n ];
1524 SwSectionNode* pSectNd = pSectFormat->GetSectionNode();
1525 if( pSectNd )
1527 bRet = true;
1528 SwPaM aPam( *pSectNd );
1530 if( pSectNd->StartOfSectionNode()->StartOfSectionIndex() ==
1531 pSectNd->GetIndex() - 1 &&
1532 pSectNd->StartOfSectionNode()->EndOfSectionIndex() ==
1533 pSectNd->EndOfSectionIndex() + 1 )
1535 // only delete the content
1536 SwContentNode* pCNd = GetNodes().GoNext(
1537 &aPam.GetPoint()->nNode );
1538 aPam.GetPoint()->nContent.Assign( pCNd, 0 );
1539 aPam.SetMark();
1540 aPam.GetPoint()->nNode = *pSectNd->EndOfSectionNode();
1541 pCNd = SwNodes::GoPrevious(
1542 &aPam.GetPoint()->nNode );
1543 aPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() );
1545 getIDocumentContentOperations().DeleteRange( aPam );
1547 else
1549 // delete the whole section
1550 aPam.SetMark();
1551 aPam.GetPoint()->nNode = *pSectNd->EndOfSectionNode();
1552 getIDocumentContentOperations().DelFullPara( aPam );
1560 if( bRet )
1561 getIDocumentState().SetModified();
1562 GetIDocumentUndoRedo().EndUndo( SwUndoId::UI_DELETE_INVISIBLECNTNT, nullptr );
1563 return bRet;
1566 bool SwDoc::HasInvisibleContent() const
1568 if(SwIterator<SwFormatField,SwFieldType>(*getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::HiddenPara)).First())
1569 return true;
1571 // Search for any hidden paragraph (hidden text attribute)
1572 for( sal_uLong n = GetNodes().Count()-1; n; --n)
1574 SwTextNode* pTextNd = GetNodes()[ n ]->GetTextNode();
1575 if ( pTextNd &&
1576 ( pTextNd->HasHiddenCharAttribute( true ) || pTextNd->HasHiddenCharAttribute( false ) ) )
1577 return true;
1580 for(auto pSectFormat : GetSections())
1582 // don't add sections in Undo/Redo
1583 if( !pSectFormat->IsInNodesArr())
1584 continue;
1585 SwSection* pSect = pSectFormat->GetSection();
1586 if( pSect->IsHidden() )
1587 return true;
1589 return false;
1592 bool SwDoc::RestoreInvisibleContent()
1594 SwUndoId nLastUndoId(SwUndoId::EMPTY);
1595 if (GetIDocumentUndoRedo().GetLastUndoInfo(nullptr, & nLastUndoId)
1596 && (SwUndoId::UI_DELETE_INVISIBLECNTNT == nLastUndoId))
1598 GetIDocumentUndoRedo().Undo();
1599 GetIDocumentUndoRedo().ClearRedo();
1600 return true;
1602 return false;
1605 bool SwDoc::ConvertFieldsToText(SwRootFrame const& rLayout)
1607 bool bRet = false;
1608 getIDocumentFieldsAccess().LockExpFields();
1609 GetIDocumentUndoRedo().StartUndo( SwUndoId::UI_REPLACE, nullptr );
1611 const SwFieldTypes* pMyFieldTypes = getIDocumentFieldsAccess().GetFieldTypes();
1612 const SwFieldTypes::size_type nCount = pMyFieldTypes->size();
1613 //go backward, field types are removed
1614 for(SwFieldTypes::size_type nType = nCount; nType > 0; --nType)
1616 const SwFieldType *pCurType = (*pMyFieldTypes)[nType - 1].get();
1618 if ( SwFieldIds::Postit == pCurType->Which() )
1619 continue;
1621 SwIterator<SwFormatField,SwFieldType> aIter( *pCurType );
1622 std::vector<const SwFormatField*> aFieldFormats;
1623 for( SwFormatField* pCurFieldFormat = aIter.First(); pCurFieldFormat; pCurFieldFormat = aIter.Next() )
1624 aFieldFormats.push_back(pCurFieldFormat);
1626 for(const auto& rpFieldFormat : aFieldFormats)
1628 const SwTextField *pTextField = rpFieldFormat->GetTextField();
1629 // skip fields that are currently not in the document
1630 // e.g. fields in undo or redo array
1632 bool bSkip = !pTextField ||
1633 !pTextField->GetpTextNode()->GetNodes().IsDocNodes();
1635 if (!bSkip)
1637 bool bInHeaderFooter = IsInHeaderFooter(SwNodeIndex(*pTextField->GetpTextNode()));
1638 const SwFormatField& rFormatField = pTextField->GetFormatField();
1639 const SwField* pField = rFormatField.GetField();
1641 //#i55595# some fields have to be excluded in headers/footers
1642 SwFieldIds nWhich = pField->GetTyp()->Which();
1643 if(!bInHeaderFooter ||
1644 (nWhich != SwFieldIds::PageNumber &&
1645 nWhich != SwFieldIds::Chapter &&
1646 nWhich != SwFieldIds::GetExp&&
1647 nWhich != SwFieldIds::SetExp&&
1648 nWhich != SwFieldIds::Input&&
1649 nWhich != SwFieldIds::RefPageGet&&
1650 nWhich != SwFieldIds::RefPageSet))
1652 OUString sText = pField->ExpandField(true, &rLayout);
1654 // database fields should not convert their command into text
1655 if( SwFieldIds::Database == pCurType->Which() && !static_cast<const SwDBField*>(pField)->IsInitialized())
1656 sText.clear();
1658 SwPaM aInsertPam(*pTextField->GetpTextNode(), pTextField->GetStart());
1659 aInsertPam.SetMark();
1661 // go to the end of the field
1662 const SwTextField *pFieldAtEnd = sw::DocumentFieldsManager::GetTextFieldAtPos(*aInsertPam.End());
1663 if (pFieldAtEnd && pFieldAtEnd->Which() == RES_TXTATR_INPUTFIELD)
1665 SwPosition &rEndPos = *aInsertPam.GetPoint();
1666 rEndPos.nContent = SwCursorShell::EndOfInputFieldAtPos( *aInsertPam.End() );
1668 else
1670 aInsertPam.Move();
1673 // first insert the text after field to keep the field's attributes,
1674 // then delete the field
1675 if (!sText.isEmpty())
1677 // to keep the position after insert
1678 SwPaM aDelPam( *aInsertPam.GetMark(), *aInsertPam.GetPoint() );
1679 aDelPam.Move( fnMoveBackward );
1680 aInsertPam.DeleteMark();
1682 getIDocumentContentOperations().InsertString( aInsertPam, sText );
1684 aDelPam.Move();
1685 // finally remove the field
1686 getIDocumentContentOperations().DeleteAndJoin( aDelPam );
1688 else
1690 getIDocumentContentOperations().DeleteAndJoin( aInsertPam );
1693 bRet = true;
1699 if( bRet )
1700 getIDocumentState().SetModified();
1701 GetIDocumentUndoRedo().EndUndo( SwUndoId::UI_REPLACE, nullptr );
1702 getIDocumentFieldsAccess().UnlockExpFields();
1703 return bRet;
1707 bool SwDoc::IsInsTableFormatNum() const
1709 return SW_MOD()->IsInsTableFormatNum(GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE));
1712 bool SwDoc::IsInsTableChangeNumFormat() const
1714 return SW_MOD()->IsInsTableChangeNumFormat(GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE));
1717 bool SwDoc::IsInsTableAlignNum() const
1719 return SW_MOD()->IsInsTableAlignNum(GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE));
1722 bool SwDoc::IsSplitVerticalByDefault() const
1724 return SW_MOD()->IsSplitVerticalByDefault(GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE));
1727 void SwDoc::SetSplitVerticalByDefault(bool value)
1729 SW_MOD()->SetSplitVerticalByDefault(GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE), value);
1732 /// Set up the InsertDB as Undo table
1733 void SwDoc::AppendUndoForInsertFromDB( const SwPaM& rPam, bool bIsTable )
1735 if( bIsTable )
1737 const SwTableNode* pTableNd = rPam.GetPoint()->nNode.GetNode().FindTableNode();
1738 if( pTableNd )
1740 std::unique_ptr<SwUndoCpyTable> pUndo(new SwUndoCpyTable(this));
1741 pUndo->SetTableSttIdx( pTableNd->GetIndex() );
1742 GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) );
1745 else if( rPam.HasMark() )
1747 std::unique_ptr<SwUndoCpyDoc> pUndo(new SwUndoCpyDoc( rPam ));
1748 pUndo->SetInsertRange( rPam, false );
1749 GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) );
1753 void SwDoc::ChangeTOX(SwTOXBase & rTOX, const SwTOXBase & rNew)
1755 assert(dynamic_cast<const SwTOXBaseSection*>(&rTOX));
1756 SwTOXBaseSection& rTOXSect(static_cast<SwTOXBaseSection&>(rTOX));
1758 if (GetIDocumentUndoRedo().DoesUndo())
1760 GetIDocumentUndoRedo().AppendUndo(
1761 std::make_unique<SwUndoTOXChange>(this, rTOXSect, rNew));
1764 rTOX = rNew;
1766 // note: do not Update the ToX here - the caller will do it, with a ViewShell!
1769 OUString SwDoc::GetPaMDescr(const SwPaM & rPam)
1771 if (&rPam.GetNode() == &rPam.GetNode(false))
1773 SwTextNode * pTextNode = rPam.GetNode().GetTextNode();
1775 if (nullptr != pTextNode)
1777 const sal_Int32 nStart = rPam.Start()->nContent.GetIndex();
1778 const sal_Int32 nEnd = rPam.End()->nContent.GetIndex();
1780 return SwResId(STR_START_QUOTE)
1781 + ShortenString(pTextNode->GetText().copy(nStart, nEnd - nStart),
1782 nUndoStringLength,
1783 SwResId(STR_LDOTS))
1784 + SwResId(STR_END_QUOTE);
1787 else
1789 return SwResId(STR_PARAGRAPHS);
1792 return OUString("??");
1795 bool SwDoc::ContainsHiddenChars() const
1797 for( sal_uLong n = GetNodes().Count(); n; )
1799 SwNode* pNd = GetNodes()[ --n ];
1800 if ( pNd->IsTextNode() && pNd->GetTextNode()->HasHiddenCharAttribute( false ) )
1801 return true;
1804 return false;
1807 std::shared_ptr<SwUnoCursor> SwDoc::CreateUnoCursor( const SwPosition& rPos, bool bTableCursor )
1809 std::shared_ptr<SwUnoCursor> pNew;
1810 if( bTableCursor )
1811 pNew = std::make_shared<SwUnoTableCursor>(rPos);
1812 else
1813 pNew = std::make_shared<SwUnoCursor>(rPos);
1815 mvUnoCursorTable.push_back( pNew );
1816 return pNew;
1819 void SwDoc::ChkCondColls()
1821 for (SwTextFormatColls::size_type n = 0; n < mpTextFormatCollTable->size(); ++n)
1823 SwTextFormatColl *pColl = (*mpTextFormatCollTable)[n];
1824 if (RES_CONDTXTFMTCOLL == pColl->Which())
1825 pColl->CallSwClientNotify( SwAttrHint() );
1829 uno::Reference< script::vba::XVBAEventProcessor > const &
1830 SwDoc::GetVbaEventProcessor()
1832 #if HAVE_FEATURE_SCRIPTING
1833 if( !mxVbaEvents.is() && mpDocShell && ooo::vba::isAlienWordDoc( *mpDocShell ) )
1837 uno::Reference< frame::XModel > xModel( mpDocShell->GetModel(), uno::UNO_SET_THROW );
1838 uno::Sequence< uno::Any > aArgs(1);
1839 aArgs[0] <<= xModel;
1840 mxVbaEvents.set( ooo::vba::createVBAUnoAPIServiceWithArgs( mpDocShell, "com.sun.star.script.vba.VBATextEventProcessor" , aArgs ), uno::UNO_QUERY_THROW );
1842 catch( uno::Exception& )
1846 #endif
1847 return mxVbaEvents;
1850 void SwDoc::SetMissingDictionaries( bool bIsMissing )
1852 if (!bIsMissing)
1853 meDictionaryMissing = MissingDictionary::False;
1854 else if (meDictionaryMissing == MissingDictionary::Undefined)
1855 meDictionaryMissing = MissingDictionary::True;
1859 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */