xref: /core/sw/source/uibase/utlui/content.cxx (revision c0aa577d)
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 <comphelper/string.hxx>
21 #include <svl/urlbmk.hxx>
22 #include <osl/thread.h>
23 #include <sal/log.hxx>
24 #include <tools/urlobj.hxx>
25 #include <sfx2/docfile.hxx>
26 #include <sfx2/dispatch.hxx>
27 #include <sfx2/event.hxx>
28 #include <sfx2/viewfrm.hxx>
29 #include <o3tl/enumrange.hxx>
30 #include <o3tl/sorted_vector.hxx>
31 #include <vcl/commandevent.hxx>
32 #include <vcl/weldutils.hxx>
33 #include <sot/formats.hxx>
34 #include <uiitems.hxx>
35 #include <fmtinfmt.hxx>
36 #include <txtinet.hxx>
37 #include <fmtfld.hxx>
38 #include <swmodule.hxx>
39 #include <wrtsh.hxx>
40 #include <view.hxx>
41 #include <docsh.hxx>
42 #include <drawdoc.hxx>
43 #include <content.hxx>
44 #include <frmfmt.hxx>
45 #include <fldbas.hxx>
46 #include <IMark.hxx>
47 #include <section.hxx>
48 #include <tox.hxx>
49 #include <navipi.hxx>
50 #include <navicont.hxx>
51 #include <navicfg.hxx>
52 #include <edtwin.hxx>
53 #include <doc.hxx>
54 #include <IDocumentSettingAccess.hxx>
55 #include <IDocumentDrawModelAccess.hxx>
56 #include <IDocumentOutlineNodes.hxx>
57 #include <unotxvw.hxx>
58 #include <cmdid.h>
59 #include <helpids.h>
60 #include <strings.hrc>
61 #include <com/sun/star/text/XTextSectionsSupplier.hpp>
62 #include <com/sun/star/text/XTextGraphicObjectsSupplier.hpp>
63 #include <com/sun/star/text/XTextTablesSupplier.hpp>
64 #include <com/sun/star/text/XDocumentIndexesSupplier.hpp>
65 #include <com/sun/star/text/XDocumentIndex.hpp>
66 #include <com/sun/star/text/XBookmarksSupplier.hpp>
67 #include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
68 #include <com/sun/star/text/XTextFramesSupplier.hpp>
69 #include <dcontact.hxx>
70 #include <svx/svdpage.hxx>
71 #include <svx/svdview.hxx>
72 #include <SwRewriter.hxx>
73 #include <hints.hxx>
74 #include <numrule.hxx>
75 #include <swundo.hxx>
76 #include <ndtxt.hxx>
77 #include <PostItMgr.hxx>
78 #include <postithelper.hxx>
79 
80 #include <swabstdlg.hxx>
81 #include <bitmaps.hlst>
82 
83 #include <navmgr.hxx>
84 #include <AnnotationWin.hxx>
85 #include <memory>
86 
87 #include <fmtcntnt.hxx>
88 #include <docstat.hxx>
89 
90 #include <viewopt.hxx>
91 
92 #define CTYPE_CNT   0
93 #define CTYPE_CTT   1
94 
95 using namespace ::std;
96 using namespace ::com::sun::star;
97 using namespace ::com::sun::star::text;
98 using namespace ::com::sun::star::uno;
99 using namespace ::com::sun::star::container;
100 
101 namespace {
102 
103 /*
104     Symbolic name representations of numeric values used for the Outline Content Visibility popup
105     menu item ids. The numbers are chosen arbitrarily to not over overlap other menu item ids.
106     see: SwContentTree::ExecuteContextMenuAction, navigatorcontextmenu.ui
107 
108     1512 toggle outline content visibility of the selected outline entry
109     1513 make the outline content of the selected outline entry and children not visible
110     1514 make the outline content of the selected entry and children visible
111 */
112 const sal_uInt32 TOGGLE_OUTLINE_CONTENT_VISIBILITY = 1512;
113 const sal_uInt32 HIDE_OUTLINE_CONTENT_VISIBILITY = 1513;
114 const sal_uInt32 SHOW_OUTLINE_CONTENT_VISIBILITY = 1514;
115 
116 constexpr char NAVI_BOOKMARK_DELIM = '\x01';
117 
118 }
119 
120 class SwContentArr
121     : public o3tl::sorted_vector<std::unique_ptr<SwContent>, o3tl::less_uniqueptr_to<SwContent>,
122                 o3tl::find_partialorder_ptrequals>
123 {
124 };
125 
126 namespace
127 {
128     bool lcl_IsContent(const weld::TreeIter& rEntry, const weld::TreeView& rTreeView)
129     {
130         return reinterpret_cast<const SwTypeNumber*>(rTreeView.get_id(rEntry).toInt64())->GetTypeId() == CTYPE_CNT;
131     }
132 
133     bool lcl_IsContentType(const weld::TreeIter& rEntry, const weld::TreeView& rTreeView)
134     {
135         return reinterpret_cast<const SwTypeNumber*>(rTreeView.get_id(rEntry).toInt64())->GetTypeId() == CTYPE_CTT;
136     }
137 
138     bool lcl_FindShell(SwWrtShell const * pShell)
139     {
140         bool bFound = false;
141         SwView *pView = SwModule::GetFirstView();
142         while (pView)
143         {
144             if(pShell == &pView->GetWrtShell())
145             {
146                 bFound = true;
147                 break;
148             }
149             pView = SwModule::GetNextView(pView);
150         }
151         return bFound;
152     }
153 
154     bool lcl_IsUiVisibleBookmark(const ::sw::mark::IMark* pMark)
155     {
156         return IDocumentMarkAccess::GetType(*pMark) == IDocumentMarkAccess::MarkType::BOOKMARK;
157     }
158 
159     size_t lcl_InsertURLFieldContent(
160         SwContentArr *pMember,
161         SwWrtShell* pWrtShell,
162         const SwContentType *pCntType)
163     {
164         SwGetINetAttrs aArr;
165         pWrtShell->GetINetAttrs( aArr );
166         const SwGetINetAttrs::size_type nCount {aArr.size()};
167         for( SwGetINetAttrs::size_type n = 0; n < nCount; ++n )
168         {
169             SwGetINetAttr* p = &aArr[ n ];
170             std::unique_ptr<SwURLFieldContent> pCnt(new SwURLFieldContent(
171                                 pCntType,
172                                 p->sText,
173                                 INetURLObject::decode(
174                                     p->rINetAttr.GetINetFormat().GetValue(),
175                                     INetURLObject::DecodeMechanism::Unambiguous ),
176                                 &p->rINetAttr,
177                                 n ));
178             pMember->insert( std::move(pCnt) );
179         }
180         return nCount;
181     }
182 }
183 
184 // Content, contains names and reference at the content type.
185 
186 SwContent::SwContent(const SwContentType* pCnt, const OUString& rName, tools::Long nYPos) :
187     SwTypeNumber(CTYPE_CNT),
188     pParent(pCnt),
189     sContentName(rName),
190     nYPosition(nYPos),
191     bInvisible(false)
192 {
193 }
194 
195 
196 SwTypeNumber::~SwTypeNumber()
197 {
198 }
199 
200 bool SwContent::IsProtect() const
201 {
202     return false;
203 }
204 
205 bool SwPostItContent::IsProtect() const
206 {
207     return pField->IsProtect();
208 }
209 
210 bool SwURLFieldContent::IsProtect() const
211 {
212     return pINetAttr->IsProtect();
213 }
214 
215 SwGraphicContent::~SwGraphicContent()
216 {
217 }
218 
219 SwTOXBaseContent::~SwTOXBaseContent()
220 {
221 }
222 
223 static const char* STR_CONTENT_TYPE_ARY[] =
224 {
225     STR_CONTENT_TYPE_OUTLINE,
226     STR_CONTENT_TYPE_TABLE,
227     STR_CONTENT_TYPE_FRAME,
228     STR_CONTENT_TYPE_GRAPHIC,
229     STR_CONTENT_TYPE_OLE,
230     STR_CONTENT_TYPE_BOOKMARK,
231     STR_CONTENT_TYPE_REGION,
232     STR_CONTENT_TYPE_URLFIELD,
233     STR_CONTENT_TYPE_REFERENCE,
234     STR_CONTENT_TYPE_INDEX,
235     STR_CONTENT_TYPE_POSTIT,
236     STR_CONTENT_TYPE_DRAWOBJECT
237 };
238 
239 static const char* STR_CONTENT_TYPE_SINGLE_ARY[] =
240 {
241     STR_CONTENT_TYPE_SINGLE_OUTLINE,
242     STR_CONTENT_TYPE_SINGLE_TABLE,
243     STR_CONTENT_TYPE_SINGLE_FRAME,
244     STR_CONTENT_TYPE_SINGLE_GRAPHIC,
245     STR_CONTENT_TYPE_SINGLE_OLE,
246     STR_CONTENT_TYPE_SINGLE_BOOKMARK,
247     STR_CONTENT_TYPE_SINGLE_REGION,
248     STR_CONTENT_TYPE_SINGLE_URLFIELD,
249     STR_CONTENT_TYPE_SINGLE_REFERENCE,
250     STR_CONTENT_TYPE_SINGLE_INDEX,
251     STR_CONTENT_TYPE_SINGLE_POSTIT,
252     STR_CONTENT_TYPE_SINGLE_DRAWOBJECT
253 };
254 
255 namespace
256 {
257     bool checkVisibilityChanged(
258         const SwContentArr& rSwContentArrA,
259         const SwContentArr& rSwContentArrB)
260     {
261         if(rSwContentArrA.size() != rSwContentArrB.size())
262         {
263             return true;
264         }
265 
266         for(size_t a(0); a < rSwContentArrA.size(); a++)
267         {
268             if(rSwContentArrA[a]->IsInvisible() != rSwContentArrB[a]->IsInvisible())
269             {
270                 return true;
271             }
272         }
273 
274         return false;
275     }
276 
277 // Gets "YPos" for SwRegionContent, i.e. a number used to sort sections in Navigator's list
278 tools::Long getYPosForSection(const SwNodeIndex& rNodeIndex)
279 {
280     sal_uLong nIndex = rNodeIndex.GetIndex();
281     if (rNodeIndex.GetNodes().GetEndOfExtras().GetIndex() >= nIndex)
282     {
283         // Not a node of BodyText
284         // Are we in a fly?
285         if (const auto pFlyFormat = rNodeIndex.GetNode().GetFlyFormat())
286         {
287             // Get node index of anchor
288             if (auto pSwPosition = pFlyFormat->GetAnchor().GetContentAnchor())
289             {
290                 nIndex = getYPosForSection(pSwPosition->nNode);
291             }
292         }
293     }
294     return static_cast<tools::Long>(nIndex);
295 }
296 } // end of anonymous namespace
297 
298 SwContentType::SwContentType(SwWrtShell* pShell, ContentTypeId nType, sal_uInt8 nLevel) :
299     SwTypeNumber(CTYPE_CTT),
300     m_pWrtShell(pShell),
301     m_sContentTypeName(SwResId(STR_CONTENT_TYPE_ARY[static_cast<int>(nType)])),
302     m_sSingleContentTypeName(SwResId(STR_CONTENT_TYPE_SINGLE_ARY[static_cast<int>(nType)])),
303     m_nMemberCount(0),
304     m_nContentType(nType),
305     m_nOutlineLevel(nLevel),
306     m_bDataValid(false),
307     m_bEdit(false),
308     m_bDelete(true)
309 {
310     Init();
311 }
312 
313 void SwContentType::Init(bool* pbInvalidateWindow)
314 {
315     // if the MemberCount is changing ...
316     size_t nOldMemberCount = m_nMemberCount;
317     m_nMemberCount = 0;
318     switch(m_nContentType)
319     {
320         case ContentTypeId::OUTLINE   :
321         {
322             m_sTypeToken = "outline";
323             m_nMemberCount = m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
324             if (m_nMemberCount < MAXLEVEL)
325             {
326                 const size_t nOutlineCount = m_nMemberCount;
327                 for(size_t j = 0; j < nOutlineCount; ++j)
328                 {
329                     if (m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(j) > m_nOutlineLevel
330                         || !m_pWrtShell->getIDocumentOutlineNodesAccess()->isOutlineInLayout(j, *m_pWrtShell->GetLayout()))
331                     {
332                         m_nMemberCount --;
333                     }
334                 }
335             }
336         }
337         break;
338 
339         case ContentTypeId::TABLE     :
340             m_sTypeToken = "table";
341             m_nMemberCount = m_pWrtShell->GetTableFrameFormatCount(true);
342             m_bEdit = true;
343         break;
344 
345         case ContentTypeId::FRAME     :
346         case ContentTypeId::GRAPHIC   :
347         case ContentTypeId::OLE       :
348         {
349             FlyCntType eType = FLYCNTTYPE_FRM;
350             m_sTypeToken = "frame";
351             if(m_nContentType == ContentTypeId::OLE)
352             {
353                 eType = FLYCNTTYPE_OLE;
354                 m_sTypeToken = "ole";
355             }
356             else if(m_nContentType == ContentTypeId::GRAPHIC)
357             {
358                 eType = FLYCNTTYPE_GRF;
359                 m_sTypeToken = "graphic";
360             }
361             m_nMemberCount = m_pWrtShell->GetFlyCount(eType, /*bIgnoreTextBoxes=*/true);
362             m_bEdit = true;
363         }
364         break;
365         case ContentTypeId::BOOKMARK:
366         {
367             IDocumentMarkAccess* const pMarkAccess = m_pWrtShell->getIDocumentMarkAccess();
368             m_nMemberCount = count_if(
369                 pMarkAccess->getBookmarksBegin(),
370                 pMarkAccess->getBookmarksEnd(),
371                 &lcl_IsUiVisibleBookmark);
372             m_sTypeToken.clear();
373             const bool bProtectedBM = m_pWrtShell->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS);
374             m_bEdit = !bProtectedBM;
375             m_bDelete = !bProtectedBM;
376         }
377         break;
378         case ContentTypeId::REGION :
379         {
380             std::unique_ptr<SwContentArr> pOldMember;
381             if(!m_pMember)
382                 m_pMember.reset( new SwContentArr );
383             else if(!m_pMember->empty())
384             {
385                 pOldMember = std::move(m_pMember);
386                 m_pMember.reset( new SwContentArr );
387             }
388             m_nMemberCount = m_pWrtShell->GetSectionFormatCount();
389             for(size_t i = 0; i < m_nMemberCount; ++i)
390             {
391                 const SwSectionFormat* pFormat = &m_pWrtShell->GetSectionFormat(i);
392                 if (!pFormat->IsInNodesArr())
393                     continue;
394                 const SwSection* pSection = pFormat->GetSection();
395                 if (SectionType eTmpType = pSection->GetType();
396                     eTmpType == SectionType::ToxContent || eTmpType == SectionType::ToxHeader)
397                     continue;
398                 const SwNodeIndex* pNodeIndex = pFormat->GetContent().GetContentIdx();
399                 if (pNodeIndex)
400                 {
401                     const OUString& rSectionName = pSection->GetSectionName();
402                     sal_uInt8 nLevel = 0;
403                     SwSectionFormat* pParentFormat = pFormat->GetParent();
404                     while(pParentFormat)
405                     {
406                         nLevel++;
407                         pParentFormat = pParentFormat->GetParent();
408                     }
409 
410                     std::unique_ptr<SwContent> pCnt(new SwRegionContent(this, rSectionName,
411                             nLevel, getYPosForSection(*pNodeIndex)));
412 
413                     SwPtrMsgPoolItem aAskItem( RES_CONTENT_VISIBLE, nullptr );
414                     if( !pFormat->GetInfo( aAskItem ) &&
415                         !aAskItem.pObject )     // not visible
416                         pCnt->SetInvisible();
417                     m_pMember->insert(std::move(pCnt));
418                 }
419             }
420             m_nMemberCount = m_pMember->size();
421             m_sTypeToken = "region";
422             m_bEdit = true;
423             m_bDelete = false;
424             if(pOldMember)
425             {
426                 if(nullptr != pbInvalidateWindow)
427                 {
428                     // need to check visibility (and equal entry number) after
429                     // creation due to a sorted list being used here (before,
430                     // entries with same index were compared already at creation
431                     // time what worked before a sorted list was used)
432                     *pbInvalidateWindow = checkVisibilityChanged(
433                         *pOldMember,
434                         *m_pMember);
435                 }
436             }
437         }
438         break;
439         case ContentTypeId::INDEX:
440         {
441             m_nMemberCount = m_pWrtShell->GetTOXCount();
442             m_bEdit = true;
443             m_bDelete = false;
444         }
445         break;
446         case ContentTypeId::REFERENCE:
447         {
448             m_nMemberCount = m_pWrtShell->GetRefMarks();
449             m_bDelete = false;
450         }
451         break;
452         case ContentTypeId::URLFIELD:
453         {
454             m_nMemberCount = 0;
455             if(!m_pMember)
456                 m_pMember.reset( new SwContentArr );
457             else
458                 m_pMember->clear();
459 
460             m_nMemberCount = lcl_InsertURLFieldContent(m_pMember.get(), m_pWrtShell, this);
461 
462             m_bEdit = true;
463             nOldMemberCount = m_nMemberCount;
464             m_bDelete = true;
465         }
466         break;
467         case ContentTypeId::POSTIT:
468         {
469             m_nMemberCount = 0;
470             if(!m_pMember)
471                 m_pMember.reset( new SwContentArr );
472             else
473                 m_pMember->clear();
474 
475             SwPostItMgr* aMgr = m_pWrtShell->GetView().GetPostItMgr();
476             if (aMgr)
477             {
478                 for(SwPostItMgr::const_iterator i = aMgr->begin(); i != aMgr->end(); ++i)
479                 {
480                     if (const SwFormatField* pFormatField = dynamic_cast<const SwFormatField *>((*i)->GetBroadcaster())) // SwPostit
481                     {
482                         if (pFormatField->GetTextField() && pFormatField->IsFieldInDoc() &&
483                             (*i)->mLayoutStatus!=SwPostItHelper::INVISIBLE )
484                         {
485                             OUString sEntry = pFormatField->GetField()->GetPar2();
486                             sEntry = RemoveNewline(sEntry);
487                             std::unique_ptr<SwPostItContent> pCnt(new SwPostItContent(
488                                                 this,
489                                                 sEntry,
490                                                 pFormatField,
491                                                 m_nMemberCount));
492                             m_pMember->insert(std::move(pCnt));
493                             m_nMemberCount++;
494                         }
495                     }
496                 }
497             }
498             m_sTypeToken.clear();
499             m_bEdit = true;
500             nOldMemberCount = m_nMemberCount;
501         }
502         break;
503         case ContentTypeId::DRAWOBJECT:
504         {
505             m_sTypeToken.clear();
506             m_bEdit = true;
507             m_nMemberCount = 0;
508             SwDrawModel* pModel = m_pWrtShell->getIDocumentDrawModelAccess().GetDrawModel();
509             if(pModel)
510             {
511                 SdrPage* pPage = pModel->GetPage(0);
512                 const size_t nCount = pPage->GetObjCount();
513                 for( size_t i=0; i<nCount; ++i )
514                 {
515                     SdrObject* pTemp = pPage->GetObj(i);
516                     // #i51726# - all drawing objects can be named now
517                     if (!pTemp->GetName().isEmpty())
518                         m_nMemberCount++;
519                 }
520             }
521         }
522         break;
523         default: break;
524     }
525     // ... then, the data can also no longer be valid,
526     // apart from those which have already been corrected,
527     // then nOldMemberCount is nevertheless not so old.
528     if( nOldMemberCount != m_nMemberCount )
529         m_bDataValid = false;
530 }
531 
532 SwContentType::~SwContentType()
533 {
534 }
535 
536 const SwContent* SwContentType::GetMember(size_t nIndex)
537 {
538     if(!m_bDataValid || !m_pMember)
539     {
540         FillMemberList();
541     }
542     if(nIndex < m_pMember->size())
543         return (*m_pMember)[nIndex].get();
544 
545     return nullptr;
546 }
547 
548 void SwContentType::Invalidate()
549 {
550     m_bDataValid = false;
551 }
552 
553 void SwContentType::FillMemberList(bool* pbLevelOrVisibilityChanged)
554 {
555     std::unique_ptr<SwContentArr> pOldMember;
556     size_t nOldMemberCount = 0;
557     SwPtrMsgPoolItem aAskItem( RES_CONTENT_VISIBLE, nullptr );
558     if(m_pMember && pbLevelOrVisibilityChanged)
559     {
560         pOldMember = std::move(m_pMember);
561         nOldMemberCount = pOldMember->size();
562         m_pMember.reset( new SwContentArr );
563         *pbLevelOrVisibilityChanged = false;
564     }
565     else if(!m_pMember)
566         m_pMember.reset( new SwContentArr );
567     else
568         m_pMember->clear();
569     switch(m_nContentType)
570     {
571         case ContentTypeId::OUTLINE   :
572         {
573             const size_t nOutlineCount = m_nMemberCount =
574                 m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
575 
576             size_t nPos = 0;
577             for (size_t i = 0; i < nOutlineCount; ++i)
578             {
579                 const sal_uInt8 nLevel = m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(i);
580                 if(nLevel >= m_nOutlineLevel )
581                     m_nMemberCount--;
582                 else
583                 {
584                     if (!m_pWrtShell->getIDocumentOutlineNodesAccess()->isOutlineInLayout(i, *m_pWrtShell->GetLayout()))
585                     {
586                         --m_nMemberCount;
587                         continue; // don't hide it, just skip it
588                     }
589                     OUString aEntry(comphelper::string::stripStart(
590                         m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineText(i, m_pWrtShell->GetLayout()), ' '));
591                     aEntry = SwNavigationPI::CleanEntry(aEntry);
592                     std::unique_ptr<SwOutlineContent> pCnt(new SwOutlineContent(this, aEntry, i, nLevel,
593                                                         m_pWrtShell->IsOutlineMovable( i ), nPos ));
594                     m_pMember->insert(std::move(pCnt));
595                     // with the same number and existing "pOldMember" the
596                     // old one is compared with the new OutlinePos.
597                     if (nOldMemberCount > nPos && static_cast<SwOutlineContent*>((*pOldMember)[nPos].get())->GetOutlineLevel() != nLevel)
598                         *pbLevelOrVisibilityChanged = true;
599 
600                     nPos++;
601                 }
602             }
603 
604         }
605         break;
606         case ContentTypeId::TABLE     :
607         {
608             const size_t nCount = m_pWrtShell->GetTableFrameFormatCount(true);
609             OSL_ENSURE(m_nMemberCount == nCount, "MemberCount differs");
610             Point aNullPt;
611             m_nMemberCount = nCount;
612             for(size_t i = 0; i < m_nMemberCount; ++i)
613             {
614                 const SwFrameFormat& rTableFormat = m_pWrtShell->GetTableFrameFormat(i, true);
615                 const OUString& sTableName( rTableFormat.GetName() );
616 
617                 SwContent* pCnt = new SwContent(this, sTableName,
618                         rTableFormat.FindLayoutRect(false, &aNullPt).Top() );
619                 if( !rTableFormat.GetInfo( aAskItem ) &&
620                     !aAskItem.pObject )     // not visible
621                     pCnt->SetInvisible();
622 
623                 m_pMember->insert(std::unique_ptr<SwContent>(pCnt));
624             }
625 
626             if (nullptr != pbLevelOrVisibilityChanged)
627             {
628                 assert(pOldMember);
629                 // need to check visibility (and equal entry number) after
630                 // creation due to a sorted list being used here (before,
631                 // entries with same index were compared already at creation
632                 // time what worked before a sorted list was used)
633                 *pbLevelOrVisibilityChanged = checkVisibilityChanged(
634                     *pOldMember,
635                     *m_pMember);
636             }
637         }
638         break;
639         case ContentTypeId::OLE       :
640         case ContentTypeId::FRAME     :
641         case ContentTypeId::GRAPHIC   :
642         {
643             FlyCntType eType = FLYCNTTYPE_FRM;
644             if(m_nContentType == ContentTypeId::OLE)
645                 eType = FLYCNTTYPE_OLE;
646             else if(m_nContentType == ContentTypeId::GRAPHIC)
647                 eType = FLYCNTTYPE_GRF;
648             Point aNullPt;
649             m_nMemberCount = m_pWrtShell->GetFlyCount(eType, /*bIgnoreTextBoxes=*/true);
650             std::vector<SwFrameFormat const*> formats(m_pWrtShell->GetFlyFrameFormats(eType, /*bIgnoreTextBoxes=*/true));
651             SAL_WARN_IF(m_nMemberCount != formats.size(), "sw.ui", "MemberCount differs");
652             m_nMemberCount = formats.size();
653             for (size_t i = 0; i < m_nMemberCount; ++i)
654             {
655                 SwFrameFormat const*const pFrameFormat = formats[i];
656                 const OUString sFrameName = pFrameFormat->GetName();
657 
658                 SwContent* pCnt;
659                 if(ContentTypeId::GRAPHIC == m_nContentType)
660                 {
661                     OUString sLink;
662                     m_pWrtShell->GetGrfNms( &sLink, nullptr, static_cast<const SwFlyFrameFormat*>( pFrameFormat));
663                     pCnt = new SwGraphicContent(this, sFrameName,
664                                 INetURLObject::decode( sLink,
665                                            INetURLObject::DecodeMechanism::Unambiguous ),
666                                 pFrameFormat->FindLayoutRect(false, &aNullPt).Top());
667                 }
668                 else
669                 {
670                     pCnt = new SwContent(this, sFrameName,
671                             pFrameFormat->FindLayoutRect(false, &aNullPt).Top() );
672                 }
673                 if( !pFrameFormat->GetInfo( aAskItem ) &&
674                     !aAskItem.pObject )     // not visible
675                     pCnt->SetInvisible();
676                 m_pMember->insert(std::unique_ptr<SwContent>(pCnt));
677             }
678 
679             if(nullptr != pbLevelOrVisibilityChanged)
680             {
681                 assert(pOldMember);
682                 // need to check visibility (and equal entry number) after
683                 // creation due to a sorted list being used here (before,
684                 // entries with same index were compared already at creation
685                 // time what worked before a sorted list was used)
686                 *pbLevelOrVisibilityChanged = checkVisibilityChanged(
687                     *pOldMember,
688                     *m_pMember);
689             }
690         }
691         break;
692         case ContentTypeId::BOOKMARK:
693         {
694             IDocumentMarkAccess* const pMarkAccess = m_pWrtShell->getIDocumentMarkAccess();
695             for(IDocumentMarkAccess::const_iterator_t ppBookmark = pMarkAccess->getBookmarksBegin();
696                 ppBookmark != pMarkAccess->getBookmarksEnd();
697                 ++ppBookmark)
698             {
699                 if(lcl_IsUiVisibleBookmark(*ppBookmark))
700                 {
701                     const OUString& rBkmName = (*ppBookmark)->GetName();
702                     //nYPos from 0 -> text::Bookmarks will be sorted alphabetically
703                     std::unique_ptr<SwContent> pCnt(new SwContent(this, rBkmName, 0));
704                     m_pMember->insert(std::move(pCnt));
705                 }
706             }
707         }
708         break;
709         case ContentTypeId::REGION    :
710         {
711             m_nMemberCount = m_pWrtShell->GetSectionFormatCount();
712             for(size_t i = 0; i < m_nMemberCount; ++i)
713             {
714                 const SwSectionFormat* pFormat = &m_pWrtShell->GetSectionFormat(i);
715                 if (!pFormat->IsInNodesArr())
716                     continue;
717                 const SwSection* pSection = pFormat->GetSection();
718                 if (SectionType eTmpType = pSection->GetType();
719                     eTmpType == SectionType::ToxContent || eTmpType == SectionType::ToxHeader)
720                     continue;
721                 const SwNodeIndex* pNodeIndex = pFormat->GetContent().GetContentIdx();
722                 if (pNodeIndex)
723                 {
724                     const OUString& sSectionName = pSection->GetSectionName();
725 
726                     sal_uInt8 nLevel = 0;
727                     SwSectionFormat* pParentFormat = pFormat->GetParent();
728                     while(pParentFormat)
729                     {
730                         nLevel++;
731                         pParentFormat = pParentFormat->GetParent();
732                     }
733 
734                     std::unique_ptr<SwContent> pCnt(new SwRegionContent(this, sSectionName,
735                             nLevel, getYPosForSection(*pNodeIndex)));
736                     if( !pFormat->GetInfo( aAskItem ) &&
737                         !aAskItem.pObject )     // not visible
738                         pCnt->SetInvisible();
739                     m_pMember->insert(std::move(pCnt));
740                 }
741 
742                 if(nullptr != pbLevelOrVisibilityChanged)
743                 {
744                     assert(pOldMember);
745                     // need to check visibility (and equal entry number) after
746                     // creation due to a sorted list being used here (before,
747                     // entries with same index were compared already at creation
748                     // time what worked before a sorted list was used)
749                     *pbLevelOrVisibilityChanged = checkVisibilityChanged(
750                         *pOldMember,
751                         *m_pMember);
752                 }
753             }
754             m_nMemberCount = m_pMember->size();
755         }
756         break;
757         case ContentTypeId::REFERENCE:
758         {
759             std::vector<OUString> aRefMarks;
760             m_nMemberCount = m_pWrtShell->GetRefMarks( &aRefMarks );
761 
762             for (const auto& rRefMark : aRefMarks)
763             {
764                 // References sorted alphabetically
765                 m_pMember->insert(std::make_unique<SwContent>(this, rRefMark, 0));
766             }
767         }
768         break;
769         case ContentTypeId::URLFIELD:
770             m_nMemberCount = lcl_InsertURLFieldContent(m_pMember.get(), m_pWrtShell, this);
771         break;
772         case ContentTypeId::INDEX:
773         {
774 
775             const sal_uInt16 nCount = m_pWrtShell->GetTOXCount();
776             m_nMemberCount = nCount;
777             for ( sal_uInt16 nTox = 0; nTox < nCount; nTox++ )
778             {
779                 const SwTOXBase* pBase = m_pWrtShell->GetTOX( nTox );
780                 OUString sTOXNm( pBase->GetTOXName() );
781 
782                 SwContent* pCnt = new SwTOXBaseContent(
783                         this, sTOXNm, nTox, *pBase);
784 
785                 if(pBase && !pBase->IsVisible())
786                     pCnt->SetInvisible();
787 
788                 m_pMember->insert( std::unique_ptr<SwContent>(pCnt) );
789                 const size_t nPos = m_pMember->size() - 1;
790                 if(nOldMemberCount > nPos &&
791                     (*pOldMember)[nPos]->IsInvisible()
792                             != pCnt->IsInvisible())
793                         *pbLevelOrVisibilityChanged = true;
794             }
795         }
796         break;
797         case ContentTypeId::POSTIT:
798         {
799             m_nMemberCount = 0;
800             m_pMember->clear();
801             SwPostItMgr* aMgr = m_pWrtShell->GetView().GetPostItMgr();
802             if (aMgr)
803             {
804                 for(SwPostItMgr::const_iterator i = aMgr->begin(); i != aMgr->end(); ++i)
805                 {
806                     if (const SwFormatField* pFormatField = dynamic_cast<const SwFormatField *>((*i)->GetBroadcaster())) // SwPostit
807                     {
808                         if (pFormatField->GetTextField() && pFormatField->IsFieldInDoc() &&
809                             (*i)->mLayoutStatus!=SwPostItHelper::INVISIBLE )
810                         {
811                             OUString sEntry = pFormatField->GetField()->GetPar2();
812                             sEntry = RemoveNewline(sEntry);
813                             std::unique_ptr<SwPostItContent> pCnt(new SwPostItContent(
814                                                 this,
815                                                 sEntry,
816                                                 pFormatField,
817                                                 m_nMemberCount));
818                             m_pMember->insert(std::move(pCnt));
819                             m_nMemberCount++;
820                         }
821                     }
822                 }
823             }
824         }
825         break;
826         case ContentTypeId::DRAWOBJECT:
827         {
828             m_nMemberCount = 0;
829             m_pMember->clear();
830 
831             IDocumentDrawModelAccess& rIDDMA = m_pWrtShell->getIDocumentDrawModelAccess();
832             SwDrawModel* pModel = rIDDMA.GetDrawModel();
833             if(pModel)
834             {
835                 SdrPage* pPage = pModel->GetPage(0);
836                 const size_t nCount = pPage->GetObjCount();
837                 for( size_t i=0; i<nCount; ++i )
838                 {
839                     SdrObject* pTemp = pPage->GetObj(i);
840                     // #i51726# - all drawing objects can be named now
841                     if (!pTemp->GetName().isEmpty())
842                     {
843                         SwContact* pContact = static_cast<SwContact*>(pTemp->GetUserCall());
844                         tools::Long nYPos = 0;
845                         const Point aNullPt;
846                         if(pContact && pContact->GetFormat())
847                             nYPos = pContact->GetFormat()->FindLayoutRect(false, &aNullPt).Top();
848                         SwContent* pCnt = new SwContent(
849                                             this,
850                                             pTemp->GetName(),
851                                             nYPos);
852                         if(!rIDDMA.IsVisibleLayerId(pTemp->GetLayer()))
853                             pCnt->SetInvisible();
854                         m_pMember->insert(std::unique_ptr<SwContent>(pCnt));
855                         m_nMemberCount++;
856                     }
857                 }
858 
859                 if (nullptr != pbLevelOrVisibilityChanged)
860                 {
861                     assert(pOldMember);
862                     // need to check visibility (and equal entry number) after
863                     // creation due to a sorted list being used here (before,
864                     // entries with same index were compared already at creation
865                     // time what worked before a sorted list was used)
866                     *pbLevelOrVisibilityChanged = checkVisibilityChanged(
867                         *pOldMember,
868                         *m_pMember);
869                 }
870             }
871         }
872         break;
873         default: break;
874     }
875     m_bDataValid = true;
876 }
877 
878 namespace {
879 
880 enum STR_CONTEXT_IDX
881 {
882     IDX_STR_OUTLINE_LEVEL = 0,
883     IDX_STR_DRAGMODE = 1,
884     IDX_STR_HYPERLINK = 2,
885     IDX_STR_LINK_REGION = 3,
886     IDX_STR_COPY_REGION = 4,
887     IDX_STR_DISPLAY = 5,
888     IDX_STR_ACTIVE_VIEW = 6,
889     IDX_STR_HIDDEN = 7,
890     IDX_STR_ACTIVE = 8,
891     IDX_STR_INACTIVE = 9,
892     IDX_STR_EDIT_ENTRY = 10,
893     IDX_STR_DELETE_ENTRY = 11,
894     IDX_STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY = 12,
895     IDX_STR_OUTLINE_TRACKING = 13,
896     IDX_STR_OUTLINE_TRACKING_DEFAULT = 14,
897     IDX_STR_OUTLINE_TRACKING_FOCUS = 15,
898     IDX_STR_OUTLINE_TRACKING_OFF = 16
899 };
900 
901 }
902 
903 static const char* STR_CONTEXT_ARY[] =
904 {
905     STR_OUTLINE_LEVEL,
906     STR_DRAGMODE,
907     STR_HYPERLINK,
908     STR_LINK_REGION,
909     STR_COPY_REGION,
910     STR_DISPLAY,
911     STR_ACTIVE_VIEW,
912     STR_HIDDEN,
913     STR_ACTIVE,
914     STR_INACTIVE,
915     STR_EDIT_ENTRY,
916     STR_DELETE_ENTRY,
917     STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY,
918     STR_OUTLINE_TRACKING,
919     STR_OUTLINE_TRACKING_DEFAULT,
920     STR_OUTLINE_TRACKING_FOCUS,
921     STR_OUTLINE_TRACKING_OFF
922 };
923 
924 SwContentTree::SwContentTree(std::unique_ptr<weld::TreeView> xTreeView, SwNavigationPI* pDialog)
925     : m_xTreeView(std::move(xTreeView))
926     , m_xScratchIter(m_xTreeView->make_iterator())
927     , m_aDropTargetHelper(*this)
928     , m_pDialog(pDialog)
929     , m_sSpace(OUString("                    "))
930     , m_sInvisible(SwResId(STR_INVISIBLE))
931     , m_pHiddenShell(nullptr)
932     , m_pActiveShell(nullptr)
933     , m_pConfig(SW_MOD()->GetNavigationConfig())
934     , m_nActiveBlock(0)
935     , m_nHiddenBlock(0)
936     , m_nEntryCount(0)
937     , m_nRootType(ContentTypeId::UNKNOWN)
938     , m_nLastSelType(ContentTypeId::UNKNOWN)
939     , m_nOutlineLevel(MAXLEVEL)
940     , m_eState(State::ACTIVE)
941     , m_bIsRoot(false)
942     , m_bIsIdleClear(false)
943     , m_bIsLastReadOnly(false)
944     , m_bIsOutlineMoveable(true)
945     , m_bViewHasChanged(false)
946 {
947     m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 30,
948                                   m_xTreeView->get_text_height() * 14);
949 
950     m_xTreeView->set_help_id(HID_NAVIGATOR_TREELIST);
951 
952     m_xTreeView->connect_expanding(LINK(this, SwContentTree, ExpandHdl));
953     m_xTreeView->connect_collapsing(LINK(this, SwContentTree, CollapseHdl));
954     m_xTreeView->connect_row_activated(LINK(this, SwContentTree, ContentDoubleClickHdl));
955     m_xTreeView->connect_changed(LINK(this, SwContentTree, SelectHdl));
956     m_xTreeView->connect_focus_in(LINK(this, SwContentTree, FocusInHdl));
957     m_xTreeView->connect_key_press(LINK(this, SwContentTree, KeyInputHdl));
958     m_xTreeView->connect_popup_menu(LINK(this, SwContentTree, CommandHdl));
959     m_xTreeView->connect_query_tooltip(LINK(this, SwContentTree, QueryTooltipHdl));
960     m_xTreeView->connect_drag_begin(LINK(this, SwContentTree, DragBeginHdl));
961 
962     for (ContentTypeId i : o3tl::enumrange<ContentTypeId>())
963     {
964         m_aActiveContentArr[i] = nullptr;
965         m_aHiddenContentArr[i] = nullptr;
966     }
967     for (int i = 0; i < CONTEXT_COUNT; ++i)
968     {
969         m_aContextStrings[i] = SwResId(STR_CONTEXT_ARY[i]);
970     }
971     m_nActiveBlock = m_pConfig->GetActiveBlock();
972     m_aUpdTimer.SetInvokeHandler(LINK(this, SwContentTree, TimerUpdate));
973     m_aUpdTimer.SetTimeout(1000);
974 }
975 
976 SwContentTree::~SwContentTree()
977 {
978     clear(); // If applicable erase content types previously.
979     m_aUpdTimer.Stop();
980     SetActiveShell(nullptr);
981 }
982 
983 // Drag&Drop methods
984 IMPL_LINK(SwContentTree, DragBeginHdl, bool&, rUnsetDragIcon, bool)
985 {
986     rUnsetDragIcon = true;
987 
988     bool bDisallow = true;
989 
990     // don't allow if tree root is selected
991     std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
992     bool bEntry = m_xTreeView->get_selected(xEntry.get());
993     if (!bEntry || lcl_IsContentType(*xEntry, *m_xTreeView))
994     {
995         return true; // disallow
996     }
997 
998     rtl::Reference<TransferDataContainer> xContainer = new TransferDataContainer;
999     sal_Int8 nDragMode = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
1000 
1001     if (FillTransferData(*xContainer, nDragMode))
1002         bDisallow = false;
1003 
1004     if (m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE)
1005     {
1006         // Only move drag entry and continuous selected siblings:
1007         m_aDndOutlinesSelected.clear();
1008 
1009         std::unique_ptr<weld::TreeIter> xScratch(m_xTreeView->make_iterator());
1010 
1011         // Find first selected of continuous siblings
1012         while (true)
1013         {
1014             m_xTreeView->copy_iterator(*xEntry, *xScratch);
1015             if (!m_xTreeView->iter_previous_sibling(*xScratch))
1016                 break;
1017             if (!m_xTreeView->is_selected(*xScratch))
1018                 break;
1019             m_xTreeView->copy_iterator(*xScratch, *xEntry);
1020         }
1021         // Record continuous selected siblings
1022         do
1023         {
1024             m_aDndOutlinesSelected.push_back(m_xTreeView->make_iterator(xEntry.get()));
1025         }
1026         while (m_xTreeView->iter_next_sibling(*xEntry) && m_xTreeView->is_selected(*xEntry));
1027         bDisallow = false;
1028     }
1029 
1030     if (!bDisallow)
1031         m_xTreeView->enable_drag_source(xContainer, nDragMode);
1032     return bDisallow;
1033 }
1034 
1035 SwContentTreeDropTarget::SwContentTreeDropTarget(SwContentTree& rTreeView)
1036     : DropTargetHelper(rTreeView.get_widget().get_drop_target())
1037     , m_rTreeView(rTreeView)
1038 {
1039 }
1040 
1041 sal_Int8 SwContentTreeDropTarget::AcceptDrop(const AcceptDropEvent& rEvt)
1042 {
1043     sal_Int8 nAccept = m_rTreeView.AcceptDrop(rEvt);
1044 
1045     if (nAccept != DND_ACTION_NONE)
1046     {
1047         // to enable the autoscroll when we're close to the edges
1048         weld::TreeView& rWidget = m_rTreeView.get_widget();
1049         rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
1050     }
1051 
1052     return nAccept;
1053 }
1054 
1055 bool SwContentTree::IsInDrag() const
1056 {
1057     return m_xTreeView->get_drag_source() == m_xTreeView.get();
1058 }
1059 
1060 // QueryDrop will be executed in the navigator
1061 sal_Int8 SwContentTree::AcceptDrop(const AcceptDropEvent& rEvt)
1062 {
1063     sal_Int8 nRet = DND_ACTION_NONE;
1064     if( m_bIsRoot )
1065     {
1066         if( m_bIsOutlineMoveable )
1067             nRet = rEvt.mnAction;
1068     }
1069     else if (!IsInDrag())
1070         nRet = GetParentWindow()->AcceptDrop();
1071     return nRet;
1072 }
1073 
1074 // Drop will be executed in the navigator
1075 static void* lcl_GetOutlineKey(SwContentTree& rTree, SwOutlineContent const * pContent)
1076 {
1077     void* key = nullptr;
1078     if (pContent)
1079     {
1080         SwWrtShell* pShell = rTree.GetWrtShell();
1081         auto const nPos = pContent->GetOutlinePos();
1082 
1083         key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
1084     }
1085     return key;
1086 }
1087 
1088 sal_Int8 SwContentTreeDropTarget::ExecuteDrop(const ExecuteDropEvent& rEvt)
1089 {
1090     return m_rTreeView.ExecuteDrop(rEvt);
1091 }
1092 
1093 sal_Int8 SwContentTree::ExecuteDrop(const ExecuteDropEvent& rEvt)
1094 {
1095     std::unique_ptr<weld::TreeIter> xDropEntry(m_xTreeView->make_iterator());
1096     if (!m_xTreeView->get_dest_row_at_pos(rEvt.maPosPixel, xDropEntry.get(), true))
1097         xDropEntry.reset();
1098 
1099     if (m_nRootType == ContentTypeId::OUTLINE)
1100     {
1101         if (xDropEntry && lcl_IsContent(*xDropEntry, *m_xTreeView))
1102         {
1103             assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xDropEntry).toInt64())));
1104             SwOutlineContent* pOutlineContent = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xDropEntry).toInt64());
1105             assert(pOutlineContent);
1106 
1107             void* key = lcl_GetOutlineKey(*this, pOutlineContent);
1108             assert(key);
1109             if (!mOutLineNodeMap[key])
1110             {
1111                 while (m_xTreeView->iter_has_child(*xDropEntry))
1112                 {
1113                     std::unique_ptr<weld::TreeIter> xChildEntry(m_xTreeView->make_iterator(xDropEntry.get()));
1114                     bool bChildEntry = m_xTreeView->iter_children(*xChildEntry);
1115                     while (bChildEntry)
1116                     {
1117                         m_xTreeView->copy_iterator(*xChildEntry, *xDropEntry);
1118                         bChildEntry = m_xTreeView->iter_next_sibling(*xChildEntry);
1119                     }
1120                 }
1121             }
1122         }
1123 
1124         SwOutlineNodes::size_type nTargetPos = 0;
1125         if (!xDropEntry)
1126         {
1127             // dropped in blank space -> move to bottom
1128             nTargetPos = GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineNodesCount() - 1;
1129         }
1130         else if (!lcl_IsContent(*xDropEntry, *m_xTreeView))
1131         {
1132             // dropped on "heading" parent -> move to start
1133             nTargetPos = SwOutlineNodes::npos;
1134         }
1135         else
1136         {
1137             assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xDropEntry).toInt64())));
1138             nTargetPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xDropEntry).toInt64())->GetOutlinePos();
1139         }
1140 
1141         if( MAXLEVEL > m_nOutlineLevel && // Not all layers are displayed.
1142                         nTargetPos != SwOutlineNodes::npos)
1143         {
1144             std::unique_ptr<weld::TreeIter> xNext(m_xTreeView->make_iterator(xDropEntry.get()));
1145             bool bNext = m_xTreeView->iter_next(*xNext);
1146             if (bNext)
1147             {
1148                 assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xNext).toInt64())));
1149                 nTargetPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xNext).toInt64())->GetOutlinePos() - 1;
1150             }
1151             else
1152                 nTargetPos = GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineNodesCount() - 1;
1153         }
1154 
1155         // remove the drop highlight before we change the contents of the tree so we don't
1156         // try and dereference a removed entry in post-processing drop
1157         m_xTreeView->unset_drag_dest_row();
1158         MoveOutline(nTargetPos);
1159 
1160     }
1161     return IsInDrag() ? DND_ACTION_NONE : GetParentWindow()->ExecuteDrop(rEvt);
1162 }
1163 
1164 namespace
1165 {
1166     bool IsAllExpanded(const weld::TreeView& rContentTree, const weld::TreeIter& rEntry)
1167     {
1168         if (!rContentTree.get_row_expanded(rEntry))
1169             return false;
1170 
1171         if (!rContentTree.iter_has_child(rEntry))
1172             return false;
1173 
1174         std::unique_ptr<weld::TreeIter> xChild(rContentTree.make_iterator(&rEntry));
1175         (void)rContentTree.iter_children(*xChild);
1176 
1177         do
1178         {
1179             if (rContentTree.iter_has_child(*xChild) || rContentTree.get_children_on_demand(*xChild))
1180             {
1181                 if (!IsAllExpanded(rContentTree, *xChild))
1182                     return false;
1183             }
1184         }
1185         while (rContentTree.iter_next_sibling(*xChild));
1186         return true;
1187     }
1188 
1189     void ExpandOrCollapseAll(weld::TreeView& rContentTree, weld::TreeIter& rEntry)
1190     {
1191         bool bExpand = !IsAllExpanded(rContentTree, rEntry);
1192         bExpand ? rContentTree.expand_row(rEntry) : rContentTree.collapse_row(rEntry);
1193         int nRefDepth = rContentTree.get_iter_depth(rEntry);
1194         while (rContentTree.iter_next(rEntry) && rContentTree.get_iter_depth(rEntry) > nRefDepth)
1195         {
1196             if (rContentTree.iter_has_child(rEntry))
1197                 bExpand ? rContentTree.expand_row(rEntry) : rContentTree.collapse_row(rEntry);
1198         }
1199     }
1200 }
1201 
1202 // Handler for Dragging and ContextMenu
1203 static bool lcl_InsertExpandCollapseAllItem(const weld::TreeView& rContentTree, const weld::TreeIter& rEntry, weld::Menu& rPop)
1204 {
1205     if (rContentTree.iter_has_child(rEntry) || rContentTree.get_children_on_demand(rEntry))
1206     {
1207         rPop.set_label(OString::number(800), IsAllExpanded(rContentTree, rEntry) ? SwResId(STR_COLLAPSEALL) : SwResId(STR_EXPANDALL));
1208         return false;
1209     }
1210     return true;
1211 }
1212 
1213 static void lcl_SetOutlineContentEntriesSensitivities(SwContentTree* pThis, const weld::TreeView& rContentTree, const weld::TreeIter& rEntry, weld::Menu& rPop)
1214 {
1215     rPop.set_sensitive(OString::number(TOGGLE_OUTLINE_CONTENT_VISIBILITY), false);
1216     rPop.set_sensitive(OString::number(HIDE_OUTLINE_CONTENT_VISIBILITY), false);
1217     rPop.set_sensitive(OString::number(SHOW_OUTLINE_CONTENT_VISIBILITY), false);
1218 
1219     // todo: multi selection
1220     if (rContentTree.count_selected_rows() > 1)
1221         return;
1222 
1223     bool bIsRoot = lcl_IsContentType(rEntry, rContentTree);
1224 
1225     if (pThis->GetActiveWrtShell()->GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
1226     {
1227         if (!bIsRoot)
1228             rPop.set_sensitive(OString::number(TOGGLE_OUTLINE_CONTENT_VISIBILITY), true);
1229         return;
1230     }
1231 
1232     const SwNodes& rNodes = pThis->GetWrtShell()->GetNodes();
1233     const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
1234     size_t nOutlinePos = weld::GetAbsPos(rContentTree, rEntry);
1235 
1236     if (!bIsRoot)
1237         --nOutlinePos;
1238 
1239     if (nOutlinePos >= rOutlineNodes.size())
1240          return;
1241 
1242     int nFirstLevel = pThis->GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos);
1243     {
1244         // determine if any concerned outline node has content
1245         bool bHasContent(false);
1246         size_t nPos = nOutlinePos;
1247         SwNode* pSttNd = rOutlineNodes[nPos];
1248         SwNode* pEndNd = &rNodes.GetEndOfContent();
1249         if (rOutlineNodes.size() > nPos + 1)
1250             pEndNd = rOutlineNodes[nPos + 1];
1251 
1252         // selected
1253         SwNodeIndex aIdx(*pSttNd);
1254         if (rNodes.GoNext(&aIdx) != pEndNd)
1255             bHasContent = true;
1256 
1257         // descendants
1258         if (!bHasContent && (rContentTree.iter_has_child(rEntry) || rContentTree.get_children_on_demand(rEntry)))
1259         {
1260             while (++nPos < rOutlineNodes.size() &&
1261                   (bIsRoot || pThis->GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nFirstLevel))
1262             {
1263                 pSttNd = rOutlineNodes[nPos];
1264                 pEndNd = &rNodes.GetEndOfContent();
1265                 if (rOutlineNodes.size() > nPos + 1)
1266                     pEndNd = rOutlineNodes[nPos + 1];
1267 
1268                 // test for content in outline node
1269                 aIdx.Assign(*pSttNd);
1270                 if (rNodes.GoNext(&aIdx) != pEndNd)
1271                 {
1272                     bHasContent = true;
1273                     break;
1274                 }
1275             }
1276         }
1277 
1278         if (!bHasContent)
1279             return; // no content in any of the concerned outline nodes
1280     }
1281 
1282     // determine for subs if all are folded or unfolded or if they are mixed
1283     if (rContentTree.iter_has_child(rEntry) || rContentTree.get_children_on_demand(rEntry))
1284     {
1285         // skip no content nodes
1286         // we know there is content from results above so this is presumably safe
1287         size_t nPos = nOutlinePos;
1288         while (true)
1289         {
1290             SwNode* pSttNd = rOutlineNodes[nPos];
1291             SwNode* pEndNd = rOutlineNodes.back();
1292             if (!bIsRoot && rOutlineNodes.size() > nPos + 1)
1293                 pEndNd = rOutlineNodes[nPos + 1];
1294 
1295             SwNodeIndex aIdx(*pSttNd);
1296             if (rNodes.GoNext(&aIdx) != pEndNd)
1297                 break;
1298             nPos++;
1299         }
1300 
1301         bool bHasFolded(!pThis->GetWrtShell()->IsOutlineContentVisible(nPos));
1302         bool bHasUnfolded(!bHasFolded);
1303 
1304         while ((++nPos < pThis->GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineNodesCount()) &&
1305                (bIsRoot || pThis->GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nFirstLevel))
1306         {
1307 
1308             SwNode* pSttNd = rOutlineNodes[nPos];
1309             SwNode* pEndNd = &rNodes.GetEndOfContent();
1310             if (rOutlineNodes.size() > nPos + 1)
1311                 pEndNd = rOutlineNodes[nPos + 1];
1312 
1313             SwNodeIndex aIdx(*pSttNd);
1314             if (rNodes.GoNext(&aIdx) == pEndNd)
1315                 continue; // skip if no content
1316 
1317             if (!pThis->GetWrtShell()->IsOutlineContentVisible(nPos))
1318                 bHasFolded = true;
1319             else
1320                 bHasUnfolded = true;
1321 
1322             if (bHasFolded && bHasUnfolded)
1323                 break; // mixed so no need to continue
1324         }
1325 
1326         rPop.set_sensitive(OString::number(HIDE_OUTLINE_CONTENT_VISIBILITY), bHasUnfolded);
1327         rPop.set_sensitive(OString::number(SHOW_OUTLINE_CONTENT_VISIBILITY), bHasFolded);
1328     }
1329 
1330     rPop.set_sensitive(OString::number(TOGGLE_OUTLINE_CONTENT_VISIBILITY), !bIsRoot);
1331 }
1332 
1333 IMPL_LINK(SwContentTree, CommandHdl, const CommandEvent&, rCEvt, bool)
1334 {
1335     if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
1336         return false;
1337 
1338     std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), "modules/swriter/ui/navigatorcontextmenu.ui"));
1339     std::unique_ptr<weld::Menu> xPop = xBuilder->weld_menu("navmenu");
1340 
1341     bool bOutline(false);
1342     std::unique_ptr<weld::Menu> xSubPop1 = xBuilder->weld_menu("outlinelevel");
1343     std::unique_ptr<weld::Menu> xSubPop2 = xBuilder->weld_menu("dragmodemenu");
1344     std::unique_ptr<weld::Menu> xSubPop3 = xBuilder->weld_menu("displaymenu");
1345     std::unique_ptr<weld::Menu> xSubPopOutlineTracking = xBuilder->weld_menu("outlinetracking");
1346 
1347     std::unique_ptr<weld::Menu> xSubPopOutlineContent = xBuilder->weld_menu("outlinecontent");
1348 
1349     xSubPopOutlineContent->append(OUString::number(TOGGLE_OUTLINE_CONTENT_VISIBILITY),
1350                                   SwResId(STR_OUTLINE_CONTENT_VISIBILITY_TOGGLE));
1351     xSubPopOutlineContent->append(OUString::number(HIDE_OUTLINE_CONTENT_VISIBILITY),
1352                                   SwResId(STR_OUTLINE_CONTENT_VISIBILITY_HIDE_ALL));
1353     xSubPopOutlineContent->append(OUString::number(SHOW_OUTLINE_CONTENT_VISIBILITY),
1354                                   SwResId(STR_OUTLINE_CONTENT_VISIBILITY_SHOW_ALL));
1355 
1356     for(int i = 1; i <= 3; ++i)
1357         xSubPopOutlineTracking->append_radio(OUString::number(i + 10), m_aContextStrings[IDX_STR_OUTLINE_TRACKING + i]);
1358     xSubPopOutlineTracking->set_active(OString::number(10 + m_nOutlineTracking), true);
1359 
1360     for (int i = 1; i <= MAXLEVEL; ++i)
1361         xSubPop1->append_radio(OUString::number(i + 100), OUString::number(i));
1362     xSubPop1->set_active(OString::number(100 + m_nOutlineLevel), true);
1363 
1364     for (int i=0; i < 3; ++i)
1365         xSubPop2->append_radio(OUString::number(i + 201), m_aContextStrings[IDX_STR_HYPERLINK + i]);
1366     xSubPop2->set_active(OString::number(201 + static_cast<int>(GetParentWindow()->GetRegionDropMode())), true);
1367 
1368     // Insert the list of the open files
1369     sal_uInt16 nId = 301;
1370     const SwView* pActiveView = ::GetActiveView();
1371     SwView *pView = SwModule::GetFirstView();
1372     while (pView)
1373     {
1374         OUString sInsert = pView->GetDocShell()->GetTitle();
1375         if (pView == pActiveView)
1376         {
1377             sInsert += "(" +
1378                 m_aContextStrings[IDX_STR_ACTIVE] +
1379                 ")";
1380         }
1381         xSubPop3->append_radio(OUString::number(nId), sInsert);
1382         if (State::CONSTANT == m_eState && m_pActiveShell == &pView->GetWrtShell())
1383             xSubPop3->set_active(OString::number(nId), true);
1384         pView = SwModule::GetNextView(pView);
1385         nId++;
1386     }
1387     xSubPop3->append_radio(OUString::number(nId++), m_aContextStrings[IDX_STR_ACTIVE_VIEW]);
1388     if (m_pHiddenShell)
1389     {
1390         OUString sHiddenEntry = m_pHiddenShell->GetView().GetDocShell()->GetTitle() +
1391             " ( " +
1392             m_aContextStrings[IDX_STR_HIDDEN] +
1393             " )";
1394         xSubPop3->append_radio(OUString::number(nId), sHiddenEntry);
1395     }
1396 
1397     if (State::ACTIVE == m_eState)
1398         xSubPop3->set_active(OString::number(--nId), true);
1399     else if (State::HIDDEN == m_eState)
1400         xSubPop3->set_active(OString::number(nId), true);
1401 
1402     std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
1403     if (!m_xTreeView->get_selected(xEntry.get()))
1404         xEntry.reset();
1405 
1406     if (State::HIDDEN == m_eState || !xEntry || !lcl_IsContent(*xEntry, *m_xTreeView))
1407         xPop->remove(OString::number(900)); // go to
1408 
1409     bool bRemovePostItEntries = true;
1410     bool bRemoveIndexEntries = true;
1411     bool bRemoveEditEntry = true;
1412     bool bRemoveUnprotectEntry = true;
1413     bool bRemoveDeleteEntry = true;
1414     bool bRemoveRenameEntry = true;
1415     bool bRemoveSelectEntry = true;
1416     bool bRemoveToggleExpandEntry = true;
1417     bool bRemoveChapterEntries = true;
1418     bool bRemoveSendOutlineEntry = true;
1419 
1420     // Edit only if the shown content is coming from the current view.
1421     if (State::HIDDEN != m_eState &&
1422             (State::ACTIVE == m_eState || m_pActiveShell == pActiveView->GetWrtShellPtr())
1423             && xEntry && lcl_IsContent(*xEntry, *m_xTreeView))
1424     {
1425         assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
1426         const SwContentType* pContType = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetParent();
1427         const ContentTypeId nContentType = pContType->GetType();
1428         const bool bReadonly = m_pActiveShell->GetView().GetDocShell()->IsReadOnly();
1429         const bool bVisible = !reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->IsInvisible();
1430         const bool bProtected = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->IsProtect();
1431         const bool bProtectBM = (ContentTypeId::BOOKMARK == nContentType)
1432             && m_pActiveShell->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS);
1433         const bool bEditable = pContType->IsEditable() &&
1434             ((bVisible && !bProtected && !bProtectBM) || ContentTypeId::REGION == nContentType);
1435         const bool bDeletable = pContType->IsDeletable() &&
1436             ((bVisible && !bProtected && !bProtectBM) || ContentTypeId::REGION == nContentType);
1437         const bool bRenamable = bEditable && !bReadonly &&
1438             (ContentTypeId::TABLE == nContentType ||
1439                 ContentTypeId::FRAME == nContentType ||
1440                 ContentTypeId::GRAPHIC == nContentType ||
1441                 ContentTypeId::OLE == nContentType ||
1442                 (ContentTypeId::BOOKMARK == nContentType && !bProtectBM) ||
1443                 ContentTypeId::REGION == nContentType ||
1444                 ContentTypeId::INDEX == nContentType ||
1445                 ContentTypeId::DRAWOBJECT == nContentType);
1446 
1447         if(ContentTypeId::OUTLINE == nContentType)
1448         {
1449             bOutline = true;
1450             lcl_SetOutlineContentEntriesSensitivities(this, *m_xTreeView, *xEntry, *xSubPopOutlineContent);
1451             bRemoveToggleExpandEntry = lcl_InsertExpandCollapseAllItem(*m_xTreeView, *xEntry, *xPop);
1452             if (!bReadonly)
1453             {
1454                 bRemoveSelectEntry = false;
1455                 bRemoveChapterEntries = false;
1456             }
1457         }
1458         else if (!bReadonly && (bEditable || bDeletable))
1459         {
1460             if(ContentTypeId::INDEX == nContentType)
1461             {
1462                 bRemoveIndexEntries = false;
1463 
1464                 const SwTOXBase* pBase = reinterpret_cast<SwTOXBaseContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetTOXBase();
1465                 if (!pBase->IsTOXBaseInReadonly())
1466                     bRemoveEditEntry = false;
1467 
1468                 xPop->set_active(OString::number(405), SwEditShell::IsTOXBaseReadonly(*pBase));
1469                 bRemoveDeleteEntry = false;
1470             }
1471             else if(ContentTypeId::TABLE == nContentType)
1472             {
1473                 bRemoveSelectEntry = false;
1474                 bRemoveEditEntry = false;
1475                 bRemoveUnprotectEntry = false;
1476                 bool bFull = false;
1477                 OUString sTableName = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetName();
1478                 bool bProt = m_pActiveShell->HasTableAnyProtection( &sTableName, &bFull );
1479                 xPop->set_sensitive(OString::number(403), !bFull);
1480                 xPop->set_sensitive(OString::number(404), bProt);
1481                 bRemoveDeleteEntry = false;
1482             }
1483             else if(ContentTypeId::DRAWOBJECT == nContentType)
1484             {
1485                 bRemoveDeleteEntry = false;
1486             }
1487             else if(ContentTypeId::REGION == nContentType)
1488             {
1489                 bRemoveSelectEntry = false;
1490                 bRemoveEditEntry = false;
1491             }
1492             else
1493             {
1494                 if (bEditable && bDeletable)
1495                 {
1496                     bRemoveEditEntry = false;
1497                     bRemoveDeleteEntry = false;
1498                 }
1499                 else if (bEditable)
1500                     bRemoveEditEntry = false;
1501                 else if (bDeletable)
1502                 {
1503                     bRemoveDeleteEntry = false;
1504                 }
1505             }
1506             //Rename object
1507             if (bRenamable)
1508                 bRemoveRenameEntry = false;
1509         }
1510     }
1511     else if (xEntry)
1512     {
1513         const SwContentType* pType;
1514         if (lcl_IsContentType(*xEntry, *m_xTreeView))
1515             pType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xEntry).toInt64());
1516         else
1517             pType = reinterpret_cast<SwContent*>(
1518                         m_xTreeView->get_id(*xEntry).toInt64())->GetParent();
1519         if (pType)
1520         {
1521             if (ContentTypeId::OUTLINE == pType->GetType())
1522             {
1523                 bOutline = true;
1524                 if (State::HIDDEN != m_eState)
1525                 {
1526                     lcl_SetOutlineContentEntriesSensitivities(this, *m_xTreeView, *xEntry,
1527                                                               *xSubPopOutlineContent);
1528                     bRemoveSendOutlineEntry = false;
1529                 }
1530                 bRemoveToggleExpandEntry = lcl_InsertExpandCollapseAllItem(*m_xTreeView, *xEntry,
1531                                                                            *xPop);
1532             }
1533             if (State::HIDDEN != m_eState &&
1534                     pType->GetType() == ContentTypeId::POSTIT &&
1535                     !m_pActiveShell->GetView().GetDocShell()->IsReadOnly() &&
1536                     pType->GetMemberCount() > 0)
1537                 bRemovePostItEntries = false;
1538         }
1539     }
1540 
1541     if (bRemoveToggleExpandEntry)
1542     {
1543         xPop->remove("separator3");
1544         xPop->remove(OString::number(800));
1545     }
1546 
1547     if (bRemoveSelectEntry)
1548         xPop->remove(OString::number(805));
1549 
1550     if (bRemoveChapterEntries)
1551     {
1552         xPop->remove("separator2");
1553         xPop->remove(OString::number(806));
1554         xPop->remove(OString::number(801));
1555         xPop->remove(OString::number(802));
1556         xPop->remove(OString::number(803));
1557         xPop->remove(OString::number(804));
1558     }
1559 
1560     if (bRemoveSendOutlineEntry)
1561         xPop->remove(OString::number(700));
1562 
1563     if (bRemovePostItEntries)
1564     {
1565         xPop->remove(OString::number(600));
1566         xPop->remove(OString::number(601));
1567         xPop->remove(OString::number(602));
1568     }
1569 
1570     if (bRemoveDeleteEntry)
1571         xPop->remove(OString::number(501));
1572 
1573     if (bRemoveRenameEntry)
1574         xPop->remove(OString::number(502));
1575 
1576     if (bRemoveIndexEntries)
1577     {
1578         xPop->remove(OString::number(401));
1579         xPop->remove(OString::number(402));
1580         xPop->remove(OString::number(405));
1581     }
1582 
1583     if (bRemoveUnprotectEntry)
1584         xPop->remove(OString::number(404));
1585 
1586     if (bRemoveEditEntry)
1587         xPop->remove(OString::number(403));
1588 
1589     if (bRemoveToggleExpandEntry &&
1590         bRemoveSelectEntry &&
1591         bRemoveChapterEntries &&
1592         bRemoveSendOutlineEntry &&
1593         bRemovePostItEntries &&
1594         bRemoveDeleteEntry &&
1595         bRemoveRenameEntry &&
1596         bRemoveIndexEntries &&
1597         bRemoveUnprotectEntry &&
1598         bRemoveEditEntry)
1599     {
1600         xPop->remove("separator1");
1601     }
1602 
1603     if (!bOutline)
1604     {
1605         xSubPop1.reset();
1606         xPop->remove(OString::number(1)); // outline level menu
1607     }
1608     if (!bOutline || State::HIDDEN == m_eState)
1609     {
1610         xSubPopOutlineTracking.reset();
1611         xPop->remove(OString::number(4)); // outline tracking menu
1612     }
1613     if (!bOutline || State::HIDDEN == m_eState ||
1614             !m_pActiveShell->GetViewOptions()->IsShowOutlineContentVisibilityButton() ||
1615             m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount() == 0)
1616     {
1617         xSubPopOutlineContent.reset();
1618         xPop->remove(OString::number(5)); // outline content menu
1619         xPop->remove("separator1511");
1620     }
1621 
1622     OString sCommand = xPop->popup_at_rect(m_xTreeView.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
1623     if (!sCommand.isEmpty())
1624         ExecuteContextMenuAction(sCommand);
1625 
1626     return true;
1627 }
1628 
1629 void SwContentTree::insert(const weld::TreeIter* pParent, const OUString& rStr, const OUString& rId,
1630                            bool bChildrenOnDemand, weld::TreeIter* pRet)
1631 {
1632     m_xTreeView->insert(pParent, -1, &rStr, &rId, nullptr, nullptr, bChildrenOnDemand, pRet);
1633     ++m_nEntryCount;
1634 }
1635 
1636 void SwContentTree::remove(const weld::TreeIter& rIter)
1637 {
1638     if (m_xTreeView->iter_has_child(rIter))
1639     {
1640         std::unique_ptr<weld::TreeIter> xChild = m_xTreeView->make_iterator(&rIter);
1641         (void)m_xTreeView->iter_children(*xChild);
1642         remove(*xChild);
1643     }
1644     m_xTreeView->remove(rIter);
1645     --m_nEntryCount;
1646 }
1647 
1648 // Content will be integrated into the Box only on demand.
1649 bool SwContentTree::RequestingChildren(const weld::TreeIter& rParent)
1650 {
1651     bool bChild = m_xTreeView->iter_has_child(rParent);
1652     if (bChild || !m_xTreeView->get_children_on_demand(rParent))
1653         return bChild;
1654 
1655     // Is this a content type?
1656     if (lcl_IsContentType(rParent, *m_xTreeView))
1657     {
1658         std::unique_ptr<weld::TreeIter> xChild = m_xTreeView->make_iterator();
1659 
1660         assert(dynamic_cast<SwContentType*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(rParent).toInt64())));
1661         SwContentType* pCntType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(rParent).toInt64());
1662 
1663         const size_t nCount = pCntType->GetMemberCount();
1664         // Add for outline plus/minus
1665         if (pCntType->GetType() == ContentTypeId::OUTLINE)
1666         {
1667             for(size_t i = 0; i < nCount; ++i)
1668             {
1669                 const SwContent* pCnt = pCntType->GetMember(i);
1670                 if(pCnt)
1671                 {
1672                     const auto nLevel = static_cast<const SwOutlineContent*>(pCnt)->GetOutlineLevel();
1673                     OUString sEntry = pCnt->GetName();
1674                     if(sEntry.isEmpty())
1675                         sEntry = m_sSpace;
1676                     OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pCnt)));
1677                     if (!bChild || (nLevel == 0))
1678                     {
1679                         insert(&rParent, sEntry, sId, false, xChild.get());
1680                         m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible());
1681                         m_xTreeView->set_extra_row_indent(*xChild, nLevel + 1 - m_xTreeView->get_iter_depth(*xChild));
1682                         bChild = true;
1683                     }
1684                     else
1685                     {
1686                         //back search parent.
1687                         if(static_cast<const SwOutlineContent*>(pCntType->GetMember(i-1))->GetOutlineLevel() < nLevel)
1688                         {
1689                             insert(xChild.get(), sEntry, sId, false, xChild.get());
1690                             m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible());
1691                             m_xTreeView->set_extra_row_indent(*xChild, nLevel + 1 - m_xTreeView->get_iter_depth(*xChild));
1692                             bChild = true;
1693                         }
1694                         else
1695                         {
1696                             bChild = m_xTreeView->iter_previous(*xChild);
1697                             assert(!bChild || lcl_IsContentType(*xChild, *m_xTreeView) || dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xChild).toInt64())));
1698                             while (bChild &&
1699                                     lcl_IsContent(*xChild, *m_xTreeView) &&
1700                                     (reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xChild).toInt64())->GetOutlineLevel() >= nLevel)
1701                                 )
1702                             {
1703                                 bChild = m_xTreeView->iter_previous(*xChild);
1704                             }
1705                             if (bChild)
1706                             {
1707                                 insert(xChild.get(), sEntry, sId, false, xChild.get());
1708                                 m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible());
1709                                 m_xTreeView->set_extra_row_indent(*xChild, nLevel + 1 - m_xTreeView->get_iter_depth(*xChild));
1710                             }
1711                         }
1712                     }
1713                 }
1714             }
1715         }
1716         else
1717         {
1718             bool bRegion = pCntType->GetType() == ContentTypeId::REGION;
1719             for(size_t i = 0; i < nCount; ++i)
1720             {
1721                 const SwContent* pCnt = pCntType->GetMember(i);
1722                 if (pCnt)
1723                 {
1724                     OUString sEntry = pCnt->GetName();
1725                     if (sEntry.isEmpty())
1726                         sEntry = m_sSpace;
1727                     OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pCnt)));
1728                     insert(&rParent, sEntry, sId, false, xChild.get());
1729                     m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible());
1730                     if (bRegion)
1731                         m_xTreeView->set_extra_row_indent(*xChild, static_cast<const SwRegionContent*>(pCnt)->GetRegionLevel());
1732                     bChild = true;
1733                 }
1734             }
1735         }
1736     }
1737 
1738     return bChild;
1739 }
1740 
1741 SdrObject* SwContentTree::GetDrawingObjectsByContent(const SwContent *pCnt)
1742 {
1743     SdrObject *pRetObj = nullptr;
1744     switch(pCnt->GetParent()->GetType())
1745     {
1746         case ContentTypeId::DRAWOBJECT:
1747         {
1748             SdrView* pDrawView = m_pActiveShell->GetDrawView();
1749             if (pDrawView)
1750             {
1751                 SwDrawModel* pDrawModel = m_pActiveShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
1752                 SdrPage* pPage = pDrawModel->GetPage(0);
1753                 const size_t nCount = pPage->GetObjCount();
1754 
1755                 for( size_t i=0; i<nCount; ++i )
1756                 {
1757                     SdrObject* pTemp = pPage->GetObj(i);
1758                     if( pTemp->GetName() == pCnt->GetName())
1759                     {
1760                         pRetObj = pTemp;
1761                         break;
1762                     }
1763                 }
1764             }
1765             break;
1766         }
1767         default:
1768             pRetObj = nullptr;
1769     }
1770     return pRetObj;
1771 }
1772 
1773 void SwContentTree::Expand(const weld::TreeIter& rParent, std::vector<std::unique_ptr<weld::TreeIter>>* pNodesToExpand)
1774 {
1775     if (!(m_xTreeView->iter_has_child(rParent) || m_xTreeView->get_children_on_demand(rParent)))
1776         return;
1777 
1778     if (!m_bIsRoot
1779         || (lcl_IsContentType(rParent, *m_xTreeView) &&
1780             reinterpret_cast<SwContentType*>(m_xTreeView->get_id(rParent).toInt64())->GetType() == ContentTypeId::OUTLINE)
1781         || (m_nRootType == ContentTypeId::OUTLINE))
1782     {
1783         if (lcl_IsContentType(rParent, *m_xTreeView))
1784         {
1785             SwContentType* pCntType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(rParent).toInt64());
1786             const sal_Int32 nOr = 1 << static_cast<int>(pCntType->GetType()); //linear -> Bitposition
1787             if (State::HIDDEN != m_eState)
1788             {
1789                 m_nActiveBlock |= nOr;
1790                 m_pConfig->SetActiveBlock(m_nActiveBlock);
1791             }
1792             else
1793                 m_nHiddenBlock |= nOr;
1794             if (pCntType->GetType() == ContentTypeId::OUTLINE)
1795             {
1796                 std::map< void*, bool > aCurrOutLineNodeMap;
1797 
1798                 SwWrtShell* pShell = GetWrtShell();
1799                 bool bParentHasChild = RequestingChildren(rParent);
1800                 if (pNodesToExpand)
1801                     pNodesToExpand->emplace_back(m_xTreeView->make_iterator(&rParent));
1802                 if (bParentHasChild)
1803                 {
1804                     std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(&rParent));
1805                     bool bChild = m_xTreeView->iter_next(*xChild);
1806                     while (bChild && lcl_IsContent(*xChild, *m_xTreeView))
1807                     {
1808                         if (m_xTreeView->iter_has_child(*xChild))
1809                         {
1810                             assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xChild).toInt64())));
1811                             auto const nPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xChild).toInt64())->GetOutlinePos();
1812                             void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
1813                             aCurrOutLineNodeMap.emplace( key, false );
1814                             std::map<void*, bool>::iterator iter = mOutLineNodeMap.find( key );
1815                             if( iter != mOutLineNodeMap.end() && mOutLineNodeMap[key])
1816                             {
1817                                 aCurrOutLineNodeMap[key] = true;
1818                                 RequestingChildren(*xChild);
1819                                 if (pNodesToExpand)
1820                                     pNodesToExpand->emplace_back(m_xTreeView->make_iterator(xChild.get()));
1821                                 m_xTreeView->set_children_on_demand(*xChild, false);
1822                             }
1823                         }
1824                         bChild = m_xTreeView->iter_next(*xChild);
1825                     }
1826                 }
1827                 mOutLineNodeMap = aCurrOutLineNodeMap;
1828                 return;
1829             }
1830         }
1831         else
1832         {
1833             if (lcl_IsContent(rParent, *m_xTreeView))
1834             {
1835                 SwWrtShell* pShell = GetWrtShell();
1836                 // paranoid assert now that outline type is checked
1837                 assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(rParent).toInt64())));
1838                 auto const nPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(rParent).toInt64())->GetOutlinePos();
1839                 void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
1840                 mOutLineNodeMap[key] = true;
1841             }
1842         }
1843     }
1844 
1845     RequestingChildren(rParent);
1846     if (pNodesToExpand)
1847         pNodesToExpand->emplace_back(m_xTreeView->make_iterator(&rParent));
1848 }
1849 
1850 IMPL_LINK(SwContentTree, ExpandHdl, const weld::TreeIter&, rParent, bool)
1851 {
1852     Expand(rParent, nullptr);
1853     return true;
1854 }
1855 
1856 IMPL_LINK(SwContentTree, CollapseHdl, const weld::TreeIter&, rParent, bool)
1857 {
1858     if (!m_xTreeView->iter_has_child(rParent) || m_xTreeView->get_children_on_demand(rParent))
1859         return true;
1860 
1861     if (lcl_IsContentType(rParent, *m_xTreeView))
1862     {
1863         if (m_bIsRoot)
1864         {
1865             // collapse to children of root node
1866             std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(&rParent));
1867             if (m_xTreeView->iter_children(*xEntry))
1868             {
1869                 do
1870                 {
1871                     m_xTreeView->collapse_row(*xEntry);
1872                 }
1873                 while (m_xTreeView->iter_next(*xEntry));
1874             }
1875             return false; // return false to notify caller not to do collapse
1876         }
1877         SwContentType* pCntType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(rParent).toInt64());
1878         const sal_Int32 nAnd = ~(1 << static_cast<int>(pCntType->GetType()));
1879         if (State::HIDDEN != m_eState)
1880         {
1881             m_nActiveBlock &= nAnd;
1882             m_pConfig->SetActiveBlock(m_nActiveBlock);
1883         }
1884         else
1885             m_nHiddenBlock &= nAnd;
1886     }
1887     else if (lcl_IsContent(rParent, *m_xTreeView))
1888     {
1889         SwWrtShell* pShell = GetWrtShell();
1890         assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(rParent).toInt64())));
1891         auto const nPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(rParent).toInt64())->GetOutlinePos();
1892         void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
1893         mOutLineNodeMap[key] = false;
1894     }
1895 
1896     return true;
1897 }
1898 
1899 // Also on double click will be initially opened only.
1900 IMPL_LINK_NOARG(SwContentTree, ContentDoubleClickHdl, weld::TreeView&, bool)
1901 {
1902     bool bConsumed = false;
1903 
1904     std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
1905     bool bEntry = m_xTreeView->get_cursor(xEntry.get());
1906     // Is it a content type?
1907     OSL_ENSURE(bEntry, "no current entry!");
1908     if (bEntry)
1909     {
1910         if (lcl_IsContentType(*xEntry, *m_xTreeView) && !m_xTreeView->iter_has_child(*xEntry))
1911         {
1912             RequestingChildren(*xEntry);
1913             m_xTreeView->set_children_on_demand(*xEntry, false);
1914         }
1915         else if (!lcl_IsContentType(*xEntry, *m_xTreeView) && (State::HIDDEN != m_eState))
1916         {
1917             if (State::CONSTANT == m_eState)
1918             {
1919                 m_pActiveShell->GetView().GetViewFrame()->GetWindow().ToTop();
1920             }
1921             //Jump to content type:
1922             assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
1923             SwContent* pCnt = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64());
1924             assert(pCnt && "no UserData");
1925             GotoContent(pCnt);
1926             // fdo#36308 don't expand outlines on double-click
1927             bConsumed = pCnt->GetParent()->GetType() == ContentTypeId::OUTLINE;
1928         }
1929     }
1930 
1931     return bConsumed; // false/true == allow/disallow more to be done, i.e. expand/collapse children
1932 }
1933 
1934 namespace
1935 {
1936     OUString GetImageIdForContentTypeId(ContentTypeId eType)
1937     {
1938         OUString sResId;
1939 
1940         switch (eType)
1941         {
1942             case ContentTypeId::OUTLINE:
1943                 sResId = RID_BMP_NAVI_OUTLINE;
1944                 break;
1945             case ContentTypeId::TABLE:
1946                 sResId = RID_BMP_NAVI_TABLE;
1947                 break;
1948             case ContentTypeId::FRAME:
1949                 sResId = RID_BMP_NAVI_FRAME;
1950                 break;
1951             case ContentTypeId::GRAPHIC:
1952                 sResId = RID_BMP_NAVI_GRAPHIC;
1953                 break;
1954             case ContentTypeId::OLE:
1955                 sResId = RID_BMP_NAVI_OLE;
1956                 break;
1957             case ContentTypeId::BOOKMARK:
1958                 sResId = RID_BMP_NAVI_BOOKMARK;
1959                 break;
1960             case ContentTypeId::REGION:
1961                 sResId = RID_BMP_NAVI_REGION;
1962                 break;
1963             case ContentTypeId::URLFIELD:
1964                 sResId = RID_BMP_NAVI_URLFIELD;
1965                 break;
1966             case ContentTypeId::REFERENCE:
1967                 sResId = RID_BMP_NAVI_REFERENCE;
1968                 break;
1969             case ContentTypeId::INDEX:
1970                 sResId = RID_BMP_NAVI_INDEX;
1971                 break;
1972             case ContentTypeId::POSTIT:
1973                 sResId = RID_BMP_NAVI_POSTIT;
1974                 break;
1975             case ContentTypeId::DRAWOBJECT:
1976                 sResId = RID_BMP_NAVI_DRAWOBJECT;
1977                 break;
1978             case ContentTypeId::UNKNOWN:
1979                 SAL_WARN("sw.ui", "ContentTypeId::UNKNOWN has no bitmap preview");
1980                 break;
1981         }
1982 
1983         return sResId;
1984     };
1985 }
1986 
1987 size_t SwContentTree::GetAbsPos(const weld::TreeIter& rIter)
1988 {
1989     return weld::GetAbsPos(*m_xTreeView, rIter);
1990 }
1991 
1992 size_t SwContentTree::GetEntryCount() const
1993 {
1994     return m_nEntryCount;
1995 }
1996 
1997 size_t SwContentTree::GetChildCount(const weld::TreeIter& rParent) const
1998 {
1999     if (!m_xTreeView->iter_has_child(rParent))
2000         return 0;
2001 
2002     std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rParent));
2003 
2004     size_t nCount = 0;
2005     auto nRefDepth = m_xTreeView->get_iter_depth(*xParent);
2006     auto nActDepth = nRefDepth;
2007     do
2008     {
2009         if (!m_xTreeView->iter_next(*xParent))
2010             xParent.reset();
2011         else
2012             nActDepth = m_xTreeView->get_iter_depth(*xParent);
2013         nCount++;
2014     } while(xParent && nRefDepth < nActDepth);
2015 
2016     nCount--;
2017     return nCount;
2018 }
2019 
2020 std::unique_ptr<weld::TreeIter> SwContentTree::GetEntryAtAbsPos(size_t nAbsPos) const
2021 {
2022     std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
2023     if (!m_xTreeView->get_iter_first(*xEntry))
2024         xEntry.reset();
2025 
2026     while (nAbsPos && xEntry)
2027     {
2028         if (!m_xTreeView->iter_next(*xEntry))
2029             xEntry.reset();
2030         nAbsPos--;
2031     }
2032     return xEntry;
2033 }
2034 
2035 void SwContentTree::Display( bool bActive )
2036 {
2037     // First read the selected entry to select it later again if necessary
2038     // -> the user data here are no longer valid!
2039     std::unique_ptr<weld::TreeIter> xOldSelEntry(m_xTreeView->make_iterator());
2040     if (!m_xTreeView->get_selected(xOldSelEntry.get()))
2041         xOldSelEntry.reset();
2042     OUString sEntryName;  // Name of the entry
2043     size_t nEntryRelPos = 0; // relative position to their parent
2044     size_t nOldEntryCount = GetEntryCount();
2045     sal_Int32 nOldScrollPos = 0;
2046     if (xOldSelEntry)
2047     {
2048         UpdateLastSelType();
2049 
2050         nOldScrollPos = m_xTreeView->vadjustment_get_value();
2051         sEntryName = m_xTreeView->get_text(*xOldSelEntry);
2052         std::unique_ptr<weld::TreeIter> xParentEntry = m_xTreeView->make_iterator(xOldSelEntry.get());
2053         while (m_xTreeView->get_iter_depth(*xParentEntry))
2054             m_xTreeView->iter_parent(*xParentEntry);
2055         if (m_xTreeView->get_iter_depth(*xOldSelEntry))
2056             nEntryRelPos = GetAbsPos(*xOldSelEntry) - GetAbsPos(*xParentEntry);
2057     }
2058 
2059     clear();
2060 
2061     if (!bActive)
2062         m_eState = State::HIDDEN;
2063     else if (State::HIDDEN == m_eState)
2064         m_eState = State::ACTIVE;
2065     SwWrtShell* pShell = GetWrtShell();
2066     const bool bReadOnly = !pShell || pShell->GetView().GetDocShell()->IsReadOnly();
2067     if(bReadOnly != m_bIsLastReadOnly)
2068     {
2069         m_bIsLastReadOnly = bReadOnly;
2070         bool bDisable =  pShell == nullptr || bReadOnly;
2071         SwNavigationPI* pNavi = GetParentWindow();
2072         pNavi->m_xContent6ToolBox->set_item_sensitive("chapterup", !bDisable);
2073         pNavi->m_xContent6ToolBox->set_item_sensitive("chapterdown", !bDisable);
2074         pNavi->m_xContent6ToolBox->set_item_sensitive("promote", !bDisable);
2075         pNavi->m_xContent6ToolBox->set_item_sensitive("demote", !bDisable);
2076         pNavi->m_xContent5ToolBox->set_item_sensitive("reminder", !bDisable);
2077     }
2078 
2079     if (pShell)
2080     {
2081         std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
2082         std::unique_ptr<weld::TreeIter> xSelEntry;
2083         std::vector<std::unique_ptr<weld::TreeIter>> aNodesToExpand;
2084         // all content navigation view
2085         if(m_nRootType == ContentTypeId::UNKNOWN)
2086         {
2087             m_xTreeView->freeze();
2088 
2089             for( ContentTypeId nCntType : o3tl::enumrange<ContentTypeId>() )
2090             {
2091                 std::unique_ptr<SwContentType>& rpContentT = bActive ?
2092                                     m_aActiveContentArr[nCntType] :
2093                                     m_aHiddenContentArr[nCntType];
2094                 if(!rpContentT)
2095                     rpContentT.reset(new SwContentType(pShell, nCntType, m_nOutlineLevel ));
2096 
2097                 OUString aImage(GetImageIdForContentTypeId(nCntType));
2098                 bool bChOnDemand = 0 != rpContentT->GetMemberCount();
2099                 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(rpContentT.get())));
2100                 insert(nullptr, rpContentT->GetName(), sId, bChOnDemand, xEntry.get());
2101                 m_xTreeView->set_image(*xEntry, aImage);
2102 
2103                 m_xTreeView->set_sensitive(*xEntry, bChOnDemand);
2104 
2105                 if (nCntType == m_nLastSelType)
2106                     xSelEntry = m_xTreeView->make_iterator(xEntry.get());
2107                 sal_Int32 nExpandOptions = (State::HIDDEN == m_eState)
2108                                             ? m_nHiddenBlock
2109                                             : m_nActiveBlock;
2110                 if (nExpandOptions & (1 << static_cast<int>(nCntType)))
2111                 {
2112                     // fill contents of to-be expanded entries while frozen
2113                     Expand(*xEntry, &aNodesToExpand);
2114                     m_xTreeView->set_children_on_demand(*xEntry, false);
2115                 }
2116             }
2117 
2118             m_xTreeView->thaw();
2119 
2120             // restore visual expanded tree state
2121             for (const auto& rNode : aNodesToExpand)
2122                 m_xTreeView->expand_row(*rNode);
2123 
2124             (void)m_xTreeView->get_iter_first(*xEntry);
2125             for (ContentTypeId nCntType : o3tl::enumrange<ContentTypeId>())
2126             {
2127                 sal_Int32 nExpandOptions = (State::HIDDEN == m_eState)
2128                                             ? m_nHiddenBlock
2129                                             : m_nActiveBlock;
2130                 if (nExpandOptions & (1 << static_cast<int>(nCntType)))
2131                 {
2132                     if (nEntryRelPos && nCntType == m_nLastSelType)
2133                     {
2134                         // reselect the entry
2135                         std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(xEntry.get()));
2136                         std::unique_ptr<weld::TreeIter> xTemp;
2137                         sal_uLong nPos = 1;
2138                         while (m_xTreeView->iter_next(*xChild))
2139                         {
2140                             // The old text will be slightly favored
2141                             if (sEntryName == m_xTreeView->get_text(*xChild) ||
2142                                 nPos == nEntryRelPos)
2143                             {
2144                                 m_xTreeView->copy_iterator(*xChild, *xSelEntry);
2145                                 break;
2146                             }
2147                             xTemp = m_xTreeView->make_iterator(xChild.get());
2148                             nPos++;
2149                         }
2150                         if (!xSelEntry || lcl_IsContentType(*xSelEntry, *m_xTreeView))
2151                             xSelEntry = std::move(xTemp);
2152                     }
2153                 }
2154 
2155                 (void)m_xTreeView->iter_next_sibling(*xEntry);
2156             }
2157 
2158             if (!xSelEntry)
2159             {
2160                 nOldScrollPos = 0;
2161                 xSelEntry = m_xTreeView->make_iterator();
2162                 if (!m_xTreeView->get_iter_first(*xSelEntry))
2163                     xSelEntry.reset();
2164             }
2165 
2166             if (xSelEntry)
2167             {
2168                 m_xTreeView->set_cursor(*xSelEntry);
2169                 Select();
2170             }
2171         }
2172         // root content navigation view
2173         else
2174         {
2175             m_xTreeView->freeze();
2176 
2177             std::unique_ptr<SwContentType>& rpRootContentT = bActive ?
2178                                     m_aActiveContentArr[m_nRootType] :
2179                                     m_aHiddenContentArr[m_nRootType];
2180             if(!rpRootContentT)
2181                 rpRootContentT.reset(new SwContentType(pShell, m_nRootType, m_nOutlineLevel ));
2182             OUString aImage(GetImageIdForContentTypeId(m_nRootType));
2183             bool bChOnDemand = m_nRootType == ContentTypeId::OUTLINE;
2184             OUString sId(OUString::number(reinterpret_cast<sal_Int64>(rpRootContentT.get())));
2185             insert(nullptr, rpRootContentT->GetName(), sId, bChOnDemand, xEntry.get());
2186             m_xTreeView->set_image(*xEntry, aImage);
2187 
2188             if (!bChOnDemand)
2189             {
2190                 bool bRegion = rpRootContentT->GetType() == ContentTypeId::REGION;
2191 
2192                 std::unique_ptr<weld::TreeIter> xChild = m_xTreeView->make_iterator();
2193                 for (size_t i = 0; i < rpRootContentT->GetMemberCount(); ++i)
2194                 {
2195                     const SwContent* pCnt = rpRootContentT->GetMember(i);
2196                     if (pCnt)
2197                     {
2198                         OUString sEntry = pCnt->GetName();
2199                         if(sEntry.isEmpty())
2200                             sEntry = m_sSpace;
2201                         OUString sSubId(OUString::number(reinterpret_cast<sal_Int64>(pCnt)));
2202                         insert(xEntry.get(), sEntry, sSubId, false, xChild.get());
2203                         m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible());
2204                         if (bRegion)
2205                             m_xTreeView->set_extra_row_indent(*xChild, static_cast<const SwRegionContent*>(pCnt)->GetRegionLevel());
2206                     }
2207                 }
2208             }
2209             else
2210             {
2211                 // fill contents of to-be expanded entries while frozen
2212                 Expand(*xEntry, &aNodesToExpand);
2213                 m_xTreeView->set_children_on_demand(*xEntry, false);
2214             }
2215 
2216             m_xTreeView->set_sensitive(*xEntry, m_xTreeView->iter_has_child(*xEntry));
2217 
2218             m_xTreeView->thaw();
2219 
2220             if (bChOnDemand)
2221             {
2222                 // restore visual expanded tree state
2223                 for (const auto& rNode : aNodesToExpand)
2224                     m_xTreeView->expand_row(*rNode);
2225             }
2226             else
2227                 m_xTreeView->expand_row(*xEntry);
2228 
2229             // reselect the entry
2230             if (nEntryRelPos)
2231             {
2232                 std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(xEntry.get()));
2233                 sal_uLong nPos = 1;
2234                 while (m_xTreeView->iter_next(*xChild))
2235                 {
2236                     // The old text will be slightly favored
2237                     if (sEntryName == m_xTreeView->get_text(*xChild) || nPos == nEntryRelPos)
2238                     {
2239                         xSelEntry = std::move(xChild);
2240                         break;
2241                     }
2242                     nPos++;
2243                 }
2244                 if (xSelEntry)
2245                 {
2246                     m_xTreeView->set_cursor(*xSelEntry); // unselect all entries, make pSelEntry visible, and select
2247                     Select();
2248                 }
2249             }
2250             else
2251             {
2252                 m_xTreeView->set_cursor(*xEntry);
2253                 Select();
2254             }
2255         }
2256     }
2257 
2258     if (!m_bIgnoreViewChange && GetEntryCount() == nOldEntryCount)
2259     {
2260         m_xTreeView->vadjustment_set_value(nOldScrollPos);
2261     }
2262 }
2263 
2264 void SwContentTree::clear()
2265 {
2266     m_xTreeView->freeze();
2267     m_xTreeView->clear();
2268     m_nEntryCount = 0;
2269     m_xTreeView->thaw();
2270 }
2271 
2272 bool SwContentTree::FillTransferData( TransferDataContainer& rTransfer,
2273                                             sal_Int8& rDragMode )
2274 {
2275     bool bRet = false;
2276     SwWrtShell* pWrtShell = GetWrtShell();
2277     OSL_ENSURE(pWrtShell, "no Shell!");
2278 
2279     std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
2280     bool bEntry = m_xTreeView->get_cursor(xEntry.get());
2281     if (!bEntry || lcl_IsContentType(*xEntry, *m_xTreeView) || !pWrtShell)
2282         return false;
2283     OUString sEntry;
2284     assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
2285     SwContent* pCnt = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64());
2286 
2287     const ContentTypeId nActType = pCnt->GetParent()->GetType();
2288     OUString sUrl;
2289     bool bOutline = false;
2290     OUString sOutlineText;
2291     switch( nActType )
2292     {
2293         case ContentTypeId::OUTLINE:
2294         {
2295             const SwOutlineNodes::size_type nPos = static_cast<SwOutlineContent*>(pCnt)->GetOutlinePos();
2296             OSL_ENSURE(nPos < pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount(),
2297                        "outlinecnt changed");
2298 
2299             // make sure outline may actually be copied
2300             if( pWrtShell->IsOutlineCopyable( nPos ) )
2301             {
2302                 const SwNumRule* pOutlRule = pWrtShell->GetOutlineNumRule();
2303                 const SwTextNode* pTextNd =
2304                         pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNode(nPos);
2305                 if (pTextNd && pOutlRule && pTextNd->IsNumbered(pWrtShell->GetLayout()))
2306                 {
2307                     SwNumberTree::tNumberVector aNumVector =
2308                         pTextNd->GetNumberVector(pWrtShell->GetLayout());
2309                     for( int nLevel = 0;
2310                          nLevel <= pTextNd->GetActualListLevel();
2311                          nLevel++ )
2312                     {
2313                         const SwNumberTree::tSwNumTreeNumber nVal = aNumVector[nLevel] + 1;
2314                         sEntry += OUString::number( nVal - pOutlRule->Get(nLevel).GetStart() ) + ".";
2315                     }
2316                 }
2317                 sEntry += pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineText(nPos, pWrtShell->GetLayout(), false);
2318                 sOutlineText = pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineText(nPos, pWrtShell->GetLayout());
2319                 m_bIsOutlineMoveable = static_cast<SwOutlineContent*>(pCnt)->IsMoveable();
2320                 bOutline = true;
2321             }
2322         }
2323         break;
2324         case ContentTypeId::POSTIT:
2325         case ContentTypeId::INDEX:
2326         case ContentTypeId::REFERENCE :
2327             // cannot be inserted, neither as URL nor as section
2328         break;
2329         case ContentTypeId::URLFIELD:
2330             sUrl = static_cast<SwURLFieldContent*>(pCnt)->GetURL();
2331             [[fallthrough]];
2332         case ContentTypeId::OLE:
2333         case ContentTypeId::GRAPHIC:
2334             if(GetParentWindow()->GetRegionDropMode() != RegionMode::NONE)
2335                 break;
2336             else
2337                 rDragMode &= ~( DND_ACTION_MOVE | DND_ACTION_LINK );
2338             [[fallthrough]];
2339         default:
2340             sEntry = m_xTreeView->get_text(*xEntry);
2341     }
2342 
2343     if(!sEntry.isEmpty())
2344     {
2345         const SwDocShell* pDocShell = pWrtShell->GetView().GetDocShell();
2346         if(sUrl.isEmpty())
2347         {
2348             if(pDocShell->HasName())
2349             {
2350                 SfxMedium* pMedium = pDocShell->GetMedium();
2351                 sUrl = pMedium->GetURLObject().GetURLNoMark();
2352                 // only if a primarily link shall be integrated.
2353                 bRet = true;
2354             }
2355             else if ( nActType == ContentTypeId::REGION || nActType == ContentTypeId::BOOKMARK )
2356             {
2357                 // For field and bookmarks a link is also allowed
2358                 // without a filename into its own document.
2359                 bRet = true;
2360             }
2361             else if (State::CONSTANT == m_eState &&
2362                     ( !::GetActiveView() ||
2363                         m_pActiveShell != ::GetActiveView()->GetWrtShellPtr()))
2364             {
2365                 // Urls of inactive views cannot dragged without
2366                 // file names, also.
2367                 bRet = false;
2368             }
2369             else
2370             {
2371                 bRet = GetParentWindow()->GetRegionDropMode() == RegionMode::NONE;
2372                 rDragMode = DND_ACTION_MOVE;
2373             }
2374 
2375             const OUString& rToken = pCnt->GetParent()->GetTypeToken();
2376             sUrl += "#" + sEntry;
2377             if(!rToken.isEmpty())
2378             {
2379                 sUrl += OUStringChar(cMarkSeparator) + rToken;
2380             }
2381         }
2382         else
2383             bRet = true;
2384 
2385         if( bRet )
2386         {
2387             // In Outlines of heading text must match
2388             // the real number into the description.
2389             if(bOutline)
2390                 sEntry = sOutlineText;
2391 
2392             {
2393                 NaviContentBookmark aBmk( sUrl, sEntry,
2394                                     GetParentWindow()->GetRegionDropMode(),
2395                                     pDocShell);
2396                 aBmk.Copy( rTransfer );
2397             }
2398 
2399             // An INetBookmark must a be delivered to foreign DocShells
2400             if( pDocShell->HasName() )
2401             {
2402                 INetBookmark aBkmk( sUrl, sEntry );
2403                 rTransfer.CopyINetBookmark( aBkmk );
2404             }
2405         }
2406     }
2407     return bRet;
2408 }
2409 
2410 void SwContentTree::ToggleToRoot()
2411 {
2412     if(!m_bIsRoot)
2413     {
2414         std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
2415         bool bEntry = m_xTreeView->get_cursor(xEntry.get());
2416         if (bEntry)
2417         {
2418             const SwContentType* pCntType;
2419             if (lcl_IsContentType(*xEntry, *m_xTreeView))
2420             {
2421                 assert(dynamic_cast<SwContentType*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
2422                 pCntType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xEntry).toInt64());
2423             }
2424             else
2425             {
2426                 assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
2427                 pCntType = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetParent();
2428             }
2429             m_nRootType = pCntType->GetType();
2430             m_bIsRoot = true;
2431             Display(State::HIDDEN != m_eState);
2432             if (m_nRootType == ContentTypeId::OUTLINE)
2433             {
2434                 m_xTreeView->set_selection_mode(SelectionMode::Multiple);
2435             }
2436         }
2437     }
2438     else
2439     {
2440         m_xTreeView->set_selection_mode(SelectionMode::Single);
2441         m_nRootType = ContentTypeId::UNKNOWN;
2442         m_bIsRoot = false;
2443         FindActiveTypeAndRemoveUserData();
2444         Display(State::HIDDEN != m_eState);
2445     }
2446     m_pConfig->SetRootType( m_nRootType );
2447     weld::Toolbar* pBox = GetParentWindow()->m_xContent5ToolBox.get();
2448     pBox->set_item_active("root", m_bIsRoot);
2449 }
2450 
2451 bool SwContentTree::HasContentChanged()
2452 {
2453     bool bContentChanged = false;
2454 
2455 //  - Run through the local array and the Treelistbox in parallel.
2456 //  - Are the records not expanded, they are discarded only in the array
2457 //    and the content type will be set as the new UserData.
2458 //  - Is the root mode is active only this will be updated.
2459 
2460 //  Valid for the displayed content types is:
2461 //  the Memberlist will be erased and the membercount will be updated
2462 //  If content will be checked, the memberlists will be replenished
2463 //  at the same time. Once a difference occurs it will be only replenished
2464 //  no longer checked. Finally, the box is filled again.
2465 
2466     // bVisibilityChanged gets set to true if some element, like a section,
2467     // changed visibility and should have its name rerendered with a new
2468     // grayed-out state
2469     bool bVisibilityChanged = false;
2470 
2471     if (State::HIDDEN == m_eState)
2472     {
2473         for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
2474         {
2475             if(m_aActiveContentArr[i])
2476                 m_aActiveContentArr[i]->Invalidate();
2477         }
2478     }
2479     // root content navigation view
2480     else if(m_bIsRoot)
2481     {
2482         std::unique_ptr<weld::TreeIter> xRootEntry(m_xTreeView->make_iterator());
2483         if (!m_xTreeView->get_iter_first(*xRootEntry))
2484             bContentChanged = true;
2485         else
2486         {
2487             assert(dynamic_cast<SwContentType*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xRootEntry).toInt64())));
2488             const ContentTypeId nType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xRootEntry).toInt64())->GetType();
2489             SwContentType* pArrType = m_aActiveContentArr[nType].get();
2490             if (!pArrType)
2491                 bContentChanged = true;
2492             else
2493             {
2494                 // start check if first selected outline level has changed
2495                 bool bCheckChanged = m_nRootType == ContentTypeId::OUTLINE && !m_xTreeView->has_focus();
2496                 if (bCheckChanged)
2497                 {
2498                     std::unique_ptr<weld::TreeIter> xFirstSel(m_xTreeView->make_iterator());
2499                     bool bFirstSel = m_xTreeView->get_selected(xFirstSel.get());
2500                     if (bFirstSel && lcl_IsContent(*xFirstSel, *m_xTreeView))
2501                     {
2502                         assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xFirstSel).toInt64())));
2503                         const auto nSelLevel = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xFirstSel).toInt64())->GetOutlineLevel();
2504                         SwWrtShell* pSh = GetWrtShell();
2505                         const SwOutlineNodes::size_type nOutlinePos = pSh->GetOutlinePos(MAXLEVEL);
2506                         if (nOutlinePos != SwOutlineNodes::npos && pSh->getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos) != nSelLevel)
2507                             bContentChanged = true;
2508                     }
2509                 }
2510                 // end check if first selected outline level has changed
2511 
2512                 pArrType->Init(&bVisibilityChanged);
2513                 pArrType->FillMemberList();
2514                 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pArrType)));
2515                 m_xTreeView->set_id(*xRootEntry, sId);
2516                 if (!bContentChanged)
2517                 {
2518                     const size_t nChildCount = GetChildCount(*xRootEntry);
2519                     if (nChildCount != pArrType->GetMemberCount())
2520                         bContentChanged = true;
2521                     else
2522                     {
2523                         std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(xRootEntry.get()));
2524                         for (size_t j = 0; j < nChildCount; ++j)
2525                         {
2526                             m_xTreeView->iter_next(*xEntry);
2527                             const SwContent* pCnt = pArrType->GetMember(j);
2528                             OUString sSubId(OUString::number(reinterpret_cast<sal_Int64>(pCnt)));
2529                             m_xTreeView->set_id(*xEntry, sSubId);
2530                             OUString sEntryText = m_xTreeView->get_text(*xEntry);
2531                             if( sEntryText != pCnt->GetName() &&
2532                                 !(sEntryText == m_sSpace && pCnt->GetName().isEmpty()))
2533                                 bContentChanged = true;
2534                         }
2535                     }
2536                 }
2537             }
2538         }
2539     }
2540     // all content navigation view
2541     else
2542     {
2543         std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
2544         bool bEntry = m_xTreeView->get_iter_first(*xEntry);
2545         while (bEntry)
2546         {
2547             bool bNext = true; // at least a next must be
2548             assert(dynamic_cast<SwContentType*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
2549             SwContentType* pCntType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xEntry).toInt64());
2550             const size_t nCntCount = pCntType->GetMemberCount();
2551             const ContentTypeId nType = pCntType->GetType();
2552             SwContentType* pArrType = m_aActiveContentArr[nType].get();
2553             if (!pArrType)
2554                 bContentChanged = true;
2555             else
2556             {
2557                 pArrType->Init(&bVisibilityChanged);
2558                 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pArrType)));
2559                 m_xTreeView->set_id(*xEntry, sId);
2560                 if (m_xTreeView->get_row_expanded(*xEntry))
2561                 {
2562                     bool bLevelOrVisibilityChanged = false;
2563                     // bLevelOrVisibilityChanged is set if outlines have changed their level
2564                     // or if the visibility of objects (frames, sections, tables) has changed
2565                     // i.e. in header/footer
2566                     pArrType->FillMemberList(&bLevelOrVisibilityChanged);
2567                     const size_t nChildCount = GetChildCount(*xEntry);
2568                     if (bLevelOrVisibilityChanged)
2569                     {
2570                         if (nType == ContentTypeId::OUTLINE)
2571                             bContentChanged = true;
2572                         else
2573                             bVisibilityChanged = true;
2574                     }
2575 
2576                     if(nChildCount != pArrType->GetMemberCount())
2577                         bContentChanged = true;
2578                     else
2579                     {
2580                         for(size_t j = 0; j < nChildCount; ++j)
2581                         {
2582                             bEntry = m_xTreeView->iter_next(*xEntry);
2583                             bNext = false;
2584                             const SwContent* pCnt = pArrType->GetMember(j);
2585                             OUString sSubId(OUString::number(reinterpret_cast<sal_Int64>(pCnt)));
2586                             m_xTreeView->set_id(*xEntry, sSubId);
2587                             OUString sEntryText = m_xTreeView->get_text(*xEntry);
2588                             if( sEntryText != pCnt->GetName() &&
2589                                 !(sEntryText == m_sSpace && pCnt->GetName().isEmpty()))
2590                                 bContentChanged = true;
2591                         }
2592                     }
2593                 }
2594                 // not expanded and has children
2595                 else if (m_xTreeView->iter_has_child(*xEntry))
2596                 {
2597                     // was the entry once opened, then must also the
2598                     // invisible records be examined.
2599                     // At least the user data must be updated.
2600                     bool bLevelOrVisibilityChanged = false;
2601                     // bLevelOrVisibilityChanged is set if outlines have changed their level
2602                     // or if the visibility of objects (frames, sections, tables) has changed
2603                     // i.e. in header/footer
2604                     pArrType->FillMemberList(&bLevelOrVisibilityChanged);
2605                     bool bRemoveChildren = false;
2606                     const size_t nOldChildCount = GetChildCount(*xEntry);
2607                     const size_t nNewChildCount = pArrType->GetMemberCount();
2608                     if (nOldChildCount != nNewChildCount)
2609                     {
2610                         bRemoveChildren = true;
2611                     }
2612                     else
2613                     {
2614                         std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(xEntry.get()));
2615                         (void)m_xTreeView->iter_children(*xChild);
2616                         for (size_t j = 0; j < nOldChildCount; ++j)
2617                         {
2618                             const SwContent* pCnt = pArrType->GetMember(j);
2619                             OUString sSubId(OUString::number(reinterpret_cast<sal_Int64>(pCnt)));
2620                             m_xTreeView->set_id(*xChild, sSubId);
2621                             OUString sEntryText = m_xTreeView->get_text(*xChild);
2622                             if( sEntryText != pCnt->GetName() &&
2623                                 !(sEntryText == m_sSpace && pCnt->GetName().isEmpty()))
2624                                 bRemoveChildren = true;
2625                             (void)m_xTreeView->iter_next(*xChild);
2626                         }
2627                     }
2628                     if (bRemoveChildren)
2629                     {
2630                         std::unique_ptr<weld::TreeIter> xRemove(m_xTreeView->make_iterator(xEntry.get()));
2631                         while (m_xTreeView->iter_children(*xRemove))
2632                         {
2633                             remove(*xRemove);
2634                             m_xTreeView->copy_iterator(*xEntry, *xRemove);
2635                         }
2636                         m_xTreeView->set_children_on_demand(*xEntry, nNewChildCount != 0);
2637                     }
2638                 }
2639                 else if((nCntCount != 0)
2640                             != (pArrType->GetMemberCount()!=0))
2641                 {
2642                     bContentChanged = true;
2643                 }
2644             }
2645             // The Root-Entry has to be found now
2646             while (bEntry && (bNext || m_xTreeView->get_iter_depth(*xEntry)))
2647             {
2648                 bEntry = m_xTreeView->iter_next(*xEntry);
2649                 bNext = false;
2650             }
2651         }
2652     }
2653 
2654     if (!bContentChanged && bVisibilityChanged)
2655         m_aUpdTimer.Start();
2656 
2657     return bContentChanged || bVisibilityChanged;
2658 }
2659 
2660 void SwContentTree::UpdateLastSelType()
2661 {
2662     std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
2663     if (m_xTreeView->get_selected(xEntry.get()))
2664     {
2665         while (m_xTreeView->get_iter_depth(*xEntry))
2666             m_xTreeView->iter_parent(*xEntry);
2667         sal_Int64 nId = m_xTreeView->get_id(*xEntry).toInt64();
2668         if (nId && lcl_IsContentType(*xEntry, *m_xTreeView))
2669         {
2670             assert(dynamic_cast<SwContentType*>(reinterpret_cast<SwTypeNumber*>(nId)));
2671             m_nLastSelType = reinterpret_cast<SwContentType*>(nId)->GetType();
2672         }
2673     }
2674 }
2675 
2676 void SwContentTree::FindActiveTypeAndRemoveUserData()
2677 {
2678     UpdateLastSelType();
2679 
2680     // If clear is called by TimerUpdate:
2681     // Only for root can the validity of the UserData be guaranteed.
2682     m_xTreeView->all_foreach([this](weld::TreeIter& rEntry){
2683         m_xTreeView->set_id(rEntry, "");
2684         return false;
2685     });
2686 }
2687 
2688 void SwContentTree::SetHiddenShell(SwWrtShell* pSh)
2689 {
2690     m_pHiddenShell = pSh;
2691     m_eState = State::HIDDEN;
2692     FindActiveTypeAndRemoveUserData();
2693     for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
2694     {
2695         m_aHiddenContentArr[i].reset();
2696     }
2697     Display(false);
2698 
2699     GetParentWindow()->UpdateListBox();
2700 }
2701 
2702 void SwContentTree::SetActiveShell(SwWrtShell* pSh)
2703 {
2704     bool bClear = m_pActiveShell != pSh;
2705     if (State::ACTIVE == m_eState && bClear)
2706     {
2707         if (m_pActiveShell)
2708             EndListening(*m_pActiveShell->GetView().GetDocShell());
2709         m_pActiveShell = pSh;
2710         FindActiveTypeAndRemoveUserData();
2711         clear();
2712     }
2713     else if (State::CONSTANT == m_eState)
2714     {
2715         if (m_pActiveShell)
2716             EndListening(*m_pActiveShell->GetView().GetDocShell());
2717         m_pActiveShell = pSh;
2718         m_eState = State::ACTIVE;
2719         bClear = true;
2720     }
2721     // Only if it is the active view, the array will be deleted and
2722     // the screen filled new.
2723     if (State::ACTIVE == m_eState && bClear)
2724     {
2725         if (m_pActiveShell)
2726             StartListening(*m_pActiveShell->GetView().GetDocShell());
2727         FindActiveTypeAndRemoveUserData();
2728         for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
2729         {
2730             m_aActiveContentArr[i].reset();
2731         }
2732         Display(true);
2733     }
2734 }
2735 
2736 void SwContentTree::SetConstantShell(SwWrtShell* pSh)
2737 {
2738     if (m_pActiveShell)
2739         EndListening(*m_pActiveShell->GetView().GetDocShell());
2740     m_pActiveShell = pSh;
2741     m_eState = State::CONSTANT;
2742     StartListening(*m_pActiveShell->GetView().GetDocShell());
2743     FindActiveTypeAndRemoveUserData();
2744     for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
2745     {
2746         m_aActiveContentArr[i].reset();
2747     }
2748     Display(true);
2749 }
2750 
2751 void SwContentTree::Notify(SfxBroadcaster & rBC, SfxHint const& rHint)
2752 {
2753     SfxViewEventHint const*const pVEHint(dynamic_cast<SfxViewEventHint const*>(&rHint));
2754     SwXTextView* pDyingShell = nullptr;
2755     if (m_pActiveShell && pVEHint && pVEHint->GetEventName() == "OnViewClosed")
2756         pDyingShell = dynamic_cast<SwXTextView*>(pVEHint->GetController().get());
2757     if (pDyingShell && pDyingShell->GetView() == &m_pActiveShell->GetView())
2758     {
2759         SetActiveShell(nullptr); // our view is dying, clear our pointers to it
2760     }
2761     else
2762     {
2763         SfxListener::Notify(rBC, rHint);
2764     }
2765     switch (rHint.GetId())
2766     {
2767         case SfxHintId::SwNavigatorUpdateTracking:
2768             UpdateTracking();
2769             break;
2770         case SfxHintId::SwNavigatorSelectOutlinesWithSelections:
2771         {
2772             if (m_nRootType == ContentTypeId::OUTLINE)
2773             {
2774                 SelectOutlinesWithSelection();
2775                 // make first selected entry visible
2776                 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
2777                 if (xEntry && m_xTreeView->get_selected(xEntry.get()))
2778                     m_xTreeView->scroll_to_row(*xEntry);
2779             }
2780             else if (m_nRootType == ContentTypeId::UNKNOWN)
2781                 m_xTreeView->unselect_all();
2782             break;
2783         }
2784         case SfxHintId::DocChanged:
2785             if (!m_bIgnoreViewChange)
2786             {
2787                 m_bViewHasChanged = true;
2788                 TimerUpdate(&m_aUpdTimer);
2789             }
2790             break;
2791         case SfxHintId::ModeChanged:
2792             if (SwWrtShell* pShell = GetWrtShell())
2793             {
2794                 const bool bReadOnly = pShell->GetView().GetDocShell()->IsReadOnly();
2795                 if (bReadOnly != m_bIsLastReadOnly)
2796                 {
2797                     m_bIsLastReadOnly = bReadOnly;
2798 
2799                     std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
2800                     if (m_xTreeView->get_cursor(xEntry.get()))
2801                     {
2802                         m_xTreeView->select(*xEntry);
2803                         Select();
2804                     }
2805                     else
2806                         m_xTreeView->unselect_all();
2807                 }
2808             }
2809             break;
2810         default:
2811             break;
2812     }
2813 }
2814 
2815 void SwContentTree::ExecCommand(std::string_view rCmd, bool bOutlineWithChildren)
2816 {
2817     const bool bUp = rCmd == "chapterup";
2818     const bool bUpDown = bUp || rCmd == "chapterdown";
2819     const bool bLeft = rCmd == "promote";
2820     const bool bLeftRight = bLeft || rCmd == "demote";
2821     if (!bUpDown && !bLeftRight)
2822         return;
2823     if (GetWrtShell()->GetView().GetDocShell()->IsReadOnly() ||
2824         (State::ACTIVE != m_eState &&
2825          (State::CONSTANT != m_eState || m_pActiveShell != GetParentWindow()->GetCreateView()->GetWrtShellPtr())))
2826     {
2827         return;
2828     }
2829 
2830     m_bIgnoreViewChange = true;
2831 
2832     SwWrtShell *const pShell = GetWrtShell();
2833     sal_Int8 nActOutlineLevel = m_nOutlineLevel;
2834     SwOutlineNodes::size_type nActPos = pShell->GetOutlinePos(nActOutlineLevel);
2835 
2836     std::vector<SwTextNode*> selectedOutlineNodes;
2837     std::vector<std::unique_ptr<weld::TreeIter>> selected;
2838 
2839     m_xTreeView->selected_foreach([this, pShell, &bLeftRight, &bOutlineWithChildren, &selected, &selectedOutlineNodes](weld::TreeIter& rEntry){
2840         // it's possible to select the root node too which is a really bad idea
2841         bool bSkip = lcl_IsContentType(rEntry, *m_xTreeView);
2842         // filter out children of selected parents so they don't get promoted
2843         // or moved twice (except if there is Ctrl modifier, since in that
2844         // case children are re-parented)
2845         if ((bLeftRight || bOutlineWithChildren) && !selected.empty())
2846         {
2847             std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rEntry));
2848             for (bool bParent = m_xTreeView->iter_parent(*xParent); bParent; bParent = m_xTreeView->iter_parent(*xParent))
2849             {
2850                 if (m_xTreeView->iter_compare(*selected.back(), *xParent) == 0)
2851                 {
2852                     bSkip = true;
2853                     break;
2854                 }
2855             }
2856         }
2857         if (!bSkip)
2858         {
2859             selected.emplace_back(m_xTreeView->make_iterator(&rEntry));
2860             const SwNodes& rNodes = pShell->GetNodes();
2861             const size_t nPos = GetAbsPos(rEntry) - 1;
2862             if (nPos < rNodes.GetOutLineNds().size())
2863             {
2864                 SwNode* pNode = rNodes.GetOutLineNds()[ nPos ];
2865                 if (pNode)
2866                 {
2867                     selectedOutlineNodes.push_back(pNode->GetTextNode());
2868                 }
2869             }
2870         }
2871         return false;
2872     });
2873 
2874     if (bUpDown && !bUp)
2875     {   // to move down, start at the end!
2876         std::reverse(selected.begin(), selected.end());
2877     }
2878 
2879     SwOutlineNodes::difference_type nDirLast = bUp ? -1 : 1;
2880     bool bStartedAction = false;
2881     std::vector<SwNode*> aOutlineNdsArray;
2882     for (auto const& pCurrentEntry : selected)
2883     {
2884         assert(pCurrentEntry && lcl_IsContent(*pCurrentEntry, *m_xTreeView));
2885         if (lcl_IsContent(*pCurrentEntry, *m_xTreeView))
2886         {
2887             assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*pCurrentEntry).toInt64())));
2888             if ((m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE) ||
2889                 reinterpret_cast<SwContent*>(m_xTreeView->get_id(*pCurrentEntry).toInt64())->GetParent()->GetType()
2890                                             ==  ContentTypeId::OUTLINE)
2891             {
2892                 nActPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*pCurrentEntry).toInt64())->GetOutlinePos();
2893             }
2894         }
2895         if (nActPos == SwOutlineNodes::npos || (bUpDown && !pShell->IsOutlineMovable(nActPos)))
2896         {
2897             continue;
2898         }
2899 
2900         if (!bStartedAction)
2901         {
2902             pShell->StartAllAction();
2903             if (bUpDown)
2904             {
2905                 if (pShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
2906                 {
2907                     // make all outline nodes content visible before move
2908                     // restore outline nodes content visible state after move
2909                     SwOutlineNodes rOutlineNds = pShell->GetDoc()->GetNodes().GetOutLineNds();
2910                     for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos)
2911                     {
2912                         SwNode* pNd = rOutlineNds[nPos];
2913                         if (pNd->IsTextNode()) // should always be true
2914                         {
2915                             bool bOutlineContentVisibleAttr = true;
2916                             pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
2917                             if (!bOutlineContentVisibleAttr)
2918                             {
2919                                 aOutlineNdsArray.push_back(pNd);
2920                                 pShell->ToggleOutlineContentVisibility(nPos);
2921                             }
2922                         }
2923                     }
2924                 }
2925             }
2926             pShell->StartUndo(bLeftRight ? SwUndoId::OUTLINE_LR : SwUndoId::OUTLINE_UD);
2927             bStartedAction = true;
2928         }
2929         pShell->GotoOutline( nActPos); // If text selection != box selection
2930         pShell->Push();
2931         pShell->MakeOutlineSel(nActPos, nActPos, bOutlineWithChildren);
2932         if (bUpDown)
2933         {
2934             const size_t nEntryAbsPos(GetAbsPos(*pCurrentEntry));
2935             SwOutlineNodes::difference_type nDir = bUp ? -1 : 1;
2936             if (!bOutlineWithChildren && ((nDir == -1 && nActPos > 0) ||
2937                        (nDir == 1 && nEntryAbsPos < GetEntryCount() - 2)))
2938             {
2939                 pShell->MoveOutlinePara( nDir );
2940                 // Set cursor back to the current position
2941                 pShell->GotoOutline( nActPos + nDir);
2942             }
2943             else if (bOutlineWithChildren)
2944             {
2945                 SwOutlineNodes::size_type nActEndPos = nActPos;
2946                 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pCurrentEntry.get()));
2947                 assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*pCurrentEntry).toInt64())));
2948                 const auto nActLevel = reinterpret_cast<SwOutlineContent*>(
2949                         m_xTreeView->get_id(*pCurrentEntry).toInt64())->GetOutlineLevel();
2950                 bool bEntry = m_xTreeView->iter_next(*xEntry);
2951                 while (bEntry && lcl_IsContent(*xEntry, *m_xTreeView))
2952                 {
2953                     assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
2954                     if (nActLevel >= reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlineLevel())
2955                         break;
2956                     nActEndPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlinePos();
2957                     bEntry = m_xTreeView->iter_next(*xEntry);
2958                 }
2959                 if (nDir == 1) // move down
2960                 {
2961                     std::unique_ptr<weld::TreeIter> xNextSibling(m_xTreeView->make_iterator(pCurrentEntry.get()));
2962                     if (m_xTreeView->iter_next_sibling(*xNextSibling) && m_xTreeView->is_selected(*xNextSibling))
2963                         nDir = nDirLast;
2964                     else
2965                     {
2966                     // If the last entry is to be moved we're done
2967                     if (bEntry && lcl_IsContent(*xEntry, *m_xTreeView))
2968                     {
2969                         // xEntry now points to the entry following the last
2970                         // selected entry.
2971                         SwOutlineNodes::size_type nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlinePos();
2972                         // here needs to found the next entry after next.
2973                         // The selection must be inserted in front of that.
2974                         while (bEntry)
2975                         {
2976                             bEntry = m_xTreeView->iter_next(*xEntry);
2977                             assert(!bEntry || !lcl_IsContent(*xEntry, *m_xTreeView)||
2978                                    dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
2979                             // nDest++ may only executed if bEntry
2980                             if (bEntry)
2981                             {
2982                                 if (!lcl_IsContent(*xEntry, *m_xTreeView))
2983                                     break;
2984                                 else if (nActLevel >= reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlineLevel())
2985                                 {
2986                                     // nDest needs adjusted if there are selected entries (including ancestral lineage)
2987                                     // immediately before the current moved entry.
2988                                     std::unique_ptr<weld::TreeIter> xTmp(m_xTreeView->make_iterator(xEntry.get()));
2989                                     bool bTmp = m_xTreeView->iter_previous(*xTmp);
2990                                     while (bTmp && lcl_IsContent(*xTmp, *m_xTreeView) &&
2991                                            nActLevel < reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlineLevel())
2992                                     {
2993                                         while (bTmp && lcl_IsContent(*xTmp, *m_xTreeView) && !m_xTreeView->is_selected(*xTmp) &&
2994                                                nActLevel < reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlineLevel())
2995                                         {
2996                                             bTmp = m_xTreeView->iter_parent(*xTmp);
2997                                         }
2998                                         if (!bTmp || !m_xTreeView->is_selected(*xTmp))
2999                                             break;
3000                                         bTmp = m_xTreeView->iter_previous(*xTmp);
3001                                         nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlinePos();
3002                                     }
3003                                     std::unique_ptr<weld::TreeIter> xPrevSibling(m_xTreeView->make_iterator(xEntry.get()));
3004                                     if (!m_xTreeView->iter_previous_sibling(*xPrevSibling) || !m_xTreeView->is_selected(*xPrevSibling))
3005                                         break;
3006                                 }
3007                                 else
3008                                 {
3009                                     nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlinePos();
3010                                 }
3011                             }
3012                         }
3013                         nDirLast = nDir = nDest - nActEndPos;
3014                         // If no entry was found that allows insertion before
3015                         // it, we just move it to the end.
3016                     }
3017                     else
3018                         nDirLast = nDir = 0;
3019                     }
3020                 }
3021                 else // move up
3022                 {
3023                     std::unique_ptr<weld::TreeIter> xPrevSibling(m_xTreeView->make_iterator(pCurrentEntry.get()));
3024                     if (m_xTreeView->iter_previous_sibling(*xPrevSibling) && m_xTreeView->is_selected(*xPrevSibling))
3025                         nDir = nDirLast;
3026                     else
3027                     {
3028                         SwOutlineNodes::size_type nDest = nActPos;
3029                         bEntry = true;
3030                         m_xTreeView->copy_iterator(*pCurrentEntry, *xEntry);
3031                         while (bEntry && nDest)
3032                         {
3033                             bEntry = m_xTreeView->iter_previous(*xEntry);
3034                             assert(!bEntry || !lcl_IsContent(*xEntry, *m_xTreeView) ||
3035                                    dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
3036                             if (bEntry && lcl_IsContent(*xEntry, *m_xTreeView))
3037                             {
3038                                 nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlinePos();
3039                             }
3040                             else
3041                             {
3042                                 nDest = 0; // presumably?
3043                             }
3044                             if (bEntry)
3045                             {
3046                                 if (!lcl_IsContent(*xEntry, *m_xTreeView))
3047                                     break;
3048                                 else if (nActLevel >= reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlineLevel())
3049                                 {
3050                                     // nDest needs adjusted if there are selected entries immediately
3051                                     // after the level change.
3052                                     std::unique_ptr<weld::TreeIter> xTmp(m_xTreeView->make_iterator(xEntry.get()));
3053                                     bool bTmp = m_xTreeView->iter_next(*xTmp);
3054                                     while (bTmp && lcl_IsContent(*xTmp, *m_xTreeView) &&
3055                                            nActLevel < reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlineLevel() &&
3056                                            m_xTreeView->is_selected(*xTmp))
3057                                     {
3058                                         nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlinePos();
3059                                         const auto nLevel = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlineLevel();
3060                                         // account for selected entries' descendent lineage
3061                                         bTmp = m_xTreeView->iter_next(*xTmp);
3062                                         while (bTmp && lcl_IsContent(*xTmp, *m_xTreeView) &&
3063                                                nLevel < reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlineLevel())
3064                                         {
3065                                             nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlinePos();
3066                                             bTmp = m_xTreeView->iter_next(*xTmp);
3067                                         }
3068                                     }
3069                                     break;
3070                                 }
3071                             }
3072                         }
3073                         nDirLast = nDir = nDest - nActPos;
3074                     }
3075                 }
3076                 if (nDir)
3077                 {
3078                     pShell->MoveOutlinePara( nDir );
3079                     // Set cursor back to the current position
3080                     pShell->GotoOutline(nActPos + nDir);
3081                 }
3082             }
3083         }
3084         else
3085         {
3086             if (!pShell->IsProtectedOutlinePara())
3087                 pShell->OutlineUpDown(bLeft ? -1 : 1);
3088         }
3089 
3090         pShell->ClearMark();
3091         pShell->Pop(SwCursorShell::PopMode::DeleteCurrent); // Cursor is now back at the current heading.
3092     }
3093 
3094     if (bStartedAction)
3095     {
3096         pShell->EndUndo();
3097         if (bUpDown)
3098         {
3099             if (pShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
3100             {
3101                 // restore state of outline content visibility to before move
3102                 for (SwNode* pNd : aOutlineNdsArray)
3103                     pShell->ToggleOutlineContentVisibility(pNd, true);
3104             }
3105         }
3106         pShell->EndAllAction();
3107         if (m_aActiveContentArr[ContentTypeId::OUTLINE])
3108             m_aActiveContentArr[ContentTypeId::OUTLINE]->Invalidate();
3109 
3110         // clear all selections to prevent the Display function from trying to reselect selected entries
3111         m_xTreeView->unselect_all();
3112         Display(true);
3113 
3114         // reselect entries
3115         const SwOutlineNodes::size_type nCurrPos = pShell->GetOutlinePos(MAXLEVEL);
3116         std::unique_ptr<weld::TreeIter> xListEntry(m_xTreeView->make_iterator());
3117         bool bListEntry = m_xTreeView->get_iter_first(*xListEntry);
3118         while ((bListEntry = m_xTreeView->iter_next(*xListEntry)) && lcl_IsContent(*xListEntry, *m_xTreeView))
3119         {
3120             assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xListEntry).toInt64())));
3121             if (reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xListEntry).toInt64())->GetOutlinePos() == nCurrPos)
3122             {
3123                 std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(xListEntry.get()));
3124                 if (m_xTreeView->iter_parent(*xParent) && !m_xTreeView->get_row_expanded(*xParent))
3125                     m_xTreeView->expand_row(*xParent);
3126                 m_xTreeView->set_cursor(*xListEntry); // unselect all entries, make entry visible, set focus, and select
3127                 Select();
3128                 break;
3129             }
3130         }
3131 
3132         if (m_bIsRoot)
3133         {
3134             const SwOutlineNodes& rOutLineNds = pShell->GetNodes().GetOutLineNds();
3135             for (SwTextNode* pNode : selectedOutlineNodes)
3136             {
3137                 SwOutlineNodes::const_iterator aFndIt = rOutLineNds.find(pNode);
3138                 if(aFndIt == rOutLineNds.end())
3139                     continue;
3140                 const size_t nFndPos = aFndIt - rOutLineNds.begin();
3141                 std::unique_ptr<weld::TreeIter> xEntry = GetEntryAtAbsPos(nFndPos + 1);
3142                 if (xEntry)
3143                 {
3144                     m_xTreeView->select(*xEntry);
3145                     std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(xEntry.get()));
3146                     if (m_xTreeView->iter_parent(*xParent) && !m_xTreeView->get_row_expanded(*xParent))
3147                         m_xTreeView->expand_row(*xParent);
3148                 }
3149             }
3150         }
3151     }
3152     m_bIgnoreViewChange = false;
3153 }
3154 
3155 void SwContentTree::ShowTree()
3156 {
3157     m_xTreeView->show();
3158     m_aUpdTimer.Start();
3159 }
3160 
3161 void SwContentTree::HideTree()
3162 {
3163     // folded together will not be idled
3164     m_aUpdTimer.Stop();
3165     m_xTreeView->hide();
3166 }
3167 
3168 static void lcl_SelectByContentTypeAndName(SwContentTree* pThis, weld::TreeView& rContentTree,
3169                                            std::u16string_view rContentTypeName, std::u16string_view rName)
3170 {
3171     if (rName.empty())
3172         return;
3173 
3174     // find content type entry
3175     std::unique_ptr<weld::TreeIter> xIter(rContentTree.make_iterator());
3176     bool bFoundEntry = rContentTree.get_iter_first(*xIter);
3177     while (bFoundEntry && rContentTypeName != rContentTree.get_text(*xIter))
3178         bFoundEntry = rContentTree.iter_next_sibling(*xIter);
3179     // find content type content entry and select it
3180     if (bFoundEntry)
3181     {
3182         rContentTree.expand_row(*xIter); // assure content type entry is expanded
3183         while (rContentTree.iter_next(*xIter) && lcl_IsContent(*xIter, rContentTree))
3184         {
3185             if (rName == rContentTree.get_text(*xIter))
3186             {
3187                 // get first selected for comparison
3188                 std::unique_ptr<weld::TreeIter> xFirstSelected(rContentTree.make_iterator());
3189                 if (!rContentTree.get_selected(xFirstSelected.get()))
3190                     xFirstSelected.reset();
3191                 if (rContentTree.count_selected_rows() != 1 ||
3192                         rContentTree.iter_compare(*xIter, *xFirstSelected) != 0)
3193                 {
3194                     // unselect all entries and make passed entry visible and selected
3195                     rContentTree.set_cursor(*xIter);
3196                     pThis->Select();
3197                 }
3198                 break;
3199             }
3200         }
3201     }
3202 }
3203 
3204 /** No idle with focus or while dragging */
3205 IMPL_LINK_NOARG(SwContentTree, TimerUpdate, Timer *, void)
3206 {
3207     // No update while focus is not in document.
3208     // No update while drag and drop.
3209     // Query view because the Navigator is cleared too late.
3210     SwView* pView = GetParentWindow()->GetCreateView();
3211     if(pView && pView->GetWrtShellPtr() && pView->GetWrtShellPtr()->GetWin() &&
3212         (pView->GetWrtShellPtr()->GetWin()->HasFocus() || m_bViewHasChanged) &&
3213         !IsInDrag() && !pView->GetWrtShellPtr()->ActionPend())
3214     {
3215         m_bViewHasChanged = false;
3216         m_bIsIdleClear = false;
3217         SwWrtShell* pActShell = pView->GetWrtShellPtr();
3218         if (State::CONSTANT == m_eState && !lcl_FindShell(m_pActiveShell))
3219         {
3220             SetActiveShell(pActShell);
3221             GetParentWindow()->UpdateListBox();
3222         }
3223 
3224         if (State::ACTIVE == m_eState && pActShell != GetWrtShell())
3225         {
3226             SetActiveShell(pActShell);
3227         }
3228         else if ((State::ACTIVE == m_eState || (State::CONSTANT == m_eState && pActShell == GetWrtShell())) &&
3229                     HasContentChanged())
3230         {
3231             FindActiveTypeAndRemoveUserData();
3232             Display(true);
3233         }
3234 
3235         UpdateTracking();
3236     }
3237     else if (!pView && State::ACTIVE == m_eState && !m_bIsIdleClear)
3238     {
3239         if(m_pActiveShell)
3240         {
3241             SetActiveShell(nullptr);
3242         }
3243         clear();
3244         m_bIsIdleClear = true;
3245     }
3246 }
3247 
3248 void SwContentTree::UpdateTracking()
3249 {
3250     if (State::HIDDEN == m_eState || !m_pActiveShell)
3251         return;
3252 
3253     // m_bIgnoreViewChange is set on delete
3254     if (m_bIgnoreViewChange)
3255     {
3256         m_bIgnoreViewChange = false;
3257         return;
3258     }
3259 
3260     // drawing
3261     if ((m_pActiveShell->GetSelectionType() & (SelectionType::DrawObject |
3262                                                SelectionType::DrawObjectEditMode |
3263                                                SelectionType::DbForm)) &&
3264             !(m_bIsRoot && m_nRootType != ContentTypeId::DRAWOBJECT))
3265     {
3266         SdrView* pSdrView = m_pActiveShell->GetDrawView();
3267         if(pSdrView && 1 == pSdrView->GetMarkedObjectCount())
3268         {
3269             SdrObject* pSelected = pSdrView->GetMarkedObjectByIndex(0);
3270             OUString aName(pSelected->GetName());
3271             if (!aName.isEmpty())
3272                 lcl_SelectByContentTypeAndName(this, *m_xTreeView,
3273                                                SwResId(STR_CONTENT_TYPE_DRAWOBJECT), aName);
3274             else
3275             {
3276                 // clear treeview selections
3277                 m_xTreeView->unselect_all();
3278                 Select();
3279             }
3280         }
3281         else
3282         {
3283             // clear treeview selections
3284             m_xTreeView->unselect_all();
3285             Select();
3286         }
3287         return;
3288     }
3289     // graphic, frame, and ole
3290     OUString aContentTypeName;
3291     if (m_pActiveShell->GetSelectionType() == SelectionType::Graphic &&
3292             !(m_bIsRoot && m_nRootType != ContentTypeId::GRAPHIC))
3293         aContentTypeName = SwResId(STR_CONTENT_TYPE_GRAPHIC);
3294     else if (m_pActiveShell->GetSelectionType() == SelectionType::Frame &&
3295              !(m_bIsRoot && m_nRootType != ContentTypeId::FRAME))
3296         aContentTypeName = SwResId(STR_CONTENT_TYPE_FRAME);
3297     else if (m_pActiveShell->GetSelectionType() == SelectionType::Ole &&
3298              !(m_bIsRoot && m_nRootType != ContentTypeId::OLE))
3299         aContentTypeName = SwResId(STR_CONTENT_TYPE_OLE);
3300     if (!aContentTypeName.isEmpty())
3301     {
3302         OUString aName(m_pActiveShell->GetFlyName());
3303         lcl_SelectByContentTypeAndName(this, *m_xTreeView, aContentTypeName, aName);
3304         return;
3305     }
3306     // table
3307     if (m_pActiveShell->IsCursorInTable()  &&
3308             !(m_bIsRoot && m_nRootType != ContentTypeId::TABLE))
3309     {
3310         if(m_pActiveShell->GetTableFormat())
3311         {
3312             OUString aName = m_pActiveShell->GetTableFormat()->GetName();
3313             lcl_SelectByContentTypeAndName(this, *m_xTreeView, SwResId(STR_CONTENT_TYPE_TABLE),
3314                                            aName);
3315         }
3316         return;
3317     }
3318     // outline
3319     // find out where the cursor is
3320     const SwOutlineNodes::size_type nActPos = GetWrtShell()->GetOutlinePos(MAXLEVEL);
3321     if (!((m_bIsRoot && m_nRootType != ContentTypeId::OUTLINE) ||
3322           m_nOutlineTracking == 3 || nActPos == SwOutlineNodes::npos))
3323     {
3324         // assure outline content type is expanded
3325         // this assumes outline content type is first in treeview
3326         std::unique_ptr<weld::TreeIter> xFirstEntry(m_xTreeView->make_iterator());
3327         if (m_xTreeView->get_iter_first(*xFirstEntry))
3328             m_xTreeView->expand_row(*xFirstEntry);
3329 
3330         m_xTreeView->all_foreach([this, nActPos](weld::TreeIter& rEntry){
3331             bool bRet = false;
3332             if (lcl_IsContent(rEntry, *m_xTreeView) && reinterpret_cast<SwContent*>(
3333                         m_xTreeView->get_id(rEntry).toInt64())->GetParent()->GetType() ==
3334                         ContentTypeId::OUTLINE)
3335             {
3336                 if (reinterpret_cast<SwOutlineContent*>(
3337                             m_xTreeView->get_id(rEntry).toInt64())->GetOutlinePos() == nActPos)
3338                 {
3339                     std::unique_ptr<weld::TreeIter> xFirstSelected(
3340                                 m_xTreeView->make_iterator());
3341                     if (!m_xTreeView->get_selected(xFirstSelected.get()))
3342                         xFirstSelected.reset();
3343                     // only select if not already selected or tree has multiple entries selected
3344                     if (m_xTreeView->count_selected_rows() != 1 ||
3345                             m_xTreeView->iter_compare(rEntry, *xFirstSelected) != 0)
3346                     {
3347                         if (m_nOutlineTracking == 2) // focused outline tracking
3348                         {
3349                             // collapse to children of root node
3350                             std::unique_ptr<weld::TreeIter> xChildEntry(
3351                                         m_xTreeView->make_iterator());
3352                             if (m_xTreeView->get_iter_first(*xChildEntry) &&
3353                                     m_xTreeView->iter_children(*xChildEntry))
3354                             {
3355                                 do
3356                                 {
3357                                     if (reinterpret_cast<SwContent*>(
3358                                                 m_xTreeView->get_id(*xChildEntry).toInt64())->
3359                                             GetParent()->GetType() == ContentTypeId::OUTLINE)
3360                                         m_xTreeView->collapse_row(*xChildEntry);
3361                                     else
3362                                         break;
3363                                 }
3364                                 while (m_xTreeView->iter_next(*xChildEntry));
3365                             }
3366                         }
3367                         // unselect all entries, make pEntry visible, and select
3368                         m_xTreeView->set_cursor(rEntry);
3369                         Select();
3370                     }
3371                     bRet = true;
3372                 }
3373             }
3374             else
3375             {
3376                 // use of this break assumes outline content type is first in tree
3377                 if (lcl_IsContentType(rEntry, *m_xTreeView) &&
3378                         reinterpret_cast<SwContentType*>(
3379                             m_xTreeView->get_id(rEntry).toInt64())->GetType() !=
3380                         ContentTypeId::OUTLINE)
3381                     bRet = true;
3382             }
3383             return bRet;
3384         });
3385     }
3386     else
3387     {
3388         // clear treeview selections
3389         m_xTreeView->unselect_all();
3390         Select();
3391     }
3392 }
3393 
3394 void SwContentTree::SelectOutlinesWithSelection()
3395 {
3396     SwCursor* pFirstCursor = m_pActiveShell->GetSwCursor();
3397     SwCursor* pCursor = pFirstCursor;
3398     std::vector<SwOutlineNodes::size_type> aOutlinePositions;
3399     do
3400     {
3401         if (pCursor)
3402         {
3403             if (pCursor->HasMark())
3404             {
3405                 aOutlinePositions.push_back(m_pActiveShell->GetOutlinePos(UCHAR_MAX, pCursor));
3406             }
3407             pCursor = pCursor->GetNext();
3408         }
3409     } while (pCursor && pCursor != pFirstCursor);
3410 
3411     if (aOutlinePositions.empty())
3412         return;
3413 
3414     // remove duplicates before selecting
3415     aOutlinePositions.erase(std::unique(aOutlinePositions.begin(), aOutlinePositions.end()),
3416                             aOutlinePositions.end());
3417 
3418     m_xTreeView->unselect_all();
3419 
3420     for (auto nOutlinePosition : aOutlinePositions)
3421     {
3422         m_xTreeView->all_foreach([this, nOutlinePosition](const weld::TreeIter& rEntry){
3423             if (lcl_IsContent(rEntry, *m_xTreeView) &&
3424                     reinterpret_cast<SwContent*>(
3425                     m_xTreeView->get_id(rEntry).toInt64())->GetParent()->GetType() ==
3426                     ContentTypeId::OUTLINE)
3427             {
3428                 if (reinterpret_cast<SwOutlineContent*>(
3429                         m_xTreeView->get_id(rEntry).toInt64())->GetOutlinePos() ==
3430                         nOutlinePosition)
3431                 {
3432                     std::unique_ptr<weld::TreeIter> xParent =
3433                             m_xTreeView->make_iterator(&rEntry);
3434                     if (m_xTreeView->iter_parent(*xParent) &&
3435                             !m_xTreeView->get_row_expanded(*xParent))
3436                         m_xTreeView->expand_row(*xParent);
3437                     m_xTreeView->select(rEntry);
3438                     return true;
3439                 }
3440             }
3441             return false;
3442         });
3443     }
3444 
3445     Select();
3446 }
3447 
3448 void SwContentTree::MoveOutline(SwOutlineNodes::size_type nTargetPos)
3449 {
3450     SwWrtShell *const pShell = GetWrtShell();
3451     pShell->StartAllAction();
3452     std::vector<SwNode*> aOutlineNdsArray;
3453 
3454     if (pShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
3455     {
3456         // make all outline nodes content visible before move
3457         // restore outline nodes content visible state after move
3458         SwOutlineNodes rOutlineNds = pShell->GetDoc()->GetNodes().GetOutLineNds();
3459         for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos)
3460         {
3461             SwNode* pNd = rOutlineNds[nPos];
3462             if (pNd->IsTextNode()) // should always be true
3463             {
3464                 bool bOutlineContentVisibleAttr = true;
3465                 pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
3466                 if (!bOutlineContentVisibleAttr)
3467                 {
3468                     aOutlineNdsArray.push_back(pNd);
3469                     pShell->ToggleOutlineContentVisibility(nPos);
3470                 }
3471             }
3472         }
3473     }
3474     pShell->StartUndo(SwUndoId::OUTLINE_UD);
3475 
3476     SwOutlineNodes::size_type nPrevSourcePos = SwOutlineNodes::npos;
3477     SwOutlineNodes::size_type nPrevTargetPosOrOffset = SwOutlineNodes::npos;
3478 
3479     bool bFirstMove = true;
3480 
3481     for (const auto& source : m_aDndOutlinesSelected)
3482     {
3483         SwOutlineNodes::size_type nSourcePos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*source).toInt64())->GetOutlinePos();
3484 
3485         // Done on the first selection move
3486         if (bFirstMove) // only do once
3487         {
3488             if (nTargetPos == SwOutlineNodes::npos || nSourcePos > nTargetPos)
3489             {
3490                 // Up moves
3491                 // The first up move sets the up move amount for the remaining selected outlines to be moved
3492                 if (nTargetPos != SwOutlineNodes::npos)
3493                     nPrevTargetPosOrOffset = nSourcePos - nTargetPos;
3494                 else
3495                     nPrevTargetPosOrOffset = nSourcePos + 1;
3496             }
3497             else if (nSourcePos < nTargetPos)
3498             {
3499                 // Down moves
3500                 // The first down move sets the source and target positions for the remaining selected outlines to be moved
3501                 nPrevSourcePos = nSourcePos;
3502                 nPrevTargetPosOrOffset = nTargetPos;
3503             }
3504             bFirstMove = false;
3505         }
3506         else
3507         {
3508             if (nTargetPos == SwOutlineNodes::npos || nSourcePos > nTargetPos)
3509             {
3510                 // Move up
3511                 nTargetPos = nSourcePos - nPrevTargetPosOrOffset;
3512             }
3513             else if (nSourcePos < nTargetPos)
3514             {
3515                 // Move down
3516                 nSourcePos = nPrevSourcePos;
3517                 nTargetPos = nPrevTargetPosOrOffset;
3518             }
3519         }
3520         GetParentWindow()->MoveOutline(nSourcePos, nTargetPos);
3521     }
3522 
3523     pShell->EndUndo();
3524     if (pShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
3525     {
3526         // restore state of outline content visibility to before move
3527         for (SwNode* pNd : aOutlineNdsArray)
3528             pShell->ToggleOutlineContentVisibility(pNd, true);
3529     }
3530     pShell->EndAllAction();
3531     m_aActiveContentArr[ContentTypeId::OUTLINE]->Invalidate();
3532     Display(true);
3533     m_aDndOutlinesSelected.clear();
3534 }
3535 
3536 // Update immediately
3537 IMPL_LINK_NOARG(SwContentTree, FocusInHdl, weld::Widget&, void)
3538 {
3539     SwView* pActView = GetParentWindow()->GetCreateView();
3540     if(pActView)
3541     {
3542         SwWrtShell* pActShell = pActView->GetWrtShellPtr();
3543         if (State::CONSTANT == m_eState && !lcl_FindShell(m_pActiveShell))
3544         {
3545             SetActiveShell(pActShell);
3546         }
3547 
3548         if (State::ACTIVE == m_eState && pActShell != GetWrtShell())
3549             SetActiveShell(pActShell);
3550         else if ((State::ACTIVE == m_eState || (State::CONSTANT == m_eState && pActShell == GetWrtShell())) &&
3551                     HasContentChanged())
3552         {
3553             Display(true);
3554         }
3555     }
3556     else if (State::ACTIVE == m_eState)
3557         clear();
3558 }
3559 
3560 IMPL_LINK(SwContentTree, KeyInputHdl, const KeyEvent&, rEvent, bool)
3561 {
3562     bool bConsumed = true;
3563 
3564     const vcl::KeyCode aCode = rEvent.GetKeyCode();
3565     if (aCode.GetCode() == KEY_MULTIPLY && aCode.IsMod1())
3566     {
3567         std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
3568         if (m_xTreeView->get_selected(xEntry.get()))
3569             ExpandOrCollapseAll(*m_xTreeView, *xEntry);
3570     }
3571     else if (aCode.GetCode() == KEY_RETURN)
3572     {
3573         std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
3574         if (m_xTreeView->get_selected(xEntry.get()))
3575         {
3576             switch(aCode.GetModifier())
3577             {
3578                 case KEY_MOD2:
3579                     // Switch boxes
3580                     GetParentWindow()->ToggleTree();
3581                 break;
3582                 case KEY_MOD1:
3583                     // Switch RootMode
3584                     ToggleToRoot();
3585                 break;
3586                 case 0:
3587                     if (lcl_IsContentType(*xEntry, *m_xTreeView))
3588                     {
3589                         m_xTreeView->get_row_expanded(*xEntry) ? m_xTreeView->collapse_row(*xEntry)
3590                                                                : m_xTreeView->expand_row(*xEntry);
3591                     }
3592                     else
3593                         ContentDoubleClickHdl(*m_xTreeView);
3594                 break;
3595             }
3596         }
3597     }
3598     else if(aCode.GetCode() == KEY_DELETE && 0 == aCode.GetModifier())
3599     {
3600         std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
3601         if (m_xTreeView->get_selected(xEntry.get()) && lcl_IsContent(*xEntry, *m_xTreeView))
3602         {
3603             assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
3604             if (reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetParent()->IsDeletable() &&
3605                     !m_pActiveShell->GetView().GetDocShell()->IsReadOnly())
3606             {
3607                 EditEntry(*xEntry, EditEntryMode::DELETE);
3608             }
3609         }
3610     }
3611     //Make KEY_SPACE has same function as DoubleClick ,
3612     //and realize multi-selection .
3613     else if (aCode.GetCode() == KEY_SPACE && 0 == aCode.GetModifier())
3614     {
3615         std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
3616         if (m_xTreeView->get_cursor(xEntry.get()))
3617         {
3618             if (State::HIDDEN != m_eState)
3619             {
3620                 if (State::CONSTANT == m_eState)
3621                 {
3622                     m_pActiveShell->GetView().GetViewFrame()->GetWindow().ToTop();
3623                 }
3624 
3625                 SwContent* pCnt = dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64()));
3626 
3627                 if (pCnt && pCnt->GetParent()->GetType() == ContentTypeId::DRAWOBJECT)
3628                 {
3629                     SdrView* pDrawView = m_pActiveShell->GetDrawView();
3630                     if (pDrawView)
3631                     {
3632                         pDrawView->SdrEndTextEdit();
3633 
3634                         SwDrawModel* pDrawModel = m_pActiveShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
3635                         SdrPage* pPage = pDrawModel->GetPage(0);
3636                         const size_t nCount = pPage->GetObjCount();
3637                         bool hasObjectMarked = false;
3638 
3639                         if (SdrObject* pObject = GetDrawingObjectsByContent(pCnt))
3640                         {
3641                             SdrPageView* pPV = pDrawView->GetSdrPageView/*GetPageViewPvNum*/(/*0*/);
3642                             if( pPV )
3643                             {
3644                                 bool bUnMark = pDrawView->IsObjMarked(pObject);
3645                                 pDrawView->MarkObj( pObject, pPV, bUnMark);
3646 
3647                             }
3648                         }
3649                         for( size_t i=0; i<nCount; ++i )
3650                         {
3651                             SdrObject* pTemp = pPage->GetObj(i);
3652                             bool bMark = pDrawView->IsObjMarked(pTemp);
3653                             switch( pTemp->GetObjIdentifier() )
3654                             {
3655                                 case OBJ_GRUP:
3656                                 case OBJ_TEXT:
3657                                 case OBJ_LINE:
3658                                 case OBJ_RECT:
3659                                 case OBJ_CIRC:
3660                                 case OBJ_SECT:
3661                                 case OBJ_CARC:
3662                                 case OBJ_CCUT:
3663                                 case OBJ_POLY:
3664                                 case OBJ_PLIN:
3665                                 case OBJ_PATHLINE:
3666                                 case OBJ_PATHFILL:
3667                                 case OBJ_FREELINE:
3668                                 case OBJ_FREEFILL:
3669                                 case OBJ_PATHPOLY:
3670                                 case OBJ_PATHPLIN:
3671                                 case OBJ_CAPTION:
3672                                 case OBJ_CUSTOMSHAPE:
3673                                     if( bMark )
3674                                         hasObjectMarked = true;
3675                                     break;
3676                                 default:
3677                                     if ( bMark )
3678                                     {
3679                                         SdrPageView* pPV = pDrawView->GetSdrPageView/*GetPageViewPvNum*/(/*0*/);
3680                                         if (pPV)
3681                                         {
3682                                             pDrawView->MarkObj(pTemp, pPV, true);
3683                                         }
3684                                     }
3685                             }
3686                             //mod end
3687                         }
3688                         if ( !hasObjectMarked )
3689                         {
3690                             SwEditWin& rEditWindow = m_pActiveShell->GetView().GetEditWin();
3691                             vcl::KeyCode tempKeycode( KEY_ESCAPE );
3692                             KeyEvent rKEvt( 0 , tempKeycode );
3693                             static_cast<vcl::Window*>(&rEditWindow)->KeyInput( rKEvt );
3694                         }
3695                     }
3696                 }
3697 
3698                 m_bViewHasChanged = true;
3699             }
3700         }
3701     }
3702     else
3703     {
3704         std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
3705         if (m_xTreeView->get_cursor(xEntry.get()))
3706         {
3707             SwContent* pCnt = dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64()));
3708             if (pCnt && pCnt->GetParent()->GetType() == ContentTypeId::OUTLINE)
3709             {
3710                 if (m_bIsRoot && aCode.GetCode() == KEY_LEFT && aCode.GetModifier() == 0)
3711                 {
3712                     m_xTreeView->unselect_all();
3713                     bConsumed = false;
3714                 }
3715                 else if (aCode.IsMod1())
3716                 {
3717                     if (aCode.GetCode() == KEY_LEFT)
3718                         ExecCommand("promote", !aCode.IsShift());
3719                     else if (aCode.GetCode() == KEY_RIGHT)
3720                         ExecCommand("demote", !aCode.IsShift());
3721                     else if (aCode.GetCode() == KEY_UP)
3722                         ExecCommand("chapterup", !aCode.IsShift());
3723                     else if (aCode.GetCode() == KEY_DOWN)
3724                         ExecCommand("chapterdown", !aCode.IsShift());
3725                     else
3726                         bConsumed = false;
3727                 }
3728                 else
3729                     bConsumed = false;
3730             }
3731             else
3732                 bConsumed = false;
3733         }
3734         else
3735             bConsumed = false;
3736     }
3737     return bConsumed;
3738 }
3739 
3740 IMPL_LINK(SwContentTree, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUString)
3741 {
3742     ContentTypeId nType;
3743     bool bContent = false;
3744     void* pUserData = reinterpret_cast<void*>(m_xTreeView->get_id(rEntry).toInt64());
3745     if (lcl_IsContentType(rEntry, *m_xTreeView))
3746     {
3747         assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pUserData)));
3748         nType = static_cast<SwContentType*>(pUserData)->GetType();
3749     }
3750     else
3751     {
3752         assert(dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pUserData)));
3753         nType = static_cast<SwContent*>(pUserData)->GetParent()->GetType();
3754         bContent = true;
3755     }
3756     OUString sEntry;
3757     if(bContent)
3758     {
3759         switch( nType )
3760         {
3761             case ContentTypeId::URLFIELD:
3762                 assert(dynamic_cast<SwURLFieldContent*>(static_cast<SwTypeNumber*>(pUserData)));
3763                 sEntry = static_cast<SwURLFieldContent*>(pUserData)->GetURL();
3764             break;
3765 
3766             case ContentTypeId::POSTIT:
3767                 assert(dynamic_cast<SwPostItContent*>(static_cast<SwTypeNumber*>(pUserData)));
3768                 sEntry = static_cast<SwPostItContent*>(pUserData)->GetName();
3769             break;
3770             case ContentTypeId::OUTLINE:
3771                 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pUserData)));
3772                 sEntry = static_cast<SwOutlineContent*>(pUserData)->GetName();
3773             break;
3774             case ContentTypeId::GRAPHIC:
3775                 assert(dynamic_cast<SwGraphicContent*>(static_cast<SwTypeNumber*>(pUserData)));
3776                 sEntry = static_cast<SwGraphicContent*>(pUserData)->GetLink();
3777             break;
3778             case ContentTypeId::REGION:
3779             {
3780                 assert(dynamic_cast<SwRegionContent*>(static_cast<SwTypeNumber*>(pUserData)));
3781                 sEntry = static_cast<SwRegionContent*>(pUserData)->GetName();
3782                 const SwSectionFormats& rFormats = GetWrtShell()->GetDoc()->GetSections();
3783                 for (SwSectionFormats::size_type n = rFormats.size(); n;)
3784                 {
3785                     const SwNodeIndex* pIdx = nullptr;
3786                     const SwSectionFormat* pFormat = rFormats[--n];
3787                     const SwSection* pSect;
3788                     if (nullptr != (pSect = pFormat->GetSection()) &&
3789                         pSect->GetSectionName() == sEntry &&
3790                         nullptr != (pIdx = pFormat->GetContent().GetContentIdx()) &&
3791                         pIdx->GetNode().GetNodes().IsDocNodes())
3792                     {
3793                         SwDocStat aDocStat;
3794                         SwPaM aPaM(*pIdx, *pIdx->GetNode().EndOfSectionNode());
3795                         SwDoc::CountWords(aPaM, aDocStat);
3796                         sEntry = SwResId(STR_REGION_DEFNAME) + ": " + sEntry + "\n" +
3797                                  SwResId(FLD_STAT_WORD) + ": " + OUString::number(aDocStat.nWord) + "\n" +
3798                                  SwResId(FLD_STAT_CHAR) + ": " + OUString::number(aDocStat.nChar);
3799                         break;
3800                     }
3801                 }
3802             }
3803             break;
3804             default: break;
3805         }
3806         if(static_cast<SwContent*>(pUserData)->IsInvisible())
3807         {
3808             if(!sEntry.isEmpty())
3809                 sEntry += ", ";
3810             sEntry += m_sInvisible;
3811         }
3812     }
3813     else
3814     {
3815         const size_t nMemberCount = static_cast<SwContentType*>(pUserData)->GetMemberCount();
3816         sEntry = OUString::number(nMemberCount) + " " +
3817             (nMemberCount == 1
3818                     ? static_cast<SwContentType*>(pUserData)->GetSingleName()
3819                     : static_cast<SwContentType*>(pUserData)->GetName());
3820     }
3821 
3822     return sEntry;
3823 }
3824 
3825 void SwContentTree::ExecuteContextMenuAction(const OString& rSelectedPopupEntry)
3826 {
3827     std::unique_ptr<weld::TreeIter> xFirst(m_xTreeView->make_iterator());
3828     if (!m_xTreeView->get_selected(xFirst.get()))
3829         xFirst.reset();
3830 
3831     auto nSelectedPopupEntry = rSelectedPopupEntry.toUInt32();
3832     switch (nSelectedPopupEntry)
3833     {
3834         case TOGGLE_OUTLINE_CONTENT_VISIBILITY:
3835         case HIDE_OUTLINE_CONTENT_VISIBILITY:
3836         case SHOW_OUTLINE_CONTENT_VISIBILITY:
3837         {
3838             m_pActiveShell->EnterStdMode();
3839             m_bIgnoreViewChange = true;
3840             SwOutlineContent* pCntFirst = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xFirst).toInt64());
3841             if (nSelectedPopupEntry == TOGGLE_OUTLINE_CONTENT_VISIBILITY)
3842             {
3843                 m_pActiveShell->ToggleOutlineContentVisibility(pCntFirst->GetOutlinePos());
3844             }
3845             else
3846             {
3847                 // with subs
3848                 SwOutlineNodes::size_type nPos = pCntFirst->GetOutlinePos();
3849                 if (lcl_IsContentType(*xFirst, *m_xTreeView)) // Headings root entry
3850                     nPos = SwOutlineNodes::npos;
3851                 SwOutlineNodes::size_type nOutlineNodesCount = m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
3852                 int nLevel = -1;
3853                 if (nPos != SwOutlineNodes::npos) // not root
3854                     nLevel = m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos);
3855                 else
3856                     nPos = 0;
3857                 bool bShow(nSelectedPopupEntry == SHOW_OUTLINE_CONTENT_VISIBILITY);
3858                 do
3859                 {
3860                     if (m_pActiveShell->IsOutlineContentVisible(nPos) != bShow)
3861                         m_pActiveShell->ToggleOutlineContentVisibility(nPos);
3862                 } while (++nPos < nOutlineNodesCount
3863                          && (nLevel == -1 || m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nLevel));
3864             }
3865             // show in the document what was toggled
3866             if (lcl_IsContentType(*xFirst, *m_xTreeView)) // Headings root entry
3867                 m_pActiveShell->GotoPage(1, true);
3868             else
3869                 GotoContent(pCntFirst);
3870             grab_focus();
3871             m_bIgnoreViewChange = false;
3872         }
3873         break;
3874         case 11:
3875         case 12:
3876         case 13:
3877             nSelectedPopupEntry -= 10;
3878             if(m_nOutlineTracking != nSelectedPopupEntry)
3879                 m_nOutlineTracking = nSelectedPopupEntry;
3880         break;
3881         //Outlinelevel
3882         case 101:
3883         case 102:
3884         case 103:
3885         case 104:
3886         case 105:
3887         case 106:
3888         case 107:
3889         case 108:
3890         case 109:
3891         case 110:
3892             nSelectedPopupEntry -= 100;
3893             if(m_nOutlineLevel != nSelectedPopupEntry )
3894                 SetOutlineLevel(static_cast<sal_Int8>(nSelectedPopupEntry));
3895         break;
3896         case 201:
3897         case 202:
3898         case 203:
3899             GetParentWindow()->SetRegionDropMode(static_cast<RegionMode>(nSelectedPopupEntry - 201));
3900         break;
3901         case 401:
3902         case 402:
3903             EditEntry(*xFirst, nSelectedPopupEntry == 401 ? EditEntryMode::RMV_IDX : EditEntryMode::UPD_IDX);
3904         break;
3905         // Edit entry
3906         case 403:
3907             EditEntry(*xFirst, EditEntryMode::EDIT);
3908         break;
3909         case 404:
3910             EditEntry(*xFirst, EditEntryMode::UNPROTECT_TABLE);
3911         break;
3912         case 405 :
3913         {
3914             const SwTOXBase* pBase = reinterpret_cast<SwTOXBaseContent*>(m_xTreeView->get_id(*xFirst).toInt64())
3915                                                                 ->GetTOXBase();
3916             m_pActiveShell->SetTOXBaseReadonly(*pBase, !SwEditShell::IsTOXBaseReadonly(*pBase));
3917         }
3918         break;
3919         case 4:
3920         break;
3921         case 501:
3922             EditEntry(*xFirst, EditEntryMode::DELETE);
3923         break;
3924         case 502 :
3925             EditEntry(*xFirst, EditEntryMode::RENAME);
3926         break;
3927         case 600:
3928             m_pActiveShell->GetView().GetPostItMgr()->Show();
3929             break;
3930         case 601:
3931             m_pActiveShell->GetView().GetPostItMgr()->Hide();
3932             break;
3933         case 602:
3934             {
3935                 m_pActiveShell->GetView().GetPostItMgr()->SetActiveSidebarWin(nullptr);
3936                 m_pActiveShell->GetView().GetPostItMgr()->Delete();
3937                 break;
3938             }
3939         case 700:
3940             {
3941                 m_pActiveShell->GetView().GetViewFrame()->GetDispatcher()->Execute(FN_OUTLINE_TO_CLIPBOARD);
3942                 break;
3943             }
3944         case 800:
3945             ExpandOrCollapseAll(*m_xTreeView, *xFirst);
3946             break;
3947         case 801:
3948             ExecCommand("chapterup", true);
3949             break;
3950         case 802:
3951             ExecCommand("chapterdown", true);
3952             break;
3953         case 803:
3954             ExecCommand("promote", true);
3955             break;
3956         case 804:
3957             ExecCommand("demote", true);
3958             break;
3959         case 805: // select document content
3960         {
3961             m_pActiveShell->KillPams();
3962             m_pActiveShell->ClearMark();
3963             m_pActiveShell->EnterAddMode();
3964             SwContent* pCnt = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xFirst).toInt64());
3965             const ContentTypeId eTypeId = pCnt->GetParent()->GetType();
3966             if (eTypeId == ContentTypeId::OUTLINE)
3967             {
3968                 m_xTreeView->selected_foreach([this](weld::TreeIter& rEntry){
3969                     m_pActiveShell->SttSelect();
3970                     SwOutlineNodes::size_type nActPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(rEntry).toInt64())->GetOutlinePos();
3971                     m_pActiveShell->MakeOutlineSel(nActPos, nActPos, !m_xTreeView->get_row_expanded(rEntry), false); // select children if not expanded
3972                     m_pActiveShell->EndSelect();
3973                     return false;
3974                 });
3975             }
3976             else if (eTypeId == ContentTypeId::TABLE)
3977             {
3978                 m_pActiveShell->GotoTable(pCnt->GetName());
3979                 m_pActiveShell->GetView().GetViewFrame()->GetDispatcher()->Execute(FN_TABLE_SELECT_ALL);
3980             }
3981             else if (eTypeId == ContentTypeId::REGION)
3982             {
3983                 m_pActiveShell->EnterStdMode();
3984                 m_pActiveShell->GotoRegion(pCnt->GetName());
3985                 GotoCurrRegionAndSkip(m_pActiveShell->GetCurrentShellCursor(), fnRegionEnd, m_pActiveShell->IsReadOnlyAvailable());
3986                 m_pActiveShell->SttSelect();
3987                 GotoCurrRegionAndSkip(m_pActiveShell->GetCurrentShellCursor(), fnRegionStart, m_pActiveShell->IsReadOnlyAvailable());
3988                 m_pActiveShell->EndSelect();
3989                 m_pActiveShell->UpdateCursor();
3990             }
3991             m_pActiveShell->LeaveAddMode();
3992         }
3993         break;
3994         case 806:
3995             // Delete outline selections
3996             EditEntry(*xFirst, EditEntryMode::DELETE);
3997             break;
3998         case 900:
3999         {
4000             SwContent* pCnt = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xFirst).toInt64());
4001             GotoContent(pCnt);
4002         }
4003         break;
4004         //Display
4005         default:
4006         if(nSelectedPopupEntry > 300 && nSelectedPopupEntry < 400)
4007         {
4008             nSelectedPopupEntry -= 300;
4009             SwView *pView = SwModule::GetFirstView();
4010             while (pView)
4011             {
4012                 nSelectedPopupEntry --;
4013                 if(nSelectedPopupEntry == 0)
4014                 {
4015                     SetConstantShell(&pView->GetWrtShell());
4016                     break;
4017                 }
4018                 pView = SwModule::GetNextView(pView);
4019             }
4020             if(nSelectedPopupEntry)
4021             {
4022                 m_bViewHasChanged = nSelectedPopupEntry == 1;
4023                 m_eState = (nSelectedPopupEntry == 1) ? State::ACTIVE : State::HIDDEN;
4024                 Display(nSelectedPopupEntry == 1);
4025             }
4026         }
4027     }
4028     GetParentWindow()->UpdateListBox();
4029 }
4030 
4031 void SwContentTree::DeleteOutlineSelections()
4032 {
4033     auto nChapters(0);
4034 
4035     m_pActiveShell->StartAction();
4036 
4037     m_pActiveShell->EnterAddMode();
4038     m_xTreeView->selected_foreach([this, &nChapters](weld::TreeIter& rEntry){
4039         ++nChapters;
4040         if (m_xTreeView->iter_has_child(rEntry) &&
4041             !m_xTreeView->get_row_expanded(rEntry)) // only count children if not expanded
4042         {
4043             nChapters += m_xTreeView->iter_n_children(rEntry);
4044         }
4045         SwOutlineNodes::size_type nActPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(rEntry).toInt64())->GetOutlinePos();
4046         m_pActiveShell->SttSelect();
4047         m_pActiveShell->MakeOutlineSel(nActPos, nActPos, !m_xTreeView->get_row_expanded(rEntry), false); // select children if not expanded
4048         m_pActiveShell->Right(CRSR_SKIP_CHARS, true, 1, false);
4049         m_pActiveShell->EndSelect();
4050         return false;
4051     });
4052     m_pActiveShell->LeaveAddMode();
4053 
4054     SwRewriter aRewriter;
4055     aRewriter.AddRule(UndoArg1, SwResId(STR_CHAPTERS, nChapters));
4056     m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
4057     m_pActiveShell->Delete();
4058     m_pActiveShell->EndUndo();
4059 
4060     m_pActiveShell->EndAction();
4061 }
4062 
4063 void SwContentTree::SetOutlineLevel(sal_uInt8 nSet)
4064 {
4065     m_nOutlineLevel = nSet;
4066     m_pConfig->SetOutlineLevel( m_nOutlineLevel );
4067     std::unique_ptr<SwContentType>& rpContentT = (State::ACTIVE == m_eState)
4068             ? m_aActiveContentArr[ContentTypeId::OUTLINE]
4069             : m_aHiddenContentArr[ContentTypeId::OUTLINE];
4070     if(rpContentT)
4071     {
4072         rpContentT->SetOutlineLevel(m_nOutlineLevel);
4073         rpContentT->Init();
4074     }
4075     Display(State::ACTIVE == m_eState);
4076 }
4077 
4078 // Mode Change: Show dropped Doc
4079 void SwContentTree::ShowHiddenShell()
4080 {
4081     if(m_pHiddenShell)
4082     {
4083         m_eState = State::HIDDEN;
4084         Display(false);
4085     }
4086 }
4087 
4088 // Mode Change: Show active view
4089 void SwContentTree::ShowActualView()
4090 {
4091     m_eState = State::ACTIVE;
4092     Display(true);
4093     GetParentWindow()->UpdateListBox();
4094 }
4095 
4096 IMPL_LINK_NOARG(SwContentTree, SelectHdl, weld::TreeView&, void)
4097 {
4098     Select();
4099 }
4100 
4101 // Here the buttons for moving outlines are en-/disabled.
4102 void SwContentTree::Select()
4103 {
4104     std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
4105     if (!m_xTreeView->get_selected(xEntry.get()))
4106         return;
4107 
4108     bool bEnable = false;
4109     std::unique_ptr<weld::TreeIter> xParentEntry(m_xTreeView->make_iterator(xEntry.get()));
4110     bool bParentEntry = m_xTreeView->iter_parent(*xParentEntry);
4111     while (bParentEntry && (!lcl_IsContentType(*xParentEntry, *m_xTreeView)))
4112         bParentEntry = m_xTreeView->iter_parent(*xParentEntry);
4113     if (!m_bIsLastReadOnly)
4114     {
4115         if (!m_xTreeView->get_visible())
4116             bEnable = true;
4117         else if (bParentEntry)
4118         {
4119             if ((m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE) ||
4120                 (lcl_IsContent(*xEntry, *m_xTreeView) &&
4121                     reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xParentEntry).toInt64())->GetType() == ContentTypeId::OUTLINE))
4122             {
4123                 bEnable = true;
4124             }
4125         }
4126     }
4127     SwNavigationPI* pNavi = GetParentWindow();
4128     pNavi->m_xContent6ToolBox->set_item_sensitive("chapterup",  bEnable);
4129     pNavi->m_xContent6ToolBox->set_item_sensitive("chapterdown", bEnable);
4130     pNavi->m_xContent6ToolBox->set_item_sensitive("promote", bEnable);
4131     pNavi->m_xContent6ToolBox->set_item_sensitive("demote", bEnable);
4132 }
4133 
4134 void SwContentTree::SetRootType(ContentTypeId nType)
4135 {
4136     m_nRootType = nType;
4137     m_bIsRoot = true;
4138     m_pConfig->SetRootType( m_nRootType );
4139 }
4140 
4141 OUString SwContentType::RemoveNewline(const OUString& rEntry)
4142 {
4143     if (rEntry.isEmpty())
4144         return rEntry;
4145 
4146     OUStringBuffer aEntry(rEntry);
4147     for (sal_Int32 i = 0; i < rEntry.getLength(); ++i)
4148         if(aEntry[i] == 10 || aEntry[i] == 13)
4149             aEntry[i] = 0x20;
4150 
4151     return aEntry.makeStringAndClear();
4152 }
4153 
4154 void SwContentTree::EditEntry(const weld::TreeIter& rEntry, EditEntryMode nMode)
4155 {
4156     SwContent* pCnt = reinterpret_cast<SwContent*>(m_xTreeView->get_id(rEntry).toInt64());
4157     GotoContent(pCnt);
4158     const ContentTypeId nType = pCnt->GetParent()->GetType();
4159     sal_uInt16 nSlot = 0;
4160 
4161     if(EditEntryMode::DELETE == nMode)
4162         m_bIgnoreViewChange = true;
4163 
4164     uno::Reference< container::XNameAccess >  xNameAccess, xSecond, xThird;
4165     switch(nType)
4166     {
4167         case ContentTypeId::OUTLINE :
4168             if(nMode == EditEntryMode::DELETE)
4169             {
4170                 DeleteOutlineSelections();
4171             }
4172         break;
4173 
4174         case ContentTypeId::TABLE     :
4175             if(nMode == EditEntryMode::UNPROTECT_TABLE)
4176             {
4177                 m_pActiveShell->GetView().GetDocShell()->
4178                         GetDoc()->UnProtectCells( pCnt->GetName());
4179             }
4180             else if(nMode == EditEntryMode::DELETE)
4181             {
4182                 m_pActiveShell->StartAction();
4183                 OUString sTable = SwResId(STR_TABLE_NAME);
4184                 SwRewriter aRewriterTableName;
4185                 aRewriterTableName.AddRule(UndoArg1, SwResId(STR_START_QUOTE));
4186                 aRewriterTableName.AddRule(UndoArg2, pCnt->GetName());
4187                 aRewriterTableName.AddRule(UndoArg3, SwResId(STR_END_QUOTE));
4188                 sTable = aRewriterTableName.Apply(sTable);
4189 
4190                 SwRewriter aRewriter;
4191                 aRewriter.AddRule(UndoArg1, sTable);
4192                 m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
4193                 m_pActiveShell->GetView().GetViewFrame()->GetDispatcher()->Execute(FN_TABLE_SELECT_ALL);
4194                 m_pActiveShell->DeleteRow();
4195                 m_pActiveShell->EndUndo();
4196                 m_pActiveShell->EndAction();
4197             }
4198             else if(nMode == EditEntryMode::RENAME)
4199             {
4200                 uno::Reference< frame::XModel >  xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
4201                 uno::Reference< text::XTextTablesSupplier >  xTables(xModel, uno::UNO_QUERY);
4202                 xNameAccess = xTables->getTextTables();
4203             }
4204             else
4205                 nSlot = FN_FORMAT_TABLE_DLG;
4206         break;
4207 
4208         case ContentTypeId::GRAPHIC   :
4209             if(nMode == EditEntryMode::DELETE)
4210             {
4211                 m_pActiveShell->DelRight();
4212             }
4213             else if(nMode == EditEntryMode::RENAME)
4214             {
4215                 uno::Reference< frame::XModel >  xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
4216                 uno::Reference< text::XTextGraphicObjectsSupplier >  xGraphics(xModel, uno::UNO_QUERY);
4217                 xNameAccess = xGraphics->getGraphicObjects();
4218                 uno::Reference< text::XTextFramesSupplier >  xFrames(xModel, uno::UNO_QUERY);
4219                 xSecond = xFrames->getTextFrames();
4220                 uno::Reference< text::XTextEmbeddedObjectsSupplier >  xObjs(xModel, uno::UNO_QUERY);
4221                 xThird = xObjs->getEmbeddedObjects();
4222             }
4223             else
4224                 nSlot = FN_FORMAT_GRAFIC_DLG;
4225         break;
4226 
4227         case ContentTypeId::FRAME     :
4228         case ContentTypeId::OLE       :
4229             if(nMode == EditEntryMode::DELETE)
4230             {
4231                 m_pActiveShell->DelRight();
4232             }
4233             else if(nMode == EditEntryMode::RENAME)
4234             {
4235                 uno::Reference< frame::XModel >  xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
4236                 uno::Reference< text::XTextFramesSupplier >  xFrames(xModel, uno::UNO_QUERY);
4237                 uno::Reference< text::XTextEmbeddedObjectsSupplier >  xObjs(xModel, uno::UNO_QUERY);
4238                 if(ContentTypeId::FRAME == nType)
4239                 {
4240                     xNameAccess = xFrames->getTextFrames();
4241                     xSecond = xObjs->getEmbeddedObjects();
4242                 }
4243                 else
4244                 {
4245                     xNameAccess = xObjs->getEmbeddedObjects();
4246                     xSecond = xFrames->getTextFrames();
4247                 }
4248                 uno::Reference< text::XTextGraphicObjectsSupplier >  xGraphics(xModel, uno::UNO_QUERY);
4249                 xThird = xGraphics->getGraphicObjects();
4250             }
4251             else
4252                 nSlot = FN_FORMAT_FRAME_DLG;
4253         break;
4254         case ContentTypeId::BOOKMARK  :
4255             assert(!m_pActiveShell->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS));
4256             if(nMode == EditEntryMode::DELETE)
4257             {
4258                 IDocumentMarkAccess* const pMarkAccess = m_pActiveShell->getIDocumentMarkAccess();
4259                 pMarkAccess->deleteMark( pMarkAccess->findMark(pCnt->GetName()) );
4260             }
4261             else if(nMode == EditEntryMode::RENAME)
4262             {
4263                 uno::Reference< frame::XModel >  xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
4264                 uno::Reference< text::XBookmarksSupplier >  xBkms(xModel, uno::UNO_QUERY);
4265                 xNameAccess = xBkms->getBookmarks();
4266             }
4267             else
4268                 nSlot = FN_INSERT_BOOKMARK;
4269         break;
4270 
4271         case ContentTypeId::REGION    :
4272             if(nMode == EditEntryMode::RENAME)
4273             {
4274                 uno::Reference< frame::XModel >  xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
4275                 uno::Reference< text::XTextSectionsSupplier >  xSects(xModel, uno::UNO_QUERY);
4276                 xNameAccess = xSects->getTextSections();
4277             }
4278             else
4279                 nSlot = FN_EDIT_REGION;
4280         break;
4281 
4282         case ContentTypeId::URLFIELD:
4283             if (nMode == EditEntryMode::DELETE)
4284                 nSlot = SID_REMOVE_HYPERLINK;
4285             else
4286                 nSlot = SID_EDIT_HYPERLINK;
4287         break;
4288         case ContentTypeId::REFERENCE:
4289             nSlot = FN_EDIT_FIELD;
4290         break;
4291 
4292         case ContentTypeId::POSTIT:
4293             m_pActiveShell->GetView().GetPostItMgr()->AssureStdModeAtShell();
4294             if(nMode == EditEntryMode::DELETE)
4295             {
4296                 m_pActiveShell->GetView().GetPostItMgr()->SetActiveSidebarWin(nullptr);
4297                 m_pActiveShell->DelRight();
4298             }
4299             else
4300             {
4301                 nSlot = FN_POSTIT;
4302             }
4303         break;
4304         case ContentTypeId::INDEX:
4305         {
4306             const SwTOXBase* pBase = static_cast<SwTOXBaseContent*>(pCnt)->GetTOXBase();
4307             switch(nMode)
4308             {
4309                 case EditEntryMode::EDIT:
4310                     if(pBase)
4311                     {
4312                         SwPtrItem aPtrItem( FN_INSERT_MULTI_TOX, const_cast<SwTOXBase *>(pBase));
4313                         m_pActiveShell->GetView().GetViewFrame()->
4314                             GetDispatcher()->ExecuteList(FN_INSERT_MULTI_TOX,
4315                                 SfxCallMode::ASYNCHRON, { &aPtrItem });
4316 
4317                     }
4318                 break;
4319                 case EditEntryMode::RMV_IDX:
4320                 case EditEntryMode::DELETE:
4321                 {
4322                     if( pBase )
4323                         m_pActiveShell->DeleteTOX(*pBase, EditEntryMode::DELETE == nMode);
4324                 }
4325                 break;
4326                 case EditEntryMode::UPD_IDX:
4327                 case EditEntryMode::RENAME:
4328                 {
4329                     Reference< frame::XModel >  xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
4330                     Reference< XDocumentIndexesSupplier >  xIndexes(xModel, UNO_QUERY);
4331                     Reference< XIndexAccess> xIdxAcc(xIndexes->getDocumentIndexes());
4332                     Reference< XNameAccess >xLocalNameAccess(xIdxAcc, UNO_QUERY);
4333                     if(EditEntryMode::RENAME == nMode)
4334                         xNameAccess = xLocalNameAccess;
4335                     else if(xLocalNameAccess.is() && xLocalNameAccess->hasByName(pBase->GetTOXName()))
4336                     {
4337                         Any aIdx = xLocalNameAccess->getByName(pBase->GetTOXName());
4338                         Reference< XDocumentIndex> xIdx;
4339                         if(aIdx >>= xIdx)
4340                             xIdx->update();
4341                     }
4342                 }
4343                 break;
4344                 default: break;
4345             }
4346         }
4347         break;
4348         case ContentTypeId::DRAWOBJECT :
4349             if(EditEntryMode::DELETE == nMode)
4350                 nSlot = SID_DELETE;
4351             else if(nMode == EditEntryMode::RENAME)
4352                 nSlot = FN_NAME_SHAPE;
4353         break;
4354         default: break;
4355     }
4356     if(nSlot)
4357         m_pActiveShell->GetView().GetViewFrame()->
4358                     GetDispatcher()->Execute(nSlot, SfxCallMode::SYNCHRON);
4359     else if(xNameAccess.is())
4360     {
4361         uno::Any aObj = xNameAccess->getByName(pCnt->GetName());
4362         uno::Reference< uno::XInterface >  xTmp;
4363         aObj >>= xTmp;
4364         uno::Reference< container::XNamed >  xNamed(xTmp, uno::UNO_QUERY);
4365         SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
4366         ScopedVclPtr<AbstractSwRenameXNamedDlg> pDlg(pFact->CreateSwRenameXNamedDlg(m_xTreeView.get(), xNamed, xNameAccess));
4367         if(xSecond.is())
4368             pDlg->SetAlternativeAccess( xSecond, xThird);
4369 
4370         OUString sForbiddenChars;
4371         if(ContentTypeId::BOOKMARK == nType)
4372         {
4373             sForbiddenChars = "/\\@:*?\";,.#";
4374         }
4375         else if(ContentTypeId::TABLE == nType)
4376         {
4377             sForbiddenChars = " .<>";
4378         }
4379         pDlg->SetForbiddenChars(sForbiddenChars);
4380         pDlg->Execute();
4381     }
4382     if(EditEntryMode::DELETE == nMode)
4383     {
4384         m_bViewHasChanged = true;
4385         GetParentWindow()->UpdateListBox();
4386         TimerUpdate(&m_aUpdTimer);
4387         grab_focus();
4388     }
4389 }
4390 
4391 static void lcl_AssureStdModeAtShell(SwWrtShell* pWrtShell)
4392 {
4393     // deselect any drawing or frame and leave editing mode
4394     SdrView* pSdrView = pWrtShell->GetDrawView();
4395     if (pSdrView && pSdrView->IsTextEdit() )
4396     {
4397         bool bLockView = pWrtShell->IsViewLocked();
4398         pWrtShell->LockView(true);
4399         pWrtShell->EndTextEdit();
4400         pWrtShell->LockView(bLockView);
4401     }
4402 
4403     if (pWrtShell->IsSelFrameMode() || pWrtShell->IsObjSelected())
4404     {
4405         pWrtShell->UnSelectFrame();
4406         pWrtShell->LeaveSelFrameMode();
4407         pWrtShell->GetView().LeaveDrawCreate();
4408         pWrtShell->EnterStdMode();
4409         pWrtShell->DrawSelChanged();
4410         pWrtShell->GetView().StopShellTimer();
4411     }
4412     else
4413         pWrtShell->EnterStdMode();
4414 }
4415 
4416 void SwContentTree::GotoContent(const SwContent* pCnt)
4417 {
4418     lcl_AssureStdModeAtShell(m_pActiveShell);
4419     switch(pCnt->GetParent()->GetType())
4420     {
4421         case ContentTypeId::OUTLINE   :
4422         {
4423             m_pActiveShell->GotoOutline(static_cast<const SwOutlineContent*>(pCnt)->GetOutlinePos());
4424         }
4425         break;
4426         case ContentTypeId::TABLE     :
4427         {
4428             m_pActiveShell->GotoTable(pCnt->GetName());
4429         }
4430         break;
4431         case ContentTypeId::FRAME     :
4432         case ContentTypeId::GRAPHIC   :
4433         case ContentTypeId::OLE       :
4434         {
4435             m_pActiveShell->GotoFly(pCnt->GetName());
4436         }
4437         break;
4438         case ContentTypeId::BOOKMARK:
4439         {
4440             m_pActiveShell->GotoMark(pCnt->GetName());
4441         }
4442         break;
4443         case ContentTypeId::REGION    :
4444         {
4445             m_pActiveShell->GotoRegion(pCnt->GetName());
4446         }
4447         break;
4448         case ContentTypeId::URLFIELD:
4449         {
4450             if(m_pActiveShell->GotoINetAttr(
4451                             *static_cast<const SwURLFieldContent*>(pCnt)->GetINetAttr() ))
4452             {
4453                 m_pActiveShell->Right( CRSR_SKIP_CHARS, true, 1, false);
4454                 m_pActiveShell->SwCursorShell::SelectTextAttr( RES_TXTATR_INETFMT, true );
4455             }
4456         }
4457         break;
4458         case ContentTypeId::REFERENCE:
4459         {
4460             m_pActiveShell->GotoRefMark(pCnt->GetName());
4461         }
4462         break;
4463         case ContentTypeId::INDEX:
4464         {
4465             const OUString& sName(pCnt->GetName());
4466             if (!m_pActiveShell->GotoNextTOXBase(&sName))
4467                 m_pActiveShell->GotoPrevTOXBase(&sName);
4468         }
4469         break;
4470         case ContentTypeId::POSTIT:
4471             m_pActiveShell->GotoFormatField(*static_cast<const SwPostItContent*>(pCnt)->GetPostIt());
4472         break;
4473         case ContentTypeId::DRAWOBJECT:
4474         {
4475             m_pActiveShell->GotoDrawingObject(pCnt->GetName());
4476         }
4477         break;
4478         default: break;
4479     }
4480 
4481     if (m_pActiveShell->IsFrameSelected() || m_pActiveShell->IsObjSelected())
4482     {
4483         m_pActiveShell->HideCursor();
4484         m_pActiveShell->EnterSelFrameMode();
4485     }
4486 
4487     SwView& rView = m_pActiveShell->GetView();
4488     rView.StopShellTimer();
4489     rView.GetPostItMgr()->SetActiveSidebarWin(nullptr);
4490     rView.GetEditWin().GrabFocus();
4491 
4492     // assure visible view area is at cursor position
4493     if (!m_pActiveShell->IsCursorVisible() && !m_pActiveShell->IsFrameSelected() &&
4494             !m_pActiveShell->IsObjSelected())
4495     {
4496         Point rPoint = m_pActiveShell->GetCursorDocPos();
4497         rPoint.setX(0);
4498         rView.SetVisArea(rPoint);
4499     }
4500 }
4501 
4502 // Now even the matching text::Bookmark
4503 NaviContentBookmark::NaviContentBookmark()
4504     :
4505     nDocSh(0),
4506     nDefDrag( RegionMode::NONE )
4507 {
4508 }
4509 
4510 NaviContentBookmark::NaviContentBookmark( const OUString &rUrl,
4511                     const OUString& rDesc,
4512                     RegionMode nDragType,
4513                     const SwDocShell* pDocSh ) :
4514     aUrl( rUrl ),
4515     aDescr(rDesc),
4516     nDocSh(reinterpret_cast<sal_IntPtr>(pDocSh)),
4517     nDefDrag( nDragType )
4518 {
4519 }
4520 
4521 void NaviContentBookmark::Copy( TransferDataContainer& rData ) const
4522 {
4523     rtl_TextEncoding eSysCSet = osl_getThreadTextEncoding();
4524 
4525     OString sStrBuf(OUStringToOString(aUrl, eSysCSet) + OStringChar(NAVI_BOOKMARK_DELIM) +
4526                     OUStringToOString(aDescr, eSysCSet) + OStringChar(NAVI_BOOKMARK_DELIM) +
4527                     OString::number(static_cast<int>(nDefDrag)) + OStringChar(NAVI_BOOKMARK_DELIM) +
4528                     OString::number(nDocSh));
4529     rData.CopyByteString(SotClipboardFormatId::SONLK, sStrBuf);
4530 }
4531 
4532 bool NaviContentBookmark::Paste( TransferableDataHelper& rData )
4533 {
4534     OUString sStr;
4535     bool bRet = rData.GetString( SotClipboardFormatId::SONLK, sStr );
4536     if( bRet )
4537     {
4538         sal_Int32 nPos = 0;
4539         aUrl    = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos );
4540         aDescr  = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos );
4541         nDefDrag= static_cast<RegionMode>( sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos ).toInt32() );
4542         nDocSh  = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos ).toInt32();
4543     }
4544     return bRet;
4545 }
4546 
4547 SwNavigationPI* SwContentTree::GetParentWindow()
4548 {
4549     return m_pDialog;
4550 }
4551 
4552 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
4553