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