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