1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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>
44 #include <hintids.hxx>
46 #include <comphelper/random.hxx>
47 #include <tools/multisel.hxx>
48 #include <rtl/ustring.hxx>
49 #include <svl/poolitem.hxx>
50 #include <unotools/syslocale.hxx>
51 #include <editeng/keepitem.hxx>
52 #include <editeng/formatbreakitem.hxx>
53 #include <editeng/pbinitem.hxx>
54 #include <unotools/localedatawrapper.hxx>
56 #include <officecfg/Office/Writer.hxx>
58 #include <swatrset.hxx>
59 #include <swmodule.hxx>
60 #include <fmtrfmrk.hxx>
61 #include <fmtinfmt.hxx>
65 #include <txtinet.hxx>
66 #include <txtrfmrk.hxx>
68 #include <pagefrm.hxx>
69 #include <rootfrm.hxx>
74 #include <UndoAttribute.hxx>
75 #include <UndoCore.hxx>
76 #include <UndoTable.hxx>
77 #include <pagedesc.hxx>
79 #include <poolfmt.hxx>
80 #include <SwGrammarMarkUp.hxx>
81 #include <scriptinfo.hxx>
84 #include <printdata.hxx>
85 #include <strings.hrc>
86 #include <SwUndoTOXChange.hxx>
87 #include <unocrsr.hxx>
89 #include <docufld.hxx>
91 #include <shellres.hxx>
93 #include <attrhint.hxx>
97 #include <o3tl/string_view.hxx>
98 #include <osl/diagnose.h>
99 #include <osl/interlck.h>
100 #include <vbahelper/vbaaccesshelper.hxx>
101 #include <editeng/langitem.hxx>
102 #include <calbck.hxx>
103 #include <crsrsh.hxx>
105 /* @@@MAINTAINABILITY-HORROR@@@
106 Probably unwanted dependency on SwDocShell
110 #include <com/sun/star/text/XTextRange.hpp>
111 #include <editeng/unoprnms.hxx>
112 #include <unotextrange.hxx>
113 #include <unoprnms.hxx>
114 #include <unomap.hxx>
116 using namespace ::com::sun::star
;
118 sal_Int32
SwDoc::acquire()
120 assert(mReferenceCount
>= 0);
121 return osl_atomic_increment(&mReferenceCount
);
124 sal_Int32
SwDoc::release()
126 assert(mReferenceCount
>= 1);
127 auto x
= osl_atomic_decrement(&mReferenceCount
);
133 sal_Int32
SwDoc::getReferenceCount() const
135 assert(mReferenceCount
>= 0);
136 return mReferenceCount
;
139 ::sw::MetaFieldManager
& SwDoc::GetMetaFieldManager()
141 return *m_pMetaFieldManager
;
144 ::SwContentControlManager
& SwDoc::GetContentControlManager()
146 return *m_pContentControlManager
;
149 ::sw::UndoManager
& SwDoc::GetUndoManager()
151 return *m_pUndoManager
;
154 ::sw::UndoManager
const & SwDoc::GetUndoManager() const
156 return *m_pUndoManager
;
160 IDocumentUndoRedo
& SwDoc::GetIDocumentUndoRedo()
162 return *m_pUndoManager
;
165 IDocumentUndoRedo
const & SwDoc::GetIDocumentUndoRedo() const
167 return *m_pUndoManager
;
170 /* IDocumentDrawModelAccess */
171 IDocumentDrawModelAccess
const & SwDoc::getIDocumentDrawModelAccess() const
173 return GetDocumentDrawModelManager();
176 IDocumentDrawModelAccess
& SwDoc::getIDocumentDrawModelAccess()
178 return GetDocumentDrawModelManager();
181 ::sw::DocumentDrawModelManager
const & SwDoc::GetDocumentDrawModelManager() const
183 return *m_pDocumentDrawModelManager
;
186 ::sw::DocumentDrawModelManager
& SwDoc::GetDocumentDrawModelManager()
188 return *m_pDocumentDrawModelManager
;
191 /* IDocumentSettingAccess */
192 IDocumentSettingAccess
const & SwDoc::getIDocumentSettingAccess() const
194 return GetDocumentSettingManager();
197 IDocumentSettingAccess
& SwDoc::getIDocumentSettingAccess()
199 return GetDocumentSettingManager();
202 ::sw::DocumentSettingManager
& SwDoc::GetDocumentSettingManager()
204 return *m_pDocumentSettingManager
;
207 ::sw::DocumentSettingManager
const & SwDoc::GetDocumentSettingManager() const
209 return *m_pDocumentSettingManager
;
212 sal_uInt32
SwDoc::getRsid() const
217 void SwDoc::setRsid( sal_uInt32 nVal
)
219 static bool bHack
= (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr);
221 sal_uInt32 nIncrease
= 0;
224 // Increase the rsid with a random number smaller than 2^17. This way we
225 // expect to be able to edit a document 2^12 times before rsid overflows.
226 // start from 1 to ensure the new rsid is not the same
227 nIncrease
= comphelper::rng::uniform_uint_distribution(1, (1 << 17) - 1);
229 mnRsid
= nVal
+ nIncrease
;
232 sal_uInt32
SwDoc::getRsidRoot() const
237 void SwDoc::setRsidRoot( sal_uInt32 nVal
)
242 /* IDocumentChartDataProviderAccess */
243 IDocumentChartDataProviderAccess
const & SwDoc::getIDocumentChartDataProviderAccess() const
245 return *m_pDocumentChartDataProviderManager
;
248 IDocumentChartDataProviderAccess
& SwDoc::getIDocumentChartDataProviderAccess()
250 return *m_pDocumentChartDataProviderManager
;
253 // IDocumentDeviceAccess
254 IDocumentDeviceAccess
const & SwDoc::getIDocumentDeviceAccess() const
256 return *m_pDeviceAccess
;
259 IDocumentDeviceAccess
& SwDoc::getIDocumentDeviceAccess()
261 return *m_pDeviceAccess
;
264 //IDocumentTimerAccess
265 IDocumentTimerAccess
const & SwDoc::getIDocumentTimerAccess() const
267 return *m_pDocumentTimerManager
;
270 IDocumentTimerAccess
& SwDoc::getIDocumentTimerAccess()
272 return *m_pDocumentTimerManager
;
275 // IDocumentLinksAdministration
276 IDocumentLinksAdministration
const & SwDoc::getIDocumentLinksAdministration() const
278 return *m_pDocumentLinksAdministrationManager
;
281 IDocumentLinksAdministration
& SwDoc::getIDocumentLinksAdministration()
283 return *m_pDocumentLinksAdministrationManager
;
286 ::sw::DocumentLinksAdministrationManager
const & SwDoc::GetDocumentLinksAdministrationManager() const
288 return *m_pDocumentLinksAdministrationManager
;
291 ::sw::DocumentLinksAdministrationManager
& SwDoc::GetDocumentLinksAdministrationManager()
293 return *m_pDocumentLinksAdministrationManager
;
297 IDocumentListItems
const & SwDoc::getIDocumentListItems() const
299 return *m_pDocumentListItemsManager
;
303 IDocumentListItems
& SwDoc::getIDocumentListItems()
305 return *m_pDocumentListItemsManager
;
308 //IDocumentListsAccess
309 IDocumentListsAccess
const & SwDoc::getIDocumentListsAccess() const
311 return *m_pDocumentListsManager
;
314 IDocumentListsAccess
& SwDoc::getIDocumentListsAccess()
316 return *m_pDocumentListsManager
;
319 //IDocumentOutlinesNodes
320 IDocumentOutlineNodes
const & SwDoc::getIDocumentOutlineNodes() const
322 return *m_pDocumentOutlineNodesManager
;
325 IDocumentOutlineNodes
& SwDoc::getIDocumentOutlineNodes()
327 return *m_pDocumentOutlineNodesManager
;
330 //IDocumentContentOperations
331 IDocumentContentOperations
const & SwDoc::getIDocumentContentOperations() const
333 return *m_pDocumentContentOperationsManager
;
336 IDocumentContentOperations
& SwDoc::getIDocumentContentOperations()
338 return *m_pDocumentContentOperationsManager
;
341 ::sw::DocumentContentOperationsManager
const & SwDoc::GetDocumentContentOperationsManager() const
343 return *m_pDocumentContentOperationsManager
;
345 ::sw::DocumentContentOperationsManager
& SwDoc::GetDocumentContentOperationsManager()
347 return *m_pDocumentContentOperationsManager
;
350 //IDocumentRedlineAccess
351 IDocumentRedlineAccess
const & SwDoc::getIDocumentRedlineAccess() const
353 return *m_pDocumentRedlineManager
;
356 IDocumentRedlineAccess
& SwDoc::getIDocumentRedlineAccess()
358 return *m_pDocumentRedlineManager
;
361 ::sw::DocumentRedlineManager
const & SwDoc::GetDocumentRedlineManager() const
363 return *m_pDocumentRedlineManager
;
366 ::sw::DocumentRedlineManager
& SwDoc::GetDocumentRedlineManager()
368 return *m_pDocumentRedlineManager
;
371 //IDocumentFieldsAccess
373 IDocumentFieldsAccess
const & SwDoc::getIDocumentFieldsAccess() const
375 return *m_pDocumentFieldsManager
;
378 IDocumentFieldsAccess
& SwDoc::getIDocumentFieldsAccess()
380 return *m_pDocumentFieldsManager
;
383 ::sw::DocumentFieldsManager
& SwDoc::GetDocumentFieldsManager()
385 return *m_pDocumentFieldsManager
;
388 //IDocumentStatistics
389 IDocumentStatistics
const & SwDoc::getIDocumentStatistics() const
391 return *m_pDocumentStatisticsManager
;
394 IDocumentStatistics
& SwDoc::getIDocumentStatistics()
396 return *m_pDocumentStatisticsManager
;
399 ::sw::DocumentStatisticsManager
const & SwDoc::GetDocumentStatisticsManager() const
401 return *m_pDocumentStatisticsManager
;
404 ::sw::DocumentStatisticsManager
& SwDoc::GetDocumentStatisticsManager()
406 return *m_pDocumentStatisticsManager
;
410 IDocumentState
const & SwDoc::getIDocumentState() const
412 return *m_pDocumentStateManager
;
415 IDocumentState
& SwDoc::getIDocumentState()
417 return *m_pDocumentStateManager
;
420 //IDocumentLayoutAccess
421 IDocumentLayoutAccess
const & SwDoc::getIDocumentLayoutAccess() const
423 return *m_pDocumentLayoutManager
;
426 IDocumentLayoutAccess
& SwDoc::getIDocumentLayoutAccess()
428 return *m_pDocumentLayoutManager
;
431 ::sw::DocumentLayoutManager
const & SwDoc::GetDocumentLayoutManager() const
433 return *m_pDocumentLayoutManager
;
436 ::sw::DocumentLayoutManager
& SwDoc::GetDocumentLayoutManager()
438 return *m_pDocumentLayoutManager
;
441 //IDocumentStylePoolAccess
442 IDocumentStylePoolAccess
const & SwDoc::getIDocumentStylePoolAccess() const
444 return *m_pDocumentStylePoolManager
;
447 IDocumentStylePoolAccess
& SwDoc::getIDocumentStylePoolAccess()
449 return *m_pDocumentStylePoolManager
;
452 //IDocumentExternalData
453 IDocumentExternalData
const & SwDoc::getIDocumentExternalData() const
455 return *m_pDocumentExternalDataManager
;
458 IDocumentExternalData
& SwDoc::getIDocumentExternalData()
460 return *m_pDocumentExternalDataManager
;
463 /* Implementations the next Interface here */
466 * Document editing (Doc-SS) to fill the document
467 * by the RTF parser and for the EditShell.
469 void SwDoc::ChgDBData(const SwDBData
& rNewData
)
471 if( rNewData
!= maDBData
)
474 getIDocumentState().SetModified();
476 m_pDBManager
->CommitLastRegistrations();
478 getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::DatabaseName
)->UpdateFields();
483 struct PostItField_
: public SetGetExpField
485 PostItField_( const SwNode
& rNd
, const SwTextField
* pField
)
486 : SetGetExpField( rNd
, pField
, std::nullopt
) {}
488 sal_uInt16
GetPageNo( const StringRangeEnumerator
&rRangeEnum
,
489 const o3tl::sorted_vector
< sal_Int32
> &rPossiblePages
,
490 sal_uInt16
& rVirtPgNo
, sal_Int32
& rLineNo
);
492 const SwPostItField
* GetPostIt() const
494 return static_cast<const SwPostItField
*>( GetTextField()->GetFormatField().GetField() );
500 sal_uInt16
PostItField_::GetPageNo(
501 const StringRangeEnumerator
&rRangeEnum
,
502 const o3tl::sorted_vector
< sal_Int32
> &rPossiblePages
,
503 /* out */ sal_uInt16
& rVirtPgNo
, /* out */ sal_Int32
& rLineNo
)
505 //Problem: If a PostItField is contained in a Node that is represented
506 //by more than one layout instance,
507 //we have to decide whether it should be printed once or n-times.
508 //Probably only once. For the page number we don't select a random one,
509 //but the PostIt's first occurrence in the selected area.
511 SwIterator
<SwTextFrame
, SwTextNode
, sw::IteratorMode::UnwrapMulti
> aIter(GetTextField()->GetTextNode());
512 for( SwTextFrame
* pFrame
= aIter
.First(); pFrame
; pFrame
= aIter
.Next() )
514 TextFrameIndex
const nPos
= pFrame
->MapModelToView(
515 &GetTextField()->GetTextNode(), GetContent());
516 if( pFrame
->GetOffset() > nPos
||
517 (pFrame
->HasFollow() && pFrame
->GetFollow()->GetOffset() <= nPos
) )
519 sal_uInt16 nPgNo
= pFrame
->GetPhyPageNum();
520 if( rRangeEnum
.hasValue( nPgNo
, &rPossiblePages
))
522 rLineNo
= o3tl::narrowing
<sal_Int32
>(pFrame
->GetLineCount( nPos
) +
523 pFrame
->GetAllLines() - pFrame
->GetThisLines());
524 rVirtPgNo
= pFrame
->GetVirtPageNum();
531 bool sw_GetPostIts(const IDocumentFieldsAccess
& rIDFA
, SetGetExpFields
* pSrtLst
)
533 SwFieldType
* pFieldType
= rIDFA
.GetSysFieldType(SwFieldIds::Postit
);
536 std::vector
<SwFormatField
*> vFields
;
537 pFieldType
->GatherFields(vFields
);
539 for(auto pField
: vFields
)
541 auto pTextField
= pField
->GetTextField();
542 std::unique_ptr
<PostItField_
> pNew(new PostItField_(pTextField
->GetTextNode(), pTextField
));
543 pSrtLst
->insert(std::move(pNew
));
546 return vFields
.size()>0;
549 static void lcl_FormatPostIt(
550 IDocumentContentOperations
* pIDCO
,
552 const SwPostItField
* pField
,
553 bool bNewPage
, bool bIsFirstPostIt
,
554 sal_uInt16 nPageNo
, sal_Int32 nLineNo
)
556 static char const sTmp
[] = " : ";
558 assert(SwViewShell::GetShellRes());
562 pIDCO
->InsertPoolItem( aPam
, SvxFormatBreakItem( SvxBreak::PageAfter
, RES_BREAK
) );
563 pIDCO
->SplitNode( *aPam
.GetPoint(), false );
565 else if (!bIsFirstPostIt
)
567 // add an empty line between different notes
568 pIDCO
->SplitNode( *aPam
.GetPoint(), false );
569 pIDCO
->SplitNode( *aPam
.GetPoint(), false );
572 OUString aStr
= SwViewShell::GetShellRes()->aPostItPage
+
574 OUString::number( nPageNo
) +
578 aStr
+= SwViewShell::GetShellRes()->aPostItLine
+
580 OUString::number( nLineNo
) +
583 SvtSysLocale aSysLocale
;
584 aStr
+= SwViewShell::GetShellRes()->aPostItAuthor
+
585 sTmp
+ pField
->GetPar1() + " " +
586 /*(LocaleDataWrapper&)*/aSysLocale
.GetLocaleData().getDate( pField
->GetDate() );
587 if(pField
->GetResolved())
588 aStr
+= " " + SwResId(STR_RESOLVED
);
589 pIDCO
->InsertString( aPam
, aStr
);
591 pIDCO
->SplitNode( *aPam
.GetPoint(), false );
592 aStr
= pField
->GetPar2();
594 // Throw out all CR in Windows
595 aStr
= aStr
.replaceAll("\r", "");
597 pIDCO
->InsertString( aPam
, aStr
);
600 /// provide the paper tray to use according to the page style in use,
601 /// but do that only if the respective item is NOT just the default item
602 static sal_Int32
lcl_GetPaperBin( const SwPageFrame
*pStartFrame
)
606 const SwFrameFormat
&rFormat
= pStartFrame
->GetPageDesc()->GetMaster();
607 const SfxPoolItem
*pItem
= nullptr;
608 SfxItemState eState
= rFormat
.GetItemState( RES_PAPER_BIN
, false, &pItem
);
609 const SvxPaperBinItem
*pPaperBinItem
= dynamic_cast< const SvxPaperBinItem
* >(pItem
);
610 if (eState
> SfxItemState::DEFAULT
&& pPaperBinItem
)
611 nRes
= pPaperBinItem
->GetValue();
618 // tdf#:114663 Translates a range string from user input (with page numbering possibly not
619 // taking blank pages into account) to equivalent string which references physical page numbers.
620 // rUIPages2PhyPagesMap must contain a contiguous sequence of UI page numbers
621 OUString
UIPages2PhyPages(const OUString
& rUIPageRange
, const std::map
< sal_Int32
, sal_Int32
>& rUIPages2PhyPagesMap
)
623 if (rUIPages2PhyPagesMap
.empty())
625 auto iMin
= rUIPages2PhyPagesMap
.begin();
626 const sal_Int32 nUIPageMin
= iMin
->first
, nPhyPageMin
= iMin
->second
;
627 auto iMax
= rUIPages2PhyPagesMap
.rbegin();
628 const sal_Int32 nUIPageMax
= iMax
->first
, nPhyPageMax
= iMax
->second
;
629 OUStringBuffer
aOut(rUIPageRange
.getLength());
630 OUStringBuffer
aNumber(16);
631 const sal_Unicode
* pInput
= rUIPageRange
.getStr();
634 while (*pInput
>= '0' && *pInput
<= '9')
635 aNumber
.append(*pInput
++);
636 if (!aNumber
.isEmpty())
638 sal_Int32 nNumber
= o3tl::toInt32(aNumber
);
639 aNumber
.setLength(0);
640 if (nNumber
< nUIPageMin
)
641 nNumber
= nPhyPageMin
-1;
642 else if (nNumber
> nUIPageMax
)
643 nNumber
= nPhyPageMax
+1;
645 nNumber
= rUIPages2PhyPagesMap
.at(nNumber
);
646 aOut
.append(nNumber
);
649 while (*pInput
&& (*pInput
< '0' || *pInput
> '9'))
650 aOut
.append(*pInput
++);
653 return aOut
.makeStringAndClear();
657 // tdf#52316 remove blank pages from page count and actual page number
658 void SwDoc::CalculateNonBlankPages(
659 const SwRootFrame
& rLayout
,
660 sal_uInt16
& nDocPageCount
,
661 sal_uInt16
& nActualPage
)
663 sal_uInt16 nDocPageCountWithBlank
= nDocPageCount
;
664 sal_uInt16 nActualPageWithBlank
= nActualPage
;
665 sal_uInt16 nPageNum
= 1;
666 const SwPageFrame
*pStPage
= dynamic_cast<const SwPageFrame
*>( rLayout
.Lower() );
667 while (pStPage
&& nPageNum
<= nDocPageCountWithBlank
)
669 if ( pStPage
->getFrameArea().Height() == 0 )
672 if (nPageNum
<= nActualPageWithBlank
)
676 pStPage
= static_cast<const SwPageFrame
*>(pStPage
->GetNext());
680 void SwDoc::CalculatePagesForPrinting(
681 const SwRootFrame
& rLayout
,
682 /* out */ SwRenderData
&rData
,
683 const SwPrintUIOptions
&rOptions
,
685 sal_Int32 nDocPageCount
)
687 const sal_Int64 nContent
= rOptions
.getIntValue( "PrintContent", 0 );
688 const bool bPrintSelection
= nContent
== 2;
690 // properties to take into account when calculating the set of pages
691 // (PDF export UI does not allow for selecting left or right pages only)
692 bool bPrintLeftPages
= bIsPDFExport
|| rOptions
.IsPrintLeftPages();
693 bool bPrintRightPages
= bIsPDFExport
|| rOptions
.IsPrintRightPages();
694 // #i103700# printing selections should not allow for automatic inserting empty pages
695 bool bPrintEmptyPages
= !bPrintSelection
&& rOptions
.IsPrintEmptyPages( bIsPDFExport
);
697 std::map
< sal_Int32
, sal_Int32
> &rPrinterPaperTrays
= rData
.GetPrinterPaperTrays();
698 o3tl::sorted_vector
< sal_Int32
> &rValidPages
= rData
.GetValidPagesSet();
699 // Map page numbers from user input (possibly ignoring blanks) to physical page numbers
700 std::map
< sal_Int32
, sal_Int32
> aUIPages2PhyPagesMap
;
703 sal_Int32 nPageNum
= 1, nUIPageNum
= 1;
704 const SwPageFrame
*pStPage
= dynamic_cast<const SwPageFrame
*>( rLayout
.Lower() );
705 while (pStPage
&& nPageNum
<= nDocPageCount
)
707 const bool bNonEmptyPage
= pStPage
->getFrameArea().Height() != 0;
708 const bool bPrintThisPage
=
709 ( (bPrintRightPages
&& pStPage
->OnRightPage()) ||
710 (bPrintLeftPages
&& !pStPage
->OnRightPage()) ) &&
711 ( bPrintEmptyPages
|| bNonEmptyPage
);
715 rValidPages
.insert( nPageNum
);
716 rPrinterPaperTrays
[ nPageNum
] = lcl_GetPaperBin( pStPage
);
719 if ( bPrintEmptyPages
|| bNonEmptyPage
)
721 aUIPages2PhyPagesMap
[nUIPageNum
++] = nPageNum
;
724 pStPage
= static_cast<const SwPageFrame
*>(pStPage
->GetNext());
727 // now that we have identified the valid pages for printing according
728 // to the print settings we need to get the PageRange to use and
729 // use both results to get the actual pages to be printed
730 // (post-it settings need to be taken into account later on!)
732 // get PageRange value to use
734 // #i116085# - adjusting fix for i113919
738 // 0 -> print all pages (default if aPageRange is empty)
739 // 1 -> print range according to PageRange
740 // 2 -> print selection
742 aPageRange
= rOptions
.getStringValue( "PageRange" );
746 // note that printing selections is actually implemented by copying
747 // the selection to a new temporary document and printing all of that one.
748 // Thus for Writer "PrintContent" must never be 2.
749 // See SwXTextDocument::GetRenderDoc for evaluating if a selection is to be
750 // printed and for creating the temporary document.
755 if (aPageRange
.isEmpty()) // empty string -> print all
757 // set page range to print to 'all pages'
758 aPageRange
= OUString::number( 1 ) + "-" + OUString::number( nDocPageCount
);
762 // Convert page numbers from user input to physical page numbers
763 aPageRange
= UIPages2PhyPages(aPageRange
, aUIPages2PhyPagesMap
);
765 rData
.SetPageRange( aPageRange
);
767 // get vector of pages to print according to PageRange and valid pages set from above
768 // (result may be an empty vector, for example if the range string is not correct)
769 // If excluding empty pages, allow range to specify range of printable pages
770 StringRangeEnumerator::getRangesFromString( aPageRange
, rData
.GetPagesToPrint(),
771 1, nDocPageCount
, 0, &rData
.GetValidPagesSet() );
774 void SwDoc::UpdatePagesForPrintingWithPostItData(
775 /* out */ SwRenderData
&rData
,
776 const SwPrintUIOptions
&rOptions
,
777 sal_Int32 nDocPageCount
)
780 SwPostItMode nPostItMode
= static_cast<SwPostItMode
>( rOptions
.getIntValue( "PrintAnnotationMode", 0 ) );
781 assert((nPostItMode
== SwPostItMode::NONE
|| rData
.HasPostItData())
782 && "print post-its without post-it data?");
783 const SetGetExpFields::size_type nPostItCount
=
784 rData
.HasPostItData() ? rData
.m_pPostItFields
->size() : 0;
785 if (nPostItMode
== SwPostItMode::NONE
|| nPostItCount
<= 0)
788 CurrShell
aCurr( rData
.m_pPostItShell
.get() );
790 // clear document and move to end of it
791 SwDoc
& rPostItDoc(*rData
.m_pPostItShell
->GetDoc());
792 SwPaM
aPam(rPostItDoc
.GetNodes().GetEndOfContent());
793 aPam
.Move( fnMoveBackward
, GoInDoc
);
795 aPam
.Move( fnMoveForward
, GoInDoc
);
796 rPostItDoc
.getIDocumentContentOperations().DeleteRange( aPam
);
798 const StringRangeEnumerator
aRangeEnum( rData
.GetPageRange(), 1, nDocPageCount
, 0 );
800 // For mode SwPostItMode::EndPage:
801 // maps a physical page number to the page number in post-it document that holds
802 // the first post-it for that physical page . Needed to relate the correct start frames
803 // from the post-it doc to the physical page of the document
804 std::map
< sal_Int32
, sal_Int32
> aPostItLastStartPageNum
;
806 // add all post-its on valid pages within the page range to the
807 // temporary post-it document.
808 // Since the array of post-it fields is sorted by page and line number we will
809 // already get them in the correct order
810 sal_uInt16 nVirtPg
= 0, nLastPageNum
= 0, nPhyPageNum
= 0;
811 sal_Int32 nLineNo
= 0;
812 bool bIsFirstPostIt
= true;
813 for (SetGetExpFields::size_type i
= 0; i
< nPostItCount
; ++i
)
815 PostItField_
& rPostIt
= static_cast<PostItField_
&>(*(*rData
.m_pPostItFields
)[ i
]);
816 nLastPageNum
= nPhyPageNum
;
817 nPhyPageNum
= rPostIt
.GetPageNo(
818 aRangeEnum
, rData
.GetValidPagesSet(), nVirtPg
, nLineNo
);
821 // need to insert a page break?
822 // In SwPostItMode::EndPage mode for each document page the following
823 // post-it page needs to start on a new page
824 const bool bNewPage
= nPostItMode
== SwPostItMode::EndPage
&&
825 !bIsFirstPostIt
&& nPhyPageNum
!= nLastPageNum
;
827 lcl_FormatPostIt( &rData
.m_pPostItShell
->GetDoc()->getIDocumentContentOperations(), aPam
,
828 rPostIt
.GetPostIt(), bNewPage
, bIsFirstPostIt
, nVirtPg
, nLineNo
);
829 bIsFirstPostIt
= false;
831 if (nPostItMode
== SwPostItMode::EndPage
)
833 // get the correct number of current pages for the post-it document
834 rData
.m_pPostItShell
->CalcLayout();
835 const sal_Int32 nPages
= rData
.m_pPostItShell
->GetPageCount();
836 aPostItLastStartPageNum
[ nPhyPageNum
] = nPages
;
841 // format post-it doc to get correct number of pages
842 rData
.m_pPostItShell
->CalcLayout();
844 SwRootFrame
* pPostItRoot
= rData
.m_pPostItShell
->GetLayout();
845 //tdf#103313 print dialog maxes out cpu as Idles never get to
846 //complete this postitshell's desire to complete formatting
847 pPostItRoot
->ResetIdleFormat();
849 const sal_Int32 nPostItDocPageCount
= rData
.m_pPostItShell
->GetPageCount();
851 if (nPostItMode
== SwPostItMode::Only
|| nPostItMode
== SwPostItMode::EndDoc
)
853 // now add those post-it pages to the vector of pages to print
854 // or replace them if only post-its should be printed
856 if (nPostItMode
== SwPostItMode::Only
)
858 // no document page to be printed
859 rData
.GetPagesToPrint().clear();
862 // now we just need to add the post-it pages to be printed to the
863 // end of the vector of pages to print
864 sal_Int32 nPageNum
= 0;
865 const SwPageFrame
* pPageFrame
= static_cast<SwPageFrame
*>(pPostItRoot
->Lower());
866 while( pPageFrame
&& nPageNum
< nPostItDocPageCount
)
869 // negative page number indicates page is from the post-it doc
870 rData
.GetPagesToPrint().push_back( -nPageNum
);
871 pPageFrame
= static_cast<const SwPageFrame
*>(pPageFrame
->GetNext());
873 OSL_ENSURE( nPageNum
== nPostItDocPageCount
, "unexpected number of pages" );
875 else if (nPostItMode
== SwPostItMode::EndPage
)
877 // the next step is to find all the pages from the post-it
878 // document that should be printed for a given physical page
881 std::vector
< sal_Int32
> aTmpPagesToPrint
;
882 sal_Int32
nLastPostItPage(0);
883 const size_t nNum
= rData
.GetPagesToPrint().size();
884 for (size_t i
= 0 ; i
< nNum
; ++i
)
886 // add the physical page to print from the document
887 const sal_Int32 nPhysPage
= rData
.GetPagesToPrint()[i
];
888 aTmpPagesToPrint
.push_back( nPhysPage
);
890 // add the post-it document pages to print, i.e those
891 // post-it pages that have the data for the above physical page
892 std::map
<sal_Int32
, sal_Int32
>::const_iterator
const iter(
893 aPostItLastStartPageNum
.find(nPhysPage
));
894 if (iter
!= aPostItLastStartPageNum
.end())
896 for (sal_Int32 j
= nLastPostItPage
+ 1;
897 j
<= iter
->second
; ++j
)
899 // negative page number indicates page is from the
900 aTmpPagesToPrint
.push_back(-j
); // post-it document
902 nLastPostItPage
= iter
->second
;
906 // finally we need to assign those vectors to the resulting ones.
907 // swapping the data should be more efficient than assigning since
908 // we won't need the temporary vectors anymore
909 rData
.GetPagesToPrint().swap( aTmpPagesToPrint
);
914 void SwDoc::CalculatePagePairsForProspectPrinting(
915 const SwRootFrame
& rLayout
,
916 /* out */ SwRenderData
&rData
,
917 const SwPrintUIOptions
&rOptions
,
918 sal_Int32 nDocPageCount
)
920 std::map
< sal_Int32
, sal_Int32
> &rPrinterPaperTrays
= rData
.GetPrinterPaperTrays();
921 o3tl::sorted_vector
< sal_Int32
> &rValidPagesSet
= rData
.GetValidPagesSet();
922 std::vector
< std::pair
< sal_Int32
, sal_Int32
> > &rPagePairs
= rData
.GetPagePairsForProspectPrinting();
923 std::map
< sal_Int32
, const SwPageFrame
* > validStartFrames
;
926 rValidPagesSet
.clear();
930 // 0 -> print all pages (default if aPageRange is empty)
931 // 1 -> print range according to PageRange
932 // 2 -> print selection
933 const sal_Int64 nContent
= rOptions
.getIntValue( "PrintContent", 0 );
935 aPageRange
= rOptions
.getStringValue( "PageRange" );
936 if (aPageRange
.isEmpty()) // empty string -> print all
938 // set page range to print to 'all pages'
939 aPageRange
= OUString::number( 1 ) + "-" + OUString::number( nDocPageCount
);
941 StringRangeEnumerator
aRange( aPageRange
, 1, nDocPageCount
, 0 );
943 if ( aRange
.size() <= 0)
946 const SwPageFrame
*pStPage
= dynamic_cast<const SwPageFrame
*>( rLayout
.Lower() );
947 for ( sal_Int32 i
= 1; pStPage
&& i
< nDocPageCount
; ++i
)
948 pStPage
= static_cast<const SwPageFrame
*>(pStPage
->GetNext());
949 if ( !pStPage
) // Then it was that
952 // currently for prospect printing all pages are valid to be printed
953 // thus we add them all to the respective map and set for later use
954 sal_Int32 nPageNum
= 0;
955 const SwPageFrame
*pPageFrame
= dynamic_cast<const SwPageFrame
*>( rLayout
.Lower() );
956 while( pPageFrame
&& nPageNum
< nDocPageCount
)
959 rValidPagesSet
.insert( nPageNum
);
960 validStartFrames
[ nPageNum
] = pPageFrame
;
961 pPageFrame
= static_cast<const SwPageFrame
*>(pPageFrame
->GetNext());
963 rPrinterPaperTrays
[ nPageNum
] = lcl_GetPaperBin( pStPage
);
965 OSL_ENSURE( nPageNum
== nDocPageCount
, "unexpected number of pages" );
967 // properties to take into account when calculating the set of pages
968 // Note: here bPrintLeftPages and bPrintRightPages refer to the (virtual) resulting pages
970 bool bPrintLeftPages
= rOptions
.IsPrintLeftPages();
971 bool bPrintRightPages
= rOptions
.IsPrintRightPages();
972 bool bPrintProspectRTL
= rOptions
.getIntValue( "PrintProspectRTL", 0 ) != 0;
974 // get pages for prospect printing according to the 'PageRange'
975 // (duplicates and any order allowed!)
976 std::vector
< sal_Int32
> aPagesToPrint
;
977 StringRangeEnumerator::getRangesFromString(
978 aPageRange
, aPagesToPrint
, 1, nDocPageCount
, 0 );
980 if (aPagesToPrint
.empty())
983 // now fill the vector for calculating the page pairs with the start frames
984 // from the above obtained vector
985 std::vector
< const SwPageFrame
* > aVec
;
986 for (sal_Int32 nPage
: aPagesToPrint
)
988 const SwPageFrame
*pFrame
= validStartFrames
[ nPage
];
989 aVec
.push_back( pFrame
);
992 // just one page is special ...
993 if ( 1 == aVec
.size() )
994 aVec
.insert( aVec
.begin() + 1, nullptr ); // insert a second empty page
997 // now extend the number of pages to fit a multiple of 4
998 // (4 'normal' pages are needed for a single prospect paper
999 // with back and front)
1000 while( aVec
.size() & 3 )
1001 aVec
.push_back( nullptr );
1004 // make sure that all pages are in correct order
1005 std::vector
< const SwPageFrame
* >::size_type nSPg
= 0;
1006 std::vector
< const SwPageFrame
* >::size_type nEPg
= aVec
.size();
1007 sal_Int32 nStep
= 1;
1008 if ( 0 == (nEPg
& 1 )) // there are no uneven ones!
1011 if ( !bPrintLeftPages
)
1013 else if ( !bPrintRightPages
)
1020 // the number of 'virtual' pages to be printed
1021 sal_Int32 nCntPage
= (( nEPg
- nSPg
) / ( 2 * nStep
)) + 1;
1023 for ( sal_Int32 nPrintCount
= 0; nSPg
< nEPg
&&
1024 nPrintCount
< nCntPage
; ++nPrintCount
)
1026 pStPage
= aVec
[ nSPg
];
1027 const SwPageFrame
* pNxtPage
= nEPg
< aVec
.size() ? aVec
[ nEPg
] : nullptr;
1029 short nRtlOfs
= bPrintProspectRTL
? 1 : 0;
1030 if ( 0 == (( nSPg
+ nRtlOfs
) & 1 ) ) // switch for odd number in LTR, even number in RTL
1032 const SwPageFrame
* pTmp
= pStPage
;
1037 sal_Int32 nFirst
= -1, nSecond
= -1;
1038 for ( int nC
= 0; nC
< 2; ++nC
)
1040 sal_Int32 nPage
= -1;
1042 nPage
= pStPage
->GetPhyPageNum();
1050 rPagePairs
.emplace_back(nFirst
, nSecond
);
1052 nSPg
= nSPg
+ nStep
;
1053 nEPg
= nEPg
- nStep
;
1055 OSL_ENSURE( size_t(nCntPage
) == rPagePairs
.size(), "size mismatch for number of page pairs" );
1057 // luckily prospect printing does not make use of post-its so far,
1058 // thus we are done here.
1061 /// @return the reference in the doc for the name
1062 const SwFormatRefMark
* SwDoc::GetRefMark( std::u16string_view rName
) const
1064 for (const SfxPoolItem
* pItem
: GetAttrPool().GetItemSurrogates(RES_TXTATR_REFMARK
))
1066 auto pFormatRef
= dynamic_cast<const SwFormatRefMark
*>(pItem
);
1070 const SwTextRefMark
* pTextRef
= pFormatRef
->GetTextRefMark();
1071 if( pTextRef
&& &pTextRef
->GetTextNode().GetNodes() == &GetNodes() &&
1072 rName
== pFormatRef
->GetRefName() )
1078 /// @return the RefMark per index - for Uno
1079 const SwFormatRefMark
* SwDoc::GetRefMark( sal_uInt16 nIndex
) const
1081 const SwFormatRefMark
* pRet
= nullptr;
1083 sal_uInt32 nCount
= 0;
1084 for (const SfxPoolItem
* pItem
: GetAttrPool().GetItemSurrogates(RES_TXTATR_REFMARK
))
1086 auto pRefMark
= dynamic_cast<const SwFormatRefMark
*>(pItem
);
1089 const SwTextRefMark
* pTextRef
= pRefMark
->GetTextRefMark();
1090 if( pTextRef
&& &pTextRef
->GetTextNode().GetNodes() == &GetNodes() )
1092 if(nCount
== nIndex
)
1103 /// @return the names of all set references in the Doc
1104 //JP 24.06.96: If the array pointer is 0, then just return whether a RefMark is set in the Doc
1105 // OS 25.06.96: From now on we always return the reference count
1106 sal_uInt16
SwDoc::GetRefMarks( std::vector
<OUString
>* pNames
) const
1108 sal_uInt16 nCount
= 0;
1109 for (const SfxPoolItem
* pItem
: GetAttrPool().GetItemSurrogates(RES_TXTATR_REFMARK
))
1111 auto pRefMark
= dynamic_cast<const SwFormatRefMark
*>(pItem
);
1114 const SwTextRefMark
* pTextRef
= pRefMark
->GetTextRefMark();
1115 if( pTextRef
&& &pTextRef
->GetTextNode().GetNodes() == &GetNodes() )
1119 OUString
aTmp(pRefMark
->GetRefName());
1120 pNames
->insert(pNames
->begin() + nCount
, aTmp
);
1129 void SwDoc::DeleteFormatRefMark(const SwFormatRefMark
* pFormatRefMark
)
1131 const SwTextRefMark
* pTextRefMark
= pFormatRefMark
->GetTextRefMark();
1132 SwTextNode
& rTextNd
= const_cast<SwTextNode
&>(pTextRefMark
->GetTextNode());
1133 std::unique_ptr
<SwRegHistory
> aRegHistory
;
1134 if (GetIDocumentUndoRedo().DoesUndo())
1136 SwUndoResetAttr
* pUndo
= new SwUndoResetAttr(SwPosition(rTextNd
, pTextRefMark
->GetStart()),
1137 RES_TXTATR_REFMARK
);
1138 GetIDocumentUndoRedo().AppendUndo(std::unique_ptr
<SwUndo
>(pUndo
));
1139 aRegHistory
.reset(new SwRegHistory(rTextNd
, &pUndo
->GetHistory()));
1140 rTextNd
.GetpSwpHints()->Register(aRegHistory
.get());
1142 rTextNd
.DeleteAttribute(const_cast<SwTextRefMark
*>(pTextRefMark
));
1143 if (GetIDocumentUndoRedo().DoesUndo())
1145 if (rTextNd
.GetpSwpHints())
1146 rTextNd
.GetpSwpHints()->DeRegister();
1148 getIDocumentState().SetModified();
1151 static bool lcl_SpellAndGrammarAgain( SwNode
* pNd
, void* pArgs
)
1153 SwTextNode
*pTextNode
= pNd
->GetTextNode();
1154 bool bOnlyWrong
= *static_cast<sal_Bool
*>(pArgs
);
1159 if( pTextNode
->GetWrong() &&
1160 pTextNode
->GetWrong()->InvalidateWrong() )
1161 pTextNode
->SetWrongDirty(sw::WrongState::TODO
);
1162 if( pTextNode
->GetGrammarCheck() &&
1163 pTextNode
->GetGrammarCheck()->InvalidateWrong() )
1164 pTextNode
->SetGrammarCheckDirty( true );
1168 pTextNode
->SetWrongDirty(sw::WrongState::TODO
);
1169 if( pTextNode
->GetWrong() )
1170 pTextNode
->GetWrong()->SetInvalid( 0, COMPLETE_STRING
);
1171 pTextNode
->SetGrammarCheckDirty( true );
1172 if( pTextNode
->GetGrammarCheck() )
1173 pTextNode
->GetGrammarCheck()->SetInvalid( 0, COMPLETE_STRING
);
1179 static bool lcl_CheckSmartTagsAgain( SwNode
* pNd
, void* )
1181 SwTextNode
*pTextNode
= pNd
->GetTextNode();
1184 pTextNode
->SetSmartTagDirty( true );
1185 pTextNode
->ClearSmartTags();
1191 * Re-trigger spelling in the idle handler.
1193 * @param bInvalid if <true>, the WrongLists in all nodes are invalidated
1194 * and the SpellInvalid flag is set on all pages.
1195 * @param bOnlyWrong controls whether only the areas with wrong words are
1196 * checked or the whole area.
1197 * @param bSmartTags ???
1199 void SwDoc::SpellItAgainSam( bool bInvalid
, bool bOnlyWrong
, bool bSmartTags
)
1201 o3tl::sorted_vector
<SwRootFrame
*> aAllLayouts
= GetAllLayouts();
1202 assert(getIDocumentLayoutAccess().GetCurrentLayout() && "SpellAgain: Where's my RootFrame?");
1205 for ( auto aLayout
: aAllLayouts
)
1207 aLayout
->AllInvalidateSmartTagsOrSpelling(bSmartTags
);
1208 aLayout
->SetNeedGrammarCheck(true);
1211 GetNodes().ForEach( lcl_CheckSmartTagsAgain
, &bOnlyWrong
);
1212 GetNodes().ForEach( lcl_SpellAndGrammarAgain
, &bOnlyWrong
);
1215 for ( auto aLayout
: aAllLayouts
)
1216 aLayout
->SetIdleFlags();
1219 void SwDoc::InvalidateAutoCompleteFlag()
1221 SwRootFrame
* pTmpRoot
= getIDocumentLayoutAccess().GetCurrentLayout();
1225 o3tl::sorted_vector
<SwRootFrame
*> aAllLayouts
= GetAllLayouts();
1226 for( auto aLayout
: aAllLayouts
)
1227 aLayout
->AllInvalidateAutoCompleteWords();
1228 for( SwNodeOffset
nNd(1), nCnt
= GetNodes().Count(); nNd
< nCnt
; ++nNd
)
1230 SwTextNode
* pTextNode
= GetNodes()[ nNd
]->GetTextNode();
1231 if ( pTextNode
) pTextNode
->SetAutoCompleteWordDirty( true );
1234 for( auto aLayout
: aAllLayouts
)
1235 aLayout
->SetIdleFlags();
1238 const SwFormatINetFormat
* SwDoc::FindINetAttr( std::u16string_view rName
) const
1240 for (const SfxPoolItem
* pItem
: GetAttrPool().GetItemSurrogates(RES_TXTATR_INETFMT
))
1242 auto pFormatItem
= dynamic_cast<const SwFormatINetFormat
*>(pItem
);
1243 if( !pFormatItem
|| pFormatItem
->GetName() != rName
)
1245 const SwTextINetFormat
* pTextAttr
= pFormatItem
->GetTextINetFormat();
1248 const SwTextNode
* pTextNd
= pTextAttr
->GetpTextNode();
1249 if( pTextNd
&& &pTextNd
->GetNodes() == &GetNodes() )
1257 void SwDoc::Summary(SwDoc
& rExtDoc
, sal_uInt8 nLevel
, sal_uInt8 nPara
, bool bImpress
)
1259 const SwOutlineNodes
& rOutNds
= GetNodes().GetOutLineNds();
1260 if (rOutNds
.empty())
1263 ::StartProgress( STR_STATSTR_SUMMARY
, 0, rOutNds
.size(), GetDocShell() );
1264 SwNodeIndex
aEndOfDoc( rExtDoc
.GetNodes().GetEndOfContent(), -1 );
1265 for( SwOutlineNodes::size_type i
= 0; i
< rOutNds
.size(); ++i
)
1267 ::SetProgressState( static_cast<tools::Long
>(i
), GetDocShell() );
1268 const SwNodeOffset nIndex
= rOutNds
[ i
]->GetIndex();
1270 const int nLvl
= GetNodes()[ nIndex
]->GetTextNode()->GetAttrOutlineLevel()-1;
1273 SwNodeOffset
nEndOfs(1);
1274 sal_uInt8 nWish
= nPara
;
1275 SwNodeOffset nNextOutNd
= i
+ 1 < rOutNds
.size() ?
1276 rOutNds
[ i
+ 1 ]->GetIndex() : GetNodes().Count();
1278 while( ( nWish
|| bKeep
) && nIndex
+ nEndOfs
< nNextOutNd
&&
1279 GetNodes()[ nIndex
+ nEndOfs
]->IsTextNode() )
1281 SwTextNode
* pTextNode
= GetNodes()[ nIndex
+nEndOfs
]->GetTextNode();
1282 if (pTextNode
->GetText().getLength() && nWish
)
1284 bKeep
= pTextNode
->GetSwAttrSet().GetKeep().GetValue();
1288 SwNodeRange
aRange( *rOutNds
[ i
], SwNodeOffset(0), *rOutNds
[ i
], nEndOfs
);
1289 GetNodes().Copy_( aRange
, aEndOfDoc
.GetNode() );
1291 const SwTextFormatColls
*pColl
= rExtDoc
.GetTextFormatColls();
1292 for( SwTextFormatColls::size_type i
= 0; i
< pColl
->size(); ++i
)
1293 (*pColl
)[ i
]->ResetFormatAttr( RES_PAGEDESC
, RES_BREAK
);
1294 SwNodeIndex
aIndx( rExtDoc
.GetNodes().GetEndOfExtras() );
1296 while( aIndx
< aEndOfDoc
)
1298 bool bDelete
= false;
1299 SwNode
*pNode
= &aIndx
.GetNode();
1300 if( pNode
->IsTextNode() )
1302 SwTextNode
*pNd
= pNode
->GetTextNode();
1303 if( pNd
->HasSwAttrSet() )
1304 pNd
->ResetAttr( RES_PAGEDESC
, RES_BREAK
);
1307 SwTextFormatColl
* pMyColl
= pNd
->GetTextColl();
1309 const sal_uInt16 nHeadLine
= o3tl::narrowing
<sal_uInt16
>(
1310 !pMyColl
->IsAssignedToListLevelOfOutlineStyle()
1311 ? RES_POOLCOLL_HEADLINE2
1312 : RES_POOLCOLL_HEADLINE1
);
1313 pMyColl
= rExtDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool( nHeadLine
);
1314 pNd
->ChgFormatColl( pMyColl
);
1317 pNd
->StartOfSectionIndex()+SwNodeOffset(2) < pNd
->EndOfSectionIndex() )
1320 rExtDoc
.GetNodes().Delete( aIndx
);
1326 ::EndProgress( GetDocShell() );
1331 void RemoveOrDeleteContents(SwTextNode
* pTextNd
, IDocumentContentOperations
& xOperations
)
1333 SwPaM
aPam(*pTextNd
, 0, *pTextNd
, pTextNd
->GetText().getLength());
1335 // Remove hidden paragraph or delete contents:
1336 // Delete contents if
1337 // 1. removing the paragraph would result in an empty section or
1338 // 2. if the paragraph is the last paragraph in the section and
1339 // there is no paragraph in front of the paragraph:
1340 if ((SwNodeOffset(2) == pTextNd
->EndOfSectionIndex() - pTextNd
->StartOfSectionIndex())
1341 || (SwNodeOffset(1) == pTextNd
->EndOfSectionIndex() - pTextNd
->GetIndex()
1342 && !pTextNd
->GetNodes()[pTextNd
->GetIndex() - 1]->GetTextNode()))
1344 xOperations
.DeleteRange(aPam
);
1349 xOperations
.DelFullPara(aPam
);
1352 // Returns if the data was actually modified
1353 bool HandleHidingField(SwFormatField
& rFormatField
, const SwNodes
& rNodes
,
1354 IDocumentContentOperations
& xOperations
)
1356 if( !rFormatField
.GetTextField() )
1358 SwTextNode
* pTextNd
= rFormatField
.GetTextField()->GetpTextNode();
1360 && pTextNd
->GetpSwpHints() && pTextNd
->IsHiddenByParaField()
1361 && &pTextNd
->GetNodes() == &rNodes
)
1363 RemoveOrDeleteContents(pTextNd
, xOperations
);
1370 // The greater the returned value, the more weight has this field type on deciding the final
1372 int SwDoc::FieldCanHideParaWeight(SwFieldIds eFieldId
) const
1376 case SwFieldIds::HiddenPara
:
1378 case SwFieldIds::Database
:
1379 return GetDocumentSettingManager().get(DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA
)
1387 bool SwDoc::FieldHidesPara(const SwField
& rField
) const
1389 switch (rField
.GetTyp()->Which())
1391 case SwFieldIds::HiddenPara
:
1392 return static_cast<const SwHiddenParaField
&>(rField
).IsHidden();
1393 case SwFieldIds::Database
:
1394 return FieldCanHideParaWeight(SwFieldIds::Database
)
1395 && rField
.ExpandField(true, nullptr).isEmpty();
1401 /// Remove the invisible content from the document e.g. hidden areas, hidden paragraphs
1402 // Returns if the data was actually modified
1403 bool SwDoc::RemoveInvisibleContent()
1406 GetIDocumentUndoRedo().StartUndo( SwUndoId::UI_DELETE_INVISIBLECNTNT
, nullptr );
1409 class FieldTypeGuard
: public SwClient
1412 explicit FieldTypeGuard(SwFieldType
* pType
)
1416 const SwFieldType
* get() const
1418 return static_cast<const SwFieldType
*>(GetRegisteredIn());
1421 // Removing some nodes for one SwFieldIds::Database type might remove the type from
1422 // document's field types, invalidating iterators. So, we need to create own list of
1423 // matching types prior to processing them.
1424 std::vector
<std::unique_ptr
<FieldTypeGuard
>> aHidingFieldTypes
;
1425 for (std::unique_ptr
<SwFieldType
> const & pType
: *getIDocumentFieldsAccess().GetFieldTypes())
1427 if (FieldCanHideParaWeight(pType
->Which()))
1428 aHidingFieldTypes
.push_back(std::make_unique
<FieldTypeGuard
>(pType
.get()));
1430 for (const auto& pTypeGuard
: aHidingFieldTypes
)
1432 if (const SwFieldType
* pType
= pTypeGuard
->get())
1434 std::vector
<SwFormatField
*> vFields
;
1435 pType
->GatherFields(vFields
);
1436 for(auto pFormatField
: vFields
)
1437 bRet
|= HandleHidingField(*pFormatField
, GetNodes(), getIDocumentContentOperations());
1442 // Remove any hidden paragraph (hidden text attribute)
1443 for( SwNodeOffset n
= GetNodes().Count(); n
; )
1445 SwTextNode
* pTextNd
= GetNodes()[ --n
]->GetTextNode();
1448 bool bRemoved
= false;
1449 if ( pTextNd
->HasHiddenCharAttribute( true ) )
1454 if (SwNodeOffset(2) == pTextNd
->EndOfSectionIndex() - pTextNd
->StartOfSectionIndex())
1456 SwFrameFormat
*const pFormat
= pTextNd
->StartOfSectionNode()->GetFlyFormat();
1457 if (nullptr != pFormat
)
1459 // remove hidden text frame
1460 getIDocumentLayoutAccess().DelLayoutFormat(pFormat
);
1464 // default, remove hidden paragraph
1465 RemoveOrDeleteContents(pTextNd
, getIDocumentContentOperations());
1470 // default, remove hidden paragraph
1471 RemoveOrDeleteContents(pTextNd
, getIDocumentContentOperations());
1474 else if ( pTextNd
->HasHiddenCharAttribute( false ) )
1478 SwScriptInfo::DeleteHiddenRanges( *pTextNd
);
1481 // Footnotes/Frames may have been removed, therefore we have
1485 // [n] has to be inside [0 .. GetNodes().Count()] range
1486 if (n
> GetNodes().Count())
1487 n
= GetNodes().Count();
1493 // Delete/empty all hidden areas
1494 o3tl::sorted_vector
<SwSectionFormat
*> aSectFormats
;
1495 SwSectionFormats
& rSectFormats
= GetSections();
1497 for( SwSectionFormats::size_type n
= rSectFormats
.size(); n
; )
1499 SwSectionFormat
* pSectFormat
= rSectFormats
[ --n
];
1500 // don't add sections in Undo/Redo
1501 if( !pSectFormat
->IsInNodesArr())
1503 SwSection
* pSect
= pSectFormat
->GetSection();
1504 if( pSect
->CalcHiddenFlag() )
1506 SwSection
* pParent
= pSect
, *pTmp
;
1507 while( nullptr != (pTmp
= pParent
->GetParent() ))
1509 if( pTmp
->IsHiddenFlag() )
1514 aSectFormats
.insert( pSect
->GetFormat() );
1516 if( !pSect
->GetCondition().isEmpty() )
1518 SwSectionData
aSectionData( *pSect
);
1519 aSectionData
.SetCondition( OUString() );
1520 aSectionData
.SetHidden( false );
1521 UpdateSection( n
, aSectionData
);
1525 auto n
= aSectFormats
.size();
1531 SwSectionFormat
* pSectFormat
= aSectFormats
[ --n
];
1532 SwSectionNode
* pSectNd
= pSectFormat
->GetSectionNode();
1536 SwPaM
aPam( *pSectNd
);
1538 if( pSectNd
->StartOfSectionNode()->StartOfSectionIndex() ==
1539 pSectNd
->GetIndex() - 1 &&
1540 pSectNd
->StartOfSectionNode()->EndOfSectionIndex() ==
1541 pSectNd
->EndOfSectionIndex() + 1 )
1543 // only delete the content
1544 SwContentNode
* pCNd
= GetNodes().GoNext( aPam
.GetPoint() );
1546 aPam
.GetPoint()->Assign( *pSectNd
->EndOfSectionNode() );
1547 pCNd
= SwNodes::GoPrevious( aPam
.GetPoint() );
1548 assert(pCNd
); // keep coverity happy
1549 aPam
.GetPoint()->SetContent( pCNd
->Len() );
1551 getIDocumentContentOperations().DeleteRange( aPam
);
1555 // delete the whole section
1557 aPam
.GetPoint()->Assign( *pSectNd
->EndOfSectionNode() );
1558 getIDocumentContentOperations().DelFullPara( aPam
);
1567 getIDocumentState().SetModified();
1568 GetIDocumentUndoRedo().EndUndo( SwUndoId::UI_DELETE_INVISIBLECNTNT
, nullptr );
1572 bool SwDoc::HasInvisibleContent() const
1574 std::vector
<SwFormatField
*> vFields
;
1575 getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::HiddenPara
)->GatherFields(vFields
);
1579 // Search for any hidden paragraph (hidden text attribute)
1580 for( SwNodeOffset n
= GetNodes().Count()-SwNodeOffset(1); n
; --n
)
1582 SwTextNode
* pTextNd
= GetNodes()[ n
]->GetTextNode();
1584 ( pTextNd
->HasHiddenCharAttribute( true ) || pTextNd
->HasHiddenCharAttribute( false ) ) )
1588 for(auto pSectFormat
: GetSections())
1590 // don't add sections in Undo/Redo
1591 if( !pSectFormat
->IsInNodesArr())
1593 SwSection
* pSect
= pSectFormat
->GetSection();
1594 if( pSect
->IsHidden() )
1600 bool SwDoc::RestoreInvisibleContent()
1602 SwUndoId
nLastUndoId(SwUndoId::EMPTY
);
1603 if (GetIDocumentUndoRedo().GetLastUndoInfo(nullptr, & nLastUndoId
)
1604 && (SwUndoId::UI_DELETE_INVISIBLECNTNT
== nLastUndoId
))
1606 GetIDocumentUndoRedo().Undo();
1607 GetIDocumentUndoRedo().ClearRedo();
1613 static bool IsMailMergeField(SwFieldIds fieldId
)
1617 case SwFieldIds::Database
: // Mail merge fields
1618 case SwFieldIds::DatabaseName
: // Database name
1619 case SwFieldIds::HiddenText
: // Hidden text may use database fields in condition
1620 case SwFieldIds::HiddenPara
: // Hidden paragraph may use database fields in condition
1621 case SwFieldIds::DbNextSet
: // Moving to next mail merge record
1622 case SwFieldIds::DbNumSet
: // Moving to a specific mail merge record
1623 case SwFieldIds::DbSetNumber
: // Number of current mail merge record
1630 bool SwDoc::ConvertFieldsToText(SwRootFrame
const& rLayout
)
1633 getIDocumentFieldsAccess().LockExpFields();
1634 GetIDocumentUndoRedo().StartUndo( SwUndoId::UI_REPLACE
, nullptr );
1636 const bool bOnlyConvertDBFields
1637 = officecfg::Office::Writer::FormLetter::ConvertToTextOnlyMMFields::get();
1639 const SwFieldTypes
* pMyFieldTypes
= getIDocumentFieldsAccess().GetFieldTypes();
1640 const SwFieldTypes::size_type nCount
= pMyFieldTypes
->size();
1641 //go backward, field types are removed
1642 for(SwFieldTypes::size_type nType
= nCount
; nType
> 0; --nType
)
1644 const SwFieldType
*pCurType
= (*pMyFieldTypes
)[nType
- 1].get();
1646 if ( SwFieldIds::Postit
== pCurType
->Which() )
1649 if (bOnlyConvertDBFields
&& !IsMailMergeField(pCurType
->Which()))
1652 std::vector
<SwFormatField
*> vFieldFormats
;
1653 pCurType
->GatherFields(vFieldFormats
, false);
1654 for(const auto& rpFieldFormat
: vFieldFormats
)
1656 const SwTextField
*pTextField
= rpFieldFormat
->GetTextField();
1657 // skip fields that are currently not in the document
1658 // e.g. fields in undo or redo array
1660 bool bSkip
= !pTextField
||
1661 !pTextField
->GetpTextNode()->GetNodes().IsDocNodes();
1665 bool bInHeaderFooter
= IsInHeaderFooter(*pTextField
->GetpTextNode());
1666 const SwFormatField
& rFormatField
= pTextField
->GetFormatField();
1667 const SwField
* pField
= rFormatField
.GetField();
1669 //#i55595# some fields have to be excluded in headers/footers
1670 SwFieldIds nWhich
= pField
->GetTyp()->Which();
1671 if(!bInHeaderFooter
||
1672 (nWhich
!= SwFieldIds::PageNumber
&&
1673 nWhich
!= SwFieldIds::Chapter
&&
1674 nWhich
!= SwFieldIds::GetExp
&&
1675 nWhich
!= SwFieldIds::SetExp
&&
1676 nWhich
!= SwFieldIds::Input
&&
1677 nWhich
!= SwFieldIds::RefPageGet
&&
1678 nWhich
!= SwFieldIds::RefPageSet
))
1680 OUString sText
= pField
->ExpandField(true, &rLayout
);
1682 // database fields should not convert their command into text
1683 if( SwFieldIds::Database
== pCurType
->Which() && !static_cast<const SwDBField
*>(pField
)->IsInitialized())
1686 SwPaM
aInsertPam(*pTextField
->GetpTextNode(), pTextField
->GetStart());
1687 aInsertPam
.SetMark();
1689 // go to the end of the field
1690 const SwTextField
*pFieldAtEnd
= sw::DocumentFieldsManager::GetTextFieldAtPos(*aInsertPam
.End());
1691 if (pFieldAtEnd
&& pFieldAtEnd
->Which() == RES_TXTATR_INPUTFIELD
)
1693 SwPosition
&rEndPos
= *aInsertPam
.GetPoint();
1694 rEndPos
.SetContent( SwCursorShell::EndOfInputFieldAtPos( *aInsertPam
.End() ) );
1701 // first insert the text after field to keep the field's attributes,
1702 // then delete the field
1703 if (!sText
.isEmpty())
1705 // to keep the position after insert
1706 SwPaM
aDelPam( *aInsertPam
.GetMark(), *aInsertPam
.GetPoint() );
1707 aDelPam
.Move( fnMoveBackward
);
1708 aInsertPam
.DeleteMark();
1710 getIDocumentContentOperations().InsertString( aInsertPam
, sText
);
1713 // finally remove the field
1714 getIDocumentContentOperations().DeleteAndJoin( aDelPam
);
1718 getIDocumentContentOperations().DeleteAndJoin( aInsertPam
);
1727 getIDocumentState().SetModified();
1728 GetIDocumentUndoRedo().EndUndo( SwUndoId::UI_REPLACE
, nullptr );
1729 getIDocumentFieldsAccess().UnlockExpFields();
1734 bool SwDoc::IsInsTableFormatNum() const
1736 return SW_MOD()->IsInsTableFormatNum(GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE
));
1739 bool SwDoc::IsInsTableChangeNumFormat() const
1741 return SW_MOD()->IsInsTableChangeNumFormat(GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE
));
1744 bool SwDoc::IsInsTableAlignNum() const
1746 return SW_MOD()->IsInsTableAlignNum(GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE
));
1749 bool SwDoc::IsSplitVerticalByDefault() const
1751 return SW_MOD()->IsSplitVerticalByDefault(GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE
));
1754 void SwDoc::SetSplitVerticalByDefault(bool value
)
1756 SW_MOD()->SetSplitVerticalByDefault(GetDocumentSettingManager().get(DocumentSettingId::HTML_MODE
), value
);
1759 /// Set up the InsertDB as Undo table
1760 void SwDoc::AppendUndoForInsertFromDB( const SwPaM
& rPam
, bool bIsTable
)
1764 const SwTableNode
* pTableNd
= rPam
.GetPoint()->GetNode().FindTableNode();
1767 std::unique_ptr
<SwUndoCpyTable
> pUndo(new SwUndoCpyTable(*this));
1768 pUndo
->SetTableSttIdx( pTableNd
->GetIndex() );
1769 GetIDocumentUndoRedo().AppendUndo( std::move(pUndo
) );
1772 else if( rPam
.HasMark() )
1774 std::unique_ptr
<SwUndoCpyDoc
> pUndo(new SwUndoCpyDoc( rPam
));
1775 pUndo
->SetInsertRange( rPam
, false );
1776 GetIDocumentUndoRedo().AppendUndo( std::move(pUndo
) );
1780 void SwDoc::ChangeTOX(SwTOXBase
& rTOX
, const SwTOXBase
& rNew
)
1782 assert(dynamic_cast<const SwTOXBaseSection
*>(&rTOX
));
1783 SwTOXBaseSection
& rTOXSect(static_cast<SwTOXBaseSection
&>(rTOX
));
1785 if (GetIDocumentUndoRedo().DoesUndo())
1787 GetIDocumentUndoRedo().AppendUndo(
1788 std::make_unique
<SwUndoTOXChange
>(*this, rTOXSect
, rNew
));
1793 // note: do not Update the ToX here - the caller will do it, with a ViewShell!
1796 OUString
SwDoc::GetPaMDescr(const SwPaM
& rPam
)
1798 if (&rPam
.GetPointNode() == &rPam
.GetMarkNode())
1800 SwTextNode
* pTextNode
= rPam
.GetPointNode().GetTextNode();
1802 if (nullptr != pTextNode
)
1804 const sal_Int32 nStart
= rPam
.Start()->GetContentIndex();
1805 const sal_Int32 nEnd
= rPam
.End()->GetContentIndex();
1807 return SwResId(STR_START_QUOTE
)
1808 + ShortenString(pTextNode
->GetText().copy(nStart
, nEnd
- nStart
),
1811 + SwResId(STR_END_QUOTE
);
1816 return SwResId(STR_PARAGRAPHS
);
1822 bool SwDoc::ContainsHiddenChars() const
1824 for( SwNodeOffset n
= GetNodes().Count(); n
; )
1826 SwNode
* pNd
= GetNodes()[ --n
];
1827 if ( pNd
->IsTextNode() && pNd
->GetTextNode()->HasHiddenCharAttribute( false ) )
1834 std::shared_ptr
<SwUnoCursor
> SwDoc::CreateUnoCursor( const SwPosition
& rPos
, bool bTableCursor
)
1836 std::shared_ptr
<SwUnoCursor
> pNew
;
1838 pNew
= std::make_shared
<SwUnoTableCursor
>(rPos
);
1840 pNew
= std::make_shared
<SwUnoCursor
>(rPos
);
1842 mvUnoCursorTable
.push_back( pNew
);
1846 void SwDoc::ChkCondColls()
1848 for (SwTextFormatColls::size_type n
= 0; n
< mpTextFormatCollTable
->size(); ++n
)
1850 SwTextFormatColl
*pColl
= (*mpTextFormatCollTable
)[n
];
1851 if (RES_CONDTXTFMTCOLL
== pColl
->Which())
1852 pColl
->CallSwClientNotify( SwAttrHint() );
1856 uno::Reference
< script::vba::XVBAEventProcessor
> const &
1857 SwDoc::GetVbaEventProcessor()
1862 void SwDoc::SetVbaEventProcessor()
1864 #if HAVE_FEATURE_SCRIPTING
1865 if (mpDocShell
&& ooo::vba::isAlienWordDoc(*mpDocShell
))
1869 uno::Reference
< frame::XModel
> xModel( mpDocShell
->GetModel(), uno::UNO_SET_THROW
);
1870 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(xModel
) };
1871 mxVbaEvents
.set( ooo::vba::createVBAUnoAPIServiceWithArgs( mpDocShell
, "com.sun.star.script.vba.VBATextEventProcessor" , aArgs
), uno::UNO_QUERY_THROW
);
1873 catch( uno::Exception
& )
1880 void SwDoc::SetMissingDictionaries( bool bIsMissing
)
1883 meDictionaryMissing
= MissingDictionary::False
;
1884 else if (meDictionaryMissing
== MissingDictionary::Undefined
)
1885 meDictionaryMissing
= MissingDictionary::True
;
1888 void SwDoc::SetLanguage(const LanguageType eLang
, const sal_uInt16 nId
)
1890 mpAttrPool
->SetPoolDefaultItem(SvxLanguageItem(eLang
, nId
));
1893 bool SwDoc::HasParagraphDirectFormatting(const SwPosition
& rPos
)
1895 uno::Reference
<text::XTextRange
> xRange(SwXTextRange::CreateXTextRange(rPos
.GetDoc(), rPos
,
1897 uno::Reference
<container::XEnumerationAccess
> xParaEnumAccess(xRange
, uno::UNO_QUERY_THROW
);
1898 uno::Reference
<container::XEnumeration
> xParaEnum
= xParaEnumAccess
->createEnumeration();
1899 uno::Reference
<text::XTextRange
> xThisParagraphRange(xParaEnum
->nextElement(), uno::UNO_QUERY
);
1900 if (xThisParagraphRange
.is())
1902 const std::vector
<OUString
> aHiddenProperties
{ UNO_NAME_RSID
,
1903 UNO_NAME_PARA_IS_NUMBERING_RESTART
,
1904 UNO_NAME_PARA_STYLE_NAME
,
1905 UNO_NAME_PARA_CONDITIONAL_STYLE_NAME
,
1906 UNO_NAME_PAGE_STYLE_NAME
,
1907 UNO_NAME_NUMBERING_START_VALUE
,
1908 UNO_NAME_NUMBERING_IS_NUMBER
,
1909 UNO_NAME_PARA_CONTINUEING_PREVIOUS_SUB_TREE
,
1910 UNO_NAME_CHAR_STYLE_NAME
,
1911 UNO_NAME_NUMBERING_LEVEL
,
1912 UNO_NAME_SORTED_TEXT_ID
,
1914 UNO_NAME_CHAR_COLOR_THEME
,
1915 UNO_NAME_CHAR_COLOR_TINT_OR_SHADE
};
1917 SfxItemPropertySet
const& rPropSet(*aSwMapProvider
.GetPropertySet(
1918 PROPERTY_MAP_PARA_AUTO_STYLE
));
1919 SfxItemPropertyMap
const& rMap(rPropSet
.getPropertyMap());
1921 uno::Reference
<beans::XPropertySet
> xPropertySet(xThisParagraphRange
,
1922 uno::UNO_QUERY_THROW
);
1923 uno::Reference
<beans::XPropertyState
> xPropertyState(xThisParagraphRange
,
1924 uno::UNO_QUERY_THROW
);
1925 const uno::Sequence
<beans::Property
> aProperties
1926 = xPropertySet
->getPropertySetInfo()->getProperties();
1927 for (const beans::Property
& rProperty
: aProperties
)
1929 const OUString
& rPropName
= rProperty
.Name
;
1930 if (!rMap
.hasPropertyByName(rPropName
))
1932 if (std::find(aHiddenProperties
.begin(), aHiddenProperties
.end(), rPropName
)
1933 != aHiddenProperties
.end())
1935 if (xPropertyState
->getPropertyState(rPropName
) == beans::PropertyState_DIRECT_VALUE
)
1942 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */