1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <libxml/xmlstring.h>
21 #include <libxml/xmlwriter.h>
22 #include <stdlib.h>
23 #include <hintids.hxx>
24 #include <osl/diagnose.h>
25 #include <sot/exchange.hxx>
26 #include <svl/stritem.hxx>
27 #include <sfx2/docfile.hxx>
28 #include <editeng/protitem.hxx>
29 #include <sfx2/linkmgr.hxx>
30 #include <sfx2/sfxsids.hrc>
31 #include <docary.hxx>
32 #include <fmtcntnt.hxx>
33 #include <fmtpdsc.hxx>
34 #include <doc.hxx>
35 #include <IDocumentUndoRedo.hxx>
36 #include <DocumentLinksAdministrationManager.hxx>
37 #include <DocumentContentOperationsManager.hxx>
38 #include <IDocumentRedlineAccess.hxx>
39 #include <IDocumentFieldsAccess.hxx>
40 #include <IDocumentStylePoolAccess.hxx>
41 #include <IDocumentState.hxx>
42 #include <IDocumentLayoutAccess.hxx>
43 #include <node.hxx>
44 #include <pam.hxx>
45 #include <frmatr.hxx>
46 #include <frmtool.hxx>
47 #include <editsh.hxx>
48 #include <hints.hxx>
49 #include <docsh.hxx>
50 #include <ndtxt.hxx>
51 #include <section.hxx>
52 #include <swserv.hxx>
53 #include <shellio.hxx>
54 #include <poolfmt.hxx>
55 #include <swbaslnk.hxx>
56 #include <mvsave.hxx>
57 #include <ftnidx.hxx>
58 #include <doctxm.hxx>
59 #include <fmteiro.hxx>
60 #include <unosection.hxx>
61 #include <calbck.hxx>
62 #include <fmtclds.hxx>
63 #include <algorithm>
64 #include "ndsect.hxx"
65 
66 using namespace ::com::sun::star;
67 
68 namespace {
69     class SwIntrnlSectRefLink : public SwBaseLink
70     {
71         SwSectionFormat& m_rSectFormat;
72 
73     public:
SwIntrnlSectRefLink(SwSectionFormat & rFormat,SfxLinkUpdateMode nUpdateType)74         SwIntrnlSectRefLink(SwSectionFormat& rFormat, SfxLinkUpdateMode nUpdateType)
75             : SwBaseLink(nUpdateType, SotClipboardFormatId::RTF)
76             , m_rSectFormat(rFormat)
77         {}
78 
79         virtual void Closed() override;
80         virtual ::sfx2::SvBaseLink::UpdateResult DataChanged(
81             const OUString& rMimeType, const css::uno::Any & rValue ) override;
82 
83         virtual const SwNode* GetAnchor() const override;
84         virtual bool IsInRange( sal_uLong nSttNd, sal_uLong nEndNd ) const override;
85 
GetSectNode()86         SwSectionNode* GetSectNode()
87         {
88             const SwNode* pSectNd( GetAnchor() );
89             return const_cast<SwSectionNode*>( dynamic_cast<const SwSectionNode*>( pSectNd ) );
90         }
91     };
92 }
93 
SwSectionData(SectionType const eType,OUString const & rName)94 SwSectionData::SwSectionData(SectionType const eType, OUString const& rName)
95     : m_eType(eType)
96     , m_sSectionName(rName)
97     , m_bHiddenFlag(false)
98     , m_bProtectFlag(false)
99     , m_bEditInReadonlyFlag(false) // edit in readonly sections
100     , m_bHidden(false)
101     , m_bCondHiddenFlag(true)
102     , m_bConnectFlag(true)
103 {
104 }
105 
106 // this must have the same semantics as operator=()
SwSectionData(SwSection const & rSection)107 SwSectionData::SwSectionData(SwSection const& rSection)
108     : m_eType(rSection.GetType())
109     , m_sSectionName(rSection.GetSectionName())
110     , m_sCondition(rSection.GetCondition())
111     , m_sLinkFileName(rSection.GetLinkFileName())
112     , m_sLinkFilePassword(rSection.GetLinkFilePassword())
113     , m_Password(rSection.GetPassword())
114     , m_bHiddenFlag(rSection.IsHiddenFlag())
115     , m_bProtectFlag(rSection.IsProtect())
116     // edit in readonly sections
117     , m_bEditInReadonlyFlag(rSection.IsEditInReadonly())
118     , m_bHidden(rSection.IsHidden())
119     , m_bCondHiddenFlag(true)
120     , m_bConnectFlag(rSection.IsConnectFlag())
121 {
122 }
123 
124 // this must have the same semantics as operator=()
SwSectionData(SwSectionData const & rOther)125 SwSectionData::SwSectionData(SwSectionData const& rOther)
126     : m_eType(rOther.m_eType)
127     , m_sSectionName(rOther.m_sSectionName)
128     , m_sCondition(rOther.m_sCondition)
129     , m_sLinkFileName(rOther.m_sLinkFileName)
130     , m_sLinkFilePassword(rOther.m_sLinkFilePassword)
131     , m_Password(rOther.m_Password)
132     , m_bHiddenFlag(rOther.m_bHiddenFlag)
133     , m_bProtectFlag(rOther.m_bProtectFlag)
134     // edit in readonly sections
135     , m_bEditInReadonlyFlag(rOther.m_bEditInReadonlyFlag)
136     , m_bHidden(rOther.m_bHidden)
137     , m_bCondHiddenFlag(true)
138     , m_bConnectFlag(rOther.m_bConnectFlag)
139 {
140 }
141 
142 // the semantics here are weird for reasons of backward compatibility
operator =(SwSectionData const & rOther)143 SwSectionData & SwSectionData::operator= (SwSectionData const& rOther)
144 {
145     m_eType = rOther.m_eType;
146     m_sSectionName = rOther.m_sSectionName;
147     m_sCondition = rOther.m_sCondition;
148     m_sLinkFileName = rOther.m_sLinkFileName;
149     m_sLinkFilePassword = rOther.m_sLinkFilePassword;
150     m_bConnectFlag = rOther.m_bConnectFlag;
151     m_Password = rOther.m_Password;
152 
153     m_bEditInReadonlyFlag = rOther.m_bEditInReadonlyFlag;
154     m_bProtectFlag = rOther.m_bProtectFlag;
155 
156     m_bHidden = rOther.m_bHidden;
157     // FIXME: old code did not assign m_bHiddenFlag ?
158     // FIXME: why should m_bCondHiddenFlag always default to true?
159     m_bCondHiddenFlag = true;
160 
161     return *this;
162 }
163 
164 // the semantics here are weird for reasons of backward compatibility
operator ==(SwSectionData const & rOther) const165 bool SwSectionData::operator==(SwSectionData const& rOther) const
166 {
167     return (m_eType == rOther.m_eType)
168         && (m_sSectionName == rOther.m_sSectionName)
169         && (m_sCondition == rOther.m_sCondition)
170         && (m_bHidden == rOther.m_bHidden)
171         && (m_bProtectFlag == rOther.m_bProtectFlag)
172         && (m_bEditInReadonlyFlag == rOther.m_bEditInReadonlyFlag)
173         && (m_sLinkFileName == rOther.m_sLinkFileName)
174         && (m_sLinkFilePassword == rOther.m_sLinkFilePassword)
175         && (m_Password == rOther.m_Password);
176     // FIXME: old code ignored m_bCondHiddenFlag m_bHiddenFlag m_bConnectFlag
177 }
178 
CollapseWhiteSpaces(const OUString & sName)179 OUString SwSectionData::CollapseWhiteSpaces(const OUString& sName)
180 {
181     const sal_Int32 nLen = sName.getLength();
182     const sal_Unicode cRef = ' ';
183     OUStringBuffer aBuf(nLen+1);
184     for (sal_Int32 i = 0; i<nLen; )
185     {
186         const sal_Unicode cCur = sName[i++];
187         aBuf.append(cCur);
188         if (cCur!=cRef)
189             continue;
190         while (i<nLen && sName[i]==cRef)
191             ++i;
192     }
193     return aBuf.makeStringAndClear();
194 }
195 
SwSection(SectionType const eType,OUString const & rName,SwSectionFormat & rFormat)196 SwSection::SwSection(
197         SectionType const eType, OUString const& rName, SwSectionFormat & rFormat)
198     : SwClient(& rFormat)
199     , m_Data(eType, rName)
200 {
201     StartListening(rFormat.GetNotifier());
202 
203     SwSection *const pParentSect = GetParent();
204     if( pParentSect )
205     {
206         // edit in readonly sections
207         m_Data.SetEditInReadonlyFlag( pParentSect->IsEditInReadonlyFlag() );
208     }
209 
210     m_Data.SetProtectFlag( rFormat.GetProtect().IsContentProtected() );
211 
212     if (!m_Data.IsEditInReadonlyFlag()) // edit in readonly sections
213     {
214         m_Data.SetEditInReadonlyFlag( rFormat.GetEditInReadonly().GetValue() );
215     }
216 }
217 
~SwSection()218 SwSection::~SwSection()
219 {
220     SwSectionFormat* pFormat = GetFormat();
221     if( !pFormat )
222         return;
223 
224     SwDoc* pDoc = pFormat->GetDoc();
225     if( pDoc->IsInDtor() )
226     {
227         // We reattach our Format to the default FrameFormat
228         // to not get any dependencies
229         if( pFormat->DerivedFrom() != pDoc->GetDfltFrameFormat() )
230             pFormat->RegisterToFormat( *pDoc->GetDfltFrameFormat() );
231     }
232     else
233     {
234         pFormat->Remove( this ); // remove
235         SvtListener::EndListeningAll();
236 
237         if (SectionType::Content != m_Data.GetType())
238         {
239             pDoc->getIDocumentLinksAdministration().GetLinkManager().Remove( m_RefLink.get() );
240         }
241 
242         if (m_RefObj.is())
243         {
244             pDoc->getIDocumentLinksAdministration().GetLinkManager().RemoveServer( m_RefObj.get() );
245         }
246 
247         // If the Section is the last Client in the Format we can delete it
248         pFormat->RemoveAllUnos();
249         if( !pFormat->HasWriterListeners() )
250         {
251             // Do not add to the Undo. This should've happened earlier.
252             ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
253             pDoc->DelSectionFormat( pFormat );
254         }
255     }
256     if (m_RefObj.is())
257     {
258         m_RefObj->Closed();
259     }
260 }
261 
SetSectionData(SwSectionData const & rData)262 void SwSection::SetSectionData(SwSectionData const& rData)
263 {
264     bool const bOldHidden( m_Data.IsHidden() );
265     m_Data = rData;
266     // The next two may actually overwrite the m_Data.m_bProtect or EditInReadonly Flag
267     // in Modify, which should result in same flag value as the old code!
268     SetProtect(m_Data.IsProtectFlag());
269     SetEditInReadonly(m_Data.IsEditInReadonlyFlag());
270     if (bOldHidden != m_Data.IsHidden()) // check if changed...
271     {
272         ImplSetHiddenFlag(m_Data.IsHidden(), m_Data.IsCondHidden());
273     }
274 }
275 
DataEquals(SwSectionData const & rCmp) const276 bool SwSection::DataEquals(SwSectionData const& rCmp) const
277 {
278     // note that the old code compared the flags of the parameter with the
279     // format attributes of this; the following mess should do the same...
280     (void) GetLinkFileName(); // updates m_sLinkFileName
281     bool const bProtect(m_Data.IsProtectFlag());
282     bool const bEditInReadonly(m_Data.IsEditInReadonlyFlag());
283     m_Data.SetProtectFlag(IsProtect());
284     m_Data.SetEditInReadonlyFlag(IsEditInReadonly());
285     bool const bResult( m_Data == rCmp );
286     m_Data.SetProtectFlag(bProtect);
287     m_Data.SetEditInReadonlyFlag(bEditInReadonly);
288     return bResult;
289 }
290 
ImplSetHiddenFlag(bool const bTmpHidden,bool const bCondition)291 void SwSection::ImplSetHiddenFlag(bool const bTmpHidden, bool const bCondition)
292 {
293     SwSectionFormat* pFormat = GetFormat();
294     OSL_ENSURE(pFormat, "ImplSetHiddenFlag: no format?");
295     if( !pFormat )
296         return;
297 
298     const bool bHide = bTmpHidden && bCondition;
299 
300     if (bHide) // should be hidden
301     {
302         if (!m_Data.IsHiddenFlag()) // is not hidden
303         {
304             // Is the Parent hidden?
305             // This should be shown by the bHiddenFlag.
306 
307             // Tell all Children that they are hidden
308             const SwMsgPoolItem aMsgItem( RES_SECTION_HIDDEN );
309             pFormat->CallSwClientNotify(sw::LegacyModifyHint(&aMsgItem, &aMsgItem));
310 
311             // Delete all Frames
312             pFormat->DelFrames();
313         }
314     }
315     else if (m_Data.IsHiddenFlag()) // show Nodes again
316     {
317         // Show all Frames (Child Sections are accounted for by MakeFrames)
318         // Only if the Parent Section is not restricting us!
319         SwSection* pParentSect = pFormat->GetParentSection();
320         if( !pParentSect || !pParentSect->IsHiddenFlag() )
321         {
322             // Tell all Children that the Parent is not hidden anymore
323             const SwMsgPoolItem aMsgItem( RES_SECTION_NOT_HIDDEN );
324             pFormat->CallSwClientNotify(sw::LegacyModifyHint(&aMsgItem, &aMsgItem));
325 
326             pFormat->MakeFrames();
327         }
328     }
329 }
330 
CalcHiddenFlag() const331 bool SwSection::CalcHiddenFlag() const
332 {
333     const SwSection* pSect = this;
334     do {
335         if( pSect->IsHidden() && pSect->IsCondHidden() )
336             return true;
337     } while( nullptr != ( pSect = pSect->GetParent()) );
338 
339     return false;
340 }
341 
IsProtect() const342 bool SwSection::IsProtect() const
343 {
344     SwSectionFormat const *const pFormat( GetFormat() );
345     OSL_ENSURE(pFormat, "SwSection::IsProtect: no format?");
346     return pFormat
347         ?   pFormat->GetProtect().IsContentProtected()
348         :   IsProtectFlag();
349 }
350 
351 // edit in readonly sections
IsEditInReadonly() const352 bool SwSection::IsEditInReadonly() const
353 {
354     SwSectionFormat const *const pFormat( GetFormat() );
355     OSL_ENSURE(pFormat, "SwSection::IsEditInReadonly: no format?");
356     return pFormat
357         ?   pFormat->GetEditInReadonly().GetValue()
358         :   IsEditInReadonlyFlag();
359 }
360 
SetHidden(bool const bFlag)361 void SwSection::SetHidden(bool const bFlag)
362 {
363     if (!m_Data.IsHidden() == !bFlag)
364         return;
365 
366     m_Data.SetHidden(bFlag);
367     ImplSetHiddenFlag(bFlag, m_Data.IsCondHidden());
368 }
369 
SetProtect(bool const bFlag)370 void SwSection::SetProtect(bool const bFlag)
371 {
372     SwSectionFormat *const pFormat( GetFormat() );
373     OSL_ENSURE(pFormat, "SwSection::SetProtect: no format?");
374     if (pFormat)
375     {
376         SvxProtectItem aItem( RES_PROTECT );
377         aItem.SetContentProtect( bFlag );
378         pFormat->SetFormatAttr( aItem );
379         // note: this will call m_Data.SetProtectFlag via Modify!
380     }
381     else
382     {
383         m_Data.SetProtectFlag(bFlag);
384     }
385 }
386 
387 // edit in readonly sections
SetEditInReadonly(bool const bFlag)388 void SwSection::SetEditInReadonly(bool const bFlag)
389 {
390     SwSectionFormat *const pFormat( GetFormat() );
391     OSL_ENSURE(pFormat, "SwSection::SetEditInReadonly: no format?");
392     if (pFormat)
393     {
394         SwFormatEditInReadonly aItem;
395         aItem.SetValue( bFlag );
396         pFormat->SetFormatAttr( aItem );
397         // note: this will call m_Data.SetEditInReadonlyFlag via Modify!
398     }
399     else
400     {
401         m_Data.SetEditInReadonlyFlag(bFlag);
402     }
403 }
404 
SwClientNotify(const SwModify &,const SfxHint & rHint)405 void SwSection::SwClientNotify(const SwModify&, const SfxHint& rHint)
406 {
407     Notify(rHint);
408 }
409 
Notify(SfxHint const & rHint)410 void SwSection::Notify(SfxHint const& rHint)
411 {
412     if (rHint.GetId() != SfxHintId::SwLegacyModify)
413         return;
414     auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
415     auto pOld = pLegacy->m_pOld;
416     auto pNew = pLegacy->m_pNew;
417     bool bUpdateFootnote = false;
418     switch(pLegacy->GetWhich())
419     {
420     case RES_ATTRSET_CHG:
421         if (pNew && pOld)
422         {
423             SfxItemSet* pNewSet = const_cast<SwAttrSetChg*>(static_cast<const SwAttrSetChg*>(pNew))->GetChgSet();
424             SfxItemSet* pOldSet = const_cast<SwAttrSetChg*>(static_cast<const SwAttrSetChg*>(pOld))->GetChgSet();
425             const SfxPoolItem* pItem;
426 
427             if( SfxItemState::SET == pNewSet->GetItemState(
428                         RES_PROTECT, false, &pItem ) )
429             {
430                 m_Data.SetProtectFlag( static_cast<SvxProtectItem const*>(pItem)
431                         ->IsContentProtected() );
432                 pNewSet->ClearItem( RES_PROTECT );
433                 pOldSet->ClearItem( RES_PROTECT );
434             }
435 
436             // --> edit in readonly sections
437             if( SfxItemState::SET == pNewSet->GetItemState(
438                         RES_EDIT_IN_READONLY, false, &pItem ) )
439             {
440                 m_Data.SetEditInReadonlyFlag(
441                     static_cast<SwFormatEditInReadonly const*>(pItem)->GetValue());
442                 pNewSet->ClearItem( RES_EDIT_IN_READONLY );
443                 pOldSet->ClearItem( RES_EDIT_IN_READONLY );
444             }
445 
446             if( SfxItemState::SET == pNewSet->GetItemState(
447                         RES_FTN_AT_TXTEND, false, &pItem ) ||
448                 SfxItemState::SET == pNewSet->GetItemState(
449                         RES_END_AT_TXTEND, false, &pItem ))
450             {
451                     bUpdateFootnote = true;
452             }
453 
454             if( !pNewSet->Count() )
455                 return;
456         }
457         break;
458 
459     case RES_PROTECT:
460         if( pNew )
461         {
462             bool bNewFlag =
463                 static_cast<const SvxProtectItem*>(pNew)->IsContentProtected();
464             // this used to inherit the flag from the parent, but then there is
465             // no way to turn it off in an inner section
466             m_Data.SetProtectFlag( bNewFlag );
467         }
468         return;
469     // edit in readonly sections
470     case RES_EDIT_IN_READONLY:
471         if( pNew )
472         {
473             const bool bNewFlag =
474                 static_cast<const SwFormatEditInReadonly*>(pNew)->GetValue();
475             m_Data.SetEditInReadonlyFlag( bNewFlag );
476         }
477         return;
478 
479     case RES_SECTION_HIDDEN:
480         m_Data.SetHiddenFlag(true);
481         return;
482 
483     case RES_SECTION_NOT_HIDDEN:
484         m_Data.SetHiddenFlag( m_Data.IsHidden() && m_Data.IsCondHidden() );
485         return;
486 
487     case RES_COL:
488         // Is handled by the Layout, if appropriate
489         break;
490 
491     case RES_FTN_AT_TXTEND:
492         if( pNew && pOld )
493         {
494             bUpdateFootnote = true;
495         }
496         break;
497 
498     case RES_END_AT_TXTEND:
499         if( pNew && pOld )
500         {
501             bUpdateFootnote = true;
502         }
503         break;
504 
505     default:
506         CheckRegistration( pOld );
507         break;
508     }
509 
510     if( bUpdateFootnote )
511     {
512         SwSectionNode* pSectNd = GetFormat()->GetSectionNode();
513         if( pSectNd )
514             pSectNd->GetDoc().GetFootnoteIdxs().UpdateFootnote(SwNodeIndex( *pSectNd ));
515     }
516 }
517 
SetRefObject(SwServerObject * pObj)518 void SwSection::SetRefObject( SwServerObject* pObj )
519 {
520     m_RefObj = pObj;
521 }
522 
SetCondHidden(bool const bFlag)523 void SwSection::SetCondHidden(bool const bFlag)
524 {
525     if (!m_Data.IsCondHidden() == !bFlag)
526         return;
527 
528     m_Data.SetCondHidden(bFlag);
529     ImplSetHiddenFlag(m_Data.IsHidden(), bFlag);
530 }
531 
532 // Set/remove the linked FileName
GetLinkFileName() const533 OUString const & SwSection::GetLinkFileName() const
534 {
535     if (m_RefLink.is())
536     {
537         OUString sTmp;
538         switch (m_Data.GetType())
539         {
540         case SectionType::DdeLink:
541             sTmp = m_RefLink->GetLinkSourceName();
542             break;
543 
544         case SectionType::FileLink:
545             {
546                 OUString sRange;
547                 OUString sFilter;
548                 if (m_RefLink->GetLinkManager() &&
549                     sfx2::LinkManager::GetDisplayNames(
550                         m_RefLink.get(), nullptr, &sTmp, &sRange, &sFilter ))
551                 {
552                     sTmp += OUStringChar(sfx2::cTokenSeparator) + sFilter
553                         + OUStringChar(sfx2::cTokenSeparator) + sRange;
554                 }
555                 else if( GetFormat() && !GetFormat()->GetSectionNode() )
556                 {
557                     // If the Section is in the UndoNodesArray, the LinkManager
558                     // does not contain the Link, thus it cannot be queried for it.
559                     // Thus return the current Name.
560                     return m_Data.GetLinkFileName();
561                 }
562             }
563             break;
564         default: break;
565         }
566         m_Data.SetLinkFileName(sTmp);
567     }
568     return m_Data.GetLinkFileName();
569 }
570 
SetLinkFileName(const OUString & rNew)571 void SwSection::SetLinkFileName(const OUString& rNew)
572 {
573     if (m_RefLink.is())
574     {
575         m_RefLink->SetLinkSourceName( rNew );
576     }
577     m_Data.SetLinkFileName(rNew);
578 }
579 
580 // If it was a Linked Section, we need to make all Child Links visible
MakeChildLinksVisible(const SwSectionNode & rSectNd)581 void SwSection::MakeChildLinksVisible( const SwSectionNode& rSectNd )
582 {
583     const SwNode* pNd;
584     const ::sfx2::SvBaseLinks& rLnks = rSectNd.GetDoc().getIDocumentLinksAdministration().GetLinkManager().GetLinks();
585     for( auto n = rLnks.size(); n; )
586     {
587         sfx2::SvBaseLink& rBLnk = *rLnks[--n];
588         if (!rBLnk.IsVisible() && dynamic_cast<const SwBaseLink*>(&rBLnk) != nullptr
589             && nullptr != (pNd = static_cast<SwBaseLink&>(rBLnk).GetAnchor()))
590         {
591             pNd = pNd->StartOfSectionNode(); // If it's a SectionNode
592             const SwSectionNode* pParent;
593             while( nullptr != ( pParent = pNd->FindSectionNode() ) &&
594                     ( SectionType::Content == pParent->GetSection().GetType()
595                         || pNd == &rSectNd ))
596                     pNd = pParent->StartOfSectionNode();
597 
598             // It's within a normal Section, so show again
599             if( !pParent )
600                 rBLnk.SetVisible(true);
601         }
602     }
603 }
604 
GetTOXBase() const605 const SwTOXBase* SwSection::GetTOXBase() const
606 {
607     const SwTOXBase* pRet = nullptr;
608     if( SectionType::ToxContent == GetType() )
609         pRet = dynamic_cast<const SwTOXBaseSection*>(this);
610     return pRet;
611 }
612 
SwSectionFormat(SwFrameFormat * pDrvdFrame,SwDoc * pDoc)613 SwSectionFormat::SwSectionFormat( SwFrameFormat* pDrvdFrame, SwDoc *pDoc )
614     : SwFrameFormat( pDoc->GetAttrPool(), OUString(), pDrvdFrame )
615 {
616     LockModify();
617     SetFormatAttr( *GetDfltAttr( RES_COL ) );
618     UnlockModify();
619 }
620 
~SwSectionFormat()621 SwSectionFormat::~SwSectionFormat()
622 {
623     if( GetDoc()->IsInDtor() )
624         return;
625 
626     SwSectionNode* pSectNd;
627     const SwNodeIndex* pIdx = GetContent( false ).GetContentIdx();
628     if( pIdx && &GetDoc()->GetNodes() == &pIdx->GetNodes() &&
629         nullptr != (pSectNd = pIdx->GetNode().GetSectionNode() ))
630     {
631         SwSection& rSect = pSectNd->GetSection();
632         // If it was a linked Section, we need to make all Child Links
633         // visible again
634         if( rSect.IsConnected() )
635             SwSection::MakeChildLinksVisible( *pSectNd );
636 
637         // Check whether we need to be visible, before deleting the Nodes
638         if( rSect.IsHiddenFlag() )
639         {
640             SwSection* pParentSect = rSect.GetParent();
641             if( !pParentSect || !pParentSect->IsHiddenFlag() )
642             {
643                 // Make Nodes visible again
644                 rSect.SetHidden(false);
645             }
646         }
647         // mba: test iteration; objects are removed while iterating
648         // use hint which allows to specify, if the content shall be saved or not
649         CallSwClientNotify( SwSectionFrameMoveAndDeleteHint( true ) );
650 
651         // Raise the Section up
652         SwNodeRange aRg( *pSectNd, 0, *pSectNd->EndOfSectionNode() );
653         GetDoc()->GetNodes().SectionUp( &aRg );
654     }
655     LockModify();
656     ResetFormatAttr( RES_CNTNT );
657     UnlockModify();
658 }
659 
GetSection() const660 SwSection * SwSectionFormat::GetSection() const
661 {
662     return SwIterator<SwSection,SwSectionFormat>( *this ).First();
663 }
664 
665 // Do not destroy all Frames in aDepend (Frames are recognized with a dynamic_cast).
DelFrames()666 void SwSectionFormat::DelFrames()
667 {
668     SwSectionNode* pSectNd;
669     const SwNodeIndex* pIdx = GetContent(false).GetContentIdx();
670     if( pIdx && &GetDoc()->GetNodes() == &pIdx->GetNodes() &&
671         nullptr != (pSectNd = pIdx->GetNode().GetSectionNode() ))
672     {
673         // First delete the <SwSectionFrame> of the <SwSectionFormat> instance
674         // mba: test iteration as objects are removed in iteration
675         // use hint which allows to specify, if the content shall be saved or not
676         CallSwClientNotify( SwSectionFrameMoveAndDeleteHint( false ) );
677 
678         // Then delete frames of the nested <SwSectionFormat> instances
679         SwIterator<SwSectionFormat,SwSectionFormat> aIter( *this );
680         SwSectionFormat *pLast = aIter.First();
681         while ( pLast )
682         {
683             pLast->DelFrames();
684             pLast = aIter.Next();
685         }
686 
687         sal_uLong nEnd = pSectNd->EndOfSectionIndex();
688         sal_uLong nStart = pSectNd->GetIndex()+1;
689         sw_DeleteFootnote( pSectNd, nStart, nEnd );
690     }
691     if( !pIdx )
692         return;
693 
694     // Send Hint for PageDesc. Actually the Layout contained in the
695     // Paste of the Frame itself would need to do this. But that leads
696     // to subsequent errors, which we'd need to solve at run-time.
697     SwNodeIndex aNextNd( *pIdx );
698     SwContentNode* pCNd = GetDoc()->GetNodes().GoNextSection( &aNextNd, true, false );
699     if( pCNd )
700     {
701         const SfxPoolItem& rItem = pCNd->GetSwAttrSet().Get(RES_PAGEDESC);
702         pCNd->CallSwClientNotify(sw::LegacyModifyHint(&rItem, &rItem));
703     }
704 }
705 
706 // Create the Views
MakeFrames()707 void SwSectionFormat::MakeFrames()
708 {
709     SwSectionNode* pSectNd;
710     const SwNodeIndex* pIdx = GetContent(false).GetContentIdx();
711 
712     if( pIdx && &GetDoc()->GetNodes() == &pIdx->GetNodes() &&
713         nullptr != (pSectNd = pIdx->GetNode().GetSectionNode() ))
714     {
715         SwNodeIndex aIdx( *pIdx );
716         pSectNd->MakeOwnFrames( &aIdx );
717     }
718 }
719 
SwClientNotify(const SwModify & rMod,const SfxHint & rHint)720 void SwSectionFormat::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
721 {
722     if (rHint.GetId() != SfxHintId::SwLegacyModify)
723         return;
724     auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
725     sal_uInt16 nWhich = pLegacy->GetWhich();
726     auto pOld = pLegacy->m_pOld;
727     auto pNew = pLegacy->m_pNew;
728     switch( nWhich )
729     {
730     case RES_ATTRSET_CHG:
731         if (HasWriterListeners() && pOld && pNew)
732         {
733             SfxItemSet* pNewSet = const_cast<SwAttrSetChg*>(static_cast<const SwAttrSetChg*>(pNew))->GetChgSet();
734             SfxItemSet* pOldSet = const_cast<SwAttrSetChg*>(static_cast<const SwAttrSetChg*>(pOld))->GetChgSet();
735             const SfxPoolItem *pItem;
736             if( SfxItemState::SET == pNewSet->GetItemState(
737                                         RES_PROTECT, false, &pItem ))
738             {
739                 GetNotifier().Broadcast(sw::LegacyModifyHint(pItem, pItem));
740                 pNewSet->ClearItem( RES_PROTECT );
741                 pOldSet->ClearItem( RES_PROTECT );
742             }
743 
744             // --> edit in readonly sections
745             if( SfxItemState::SET == pNewSet->GetItemState(
746                         RES_EDIT_IN_READONLY, false, &pItem ) )
747             {
748                 GetNotifier().Broadcast(sw::LegacyModifyHint(pItem, pItem));
749                 pNewSet->ClearItem( RES_EDIT_IN_READONLY );
750                 pOldSet->ClearItem( RES_EDIT_IN_READONLY );
751             }
752 
753             if( SfxItemState::SET == pNewSet->GetItemState(
754                                     RES_FTN_AT_TXTEND, false, &pItem ))
755             {
756                 GetNotifier().Broadcast(sw::LegacyModifyHint(pItem, pItem));
757                 pNewSet->ClearItem( RES_FTN_AT_TXTEND );
758                 pOldSet->ClearItem( RES_FTN_AT_TXTEND );
759             }
760             if( SfxItemState::SET == pNewSet->GetItemState(
761                                     RES_END_AT_TXTEND, false, &pItem ))
762             {
763                 GetNotifier().Broadcast(sw::LegacyModifyHint(pItem, pItem));
764                 pNewSet->ClearItem( RES_END_AT_TXTEND );
765                 pOldSet->ClearItem( RES_END_AT_TXTEND );
766             }
767             if( !static_cast<const SwAttrSetChg*>(pOld)->GetChgSet()->Count() )
768                 return;
769         }
770         break;
771 
772     case RES_SECTION_HIDDEN:
773     case RES_SECTION_NOT_HIDDEN:
774         {
775             auto pSect = GetSection();
776             if(!pSect || (RES_SECTION_HIDDEN == nWhich) == pSect->IsHiddenFlag()) // already at target state, skipping.
777                 return;
778         }
779         [[fallthrough]];
780     case RES_FTN_AT_TXTEND:
781     case RES_END_AT_TXTEND:
782         GetNotifier().Broadcast(sw::LegacyModifyHint(pOld, pNew));
783         return;
784     case RES_PROTECT:
785     case RES_EDIT_IN_READONLY: // edit in readonly sections
786         // Pass through these Messages until the End of the tree!
787         GetNotifier().Broadcast(sw::LegacyModifyHint(pOld, pNew));
788         return; // That's it!
789 
790     case RES_OBJECTDYING:
791         if( !GetDoc()->IsInDtor() && pOld &&
792             static_cast<const SwPtrMsgPoolItem *>(pOld)->pObject == static_cast<void*>(GetRegisteredIn()) )
793         {
794             // My Parents will be destroyed, so get the Parent's Parent
795             // and update
796             SwFrameFormat::SwClientNotify(rMod, rHint);
797             UpdateParent();
798             return;
799         }
800         break;
801 
802     case RES_FMT_CHG:
803         if( !GetDoc()->IsInDtor() &&
804             static_cast<const SwFormatChg*>(pNew)->pChangedFormat == static_cast<void*>(GetRegisteredIn()) &&
805             dynamic_cast<const SwSectionFormat*>(static_cast<const SwFormatChg*>(pNew)->pChangedFormat) != nullptr )
806         {
807             // My Parent will be changed, thus I need to update
808             SwFrameFormat::SwClientNotify(rMod, rHint);
809             UpdateParent();
810             return;
811         }
812         break;
813     }
814     SwFrameFormat::SwClientNotify(rMod, rHint);
815 
816     if (pOld && (RES_REMOVE_UNO_OBJECT == pOld->Which()))
817     {   // invalidate cached uno object
818         SetXTextSection(uno::Reference<text::XTextSection>(nullptr));
819     }
820 }
821 
822 // Get info from the Format
GetInfo(SfxPoolItem & rInfo) const823 bool SwSectionFormat::GetInfo( SfxPoolItem& rInfo ) const
824 {
825     switch( rInfo.Which() )
826     {
827     case RES_FINDNEARESTNODE:
828         if( GetFormatAttr( RES_PAGEDESC ).GetPageDesc() )
829         {
830             const SwSectionNode* pNd = GetSectionNode();
831             if( pNd )
832                 static_cast<SwFindNearestNode&>(rInfo).CheckNode( *pNd );
833         }
834         return true;
835 
836     case RES_CONTENT_VISIBLE:
837         {
838             SwFrame* pFrame = SwIterator<SwFrame,SwFormat>(*this).First();
839             // if the current section has no own frame search for the children
840             if(!pFrame)
841             {
842                 SwIterator<SwSectionFormat,SwSectionFormat> aFormatIter(*this);
843                 SwSectionFormat* pChild = aFormatIter.First();
844                 while(pChild && !pFrame)
845                 {
846                     pFrame = SwIterator<SwFrame,SwFormat>(*pChild).First();
847                     pChild = aFormatIter.Next();
848                 }
849             }
850             static_cast<SwPtrMsgPoolItem&>(rInfo).pObject = pFrame;
851         }
852         return false;
853     }
854     return sw::BroadcastingModify::GetInfo( rInfo );
855 }
856 
lcl_SectionCmpPos(const SwSection * pFirst,const SwSection * pSecond)857 static bool lcl_SectionCmpPos( const SwSection *pFirst, const SwSection *pSecond)
858 {
859     const SwSectionFormat* pFSectFormat = pFirst->GetFormat();
860     const SwSectionFormat* pSSectFormat = pSecond->GetFormat();
861     OSL_ENSURE( pFSectFormat && pSSectFormat &&
862             pFSectFormat->GetContent(false).GetContentIdx() &&
863             pSSectFormat->GetContent(false).GetContentIdx(),
864                 "Invalid sections" );
865     return pFSectFormat->GetContent(false).GetContentIdx()->GetIndex() <
866                   pSSectFormat->GetContent(false).GetContentIdx()->GetIndex();
867 }
868 
869 // get all Sections that have been derived from this one
GetChildSections(SwSections & rArr,SectionSort eSort,bool bAllSections) const870 void SwSectionFormat::GetChildSections( SwSections& rArr,
871                                         SectionSort eSort,
872                                         bool bAllSections ) const
873 {
874     rArr.clear();
875 
876     if( !HasWriterListeners() )
877         return;
878 
879     SwIterator<SwSectionFormat,SwSectionFormat> aIter(*this);
880     const SwNodeIndex* pIdx;
881     for( SwSectionFormat* pLast = aIter.First(); pLast; pLast = aIter.Next() )
882         if( bAllSections ||
883             ( nullptr != ( pIdx = pLast->GetContent(false).
884             GetContentIdx()) && &pIdx->GetNodes() == &GetDoc()->GetNodes() ))
885         {
886             SwSection* pDummy = pLast->GetSection();
887             rArr.push_back( pDummy );
888         }
889 
890     // Do we need any sorting?
891     if( 1 < rArr.size() )
892         switch( eSort )
893         {
894         case SectionSort::Pos:
895             std::sort( rArr.begin(), rArr.end(), lcl_SectionCmpPos );
896             break;
897         case SectionSort::Not: break;
898         }
899 }
900 
901 // See whether the Section is within the Nodes or the UndoNodes array
IsInNodesArr() const902 bool SwSectionFormat::IsInNodesArr() const
903 {
904     const SwNodeIndex* pIdx = GetContent(false).GetContentIdx();
905     return pIdx && &pIdx->GetNodes() == &GetDoc()->GetNodes();
906 }
907 
908 // Parent was changed
UpdateParent()909 void SwSectionFormat::UpdateParent()
910 {
911     if(!HasWriterListeners())
912         return;
913 
914     const SwSection* pSection = GetSection();
915     const SvxProtectItem* pProtect = &GetProtect();
916     // edit in readonly sections
917     const SwFormatEditInReadonly* pEditInReadonly = &GetEditInReadonly();
918     bool bIsHidden = pSection->IsHidden();
919     if(GetRegisteredIn())
920     {
921         const SwSection* pPS = GetParentSection();
922         pProtect = &pPS->GetFormat()->GetProtect();
923         pEditInReadonly = &pPS->GetFormat()->GetEditInReadonly();
924         bIsHidden = pPS->IsHiddenFlag();
925     }
926     SwIterator<SwSectionFormat,SwSectionFormat> aIter(*this);
927     if(!pProtect->IsContentProtected() != !pSection->IsProtectFlag())
928         CallSwClientNotify(sw::LegacyModifyHint(pProtect, pProtect));
929 
930     // edit in readonly sections
931     if(!pEditInReadonly->GetValue() != !pSection->IsEditInReadonlyFlag())
932         CallSwClientNotify(sw::LegacyModifyHint(pEditInReadonly, pEditInReadonly));
933 
934     if(bIsHidden == pSection->IsHiddenFlag())
935     {
936         SwMsgPoolItem aMsgItem(o3tl::narrowing<sal_uInt16>(bIsHidden
937                 ? RES_SECTION_HIDDEN
938                 : RES_SECTION_NOT_HIDDEN));
939         CallSwClientNotify(sw::LegacyModifyHint(&aMsgItem, &aMsgItem));
940     }
941 }
942 
GetSectionNode()943 SwSectionNode* SwSectionFormat::GetSectionNode()
944 {
945     const SwNodeIndex* pIdx = GetContent(false).GetContentIdx();
946     if( pIdx && ( &pIdx->GetNodes() == &GetDoc()->GetNodes() ))
947         return pIdx->GetNode().GetSectionNode();
948     return nullptr;
949 }
950 
951 // Is this Section valid for the GlobalDocument?
GetGlobalDocSection() const952 const SwSection* SwSectionFormat::GetGlobalDocSection() const
953 {
954     const SwSectionNode* pNd = GetSectionNode();
955     if( pNd &&
956         ( SectionType::FileLink == pNd->GetSection().GetType() ||
957           SectionType::ToxContent == pNd->GetSection().GetType() ) &&
958         pNd->GetIndex() > pNd->GetNodes().GetEndOfExtras().GetIndex() &&
959         !pNd->StartOfSectionNode()->IsSectionNode() &&
960         !pNd->StartOfSectionNode()->FindSectionNode() )
961         return &pNd->GetSection();
962     return nullptr;
963 }
964 
965 // sw::Metadatable
GetRegistry()966 ::sfx2::IXmlIdRegistry& SwSectionFormat::GetRegistry()
967 {
968     return GetDoc()->GetXmlIdRegistry();
969 }
970 
IsInClipboard() const971 bool SwSectionFormat::IsInClipboard() const
972 {
973     return GetDoc()->IsClipBoard();
974 }
975 
IsInUndo() const976 bool SwSectionFormat::IsInUndo() const
977 {
978     return !IsInNodesArr();
979 }
980 
IsInContent() const981 bool SwSectionFormat::IsInContent() const
982 {
983     SwNodeIndex const*const pIdx = GetContent(false).GetContentIdx();
984     OSL_ENSURE(pIdx, "SwSectionFormat::IsInContent: no index?");
985     return pIdx == nullptr || !GetDoc()->IsInHeaderFooter(*pIdx);
986 }
987 
988 // n.b.: if the section format represents an index, then there is both a
989 // SwXDocumentIndex and a SwXTextSection instance for this single core object.
990 // these two can both implement XMetadatable and forward to the same core
991 // section format.  but here only one UNO object can be returned,
992 // so always return the text section.
993 uno::Reference< rdf::XMetadatable >
MakeUnoObject()994 SwSectionFormat::MakeUnoObject()
995 {
996     uno::Reference<rdf::XMetadatable> xMeta;
997     SwSection *const pSection( GetSection() );
998     if (pSection)
999     {
1000         xMeta.set(  SwXTextSection::CreateXTextSection(this,
1001                         SectionType::ToxHeader == pSection->GetType()),
1002                     uno::UNO_QUERY );
1003     }
1004     return xMeta;
1005 }
1006 
supportsFullDrawingLayerFillAttributeSet() const1007 bool SwSectionFormat::supportsFullDrawingLayerFillAttributeSet() const
1008 {
1009     return false;
1010 }
1011 
dumpAsXml(xmlTextWriterPtr pWriter) const1012 void SwSectionFormat::dumpAsXml(xmlTextWriterPtr pWriter) const
1013 {
1014     (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwSectionFormat"));
1015     (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("name"), BAD_CAST(GetName().toUtf8().getStr()));
1016     GetAttrSet().dumpAsXml(pWriter);
1017     (void)xmlTextWriterEndElement(pWriter);
1018 }
1019 
dumpAsXml(xmlTextWriterPtr pWriter) const1020 void SwSectionFormats::dumpAsXml(xmlTextWriterPtr pWriter) const
1021 {
1022     (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwSectionFormats"));
1023     for (size_t i = 0; i < size(); ++i)
1024         GetFormat(i)->dumpAsXml(pWriter);
1025     (void)xmlTextWriterEndElement(pWriter);
1026 }
1027 
1028 // Method to break section links inside a linked section
lcl_BreakSectionLinksInSect(const SwSectionNode & rSectNd)1029 static void lcl_BreakSectionLinksInSect( const SwSectionNode& rSectNd )
1030 {
1031     if ( !rSectNd.GetSection().IsConnected() )
1032     {
1033         OSL_FAIL( "method <lcl_RemoveSectionLinksInSect(..)> - no Link at Section of SectionNode" );
1034         return;
1035     }
1036     const ::sfx2::SvBaseLink* pOwnLink( &(rSectNd.GetSection().GetBaseLink() ) );
1037     const ::sfx2::SvBaseLinks& rLnks = rSectNd.GetDoc().getIDocumentLinksAdministration().GetLinkManager().GetLinks();
1038     for ( auto n = rLnks.size(); n > 0; )
1039     {
1040         SwIntrnlSectRefLink* pSectLnk = dynamic_cast<SwIntrnlSectRefLink*>(&(*rLnks[ --n ]));
1041         if ( pSectLnk && pSectLnk != pOwnLink &&
1042              pSectLnk->IsInRange( rSectNd.GetIndex(), rSectNd.EndOfSectionIndex() ) )
1043         {
1044             // break the link of the corresponding section.
1045             // the link is also removed from the link manager
1046             SwSectionNode* pSectNode = pSectLnk->GetSectNode();
1047             assert(pSectNode);
1048             pSectNode->GetSection().BreakLink();
1049 
1050             // for robustness, because link is removed from the link manager
1051             if ( n > rLnks.size() )
1052             {
1053                 n = rLnks.size();
1054             }
1055         }
1056     }
1057 }
1058 
lcl_UpdateLinksInSect(SwBaseLink & rUpdLnk,SwSectionNode & rSectNd)1059 static void lcl_UpdateLinksInSect( SwBaseLink& rUpdLnk, SwSectionNode& rSectNd )
1060 {
1061     SwDoc& rDoc = rSectNd.GetDoc();
1062     SwDocShell* pDShell = rDoc.GetDocShell();
1063     if( !pDShell || !pDShell->GetMedium() )
1064         return ;
1065 
1066     const OUString sName( pDShell->GetMedium()->GetName() );
1067     const OUString sMimeType( SotExchange::GetFormatMimeType( SotClipboardFormatId::SIMPLE_FILE ));
1068     uno::Any aValue;
1069     aValue <<= sName; // Arbitrary name
1070 
1071     const ::sfx2::SvBaseLinks& rLnks = rDoc.getIDocumentLinksAdministration().GetLinkManager().GetLinks();
1072     for( auto n = rLnks.size(); n; )
1073     {
1074         ::sfx2::SvBaseLink* pLnk = &(*rLnks[ --n ]);
1075         if( pLnk == &rUpdLnk )
1076             continue;
1077         if( sfx2::SvBaseLinkObjectType::ClientFile != pLnk->GetObjType() )
1078             continue;
1079         SwBaseLink* pBLink = dynamic_cast<SwBaseLink*>( pLnk );
1080         if( pBLink && pBLink->IsInRange( rSectNd.GetIndex(),
1081                                         rSectNd.EndOfSectionIndex() ) )
1082         {
1083             // It's in the Section, so update. But only if it's not in the same File!
1084             OUString sFName;
1085             sfx2::LinkManager::GetDisplayNames( pBLink, nullptr, &sFName );
1086             if( sFName != sName )
1087             {
1088                 pBLink->DataChanged( sMimeType, aValue );
1089 
1090                 // If needed find the Link pointer to avoid skipping one or calling one twice
1091                 if( n >= rLnks.size() && 0 != ( n = rLnks.size() ))
1092                     --n;
1093 
1094                 if( n && pLnk != &(*rLnks[ n ]) )
1095                 {
1096                     // Find - it can only precede it!
1097                     while( n )
1098                         if( pLnk == &(*rLnks[ --n ] ) )
1099                             break;
1100                 }
1101             }
1102         }
1103     }
1104 }
1105 
DataChanged(const OUString & rMimeType,const uno::Any & rValue)1106 ::sfx2::SvBaseLink::UpdateResult SwIntrnlSectRefLink::DataChanged(
1107     const OUString& rMimeType, const uno::Any & rValue )
1108 {
1109     SwSectionNode* pSectNd = m_rSectFormat.GetSectionNode();
1110     SwDoc* pDoc = m_rSectFormat.GetDoc();
1111 
1112     SotClipboardFormatId nDataFormat = SotExchange::GetFormatIdFromMimeType( rMimeType );
1113 
1114     if( !pSectNd || !pDoc || pDoc->IsInDtor() || ChkNoDataFlag() ||
1115         sfx2::LinkManager::RegisterStatusInfoId() == nDataFormat )
1116     {
1117         // Should we be in the Undo already?
1118         return SUCCESS;
1119     }
1120 
1121     //  #i38810# - Due to possible existing signatures, the
1122     // document has to be modified after updating a link.
1123     pDoc->getIDocumentState().SetModified();
1124     // set additional flag that links have been updated, in order to check this
1125     // during load.
1126     pDoc->getIDocumentLinksAdministration().SetLinksUpdated( true );
1127 
1128     // Always switch off Undo
1129     bool const bWasUndo = pDoc->GetIDocumentUndoRedo().DoesUndo();
1130     pDoc->GetIDocumentUndoRedo().DoUndo(false);
1131     bool bWasVisibleLinks = pDoc->getIDocumentLinksAdministration().IsVisibleLinks();
1132     pDoc->getIDocumentLinksAdministration().SetVisibleLinks( false );
1133 
1134     SwPaM* pPam;
1135     SwViewShell* pVSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
1136     SwEditShell* pESh = pDoc->GetEditShell();
1137     pDoc->getIDocumentFieldsAccess().LockExpFields();
1138     {
1139         // Insert an empty TextNode at the Section's start
1140         SwNodeIndex aIdx( *pSectNd, +1 );
1141         SwNodeIndex aEndIdx( *pSectNd->EndOfSectionNode() );
1142         SwTextNode* pNewNd = pDoc->GetNodes().MakeTextNode( aIdx,
1143                         pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT ) );
1144 
1145         if( pESh )
1146             pESh->StartAllAction();
1147         else if( pVSh )
1148             pVSh->StartAction();
1149 
1150         SwPosition aPos( aIdx, SwIndex( pNewNd, 0 ));
1151         --aPos.nNode;
1152         SwDoc::CorrAbs( aIdx, aEndIdx, aPos, true );
1153 
1154         pPam = new SwPaM( aPos );
1155 
1156         // Delete everything succeeding it
1157         --aIdx;
1158         DelFlyInRange( aIdx, aEndIdx );
1159         DelBookmarks(aIdx, aEndIdx);
1160         ++aIdx;
1161 
1162         pDoc->GetNodes().Delete( aIdx, aEndIdx.GetIndex() - aIdx.GetIndex() );
1163     }
1164 
1165     SwSection& rSection = pSectNd->GetSection();
1166     rSection.SetConnectFlag(false);
1167 
1168     Reader* pRead = nullptr;
1169     switch( nDataFormat )
1170     {
1171     case SotClipboardFormatId::STRING:
1172         pRead = ReadAscii;
1173         break;
1174 
1175     case SotClipboardFormatId::RICHTEXT:
1176     case SotClipboardFormatId::RTF:
1177         pRead = SwReaderWriter::GetRtfReader();
1178         break;
1179 
1180     case SotClipboardFormatId::SIMPLE_FILE:
1181         if ( rValue.hasValue() )
1182         {
1183             OUString sFileName;
1184             if ( !(rValue >>= sFileName) )
1185                 break;
1186             OUString sFilter;
1187             OUString sRange;
1188             sfx2::LinkManager::GetDisplayNames( this, nullptr, &sFileName,
1189                                                     &sRange, &sFilter );
1190 
1191             RedlineFlags eOldRedlineFlags = RedlineFlags::NONE;
1192             SfxObjectShellRef xDocSh;
1193             SfxObjectShellLock xLockRef;
1194             int nRet;
1195             if( sFileName.isEmpty() )
1196             {
1197                 xDocSh = pDoc->GetDocShell();
1198                 nRet = 1;
1199             }
1200             else
1201             {
1202                 nRet = SwFindDocShell( xDocSh, xLockRef, sFileName,
1203                                     rSection.GetLinkFilePassword(),
1204                                     sFilter, 0, pDoc->GetDocShell() );
1205                 if( nRet )
1206                 {
1207                     SwDoc* pSrcDoc = static_cast<SwDocShell*>( xDocSh.get() )->GetDoc();
1208                     eOldRedlineFlags = pSrcDoc->getIDocumentRedlineAccess().GetRedlineFlags();
1209                     pSrcDoc->getIDocumentRedlineAccess().SetRedlineFlags( RedlineFlags::ShowInsert );
1210                 }
1211             }
1212 
1213             if( nRet )
1214             {
1215                 rSection.SetConnectFlag();
1216 
1217                 SwNodeIndex aSave( pPam->GetPoint()->nNode, -1 );
1218                 std::unique_ptr<SwNodeRange> pCpyRg;
1219 
1220                 if( xDocSh->GetMedium() &&
1221                     rSection.GetLinkFilePassword().isEmpty() )
1222                 {
1223                     const SfxPoolItem* pItem;
1224                     if( SfxItemState::SET == xDocSh->GetMedium()->GetItemSet()->
1225                         GetItemState( SID_PASSWORD, false, &pItem ) )
1226                         rSection.SetLinkFilePassword(
1227                                 static_cast<const SfxStringItem*>(pItem)->GetValue() );
1228                 }
1229 
1230                 SwDoc* pSrcDoc = static_cast<SwDocShell*>( xDocSh.get() )->GetDoc();
1231 
1232                 if( !sRange.isEmpty() )
1233                 {
1234                     // Catch recursion
1235                     bool bRecursion = false;
1236                     if( pSrcDoc == pDoc )
1237                     {
1238                         tools::SvRef<SwServerObject> refObj( static_cast<SwServerObject*>(
1239                                         pDoc->getIDocumentLinksAdministration().CreateLinkSource( sRange )));
1240                         if( refObj.is() )
1241                         {
1242                             bRecursion = refObj->IsLinkInServer( this ) ||
1243                                         ChkNoDataFlag();
1244                         }
1245                     }
1246 
1247                     SwNodeIndex& rInsPos = pPam->GetPoint()->nNode;
1248 
1249                     SwPaM* pCpyPam = nullptr;
1250                     if( !bRecursion &&
1251                         pSrcDoc->GetDocumentLinksAdministrationManager().SelectServerObj( sRange, pCpyPam, pCpyRg )
1252                         && pCpyPam )
1253                     {
1254                         if( pSrcDoc != pDoc ||
1255                             pCpyPam->Start()->nNode > rInsPos ||
1256                             rInsPos >= pCpyPam->End()->nNode )
1257                         {
1258                             pSrcDoc->getIDocumentContentOperations().CopyRange(*pCpyPam, *pPam->GetPoint(), SwCopyFlags::CheckPosInFly);
1259                         }
1260                         delete pCpyPam;
1261                     }
1262                     if( pCpyRg && pSrcDoc == pDoc &&
1263                         pCpyRg->aStart < rInsPos && rInsPos < pCpyRg->aEnd )
1264                     {
1265                         pCpyRg.reset();
1266                     }
1267                 }
1268                 else if( pSrcDoc != pDoc )
1269                     pCpyRg.reset(new SwNodeRange( pSrcDoc->GetNodes().GetEndOfExtras(), 2,
1270                                           pSrcDoc->GetNodes().GetEndOfContent() ));
1271 
1272                 // #i81653#
1273                 // Update links of extern linked document or extern linked
1274                 // document section, if section is protected.
1275                 if ( pSrcDoc != pDoc &&
1276                      rSection.IsProtectFlag() )
1277                 {
1278                     pSrcDoc->getIDocumentLinksAdministration().GetLinkManager().UpdateAllLinks( false, false, nullptr );
1279                 }
1280 
1281                 if( pCpyRg )
1282                 {
1283                     SwNodeIndex& rInsPos = pPam->GetPoint()->nNode;
1284                     bool bCreateFrame = rInsPos.GetIndex() <=
1285                                 pDoc->GetNodes().GetEndOfExtras().GetIndex() ||
1286                                 rInsPos.GetNode().FindTableNode();
1287 
1288                     SwTableNumFormatMerge aTNFM( *pSrcDoc, *pDoc );
1289 
1290                     pSrcDoc->GetDocumentContentOperationsManager().CopyWithFlyInFly(*pCpyRg, rInsPos, nullptr, bCreateFrame);
1291                     ++aSave;
1292 
1293                     if( !bCreateFrame )
1294                         ::MakeFrames( pDoc, aSave, rInsPos );
1295 
1296                     // Delete last Node, only if it was copied successfully
1297                     // (the Section contains more than one Node)
1298                     if( 2 < pSectNd->EndOfSectionIndex() - pSectNd->GetIndex() )
1299                     {
1300                         aSave = rInsPos;
1301                         pPam->Move( fnMoveBackward, GoInNode );
1302                         pPam->SetMark(); // Rewire both SwPositions
1303 
1304                         pDoc->CorrAbs( aSave, *pPam->GetPoint(), 0, true );
1305                         pDoc->GetNodes().Delete( aSave );
1306                     }
1307                     pCpyRg.reset();
1308                 }
1309 
1310                 lcl_BreakSectionLinksInSect( *pSectNd );
1311 
1312                 // Update all Links in this Section
1313                 lcl_UpdateLinksInSect( *this, *pSectNd );
1314             }
1315             if( xDocSh.is() )
1316             {
1317                 if( 2 == nRet )
1318                     xDocSh->DoClose();
1319                 else if( static_cast<SwDocShell*>( xDocSh.get() )->GetDoc() )
1320                     static_cast<SwDocShell*>( xDocSh.get() )->GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags(
1321                                 eOldRedlineFlags );
1322             }
1323         }
1324         break;
1325     default: break;
1326     }
1327 
1328     // Only create DDE if Shell is available!
1329     uno::Sequence< sal_Int8 > aSeq;
1330     if( pRead && rValue.hasValue() && ( rValue >>= aSeq ) )
1331     {
1332         if( pESh )
1333         {
1334             pESh->Push();
1335             SwPaM* pCursor = pESh->GetCursor();
1336             *pCursor->GetPoint() = *pPam->GetPoint();
1337             delete pPam;
1338             pPam = pCursor;
1339         }
1340 
1341         SvMemoryStream aStrm( const_cast<sal_Int8 *>(aSeq.getConstArray()), aSeq.getLength(),
1342                                 StreamMode::READ );
1343         aStrm.Seek( 0 );
1344 
1345         // TODO/MBA: it's impossible to set a BaseURL here!
1346         SwReader aTmpReader( aStrm, OUString(), pDoc->GetDocShell()->GetMedium()->GetBaseURL(), *pPam );
1347 
1348         if( ! aTmpReader.Read( *pRead ).IsError() )
1349         {
1350             rSection.SetConnectFlag();
1351         }
1352 
1353         if( pESh )
1354         {
1355             pESh->Pop(SwCursorShell::PopMode::DeleteCurrent);
1356             pPam = nullptr; // pam was deleted earlier
1357         }
1358     }
1359 
1360     // remove all undo actions and turn undo on again
1361     pDoc->GetIDocumentUndoRedo().DelAllUndoObj();
1362     pDoc->GetIDocumentUndoRedo().DoUndo(bWasUndo);
1363     pDoc->getIDocumentLinksAdministration().SetVisibleLinks( bWasVisibleLinks );
1364 
1365     pDoc->getIDocumentFieldsAccess().UnlockExpFields();
1366     if( !pDoc->getIDocumentFieldsAccess().IsExpFieldsLocked() )
1367         pDoc->getIDocumentFieldsAccess().UpdateExpFields(nullptr, true);
1368 
1369     if( pESh )
1370         pESh->EndAllAction();
1371     else if( pVSh )
1372         pVSh->EndAction();
1373     delete pPam; // Was created at the start
1374 
1375     return SUCCESS;
1376 }
1377 
Closed()1378 void SwIntrnlSectRefLink::Closed()
1379 {
1380     SwDoc* pDoc = m_rSectFormat.GetDoc();
1381     if( pDoc && !pDoc->IsInDtor() )
1382     {
1383         // Advise says goodbye: mark the Section as not protected
1384         // and change the Flag
1385         const SwSectionFormats& rFormats = pDoc->GetSections();
1386         for( auto n = rFormats.size(); n; )
1387             if (rFormats[--n] == &m_rSectFormat)
1388             {
1389                 SwViewShell* pSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
1390                 SwEditShell* pESh = pDoc->GetEditShell();
1391 
1392                 if( pESh )
1393                     pESh->StartAllAction();
1394                 else
1395                     pSh->StartAction();
1396 
1397                 SwSectionData aSectionData(*m_rSectFormat.GetSection());
1398                 aSectionData.SetType( SectionType::Content );
1399                 aSectionData.SetLinkFileName( OUString() );
1400                 aSectionData.SetProtectFlag( false );
1401                 // edit in readonly sections
1402                 aSectionData.SetEditInReadonlyFlag( false );
1403 
1404                 aSectionData.SetConnectFlag( false );
1405 
1406                 pDoc->UpdateSection( n, aSectionData );
1407 
1408                 // Make all Links within the Section visible again
1409                 SwSectionNode* pSectNd = m_rSectFormat.GetSectionNode();
1410                 if( pSectNd )
1411                     SwSection::MakeChildLinksVisible( *pSectNd );
1412 
1413                 if( pESh )
1414                     pESh->EndAllAction();
1415                 else
1416                     pSh->EndAction();
1417                 break;
1418             }
1419     }
1420     SvBaseLink::Closed();
1421 }
1422 
CreateLink(LinkCreateType eCreateType)1423 void SwSection::CreateLink( LinkCreateType eCreateType )
1424 {
1425     SwSectionFormat* pFormat = GetFormat();
1426     OSL_ENSURE(pFormat, "SwSection::CreateLink: no format?");
1427     if (!pFormat || (SectionType::Content == m_Data.GetType()))
1428         return ;
1429 
1430     SfxLinkUpdateMode nUpdateType = SfxLinkUpdateMode::ALWAYS;
1431 
1432     if (!m_RefLink.is())
1433     {
1434         // create BaseLink
1435         m_RefLink = new SwIntrnlSectRefLink( *pFormat, nUpdateType );
1436     }
1437     else
1438     {
1439         pFormat->GetDoc()->getIDocumentLinksAdministration().GetLinkManager().Remove( m_RefLink.get() );
1440     }
1441 
1442     SwIntrnlSectRefLink *const pLnk =
1443         static_cast<SwIntrnlSectRefLink*>( m_RefLink.get() );
1444 
1445     const OUString sCmd(SwSectionData::CollapseWhiteSpaces(m_Data.GetLinkFileName()));
1446     pLnk->SetUpdateMode( nUpdateType );
1447     pLnk->SetVisible( pFormat->GetDoc()->getIDocumentLinksAdministration().IsVisibleLinks() );
1448 
1449     switch (m_Data.GetType())
1450     {
1451     case SectionType::DdeLink:
1452         pLnk->SetLinkSourceName( sCmd );
1453         pFormat->GetDoc()->getIDocumentLinksAdministration().GetLinkManager().InsertDDELink( pLnk );
1454         break;
1455     case SectionType::FileLink:
1456         {
1457             pLnk->SetContentType( SotClipboardFormatId::SIMPLE_FILE );
1458             sal_Int32 nIndex = 0;
1459             const OUString sFile(sCmd.getToken( 0, sfx2::cTokenSeparator, nIndex ));
1460             const OUString sFltr(sCmd.getToken( 0, sfx2::cTokenSeparator, nIndex ));
1461             const OUString sRange(sCmd.getToken( 0, sfx2::cTokenSeparator, nIndex ));
1462             pFormat->GetDoc()->getIDocumentLinksAdministration().GetLinkManager().InsertFileLink( *pLnk,
1463                                 static_cast<sfx2::SvBaseLinkObjectType>(m_Data.GetType()),
1464                                 sFile,
1465                                 ( !sFltr.isEmpty() ? &sFltr : nullptr ),
1466                                 ( !sRange.isEmpty() ? &sRange : nullptr ) );
1467         }
1468         break;
1469     default:
1470         OSL_ENSURE( false, "What kind of Link is this?" );
1471     }
1472 
1473     switch( eCreateType )
1474     {
1475     case LinkCreateType::Connect: // Connect Link right away
1476         pLnk->Connect();
1477         break;
1478 
1479     case LinkCreateType::Update: // Connect Link and update
1480         pLnk->Update();
1481         break;
1482     case LinkCreateType::NONE: break;
1483     }
1484 }
1485 
BreakLink()1486 void SwSection::BreakLink()
1487 {
1488     const SectionType eCurrentType( GetType() );
1489     if ( eCurrentType == SectionType::Content ||
1490          eCurrentType == SectionType::ToxHeader ||
1491          eCurrentType == SectionType::ToxContent )
1492     {
1493         // nothing to do
1494         return;
1495     }
1496 
1497     // Release link, if it exists
1498     if (m_RefLink.is())
1499     {
1500         SwSectionFormat *const pFormat( GetFormat() );
1501         OSL_ENSURE(pFormat, "SwSection::BreakLink: no format?");
1502         if (pFormat)
1503         {
1504             pFormat->GetDoc()->getIDocumentLinksAdministration().GetLinkManager().Remove( m_RefLink.get() );
1505         }
1506         m_RefLink.clear();
1507     }
1508     // change type
1509     SetType( SectionType::Content );
1510     // reset linked file data
1511     SetLinkFileName( OUString() );
1512     SetLinkFilePassword( OUString() );
1513 }
1514 
GetAnchor() const1515 const SwNode* SwIntrnlSectRefLink::GetAnchor() const { return m_rSectFormat.GetSectionNode(); }
1516 
IsInRange(sal_uLong nSttNd,sal_uLong nEndNd) const1517 bool SwIntrnlSectRefLink::IsInRange( sal_uLong nSttNd, sal_uLong nEndNd ) const
1518 {
1519     SwStartNode* pSttNd = m_rSectFormat.GetSectionNode();
1520     return pSttNd &&
1521             nSttNd < pSttNd->GetIndex() &&
1522             pSttNd->EndOfSectionIndex() < nEndNd;
1523 }
1524 
1525 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1526