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/help.hxx>
32 #include <vcl/settings.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 <txtatr.hxx>
47 #include <IMark.hxx>
48 #include <section.hxx>
49 #include <tox.hxx>
50 #include <navipi.hxx>
51 #include <navicont.hxx>
52 #include <navicfg.hxx>
53 #include <edtwin.hxx>
54 #include <doc.hxx>
55 #include <IDocumentDrawModelAccess.hxx>
56 #include <IDocumentOutlineNodes.hxx>
57 #include <unotools.hxx>
58 #include <unotxvw.hxx>
59 #include <cmdid.h>
60 #include <helpids.h>
61 #include <strings.hrc>
62 #include <com/sun/star/text/XTextSectionsSupplier.hpp>
63 #include <com/sun/star/text/XTextGraphicObjectsSupplier.hpp>
64 #include <com/sun/star/text/XTextTablesSupplier.hpp>
65 #include <com/sun/star/text/XDocumentIndexesSupplier.hpp>
66 #include <com/sun/star/text/XDocumentIndex.hpp>
67 #include <com/sun/star/text/XBookmarksSupplier.hpp>
68 #include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
69 #include <com/sun/star/text/XTextFramesSupplier.hpp>
70 #include <dcontact.hxx>
71 #include <svx/svdogrp.hxx>
72 #include <svx/svdmodel.hxx>
73 #include <svx/svdpage.hxx>
74 #include <svx/svdview.hxx>
75 #include <svx/svxids.hrc>
76 #include <vcl/scrbar.hxx>
77 #include <SwRewriter.hxx>
78 #include <hints.hxx>
79 #include <numrule.hxx>
80 #include <swundo.hxx>
81 #include <ndtxt.hxx>
82 #include <fmtcntnt.hxx>
83 #include <PostItMgr.hxx>
84 #include <postithelper.hxx>
85 #include <redline.hxx>
86 #include <docary.hxx>
87 #include <vcl/treelistentry.hxx>
88 
89 #include <swabstdlg.hxx>
90 #include <globals.hrc>
91 #include <bitmaps.hlst>
92 #include <unomid.h>
93 
94 #include <navmgr.hxx>
95 #include <AnnotationWin.hxx>
96 #include <memory>
97 
98 #define CTYPE_CNT   0
99 #define CTYPE_CTT   1
100 
101 using namespace ::std;
102 using namespace ::com::sun::star;
103 using namespace ::com::sun::star::text;
104 using namespace ::com::sun::star::uno;
105 using namespace ::com::sun::star::container;
106 
107 namespace {
108 
109 constexpr char NAVI_BOOKMARK_DELIM = '\x01';
110 
111 }
112 
113 class SwContentArr
114     : public o3tl::sorted_vector<std::unique_ptr<SwContent>, o3tl::less_uniqueptr_to<SwContent>,
115                 o3tl::find_partialorder_ptrequals>
116 {
117 };
118 
119 bool SwContentTree::bIsInDrag = false;
120 
121 namespace
122 {
lcl_IsContent(const SvTreeListEntry * pEntry)123     bool lcl_IsContent(const SvTreeListEntry* pEntry)
124     {
125         return static_cast<const SwTypeNumber*>(pEntry->GetUserData())->GetTypeId() == CTYPE_CNT;
126     }
127 
lcl_IsContentType(const SvTreeListEntry * pEntry)128     bool lcl_IsContentType(const SvTreeListEntry* pEntry)
129     {
130         return static_cast<const SwTypeNumber*>(pEntry->GetUserData())->GetTypeId() == CTYPE_CTT;
131     }
132 
lcl_FindShell(SwWrtShell const * pShell)133     bool lcl_FindShell(SwWrtShell const * pShell)
134     {
135         bool bFound = false;
136         SwView *pView = SwModule::GetFirstView();
137         while (pView)
138         {
139             if(pShell == &pView->GetWrtShell())
140             {
141                 bFound = true;
142                 break;
143             }
144             pView = SwModule::GetNextView(pView);
145         }
146         return bFound;
147     }
148 
lcl_IsUiVisibleBookmark(const::sw::mark::IMark * pMark)149     bool lcl_IsUiVisibleBookmark(const ::sw::mark::IMark* pMark)
150     {
151         return IDocumentMarkAccess::GetType(*pMark) == IDocumentMarkAccess::MarkType::BOOKMARK;
152     }
153 
lcl_InsertURLFieldContent(SwContentArr * pMember,SwWrtShell * pWrtShell,const SwContentType * pCntType)154     size_t lcl_InsertURLFieldContent(
155         SwContentArr *pMember,
156         SwWrtShell* pWrtShell,
157         const SwContentType *pCntType)
158     {
159         SwGetINetAttrs aArr;
160         pWrtShell->GetINetAttrs( aArr );
161         const SwGetINetAttrs::size_type nCount {aArr.size()};
162         for( SwGetINetAttrs::size_type n = 0; n < nCount; ++n )
163         {
164             SwGetINetAttr* p = &aArr[ n ];
165             std::unique_ptr<SwURLFieldContent> pCnt(new SwURLFieldContent(
166                                 pCntType,
167                                 p->sText,
168                                 INetURLObject::decode(
169                                     p->rINetAttr.GetINetFormat().GetValue(),
170                                     INetURLObject::DecodeMechanism::Unambiguous ),
171                                 &p->rINetAttr,
172                                 n ));
173             pMember->insert( std::move(pCnt) );
174         }
175         return nCount;
176     }
177 }
178 
179 // Content, contains names and reference at the content type.
180 
SwContent(const SwContentType * pCnt,const OUString & rName,long nYPos)181 SwContent::SwContent(const SwContentType* pCnt, const OUString& rName, long nYPos) :
182     SwTypeNumber(CTYPE_CNT),
183     pParent(pCnt),
184     sContentName(rName),
185     nYPosition(nYPos),
186     bInvisible(false)
187 {
188 }
189 
190 
~SwTypeNumber()191 SwTypeNumber::~SwTypeNumber()
192 {
193 }
194 
IsProtect() const195 bool SwContent::IsProtect() const
196 {
197     return false;
198 }
199 
IsProtect() const200 bool SwPostItContent::IsProtect() const
201 {
202     return pField->IsProtect();
203 }
204 
IsProtect() const205 bool SwURLFieldContent::IsProtect() const
206 {
207     return pINetAttr->IsProtect();
208 }
209 
~SwGraphicContent()210 SwGraphicContent::~SwGraphicContent()
211 {
212 }
213 
~SwTOXBaseContent()214 SwTOXBaseContent::~SwTOXBaseContent()
215 {
216 }
217 
218 static const char* STR_CONTENT_TYPE_ARY[] =
219 {
220     STR_CONTENT_TYPE_OUTLINE,
221     STR_CONTENT_TYPE_TABLE,
222     STR_CONTENT_TYPE_FRAME,
223     STR_CONTENT_TYPE_GRAPHIC,
224     STR_CONTENT_TYPE_OLE,
225     STR_CONTENT_TYPE_BOOKMARK,
226     STR_CONTENT_TYPE_REGION,
227     STR_CONTENT_TYPE_URLFIELD,
228     STR_CONTENT_TYPE_REFERENCE,
229     STR_CONTENT_TYPE_INDEX,
230     STR_CONTENT_TYPE_POSTIT,
231     STR_CONTENT_TYPE_DRAWOBJECT
232 };
233 
234 static const char* STR_CONTENT_TYPE_SINGLE_ARY[] =
235 {
236     STR_CONTENT_TYPE_SINGLE_OUTLINE,
237     STR_CONTENT_TYPE_SINGLE_TABLE,
238     STR_CONTENT_TYPE_SINGLE_FRAME,
239     STR_CONTENT_TYPE_SINGLE_GRAPHIC,
240     STR_CONTENT_TYPE_SINGLE_OLE,
241     STR_CONTENT_TYPE_SINGLE_BOOKMARK,
242     STR_CONTENT_TYPE_SINGLE_REGION,
243     STR_CONTENT_TYPE_SINGLE_URLFIELD,
244     STR_CONTENT_TYPE_SINGLE_REFERENCE,
245     STR_CONTENT_TYPE_SINGLE_INDEX,
246     STR_CONTENT_TYPE_SINGLE_POSTIT,
247     STR_CONTENT_TYPE_SINGLE_DRAWOBJECT
248 };
249 
250 namespace
251 {
checkVisibilityChanged(const SwContentArr & rSwContentArrA,const SwContentArr & rSwContentArrB)252     bool checkVisibilityChanged(
253         const SwContentArr& rSwContentArrA,
254         const SwContentArr& rSwContentArrB)
255     {
256         if(rSwContentArrA.size() != rSwContentArrB.size())
257         {
258             return true;
259         }
260 
261         for(size_t a(0); a < rSwContentArrA.size(); a++)
262         {
263             if(rSwContentArrA[a]->IsInvisible() != rSwContentArrB[a]->IsInvisible())
264             {
265                 return true;
266             }
267         }
268 
269         return false;
270     }
271 } // end of anonymous namespace
272 
SwContentType(SwWrtShell * pShell,ContentTypeId nType,sal_uInt8 nLevel)273 SwContentType::SwContentType(SwWrtShell* pShell, ContentTypeId nType, sal_uInt8 nLevel) :
274     SwTypeNumber(CTYPE_CTT),
275     m_pWrtShell(pShell),
276     m_sContentTypeName(SwResId(STR_CONTENT_TYPE_ARY[static_cast<int>(nType)])),
277     m_sSingleContentTypeName(SwResId(STR_CONTENT_TYPE_SINGLE_ARY[static_cast<int>(nType)])),
278     m_nMemberCount(0),
279     m_nContentType(nType),
280     m_nOutlineLevel(nLevel),
281     m_bDataValid(false),
282     m_bEdit(false),
283     m_bDelete(true)
284 {
285     Init();
286 }
287 
Init(bool * pbInvalidateWindow)288 void SwContentType::Init(bool* pbInvalidateWindow)
289 {
290     // if the MemberCount is changing ...
291     size_t nOldMemberCount = m_nMemberCount;
292     m_nMemberCount = 0;
293     switch(m_nContentType)
294     {
295         case ContentTypeId::OUTLINE   :
296         {
297             m_sTypeToken = "outline";
298             m_nMemberCount = m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
299             if (m_nMemberCount < MAXLEVEL)
300             {
301                 const size_t nOutlineCount = m_nMemberCount;
302                 for(size_t j = 0; j < nOutlineCount; ++j)
303                 {
304                     if (m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(j) > m_nOutlineLevel
305                         || !m_pWrtShell->getIDocumentOutlineNodesAccess()->isOutlineInLayout(j, *m_pWrtShell->GetLayout()))
306                     {
307                         m_nMemberCount --;
308                     }
309                 }
310             }
311             m_bDelete = false;
312         }
313         break;
314 
315         case ContentTypeId::TABLE     :
316             m_sTypeToken = "table";
317             m_nMemberCount = m_pWrtShell->GetTableFrameFormatCount(true);
318             m_bEdit = true;
319         break;
320 
321         case ContentTypeId::FRAME     :
322         case ContentTypeId::GRAPHIC   :
323         case ContentTypeId::OLE       :
324         {
325             FlyCntType eType = FLYCNTTYPE_FRM;
326             m_sTypeToken = "frame";
327             if(m_nContentType == ContentTypeId::OLE)
328             {
329                 eType = FLYCNTTYPE_OLE;
330                 m_sTypeToken = "ole";
331             }
332             else if(m_nContentType == ContentTypeId::GRAPHIC)
333             {
334                 eType = FLYCNTTYPE_GRF;
335                 m_sTypeToken = "graphic";
336             }
337             m_nMemberCount = m_pWrtShell->GetFlyCount(eType, /*bIgnoreTextBoxes=*/true);
338             m_bEdit = true;
339         }
340         break;
341         case ContentTypeId::BOOKMARK:
342         {
343             IDocumentMarkAccess* const pMarkAccess = m_pWrtShell->getIDocumentMarkAccess();
344             m_nMemberCount = count_if(
345                 pMarkAccess->getBookmarksBegin(),
346                 pMarkAccess->getBookmarksEnd(),
347                 &lcl_IsUiVisibleBookmark);
348             m_sTypeToken.clear();
349             m_bEdit = true;
350         }
351         break;
352         case ContentTypeId::REGION :
353         {
354             std::unique_ptr<SwContentArr> pOldMember;
355             if(!m_pMember)
356                 m_pMember.reset( new SwContentArr );
357             else if(!m_pMember->empty())
358             {
359                 pOldMember = std::move(m_pMember);
360                 m_pMember.reset( new SwContentArr );
361             }
362             const Point aNullPt;
363             m_nMemberCount = m_pWrtShell->GetSectionFormatCount();
364             for(size_t i = 0; i < m_nMemberCount; ++i)
365             {
366                 const SwSectionFormat* pFormat;
367                 SectionType eTmpType;
368                 if( (pFormat = &m_pWrtShell->GetSectionFormat(i))->IsInNodesArr() &&
369                 (eTmpType = pFormat->GetSection()->GetType()) != TOX_CONTENT_SECTION
370                 && TOX_HEADER_SECTION != eTmpType )
371                 {
372                     const OUString& rSectionName =
373                         pFormat->GetSection()->GetSectionName();
374                     sal_uInt8 nLevel = 0;
375                     SwSectionFormat* pParentFormat = pFormat->GetParent();
376                     while(pParentFormat)
377                     {
378                         nLevel++;
379                         pParentFormat = pParentFormat->GetParent();
380                     }
381 
382                     std::unique_ptr<SwContent> pCnt(new SwRegionContent(this, rSectionName,
383                             nLevel,
384                             pFormat->FindLayoutRect( false, &aNullPt ).Top()));
385 
386                     SwPtrMsgPoolItem aAskItem( RES_CONTENT_VISIBLE, nullptr );
387                     if( !pFormat->GetInfo( aAskItem ) &&
388                         !aAskItem.pObject )     // not visible
389                         pCnt->SetInvisible();
390                     m_pMember->insert(std::move(pCnt));
391                 }
392             }
393             m_nMemberCount = m_pMember->size();
394             m_sTypeToken = "region";
395             m_bEdit = true;
396             m_bDelete = false;
397             if(pOldMember)
398             {
399                 if(nullptr != pbInvalidateWindow)
400                 {
401                     // need to check visibility (and equal entry number) after
402                     // creation due to a sorted list being used here (before,
403                     // entries with same index were compared already at creation
404                     // time what worked before a sorted list was used)
405                     *pbInvalidateWindow = checkVisibilityChanged(
406                         *pOldMember,
407                         *m_pMember);
408                 }
409             }
410         }
411         break;
412         case ContentTypeId::INDEX:
413         {
414             m_nMemberCount = m_pWrtShell->GetTOXCount();
415             m_bEdit = true;
416             m_bDelete = false;
417         }
418         break;
419         case ContentTypeId::REFERENCE:
420         {
421             m_nMemberCount = m_pWrtShell->GetRefMarks();
422             m_bDelete = false;
423         }
424         break;
425         case ContentTypeId::URLFIELD:
426         {
427             m_nMemberCount = 0;
428             if(!m_pMember)
429                 m_pMember.reset( new SwContentArr );
430             else
431                 m_pMember->clear();
432 
433             m_nMemberCount = lcl_InsertURLFieldContent(m_pMember.get(), m_pWrtShell, this);
434 
435             m_bEdit = true;
436             nOldMemberCount = m_nMemberCount;
437             m_bDelete = false;
438         }
439         break;
440         case ContentTypeId::POSTIT:
441         {
442             m_nMemberCount = 0;
443             if(!m_pMember)
444                 m_pMember.reset( new SwContentArr );
445             else
446                 m_pMember->clear();
447 
448             SwPostItMgr* aMgr = m_pWrtShell->GetView().GetPostItMgr();
449             if (aMgr)
450             {
451                 for(SwPostItMgr::const_iterator i = aMgr->begin(); i != aMgr->end(); ++i)
452                 {
453                     if (const SwFormatField* pFormatField = dynamic_cast<const SwFormatField *>((*i)->GetBroadcaster())) // SwPostit
454                     {
455                         if (pFormatField->GetTextField() && pFormatField->IsFieldInDoc() &&
456                             (*i)->mLayoutStatus!=SwPostItHelper::INVISIBLE )
457                         {
458                             OUString sEntry = pFormatField->GetField()->GetPar2();
459                             sEntry = RemoveNewline(sEntry);
460                             std::unique_ptr<SwPostItContent> pCnt(new SwPostItContent(
461                                                 this,
462                                                 sEntry,
463                                                 pFormatField,
464                                                 m_nMemberCount));
465                             m_pMember->insert(std::move(pCnt));
466                             m_nMemberCount++;
467                         }
468                     }
469                 }
470             }
471             m_sTypeToken.clear();
472             m_bEdit = true;
473             nOldMemberCount = m_nMemberCount;
474         }
475         break;
476         case ContentTypeId::DRAWOBJECT:
477         {
478             m_sTypeToken.clear();
479             m_nMemberCount = 0;
480             SwDrawModel* pModel = m_pWrtShell->getIDocumentDrawModelAccess().GetDrawModel();
481             if(pModel)
482             {
483                 SdrPage* pPage = pModel->GetPage(0);
484                 const size_t nCount = pPage->GetObjCount();
485                 for( size_t i=0; i<nCount; ++i )
486                 {
487                     SdrObject* pTemp = pPage->GetObj(i);
488                     // #i51726# - all drawing objects can be named now
489                     if (!pTemp->GetName().isEmpty())
490                         m_nMemberCount++;
491                 }
492             }
493         }
494         break;
495         default: break;
496     }
497     // ... then, the data can also no longer be valid,
498     // apart from those which have already been corrected,
499     // then nOldMemberCount is nevertheless not so old.
500     if( nOldMemberCount != m_nMemberCount )
501         m_bDataValid = false;
502 }
503 
~SwContentType()504 SwContentType::~SwContentType()
505 {
506 }
507 
GetMember(size_t nIndex)508 const SwContent* SwContentType::GetMember(size_t nIndex)
509 {
510     if(!m_bDataValid || !m_pMember)
511     {
512         FillMemberList();
513     }
514     if(nIndex < m_pMember->size())
515         return (*m_pMember)[nIndex].get();
516 
517     return nullptr;
518 }
519 
Invalidate()520 void SwContentType::Invalidate()
521 {
522     m_bDataValid = false;
523 }
524 
FillMemberList(bool * pbLevelOrVisibilityChanged)525 void SwContentType::FillMemberList(bool* pbLevelOrVisibilityChanged)
526 {
527     std::unique_ptr<SwContentArr> pOldMember;
528     size_t nOldMemberCount = 0;
529     SwPtrMsgPoolItem aAskItem( RES_CONTENT_VISIBLE, nullptr );
530     if(m_pMember && pbLevelOrVisibilityChanged)
531     {
532         pOldMember = std::move(m_pMember);
533         nOldMemberCount = pOldMember->size();
534         m_pMember.reset( new SwContentArr );
535         *pbLevelOrVisibilityChanged = false;
536     }
537     else if(!m_pMember)
538         m_pMember.reset( new SwContentArr );
539     else
540         m_pMember->clear();
541     switch(m_nContentType)
542     {
543         case ContentTypeId::OUTLINE   :
544         {
545             const size_t nOutlineCount = m_nMemberCount =
546                 m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
547 
548             size_t nPos = 0;
549             for (size_t i = 0; i < nOutlineCount; ++i)
550             {
551                 const sal_Int8 nLevel = static_cast<sal_Int8>(m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(i));
552                 if(nLevel >= m_nOutlineLevel )
553                     m_nMemberCount--;
554                 else
555                 {
556                     if (!m_pWrtShell->getIDocumentOutlineNodesAccess()->isOutlineInLayout(i, *m_pWrtShell->GetLayout()))
557                     {
558                         --m_nMemberCount;
559                         continue; // don't hide it, just skip it
560                     }
561                     OUString aEntry(comphelper::string::stripStart(
562                         m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineText(i, m_pWrtShell->GetLayout()), ' '));
563                     aEntry = SwNavigationPI::CleanEntry(aEntry);
564                     std::unique_ptr<SwOutlineContent> pCnt(new SwOutlineContent(this, aEntry, i, nLevel,
565                                                         m_pWrtShell->IsOutlineMovable( i ), nPos ));
566                     m_pMember->insert(std::move(pCnt));
567                     // with the same number and existing "pOldMember" the
568                     // old one is compared with the new OutlinePos.
569                     if (nOldMemberCount > nPos && static_cast<SwOutlineContent*>((*pOldMember)[nPos].get())->GetOutlineLevel() != nLevel)
570                         *pbLevelOrVisibilityChanged = true;
571 
572                     nPos++;
573                 }
574             }
575 
576         }
577         break;
578 
579         case ContentTypeId::TABLE     :
580         {
581             const size_t nCount = m_pWrtShell->GetTableFrameFormatCount(true);
582             OSL_ENSURE(m_nMemberCount == nCount, "MemberCount differs");
583             Point aNullPt;
584             m_nMemberCount = nCount;
585             for(size_t i = 0; i < m_nMemberCount; ++i)
586             {
587                 const SwFrameFormat& rTableFormat = m_pWrtShell->GetTableFrameFormat(i, true);
588                 const OUString& sTableName( rTableFormat.GetName() );
589 
590                 SwContent* pCnt = new SwContent(this, sTableName,
591                         rTableFormat.FindLayoutRect(false, &aNullPt).Top() );
592                 if( !rTableFormat.GetInfo( aAskItem ) &&
593                     !aAskItem.pObject )     // not visible
594                     pCnt->SetInvisible();
595 
596                 m_pMember->insert(std::unique_ptr<SwContent>(pCnt));
597 
598                 if(nOldMemberCount > i &&
599                     (*pOldMember)[i]->IsInvisible() != pCnt->IsInvisible())
600                         *pbLevelOrVisibilityChanged = true;
601             }
602         }
603         break;
604         case ContentTypeId::OLE       :
605         case ContentTypeId::FRAME     :
606         case ContentTypeId::GRAPHIC   :
607         {
608             FlyCntType eType = FLYCNTTYPE_FRM;
609             if(m_nContentType == ContentTypeId::OLE)
610                 eType = FLYCNTTYPE_OLE;
611             else if(m_nContentType == ContentTypeId::GRAPHIC)
612                 eType = FLYCNTTYPE_GRF;
613             Point aNullPt;
614             m_nMemberCount = m_pWrtShell->GetFlyCount(eType, /*bIgnoreTextBoxes=*/true);
615             std::vector<SwFrameFormat const*> formats(m_pWrtShell->GetFlyFrameFormats(eType, /*bIgnoreTextBoxes=*/true));
616             SAL_WARN_IF(m_nMemberCount != formats.size(), "sw.ui", "MemberCount differs");
617             m_nMemberCount = formats.size();
618             for (size_t i = 0; i < m_nMemberCount; ++i)
619             {
620                 SwFrameFormat const*const pFrameFormat = formats[i];
621                 const OUString sFrameName = pFrameFormat->GetName();
622 
623                 SwContent* pCnt;
624                 if(ContentTypeId::GRAPHIC == m_nContentType)
625                 {
626                     OUString sLink;
627                     m_pWrtShell->GetGrfNms( &sLink, nullptr, static_cast<const SwFlyFrameFormat*>( pFrameFormat));
628                     pCnt = new SwGraphicContent(this, sFrameName,
629                                 INetURLObject::decode( sLink,
630                                            INetURLObject::DecodeMechanism::Unambiguous ),
631                                 pFrameFormat->FindLayoutRect(false, &aNullPt).Top());
632                 }
633                 else
634                 {
635                     pCnt = new SwContent(this, sFrameName,
636                             pFrameFormat->FindLayoutRect(false, &aNullPt).Top() );
637                 }
638                 if( !pFrameFormat->GetInfo( aAskItem ) &&
639                     !aAskItem.pObject )     // not visible
640                     pCnt->SetInvisible();
641                 m_pMember->insert(std::unique_ptr<SwContent>(pCnt));
642                 if (nOldMemberCount > i &&
643                     (*pOldMember)[i]->IsInvisible() != pCnt->IsInvisible())
644                         *pbLevelOrVisibilityChanged = true;
645             }
646         }
647         break;
648         case ContentTypeId::BOOKMARK:
649         {
650             IDocumentMarkAccess* const pMarkAccess = m_pWrtShell->getIDocumentMarkAccess();
651             for(IDocumentMarkAccess::const_iterator_t ppBookmark = pMarkAccess->getBookmarksBegin();
652                 ppBookmark != pMarkAccess->getBookmarksEnd();
653                 ++ppBookmark)
654             {
655                 if(lcl_IsUiVisibleBookmark(*ppBookmark))
656                 {
657                     const OUString& rBkmName = (*ppBookmark)->GetName();
658                     //nYPos from 0 -> text::Bookmarks will be sorted alphabetically
659                     std::unique_ptr<SwContent> pCnt(new SwContent(this, rBkmName, 0));
660                     m_pMember->insert(std::move(pCnt));
661                 }
662             }
663         }
664         break;
665         case ContentTypeId::REGION    :
666         {
667             const Point aNullPt;
668             m_nMemberCount = m_pWrtShell->GetSectionFormatCount();
669             for(size_t i = 0; i < m_nMemberCount; ++i)
670             {
671                 const SwSectionFormat* pFormat;
672                 SectionType eTmpType;
673                 if( (pFormat = &m_pWrtShell->GetSectionFormat(i))->IsInNodesArr() &&
674                 (eTmpType = pFormat->GetSection()->GetType()) != TOX_CONTENT_SECTION
675                 && TOX_HEADER_SECTION != eTmpType )
676                 {
677                     OUString sSectionName = pFormat->GetSection()->GetSectionName();
678 
679                     sal_uInt8 nLevel = 0;
680                     SwSectionFormat* pParentFormat = pFormat->GetParent();
681                     while(pParentFormat)
682                     {
683                         nLevel++;
684                         pParentFormat = pParentFormat->GetParent();
685                     }
686 
687                     std::unique_ptr<SwContent> pCnt(new SwRegionContent(this, sSectionName,
688                             nLevel,
689                             pFormat->FindLayoutRect( false, &aNullPt ).Top()));
690                     if( !pFormat->GetInfo( aAskItem ) &&
691                         !aAskItem.pObject )     // not visible
692                         pCnt->SetInvisible();
693                     m_pMember->insert(std::move(pCnt));
694                 }
695 
696                 if(nullptr != pbLevelOrVisibilityChanged)
697                 {
698                     assert(pOldMember);
699                     // need to check visibility (and equal entry number) after
700                     // creation due to a sorted list being used here (before,
701                     // entries with same index were compared already at creation
702                     // time what worked before a sorted list was used)
703                     *pbLevelOrVisibilityChanged = checkVisibilityChanged(
704                         *pOldMember,
705                         *m_pMember);
706                 }
707             }
708             m_nMemberCount = m_pMember->size();
709         }
710         break;
711         case ContentTypeId::REFERENCE:
712         {
713             std::vector<OUString> aRefMarks;
714             m_nMemberCount = m_pWrtShell->GetRefMarks( &aRefMarks );
715 
716             for (const auto& rRefMark : aRefMarks)
717             {
718                 // References sorted alphabetically
719                 m_pMember->insert(std::make_unique<SwContent>(this, rRefMark, 0));
720             }
721         }
722         break;
723         case ContentTypeId::URLFIELD:
724             m_nMemberCount = lcl_InsertURLFieldContent(m_pMember.get(), m_pWrtShell, this);
725         break;
726         case ContentTypeId::INDEX:
727         {
728 
729             const sal_uInt16 nCount = m_pWrtShell->GetTOXCount();
730             m_nMemberCount = nCount;
731             for ( sal_uInt16 nTox = 0; nTox < nCount; nTox++ )
732             {
733                 const SwTOXBase* pBase = m_pWrtShell->GetTOX( nTox );
734                 OUString sTOXNm( pBase->GetTOXName() );
735 
736                 SwContent* pCnt = new SwTOXBaseContent(
737                         this, sTOXNm, nTox, *pBase);
738 
739                 if( !pBase->GetInfo( aAskItem ) &&
740                     !aAskItem.pObject )     // not visible
741                     pCnt->SetInvisible();
742 
743                 m_pMember->insert( std::unique_ptr<SwContent>(pCnt) );
744                 const size_t nPos = m_pMember->size() - 1;
745                 if(nOldMemberCount > nPos &&
746                     (*pOldMember)[nPos]->IsInvisible()
747                             != pCnt->IsInvisible())
748                         *pbLevelOrVisibilityChanged = true;
749             }
750         }
751         break;
752         case ContentTypeId::POSTIT:
753         {
754             m_nMemberCount = 0;
755             m_pMember->clear();
756             SwPostItMgr* aMgr = m_pWrtShell->GetView().GetPostItMgr();
757             if (aMgr)
758             {
759                 for(SwPostItMgr::const_iterator i = aMgr->begin(); i != aMgr->end(); ++i)
760                 {
761                     if (const SwFormatField* pFormatField = dynamic_cast<const SwFormatField *>((*i)->GetBroadcaster())) // SwPostit
762                     {
763                         if (pFormatField->GetTextField() && pFormatField->IsFieldInDoc() &&
764                             (*i)->mLayoutStatus!=SwPostItHelper::INVISIBLE )
765                         {
766                             OUString sEntry = pFormatField->GetField()->GetPar2();
767                             sEntry = RemoveNewline(sEntry);
768                             std::unique_ptr<SwPostItContent> pCnt(new SwPostItContent(
769                                                 this,
770                                                 sEntry,
771                                                 pFormatField,
772                                                 m_nMemberCount));
773                             m_pMember->insert(std::move(pCnt));
774                             m_nMemberCount++;
775                         }
776                     }
777                 }
778             }
779         }
780         break;
781         case ContentTypeId::DRAWOBJECT:
782         {
783             m_nMemberCount = 0;
784             m_pMember->clear();
785 
786             IDocumentDrawModelAccess& rIDDMA = m_pWrtShell->getIDocumentDrawModelAccess();
787             SwDrawModel* pModel = rIDDMA.GetDrawModel();
788             if(pModel)
789             {
790                 SdrPage* pPage = pModel->GetPage(0);
791                 const size_t nCount = pPage->GetObjCount();
792                 for( size_t i=0; i<nCount; ++i )
793                 {
794                     SdrObject* pTemp = pPage->GetObj(i);
795                     // #i51726# - all drawing objects can be named now
796                     if (!pTemp->GetName().isEmpty())
797                     {
798                         SwContact* pContact = static_cast<SwContact*>(pTemp->GetUserCall());
799                         long nYPos = 0;
800                         const Point aNullPt;
801                         if(pContact && pContact->GetFormat())
802                             nYPos = pContact->GetFormat()->FindLayoutRect(false, &aNullPt).Top();
803                         SwContent* pCnt = new SwContent(
804                                             this,
805                                             pTemp->GetName(),
806                                             nYPos);
807                         if(!rIDDMA.IsVisibleLayerId(pTemp->GetLayer()))
808                             pCnt->SetInvisible();
809                         m_pMember->insert(std::unique_ptr<SwContent>(pCnt));
810                         m_nMemberCount++;
811                         if (nOldMemberCount > i &&
812                             (*pOldMember)[i]->IsInvisible() != pCnt->IsInvisible() )
813                                 *pbLevelOrVisibilityChanged = true;
814                     }
815                 }
816             }
817         }
818         break;
819         default: break;
820     }
821     m_bDataValid = true;
822 }
823 
824 enum STR_CONTEXT_IDX
825 {
826     IDX_STR_OUTLINE_LEVEL = 0,
827     IDX_STR_DRAGMODE = 1,
828     IDX_STR_HYPERLINK = 2,
829     IDX_STR_LINK_REGION = 3,
830     IDX_STR_COPY_REGION = 4,
831     IDX_STR_DISPLAY = 5,
832     IDX_STR_ACTIVE_VIEW = 6,
833     IDX_STR_HIDDEN = 7,
834     IDX_STR_ACTIVE = 8,
835     IDX_STR_INACTIVE = 9,
836     IDX_STR_EDIT_ENTRY = 10,
837     IDX_STR_DELETE_ENTRY = 11,
838     IDX_STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY = 12
839 };
840 
841 static const char* STR_CONTEXT_ARY[] =
842 {
843     STR_OUTLINE_LEVEL,
844     STR_DRAGMODE,
845     STR_HYPERLINK,
846     STR_LINK_REGION,
847     STR_COPY_REGION,
848     STR_DISPLAY,
849     STR_ACTIVE_VIEW,
850     STR_HIDDEN,
851     STR_ACTIVE,
852     STR_INACTIVE,
853     STR_EDIT_ENTRY,
854     STR_DELETE_ENTRY,
855     STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY
856 };
857 
SwContentTree(vcl::Window * pParent,SwNavigationPI * pDialog)858 SwContentTree::SwContentTree(vcl::Window* pParent, SwNavigationPI* pDialog)
859     : SvTreeListBox(pParent)
860     , m_xDialog(pDialog)
861     , m_sSpace(OUString("                    "))
862     , m_sRemoveIdx(SwResId(STR_REMOVE_INDEX))
863     , m_sUpdateIdx(SwResId(STR_UPDATE))
864     , m_sUnprotTable(SwResId(STR_REMOVE_TBL_PROTECTION))
865     , m_sRename(SwResId(STR_RENAME))
866     , m_sReadonlyIdx(SwResId(STR_READONLY_IDX))
867     , m_sInvisible(SwResId(STR_INVISIBLE))
868     , m_sPostItShow(SwResId(STR_POSTIT_SHOW))
869     , m_sPostItHide(SwResId(STR_POSTIT_HIDE))
870     , m_sPostItDelete(SwResId(STR_POSTIT_DELETE))
871     , m_pHiddenShell(nullptr)
872     , m_pActiveShell(nullptr)
873     , m_pConfig(SW_MOD()->GetNavigationConfig())
874     , m_nActiveBlock(0)
875     , m_nHiddenBlock(0)
876     , m_nRootType(ContentTypeId::UNKNOWN)
877     , m_nLastSelType(ContentTypeId::UNKNOWN)
878     , m_nOutlineLevel(MAXLEVEL)
879     , m_eState(State::ACTIVE)
880     , m_bDocChgdInDragging(false)
881     , m_bIsInternalDrag(false)
882     , m_bIsRoot(false)
883     , m_bIsIdleClear(false)
884     , m_bIsLastReadOnly(false)
885     , m_bIsOutlineMoveable(true)
886     , m_bViewHasChanged(false)
887     , m_bIsKeySpace(false)
888 {
889     SetHelpId(HID_NAVIGATOR_TREELIST);
890 
891     SetNodeDefaultImages();
892     SetDoubleClickHdl(LINK(this, SwContentTree, ContentDoubleClickHdl));
893     SetDragDropMode(DragDropMode::APP_COPY);
894     for (ContentTypeId i : o3tl::enumrange<ContentTypeId>())
895     {
896         m_aActiveContentArr[i]    = nullptr;
897         m_aHiddenContentArr[i]    = nullptr;
898     }
899     for (int i = 0; i < CONTEXT_COUNT; ++i)
900     {
901         m_aContextStrings[i] = SwResId(STR_CONTEXT_ARY[i]);
902     }
903     m_nActiveBlock = m_pConfig->GetActiveBlock();
904     m_aUpdTimer.SetInvokeHandler(LINK(this, SwContentTree, TimerUpdate));
905     m_aUpdTimer.SetTimeout(1000);
906     Clear();
907     EnableContextMenuHandling();
908     SetQuickSearch(true);
909 }
910 
~SwContentTree()911 SwContentTree::~SwContentTree()
912 {
913     disposeOnce();
914 }
915 
dispose()916 void SwContentTree::dispose()
917 {
918     Clear(); // If applicable erase content types previously.
919     bIsInDrag = false;
920     m_aUpdTimer.Stop();
921     SetActiveShell(nullptr);
922     m_xDialog.clear();
923     SvTreeListBox::dispose();
924 }
925 
GetOptimalSize() const926 Size SwContentTree::GetOptimalSize() const
927 {
928     return LogicToPixel(Size(110, 112), MapMode(MapUnit::MapAppFont));
929 }
930 
GetEntryAltText(SvTreeListEntry * pEntry) const931 OUString SwContentTree::GetEntryAltText( SvTreeListEntry* pEntry ) const
932 {
933     if (pEntry == nullptr || !lcl_IsContent(pEntry))
934         return OUString();
935 
936     assert(pEntry->GetUserData() == nullptr || dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
937     SwContent* pCnt = static_cast<SwContent*>(pEntry->GetUserData());
938     if( pCnt == nullptr || pCnt->GetParent() == nullptr)
939         return OUString();
940 
941     ContentTypeId nJumpType = pCnt->GetParent()->GetType();
942     SdrObject* pTemp;
943 
944     switch(nJumpType)
945     {
946         case ContentTypeId::DRAWOBJECT:
947             {
948                 SdrView* pDrawView = m_pActiveShell->GetDrawView();
949                 if (pDrawView)
950                 {
951                     SwDrawModel* pDrawModel = m_pActiveShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
952                     SdrPage* pPage = pDrawModel->GetPage(0);
953                     const size_t nCount = pPage->GetObjCount();
954                     for( size_t i=0; i<nCount; ++i )
955                     {
956                         pTemp = pPage->GetObj(i);
957                         sal_uInt16 nCmpId;
958                         switch( pTemp->GetObjIdentifier() )
959                         {
960                         case OBJ_GRUP:
961                         case OBJ_TEXT:
962                         case OBJ_LINE:
963                         case OBJ_RECT:
964                         case OBJ_CUSTOMSHAPE:
965                         case OBJ_CIRC:
966                         case OBJ_SECT:
967                         case OBJ_CARC:
968                         case OBJ_CCUT:
969                         case OBJ_POLY:
970                         case OBJ_PLIN:
971                         case OBJ_PATHLINE:
972                         case OBJ_PATHFILL:
973                         case OBJ_FREELINE:
974                         case OBJ_FREEFILL:
975                         case OBJ_PATHPOLY:
976                         case OBJ_PATHPLIN:
977                         case OBJ_CAPTION:
978                             nCmpId = OBJ_GRUP;
979                             break;
980                         default:
981                             nCmpId = pTemp->GetObjIdentifier();
982                         }
983                         if(nCmpId == OBJ_GRUP && pTemp->GetName() == pCnt->GetName())
984                         {
985                             return pTemp->GetTitle();
986                         }
987                     }
988                 }
989             }
990             break;
991         case ContentTypeId::GRAPHIC   :
992             {
993                 if( m_pActiveShell && m_pActiveShell->GetDoc() )
994                 {
995                     const SwFlyFrameFormat* pFrameFormat = m_pActiveShell->GetDoc()->FindFlyByName( pCnt->GetName());
996                     if( pFrameFormat )
997                         return pFrameFormat->GetObjTitle();
998                 }
999             }
1000             break;
1001         case ContentTypeId::OLE       :
1002         case ContentTypeId::FRAME     :
1003             {
1004                 //Can't find the GetAlternateText function. Need to verify again.
1005                 const SwFlyFrameFormat* pFlyFormat = m_pActiveShell->GetDoc()->FindFlyByName( pCnt->GetName());
1006                 if( pFlyFormat )
1007                     return pFlyFormat->/*GetAlternateText*/GetName();
1008             }
1009             break;
1010         default: break;
1011     }
1012     return OUString();
1013 }
1014 
GetEntryLongDescription(SvTreeListEntry * pEntry) const1015 OUString SwContentTree::GetEntryLongDescription( SvTreeListEntry* pEntry ) const
1016 {
1017     if( pEntry == nullptr)
1018         return OUString();
1019 
1020     assert(pEntry->GetUserData() == nullptr || dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
1021     SwContent* pCnt = static_cast<SwContent*>(pEntry->GetUserData());
1022     if( pCnt == nullptr || pCnt->GetParent() == nullptr)
1023         return OUString();
1024 
1025     SdrObject* pTemp;
1026 
1027     switch(pCnt->GetParent()->GetType())
1028     {
1029         case ContentTypeId::DRAWOBJECT:
1030             {
1031                 SdrView* pDrawView = m_pActiveShell->GetDrawView();
1032                 if (pDrawView)
1033                 {
1034                     SwDrawModel* pDrawModel = m_pActiveShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
1035                     SdrPage* pPage = pDrawModel->GetPage(0);
1036                     const size_t nCount = pPage->GetObjCount();
1037                     for( size_t i=0; i<nCount; ++i )
1038                     {
1039                         pTemp = pPage->GetObj(i);
1040                         sal_uInt16 nCmpId;
1041                         switch( pTemp->GetObjIdentifier() )
1042                         {
1043                         case OBJ_GRUP:
1044                         case OBJ_TEXT:
1045                         case OBJ_LINE:
1046                         case OBJ_RECT:
1047                         case OBJ_CUSTOMSHAPE:
1048                         case OBJ_CIRC:
1049                         case OBJ_SECT:
1050                         case OBJ_CARC:
1051                         case OBJ_CCUT:
1052                         case OBJ_POLY:
1053                         case OBJ_PLIN:
1054                         case OBJ_PATHLINE:
1055                         case OBJ_PATHFILL:
1056                         case OBJ_FREELINE:
1057                         case OBJ_FREEFILL:
1058                         case OBJ_PATHPOLY:
1059                         case OBJ_PATHPLIN:
1060                         case OBJ_CAPTION:
1061                             nCmpId = OBJ_GRUP;
1062                             break;
1063                         default:
1064                             nCmpId = pTemp->GetObjIdentifier();
1065                         }
1066                         if(nCmpId == OBJ_GRUP /*dynamic_cast< const SdrObjGroup *>( pTemp ) !=  nullptr*/ && pTemp->GetName() == pCnt->GetName())
1067                         {
1068                             return pTemp->GetDescription();
1069                         }
1070                     }
1071                 }
1072             }
1073             break;
1074         case ContentTypeId::GRAPHIC   :
1075         case ContentTypeId::OLE       :
1076         case ContentTypeId::FRAME     :
1077             {
1078                 //Can't find the function "GetLongDescription". Need to verify again.
1079                 const SwFlyFrameFormat* pFlyFormat = m_pActiveShell->GetDoc()->FindFlyByName( pCnt->GetName());
1080                 if( pFlyFormat )
1081                     return pFlyFormat->GetDescription();
1082             }
1083             break;
1084         default: break;
1085     }
1086     return OUString();
1087 }
1088 
1089 // Drag&Drop methods
1090 
StartDrag(sal_Int8 nAction,const Point & rPosPixel)1091 void SwContentTree::StartDrag( sal_Int8 nAction, const Point& rPosPixel )
1092 {
1093     if( !m_bIsRoot || m_nRootType != ContentTypeId::OUTLINE )
1094     {
1095         ReleaseMouse();
1096 
1097         rtl::Reference<TransferDataContainer> pContainer = new TransferDataContainer;
1098 
1099         sal_Int8 nDragMode = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
1100         if( FillTransferData( *pContainer, nDragMode ))
1101         {
1102             SwContentTree::SetInDrag(true);
1103             pContainer->StartDrag( this, nDragMode, GetDragFinishedHdl() );
1104         }
1105     }
1106     else
1107     {
1108         SwWrtShell *const pShell = GetWrtShell();
1109         pShell->StartAllAction();
1110         pShell->StartUndo(SwUndoId::OUTLINE_UD);
1111         // Only move drag entry and continuous selected siblings:
1112         m_aDndOutlinesSelected.clear();
1113         SvTreeListEntry* pEntry = GetEntry(rPosPixel);
1114         // Find first selected of continuous siblings
1115         while (pEntry && IsSelected(pEntry->PrevSibling()))
1116         {
1117             pEntry = pEntry->PrevSibling();
1118         }
1119         // Record continuous selected siblings
1120         if (pEntry)
1121         {
1122             m_aDndOutlinesSelected.push_back(pEntry);
1123             while (pEntry && IsSelected(pEntry->NextSibling()))
1124             {
1125                 pEntry = pEntry->NextSibling();
1126                 m_aDndOutlinesSelected.push_back(pEntry);
1127             }
1128         }
1129         SvTreeListBox::StartDrag( nAction, rPosPixel );
1130     }
1131 }
1132 
DragFinished(sal_Int8 nAction)1133 void SwContentTree::DragFinished( sal_Int8 nAction )
1134 {
1135     if (m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE)
1136     {
1137         SwWrtShell *const pShell = GetWrtShell();
1138         pShell->EndUndo();
1139         pShell->EndAllAction();
1140         m_aActiveContentArr[ContentTypeId::OUTLINE]->Invalidate();
1141         Display(true);
1142         m_aDndOutlinesSelected.clear();
1143     }
1144 
1145     // To prevent the removing of the selected entry in external drag and drop
1146     // the drag action mustn't be MOVE.
1147     SvTreeListBox::DragFinished( m_bIsInternalDrag ? nAction : DND_ACTION_COPY );
1148     SwContentTree::SetInDrag(false);
1149     m_bIsInternalDrag = false;
1150 }
1151 
1152 // QueryDrop will be executed in the navigator
1153 
AcceptDrop(const AcceptDropEvent & rEvt)1154 sal_Int8 SwContentTree::AcceptDrop( const AcceptDropEvent& rEvt )
1155 {
1156     sal_Int8 nRet = DND_ACTION_NONE;
1157     if( m_bIsRoot )
1158     {
1159         if( m_bIsOutlineMoveable )
1160             nRet = SvTreeListBox::AcceptDrop( rEvt );
1161     }
1162     else if( !bIsInDrag )
1163         nRet = GetParentWindow()->AcceptDrop();
1164     return nRet;
1165 }
1166 
1167 // Drop will be executed in the navigator
1168 
lcl_GetOutlineKey(SwContentTree * pTree,SwOutlineContent const * pContent)1169 static void* lcl_GetOutlineKey( SwContentTree* pTree, SwOutlineContent const * pContent)
1170 {
1171     void* key = nullptr;
1172     if( pTree && pContent )
1173     {
1174         SwWrtShell* pShell = pTree->GetWrtShell();
1175         auto const nPos = pContent->GetOutlinePos();
1176 
1177         key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
1178     }
1179     return key;
1180 }
1181 
ExecuteDrop(const ExecuteDropEvent & rEvt)1182 sal_Int8 SwContentTree::ExecuteDrop( const ExecuteDropEvent& rEvt )
1183 {
1184     SvTreeListEntry* pEntry = pTargetEntry;
1185     if( pEntry && ( m_nRootType == ContentTypeId::OUTLINE ) && lcl_IsContent( pEntry ) )
1186     {
1187         assert(pEntry->GetUserData() == nullptr || dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
1188         SwOutlineContent* pOutlineContent = static_cast<SwOutlineContent*>(pEntry->GetUserData());
1189         if( pOutlineContent )
1190         {
1191             void* key = lcl_GetOutlineKey(this, pOutlineContent);
1192             if( !mOutLineNodeMap[key] )
1193             {
1194                 while( pEntry->HasChildren() )
1195                 {
1196                     SvTreeListEntry* pChildEntry = FirstChild( pEntry );
1197                     while( pChildEntry )
1198                     {
1199                         pEntry = pChildEntry;
1200                         pChildEntry = pChildEntry->NextSibling();
1201                     }
1202                 }
1203                 pTargetEntry = pEntry;
1204             }
1205         }
1206     }
1207     if( m_bIsRoot )
1208         return SvTreeListBox::ExecuteDrop( rEvt );
1209     return bIsInDrag ? DND_ACTION_NONE : GetParentWindow()->ExecuteDrop(rEvt);
1210 }
1211 
1212 // Handler for Dragging and ContextMenu
1213 
lcl_InsertExpandCollapseAllItem(SwContentTree * pContentTree,SvTreeListEntry * pEntry,PopupMenu * pPop)1214 static void lcl_InsertExpandCollapseAllItem(SwContentTree* pContentTree, SvTreeListEntry* pEntry, PopupMenu* pPop)
1215 {
1216     if(pEntry->HasChildren() || pEntry->HasChildrenOnDemand())
1217     {
1218         pPop->InsertSeparator();
1219         pPop->InsertItem(800, pContentTree->IsAllExpanded(pEntry) ? SwResId(STR_COLLAPSEALL) : SwResId(STR_EXPANDALL));
1220         pPop->SetAccelKey(800, vcl::KeyCode(KEY_MULTIPLY, false, true, false, false));
1221     }
1222 }
1223 
CreateContextMenu()1224 VclPtr<PopupMenu> SwContentTree::CreateContextMenu()
1225 {
1226     auto pPop = VclPtr<PopupMenu>::Create();
1227     VclPtrInstance<PopupMenu> pSubPop1;
1228     VclPtrInstance<PopupMenu> pSubPop2;
1229     VclPtrInstance<PopupMenu> pSubPop3;
1230     VclPtrInstance<PopupMenu> pSubPop4; // Edit
1231     bool bSubPop4 = false;
1232 
1233     for(int i = 1; i <= MAXLEVEL; ++i)
1234     {
1235         pSubPop1->InsertItem(i + 100, OUString::number(i), MenuItemBits::AUTOCHECK | MenuItemBits::RADIOCHECK);
1236     }
1237     pSubPop1->CheckItem(100 + m_nOutlineLevel);
1238     for(int i=0; i < 3; ++i)
1239     {
1240         pSubPop2->InsertItem(i + 201, m_aContextStrings[
1241                 IDX_STR_HYPERLINK + i], MenuItemBits::AUTOCHECK | MenuItemBits::RADIOCHECK);
1242     }
1243     pSubPop2->CheckItem(201 + static_cast<int>(GetParentWindow()->GetRegionDropMode()));
1244     // Insert the list of the open files
1245     sal_uInt16 nId = 301;
1246     const SwView* pActiveView = ::GetActiveView();
1247     SwView *pView = SwModule::GetFirstView();
1248     while (pView)
1249     {
1250         OUString sInsert = pView->GetDocShell()->GetTitle();
1251         if(pView == pActiveView)
1252         {
1253             sInsert += "(" +
1254                 m_aContextStrings[IDX_STR_ACTIVE] +
1255                 ")";
1256         }
1257         pSubPop3->InsertItem(nId, sInsert, MenuItemBits::AUTOCHECK | MenuItemBits::RADIOCHECK);
1258         if (State::CONSTANT == m_eState && m_pActiveShell == &pView->GetWrtShell())
1259             pSubPop3->CheckItem(nId);
1260         pView = SwModule::GetNextView(pView);
1261         nId++;
1262     }
1263     pSubPop3->InsertItem(nId++, m_aContextStrings[IDX_STR_ACTIVE_VIEW], MenuItemBits::AUTOCHECK | MenuItemBits::RADIOCHECK);
1264     if(m_pHiddenShell)
1265     {
1266         OUString sHiddenEntry = m_pHiddenShell->GetView().GetDocShell()->GetTitle() +
1267             " ( " +
1268             m_aContextStrings[IDX_STR_HIDDEN] +
1269             " )";
1270         pSubPop3->InsertItem(nId, sHiddenEntry, MenuItemBits::AUTOCHECK | MenuItemBits::RADIOCHECK);
1271     }
1272 
1273     if (State::ACTIVE == m_eState)
1274         pSubPop3->CheckItem( --nId );
1275     else if (State::HIDDEN == m_eState)
1276         pSubPop3->CheckItem( nId );
1277 
1278     pPop->InsertItem( 1, m_aContextStrings[IDX_STR_OUTLINE_LEVEL]);
1279     pPop->InsertItem(2, m_aContextStrings[IDX_STR_DRAGMODE]);
1280     pPop->InsertItem(3, m_aContextStrings[IDX_STR_DISPLAY]);
1281     // Now edit
1282     SvTreeListEntry* pEntry = nullptr;
1283     // Edit only if the shown content is coming from the current view.
1284     if ((State::ACTIVE == m_eState || m_pActiveShell == pActiveView->GetWrtShellPtr())
1285             && nullptr != (pEntry = FirstSelected()) && lcl_IsContent(pEntry))
1286     {
1287         assert(dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
1288         const SwContentType* pContType = static_cast<SwContent*>(pEntry->GetUserData())->GetParent();
1289         const ContentTypeId nContentType = pContType->GetType();
1290         bool bReadonly = m_pActiveShell->GetView().GetDocShell()->IsReadOnly();
1291         bool bVisible = !static_cast<SwContent*>(pEntry->GetUserData())->IsInvisible();
1292         bool bProtected = static_cast<SwContent*>(pEntry->GetUserData())->IsProtect();
1293         bool bEditable = pContType->IsEditable() &&
1294             ((bVisible && !bProtected) ||ContentTypeId::REGION == nContentType);
1295         bool bDeletable = pContType->IsDeletable() &&
1296             ((bVisible && !bProtected) ||ContentTypeId::REGION == nContentType);
1297         bool bRenamable = bEditable && !bReadonly &&
1298             (ContentTypeId::TABLE == nContentType ||
1299                 ContentTypeId::FRAME == nContentType ||
1300                 ContentTypeId::GRAPHIC == nContentType ||
1301                 ContentTypeId::OLE == nContentType ||
1302                 ContentTypeId::BOOKMARK == nContentType ||
1303                 ContentTypeId::REGION == nContentType||
1304                 ContentTypeId::INDEX == nContentType);
1305 
1306         if(!bReadonly && (bEditable || bDeletable))
1307         {
1308             if(ContentTypeId::INDEX == nContentType)
1309             {
1310                 bSubPop4 = true;
1311                 pSubPop4->InsertItem(401, m_sRemoveIdx);
1312                 pSubPop4->InsertItem(402, m_sUpdateIdx);
1313 
1314                 const SwTOXBase* pBase = static_cast<SwTOXBaseContent*>(pEntry->GetUserData())->GetTOXBase();
1315                 if(!pBase->IsTOXBaseInReadonly())
1316                     pSubPop4->InsertItem(403, m_aContextStrings[IDX_STR_EDIT_ENTRY]);
1317                 pSubPop4->InsertItem(405, m_sReadonlyIdx);
1318 
1319                 pSubPop4->CheckItem( 405, SwEditShell::IsTOXBaseReadonly(*pBase));
1320                 pSubPop4->InsertItem(501, m_aContextStrings[IDX_STR_DELETE_ENTRY]);
1321             }
1322             else if(ContentTypeId::TABLE == nContentType)
1323             {
1324                 bSubPop4 = true;
1325                 pSubPop4->InsertItem(403, m_aContextStrings[IDX_STR_EDIT_ENTRY]);
1326                 pSubPop4->InsertItem(404, m_sUnprotTable);
1327                 bool bFull = false;
1328                 OUString sTableName = static_cast<SwContent*>(pEntry->GetUserData())->GetName();
1329                 bool bProt = m_pActiveShell->HasTableAnyProtection( &sTableName, &bFull );
1330                 pSubPop4->EnableItem(403, !bFull );
1331                 pSubPop4->EnableItem(404, bProt );
1332                 pSubPop4->InsertItem(501, m_aContextStrings[IDX_STR_DELETE_ENTRY]);
1333             }
1334             else
1335             {
1336 
1337                 if(bEditable && bDeletable)
1338                 {
1339                     pSubPop4->InsertItem(403, m_aContextStrings[IDX_STR_EDIT_ENTRY]);
1340                     pSubPop4->InsertItem(501, m_aContextStrings[IDX_STR_DELETE_ENTRY]);
1341                     bSubPop4 = true;
1342                 }
1343                 else if(bEditable)
1344                     pPop->InsertItem(403, m_aContextStrings[IDX_STR_EDIT_ENTRY]);
1345                 else if(bDeletable)
1346                 {
1347                     pSubPop4->InsertItem(501, m_aContextStrings[IDX_STR_DELETE_ENTRY]);
1348                 }
1349             }
1350             //Rename object
1351             if(bRenamable)
1352             {
1353                 if(bSubPop4)
1354                     pSubPop4->InsertItem(502, m_sRename);
1355                 else
1356                     pPop->InsertItem(502, m_sRename);
1357             }
1358 
1359             if(bSubPop4)
1360             {
1361                 pPop->InsertItem(4, pContType->GetSingleName());
1362                 pPop->SetPopupMenu(4, pSubPop4);
1363             }
1364         }
1365         else if(ContentTypeId::OUTLINE == nContentType)
1366             lcl_InsertExpandCollapseAllItem(this, pEntry, pPop);
1367     }
1368     else if( pEntry )
1369     {
1370         assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
1371         SwContentType* pType = static_cast<SwContentType*>(pEntry->GetUserData());
1372         if(ContentTypeId::OUTLINE == pType->GetType())
1373         {
1374             lcl_InsertExpandCollapseAllItem(this, pEntry, pPop);
1375             pPop->InsertSeparator();
1376             pPop->InsertItem(700, m_aContextStrings[IDX_STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY]);
1377         }
1378         if ( (pType->GetType() == ContentTypeId::POSTIT) &&  (!m_pActiveShell->GetView().GetDocShell()->IsReadOnly()) && ( pType->GetMemberCount() > 0) )
1379         {
1380             bSubPop4 = true;
1381             pSubPop4->InsertItem(600, m_sPostItShow );
1382             pSubPop4->InsertItem(601, m_sPostItHide );
1383             pSubPop4->InsertItem(602, m_sPostItDelete );
1384             pPop->InsertItem(4, pType->GetSingleName());
1385             pPop->SetPopupMenu(4, pSubPop4);
1386         }
1387     }
1388 
1389     pPop->SetPopupMenu( 1, pSubPop1 );
1390     pPop->SetPopupMenu( 2, pSubPop2 );
1391     pPop->SetPopupMenu( 3, pSubPop3 );
1392     if (!bSubPop4)
1393         pSubPop4.disposeAndClear();
1394     return pPop;
1395 }
1396 
1397 // Indentation for outlines (and sections)
1398 
GetTabPos(SvTreeListEntry * pEntry,SvLBoxTab * pTab)1399 sal_IntPtr SwContentTree::GetTabPos( SvTreeListEntry* pEntry, SvLBoxTab* pTab)
1400 {
1401     sal_IntPtr nLevel = 0;
1402     if(lcl_IsContent(pEntry))
1403     {
1404         nLevel++;
1405         assert(pEntry->GetUserData() == nullptr || dynamic_cast<SwContent *>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
1406         SwContent* pCnt = static_cast<SwContent *>(pEntry->GetUserData());
1407         const SwContentType*    pParent;
1408         if(pCnt &&  nullptr != (pParent = pCnt->GetParent()))
1409         {
1410             if(pParent->GetType() == ContentTypeId::OUTLINE)
1411                 nLevel = nLevel + static_cast<SwOutlineContent*>(pCnt)->GetOutlineLevel();
1412             else if(pParent->GetType() == ContentTypeId::REGION)
1413                 nLevel = nLevel + static_cast<SwRegionContent*>(pCnt)->GetRegionLevel();
1414         }
1415     }
1416     return nLevel * 10 + (m_bIsRoot ? 0 : 5) + pTab->GetPos();  //determined empirically
1417 }
1418 
1419 // Content will be integrated into the Box only on demand.
1420 
RequestingChildren(SvTreeListEntry * pParent)1421 void SwContentTree::RequestingChildren( SvTreeListEntry* pParent )
1422 {
1423     // Is this a content type?
1424     if(lcl_IsContentType(pParent))
1425     {
1426         if(!pParent->HasChildren())
1427         {
1428             assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pParent->GetUserData())));
1429             SwContentType* pCntType = static_cast<SwContentType*>(pParent->GetUserData());
1430 
1431             const size_t nCount = pCntType->GetMemberCount();
1432             // Add for outline plus/minus
1433             if(pCntType->GetType() == ContentTypeId::OUTLINE)
1434             {
1435                 SvTreeListEntry* pChild = nullptr;
1436                 for(size_t i = 0; i < nCount; ++i)
1437                 {
1438                     const SwContent* pCnt = pCntType->GetMember(i);
1439                     if(pCnt)
1440                     {
1441                         const auto nLevel = static_cast<const SwOutlineContent*>(pCnt)->GetOutlineLevel();
1442                         OUString sEntry = pCnt->GetName();
1443                         if(sEntry.isEmpty())
1444                             sEntry = m_sSpace;
1445                         if(!pChild || (nLevel == 0))
1446                             pChild = InsertEntry(sEntry, pParent, false, TREELIST_APPEND,const_cast<SwContent *>(pCnt));
1447                         else
1448                         {
1449                             //back search parent.
1450                             if(static_cast<const SwOutlineContent*>(pCntType->GetMember(i-1))->GetOutlineLevel() < nLevel)
1451                                 pChild = InsertEntry(sEntry, pChild, false, TREELIST_APPEND, const_cast<SwContent *>(pCnt));
1452                             else
1453                             {
1454                                 pChild = Prev(pChild);
1455                                 assert(!pChild || lcl_IsContentType(pChild) || dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pChild->GetUserData())));
1456                                 while(pChild &&
1457                                         lcl_IsContent(pChild) &&
1458                                         (static_cast<SwOutlineContent*>(pChild->GetUserData())->GetOutlineLevel() >= nLevel)
1459                                     )
1460                                 {
1461                                     pChild = Prev(pChild);
1462                                 }
1463                                 if(pChild)
1464                                     pChild = InsertEntry(sEntry, pChild,
1465                                                 false, TREELIST_APPEND, const_cast<SwContent *>(pCnt));
1466                             }
1467                         }
1468                     }
1469                 }
1470             }
1471             else
1472             {
1473                 for(size_t i = 0; i < nCount; ++i)
1474                 {
1475                     const SwContent* pCnt = pCntType->GetMember(i);
1476                     if (pCnt)
1477                     {
1478                         OUString sEntry = pCnt->GetName();
1479                         if (sEntry.isEmpty())
1480                             sEntry = m_sSpace;
1481                         InsertEntry(sEntry, pParent, false, TREELIST_APPEND, const_cast<SwContent *>(pCnt));
1482                     }
1483                 }
1484             }
1485         }
1486     }
1487 }
1488 
GetDrawingObjectsByContent(const SwContent * pCnt)1489 SdrObject* SwContentTree::GetDrawingObjectsByContent(const SwContent *pCnt)
1490 {
1491     SdrObject *pRetObj = nullptr;
1492     switch(pCnt->GetParent()->GetType())
1493     {
1494         case ContentTypeId::DRAWOBJECT:
1495         {
1496             SdrView* pDrawView = m_pActiveShell->GetDrawView();
1497             if (pDrawView)
1498             {
1499                 SwDrawModel* pDrawModel = m_pActiveShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
1500                 SdrPage* pPage = pDrawModel->GetPage(0);
1501                 const size_t nCount = pPage->GetObjCount();
1502 
1503                 for( size_t i=0; i<nCount; ++i )
1504                 {
1505                     SdrObject* pTemp = pPage->GetObj(i);
1506                     if( pTemp->GetName() == pCnt->GetName())
1507                     {
1508                         pRetObj = pTemp;
1509                         break;
1510                     }
1511                 }
1512             }
1513             break;
1514         }
1515         default:
1516             pRetObj = nullptr;
1517     }
1518     return pRetObj;
1519 }
1520 
Expand(SvTreeListEntry * pParent)1521 bool  SwContentTree::Expand( SvTreeListEntry* pParent )
1522 {
1523     if (!(pParent->HasChildren() || pParent->HasChildrenOnDemand()))
1524         return SvTreeListBox::Expand(pParent);
1525 
1526     if (!m_bIsRoot
1527         || (lcl_IsContentType(pParent) && static_cast<SwContentType*>(pParent->GetUserData())->GetType() == ContentTypeId::OUTLINE)
1528         || (m_nRootType == ContentTypeId::OUTLINE))
1529     {
1530         if(lcl_IsContentType(pParent))
1531         {
1532             SwContentType* pCntType = static_cast<SwContentType*>(pParent->GetUserData());
1533             const sal_Int32 nOr = 1 << static_cast<int>(pCntType->GetType()); //linear -> Bitposition
1534             if (State::HIDDEN != m_eState)
1535             {
1536                 m_nActiveBlock |= nOr;
1537                 m_pConfig->SetActiveBlock(m_nActiveBlock);
1538             }
1539             else
1540                 m_nHiddenBlock |= nOr;
1541             if(pCntType->GetType() == ContentTypeId::OUTLINE)
1542             {
1543                 std::map< void*, bool > aCurrOutLineNodeMap;
1544 
1545                 SwWrtShell* pShell = GetWrtShell();
1546                 bool bBool = SvTreeListBox::Expand(pParent);
1547                 SvTreeListEntry* pChild = Next(pParent);
1548                 while(pChild && lcl_IsContent(pChild) && pParent->HasChildren())
1549                 {
1550                     if(pChild->HasChildren())
1551                     {
1552                         assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pChild->GetUserData())));
1553                         auto const nPos = static_cast<SwOutlineContent*>(pChild->GetUserData())->GetOutlinePos();
1554                         void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
1555                         aCurrOutLineNodeMap.emplace( key, false );
1556                         std::map<void*, bool>::iterator iter = mOutLineNodeMap.find( key );
1557                         if( iter != mOutLineNodeMap.end() && mOutLineNodeMap[key])
1558                         {
1559                             aCurrOutLineNodeMap[key] = true;
1560                             SvTreeListBox::Expand(pChild);
1561                         }
1562                     }
1563                     pChild = Next(pChild);
1564                 }
1565                 mOutLineNodeMap = aCurrOutLineNodeMap;
1566                 return bBool;
1567             }
1568 
1569         }
1570         else if( lcl_IsContent(pParent) && static_cast<SwContentType*>(pParent->GetUserData())->GetType() == ContentTypeId::OUTLINE)
1571         {
1572             SwWrtShell* pShell = GetWrtShell();
1573             // paranoid assert now that outline type is checked
1574             assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pParent->GetUserData())));
1575             auto const nPos = static_cast<SwOutlineContent*>(pParent->GetUserData())->GetOutlinePos();
1576             void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
1577             mOutLineNodeMap[key] = true;
1578         }
1579     }
1580     return SvTreeListBox::Expand(pParent);
1581 }
1582 
Collapse(SvTreeListEntry * pParent)1583 bool  SwContentTree::Collapse( SvTreeListEntry* pParent )
1584 {
1585     if (!m_bIsRoot
1586         || (lcl_IsContentType(pParent) && static_cast<SwContentType*>(pParent->GetUserData())->GetType() == ContentTypeId::OUTLINE)
1587         || (m_nRootType == ContentTypeId::OUTLINE))
1588     {
1589         if(lcl_IsContentType(pParent))
1590         {
1591             if(m_bIsRoot)
1592                 return false;
1593             SwContentType* pCntType = static_cast<SwContentType*>(pParent->GetUserData());
1594             const sal_Int32 nAnd = ~(1 << static_cast<int>(pCntType->GetType()));
1595             if (State::HIDDEN != m_eState)
1596             {
1597                 m_nActiveBlock &= nAnd;
1598                 m_pConfig->SetActiveBlock(m_nActiveBlock);
1599             }
1600             else
1601                 m_nHiddenBlock &= nAnd;
1602         }
1603         else if( lcl_IsContent(pParent) )
1604         {
1605             SwWrtShell* pShell = GetWrtShell();
1606             assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pParent->GetUserData())));
1607             auto const nPos = static_cast<SwOutlineContent*>(pParent->GetUserData())->GetOutlinePos();
1608             void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
1609             mOutLineNodeMap[key] = false;
1610         }
1611     }
1612 
1613     return SvTreeListBox::Collapse(pParent);
1614 }
1615 
1616 // Also on double click will be initially opened only.
1617 
IMPL_LINK_NOARG(SwContentTree,ContentDoubleClickHdl,SvTreeListBox *,bool)1618 IMPL_LINK_NOARG(SwContentTree, ContentDoubleClickHdl, SvTreeListBox*, bool)
1619 {
1620     SvTreeListEntry* pEntry = GetCurEntry();
1621     // Is it a content type?
1622     OSL_ENSURE(pEntry, "no current entry!");
1623     if(pEntry)
1624     {
1625         if(lcl_IsContentType(pEntry) && !pEntry->HasChildren())
1626         {
1627             RequestingChildren(pEntry);
1628         }
1629         else if (!lcl_IsContentType(pEntry) && (State::HIDDEN != m_eState))
1630         {
1631             if (State::CONSTANT == m_eState)
1632             {
1633                 m_pActiveShell->GetView().GetViewFrame()->GetWindow().ToTop();
1634             }
1635             //Jump to content type:
1636             assert(dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
1637             SwContent* pCnt = static_cast<SwContent*>(pEntry->GetUserData());
1638             OSL_ENSURE( pCnt, "no UserData");
1639             GotoContent(pCnt);
1640             if(pCnt->GetParent()->GetType() == ContentTypeId::FRAME)
1641                 m_pActiveShell->EnterStdMode();
1642             return false;   // treelist processing finished
1643         }
1644         return true;        // signal more to be done, i.e. expand/collapse children
1645     }
1646     return false;
1647 }
1648 
1649 namespace
1650 {
GetBitmapForContentTypeId(ContentTypeId eType)1651     BitmapEx GetBitmapForContentTypeId(ContentTypeId eType)
1652     {
1653         OUString sResId;
1654 
1655         switch (eType)
1656         {
1657             case ContentTypeId::OUTLINE:
1658                 sResId = RID_BMP_NAVI_OUTLINE;
1659                 break;
1660             case ContentTypeId::TABLE:
1661                 sResId = RID_BMP_NAVI_TABLE;
1662                 break;
1663             case ContentTypeId::FRAME:
1664                 sResId = RID_BMP_NAVI_FRAME;
1665                 break;
1666             case ContentTypeId::GRAPHIC:
1667                 sResId = RID_BMP_NAVI_GRAPHIC;
1668                 break;
1669             case ContentTypeId::OLE:
1670                 sResId = RID_BMP_NAVI_OLE;
1671                 break;
1672             case ContentTypeId::BOOKMARK:
1673                 sResId = RID_BMP_NAVI_BOOKMARK;
1674                 break;
1675             case ContentTypeId::REGION:
1676                 sResId = RID_BMP_NAVI_REGION;
1677                 break;
1678             case ContentTypeId::URLFIELD:
1679                 sResId = RID_BMP_NAVI_URLFIELD;
1680                 break;
1681             case ContentTypeId::REFERENCE:
1682                 sResId = RID_BMP_NAVI_REFERENCE;
1683                 break;
1684             case ContentTypeId::INDEX:
1685                 sResId = RID_BMP_NAVI_INDEX;
1686                 break;
1687             case ContentTypeId::POSTIT:
1688                 sResId = RID_BMP_NAVI_POSTIT;
1689                 break;
1690             case ContentTypeId::DRAWOBJECT:
1691                 sResId = RID_BMP_NAVI_DRAWOBJECT;
1692                 break;
1693             case ContentTypeId::UNKNOWN:
1694                 SAL_WARN("sw.ui", "ContentTypeId::UNKNOWN has no bitmap preview");
1695                 break;
1696         }
1697 
1698         return BitmapEx(sResId);
1699     };
1700 }
1701 
Display(bool bActive)1702 void SwContentTree::Display( bool bActive )
1703 {
1704     // First read the selected entry to select it later again if necessary
1705     // -> the user data here are no longer valid!
1706     SvTreeListEntry* pOldSelEntry = FirstSelected();
1707     OUString sEntryName;  // Name of the entry
1708     sal_uLong nEntryRelPos = 0; // relative position to their parent
1709     sal_uInt32 nOldEntryCount = GetEntryCount();
1710     sal_Int32 nOldScrollPos = 0;
1711     if(pOldSelEntry)
1712     {
1713         ScrollBar* pVScroll = GetVScroll();
1714         if(pVScroll && pVScroll->IsVisible())
1715             nOldScrollPos = pVScroll->GetThumbPos();
1716 
1717         sEntryName = GetEntryText(pOldSelEntry);
1718         SvTreeListEntry* pParantEntry = pOldSelEntry;
1719         while( GetParent(pParantEntry))
1720         {
1721             pParantEntry = GetParent(pParantEntry);
1722         }
1723         if(GetParent(pOldSelEntry))
1724         {
1725             nEntryRelPos = GetModel()->GetAbsPos(pOldSelEntry) - GetModel()->GetAbsPos(pParantEntry);
1726         }
1727     }
1728     Clear();
1729     SetUpdateMode( false );
1730     if (!bActive)
1731         m_eState = State::HIDDEN;
1732     else if (State::HIDDEN == m_eState)
1733         m_eState = State::ACTIVE;
1734     SwWrtShell* pShell = GetWrtShell();
1735     const bool bReadOnly = !pShell || pShell->GetView().GetDocShell()->IsReadOnly();
1736     if(bReadOnly != m_bIsLastReadOnly)
1737     {
1738         m_bIsLastReadOnly = bReadOnly;
1739         bool bDisable =  pShell == nullptr || bReadOnly;
1740         SwNavigationPI* pNavi = GetParentWindow();
1741         pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("up"), !bDisable);
1742         pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("down"), !bDisable);
1743         pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("promote"), !bDisable);
1744         pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("demote"), !bDisable);
1745         pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("reminder"), !bDisable);
1746     }
1747     if(pShell)
1748     {
1749         SvTreeListEntry* pSelEntry = nullptr;
1750         if(m_nRootType == ContentTypeId::UNKNOWN)
1751         {
1752             for( ContentTypeId nCntType : o3tl::enumrange<ContentTypeId>() )
1753             {
1754                 std::unique_ptr<SwContentType>& rpContentT = bActive ?
1755                                     m_aActiveContentArr[nCntType] :
1756                                     m_aHiddenContentArr[nCntType];
1757                 if(!rpContentT)
1758                     rpContentT.reset(new SwContentType(pShell, nCntType, m_nOutlineLevel ));
1759 
1760                 OUString sEntry = rpContentT->GetName();
1761                 SvTreeListEntry* pEntry;
1762                 Image aImage(GetBitmapForContentTypeId(nCntType));
1763                 bool bChOnDemand = 0 != rpContentT->GetMemberCount();
1764                 pEntry = InsertEntry(sEntry, aImage, aImage,
1765                                 nullptr, bChOnDemand, TREELIST_APPEND, rpContentT.get());
1766                 if(pEntry && !pEntry->HasChildren() && !pEntry->HasChildrenOnDemand())
1767                 {
1768                     pEntry->SetFlags(pEntry->GetFlags() | SvTLEntryFlags::SEMITRANSPARENT);
1769                     pEntry->SetTextColor(COL_GRAY);
1770                 }
1771                 if(nCntType == m_nLastSelType)
1772                     pSelEntry = pEntry;
1773                 sal_Int32 nExpandOptions = (State::HIDDEN == m_eState)
1774                                             ? m_nHiddenBlock
1775                                             : m_nActiveBlock;
1776                 if(nExpandOptions & (1 << static_cast<int>(nCntType)))
1777                 {
1778                     Expand(pEntry);
1779                     if(nEntryRelPos && nCntType == m_nLastSelType)
1780                     {
1781                         // Now maybe select an additional child
1782                         SvTreeListEntry* pChild = pEntry;
1783                         SvTreeListEntry* pTemp = nullptr;
1784                         sal_uLong nPos = 1;
1785                         while(nullptr != (pChild = Next(pChild)))
1786                         {
1787                             // The old text will be slightly favored
1788                             if(sEntryName == GetEntryText(pChild) ||
1789                                 nPos == nEntryRelPos )
1790                             {
1791                                 pSelEntry = pChild;
1792                                 break;
1793                             }
1794                             pTemp = pChild;
1795                             nPos++;
1796                         }
1797                         if(!pSelEntry || lcl_IsContentType(pSelEntry))
1798                             pSelEntry = pTemp;
1799                     }
1800 
1801                 }
1802             }
1803             if(pSelEntry)
1804             {
1805                 MakeVisible(pSelEntry);
1806                 Select(pSelEntry);
1807             }
1808             else
1809                 nOldScrollPos = 0;
1810         }
1811         else
1812         {
1813             std::unique_ptr<SwContentType>& rpRootContentT = bActive ?
1814                                     m_aActiveContentArr[m_nRootType] :
1815                                     m_aHiddenContentArr[m_nRootType];
1816             if(!rpRootContentT)
1817                 rpRootContentT.reset(new SwContentType(pShell, m_nRootType, m_nOutlineLevel ));
1818             Image aImage(GetBitmapForContentTypeId(m_nRootType));
1819             SvTreeListEntry* pParent = InsertEntry(
1820                     rpRootContentT->GetName(), aImage, aImage,
1821                         nullptr, false, TREELIST_APPEND, rpRootContentT.get());
1822 
1823             if(m_nRootType != ContentTypeId::OUTLINE)
1824             {
1825                 for(size_t i = 0; i < rpRootContentT->GetMemberCount(); ++i)
1826                 {
1827                     const SwContent* pCnt = rpRootContentT->GetMember(i);
1828                     if(pCnt)
1829                     {
1830                         OUString sEntry = pCnt->GetName();
1831                         if(sEntry.isEmpty())
1832                             sEntry = m_sSpace;
1833                         InsertEntry( sEntry, pParent,
1834                             false, TREELIST_APPEND, const_cast<SwContent *>(pCnt));
1835                     }
1836                 }
1837             }
1838             else
1839                 RequestingChildren(pParent);
1840             Expand(pParent);
1841             if (m_nRootType == ContentTypeId::OUTLINE && State::ACTIVE == m_eState)
1842             {
1843                 // find out where the cursor is
1844                 const SwOutlineNodes::size_type nActPos = pShell->GetOutlinePos(MAXLEVEL);
1845                 SvTreeListEntry* pEntry = First();
1846 
1847                 while( nullptr != (pEntry = Next(pEntry)) )
1848                 {
1849                     assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
1850                     if (static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlinePos() == nActPos)
1851                     {
1852                         MakeVisible(pEntry);
1853                         Select(pEntry);
1854                         SetCurEntry(pEntry);
1855                     }
1856                 }
1857 
1858             }
1859             else
1860             {
1861                 // Now maybe select an additional child
1862                 SvTreeListEntry* pChild = pParent;
1863                 SvTreeListEntry* pTemp = nullptr;
1864                 sal_uLong nPos = 1;
1865                 while(nullptr != (pChild = Next(pChild)))
1866                 {
1867                     // The old text will be slightly favored
1868                     if(sEntryName == GetEntryText(pChild) ||
1869                         nPos == nEntryRelPos )
1870                     {
1871                         pSelEntry = pChild;
1872                         break;
1873                     }
1874                     pTemp = pChild;
1875                     nPos++;
1876                 }
1877                 if(!pSelEntry)
1878                     pSelEntry = pTemp;
1879                 if(pSelEntry)
1880                 {
1881                     MakeVisible(pSelEntry);
1882                     Select(pSelEntry);
1883                 }
1884             }
1885         }
1886     }
1887     SetUpdateMode( true );
1888     ScrollBar* pVScroll = GetVScroll();
1889     if(GetEntryCount() == nOldEntryCount &&
1890         nOldScrollPos && pVScroll && pVScroll->IsVisible()
1891         && pVScroll->GetThumbPos() != nOldScrollPos)
1892     {
1893         sal_Int32 nDelta = pVScroll->GetThumbPos() - nOldScrollPos;
1894         ScrollOutputArea( static_cast<short>(nDelta) );
1895     }
1896 }
1897 
Clear()1898 void SwContentTree::Clear()
1899 {
1900     SetUpdateMode(false);
1901     SvTreeListBox::Clear();
1902     SetUpdateMode(true);
1903 }
1904 
FillTransferData(TransferDataContainer & rTransfer,sal_Int8 & rDragMode)1905 bool SwContentTree::FillTransferData( TransferDataContainer& rTransfer,
1906                                             sal_Int8& rDragMode )
1907 {
1908     SwWrtShell* pWrtShell = GetWrtShell();
1909     OSL_ENSURE(pWrtShell, "no Shell!");
1910     SvTreeListEntry* pEntry = GetCurEntry();
1911     if(!pEntry || lcl_IsContentType(pEntry) || !pWrtShell)
1912         return false;
1913     OUString sEntry;
1914     assert(dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
1915     SwContent* pCnt = static_cast<SwContent*>(pEntry->GetUserData());
1916 
1917     const ContentTypeId nActType = pCnt->GetParent()->GetType();
1918     OUString sUrl;
1919     bool bOutline = false;
1920     OUString sOutlineText;
1921     switch( nActType )
1922     {
1923         case ContentTypeId::OUTLINE:
1924         {
1925             const SwOutlineNodes::size_type nPos = static_cast<SwOutlineContent*>(pCnt)->GetOutlinePos();
1926             OSL_ENSURE(nPos < pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount(),
1927                        "outlinecnt changed");
1928 
1929             // make sure outline may actually be copied
1930             if( pWrtShell->IsOutlineCopyable( nPos ) )
1931             {
1932                 const SwNumRule* pOutlRule = pWrtShell->GetOutlineNumRule();
1933                 const SwTextNode* pTextNd =
1934                         pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNode(nPos);
1935                 if (pTextNd && pOutlRule && pTextNd->IsNumbered(pWrtShell->GetLayout()))
1936                 {
1937                     SwNumberTree::tNumberVector aNumVector =
1938                         pTextNd->GetNumberVector(pWrtShell->GetLayout());
1939                     for( int nLevel = 0;
1940                          nLevel <= pTextNd->GetActualListLevel();
1941                          nLevel++ )
1942                     {
1943                         const SwNumberTree::tSwNumTreeNumber nVal = aNumVector[nLevel] + 1;
1944                         sEntry += OUString::number( nVal - pOutlRule->Get(nLevel).GetStart() ) + ".";
1945                     }
1946                 }
1947                 sEntry += pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineText(nPos, pWrtShell->GetLayout(), false);
1948                 sOutlineText = pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineText(nPos, pWrtShell->GetLayout());
1949                 m_bIsOutlineMoveable = static_cast<SwOutlineContent*>(pCnt)->IsMoveable();
1950                 bOutline = true;
1951             }
1952         }
1953         break;
1954         case ContentTypeId::POSTIT:
1955         case ContentTypeId::INDEX:
1956         case ContentTypeId::REFERENCE :
1957             // cannot be inserted, neither as URL nor as section
1958         break;
1959         case ContentTypeId::URLFIELD:
1960             sUrl = static_cast<SwURLFieldContent*>(pCnt)->GetURL();
1961             [[fallthrough]];
1962         case ContentTypeId::OLE:
1963         case ContentTypeId::GRAPHIC:
1964             if(GetParentWindow()->GetRegionDropMode() != RegionMode::NONE)
1965                 break;
1966             else
1967                 rDragMode &= ~( DND_ACTION_MOVE | DND_ACTION_LINK );
1968             [[fallthrough]];
1969         default:
1970             sEntry = GetEntryText(pEntry);
1971     }
1972 
1973     bool bRet = false;
1974     if(!sEntry.isEmpty())
1975     {
1976         const SwDocShell* pDocShell = pWrtShell->GetView().GetDocShell();
1977         if(sUrl.isEmpty())
1978         {
1979             if(pDocShell->HasName())
1980             {
1981                 SfxMedium* pMedium = pDocShell->GetMedium();
1982                 sUrl = pMedium->GetURLObject().GetURLNoMark();
1983                 // only if a primarily link shall be integrated.
1984                 bRet = true;
1985             }
1986             else if ( nActType == ContentTypeId::REGION || nActType == ContentTypeId::BOOKMARK )
1987             {
1988                 // For field and bookmarks a link is also allowed
1989                 // without a filename into its own document.
1990                 bRet = true;
1991             }
1992             else if (State::CONSTANT == m_eState &&
1993                     ( !::GetActiveView() ||
1994                         m_pActiveShell != ::GetActiveView()->GetWrtShellPtr()))
1995             {
1996                 // Urls of inactive views cannot dragged without
1997                 // file names, also.
1998                 bRet = false;
1999             }
2000             else
2001             {
2002                 bRet = GetParentWindow()->GetRegionDropMode() == RegionMode::NONE;
2003                 rDragMode = DND_ACTION_MOVE;
2004             }
2005 
2006             const OUString& rToken = pCnt->GetParent()->GetTypeToken();
2007             sUrl += "#" + sEntry;
2008             if(!rToken.isEmpty())
2009             {
2010                 sUrl += OUStringChar(cMarkSeparator) + rToken;
2011             }
2012         }
2013         else
2014             bRet = true;
2015 
2016         if( bRet )
2017         {
2018             // In Outlines of heading text must match
2019             // the real number into the description.
2020             if(bOutline)
2021                 sEntry = sOutlineText;
2022 
2023             {
2024                 NaviContentBookmark aBmk( sUrl, sEntry,
2025                                     GetParentWindow()->GetRegionDropMode(),
2026                                     pDocShell);
2027                 aBmk.Copy( rTransfer );
2028             }
2029 
2030             // An INetBookmark must a be delivered to foreign DocShells
2031             if( pDocShell->HasName() )
2032             {
2033                 INetBookmark aBkmk( sUrl, sEntry );
2034                 rTransfer.CopyINetBookmark( aBkmk );
2035             }
2036         }
2037     }
2038     return bRet;
2039 }
2040 
ToggleToRoot()2041 void SwContentTree::ToggleToRoot()
2042 {
2043     if(!m_bIsRoot)
2044     {
2045         SvTreeListEntry* pEntry = GetCurEntry();
2046         const SwContentType* pCntType;
2047         if(pEntry)
2048         {
2049             if(lcl_IsContentType(pEntry))
2050             {
2051                 assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2052                 pCntType = static_cast<SwContentType*>(pEntry->GetUserData());
2053             }
2054             else
2055             {
2056                 assert(dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2057                 pCntType = static_cast<SwContent*>(pEntry->GetUserData())->GetParent();
2058             }
2059             m_nRootType = pCntType->GetType();
2060             m_bIsRoot = true;
2061             Display(State::HIDDEN != m_eState);
2062             if (m_nRootType == ContentTypeId::OUTLINE)
2063             {
2064                 SetSelectionMode(SelectionMode::Multiple);
2065                 SetDragDropMode(DragDropMode::CTRL_MOVE |
2066                     DragDropMode::CTRL_COPY |
2067                     DragDropMode::ENABLE_TOP);
2068             }
2069         }
2070     }
2071     else
2072     {
2073         SetSelectionMode(SelectionMode::Single);
2074         m_nRootType = ContentTypeId::UNKNOWN;
2075         m_bIsRoot = false;
2076         FindActiveTypeAndRemoveUserData();
2077         Display(State::HIDDEN != m_eState);
2078         if( m_bIsKeySpace )
2079         {
2080             HideFocus();
2081             ShowFocus( m_aOldRectangle);
2082             m_bIsKeySpace = false;
2083         }
2084     }
2085     m_pConfig->SetRootType( m_nRootType );
2086     VclPtr<SwNavHelpToolBox> xBox = GetParentWindow()->m_aContentToolBox;
2087     xBox->CheckItem(xBox->GetItemId("root"), m_bIsRoot);
2088 }
2089 
HasContentChanged()2090 bool SwContentTree::HasContentChanged()
2091 {
2092 
2093 //  - Run through the local array and the Treelistbox in parallel.
2094 //  - Are the records not expanded, they are discarded only in the array
2095 //    and the content type will be set as the new UserData.
2096 //  - Is the root mode is active only this will be updated.
2097 
2098 //  Valid for the displayed content types is:
2099 //  the Memberlist will be erased and the membercount will be updated
2100 //  If content will be checked, the memberlists will be replenished
2101 //  at the same time. Once a difference occurs it will be only replenished
2102 //  no longer checked. Finally, the box is filled again.
2103 
2104     bool bRepaint = false;
2105     bool bInvalidate = false;
2106 
2107     if (State::HIDDEN == m_eState)
2108     {
2109         for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
2110         {
2111             if(m_aActiveContentArr[i])
2112                 m_aActiveContentArr[i]->Invalidate();
2113         }
2114     }
2115     else if(m_bIsRoot)
2116     {
2117         bool bOutline = false;
2118         SvTreeListEntry* pEntry = First();
2119         if(!pEntry)
2120             bRepaint = true;
2121         else
2122         {
2123             assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2124             const ContentTypeId nType = static_cast<SwContentType*>(pEntry->GetUserData())->GetType();
2125             bOutline = m_nRootType == ContentTypeId::OUTLINE;
2126             SwContentType* pArrType = m_aActiveContentArr[nType].get();
2127             if(!pArrType)
2128                 bRepaint = true;
2129             else
2130             {
2131                 SvTreeListEntry* pFirstSel;
2132                 if(bOutline && !HasFocus() &&
2133                         nullptr != ( pFirstSel = FirstSelected()) &&
2134                             lcl_IsContent(pFirstSel))
2135                 {
2136                     assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pFirstSel->GetUserData())));
2137                     const auto nSelLevel =
2138                         static_cast<SwOutlineContent*>(pFirstSel->GetUserData())->GetOutlineLevel();
2139                     SwWrtShell* pSh = GetWrtShell();
2140                     const SwOutlineNodes::size_type nOutlinePos = pSh->GetOutlinePos(MAXLEVEL);
2141                     if (nOutlinePos != SwOutlineNodes::npos &&
2142                         pSh->getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos) != nSelLevel)
2143                         bRepaint = true;
2144                 }
2145 
2146                 pArrType->Init(&bInvalidate);
2147                 pArrType->FillMemberList();
2148                 pEntry->SetUserData(static_cast<void*>(pArrType));
2149                 if(!bRepaint)
2150                 {
2151                     if(GetChildCount(pEntry) != pArrType->GetMemberCount())
2152                             bRepaint = true;
2153                     else
2154                     {
2155                         const size_t nChildCount = GetChildCount(pEntry);
2156                         for(size_t j = 0; j < nChildCount; ++j)
2157                         {
2158                             pEntry = Next(pEntry);
2159                             assert(pEntry);
2160                             const SwContent* pCnt = pArrType->GetMember(j);
2161                             pEntry->SetUserData(const_cast<SwContent *>(pCnt));
2162                             OUString sEntryText = GetEntryText(pEntry);
2163                             if( sEntryText != pCnt->GetName() &&
2164                                 !(sEntryText == m_sSpace && pCnt->GetName().isEmpty()))
2165                                 bRepaint = true;
2166                         }
2167                     }
2168                 }
2169             }
2170         }
2171         if( !bRepaint && bOutline && !HasFocus() )
2172         {
2173             // find out where the cursor is
2174             const SwOutlineNodes::size_type nActPos = GetWrtShell()->GetOutlinePos(MAXLEVEL);
2175             SvTreeListEntry* pFirstEntry = First();
2176 
2177             while( nullptr != (pFirstEntry = Next(pFirstEntry)) )
2178             {
2179                 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pFirstEntry->GetUserData())));
2180                 if (static_cast<SwOutlineContent*>(pFirstEntry->GetUserData())->GetOutlinePos() == nActPos)
2181                 {
2182                     if(FirstSelected() != pFirstEntry)
2183                     {
2184                         Select(pFirstEntry);
2185                         MakeVisible(pFirstEntry);
2186                     }
2187                 }
2188                 else if (IsSelected(pFirstEntry))
2189                 {
2190                     SvTreeListBox::SelectListEntry(pFirstEntry, false);
2191                     bInvalidate = true;
2192                 }
2193             }
2194 
2195         }
2196 
2197     }
2198     else
2199     {
2200         SvTreeListEntry* pEntry = First();
2201         while ( pEntry )
2202         {
2203             bool bNext = true; // at least a next must be
2204             assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2205             SwContentType* pTreeType = static_cast<SwContentType*>(pEntry->GetUserData());
2206             const size_t nTreeCount = pTreeType->GetMemberCount();
2207             const ContentTypeId nType = pTreeType->GetType();
2208             SwContentType* pArrType = m_aActiveContentArr[nType].get();
2209             if(!pArrType)
2210                 bRepaint = true;
2211             else
2212             {
2213                 pArrType->Init(&bInvalidate);
2214                 pEntry->SetUserData(static_cast<void*>(pArrType));
2215                 if(IsExpanded(pEntry))
2216                 {
2217                     bool bLevelOrVisibiblityChanged = false;
2218                     // bLevelOrVisibiblityChanged is set if outlines have changed their level
2219                     // or if the visibility of objects (frames, sections, tables) has changed
2220                     // i.e. in header/footer
2221                     pArrType->FillMemberList(&bLevelOrVisibiblityChanged);
2222                     const size_t nChildCount = GetChildCount(pEntry);
2223                     if((nType == ContentTypeId::OUTLINE) && bLevelOrVisibiblityChanged)
2224                         bRepaint = true;
2225                     if(bLevelOrVisibiblityChanged)
2226                         bInvalidate = true;
2227 
2228                     if(nChildCount != pArrType->GetMemberCount())
2229                         bRepaint = true;
2230                     else
2231                     {
2232                         for(size_t j = 0; j < nChildCount; ++j)
2233                         {
2234                             pEntry = Next(pEntry);
2235                             assert(pEntry);
2236                             bNext = false;
2237                             const SwContent* pCnt = pArrType->GetMember(j);
2238                             pEntry->SetUserData(const_cast<SwContent *>(pCnt));
2239                             OUString sEntryText = GetEntryText(pEntry);
2240                             if( sEntryText != pCnt->GetName() &&
2241                                 !(sEntryText == m_sSpace && pCnt->GetName().isEmpty()))
2242                                 bRepaint = true;
2243                         }
2244                     }
2245 
2246                 }
2247                 else if(pEntry->HasChildren())
2248                 {
2249                     // was the entry once opened, then must also the
2250                     // invisible records be examined.
2251                     // At least the user data must be updated.
2252                     bool bLevelOrVisibiblityChanged = false;
2253                     // bLevelOrVisibiblityChanged is set if outlines have changed their level
2254                     // or if the visibility of objects (frames, sections, tables) has changed
2255                     // i.e. in header/footer
2256                     pArrType->FillMemberList(&bLevelOrVisibiblityChanged);
2257                     bool bRemoveChildren = false;
2258                     const size_t nChildCount = GetChildCount(pEntry);
2259                     if( nChildCount != pArrType->GetMemberCount() )
2260                     {
2261                         bRemoveChildren = true;
2262                     }
2263                     else
2264                     {
2265                         SvTreeListEntry* pChild = FirstChild(pEntry);
2266                         for(size_t j = 0; j < nChildCount; ++j)
2267                         {
2268                             const SwContent* pCnt = pArrType->GetMember(j);
2269                             assert(pChild);
2270                             pChild->SetUserData(const_cast<SwContent *>(pCnt));
2271                             OUString sEntryText = GetEntryText(pChild);
2272                             if( sEntryText != pCnt->GetName() &&
2273                                 !(sEntryText == m_sSpace && pCnt->GetName().isEmpty()))
2274                                 bRemoveChildren = true;
2275                             pChild = Next(pChild);
2276                         }
2277                     }
2278                     if(bRemoveChildren)
2279                     {
2280                         while (SvTreeListEntry *const pRemove = FirstChild(pEntry))
2281                             RemoveEntry(pRemove);
2282                     }
2283                     if(!nChildCount)
2284                     {
2285                         pEntry->EnableChildrenOnDemand(false);
2286                         InvalidateEntry(pEntry);
2287                     }
2288 
2289                 }
2290                 else if((nTreeCount != 0)
2291                             != (pArrType->GetMemberCount()!=0))
2292                 {
2293                     bRepaint = true;
2294                 }
2295             }
2296             // The Root-Entry has to be found now
2297             while( pEntry && (bNext || GetParent(pEntry ) ))
2298             {
2299                 pEntry = Next(pEntry);
2300                 bNext = false;
2301             }
2302         }
2303     }
2304     if(!bRepaint && bInvalidate)
2305         Invalidate();
2306     return bRepaint;
2307 }
2308 
FindActiveTypeAndRemoveUserData()2309 void SwContentTree::FindActiveTypeAndRemoveUserData()
2310 {
2311     SvTreeListEntry* pEntry = FirstSelected();
2312     if(pEntry)
2313     {
2314         // If clear is called by TimerUpdate:
2315         // Only for root can the validity of the UserData be guaranteed.
2316         SvTreeListEntry* pParent;
2317         while(nullptr != (pParent = GetParent(pEntry)))
2318             pEntry = pParent;
2319         if(pEntry->GetUserData() && lcl_IsContentType(pEntry))
2320         {
2321             assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2322             m_nLastSelType = static_cast<SwContentType*>(pEntry->GetUserData())->GetType();
2323         }
2324     }
2325     pEntry = First();
2326     while(pEntry)
2327     {
2328         pEntry->SetUserData(nullptr);
2329         pEntry = Next(pEntry);
2330     }
2331 }
2332 
SetHiddenShell(SwWrtShell * pSh)2333 void SwContentTree::SetHiddenShell(SwWrtShell* pSh)
2334 {
2335     m_pHiddenShell = pSh;
2336     m_eState = State::HIDDEN;
2337     FindActiveTypeAndRemoveUserData();
2338     for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
2339     {
2340         m_aHiddenContentArr[i].reset();
2341     }
2342     Display(false);
2343 
2344     GetParentWindow()->UpdateListBox();
2345 }
2346 
SetActiveShell(SwWrtShell * pSh)2347 void SwContentTree::SetActiveShell(SwWrtShell* pSh)
2348 {
2349     if(m_bIsInternalDrag)
2350         m_bDocChgdInDragging = true;
2351     bool bClear = m_pActiveShell != pSh;
2352     if (State::ACTIVE == m_eState && bClear)
2353     {
2354         if (m_pActiveShell)
2355             EndListening(*m_pActiveShell->GetView().GetDocShell());
2356         m_pActiveShell = pSh;
2357         FindActiveTypeAndRemoveUserData();
2358         Clear();
2359     }
2360     else if (State::CONSTANT == m_eState)
2361     {
2362         if (m_pActiveShell)
2363             EndListening(*m_pActiveShell->GetView().GetDocShell());
2364         m_pActiveShell = pSh;
2365         m_eState = State::ACTIVE;
2366         bClear = true;
2367     }
2368     // Only if it is the active view, the array will be deleted and
2369     // the screen filled new.
2370     if (State::ACTIVE == m_eState && bClear)
2371     {
2372         if (m_pActiveShell)
2373             StartListening(*m_pActiveShell->GetView().GetDocShell());
2374         FindActiveTypeAndRemoveUserData();
2375         for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
2376         {
2377             m_aActiveContentArr[i].reset();
2378         }
2379         Display(true);
2380     }
2381 }
2382 
SetConstantShell(SwWrtShell * pSh)2383 void SwContentTree::SetConstantShell(SwWrtShell* pSh)
2384 {
2385     if (m_pActiveShell)
2386         EndListening(*m_pActiveShell->GetView().GetDocShell());
2387     m_pActiveShell = pSh;
2388     m_eState = State::CONSTANT;
2389     StartListening(*m_pActiveShell->GetView().GetDocShell());
2390     FindActiveTypeAndRemoveUserData();
2391     for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
2392     {
2393         m_aActiveContentArr[i].reset();
2394     }
2395     Display(true);
2396 }
2397 
2398 
Notify(SfxBroadcaster & rBC,SfxHint const & rHint)2399 void SwContentTree::Notify(SfxBroadcaster & rBC, SfxHint const& rHint)
2400 {
2401     SfxViewEventHint const*const pVEHint(dynamic_cast<SfxViewEventHint const*>(&rHint));
2402     SwXTextView* pDyingShell = nullptr;
2403     if (m_pActiveShell && pVEHint && pVEHint->GetEventName() == "OnViewClosed")
2404         pDyingShell = dynamic_cast<SwXTextView*>(pVEHint->GetController().get());
2405     if (pDyingShell && pDyingShell->GetView() == &m_pActiveShell->GetView())
2406     {
2407         SetActiveShell(nullptr); // our view is dying, clear our pointers to it
2408     }
2409     else
2410     {
2411         SfxListener::Notify(rBC, rHint);
2412     }
2413     switch (rHint.GetId())
2414     {
2415         case SfxHintId::DocChanged:
2416             if (!(m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE && HasFocus()))
2417             {
2418                 m_bViewHasChanged = true;
2419             }
2420             break;
2421         case SfxHintId::ModeChanged:
2422             if (SwWrtShell* pShell = GetWrtShell())
2423             {
2424                 const bool bReadOnly = pShell->GetView().GetDocShell()->IsReadOnly();
2425                 if (bReadOnly != m_bIsLastReadOnly)
2426                 {
2427                     m_bIsLastReadOnly = bReadOnly;
2428                     Select(GetCurEntry());
2429                 }
2430             }
2431             break;
2432         default:
2433             break;
2434     }
2435 }
2436 
2437 
2438 
ExecCommand(const OUString & rCmd,bool bOutlineWithChildren)2439 void SwContentTree::ExecCommand(const OUString& rCmd, bool bOutlineWithChildren)
2440 {
2441     const bool bUp = rCmd == "up";
2442     const bool bUpDown = bUp || rCmd == "down";
2443     const bool bLeft = rCmd == "promote";
2444     const bool bLeftRight = bLeft || rCmd == "demote";
2445     if (!bUpDown && !bLeftRight)
2446         return;
2447     if (GetWrtShell()->GetView().GetDocShell()->IsReadOnly() ||
2448         (State::ACTIVE != m_eState &&
2449          (State::CONSTANT != m_eState || m_pActiveShell != GetParentWindow()->GetCreateView()->GetWrtShellPtr())))
2450     {
2451         return;
2452     }
2453 
2454     SwWrtShell *const pShell = GetWrtShell();
2455     sal_Int8 nActOutlineLevel = m_nOutlineLevel;
2456     SwOutlineNodes::size_type nActPos = pShell->GetOutlinePos(nActOutlineLevel);
2457 
2458     std::vector<SwTextNode*> selectedOutlineNodes;
2459     std::vector<SvTreeListEntry*> selected;
2460     for (SvTreeListEntry * pEntry = FirstSelected(); pEntry; pEntry = NextSelected(pEntry))
2461     {
2462         // it's possible to select the root node too which is a really bad idea
2463         bool bSkip = lcl_IsContentType(pEntry);
2464         // filter out children of selected parents so they don't get promoted
2465         // or moved twice (except if there is Ctrl modifier, since in that
2466         // case children are re-parented)
2467         if ((bLeftRight || bOutlineWithChildren) && !selected.empty())
2468         {
2469             for (auto pParent = GetParent(pEntry); pParent; pParent = GetParent(pParent))
2470             {
2471                 if (selected.back() == pParent)
2472                 {
2473                     bSkip = true;
2474                     break;
2475                 }
2476             }
2477         }
2478         if (!bSkip)
2479         {
2480             selected.push_back(pEntry);
2481             const SwNodes& rNodes = pShell->GetNodes();
2482             const sal_uLong nPos = GetAbsPos(pEntry) - 1;
2483             if (nPos < rNodes.GetOutLineNds().size())
2484             {
2485                 SwNode* pNode = rNodes.GetOutLineNds()[ nPos ];
2486                 if (pNode)
2487                 {
2488                     selectedOutlineNodes.push_back(pNode->GetTextNode());
2489                 }
2490             }
2491         }
2492     }
2493     if (bUpDown && !bUp)
2494     {   // to move down, start at the end!
2495         std::reverse(selected.begin(), selected.end());
2496     }
2497 
2498     SwOutlineNodes::difference_type nDirLast = bUp ? -1 : 1;
2499     bool bStartedAction = false;
2500     for (auto const pCurrentEntry : selected)
2501     {
2502         assert(pCurrentEntry && lcl_IsContent(pCurrentEntry));
2503         if (lcl_IsContent(pCurrentEntry))
2504         {
2505             assert(dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pCurrentEntry->GetUserData())));
2506             if ((m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE) ||
2507                 static_cast<SwContent*>(pCurrentEntry->GetUserData())->GetParent()->GetType()
2508                                             ==  ContentTypeId::OUTLINE)
2509             {
2510                 nActPos = static_cast<SwOutlineContent*>(pCurrentEntry->GetUserData())->GetOutlinePos();
2511             }
2512         }
2513         if (nActPos == SwOutlineNodes::npos || (bUpDown && !pShell->IsOutlineMovable(nActPos)))
2514         {
2515             continue;
2516         }
2517 
2518         if (!bStartedAction)
2519         {
2520             pShell->StartAllAction();
2521             pShell->StartUndo(bLeftRight ? SwUndoId::OUTLINE_LR : SwUndoId::OUTLINE_UD);
2522             bStartedAction = true;
2523         }
2524         pShell->GotoOutline( nActPos); // If text selection != box selection
2525         pShell->Push();
2526         pShell->MakeOutlineSel(nActPos, nActPos, bOutlineWithChildren);
2527         if (bUpDown)
2528         {
2529             sal_uLong const nEntryAbsPos(GetModel()->GetAbsPos(pCurrentEntry));
2530             SwOutlineNodes::difference_type nDir = bUp ? -1 : 1;
2531             if (!bOutlineWithChildren && ((nDir == -1 && nActPos > 0) ||
2532                        (nDir == 1 && nEntryAbsPos < GetEntryCount() - 2)))
2533             {
2534                 pShell->MoveOutlinePara( nDir );
2535                 // Set cursor back to the current position
2536                 pShell->GotoOutline( nActPos + nDir);
2537             }
2538             else if (bOutlineWithChildren)
2539             {
2540                 SwOutlineNodes::size_type nActEndPos = nActPos;
2541                 SvTreeListEntry* pEntry = pCurrentEntry;
2542                 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pCurrentEntry->GetUserData())));
2543                 const auto nActLevel = static_cast<SwOutlineContent*>(
2544                         pCurrentEntry->GetUserData())->GetOutlineLevel();
2545                 pEntry = Next(pEntry);
2546                 while (pEntry && lcl_IsContent(pEntry))
2547                 {
2548                     assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2549                     if (nActLevel >= static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlineLevel())
2550                         break;
2551                     nActEndPos = static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlinePos();
2552                     pEntry = Next(pEntry);
2553                 }
2554                 if (nDir == 1) // move down
2555                 {
2556                     if (IsSelected(pCurrentEntry->NextSibling()))
2557                         nDir = nDirLast;
2558                     else
2559                     {
2560                     // If the last entry is to be moved we're done
2561                     if (pEntry && lcl_IsContent(pEntry))
2562                     {
2563                         // pEntry now points to the entry following the last
2564                         // selected entry.
2565                         SwOutlineNodes::size_type nDest = static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlinePos();
2566                         // here needs to found the next entry after next.
2567                         // The selection must be inserted in front of that.
2568                         while (pEntry)
2569                         {
2570                             pEntry = Next(pEntry);
2571                             assert(pEntry == nullptr || !lcl_IsContent(pEntry) || dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2572                             // nDest++ may only executed if pEntry != 0
2573                             if (pEntry)
2574                             {
2575                                 if (!lcl_IsContent(pEntry))
2576                                     break;
2577                                 else if (nActLevel >= static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlineLevel())
2578                                 {
2579                                     // nDest needs adjusted if there are selected entries (including ancestral lineage)
2580                                     // immediately before the current moved entry.
2581                                     SvTreeListEntry* pTmp = Prev(pEntry);
2582                                     while (pTmp && lcl_IsContent(pTmp) &&
2583                                            nActLevel < static_cast<SwOutlineContent*>(pTmp->GetUserData())->GetOutlineLevel())
2584                                     {
2585                                         while (pTmp && lcl_IsContent(pTmp) && !IsSelected(pTmp) &&
2586                                                nActLevel < static_cast<SwOutlineContent*>(pTmp->GetUserData())->GetOutlineLevel())
2587                                         {
2588                                             pTmp = GetParent(pTmp);
2589                                         }
2590                                         if (!IsSelected(pTmp))
2591                                             break;
2592                                         pTmp = Prev(pTmp);
2593                                         nDest = static_cast<SwOutlineContent*>(pTmp->GetUserData())->GetOutlinePos();
2594                                     }
2595                                     if (!IsSelected(pEntry->PrevSibling()))
2596                                         break;
2597                                 }
2598                                 else
2599                                 {
2600                                     nDest = static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlinePos();
2601                                 }
2602                             }
2603                         }
2604                         nDirLast = nDir = nDest - nActEndPos;
2605                         // If no entry was found that allows insertion before
2606                         // it, we just move it to the end.
2607                     }
2608                     else
2609                         nDirLast = nDir = 0;
2610                     }
2611                 }
2612                 else // move up
2613                 {
2614                     if (IsSelected(pCurrentEntry->PrevSibling()))
2615                         nDir = nDirLast;
2616                     else
2617                     {
2618                         SwOutlineNodes::size_type nDest = nActPos;
2619                         pEntry = pCurrentEntry;
2620                         while (pEntry && nDest)
2621                         {
2622                             pEntry = Prev(pEntry);
2623                             assert(pEntry == nullptr || !lcl_IsContent(pEntry) || dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2624                             if (pEntry && lcl_IsContent(pEntry))
2625                             {
2626                                 nDest = static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlinePos();
2627                             }
2628                             else
2629                             {
2630                                 nDest = 0; // presumably?
2631                             }
2632                             if (pEntry)
2633                             {
2634                                 if (!lcl_IsContent(pEntry))
2635                                     break;
2636                                 else if (nActLevel >= static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlineLevel())
2637                                 {
2638                                     // nDest needs adjusted if there are selected entries immediately
2639                                     // after the level change.
2640                                     SvTreeListEntry* pTmp = Next(pEntry);
2641                                     while (pTmp && lcl_IsContent(pTmp) &&
2642                                            nActLevel < static_cast<SwOutlineContent*>(pTmp->GetUserData())->GetOutlineLevel() &&
2643                                            IsSelected(pTmp))
2644                                     {
2645                                         nDest = static_cast<SwOutlineContent*>(pTmp->GetUserData())->GetOutlinePos();
2646                                         const auto nLevel = static_cast<SwOutlineContent*>(pTmp->GetUserData())->GetOutlineLevel();
2647                                         // account for selected entries' descendent lineage
2648                                         pTmp = Next(pTmp);
2649                                         while (pTmp && lcl_IsContent(pTmp) &&
2650                                                nLevel < static_cast<SwOutlineContent*>(pTmp->GetUserData())->GetOutlineLevel())
2651                                         {
2652                                             nDest = static_cast<SwOutlineContent*>(pTmp->GetUserData())->GetOutlinePos();
2653                                             pTmp = Next(pTmp);
2654                                         }
2655                                     }
2656                                     break;
2657                                 }
2658                             }
2659                         }
2660                         nDirLast = nDir = nDest - nActPos;
2661                     }
2662                 }
2663                 if (nDir)
2664                 {
2665                     pShell->MoveOutlinePara( nDir );
2666                     // Set cursor back to the current position
2667                     pShell->GotoOutline(nActPos + nDir);
2668                 }
2669             }
2670         }
2671         else
2672         {
2673             if (!pShell->IsProtectedOutlinePara())
2674                 pShell->OutlineUpDown(bLeft ? -1 : 1);
2675         }
2676 
2677         pShell->ClearMark();
2678         pShell->Pop(SwCursorShell::PopMode::DeleteCurrent); // Cursor is now back at the current heading.
2679     }
2680 
2681     if (bStartedAction)
2682     {
2683         pShell->EndUndo();
2684         pShell->EndAllAction();
2685         if (m_aActiveContentArr[ContentTypeId::OUTLINE])
2686             m_aActiveContentArr[ContentTypeId::OUTLINE]->Invalidate();
2687         Display(true);
2688         if (!m_bIsRoot)
2689         {
2690             const SwOutlineNodes::size_type nCurrPos = pShell->GetOutlinePos(MAXLEVEL);
2691             SvTreeListEntry* pFirst = First();
2692 
2693             while (nullptr != (pFirst = Next(pFirst)) && lcl_IsContent(pFirst))
2694             {
2695                 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pFirst->GetUserData())));
2696                 if (static_cast<SwOutlineContent*>(pFirst->GetUserData())->GetOutlinePos() == nCurrPos)
2697                 {
2698                     Select(pFirst);
2699                     MakeVisible(pFirst);
2700                 }
2701             }
2702         }
2703         else
2704         {
2705             // Reselect entries
2706             const SwOutlineNodes& rOutLineNds = pShell->GetNodes().GetOutLineNds();
2707             for (SwTextNode* pNode : selectedOutlineNodes)
2708             {
2709                 SwOutlineNodes::const_iterator aFndIt = rOutLineNds.find(pNode);
2710                 if(aFndIt == rOutLineNds.end())
2711                     continue;
2712                 const size_t nFndPos = aFndIt - rOutLineNds.begin();
2713                 SvTreeListEntry* pEntry = GetEntryAtAbsPos(nFndPos + 1);
2714                 if (pEntry)
2715                 {
2716                     SvTreeListBox::SelectListEntry(pEntry, true);
2717                     if (!IsExpanded(pEntry->GetParent()))
2718                         Expand(pEntry->GetParent());
2719                 }
2720             }
2721             SvTreeListBox::Invalidate();
2722         }
2723     }
2724 }
2725 
ShowTree()2726 void SwContentTree::ShowTree()
2727 {
2728     SvTreeListBox::Show();
2729 }
2730 
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle & rRect)2731 void SwContentTree::Paint( vcl::RenderContext& rRenderContext,
2732                            const tools::Rectangle& rRect )
2733 {
2734     // Start the update timer on the first paint; avoids
2735     // flicker on the first reveal.
2736     m_aUpdTimer.Start();
2737     SvTreeListBox::Paint( rRenderContext, rRect );
2738 }
2739 
HideTree()2740 void SwContentTree::HideTree()
2741 {
2742     m_aUpdTimer.Stop();
2743     SvTreeListBox::Hide();
2744 }
2745 
2746 /** No idle with focus or while dragging */
IMPL_LINK_NOARG(SwContentTree,TimerUpdate,Timer *,void)2747 IMPL_LINK_NOARG(SwContentTree, TimerUpdate, Timer *, void)
2748 {
2749     if (IsDisposed())
2750         return;
2751 
2752     // No update while focus is not in document.
2753     // No update while drag and drop.
2754     // Query view because the Navigator is cleared too late.
2755     SwView* pView = GetParentWindow()->GetCreateView();
2756 
2757     if(pView && pView->GetWrtShellPtr() &&
2758             ((pView->GetWrtShellPtr()->GetWin() == GetFocusedWindow()) || m_bViewHasChanged) &&
2759             !bIsInDrag && !m_bIsInternalDrag && !pView->GetWrtShellPtr()->ActionPend())
2760     {
2761         m_bViewHasChanged = false;
2762         m_bIsIdleClear = false;
2763         SwWrtShell* pActShell = pView->GetWrtShellPtr();
2764         if (State::CONSTANT == m_eState && !lcl_FindShell(m_pActiveShell))
2765         {
2766             SetActiveShell(pActShell);
2767             GetParentWindow()->UpdateListBox();
2768         }
2769 
2770         if (State::ACTIVE == m_eState && pActShell != GetWrtShell())
2771         {
2772             SetActiveShell(pActShell);
2773         }
2774         else if ((State::ACTIVE == m_eState || (State::CONSTANT == m_eState && pActShell == GetWrtShell())) &&
2775                     HasContentChanged())
2776         {
2777             FindActiveTypeAndRemoveUserData();
2778             Display(true);
2779         }
2780     }
2781     else if (!pView && State::ACTIVE == m_eState && !m_bIsIdleClear)
2782     {
2783         if(m_pActiveShell)
2784         {
2785             SetActiveShell(nullptr);
2786         }
2787         Clear();
2788         m_bIsIdleClear = true;
2789     }
2790 }
2791 
NotifyStartDrag(TransferDataContainer & rContainer,SvTreeListEntry * pEntry)2792 DragDropMode SwContentTree::NotifyStartDrag(
2793                 TransferDataContainer& rContainer,
2794                 SvTreeListEntry* pEntry )
2795 {
2796     DragDropMode eMode = DragDropMode(0);
2797     if (State::ACTIVE == m_eState && m_nRootType == ContentTypeId::OUTLINE &&
2798             GetModel()->GetAbsPos( pEntry ) > 0
2799             && !GetWrtShell()->GetView().GetDocShell()->IsReadOnly())
2800     {
2801         eMode = GetDragDropMode();
2802         if (m_bIsRoot)
2803         {
2804             // Restore selection for multiple selected outlines.
2805             for (const auto pSelected : m_aDndOutlinesSelected)
2806                 SelectListEntry(pSelected, true);
2807         }
2808     }
2809     else if (State::ACTIVE != m_eState && GetWrtShell()->GetView().GetDocShell()->HasName())
2810         eMode = DragDropMode::APP_COPY;
2811 
2812     sal_Int8 nDragMode;
2813     FillTransferData( rContainer, nDragMode );
2814     m_bDocChgdInDragging = false;
2815     m_bIsInternalDrag = true;
2816     return eMode;
2817 }
2818 // After the drag the current paragraph will be moved  w i t h  the children.
2819 
NotifyMoving(SvTreeListEntry * pTarget,SvTreeListEntry * pEntry,SvTreeListEntry * &,sal_uLong &)2820 TriState SwContentTree::NotifyMoving( SvTreeListEntry*  pTarget,
2821         SvTreeListEntry*  pEntry, SvTreeListEntry*& , sal_uLong& )
2822 {
2823     static SwOutlineNodes::size_type nStaticSourcePos = SwOutlineNodes::npos;
2824     static SwOutlineNodes::size_type nStaticTargetPosOrOffset = SwOutlineNodes::npos;
2825     if(!m_bDocChgdInDragging)
2826     {
2827         SwOutlineNodes::size_type nTargetPos = 0;
2828         assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2829         SwOutlineNodes::size_type nSourcePos = static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlinePos();
2830         if(!lcl_IsContent(pTarget))
2831             nTargetPos = SwOutlineNodes::npos;
2832         else
2833         {
2834             assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pTarget->GetUserData())));
2835             nTargetPos = static_cast<SwOutlineContent*>(pTarget->GetUserData())->GetOutlinePos();
2836         }
2837         if( MAXLEVEL > m_nOutlineLevel && // Not all layers are displayed.
2838                         nTargetPos != SwOutlineNodes::npos)
2839         {
2840             SvTreeListEntry* pNext = Next(pTarget);
2841             if(pNext)
2842             {
2843                 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pNext->GetUserData())));
2844                 nTargetPos = static_cast<SwOutlineContent*>(pNext->GetUserData())->GetOutlinePos() - 1;
2845             }
2846             else
2847                 nTargetPos = GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineNodesCount() - 1;
2848         }
2849 
2850         OSL_ENSURE( pEntry &&
2851             lcl_IsContent(pEntry),"Source == 0 or Source has no Content" );
2852 
2853         if (nStaticTargetPosOrOffset != SwOutlineNodes::npos)
2854         {
2855             if (nTargetPos == SwOutlineNodes::npos || nSourcePos > nTargetPos)
2856             {
2857                 // Move up
2858                 nTargetPos = nSourcePos - nStaticTargetPosOrOffset;
2859             }
2860             else if (nSourcePos < nTargetPos)
2861             {
2862                 // Move down
2863                 nSourcePos = nStaticSourcePos;
2864                 nTargetPos = nStaticTargetPosOrOffset;
2865             }
2866         }
2867         // Done on the first selection move
2868         if (nTargetPos == SwOutlineNodes::npos || (nStaticTargetPosOrOffset == SwOutlineNodes::npos && nSourcePos > nTargetPos)) // only do once
2869         {
2870             // Up moves
2871             // The first up move sets the up move amount for the remaining selected outlines to be moved
2872             if (nTargetPos != SwOutlineNodes::npos)
2873                 nStaticTargetPosOrOffset = nSourcePos - nTargetPos;
2874             else
2875                 nStaticTargetPosOrOffset = nSourcePos + 1;
2876         }
2877         else if (nStaticTargetPosOrOffset == SwOutlineNodes::npos && nSourcePos < nTargetPos)
2878         {
2879             // Down moves
2880             // The first down move sets the source and target positions for the remaining selected outlines to be moved
2881             nStaticSourcePos = nSourcePos;
2882             nStaticTargetPosOrOffset = nTargetPos;
2883         }
2884         // Done on the last selection move
2885         if (!IsSelected(pEntry->NextSibling()))
2886             nStaticTargetPosOrOffset = SwOutlineNodes::npos;
2887 
2888         GetParentWindow()->MoveOutline( nSourcePos,
2889                                     nTargetPos,
2890                                     true);
2891     }
2892     //TreeListBox will be reloaded from the document
2893     return TRISTATE_FALSE;
2894 }
2895 
2896 // After the drag the current paragraph will be moved  w i t h o u t  the children.
2897 
NotifyCopying(SvTreeListEntry * pTarget,SvTreeListEntry * pEntry,SvTreeListEntry * &,sal_uLong &)2898 TriState SwContentTree::NotifyCopying( SvTreeListEntry*  pTarget,
2899         SvTreeListEntry*  pEntry, SvTreeListEntry*& , sal_uLong& )
2900 {
2901     if(!m_bDocChgdInDragging)
2902     {
2903         SwOutlineNodes::size_type nTargetPos = 0;
2904         assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2905         SwOutlineNodes::size_type nSourcePos = static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlinePos();
2906         if(!lcl_IsContent(pTarget))
2907             nTargetPos = SwOutlineNodes::npos;
2908         else
2909         {
2910             assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pTarget->GetUserData())));
2911             nTargetPos = static_cast<SwOutlineContent*>(pTarget->GetUserData())->GetOutlinePos();
2912         }
2913 
2914         if( MAXLEVEL > m_nOutlineLevel && // Not all layers are displayed.
2915                         nTargetPos != SwOutlineNodes::npos)
2916         {
2917             SvTreeListEntry* pNext = Next(pTarget);
2918             if(pNext)
2919             {
2920                 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pNext->GetUserData())));
2921                 nTargetPos = static_cast<SwOutlineContent*>(pNext->GetUserData())->GetOutlinePos() - 1;
2922             }
2923             else
2924                 nTargetPos = GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineNodesCount() - 1;
2925         }
2926 
2927         OSL_ENSURE( pEntry &&
2928             lcl_IsContent(pEntry),"Source == 0 or Source has no Content" );
2929         GetParentWindow()->MoveOutline( nSourcePos, nTargetPos, false);
2930 
2931         //TreeListBox will be reloaded from the document
2932         m_aActiveContentArr[ContentTypeId::OUTLINE]->Invalidate();
2933         Display(true);
2934     }
2935     return TRISTATE_FALSE;
2936 }
2937 
2938 // No drop before the first entry - it's a SwContentType
2939 
NotifyAcceptDrop(SvTreeListEntry * pEntry)2940 bool  SwContentTree::NotifyAcceptDrop( SvTreeListEntry* pEntry)
2941 {
2942     return pEntry != nullptr;
2943 }
2944 
2945 // If a Ctrl + DoubleClick are executed in an open area,
2946 // then the base function of the control is to be called.
2947 
MouseButtonDown(const MouseEvent & rMEvt)2948 void SwContentTree::MouseButtonDown( const MouseEvent& rMEvt )
2949 {
2950     Point aPos( rMEvt.GetPosPixel());
2951     SvTreeListEntry* pEntry = GetEntry( aPos, true );
2952     if( !pEntry && rMEvt.IsLeft() && rMEvt.IsMod1() && (rMEvt.GetClicks() % 2) == 0)
2953         Control::MouseButtonDown( rMEvt );
2954     else
2955     {
2956         if( pEntry && (rMEvt.GetClicks() % 2) == 0)
2957         {
2958             SwContent* pCnt = static_cast<SwContent*>(pEntry->GetUserData());
2959             const ContentTypeId nActType = pCnt->GetParent()->GetType();
2960             SetSublistDontOpenWithDoubleClick( nActType == ContentTypeId::OUTLINE );
2961         }
2962         SvTreeListBox::MouseButtonDown( rMEvt );
2963     }
2964 }
2965 
2966 // Update immediately
2967 
GetFocus()2968 void SwContentTree::GetFocus()
2969 {
2970     SwView* pActView = GetParentWindow()->GetCreateView();
2971     if(pActView)
2972     {
2973         SwWrtShell* pActShell = pActView->GetWrtShellPtr();
2974         if (State::CONSTANT == m_eState && !lcl_FindShell(m_pActiveShell))
2975         {
2976             SetActiveShell(pActShell);
2977         }
2978 
2979         if (State::ACTIVE == m_eState && pActShell != GetWrtShell())
2980             SetActiveShell(pActShell);
2981         else if ((State::ACTIVE == m_eState || (State::CONSTANT == m_eState && pActShell == GetWrtShell())) &&
2982                     HasContentChanged())
2983         {
2984             Display(true);
2985         }
2986     }
2987     else if (State::ACTIVE == m_eState)
2988         Clear();
2989     SvTreeListBox::GetFocus();
2990 }
2991 
KeyInput(const KeyEvent & rEvent)2992 void SwContentTree::KeyInput(const KeyEvent& rEvent)
2993 {
2994     const vcl::KeyCode aCode = rEvent.GetKeyCode();
2995     if(aCode.GetCode() == KEY_RETURN)
2996     {
2997         SvTreeListEntry* pEntry = FirstSelected();
2998         if ( pEntry )
2999         {
3000             switch(aCode.GetModifier())
3001             {
3002                 case KEY_MOD2:
3003                     // Switch boxes
3004                     GetParentWindow()->ToggleTree();
3005                 break;
3006                 case KEY_MOD1:
3007                     // Switch RootMode
3008                     ToggleToRoot();
3009                 break;
3010                 case 0:
3011                     if(lcl_IsContentType(pEntry))
3012                     {
3013                         IsExpanded(pEntry) ? Collapse(pEntry) : Expand(pEntry);
3014                     }
3015                     else
3016                         ContentDoubleClickHdl(nullptr);
3017                 break;
3018             }
3019         }
3020     }
3021     else if(aCode.GetCode() == KEY_DELETE && 0 == aCode.GetModifier())
3022     {
3023         SvTreeListEntry* pEntry = FirstSelected();
3024         assert(!pEntry || dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
3025         if(pEntry &&
3026             lcl_IsContent(pEntry) &&
3027                 static_cast<SwContent*>(pEntry->GetUserData())->GetParent()->IsDeletable() &&
3028                     !m_pActiveShell->GetView().GetDocShell()->IsReadOnly())
3029         {
3030             EditEntry(pEntry, EditEntryMode::DELETE);
3031             m_bViewHasChanged = true;
3032             GetParentWindow()->UpdateListBox();
3033             TimerUpdate(&m_aUpdTimer);
3034             GrabFocus();
3035         }
3036     }
3037     //Make KEY_SPACE has same function as DoubleClick ,
3038     //and realize multi-selection .
3039     else if(aCode.GetCode() == KEY_SPACE && 0 == aCode.GetModifier())
3040     {
3041         SvTreeListEntry* pEntry = GetCurEntry();
3042         if(pEntry)
3043         {
3044             if( GetChildCount( pEntry ) == 0 )
3045                 m_bIsKeySpace = true;
3046             Point tempPoint = GetEntryPosition( pEntry );//Change from "GetEntryPos" to "GetEntryPosition" for acc migration
3047             m_aOldRectangle = GetFocusRect(pEntry, tempPoint.Y());
3048 
3049             if (State::HIDDEN != m_eState)
3050             {
3051                 if (State::CONSTANT == m_eState)
3052                 {
3053                     m_pActiveShell->GetView().GetViewFrame()->GetWindow().ToTop();
3054                 }
3055 
3056                 SwContent* pCnt = dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData()));
3057 
3058                 if (pCnt && pCnt->GetParent()->GetType() == ContentTypeId::DRAWOBJECT)
3059                 {
3060                     SdrView* pDrawView = m_pActiveShell->GetDrawView();
3061                     if (pDrawView)
3062                     {
3063                         pDrawView->SdrEndTextEdit();
3064 
3065                         SwDrawModel* pDrawModel = m_pActiveShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
3066                         SdrPage* pPage = pDrawModel->GetPage(0);
3067                         const size_t nCount = pPage->GetObjCount();
3068                         bool hasObjectMarked = false;
3069 
3070                         if (SdrObject* pObject = GetDrawingObjectsByContent(pCnt))
3071                         {
3072                             SdrPageView* pPV = pDrawView->GetSdrPageView/*GetPageViewPvNum*/(/*0*/);
3073                             if( pPV )
3074                             {
3075                                 bool bUnMark = pDrawView->IsObjMarked(pObject);
3076                                 pDrawView->MarkObj( pObject, pPV, bUnMark);
3077 
3078                             }
3079                         }
3080                         for( size_t i=0; i<nCount; ++i )
3081                         {
3082                             SdrObject* pTemp = pPage->GetObj(i);
3083                             bool bMark = pDrawView->IsObjMarked(pTemp);
3084                             switch( pTemp->GetObjIdentifier() )
3085                             {
3086                                 case OBJ_GRUP:
3087                                 case OBJ_TEXT:
3088                                 case OBJ_LINE:
3089                                 case OBJ_RECT:
3090                                 case OBJ_CIRC:
3091                                 case OBJ_SECT:
3092                                 case OBJ_CARC:
3093                                 case OBJ_CCUT:
3094                                 case OBJ_POLY:
3095                                 case OBJ_PLIN:
3096                                 case OBJ_PATHLINE:
3097                                 case OBJ_PATHFILL:
3098                                 case OBJ_FREELINE:
3099                                 case OBJ_FREEFILL:
3100                                 case OBJ_PATHPOLY:
3101                                 case OBJ_PATHPLIN:
3102                                 case OBJ_CAPTION:
3103                                 case OBJ_CUSTOMSHAPE:
3104                                     if( bMark )
3105                                         hasObjectMarked = true;
3106                                     break;
3107                                 default:
3108                                     if ( bMark )
3109                                     {
3110                                         SdrPageView* pPV = pDrawView->GetSdrPageView/*GetPageViewPvNum*/(/*0*/);
3111                                         if (pPV)
3112                                         {
3113                                             pDrawView->MarkObj(pTemp, pPV, true);
3114                                         }
3115                                     }
3116                             }
3117                             //mod end
3118                         }
3119                         if ( !hasObjectMarked )
3120                         {
3121                             SwEditWin& rEditWindow = m_pActiveShell->GetView().GetEditWin();
3122                             vcl::KeyCode tempKeycode( KEY_ESCAPE );
3123                             KeyEvent rKEvt( 0 , tempKeycode );
3124                             static_cast<vcl::Window*>(&rEditWindow)->KeyInput( rKEvt );
3125                         }
3126                     }
3127                 }
3128 
3129                 m_bViewHasChanged = true;
3130             }
3131         }
3132 
3133     }
3134     else if (m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE && aCode.GetCode() == KEY_LEFT)
3135     {
3136         SelectAll(false);
3137         SvTreeListBox::KeyInput(rEvent);
3138     }
3139     else
3140         SvTreeListBox::KeyInput(rEvent);
3141 
3142 }
3143 
RequestHelp(const HelpEvent & rHEvt)3144 void SwContentTree::RequestHelp( const HelpEvent& rHEvt )
3145 {
3146     bool bCallBase = true;
3147     if( rHEvt.GetMode() & HelpEventMode::QUICK )
3148     {
3149         Point aPos( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ));
3150         SvTreeListEntry* pEntry = GetEntry( aPos );
3151         if( pEntry )
3152         {
3153             ContentTypeId nType;
3154             bool bBalloon = false;
3155             bool bContent = false;
3156             void* pUserData = pEntry->GetUserData();
3157             if(lcl_IsContentType(pEntry))
3158             {
3159                 assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pUserData)));
3160                 nType = static_cast<SwContentType*>(pUserData)->GetType();
3161             }
3162             else
3163             {
3164                 assert(dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pUserData)));
3165                 nType = static_cast<SwContent*>(pUserData)->GetParent()->GetType();
3166                 bContent = true;
3167             }
3168             OUString sEntry;
3169             bool bRet = false;
3170             if(bContent)
3171             {
3172                 switch( nType )
3173                 {
3174                     case ContentTypeId::URLFIELD:
3175                         assert(dynamic_cast<SwURLFieldContent*>(static_cast<SwTypeNumber*>(pUserData)));
3176                         sEntry = static_cast<SwURLFieldContent*>(pUserData)->GetURL();
3177                         bRet = true;
3178                     break;
3179 
3180                     case ContentTypeId::POSTIT:
3181                         assert(dynamic_cast<SwPostItContent*>(static_cast<SwTypeNumber*>(pUserData)));
3182                         sEntry = static_cast<SwPostItContent*>(pUserData)->GetName();
3183                         bRet = true;
3184                         if(Help::IsBalloonHelpEnabled())
3185                             bBalloon = true;
3186                     break;
3187                     case ContentTypeId::OUTLINE:
3188                         assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pUserData)));
3189                         sEntry = static_cast<SwOutlineContent*>(pUserData)->GetName();
3190                         bRet = true;
3191                     break;
3192                     case ContentTypeId::GRAPHIC:
3193                         assert(dynamic_cast<SwGraphicContent*>(static_cast<SwTypeNumber*>(pUserData)));
3194                         sEntry = static_cast<SwGraphicContent*>(pUserData)->GetLink();
3195                         bRet = true;
3196                     break;
3197                     default: break;
3198                 }
3199                 if(static_cast<SwContent*>(pUserData)->IsInvisible())
3200                 {
3201                     if(!sEntry.isEmpty())
3202                         sEntry += ", ";
3203                     sEntry += m_sInvisible;
3204                     bRet = true;
3205                 }
3206             }
3207             else
3208             {
3209                 const size_t nMemberCount = static_cast<SwContentType*>(pUserData)->GetMemberCount();
3210                 sEntry = OUString::number(nMemberCount) + " " +
3211                     (nMemberCount == 1
3212                             ? static_cast<SwContentType*>(pUserData)->GetSingleName()
3213                             : static_cast<SwContentType*>(pUserData)->GetName());
3214                 bRet = true;
3215             }
3216             if(bRet)
3217             {
3218                 SvLBoxTab* pTab;
3219                 SvLBoxItem* pItem = GetItem( pEntry, aPos.X(), &pTab );
3220                 if (pItem && SvLBoxItemType::String == pItem->GetType())
3221                 {
3222                     aPos = GetEntryPosition( pEntry );
3223 
3224                     aPos.setX( GetTabPos( pEntry, pTab ) );
3225                     Size aSize(pItem->GetWidth(this, pEntry), pItem->GetHeight(this, pEntry));
3226 
3227                     if((aPos.X() + aSize.Width()) > GetSizePixel().Width())
3228                         aSize.setWidth( GetSizePixel().Width() - aPos.X() );
3229 
3230                     aPos = OutputToScreenPixel(aPos);
3231                     tools::Rectangle aItemRect( aPos, aSize );
3232                     if(bBalloon)
3233                     {
3234                         aPos.AdjustX(aSize.Width() );
3235                         Help::ShowBalloon( this, aPos, aItemRect, sEntry );
3236                     }
3237                     else
3238                         Help::ShowQuickHelp( this, aItemRect, sEntry,
3239                             QuickHelpFlags::Left|QuickHelpFlags::VCenter );
3240                     bCallBase = false;
3241                 }
3242             }
3243             else
3244             {
3245                 Help::ShowQuickHelp( this, tools::Rectangle(), OUString() );
3246                 bCallBase = false;
3247             }
3248         }
3249     }
3250     if( bCallBase )
3251         Window::RequestHelp( rHEvt );
3252 }
3253 
ExecuteContextMenuAction(sal_uInt16 nSelectedPopupEntry)3254 void SwContentTree::ExecuteContextMenuAction( sal_uInt16 nSelectedPopupEntry )
3255 {
3256     SvTreeListEntry* pFirst = FirstSelected();
3257     switch( nSelectedPopupEntry )
3258     {
3259         //Outlinelevel
3260         case 101:
3261         case 102:
3262         case 103:
3263         case 104:
3264         case 105:
3265         case 106:
3266         case 107:
3267         case 108:
3268         case 109:
3269         case 110:
3270             nSelectedPopupEntry -= 100;
3271             if(m_nOutlineLevel != nSelectedPopupEntry )
3272                 SetOutlineLevel(static_cast<sal_Int8>(nSelectedPopupEntry));
3273         break;
3274         case 201:
3275         case 202:
3276         case 203:
3277             GetParentWindow()->SetRegionDropMode(static_cast<RegionMode>(nSelectedPopupEntry - 201));
3278         break;
3279         case 401:
3280         case 402:
3281             EditEntry(pFirst, nSelectedPopupEntry == 401 ? EditEntryMode::RMV_IDX : EditEntryMode::UPD_IDX);
3282         break;
3283         // Edit entry
3284         case 403:
3285             EditEntry(pFirst, EditEntryMode::EDIT);
3286         break;
3287         case 404:
3288             EditEntry(pFirst, EditEntryMode::UNPROTECT_TABLE);
3289         break;
3290         case 405 :
3291         {
3292             const SwTOXBase* pBase = static_cast<SwTOXBaseContent*>(pFirst->GetUserData())
3293                                                                 ->GetTOXBase();
3294             m_pActiveShell->SetTOXBaseReadonly(*pBase, !SwEditShell::IsTOXBaseReadonly(*pBase));
3295         }
3296         break;
3297         case 4:
3298         break;
3299         case 501:
3300             EditEntry(pFirst, EditEntryMode::DELETE);
3301         break;
3302         case 502 :
3303             EditEntry(pFirst, EditEntryMode::RENAME);
3304         break;
3305         case 600:
3306             m_pActiveShell->GetView().GetPostItMgr()->Show();
3307             break;
3308         case 601:
3309             m_pActiveShell->GetView().GetPostItMgr()->Hide();
3310             break;
3311         case 602:
3312             {
3313                 m_pActiveShell->GetView().GetPostItMgr()->SetActiveSidebarWin(nullptr);
3314                 m_pActiveShell->GetView().GetPostItMgr()->Delete();
3315                 break;
3316             }
3317         case 700:
3318             {
3319                 m_pActiveShell->GetView().GetViewFrame()->GetDispatcher()->Execute(FN_OUTLINE_TO_CLIPBOARD);
3320                 break;
3321             }
3322         case 800:
3323             KeyInput(KeyEvent(0, KEY_MOD1|KEY_MULTIPLY));
3324             break;
3325         //Display
3326         default:
3327         if(nSelectedPopupEntry > 300 && nSelectedPopupEntry < 400)
3328         {
3329             nSelectedPopupEntry -= 300;
3330             SwView *pView = SwModule::GetFirstView();
3331             while (pView)
3332             {
3333                 nSelectedPopupEntry --;
3334                 if(nSelectedPopupEntry == 0)
3335                 {
3336                     SetConstantShell(&pView->GetWrtShell());
3337                     break;
3338                 }
3339                 pView = SwModule::GetNextView(pView);
3340             }
3341             if(nSelectedPopupEntry)
3342             {
3343                 m_bViewHasChanged = nSelectedPopupEntry == 1;
3344                 m_eState = (nSelectedPopupEntry == 1) ? State::ACTIVE : State::HIDDEN;
3345                 Display(nSelectedPopupEntry == 1);
3346             }
3347         }
3348     }
3349     GetParentWindow()->UpdateListBox();
3350 }
3351 
SetOutlineLevel(sal_uInt8 nSet)3352 void SwContentTree::SetOutlineLevel(sal_uInt8 nSet)
3353 {
3354     m_nOutlineLevel = nSet;
3355     m_pConfig->SetOutlineLevel( m_nOutlineLevel );
3356     std::unique_ptr<SwContentType>& rpContentT = (State::ACTIVE == m_eState)
3357             ? m_aActiveContentArr[ContentTypeId::OUTLINE]
3358             : m_aHiddenContentArr[ContentTypeId::OUTLINE];
3359     if(rpContentT)
3360     {
3361         rpContentT->SetOutlineLevel(m_nOutlineLevel);
3362         rpContentT->Init();
3363     }
3364     Display(State::ACTIVE == m_eState);
3365 }
3366 
3367 // Mode Change: Show dropped Doc
3368 
ShowHiddenShell()3369 void SwContentTree::ShowHiddenShell()
3370 {
3371     if(m_pHiddenShell)
3372     {
3373         m_eState = State::HIDDEN;
3374         Display(false);
3375     }
3376 }
3377 
3378 // Mode Change: Show active view
3379 
ShowActualView()3380 void SwContentTree::ShowActualView()
3381 {
3382     m_eState = State::ACTIVE;
3383     Display(true);
3384     GetParentWindow()->UpdateListBox();
3385 }
3386 
3387 // Here the buttons for moving outlines are en-/disabled.
Select(SvTreeListEntry * pEntry,bool bSelect)3388 bool SwContentTree::Select( SvTreeListEntry* pEntry, bool bSelect )
3389 {
3390     if(!pEntry)
3391         return false;
3392     bool bEnable = false;
3393     SvTreeListEntry* pParentEntry = GetParent(pEntry);
3394     while(pParentEntry && (!lcl_IsContentType(pParentEntry)))
3395     {
3396         pParentEntry = GetParent(pParentEntry);
3397     }
3398     if (!m_bIsLastReadOnly)
3399     {
3400         if (!IsVisible())
3401             bEnable = true;
3402         else if (pParentEntry)
3403         {
3404             if ((m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE) ||
3405                 (lcl_IsContent(pEntry) &&
3406                     static_cast<SwContentType*>(pParentEntry->GetUserData())->GetType() == ContentTypeId::OUTLINE))
3407             {
3408                 bEnable = true;
3409             }
3410         }
3411     }
3412     SwNavigationPI* pNavi = GetParentWindow();
3413     pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("up"),  bEnable);
3414     pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("down"), bEnable);
3415     pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("promote"), bEnable);
3416     pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("demote"), bEnable);
3417 
3418     return SvTreeListBox::Select(pEntry, bSelect);
3419 }
3420 
SetRootType(ContentTypeId nType)3421 void SwContentTree::SetRootType(ContentTypeId nType)
3422 {
3423     m_nRootType = nType;
3424     m_bIsRoot = true;
3425     m_pConfig->SetRootType( m_nRootType );
3426 }
3427 
RemoveNewline(const OUString & rEntry)3428 OUString SwContentType::RemoveNewline(const OUString& rEntry)
3429 {
3430     if (rEntry.isEmpty())
3431         return rEntry;
3432 
3433     OUStringBuffer aEntry(rEntry);
3434     for (sal_Int32 i = 0; i < rEntry.getLength(); ++i)
3435         if(aEntry[i] == 10 || aEntry[i] == 13)
3436             aEntry[i] = 0x20;
3437 
3438     return aEntry.makeStringAndClear();
3439 }
3440 
EditEntry(SvTreeListEntry const * pEntry,EditEntryMode nMode)3441 void SwContentTree::EditEntry(SvTreeListEntry const * pEntry, EditEntryMode nMode)
3442 {
3443     SwContent* pCnt = static_cast<SwContent*>(pEntry->GetUserData());
3444     GotoContent(pCnt);
3445     const ContentTypeId nType = pCnt->GetParent()->GetType();
3446     sal_uInt16 nSlot = 0;
3447 
3448     uno::Reference< container::XNameAccess >  xNameAccess, xSecond, xThird;
3449     switch(nType)
3450     {
3451         case ContentTypeId::TABLE     :
3452             if(nMode == EditEntryMode::UNPROTECT_TABLE)
3453             {
3454                 m_pActiveShell->GetView().GetDocShell()->
3455                         GetDoc()->UnProtectCells( pCnt->GetName());
3456             }
3457             else if(nMode == EditEntryMode::DELETE)
3458             {
3459                 m_pActiveShell->StartAction();
3460                 OUString sTable = SwResId(STR_TABLE_NAME);
3461                 SwRewriter aRewriterTableName;
3462                 aRewriterTableName.AddRule(UndoArg1, SwResId(STR_START_QUOTE));
3463                 aRewriterTableName.AddRule(UndoArg2, pCnt->GetName());
3464                 aRewriterTableName.AddRule(UndoArg3, SwResId(STR_END_QUOTE));
3465                 sTable = aRewriterTableName.Apply(sTable);
3466 
3467                 SwRewriter aRewriter;
3468                 aRewriter.AddRule(UndoArg1, sTable);
3469                 m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
3470                 m_pActiveShell->GetView().GetViewFrame()->GetDispatcher()->Execute(FN_TABLE_SELECT_ALL);
3471                 m_pActiveShell->DeleteRow();
3472                 m_pActiveShell->EndUndo();
3473                 m_pActiveShell->EndAction();
3474             }
3475             else if(nMode == EditEntryMode::RENAME)
3476             {
3477                 uno::Reference< frame::XModel >  xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
3478                 uno::Reference< text::XTextTablesSupplier >  xTables(xModel, uno::UNO_QUERY);
3479                 xNameAccess = xTables->getTextTables();
3480             }
3481             else
3482                 nSlot = FN_FORMAT_TABLE_DLG;
3483         break;
3484 
3485         case ContentTypeId::GRAPHIC   :
3486             if(nMode == EditEntryMode::DELETE)
3487             {
3488                 m_pActiveShell->DelRight();
3489             }
3490             else if(nMode == EditEntryMode::RENAME)
3491             {
3492                 uno::Reference< frame::XModel >  xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
3493                 uno::Reference< text::XTextGraphicObjectsSupplier >  xGraphics(xModel, uno::UNO_QUERY);
3494                 xNameAccess = xGraphics->getGraphicObjects();
3495                 uno::Reference< text::XTextFramesSupplier >  xFrames(xModel, uno::UNO_QUERY);
3496                 xSecond = xFrames->getTextFrames();
3497                 uno::Reference< text::XTextEmbeddedObjectsSupplier >  xObjs(xModel, uno::UNO_QUERY);
3498                 xThird = xObjs->getEmbeddedObjects();
3499             }
3500             else
3501                 nSlot = FN_FORMAT_GRAFIC_DLG;
3502         break;
3503 
3504         case ContentTypeId::FRAME     :
3505         case ContentTypeId::OLE       :
3506             if(nMode == EditEntryMode::DELETE)
3507             {
3508                 m_pActiveShell->DelRight();
3509             }
3510             else if(nMode == EditEntryMode::RENAME)
3511             {
3512                 uno::Reference< frame::XModel >  xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
3513                 uno::Reference< text::XTextFramesSupplier >  xFrames(xModel, uno::UNO_QUERY);
3514                 uno::Reference< text::XTextEmbeddedObjectsSupplier >  xObjs(xModel, uno::UNO_QUERY);
3515                 if(ContentTypeId::FRAME == nType)
3516                 {
3517                     xNameAccess = xFrames->getTextFrames();
3518                     xSecond = xObjs->getEmbeddedObjects();
3519                 }
3520                 else
3521                 {
3522                     xNameAccess = xObjs->getEmbeddedObjects();
3523                     xSecond = xFrames->getTextFrames();
3524                 }
3525                 uno::Reference< text::XTextGraphicObjectsSupplier >  xGraphics(xModel, uno::UNO_QUERY);
3526                 xThird = xGraphics->getGraphicObjects();
3527             }
3528             else
3529                 nSlot = FN_FORMAT_FRAME_DLG;
3530         break;
3531         case ContentTypeId::BOOKMARK  :
3532             if(nMode == EditEntryMode::DELETE)
3533             {
3534                 IDocumentMarkAccess* const pMarkAccess = m_pActiveShell->getIDocumentMarkAccess();
3535                 pMarkAccess->deleteMark( pMarkAccess->findMark(pCnt->GetName()) );
3536             }
3537             else if(nMode == EditEntryMode::RENAME)
3538             {
3539                 uno::Reference< frame::XModel >  xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
3540                 uno::Reference< text::XBookmarksSupplier >  xBkms(xModel, uno::UNO_QUERY);
3541                 xNameAccess = xBkms->getBookmarks();
3542             }
3543             else
3544                 nSlot = FN_INSERT_BOOKMARK;
3545         break;
3546 
3547         case ContentTypeId::REGION    :
3548             if(nMode == EditEntryMode::RENAME)
3549             {
3550                 uno::Reference< frame::XModel >  xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
3551                 uno::Reference< text::XTextSectionsSupplier >  xSects(xModel, uno::UNO_QUERY);
3552                 xNameAccess = xSects->getTextSections();
3553             }
3554             else
3555                 nSlot = FN_EDIT_REGION;
3556         break;
3557 
3558         case ContentTypeId::URLFIELD:
3559             nSlot = SID_EDIT_HYPERLINK;
3560         break;
3561         case ContentTypeId::REFERENCE:
3562             nSlot = FN_EDIT_FIELD;
3563         break;
3564 
3565         case ContentTypeId::POSTIT:
3566             m_pActiveShell->GetView().GetPostItMgr()->AssureStdModeAtShell();
3567             if(nMode == EditEntryMode::DELETE)
3568             {
3569                 m_pActiveShell->GetView().GetPostItMgr()->SetActiveSidebarWin(nullptr);
3570                 m_pActiveShell->DelRight();
3571             }
3572             else
3573             {
3574                 nSlot = FN_POSTIT;
3575             }
3576         break;
3577         case ContentTypeId::INDEX:
3578         {
3579             const SwTOXBase* pBase = static_cast<SwTOXBaseContent*>(pCnt)->GetTOXBase();
3580             switch(nMode)
3581             {
3582                 case EditEntryMode::EDIT:
3583                     if(pBase)
3584                     {
3585                         SwPtrItem aPtrItem( FN_INSERT_MULTI_TOX, const_cast<SwTOXBase *>(pBase));
3586                         m_pActiveShell->GetView().GetViewFrame()->
3587                             GetDispatcher()->ExecuteList(FN_INSERT_MULTI_TOX,
3588                                 SfxCallMode::ASYNCHRON, { &aPtrItem });
3589 
3590                     }
3591                 break;
3592                 case EditEntryMode::RMV_IDX:
3593                 case EditEntryMode::DELETE:
3594                 {
3595                     if( pBase )
3596                         m_pActiveShell->DeleteTOX(*pBase, EditEntryMode::DELETE == nMode);
3597                 }
3598                 break;
3599                 case EditEntryMode::UPD_IDX:
3600                 case EditEntryMode::RENAME:
3601                 {
3602                     Reference< frame::XModel >  xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
3603                     Reference< XDocumentIndexesSupplier >  xIndexes(xModel, UNO_QUERY);
3604                     Reference< XIndexAccess> xIdxAcc(xIndexes->getDocumentIndexes());
3605                     Reference< XNameAccess >xLocalNameAccess(xIdxAcc, UNO_QUERY);
3606                     if(EditEntryMode::RENAME == nMode)
3607                         xNameAccess = xLocalNameAccess;
3608                     else if(xLocalNameAccess.is() && xLocalNameAccess->hasByName(pBase->GetTOXName()))
3609                     {
3610                         Any aIdx = xLocalNameAccess->getByName(pBase->GetTOXName());
3611                         Reference< XDocumentIndex> xIdx;
3612                         if(aIdx >>= xIdx)
3613                             xIdx->update();
3614                     }
3615                 }
3616                 break;
3617                 default: break;
3618             }
3619         }
3620         break;
3621         case ContentTypeId::DRAWOBJECT :
3622             if(EditEntryMode::DELETE == nMode)
3623                 nSlot = SID_DELETE;
3624         break;
3625         default: break;
3626     }
3627     if(nSlot)
3628         m_pActiveShell->GetView().GetViewFrame()->
3629                     GetDispatcher()->Execute(nSlot, SfxCallMode::ASYNCHRON);
3630     else if(xNameAccess.is())
3631     {
3632         uno::Any aObj = xNameAccess->getByName(pCnt->GetName());
3633         uno::Reference< uno::XInterface >  xTmp;
3634         aObj >>= xTmp;
3635         uno::Reference< container::XNamed >  xNamed(xTmp, uno::UNO_QUERY);
3636         SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
3637         ScopedVclPtr<AbstractSwRenameXNamedDlg> pDlg(pFact->CreateSwRenameXNamedDlg(GetFrameWeld(), xNamed, xNameAccess));
3638         if(xSecond.is())
3639             pDlg->SetAlternativeAccess( xSecond, xThird);
3640 
3641         OUString sForbiddenChars;
3642         if(ContentTypeId::BOOKMARK == nType)
3643         {
3644             sForbiddenChars = "/\\@:*?\";,.#";
3645         }
3646         else if(ContentTypeId::TABLE == nType)
3647         {
3648             sForbiddenChars = " .<>";
3649         }
3650         pDlg->SetForbiddenChars(sForbiddenChars);
3651         pDlg->Execute();
3652     }
3653 }
3654 
GotoContent(const SwContent * pCnt)3655 void SwContentTree::GotoContent(const SwContent* pCnt)
3656 {
3657     m_pActiveShell->EnterStdMode();
3658 
3659     bool bSel = false;
3660     switch(pCnt->GetParent()->GetType())
3661     {
3662         case ContentTypeId::OUTLINE   :
3663         {
3664             m_pActiveShell->GotoOutline(static_cast<const SwOutlineContent*>(pCnt)->GetOutlinePos());
3665         }
3666         break;
3667         case ContentTypeId::TABLE     :
3668         {
3669             m_pActiveShell->GotoTable(pCnt->GetName());
3670         }
3671         break;
3672         case ContentTypeId::FRAME     :
3673         case ContentTypeId::GRAPHIC   :
3674         case ContentTypeId::OLE       :
3675         {
3676             if(m_pActiveShell->GotoFly(pCnt->GetName()))
3677                 bSel = true;
3678         }
3679         break;
3680         case ContentTypeId::BOOKMARK:
3681         {
3682             m_pActiveShell->GotoMark(pCnt->GetName());
3683         }
3684         break;
3685         case ContentTypeId::REGION    :
3686         {
3687             m_pActiveShell->GotoRegion(pCnt->GetName());
3688         }
3689         break;
3690         case ContentTypeId::URLFIELD:
3691         {
3692             if(m_pActiveShell->GotoINetAttr(
3693                             *static_cast<const SwURLFieldContent*>(pCnt)->GetINetAttr() ))
3694             {
3695                 m_pActiveShell->Right( CRSR_SKIP_CHARS, true, 1, false);
3696                 m_pActiveShell->SwCursorShell::SelectTextAttr( RES_TXTATR_INETFMT, true );
3697             }
3698 
3699         }
3700         break;
3701         case ContentTypeId::REFERENCE:
3702         {
3703             m_pActiveShell->GotoRefMark(pCnt->GetName());
3704         }
3705         break;
3706         case ContentTypeId::INDEX:
3707         {
3708             const OUString& sName(pCnt->GetName());
3709             if (!m_pActiveShell->GotoNextTOXBase(&sName))
3710                 m_pActiveShell->GotoPrevTOXBase(&sName);
3711         }
3712         break;
3713         case ContentTypeId::POSTIT:
3714             m_pActiveShell->GetView().GetPostItMgr()->AssureStdModeAtShell();
3715             m_pActiveShell->GotoFormatField(*static_cast<const SwPostItContent*>(pCnt)->GetPostIt());
3716         break;
3717         case ContentTypeId::DRAWOBJECT:
3718         {
3719             SwPosition aPos = *m_pActiveShell->GetCursor()->GetPoint();
3720             SdrView* pDrawView = m_pActiveShell->GetDrawView();
3721             if (pDrawView)
3722             {
3723                 pDrawView->SdrEndTextEdit();
3724                 pDrawView->UnmarkAll();
3725                 SwDrawModel* _pModel = m_pActiveShell->getIDocumentDrawModelAccess().GetDrawModel();
3726                 SdrPage* pPage = _pModel->GetPage(0);
3727                 const size_t nCount = pPage->GetObjCount();
3728                 for( size_t i=0; i<nCount; ++i )
3729                 {
3730                     SdrObject* pTemp = pPage->GetObj(i);
3731                     if (pTemp->GetName() == pCnt->GetName())
3732                     {
3733                         SdrPageView* pPV = pDrawView->GetSdrPageView();
3734                         if( pPV )
3735                         {
3736                             pDrawView->MarkObj( pTemp, pPV );
3737                         }
3738                     }
3739                 }
3740                 m_pActiveShell->GetNavigationMgr().addEntry(aPos);
3741                 m_pActiveShell->EnterStdMode();
3742                 bSel = true;
3743             }
3744         }
3745         break;
3746         default: break;
3747     }
3748     if(bSel)
3749     {
3750         m_pActiveShell->HideCursor();
3751         m_pActiveShell->EnterSelFrameMode();
3752     }
3753     SwView& rView = m_pActiveShell->GetView();
3754     rView.StopShellTimer();
3755     rView.GetPostItMgr()->SetActiveSidebarWin(nullptr);
3756     rView.GetEditWin().GrabFocus();
3757 
3758     // force scroll to cursor position when navigating to inactive document
3759     if(!bSel)
3760     {
3761         Point rPoint = m_pActiveShell->GetCursorDocPos();
3762         rPoint.setX(0);
3763         rView.SetVisArea(rPoint);
3764     }
3765 }
3766 
3767 // Now even the matching text::Bookmark
NaviContentBookmark()3768 NaviContentBookmark::NaviContentBookmark()
3769     :
3770     nDocSh(0),
3771     nDefDrag( RegionMode::NONE )
3772 {
3773 }
3774 
NaviContentBookmark(const OUString & rUrl,const OUString & rDesc,RegionMode nDragType,const SwDocShell * pDocSh)3775 NaviContentBookmark::NaviContentBookmark( const OUString &rUrl,
3776                     const OUString& rDesc,
3777                     RegionMode nDragType,
3778                     const SwDocShell* pDocSh ) :
3779     aUrl( rUrl ),
3780     aDescr(rDesc),
3781     nDocSh(reinterpret_cast<sal_IntPtr>(pDocSh)),
3782     nDefDrag( nDragType )
3783 {
3784 }
3785 
Copy(TransferDataContainer & rData) const3786 void NaviContentBookmark::Copy( TransferDataContainer& rData ) const
3787 {
3788     rtl_TextEncoding eSysCSet = osl_getThreadTextEncoding();
3789 
3790     OString sStrBuf(OUStringToOString(aUrl, eSysCSet) + OStringChar(NAVI_BOOKMARK_DELIM) +
3791                     OUStringToOString(aDescr, eSysCSet) + OStringChar(NAVI_BOOKMARK_DELIM) +
3792                     OString::number(static_cast<int>(nDefDrag)) + OStringChar(NAVI_BOOKMARK_DELIM) +
3793                     OString::number(nDocSh));
3794     rData.CopyByteString(SotClipboardFormatId::SONLK, sStrBuf);
3795 }
3796 
Paste(TransferableDataHelper & rData)3797 bool NaviContentBookmark::Paste( TransferableDataHelper& rData )
3798 {
3799     OUString sStr;
3800     bool bRet = rData.GetString( SotClipboardFormatId::SONLK, sStr );
3801     if( bRet )
3802     {
3803         sal_Int32 nPos = 0;
3804         aUrl    = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos );
3805         aDescr  = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos );
3806         nDefDrag= static_cast<RegionMode>( sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos ).toInt32() );
3807         nDocSh  = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos ).toInt32();
3808     }
3809     return bRet;
3810 }
3811 
3812 class SwContentLBoxString : public SvLBoxString
3813 {
3814 public:
SwContentLBoxString(const OUString & rStr)3815     explicit SwContentLBoxString(const OUString& rStr) : SvLBoxString(rStr) {}
3816 
3817     virtual void Paint(const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext,
3818                        const SvViewDataEntry* pView, const SvTreeListEntry& rEntry) override;
3819 };
3820 
InitEntry(SvTreeListEntry * pEntry,const OUString & rStr,const Image & rImg1,const Image & rImg2)3821 void SwContentTree::InitEntry(SvTreeListEntry* pEntry,
3822         const OUString& rStr ,const Image& rImg1,const Image& rImg2)
3823 {
3824     const size_t nColToHilite = 1; //0==Bitmap;1=="Column1";2=="Column2"
3825     SvTreeListBox::InitEntry( pEntry, rStr, rImg1, rImg2 );
3826     SvLBoxString& rCol = static_cast<SvLBoxString&>(pEntry->GetItem( nColToHilite ));
3827     pEntry->ReplaceItem(std::make_unique<SwContentLBoxString>(rCol.GetText()), nColToHilite);
3828 }
3829 
Paint(const Point & rPos,SvTreeListBox & rDev,vcl::RenderContext & rRenderContext,const SvViewDataEntry * pView,const SvTreeListEntry & rEntry)3830 void SwContentLBoxString::Paint(const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext,
3831                                 const SvViewDataEntry* pView, const SvTreeListEntry& rEntry)
3832 {
3833     if (lcl_IsContent(&rEntry) && static_cast<SwContent *>(rEntry.GetUserData())->IsInvisible())
3834     {
3835         vcl::Font aOldFont(rRenderContext.GetFont());
3836         vcl::Font aFont(aOldFont);
3837         aFont.SetColor(COL_LIGHTGRAY);
3838         rRenderContext.SetFont(aFont );
3839         rRenderContext.DrawText(rPos, GetText());
3840         rRenderContext.SetFont(aOldFont);
3841     }
3842     else
3843     {
3844         SvLBoxString::Paint(rPos, rDev, rRenderContext, pView, rEntry);
3845     }
3846 }
3847 
DataChanged(const DataChangedEvent & rDCEvt)3848 void SwContentTree::DataChanged(const DataChangedEvent& rDCEvt)
3849 {
3850     if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
3851          (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
3852     {
3853         FindActiveTypeAndRemoveUserData();
3854 
3855         Display(true);
3856     }
3857 
3858     SvTreeListBox::DataChanged( rDCEvt );
3859 }
3860 
GetParentWindow()3861 SwNavigationPI* SwContentTree::GetParentWindow()
3862 {
3863     return m_xDialog;
3864 }
3865 
3866 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3867