tdf#137358 Fix incorrect outline position returned
[LibreOffice.git] / sw / source / uibase / utlui / content.cxx
blob5b3ce3b6474be8f69b87658ed547607de78d1040
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <comphelper/string.hxx>
21 #include <svl/urlbmk.hxx>
22 #include <osl/thread.h>
23 #include <sal/log.hxx>
24 #include <tools/urlobj.hxx>
25 #include <sfx2/docfile.hxx>
26 #include <sfx2/dispatch.hxx>
27 #include <sfx2/event.hxx>
28 #include <sfx2/viewfrm.hxx>
29 #include <o3tl/enumrange.hxx>
30 #include <o3tl/sorted_vector.hxx>
31 #include <vcl/commandevent.hxx>
32 #include <vcl/weldutils.hxx>
33 #include <sot/formats.hxx>
34 #include <uiitems.hxx>
35 #include <fmtinfmt.hxx>
36 #include <txtinet.hxx>
37 #include <fmtfld.hxx>
38 #include <swmodule.hxx>
39 #include <wrtsh.hxx>
40 #include <view.hxx>
41 #include <docsh.hxx>
42 #include <drawdoc.hxx>
43 #include <content.hxx>
44 #include <frmfmt.hxx>
45 #include <fldbas.hxx>
46 #include <IMark.hxx>
47 #include <section.hxx>
48 #include <tox.hxx>
49 #include <navipi.hxx>
50 #include <navicont.hxx>
51 #include <navicfg.hxx>
52 #include <edtwin.hxx>
53 #include <doc.hxx>
54 #include <IDocumentSettingAccess.hxx>
55 #include <IDocumentDrawModelAccess.hxx>
56 #include <IDocumentOutlineNodes.hxx>
57 #include <unotxvw.hxx>
58 #include <cmdid.h>
59 #include <helpids.h>
60 #include <strings.hrc>
61 #include <com/sun/star/text/XTextSectionsSupplier.hpp>
62 #include <com/sun/star/text/XTextGraphicObjectsSupplier.hpp>
63 #include <com/sun/star/text/XTextTablesSupplier.hpp>
64 #include <com/sun/star/text/XDocumentIndexesSupplier.hpp>
65 #include <com/sun/star/text/XDocumentIndex.hpp>
66 #include <com/sun/star/text/XBookmarksSupplier.hpp>
67 #include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
68 #include <com/sun/star/text/XTextFramesSupplier.hpp>
69 #include <dcontact.hxx>
70 #include <svx/svdpage.hxx>
71 #include <svx/svdview.hxx>
72 #include <SwRewriter.hxx>
73 #include <hints.hxx>
74 #include <numrule.hxx>
75 #include <swundo.hxx>
76 #include <ndtxt.hxx>
77 #include <PostItMgr.hxx>
78 #include <postithelper.hxx>
80 #include <swabstdlg.hxx>
81 #include <bitmaps.hlst>
83 #include <navmgr.hxx>
84 #include <AnnotationWin.hxx>
85 #include <memory>
87 #include <fmtcntnt.hxx>
88 #include <docstat.hxx>
90 #include <viewopt.hxx>
92 #define CTYPE_CNT 0
93 #define CTYPE_CTT 1
95 using namespace ::std;
96 using namespace ::com::sun::star;
97 using namespace ::com::sun::star::text;
98 using namespace ::com::sun::star::uno;
99 using namespace ::com::sun::star::container;
101 namespace {
103 constexpr char NAVI_BOOKMARK_DELIM = '\x01';
107 class SwContentArr
108 : public o3tl::sorted_vector<std::unique_ptr<SwContent>, o3tl::less_uniqueptr_to<SwContent>,
109 o3tl::find_partialorder_ptrequals>
113 namespace
115 bool lcl_IsContent(const weld::TreeIter& rEntry, const weld::TreeView& rTreeView)
117 return reinterpret_cast<const SwTypeNumber*>(rTreeView.get_id(rEntry).toInt64())->GetTypeId() == CTYPE_CNT;
120 bool lcl_IsContentType(const weld::TreeIter& rEntry, const weld::TreeView& rTreeView)
122 return reinterpret_cast<const SwTypeNumber*>(rTreeView.get_id(rEntry).toInt64())->GetTypeId() == CTYPE_CTT;
125 bool lcl_FindShell(SwWrtShell const * pShell)
127 bool bFound = false;
128 SwView *pView = SwModule::GetFirstView();
129 while (pView)
131 if(pShell == &pView->GetWrtShell())
133 bFound = true;
134 break;
136 pView = SwModule::GetNextView(pView);
138 return bFound;
141 bool lcl_IsUiVisibleBookmark(const ::sw::mark::IMark* pMark)
143 return IDocumentMarkAccess::GetType(*pMark) == IDocumentMarkAccess::MarkType::BOOKMARK;
146 size_t lcl_InsertURLFieldContent(
147 SwContentArr *pMember,
148 SwWrtShell* pWrtShell,
149 const SwContentType *pCntType)
151 SwGetINetAttrs aArr;
152 pWrtShell->GetINetAttrs( aArr );
153 const SwGetINetAttrs::size_type nCount {aArr.size()};
154 for( SwGetINetAttrs::size_type n = 0; n < nCount; ++n )
156 SwGetINetAttr* p = &aArr[ n ];
157 std::unique_ptr<SwURLFieldContent> pCnt(new SwURLFieldContent(
158 pCntType,
159 p->sText,
160 INetURLObject::decode(
161 p->rINetAttr.GetINetFormat().GetValue(),
162 INetURLObject::DecodeMechanism::Unambiguous ),
163 &p->rINetAttr,
164 n ));
165 pMember->insert( std::move(pCnt) );
167 return nCount;
171 // Content, contains names and reference at the content type.
173 SwContent::SwContent(const SwContentType* pCnt, const OUString& rName, tools::Long nYPos) :
174 SwTypeNumber(CTYPE_CNT),
175 pParent(pCnt),
176 sContentName(rName),
177 nYPosition(nYPos),
178 bInvisible(false)
183 SwTypeNumber::~SwTypeNumber()
187 bool SwContent::IsProtect() const
189 return false;
192 bool SwPostItContent::IsProtect() const
194 return pField->IsProtect();
197 bool SwURLFieldContent::IsProtect() const
199 return pINetAttr->IsProtect();
202 SwGraphicContent::~SwGraphicContent()
206 SwTOXBaseContent::~SwTOXBaseContent()
210 static const char* STR_CONTENT_TYPE_ARY[] =
212 STR_CONTENT_TYPE_OUTLINE,
213 STR_CONTENT_TYPE_TABLE,
214 STR_CONTENT_TYPE_FRAME,
215 STR_CONTENT_TYPE_GRAPHIC,
216 STR_CONTENT_TYPE_OLE,
217 STR_CONTENT_TYPE_BOOKMARK,
218 STR_CONTENT_TYPE_REGION,
219 STR_CONTENT_TYPE_URLFIELD,
220 STR_CONTENT_TYPE_REFERENCE,
221 STR_CONTENT_TYPE_INDEX,
222 STR_CONTENT_TYPE_POSTIT,
223 STR_CONTENT_TYPE_DRAWOBJECT
226 static const char* STR_CONTENT_TYPE_SINGLE_ARY[] =
228 STR_CONTENT_TYPE_SINGLE_OUTLINE,
229 STR_CONTENT_TYPE_SINGLE_TABLE,
230 STR_CONTENT_TYPE_SINGLE_FRAME,
231 STR_CONTENT_TYPE_SINGLE_GRAPHIC,
232 STR_CONTENT_TYPE_SINGLE_OLE,
233 STR_CONTENT_TYPE_SINGLE_BOOKMARK,
234 STR_CONTENT_TYPE_SINGLE_REGION,
235 STR_CONTENT_TYPE_SINGLE_URLFIELD,
236 STR_CONTENT_TYPE_SINGLE_REFERENCE,
237 STR_CONTENT_TYPE_SINGLE_INDEX,
238 STR_CONTENT_TYPE_SINGLE_POSTIT,
239 STR_CONTENT_TYPE_SINGLE_DRAWOBJECT
242 namespace
244 bool checkVisibilityChanged(
245 const SwContentArr& rSwContentArrA,
246 const SwContentArr& rSwContentArrB)
248 if(rSwContentArrA.size() != rSwContentArrB.size())
250 return true;
253 for(size_t a(0); a < rSwContentArrA.size(); a++)
255 if(rSwContentArrA[a]->IsInvisible() != rSwContentArrB[a]->IsInvisible())
257 return true;
261 return false;
263 } // end of anonymous namespace
265 SwContentType::SwContentType(SwWrtShell* pShell, ContentTypeId nType, sal_uInt8 nLevel) :
266 SwTypeNumber(CTYPE_CTT),
267 m_pWrtShell(pShell),
268 m_sContentTypeName(SwResId(STR_CONTENT_TYPE_ARY[static_cast<int>(nType)])),
269 m_sSingleContentTypeName(SwResId(STR_CONTENT_TYPE_SINGLE_ARY[static_cast<int>(nType)])),
270 m_nMemberCount(0),
271 m_nContentType(nType),
272 m_nOutlineLevel(nLevel),
273 m_bDataValid(false),
274 m_bEdit(false),
275 m_bDelete(true)
277 Init();
280 void SwContentType::Init(bool* pbInvalidateWindow)
282 // if the MemberCount is changing ...
283 size_t nOldMemberCount = m_nMemberCount;
284 m_nMemberCount = 0;
285 switch(m_nContentType)
287 case ContentTypeId::OUTLINE :
289 m_sTypeToken = "outline";
290 m_nMemberCount = m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
291 if (m_nMemberCount < MAXLEVEL)
293 const size_t nOutlineCount = m_nMemberCount;
294 for(size_t j = 0; j < nOutlineCount; ++j)
296 if (m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(j) > m_nOutlineLevel
297 || !m_pWrtShell->getIDocumentOutlineNodesAccess()->isOutlineInLayout(j, *m_pWrtShell->GetLayout()))
299 m_nMemberCount --;
304 break;
306 case ContentTypeId::TABLE :
307 m_sTypeToken = "table";
308 m_nMemberCount = m_pWrtShell->GetTableFrameFormatCount(true);
309 m_bEdit = true;
310 break;
312 case ContentTypeId::FRAME :
313 case ContentTypeId::GRAPHIC :
314 case ContentTypeId::OLE :
316 FlyCntType eType = FLYCNTTYPE_FRM;
317 m_sTypeToken = "frame";
318 if(m_nContentType == ContentTypeId::OLE)
320 eType = FLYCNTTYPE_OLE;
321 m_sTypeToken = "ole";
323 else if(m_nContentType == ContentTypeId::GRAPHIC)
325 eType = FLYCNTTYPE_GRF;
326 m_sTypeToken = "graphic";
328 m_nMemberCount = m_pWrtShell->GetFlyCount(eType, /*bIgnoreTextBoxes=*/true);
329 m_bEdit = true;
331 break;
332 case ContentTypeId::BOOKMARK:
334 IDocumentMarkAccess* const pMarkAccess = m_pWrtShell->getIDocumentMarkAccess();
335 m_nMemberCount = count_if(
336 pMarkAccess->getBookmarksBegin(),
337 pMarkAccess->getBookmarksEnd(),
338 &lcl_IsUiVisibleBookmark);
339 m_sTypeToken.clear();
340 const bool bProtectedBM = m_pWrtShell->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS);
341 m_bEdit = !bProtectedBM;
342 m_bDelete = !bProtectedBM;
344 break;
345 case ContentTypeId::REGION :
347 std::unique_ptr<SwContentArr> pOldMember;
348 if(!m_pMember)
349 m_pMember.reset( new SwContentArr );
350 else if(!m_pMember->empty())
352 pOldMember = std::move(m_pMember);
353 m_pMember.reset( new SwContentArr );
355 const Point aNullPt;
356 m_nMemberCount = m_pWrtShell->GetSectionFormatCount();
357 for(size_t i = 0; i < m_nMemberCount; ++i)
359 const SwSectionFormat* pFormat;
360 SectionType eTmpType;
361 if( (pFormat = &m_pWrtShell->GetSectionFormat(i))->IsInNodesArr() &&
362 (eTmpType = pFormat->GetSection()->GetType()) != SectionType::ToxContent
363 && SectionType::ToxHeader != eTmpType )
365 const OUString& rSectionName =
366 pFormat->GetSection()->GetSectionName();
367 sal_uInt8 nLevel = 0;
368 SwSectionFormat* pParentFormat = pFormat->GetParent();
369 while(pParentFormat)
371 nLevel++;
372 pParentFormat = pParentFormat->GetParent();
375 std::unique_ptr<SwContent> pCnt(new SwRegionContent(this, rSectionName,
376 nLevel,
377 pFormat->FindLayoutRect( false, &aNullPt ).Top()));
379 SwPtrMsgPoolItem aAskItem( RES_CONTENT_VISIBLE, nullptr );
380 if( !pFormat->GetInfo( aAskItem ) &&
381 !aAskItem.pObject ) // not visible
382 pCnt->SetInvisible();
383 m_pMember->insert(std::move(pCnt));
386 m_nMemberCount = m_pMember->size();
387 m_sTypeToken = "region";
388 m_bEdit = true;
389 m_bDelete = false;
390 if(pOldMember)
392 if(nullptr != pbInvalidateWindow)
394 // need to check visibility (and equal entry number) after
395 // creation due to a sorted list being used here (before,
396 // entries with same index were compared already at creation
397 // time what worked before a sorted list was used)
398 *pbInvalidateWindow = checkVisibilityChanged(
399 *pOldMember,
400 *m_pMember);
404 break;
405 case ContentTypeId::INDEX:
407 m_nMemberCount = m_pWrtShell->GetTOXCount();
408 m_bEdit = true;
409 m_bDelete = false;
411 break;
412 case ContentTypeId::REFERENCE:
414 m_nMemberCount = m_pWrtShell->GetRefMarks();
415 m_bDelete = false;
417 break;
418 case ContentTypeId::URLFIELD:
420 m_nMemberCount = 0;
421 if(!m_pMember)
422 m_pMember.reset( new SwContentArr );
423 else
424 m_pMember->clear();
426 m_nMemberCount = lcl_InsertURLFieldContent(m_pMember.get(), m_pWrtShell, this);
428 m_bEdit = true;
429 nOldMemberCount = m_nMemberCount;
430 m_bDelete = true;
432 break;
433 case ContentTypeId::POSTIT:
435 m_nMemberCount = 0;
436 if(!m_pMember)
437 m_pMember.reset( new SwContentArr );
438 else
439 m_pMember->clear();
441 SwPostItMgr* aMgr = m_pWrtShell->GetView().GetPostItMgr();
442 if (aMgr)
444 for(SwPostItMgr::const_iterator i = aMgr->begin(); i != aMgr->end(); ++i)
446 if (const SwFormatField* pFormatField = dynamic_cast<const SwFormatField *>((*i)->GetBroadcaster())) // SwPostit
448 if (pFormatField->GetTextField() && pFormatField->IsFieldInDoc() &&
449 (*i)->mLayoutStatus!=SwPostItHelper::INVISIBLE )
451 OUString sEntry = pFormatField->GetField()->GetPar2();
452 sEntry = RemoveNewline(sEntry);
453 std::unique_ptr<SwPostItContent> pCnt(new SwPostItContent(
454 this,
455 sEntry,
456 pFormatField,
457 m_nMemberCount));
458 m_pMember->insert(std::move(pCnt));
459 m_nMemberCount++;
464 m_sTypeToken.clear();
465 m_bEdit = true;
466 nOldMemberCount = m_nMemberCount;
468 break;
469 case ContentTypeId::DRAWOBJECT:
471 m_sTypeToken.clear();
472 m_bEdit = true;
473 m_nMemberCount = 0;
474 SwDrawModel* pModel = m_pWrtShell->getIDocumentDrawModelAccess().GetDrawModel();
475 if(pModel)
477 SdrPage* pPage = pModel->GetPage(0);
478 const size_t nCount = pPage->GetObjCount();
479 for( size_t i=0; i<nCount; ++i )
481 SdrObject* pTemp = pPage->GetObj(i);
482 // #i51726# - all drawing objects can be named now
483 if (!pTemp->GetName().isEmpty())
484 m_nMemberCount++;
488 break;
489 default: break;
491 // ... then, the data can also no longer be valid,
492 // apart from those which have already been corrected,
493 // then nOldMemberCount is nevertheless not so old.
494 if( nOldMemberCount != m_nMemberCount )
495 m_bDataValid = false;
498 SwContentType::~SwContentType()
502 const SwContent* SwContentType::GetMember(size_t nIndex)
504 if(!m_bDataValid || !m_pMember)
506 FillMemberList();
508 if(nIndex < m_pMember->size())
509 return (*m_pMember)[nIndex].get();
511 return nullptr;
514 void SwContentType::Invalidate()
516 m_bDataValid = false;
519 void SwContentType::FillMemberList(bool* pbLevelOrVisibilityChanged)
521 std::unique_ptr<SwContentArr> pOldMember;
522 size_t nOldMemberCount = 0;
523 SwPtrMsgPoolItem aAskItem( RES_CONTENT_VISIBLE, nullptr );
524 if(m_pMember && pbLevelOrVisibilityChanged)
526 pOldMember = std::move(m_pMember);
527 nOldMemberCount = pOldMember->size();
528 m_pMember.reset( new SwContentArr );
529 *pbLevelOrVisibilityChanged = false;
531 else if(!m_pMember)
532 m_pMember.reset( new SwContentArr );
533 else
534 m_pMember->clear();
535 switch(m_nContentType)
537 case ContentTypeId::OUTLINE :
539 const size_t nOutlineCount = m_nMemberCount =
540 m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
542 size_t nPos = 0;
543 for (size_t i = 0; i < nOutlineCount; ++i)
545 const sal_uInt8 nLevel = m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(i);
546 if(nLevel >= m_nOutlineLevel )
547 m_nMemberCount--;
548 else
550 if (!m_pWrtShell->getIDocumentOutlineNodesAccess()->isOutlineInLayout(i, *m_pWrtShell->GetLayout()))
552 --m_nMemberCount;
553 continue; // don't hide it, just skip it
555 OUString aEntry(comphelper::string::stripStart(
556 m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineText(i, m_pWrtShell->GetLayout()), ' '));
557 aEntry = SwNavigationPI::CleanEntry(aEntry);
558 std::unique_ptr<SwOutlineContent> pCnt(new SwOutlineContent(this, aEntry, i, nLevel,
559 m_pWrtShell->IsOutlineMovable( i ), nPos ));
560 m_pMember->insert(std::move(pCnt));
561 // with the same number and existing "pOldMember" the
562 // old one is compared with the new OutlinePos.
563 if (nOldMemberCount > nPos && static_cast<SwOutlineContent*>((*pOldMember)[nPos].get())->GetOutlineLevel() != nLevel)
564 *pbLevelOrVisibilityChanged = true;
566 nPos++;
571 break;
572 case ContentTypeId::TABLE :
574 const size_t nCount = m_pWrtShell->GetTableFrameFormatCount(true);
575 OSL_ENSURE(m_nMemberCount == nCount, "MemberCount differs");
576 Point aNullPt;
577 m_nMemberCount = nCount;
578 for(size_t i = 0; i < m_nMemberCount; ++i)
580 const SwFrameFormat& rTableFormat = m_pWrtShell->GetTableFrameFormat(i, true);
581 const OUString& sTableName( rTableFormat.GetName() );
583 SwContent* pCnt = new SwContent(this, sTableName,
584 rTableFormat.FindLayoutRect(false, &aNullPt).Top() );
585 if( !rTableFormat.GetInfo( aAskItem ) &&
586 !aAskItem.pObject ) // not visible
587 pCnt->SetInvisible();
589 m_pMember->insert(std::unique_ptr<SwContent>(pCnt));
592 if (nullptr != pbLevelOrVisibilityChanged)
594 assert(pOldMember);
595 // need to check visibility (and equal entry number) after
596 // creation due to a sorted list being used here (before,
597 // entries with same index were compared already at creation
598 // time what worked before a sorted list was used)
599 *pbLevelOrVisibilityChanged = checkVisibilityChanged(
600 *pOldMember,
601 *m_pMember);
604 break;
605 case ContentTypeId::OLE :
606 case ContentTypeId::FRAME :
607 case ContentTypeId::GRAPHIC :
609 FlyCntType eType = FLYCNTTYPE_FRM;
610 if(m_nContentType == ContentTypeId::OLE)
611 eType = FLYCNTTYPE_OLE;
612 else if(m_nContentType == ContentTypeId::GRAPHIC)
613 eType = FLYCNTTYPE_GRF;
614 Point aNullPt;
615 m_nMemberCount = m_pWrtShell->GetFlyCount(eType, /*bIgnoreTextBoxes=*/true);
616 std::vector<SwFrameFormat const*> formats(m_pWrtShell->GetFlyFrameFormats(eType, /*bIgnoreTextBoxes=*/true));
617 SAL_WARN_IF(m_nMemberCount != formats.size(), "sw.ui", "MemberCount differs");
618 m_nMemberCount = formats.size();
619 for (size_t i = 0; i < m_nMemberCount; ++i)
621 SwFrameFormat const*const pFrameFormat = formats[i];
622 const OUString sFrameName = pFrameFormat->GetName();
624 SwContent* pCnt;
625 if(ContentTypeId::GRAPHIC == m_nContentType)
627 OUString sLink;
628 m_pWrtShell->GetGrfNms( &sLink, nullptr, static_cast<const SwFlyFrameFormat*>( pFrameFormat));
629 pCnt = new SwGraphicContent(this, sFrameName,
630 INetURLObject::decode( sLink,
631 INetURLObject::DecodeMechanism::Unambiguous ),
632 pFrameFormat->FindLayoutRect(false, &aNullPt).Top());
634 else
636 pCnt = new SwContent(this, sFrameName,
637 pFrameFormat->FindLayoutRect(false, &aNullPt).Top() );
639 if( !pFrameFormat->GetInfo( aAskItem ) &&
640 !aAskItem.pObject ) // not visible
641 pCnt->SetInvisible();
642 m_pMember->insert(std::unique_ptr<SwContent>(pCnt));
645 if(nullptr != pbLevelOrVisibilityChanged)
647 assert(pOldMember);
648 // need to check visibility (and equal entry number) after
649 // creation due to a sorted list being used here (before,
650 // entries with same index were compared already at creation
651 // time what worked before a sorted list was used)
652 *pbLevelOrVisibilityChanged = checkVisibilityChanged(
653 *pOldMember,
654 *m_pMember);
657 break;
658 case ContentTypeId::BOOKMARK:
660 IDocumentMarkAccess* const pMarkAccess = m_pWrtShell->getIDocumentMarkAccess();
661 for(IDocumentMarkAccess::const_iterator_t ppBookmark = pMarkAccess->getBookmarksBegin();
662 ppBookmark != pMarkAccess->getBookmarksEnd();
663 ++ppBookmark)
665 if(lcl_IsUiVisibleBookmark(*ppBookmark))
667 const OUString& rBkmName = (*ppBookmark)->GetName();
668 //nYPos from 0 -> text::Bookmarks will be sorted alphabetically
669 std::unique_ptr<SwContent> pCnt(new SwContent(this, rBkmName, 0));
670 m_pMember->insert(std::move(pCnt));
674 break;
675 case ContentTypeId::REGION :
677 const Point aNullPt;
678 m_nMemberCount = m_pWrtShell->GetSectionFormatCount();
679 for(size_t i = 0; i < m_nMemberCount; ++i)
681 const SwSectionFormat* pFormat;
682 SectionType eTmpType;
683 if( (pFormat = &m_pWrtShell->GetSectionFormat(i))->IsInNodesArr() &&
684 (eTmpType = pFormat->GetSection()->GetType()) != SectionType::ToxContent
685 && SectionType::ToxHeader != eTmpType )
687 OUString sSectionName = pFormat->GetSection()->GetSectionName();
689 sal_uInt8 nLevel = 0;
690 SwSectionFormat* pParentFormat = pFormat->GetParent();
691 while(pParentFormat)
693 nLevel++;
694 pParentFormat = pParentFormat->GetParent();
697 std::unique_ptr<SwContent> pCnt(new SwRegionContent(this, sSectionName,
698 nLevel,
699 pFormat->FindLayoutRect( false, &aNullPt ).Top()));
700 if( !pFormat->GetInfo( aAskItem ) &&
701 !aAskItem.pObject ) // not visible
702 pCnt->SetInvisible();
703 m_pMember->insert(std::move(pCnt));
706 if(nullptr != pbLevelOrVisibilityChanged)
708 assert(pOldMember);
709 // need to check visibility (and equal entry number) after
710 // creation due to a sorted list being used here (before,
711 // entries with same index were compared already at creation
712 // time what worked before a sorted list was used)
713 *pbLevelOrVisibilityChanged = checkVisibilityChanged(
714 *pOldMember,
715 *m_pMember);
718 m_nMemberCount = m_pMember->size();
720 break;
721 case ContentTypeId::REFERENCE:
723 std::vector<OUString> aRefMarks;
724 m_nMemberCount = m_pWrtShell->GetRefMarks( &aRefMarks );
726 for (const auto& rRefMark : aRefMarks)
728 // References sorted alphabetically
729 m_pMember->insert(std::make_unique<SwContent>(this, rRefMark, 0));
732 break;
733 case ContentTypeId::URLFIELD:
734 m_nMemberCount = lcl_InsertURLFieldContent(m_pMember.get(), m_pWrtShell, this);
735 break;
736 case ContentTypeId::INDEX:
739 const sal_uInt16 nCount = m_pWrtShell->GetTOXCount();
740 m_nMemberCount = nCount;
741 for ( sal_uInt16 nTox = 0; nTox < nCount; nTox++ )
743 const SwTOXBase* pBase = m_pWrtShell->GetTOX( nTox );
744 OUString sTOXNm( pBase->GetTOXName() );
746 SwContent* pCnt = new SwTOXBaseContent(
747 this, sTOXNm, nTox, *pBase);
749 if(pBase && !pBase->IsVisible())
750 pCnt->SetInvisible();
752 m_pMember->insert( std::unique_ptr<SwContent>(pCnt) );
753 const size_t nPos = m_pMember->size() - 1;
754 if(nOldMemberCount > nPos &&
755 (*pOldMember)[nPos]->IsInvisible()
756 != pCnt->IsInvisible())
757 *pbLevelOrVisibilityChanged = true;
760 break;
761 case ContentTypeId::POSTIT:
763 m_nMemberCount = 0;
764 m_pMember->clear();
765 SwPostItMgr* aMgr = m_pWrtShell->GetView().GetPostItMgr();
766 if (aMgr)
768 for(SwPostItMgr::const_iterator i = aMgr->begin(); i != aMgr->end(); ++i)
770 if (const SwFormatField* pFormatField = dynamic_cast<const SwFormatField *>((*i)->GetBroadcaster())) // SwPostit
772 if (pFormatField->GetTextField() && pFormatField->IsFieldInDoc() &&
773 (*i)->mLayoutStatus!=SwPostItHelper::INVISIBLE )
775 OUString sEntry = pFormatField->GetField()->GetPar2();
776 sEntry = RemoveNewline(sEntry);
777 std::unique_ptr<SwPostItContent> pCnt(new SwPostItContent(
778 this,
779 sEntry,
780 pFormatField,
781 m_nMemberCount));
782 m_pMember->insert(std::move(pCnt));
783 m_nMemberCount++;
789 break;
790 case ContentTypeId::DRAWOBJECT:
792 m_nMemberCount = 0;
793 m_pMember->clear();
795 IDocumentDrawModelAccess& rIDDMA = m_pWrtShell->getIDocumentDrawModelAccess();
796 SwDrawModel* pModel = rIDDMA.GetDrawModel();
797 if(pModel)
799 SdrPage* pPage = pModel->GetPage(0);
800 const size_t nCount = pPage->GetObjCount();
801 for( size_t i=0; i<nCount; ++i )
803 SdrObject* pTemp = pPage->GetObj(i);
804 // #i51726# - all drawing objects can be named now
805 if (!pTemp->GetName().isEmpty())
807 SwContact* pContact = static_cast<SwContact*>(pTemp->GetUserCall());
808 tools::Long nYPos = 0;
809 const Point aNullPt;
810 if(pContact && pContact->GetFormat())
811 nYPos = pContact->GetFormat()->FindLayoutRect(false, &aNullPt).Top();
812 SwContent* pCnt = new SwContent(
813 this,
814 pTemp->GetName(),
815 nYPos);
816 if(!rIDDMA.IsVisibleLayerId(pTemp->GetLayer()))
817 pCnt->SetInvisible();
818 m_pMember->insert(std::unique_ptr<SwContent>(pCnt));
819 m_nMemberCount++;
823 if (nullptr != pbLevelOrVisibilityChanged)
825 assert(pOldMember);
826 // need to check visibility (and equal entry number) after
827 // creation due to a sorted list being used here (before,
828 // entries with same index were compared already at creation
829 // time what worked before a sorted list was used)
830 *pbLevelOrVisibilityChanged = checkVisibilityChanged(
831 *pOldMember,
832 *m_pMember);
836 break;
837 default: break;
839 m_bDataValid = true;
842 namespace {
844 enum STR_CONTEXT_IDX
846 IDX_STR_OUTLINE_LEVEL = 0,
847 IDX_STR_DRAGMODE = 1,
848 IDX_STR_HYPERLINK = 2,
849 IDX_STR_LINK_REGION = 3,
850 IDX_STR_COPY_REGION = 4,
851 IDX_STR_DISPLAY = 5,
852 IDX_STR_ACTIVE_VIEW = 6,
853 IDX_STR_HIDDEN = 7,
854 IDX_STR_ACTIVE = 8,
855 IDX_STR_INACTIVE = 9,
856 IDX_STR_EDIT_ENTRY = 10,
857 IDX_STR_DELETE_ENTRY = 11,
858 IDX_STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY = 12,
859 IDX_STR_OUTLINE_TRACKING = 13,
860 IDX_STR_OUTLINE_TRACKING_DEFAULT = 14,
861 IDX_STR_OUTLINE_TRACKING_FOCUS = 15,
862 IDX_STR_OUTLINE_TRACKING_OFF = 16
867 static const char* STR_CONTEXT_ARY[] =
869 STR_OUTLINE_LEVEL,
870 STR_DRAGMODE,
871 STR_HYPERLINK,
872 STR_LINK_REGION,
873 STR_COPY_REGION,
874 STR_DISPLAY,
875 STR_ACTIVE_VIEW,
876 STR_HIDDEN,
877 STR_ACTIVE,
878 STR_INACTIVE,
879 STR_EDIT_ENTRY,
880 STR_DELETE_ENTRY,
881 STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY,
882 STR_OUTLINE_TRACKING,
883 STR_OUTLINE_TRACKING_DEFAULT,
884 STR_OUTLINE_TRACKING_FOCUS,
885 STR_OUTLINE_TRACKING_OFF
888 SwContentTree::SwContentTree(std::unique_ptr<weld::TreeView> xTreeView, SwNavigationPI* pDialog)
889 : m_xTreeView(std::move(xTreeView))
890 , m_xScratchIter(m_xTreeView->make_iterator())
891 , m_aDropTargetHelper(*this)
892 , m_xDialog(pDialog)
893 , m_sSpace(OUString(" "))
894 , m_sInvisible(SwResId(STR_INVISIBLE))
895 , m_pHiddenShell(nullptr)
896 , m_pActiveShell(nullptr)
897 , m_pConfig(SW_MOD()->GetNavigationConfig())
898 , m_nActiveBlock(0)
899 , m_nHiddenBlock(0)
900 , m_nEntryCount(0)
901 , m_nRootType(ContentTypeId::UNKNOWN)
902 , m_nLastSelType(ContentTypeId::UNKNOWN)
903 , m_nOutlineLevel(MAXLEVEL)
904 , m_eState(State::ACTIVE)
905 , m_bIsRoot(false)
906 , m_bIsIdleClear(false)
907 , m_bIsLastReadOnly(false)
908 , m_bIsOutlineMoveable(true)
909 , m_bViewHasChanged(false)
911 Size aSize(m_xDialog->LogicToPixel(Size(110, 112), MapMode(MapUnit::MapAppFont)));
912 m_xTreeView->set_size_request(aSize.Width(), aSize.Height());
914 m_xTreeView->set_help_id(HID_NAVIGATOR_TREELIST);
916 m_xTreeView->connect_expanding(LINK(this, SwContentTree, ExpandHdl));
917 m_xTreeView->connect_collapsing(LINK(this, SwContentTree, CollapseHdl));
918 m_xTreeView->connect_row_activated(LINK(this, SwContentTree, ContentDoubleClickHdl));
919 m_xTreeView->connect_changed(LINK(this, SwContentTree, SelectHdl));
920 m_xTreeView->connect_focus_in(LINK(this, SwContentTree, FocusHdl));
921 m_xTreeView->connect_key_press(LINK(this, SwContentTree, KeyInputHdl));
922 m_xTreeView->connect_popup_menu(LINK(this, SwContentTree, CommandHdl));
923 m_xTreeView->connect_query_tooltip(LINK(this, SwContentTree, QueryTooltipHdl));
924 m_xTreeView->connect_drag_begin(LINK(this, SwContentTree, DragBeginHdl));
926 for (ContentTypeId i : o3tl::enumrange<ContentTypeId>())
928 m_aActiveContentArr[i] = nullptr;
929 m_aHiddenContentArr[i] = nullptr;
931 for (int i = 0; i < CONTEXT_COUNT; ++i)
933 m_aContextStrings[i] = SwResId(STR_CONTEXT_ARY[i]);
935 m_nActiveBlock = m_pConfig->GetActiveBlock();
936 m_aUpdTimer.SetInvokeHandler(LINK(this, SwContentTree, TimerUpdate));
937 m_aUpdTimer.SetTimeout(1000);
940 SwContentTree::~SwContentTree()
942 clear(); // If applicable erase content types previously.
943 m_aUpdTimer.Stop();
944 SetActiveShell(nullptr);
945 m_xDialog.clear();
948 // Drag&Drop methods
949 IMPL_LINK(SwContentTree, DragBeginHdl, bool&, rUnsetDragIcon, bool)
951 rUnsetDragIcon = true;
953 bool bDisallow = true;
955 // don't allow if tree root is selected
956 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
957 bool bEntry = m_xTreeView->get_selected(xEntry.get());
958 if (!bEntry || lcl_IsContentType(*xEntry, *m_xTreeView))
960 return true; // disallow
963 rtl::Reference<TransferDataContainer> xContainer = new TransferDataContainer;
964 sal_Int8 nDragMode = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
966 if (FillTransferData(*xContainer, nDragMode))
967 bDisallow = false;
969 if (m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE)
971 // Only move drag entry and continuous selected siblings:
972 m_aDndOutlinesSelected.clear();
974 std::unique_ptr<weld::TreeIter> xScratch(m_xTreeView->make_iterator());
976 // Find first selected of continuous siblings
977 while (true)
979 m_xTreeView->copy_iterator(*xEntry, *xScratch);
980 if (!m_xTreeView->iter_previous_sibling(*xScratch))
981 break;
982 if (!m_xTreeView->is_selected(*xScratch))
983 break;
984 m_xTreeView->copy_iterator(*xScratch, *xEntry);
986 // Record continuous selected siblings
989 m_aDndOutlinesSelected.push_back(m_xTreeView->make_iterator(xEntry.get()));
991 while (m_xTreeView->iter_next_sibling(*xEntry) && m_xTreeView->is_selected(*xEntry));
992 bDisallow = false;
995 if (!bDisallow)
996 m_xTreeView->enable_drag_source(xContainer, nDragMode);
997 return bDisallow;
1000 SwContentTreeDropTarget::SwContentTreeDropTarget(SwContentTree& rTreeView)
1001 : DropTargetHelper(rTreeView.get_widget().get_drop_target())
1002 , m_rTreeView(rTreeView)
1006 sal_Int8 SwContentTreeDropTarget::AcceptDrop(const AcceptDropEvent& rEvt)
1008 sal_Int8 nAccept = m_rTreeView.AcceptDrop(rEvt);
1010 if (nAccept != DND_ACTION_NONE)
1012 // to enable the autoscroll when we're close to the edges
1013 weld::TreeView& rWidget = m_rTreeView.get_widget();
1014 rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
1017 return nAccept;
1020 bool SwContentTree::IsInDrag() const
1022 return m_xTreeView->get_drag_source() == m_xTreeView.get();
1025 // QueryDrop will be executed in the navigator
1026 sal_Int8 SwContentTree::AcceptDrop(const AcceptDropEvent& rEvt)
1028 sal_Int8 nRet = DND_ACTION_NONE;
1029 if( m_bIsRoot )
1031 if( m_bIsOutlineMoveable )
1032 nRet = rEvt.mnAction;
1034 else if (!IsInDrag())
1035 nRet = GetParentWindow()->AcceptDrop();
1036 return nRet;
1039 // Drop will be executed in the navigator
1040 static void* lcl_GetOutlineKey(SwContentTree& rTree, SwOutlineContent const * pContent)
1042 void* key = nullptr;
1043 if (pContent)
1045 SwWrtShell* pShell = rTree.GetWrtShell();
1046 auto const nPos = pContent->GetOutlinePos();
1048 key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
1050 return key;
1053 sal_Int8 SwContentTreeDropTarget::ExecuteDrop(const ExecuteDropEvent& rEvt)
1055 return m_rTreeView.ExecuteDrop(rEvt);
1058 sal_Int8 SwContentTree::ExecuteDrop(const ExecuteDropEvent& rEvt)
1060 std::unique_ptr<weld::TreeIter> xDropEntry(m_xTreeView->make_iterator());
1061 if (!m_xTreeView->get_dest_row_at_pos(rEvt.maPosPixel, xDropEntry.get(), true))
1062 xDropEntry.reset();
1064 if (m_nRootType == ContentTypeId::OUTLINE)
1066 if (xDropEntry && lcl_IsContent(*xDropEntry, *m_xTreeView))
1068 assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xDropEntry).toInt64())));
1069 SwOutlineContent* pOutlineContent = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xDropEntry).toInt64());
1070 assert(pOutlineContent);
1072 void* key = lcl_GetOutlineKey(*this, pOutlineContent);
1073 assert(key);
1074 if (!mOutLineNodeMap[key])
1076 while (m_xTreeView->iter_has_child(*xDropEntry))
1078 std::unique_ptr<weld::TreeIter> xChildEntry(m_xTreeView->make_iterator(xDropEntry.get()));
1079 bool bChildEntry = m_xTreeView->iter_children(*xChildEntry);
1080 while (bChildEntry)
1082 m_xTreeView->copy_iterator(*xChildEntry, *xDropEntry);
1083 bChildEntry = m_xTreeView->iter_next_sibling(*xChildEntry);
1089 SwOutlineNodes::size_type nTargetPos = 0;
1090 if (!xDropEntry)
1092 // dropped in blank space -> move to bottom
1093 nTargetPos = GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineNodesCount() - 1;
1095 else if (!lcl_IsContent(*xDropEntry, *m_xTreeView))
1097 // dropped on "heading" parent -> move to start
1098 nTargetPos = SwOutlineNodes::npos;
1100 else
1102 assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xDropEntry).toInt64())));
1103 nTargetPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xDropEntry).toInt64())->GetOutlinePos();
1106 if( MAXLEVEL > m_nOutlineLevel && // Not all layers are displayed.
1107 nTargetPos != SwOutlineNodes::npos)
1109 std::unique_ptr<weld::TreeIter> xNext(m_xTreeView->make_iterator(xDropEntry.get()));
1110 bool bNext = m_xTreeView->iter_next(*xNext);
1111 if (bNext)
1113 assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xNext).toInt64())));
1114 nTargetPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xNext).toInt64())->GetOutlinePos() - 1;
1116 else
1117 nTargetPos = GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineNodesCount() - 1;
1120 // remove the drop highlight before we change the contents of the tree so we don't
1121 // try and dereference a removed entry in post-processing drop
1122 m_xTreeView->unset_drag_dest_row();
1123 MoveOutline(nTargetPos);
1126 return IsInDrag() ? DND_ACTION_NONE : GetParentWindow()->ExecuteDrop(rEvt);
1129 namespace
1131 bool IsAllExpanded(const weld::TreeView& rContentTree, const weld::TreeIter& rEntry)
1133 if (!rContentTree.get_row_expanded(rEntry))
1134 return false;
1136 if (!rContentTree.iter_has_child(rEntry))
1137 return false;
1139 std::unique_ptr<weld::TreeIter> xChild(rContentTree.make_iterator(&rEntry));
1140 (void)rContentTree.iter_children(*xChild);
1144 if (rContentTree.iter_has_child(*xChild) || rContentTree.get_children_on_demand(*xChild))
1146 if (!IsAllExpanded(rContentTree, *xChild))
1147 return false;
1150 while (rContentTree.iter_next_sibling(*xChild));
1151 return true;
1154 void ExpandOrCollapseAll(weld::TreeView& rContentTree, weld::TreeIter& rEntry)
1156 bool bExpand = !IsAllExpanded(rContentTree, rEntry);
1157 bExpand ? rContentTree.expand_row(rEntry) : rContentTree.collapse_row(rEntry);
1158 int nRefDepth = rContentTree.get_iter_depth(rEntry);
1159 while (rContentTree.iter_next(rEntry) && rContentTree.get_iter_depth(rEntry) > nRefDepth)
1161 if (rContentTree.iter_has_child(rEntry))
1162 bExpand ? rContentTree.expand_row(rEntry) : rContentTree.collapse_row(rEntry);
1167 // Handler for Dragging and ContextMenu
1168 static bool lcl_InsertExpandCollapseAllItem(const weld::TreeView& rContentTree, const weld::TreeIter& rEntry, weld::Menu& rPop)
1170 if (rContentTree.iter_has_child(rEntry) || rContentTree.get_children_on_demand(rEntry))
1172 rPop.set_label(OString::number(800), IsAllExpanded(rContentTree, rEntry) ? SwResId(STR_COLLAPSEALL) : SwResId(STR_EXPANDALL));
1173 return false;
1175 return true;
1178 static void lcl_SetOutlineContentEntriesSensitivities(SwContentTree* pThis, const weld::TreeView& rContentTree, const weld::TreeIter& rEntry, weld::Menu& rPop)
1181 // 1512 toggle outline content visibility of the selected outline entry
1182 // 1513 make the outline content of the selected outline entry and children not visible
1183 // 1514 make the outline content of the selected entry and children visible
1184 rPop.set_sensitive(OString::number(1512), false);
1185 rPop.set_sensitive(OString::number(1513), false);
1186 rPop.set_sensitive(OString::number(1514), false);
1188 if (!pThis->GetActiveWrtShell()->GetViewOptions()->IsShowOutlineContentVisibilityButton())
1189 return;
1191 // todo: multi selection
1192 if (rContentTree.count_selected_rows() > 1)
1193 return;
1195 const SwNodes& rNodes = pThis->GetWrtShell()->GetNodes();
1196 const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
1197 size_t nOutlinePos = weld::GetAbsPos(rContentTree, rEntry);
1199 bool bIsRoot = lcl_IsContentType(rEntry, rContentTree);
1201 if (!bIsRoot)
1202 --nOutlinePos;
1204 if (nOutlinePos >= rOutlineNodes.size())
1205 return;
1207 int nFirstLevel = pThis->GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos);
1209 // determine if any concerned outline node has content
1210 bool bHasContent(false);
1211 size_t nPos = nOutlinePos;
1212 SwNode* pSttNd = rOutlineNodes[nPos];
1213 SwNode* pEndNd = &rNodes.GetEndOfContent();
1214 if (rOutlineNodes.size() > nPos + 1)
1215 pEndNd = rOutlineNodes[nPos + 1];
1217 // selected
1218 SwNodeIndex aIdx(*pSttNd);
1219 if (rNodes.GoNext(&aIdx) != pEndNd)
1220 bHasContent = true;
1222 // descendants
1223 if (!bHasContent && (rContentTree.iter_has_child(rEntry) || rContentTree.get_children_on_demand(rEntry)))
1225 while (++nPos < rOutlineNodes.size() &&
1226 (bIsRoot || pThis->GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nFirstLevel))
1228 pSttNd = rOutlineNodes[nPos];
1229 pEndNd = &rNodes.GetEndOfContent();
1230 if (rOutlineNodes.size() > nPos + 1)
1231 pEndNd = rOutlineNodes[nPos + 1];
1233 // test for content in outline node
1234 aIdx.Assign(*pSttNd);
1235 if (rNodes.GoNext(&aIdx) != pEndNd)
1237 bHasContent = true;
1238 break;
1243 if (!bHasContent)
1244 return; // no content in any of the concerned outline nodes
1247 // determine for subs if all are folded or unfolded or if they are mixed
1248 if (rContentTree.iter_has_child(rEntry) || rContentTree.get_children_on_demand(rEntry))
1250 // skip no content nodes
1251 // we know there is content from results above so this is presumably safe
1252 size_t nPos = nOutlinePos;
1253 while (true)
1255 SwNode* pSttNd = rOutlineNodes[nPos];
1256 SwNode* pEndNd = rOutlineNodes.back();
1257 if (!bIsRoot && rOutlineNodes.size() > nPos + 1)
1258 pEndNd = rOutlineNodes[nPos + 1];
1260 SwNodeIndex aIdx(*pSttNd);
1261 if (rNodes.GoNext(&aIdx) != pEndNd)
1262 break;
1263 nPos++;
1266 bool bHasFolded(!pThis->GetWrtShell()->IsOutlineContentVisible(nPos));
1267 bool bHasUnfolded(!bHasFolded);
1269 while ((++nPos < pThis->GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineNodesCount()) &&
1270 (bIsRoot || pThis->GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nFirstLevel))
1273 SwNode* pSttNd = rOutlineNodes[nPos];
1274 SwNode* pEndNd = &rNodes.GetEndOfContent();
1275 if (rOutlineNodes.size() > nPos + 1)
1276 pEndNd = rOutlineNodes[nPos + 1];
1278 SwNodeIndex aIdx(*pSttNd);
1279 if (rNodes.GoNext(&aIdx) == pEndNd)
1280 continue; // skip if no content
1282 if (!pThis->GetWrtShell()->IsOutlineContentVisible(nPos))
1283 bHasFolded = true;
1284 else
1285 bHasUnfolded = true;
1287 if (bHasFolded && bHasUnfolded)
1288 break; // mixed so no need to continue
1291 rPop.set_sensitive(OString::number(1513), bHasUnfolded);
1292 rPop.set_sensitive(OString::number(1514), bHasFolded);
1295 bIsRoot ? rPop.remove(OString::number(1512)) : rPop.set_sensitive(OString::number(1512), true);
1298 IMPL_LINK(SwContentTree, CommandHdl, const CommandEvent&, rCEvt, bool)
1300 if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
1301 return false;
1303 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), "modules/swriter/ui/navigatorcontextmenu.ui"));
1304 std::unique_ptr<weld::Menu> xPop = xBuilder->weld_menu("navmenu");
1306 bool bOutline(false);
1307 std::unique_ptr<weld::Menu> xSubPop1 = xBuilder->weld_menu("outlinelevel");
1308 std::unique_ptr<weld::Menu> xSubPop2 = xBuilder->weld_menu("dragmodemenu");
1309 std::unique_ptr<weld::Menu> xSubPop3 = xBuilder->weld_menu("displaymenu");
1310 std::unique_ptr<weld::Menu> xSubPopOutlineTracking = xBuilder->weld_menu("outlinetracking");
1312 std::unique_ptr<weld::Menu> xSubPopOutlineContent = xBuilder->weld_menu("outlinecontent");
1314 // More magic numbers, huh.
1315 xSubPopOutlineContent->append(OUString::number(1512), SwResId(STR_OUTLINE_CONTENT_VISIBILITY_TOGGLE));
1316 xSubPopOutlineContent->append(OUString::number(1513), SwResId(STR_OUTLINE_CONTENT_VISIBILITY_HIDE_ALL));
1317 xSubPopOutlineContent->append(OUString::number(1514), SwResId(STR_OUTLINE_CONTENT_VISIBILITY_SHOW_ALL));
1319 for(int i = 1; i <= 3; ++i)
1320 xSubPopOutlineTracking->append_radio(OUString::number(i + 10), m_aContextStrings[IDX_STR_OUTLINE_TRACKING + i]);
1321 xSubPopOutlineTracking->set_active(OString::number(10 + m_nOutlineTracking), true);
1323 for (int i = 1; i <= MAXLEVEL; ++i)
1324 xSubPop1->append_radio(OUString::number(i + 100), OUString::number(i));
1325 xSubPop1->set_active(OString::number(100 + m_nOutlineLevel), true);
1327 for (int i=0; i < 3; ++i)
1328 xSubPop2->append_radio(OUString::number(i + 201), m_aContextStrings[IDX_STR_HYPERLINK + i]);
1329 xSubPop2->set_active(OString::number(201 + static_cast<int>(GetParentWindow()->GetRegionDropMode())), true);
1331 // Insert the list of the open files
1332 sal_uInt16 nId = 301;
1333 const SwView* pActiveView = ::GetActiveView();
1334 SwView *pView = SwModule::GetFirstView();
1335 while (pView)
1337 OUString sInsert = pView->GetDocShell()->GetTitle();
1338 if (pView == pActiveView)
1340 sInsert += "(" +
1341 m_aContextStrings[IDX_STR_ACTIVE] +
1342 ")";
1344 xSubPop3->append_radio(OUString::number(nId), sInsert);
1345 if (State::CONSTANT == m_eState && m_pActiveShell == &pView->GetWrtShell())
1346 xSubPop3->set_active(OString::number(nId), true);
1347 pView = SwModule::GetNextView(pView);
1348 nId++;
1350 xSubPop3->append_radio(OUString::number(nId++), m_aContextStrings[IDX_STR_ACTIVE_VIEW]);
1351 if (m_pHiddenShell)
1353 OUString sHiddenEntry = m_pHiddenShell->GetView().GetDocShell()->GetTitle() +
1354 " ( " +
1355 m_aContextStrings[IDX_STR_HIDDEN] +
1356 " )";
1357 xSubPop3->append_radio(OUString::number(nId), sHiddenEntry);
1360 if (State::ACTIVE == m_eState)
1361 xSubPop3->set_active(OString::number(--nId), true);
1362 else if (State::HIDDEN == m_eState)
1363 xSubPop3->set_active(OString::number(nId), true);
1365 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
1366 if (!m_xTreeView->get_selected(xEntry.get()))
1367 xEntry.reset();
1369 if (State::HIDDEN == m_eState || !xEntry || !lcl_IsContent(*xEntry, *m_xTreeView))
1370 xPop->remove(OString::number(900)); // go to
1372 bool bRemovePostItEntries = true;
1373 bool bRemoveIndexEntries = true;
1374 bool bRemoveEditEntry = true;
1375 bool bRemoveUnprotectEntry = true;
1376 bool bRemoveDeleteEntry = true;
1377 bool bRemoveRenameEntry = true;
1378 bool bRemoveSelectEntry = true;
1379 bool bRemoveToggleExpandEntry = true;
1380 bool bRemoveChapterEntries = true;
1381 bool bRemoveSendOutlineEntry = true;
1383 // Edit only if the shown content is coming from the current view.
1384 if (State::HIDDEN != m_eState &&
1385 (State::ACTIVE == m_eState || m_pActiveShell == pActiveView->GetWrtShellPtr())
1386 && xEntry && lcl_IsContent(*xEntry, *m_xTreeView))
1388 assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
1389 const SwContentType* pContType = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetParent();
1390 const ContentTypeId nContentType = pContType->GetType();
1391 const bool bReadonly = m_pActiveShell->GetView().GetDocShell()->IsReadOnly();
1392 const bool bVisible = !reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->IsInvisible();
1393 const bool bProtected = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->IsProtect();
1394 const bool bProtectBM = (ContentTypeId::BOOKMARK == nContentType)
1395 && m_pActiveShell->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS);
1396 const bool bEditable = pContType->IsEditable() &&
1397 ((bVisible && !bProtected && !bProtectBM) || ContentTypeId::REGION == nContentType);
1398 const bool bDeletable = pContType->IsDeletable() &&
1399 ((bVisible && !bProtected && !bProtectBM) || ContentTypeId::REGION == nContentType);
1400 const bool bRenamable = bEditable && !bReadonly &&
1401 (ContentTypeId::TABLE == nContentType ||
1402 ContentTypeId::FRAME == nContentType ||
1403 ContentTypeId::GRAPHIC == nContentType ||
1404 ContentTypeId::OLE == nContentType ||
1405 (ContentTypeId::BOOKMARK == nContentType && !bProtectBM) ||
1406 ContentTypeId::REGION == nContentType ||
1407 ContentTypeId::INDEX == nContentType ||
1408 ContentTypeId::DRAWOBJECT == nContentType);
1410 if(ContentTypeId::OUTLINE == nContentType)
1412 bOutline = true;
1413 lcl_SetOutlineContentEntriesSensitivities(this, *m_xTreeView, *xEntry, *xSubPopOutlineContent);
1414 bRemoveToggleExpandEntry = lcl_InsertExpandCollapseAllItem(*m_xTreeView, *xEntry, *xPop);
1415 if (!bReadonly)
1417 bRemoveSelectEntry = false;
1418 bRemoveChapterEntries = false;
1421 else if (!bReadonly && (bEditable || bDeletable))
1423 if(ContentTypeId::INDEX == nContentType)
1425 bRemoveIndexEntries = false;
1427 const SwTOXBase* pBase = reinterpret_cast<SwTOXBaseContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetTOXBase();
1428 if (!pBase->IsTOXBaseInReadonly())
1429 bRemoveEditEntry = false;
1431 xPop->set_active(OString::number(405), SwEditShell::IsTOXBaseReadonly(*pBase));
1432 bRemoveDeleteEntry = false;
1434 else if(ContentTypeId::TABLE == nContentType)
1436 bRemoveSelectEntry = false;
1437 bRemoveEditEntry = false;
1438 bRemoveUnprotectEntry = false;
1439 bool bFull = false;
1440 OUString sTableName = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetName();
1441 bool bProt = m_pActiveShell->HasTableAnyProtection( &sTableName, &bFull );
1442 xPop->set_sensitive(OString::number(403), !bFull);
1443 xPop->set_sensitive(OString::number(404), bProt);
1444 bRemoveDeleteEntry = false;
1446 else if(ContentTypeId::DRAWOBJECT == nContentType)
1448 bRemoveDeleteEntry = false;
1450 else if(ContentTypeId::REGION == nContentType)
1452 bRemoveSelectEntry = false;
1453 bRemoveEditEntry = false;
1455 else
1457 if (bEditable && bDeletable)
1459 bRemoveEditEntry = false;
1460 bRemoveDeleteEntry = false;
1462 else if (bEditable)
1463 bRemoveEditEntry = false;
1464 else if (bDeletable)
1466 bRemoveDeleteEntry = false;
1469 //Rename object
1470 if (bRenamable)
1471 bRemoveRenameEntry = false;
1474 else if (xEntry)
1476 const SwContentType* pType;
1477 if (lcl_IsContentType(*xEntry, *m_xTreeView))
1478 pType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xEntry).toInt64());
1479 else
1480 pType = reinterpret_cast<SwContent*>(
1481 m_xTreeView->get_id(*xEntry).toInt64())->GetParent();
1482 if (pType)
1484 if (ContentTypeId::OUTLINE == pType->GetType())
1486 bOutline = true;
1487 if (State::HIDDEN != m_eState)
1489 lcl_SetOutlineContentEntriesSensitivities(this, *m_xTreeView, *xEntry,
1490 *xSubPopOutlineContent);
1491 bRemoveSendOutlineEntry = false;
1493 bRemoveToggleExpandEntry = lcl_InsertExpandCollapseAllItem(*m_xTreeView, *xEntry,
1494 *xPop);
1496 if (State::HIDDEN != m_eState &&
1497 pType->GetType() == ContentTypeId::POSTIT &&
1498 !m_pActiveShell->GetView().GetDocShell()->IsReadOnly() &&
1499 pType->GetMemberCount() > 0)
1500 bRemovePostItEntries = false;
1504 if (bRemoveToggleExpandEntry)
1506 xPop->remove("separator3");
1507 xPop->remove(OString::number(800));
1510 if (bRemoveSelectEntry)
1511 xPop->remove(OString::number(805));
1513 if (bRemoveChapterEntries)
1515 xPop->remove("separator2");
1516 xPop->remove(OString::number(806));
1517 xPop->remove(OString::number(801));
1518 xPop->remove(OString::number(802));
1519 xPop->remove(OString::number(803));
1520 xPop->remove(OString::number(804));
1523 if (bRemoveSendOutlineEntry)
1524 xPop->remove(OString::number(700));
1526 if (bRemovePostItEntries)
1528 xPop->remove(OString::number(600));
1529 xPop->remove(OString::number(601));
1530 xPop->remove(OString::number(602));
1533 if (bRemoveDeleteEntry)
1534 xPop->remove(OString::number(501));
1536 if (bRemoveRenameEntry)
1537 xPop->remove(OString::number(502));
1539 if (bRemoveIndexEntries)
1541 xPop->remove(OString::number(401));
1542 xPop->remove(OString::number(402));
1543 xPop->remove(OString::number(405));
1546 if (bRemoveUnprotectEntry)
1547 xPop->remove(OString::number(404));
1549 if (bRemoveEditEntry)
1550 xPop->remove(OString::number(403));
1552 if (bRemoveToggleExpandEntry &&
1553 bRemoveSelectEntry &&
1554 bRemoveChapterEntries &&
1555 bRemoveSendOutlineEntry &&
1556 bRemovePostItEntries &&
1557 bRemoveDeleteEntry &&
1558 bRemoveRenameEntry &&
1559 bRemoveIndexEntries &&
1560 bRemoveUnprotectEntry &&
1561 bRemoveEditEntry)
1563 xPop->remove("separator1");
1566 if (!bOutline)
1568 xSubPop1.reset();
1569 xPop->remove(OString::number(1)); // outline level menu
1571 if (!bOutline || State::HIDDEN == m_eState)
1573 xSubPopOutlineTracking.reset();
1574 xPop->remove(OString::number(4)); // outline tracking menu
1576 if (!bOutline || State::HIDDEN == m_eState ||
1577 !m_pActiveShell->GetViewOptions()->IsShowOutlineContentVisibilityButton() ||
1578 m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount() == 0)
1580 xSubPopOutlineContent.reset();
1581 xPop->remove(OString::number(5)); // outline content menu
1582 xPop->remove("separator1511");
1585 OString sCommand = xPop->popup_at_rect(m_xTreeView.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
1586 if (!sCommand.isEmpty())
1587 ExecuteContextMenuAction(sCommand);
1589 return true;
1592 void SwContentTree::insert(const weld::TreeIter* pParent, const OUString& rStr, const OUString& rId,
1593 bool bChildrenOnDemand, weld::TreeIter* pRet)
1595 m_xTreeView->insert(pParent, -1, &rStr, &rId, nullptr, nullptr, bChildrenOnDemand, pRet);
1596 ++m_nEntryCount;
1599 void SwContentTree::remove(const weld::TreeIter& rIter)
1601 if (m_xTreeView->iter_has_child(rIter))
1603 std::unique_ptr<weld::TreeIter> xChild = m_xTreeView->make_iterator(&rIter);
1604 (void)m_xTreeView->iter_children(*xChild);
1605 remove(*xChild);
1607 m_xTreeView->remove(rIter);
1608 --m_nEntryCount;
1611 // Content will be integrated into the Box only on demand.
1612 bool SwContentTree::RequestingChildren(const weld::TreeIter& rParent)
1614 bool bChild = m_xTreeView->iter_has_child(rParent);
1615 if (bChild || !m_xTreeView->get_children_on_demand(rParent))
1616 return bChild;
1618 // Is this a content type?
1619 if (lcl_IsContentType(rParent, *m_xTreeView))
1621 std::unique_ptr<weld::TreeIter> xChild = m_xTreeView->make_iterator();
1623 assert(dynamic_cast<SwContentType*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(rParent).toInt64())));
1624 SwContentType* pCntType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(rParent).toInt64());
1626 const size_t nCount = pCntType->GetMemberCount();
1627 // Add for outline plus/minus
1628 if (pCntType->GetType() == ContentTypeId::OUTLINE)
1630 for(size_t i = 0; i < nCount; ++i)
1632 const SwContent* pCnt = pCntType->GetMember(i);
1633 if(pCnt)
1635 const auto nLevel = static_cast<const SwOutlineContent*>(pCnt)->GetOutlineLevel();
1636 OUString sEntry = pCnt->GetName();
1637 if(sEntry.isEmpty())
1638 sEntry = m_sSpace;
1639 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pCnt)));
1640 if (!bChild || (nLevel == 0))
1642 insert(&rParent, sEntry, sId, false, xChild.get());
1643 m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible());
1644 m_xTreeView->set_extra_row_indent(*xChild, nLevel + 1 - m_xTreeView->get_iter_depth(*xChild));
1645 bChild = true;
1647 else
1649 //back search parent.
1650 if(static_cast<const SwOutlineContent*>(pCntType->GetMember(i-1))->GetOutlineLevel() < nLevel)
1652 insert(xChild.get(), sEntry, sId, false, xChild.get());
1653 m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible());
1654 m_xTreeView->set_extra_row_indent(*xChild, nLevel + 1 - m_xTreeView->get_iter_depth(*xChild));
1655 bChild = true;
1657 else
1659 bChild = m_xTreeView->iter_previous(*xChild);
1660 assert(!bChild || lcl_IsContentType(*xChild, *m_xTreeView) || dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xChild).toInt64())));
1661 while (bChild &&
1662 lcl_IsContent(*xChild, *m_xTreeView) &&
1663 (reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xChild).toInt64())->GetOutlineLevel() >= nLevel)
1666 bChild = m_xTreeView->iter_previous(*xChild);
1668 if (bChild)
1670 insert(xChild.get(), sEntry, sId, false, xChild.get());
1671 m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible());
1672 m_xTreeView->set_extra_row_indent(*xChild, nLevel + 1 - m_xTreeView->get_iter_depth(*xChild));
1679 else
1681 bool bRegion = pCntType->GetType() == ContentTypeId::REGION;
1682 for(size_t i = 0; i < nCount; ++i)
1684 const SwContent* pCnt = pCntType->GetMember(i);
1685 if (pCnt)
1687 OUString sEntry = pCnt->GetName();
1688 if (sEntry.isEmpty())
1689 sEntry = m_sSpace;
1690 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pCnt)));
1691 insert(&rParent, sEntry, sId, false, xChild.get());
1692 m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible());
1693 if (bRegion)
1694 m_xTreeView->set_extra_row_indent(*xChild, static_cast<const SwRegionContent*>(pCnt)->GetRegionLevel());
1695 bChild = true;
1701 return bChild;
1704 SdrObject* SwContentTree::GetDrawingObjectsByContent(const SwContent *pCnt)
1706 SdrObject *pRetObj = nullptr;
1707 switch(pCnt->GetParent()->GetType())
1709 case ContentTypeId::DRAWOBJECT:
1711 SdrView* pDrawView = m_pActiveShell->GetDrawView();
1712 if (pDrawView)
1714 SwDrawModel* pDrawModel = m_pActiveShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
1715 SdrPage* pPage = pDrawModel->GetPage(0);
1716 const size_t nCount = pPage->GetObjCount();
1718 for( size_t i=0; i<nCount; ++i )
1720 SdrObject* pTemp = pPage->GetObj(i);
1721 if( pTemp->GetName() == pCnt->GetName())
1723 pRetObj = pTemp;
1724 break;
1728 break;
1730 default:
1731 pRetObj = nullptr;
1733 return pRetObj;
1736 void SwContentTree::Expand(const weld::TreeIter& rParent, std::vector<std::unique_ptr<weld::TreeIter>>* pNodesToExpand)
1738 if (!(m_xTreeView->iter_has_child(rParent) || m_xTreeView->get_children_on_demand(rParent)))
1739 return;
1741 if (!m_bIsRoot
1742 || (lcl_IsContentType(rParent, *m_xTreeView) &&
1743 reinterpret_cast<SwContentType*>(m_xTreeView->get_id(rParent).toInt64())->GetType() == ContentTypeId::OUTLINE)
1744 || (m_nRootType == ContentTypeId::OUTLINE))
1746 if (lcl_IsContentType(rParent, *m_xTreeView))
1748 SwContentType* pCntType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(rParent).toInt64());
1749 const sal_Int32 nOr = 1 << static_cast<int>(pCntType->GetType()); //linear -> Bitposition
1750 if (State::HIDDEN != m_eState)
1752 m_nActiveBlock |= nOr;
1753 m_pConfig->SetActiveBlock(m_nActiveBlock);
1755 else
1756 m_nHiddenBlock |= nOr;
1757 if (pCntType->GetType() == ContentTypeId::OUTLINE)
1759 std::map< void*, bool > aCurrOutLineNodeMap;
1761 SwWrtShell* pShell = GetWrtShell();
1762 bool bParentHasChild = RequestingChildren(rParent);
1763 if (pNodesToExpand)
1764 pNodesToExpand->emplace_back(m_xTreeView->make_iterator(&rParent));
1765 if (bParentHasChild)
1767 std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(&rParent));
1768 bool bChild = m_xTreeView->iter_next(*xChild);
1769 while (bChild && lcl_IsContent(*xChild, *m_xTreeView))
1771 if (m_xTreeView->iter_has_child(*xChild))
1773 assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xChild).toInt64())));
1774 auto const nPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xChild).toInt64())->GetOutlinePos();
1775 void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
1776 aCurrOutLineNodeMap.emplace( key, false );
1777 std::map<void*, bool>::iterator iter = mOutLineNodeMap.find( key );
1778 if( iter != mOutLineNodeMap.end() && mOutLineNodeMap[key])
1780 aCurrOutLineNodeMap[key] = true;
1781 RequestingChildren(*xChild);
1782 if (pNodesToExpand)
1783 pNodesToExpand->emplace_back(m_xTreeView->make_iterator(xChild.get()));
1784 m_xTreeView->set_children_on_demand(*xChild, false);
1787 bChild = m_xTreeView->iter_next(*xChild);
1790 mOutLineNodeMap = aCurrOutLineNodeMap;
1791 return;
1794 else
1796 if (lcl_IsContent(rParent, *m_xTreeView))
1798 SwWrtShell* pShell = GetWrtShell();
1799 // paranoid assert now that outline type is checked
1800 assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(rParent).toInt64())));
1801 auto const nPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(rParent).toInt64())->GetOutlinePos();
1802 void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
1803 mOutLineNodeMap[key] = true;
1808 RequestingChildren(rParent);
1809 if (pNodesToExpand)
1810 pNodesToExpand->emplace_back(m_xTreeView->make_iterator(&rParent));
1813 IMPL_LINK(SwContentTree, ExpandHdl, const weld::TreeIter&, rParent, bool)
1815 Expand(rParent, nullptr);
1816 return true;
1819 IMPL_LINK(SwContentTree, CollapseHdl, const weld::TreeIter&, rParent, bool)
1821 if (!m_xTreeView->iter_has_child(rParent) || m_xTreeView->get_children_on_demand(rParent))
1822 return true;
1824 if (lcl_IsContentType(rParent, *m_xTreeView))
1826 if (m_bIsRoot)
1828 // collapse to children of root node
1829 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(&rParent));
1830 if (m_xTreeView->iter_children(*xEntry))
1834 m_xTreeView->collapse_row(*xEntry);
1836 while (m_xTreeView->iter_next(*xEntry));
1838 return false; // return false to notify caller not to do collapse
1840 SwContentType* pCntType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(rParent).toInt64());
1841 const sal_Int32 nAnd = ~(1 << static_cast<int>(pCntType->GetType()));
1842 if (State::HIDDEN != m_eState)
1844 m_nActiveBlock &= nAnd;
1845 m_pConfig->SetActiveBlock(m_nActiveBlock);
1847 else
1848 m_nHiddenBlock &= nAnd;
1850 else if (lcl_IsContent(rParent, *m_xTreeView))
1852 SwWrtShell* pShell = GetWrtShell();
1853 assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(rParent).toInt64())));
1854 auto const nPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(rParent).toInt64())->GetOutlinePos();
1855 void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
1856 mOutLineNodeMap[key] = false;
1859 return true;
1862 // Also on double click will be initially opened only.
1863 IMPL_LINK_NOARG(SwContentTree, ContentDoubleClickHdl, weld::TreeView&, bool)
1865 bool bConsumed = false;
1867 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
1868 bool bEntry = m_xTreeView->get_cursor(xEntry.get());
1869 // Is it a content type?
1870 OSL_ENSURE(bEntry, "no current entry!");
1871 if (bEntry)
1873 if (lcl_IsContentType(*xEntry, *m_xTreeView) && !m_xTreeView->iter_has_child(*xEntry))
1875 RequestingChildren(*xEntry);
1876 m_xTreeView->set_children_on_demand(*xEntry, false);
1878 else if (!lcl_IsContentType(*xEntry, *m_xTreeView) && (State::HIDDEN != m_eState))
1880 if (State::CONSTANT == m_eState)
1882 m_pActiveShell->GetView().GetViewFrame()->GetWindow().ToTop();
1884 //Jump to content type:
1885 assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
1886 SwContent* pCnt = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64());
1887 assert(pCnt && "no UserData");
1888 GotoContent(pCnt);
1889 // fdo#36308 don't expand outlines on double-click
1890 bConsumed = pCnt->GetParent()->GetType() == ContentTypeId::OUTLINE;
1894 return bConsumed; // false/true == allow/disallow more to be done, i.e. expand/collapse children
1897 namespace
1899 OUString GetImageIdForContentTypeId(ContentTypeId eType)
1901 OUString sResId;
1903 switch (eType)
1905 case ContentTypeId::OUTLINE:
1906 sResId = RID_BMP_NAVI_OUTLINE;
1907 break;
1908 case ContentTypeId::TABLE:
1909 sResId = RID_BMP_NAVI_TABLE;
1910 break;
1911 case ContentTypeId::FRAME:
1912 sResId = RID_BMP_NAVI_FRAME;
1913 break;
1914 case ContentTypeId::GRAPHIC:
1915 sResId = RID_BMP_NAVI_GRAPHIC;
1916 break;
1917 case ContentTypeId::OLE:
1918 sResId = RID_BMP_NAVI_OLE;
1919 break;
1920 case ContentTypeId::BOOKMARK:
1921 sResId = RID_BMP_NAVI_BOOKMARK;
1922 break;
1923 case ContentTypeId::REGION:
1924 sResId = RID_BMP_NAVI_REGION;
1925 break;
1926 case ContentTypeId::URLFIELD:
1927 sResId = RID_BMP_NAVI_URLFIELD;
1928 break;
1929 case ContentTypeId::REFERENCE:
1930 sResId = RID_BMP_NAVI_REFERENCE;
1931 break;
1932 case ContentTypeId::INDEX:
1933 sResId = RID_BMP_NAVI_INDEX;
1934 break;
1935 case ContentTypeId::POSTIT:
1936 sResId = RID_BMP_NAVI_POSTIT;
1937 break;
1938 case ContentTypeId::DRAWOBJECT:
1939 sResId = RID_BMP_NAVI_DRAWOBJECT;
1940 break;
1941 case ContentTypeId::UNKNOWN:
1942 SAL_WARN("sw.ui", "ContentTypeId::UNKNOWN has no bitmap preview");
1943 break;
1946 return sResId;
1950 size_t SwContentTree::GetAbsPos(const weld::TreeIter& rIter)
1952 return weld::GetAbsPos(*m_xTreeView, rIter);
1955 size_t SwContentTree::GetEntryCount() const
1957 return m_nEntryCount;
1960 size_t SwContentTree::GetChildCount(const weld::TreeIter& rParent) const
1962 if (!m_xTreeView->iter_has_child(rParent))
1963 return 0;
1965 std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rParent));
1967 size_t nCount = 0;
1968 auto nRefDepth = m_xTreeView->get_iter_depth(*xParent);
1969 auto nActDepth = nRefDepth;
1972 if (!m_xTreeView->iter_next(*xParent))
1973 xParent.reset();
1974 else
1975 nActDepth = m_xTreeView->get_iter_depth(*xParent);
1976 nCount++;
1977 } while(xParent && nRefDepth < nActDepth);
1979 nCount--;
1980 return nCount;
1983 std::unique_ptr<weld::TreeIter> SwContentTree::GetEntryAtAbsPos(size_t nAbsPos) const
1985 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
1986 if (!m_xTreeView->get_iter_first(*xEntry))
1987 xEntry.reset();
1989 while (nAbsPos && xEntry)
1991 if (!m_xTreeView->iter_next(*xEntry))
1992 xEntry.reset();
1993 nAbsPos--;
1995 return xEntry;
1998 void SwContentTree::Display( bool bActive )
2000 // First read the selected entry to select it later again if necessary
2001 // -> the user data here are no longer valid!
2002 std::unique_ptr<weld::TreeIter> xOldSelEntry(m_xTreeView->make_iterator());
2003 if (!m_xTreeView->get_selected(xOldSelEntry.get()))
2004 xOldSelEntry.reset();
2005 OUString sEntryName; // Name of the entry
2006 size_t nEntryRelPos = 0; // relative position to their parent
2007 size_t nOldEntryCount = GetEntryCount();
2008 sal_Int32 nOldScrollPos = 0;
2009 if (xOldSelEntry)
2011 UpdateLastSelType();
2013 nOldScrollPos = m_xTreeView->vadjustment_get_value();
2014 sEntryName = m_xTreeView->get_text(*xOldSelEntry);
2015 std::unique_ptr<weld::TreeIter> xParentEntry = m_xTreeView->make_iterator(xOldSelEntry.get());
2016 while (m_xTreeView->get_iter_depth(*xParentEntry))
2017 m_xTreeView->iter_parent(*xParentEntry);
2018 if (m_xTreeView->get_iter_depth(*xOldSelEntry))
2019 nEntryRelPos = GetAbsPos(*xOldSelEntry) - GetAbsPos(*xParentEntry);
2022 clear();
2024 if (!bActive)
2025 m_eState = State::HIDDEN;
2026 else if (State::HIDDEN == m_eState)
2027 m_eState = State::ACTIVE;
2028 SwWrtShell* pShell = GetWrtShell();
2029 const bool bReadOnly = !pShell || pShell->GetView().GetDocShell()->IsReadOnly();
2030 if(bReadOnly != m_bIsLastReadOnly)
2032 m_bIsLastReadOnly = bReadOnly;
2033 bool bDisable = pShell == nullptr || bReadOnly;
2034 SwNavigationPI* pNavi = GetParentWindow();
2035 pNavi->m_xContent6ToolBox->set_item_sensitive("chapterup", !bDisable);
2036 pNavi->m_xContent6ToolBox->set_item_sensitive("chapterdown", !bDisable);
2037 pNavi->m_xContent6ToolBox->set_item_sensitive("promote", !bDisable);
2038 pNavi->m_xContent6ToolBox->set_item_sensitive("demote", !bDisable);
2039 pNavi->m_xContent5ToolBox->set_item_sensitive("reminder", !bDisable);
2042 if (pShell)
2044 std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
2045 std::unique_ptr<weld::TreeIter> xSelEntry;
2046 std::vector<std::unique_ptr<weld::TreeIter>> aNodesToExpand;
2047 // all content navigation view
2048 if(m_nRootType == ContentTypeId::UNKNOWN)
2050 m_xTreeView->freeze();
2052 for( ContentTypeId nCntType : o3tl::enumrange<ContentTypeId>() )
2054 std::unique_ptr<SwContentType>& rpContentT = bActive ?
2055 m_aActiveContentArr[nCntType] :
2056 m_aHiddenContentArr[nCntType];
2057 if(!rpContentT)
2058 rpContentT.reset(new SwContentType(pShell, nCntType, m_nOutlineLevel ));
2060 OUString aImage(GetImageIdForContentTypeId(nCntType));
2061 bool bChOnDemand = 0 != rpContentT->GetMemberCount();
2062 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(rpContentT.get())));
2063 insert(nullptr, rpContentT->GetName(), sId, bChOnDemand, xEntry.get());
2064 m_xTreeView->set_image(*xEntry, aImage);
2066 m_xTreeView->set_sensitive(*xEntry, bChOnDemand);
2068 if (nCntType == m_nLastSelType)
2069 xSelEntry = m_xTreeView->make_iterator(xEntry.get());
2070 sal_Int32 nExpandOptions = (State::HIDDEN == m_eState)
2071 ? m_nHiddenBlock
2072 : m_nActiveBlock;
2073 if (nExpandOptions & (1 << static_cast<int>(nCntType)))
2075 // fill contents of to-be expanded entries while frozen
2076 Expand(*xEntry, &aNodesToExpand);
2077 m_xTreeView->set_children_on_demand(*xEntry, false);
2081 m_xTreeView->thaw();
2083 // restore visual expanded tree state
2084 for (const auto& rNode : aNodesToExpand)
2085 m_xTreeView->expand_row(*rNode);
2087 (void)m_xTreeView->get_iter_first(*xEntry);
2088 for (ContentTypeId nCntType : o3tl::enumrange<ContentTypeId>())
2090 sal_Int32 nExpandOptions = (State::HIDDEN == m_eState)
2091 ? m_nHiddenBlock
2092 : m_nActiveBlock;
2093 if (nExpandOptions & (1 << static_cast<int>(nCntType)))
2095 if (nEntryRelPos && nCntType == m_nLastSelType)
2097 // reselect the entry
2098 std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(xEntry.get()));
2099 std::unique_ptr<weld::TreeIter> xTemp;
2100 sal_uLong nPos = 1;
2101 while (m_xTreeView->iter_next(*xChild))
2103 // The old text will be slightly favored
2104 if (sEntryName == m_xTreeView->get_text(*xChild) ||
2105 nPos == nEntryRelPos)
2107 m_xTreeView->copy_iterator(*xChild, *xSelEntry);
2108 break;
2110 xTemp = m_xTreeView->make_iterator(xChild.get());
2111 nPos++;
2113 if (!xSelEntry || lcl_IsContentType(*xSelEntry, *m_xTreeView))
2114 xSelEntry = std::move(xTemp);
2118 (void)m_xTreeView->iter_next_sibling(*xEntry);
2121 if (!xSelEntry)
2123 nOldScrollPos = 0;
2124 xSelEntry = m_xTreeView->make_iterator();
2125 if (!m_xTreeView->get_iter_first(*xSelEntry))
2126 xSelEntry.reset();
2129 if (xSelEntry)
2131 m_xTreeView->set_cursor(*xSelEntry);
2132 Select();
2135 // root content navigation view
2136 else
2138 m_xTreeView->freeze();
2140 std::unique_ptr<SwContentType>& rpRootContentT = bActive ?
2141 m_aActiveContentArr[m_nRootType] :
2142 m_aHiddenContentArr[m_nRootType];
2143 if(!rpRootContentT)
2144 rpRootContentT.reset(new SwContentType(pShell, m_nRootType, m_nOutlineLevel ));
2145 OUString aImage(GetImageIdForContentTypeId(m_nRootType));
2146 bool bChOnDemand = m_nRootType == ContentTypeId::OUTLINE;
2147 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(rpRootContentT.get())));
2148 insert(nullptr, rpRootContentT->GetName(), sId, bChOnDemand, xEntry.get());
2149 m_xTreeView->set_image(*xEntry, aImage);
2151 if (!bChOnDemand)
2153 bool bRegion = rpRootContentT->GetType() == ContentTypeId::REGION;
2155 std::unique_ptr<weld::TreeIter> xChild = m_xTreeView->make_iterator();
2156 for (size_t i = 0; i < rpRootContentT->GetMemberCount(); ++i)
2158 const SwContent* pCnt = rpRootContentT->GetMember(i);
2159 if (pCnt)
2161 OUString sEntry = pCnt->GetName();
2162 if(sEntry.isEmpty())
2163 sEntry = m_sSpace;
2164 OUString sSubId(OUString::number(reinterpret_cast<sal_Int64>(pCnt)));
2165 insert(xEntry.get(), sEntry, sSubId, false, xChild.get());
2166 m_xTreeView->set_sensitive(*xChild, !pCnt->IsInvisible());
2167 if (bRegion)
2168 m_xTreeView->set_extra_row_indent(*xChild, static_cast<const SwRegionContent*>(pCnt)->GetRegionLevel());
2172 else
2174 // fill contents of to-be expanded entries while frozen
2175 Expand(*xEntry, &aNodesToExpand);
2176 m_xTreeView->set_children_on_demand(*xEntry, false);
2179 m_xTreeView->set_sensitive(*xEntry, m_xTreeView->iter_has_child(*xEntry));
2181 m_xTreeView->thaw();
2183 if (bChOnDemand)
2185 // restore visual expanded tree state
2186 for (const auto& rNode : aNodesToExpand)
2187 m_xTreeView->expand_row(*rNode);
2189 else
2190 m_xTreeView->expand_row(*xEntry);
2192 // reselect the entry
2193 if (nEntryRelPos)
2195 std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(xEntry.get()));
2196 sal_uLong nPos = 1;
2197 while (m_xTreeView->iter_next(*xChild))
2199 // The old text will be slightly favored
2200 if (sEntryName == m_xTreeView->get_text(*xChild) || nPos == nEntryRelPos)
2202 xSelEntry = std::move(xChild);
2203 break;
2205 nPos++;
2207 if (xSelEntry)
2209 m_xTreeView->set_cursor(*xSelEntry); // unselect all entries, make pSelEntry visible, and select
2210 Select();
2213 else
2215 m_xTreeView->set_cursor(*xEntry);
2216 Select();
2221 if (!m_bIgnoreViewChange && GetEntryCount() == nOldEntryCount)
2223 m_xTreeView->vadjustment_set_value(nOldScrollPos);
2227 void SwContentTree::clear()
2229 m_xTreeView->freeze();
2230 m_xTreeView->clear();
2231 m_nEntryCount = 0;
2232 m_xTreeView->thaw();
2235 bool SwContentTree::FillTransferData( TransferDataContainer& rTransfer,
2236 sal_Int8& rDragMode )
2238 bool bRet = false;
2239 SwWrtShell* pWrtShell = GetWrtShell();
2240 OSL_ENSURE(pWrtShell, "no Shell!");
2242 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
2243 bool bEntry = m_xTreeView->get_cursor(xEntry.get());
2244 if (!bEntry || lcl_IsContentType(*xEntry, *m_xTreeView) || !pWrtShell)
2245 return false;
2246 OUString sEntry;
2247 assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
2248 SwContent* pCnt = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64());
2250 const ContentTypeId nActType = pCnt->GetParent()->GetType();
2251 OUString sUrl;
2252 bool bOutline = false;
2253 OUString sOutlineText;
2254 switch( nActType )
2256 case ContentTypeId::OUTLINE:
2258 const SwOutlineNodes::size_type nPos = static_cast<SwOutlineContent*>(pCnt)->GetOutlinePos();
2259 OSL_ENSURE(nPos < pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount(),
2260 "outlinecnt changed");
2262 // make sure outline may actually be copied
2263 if( pWrtShell->IsOutlineCopyable( nPos ) )
2265 const SwNumRule* pOutlRule = pWrtShell->GetOutlineNumRule();
2266 const SwTextNode* pTextNd =
2267 pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNode(nPos);
2268 if (pTextNd && pOutlRule && pTextNd->IsNumbered(pWrtShell->GetLayout()))
2270 SwNumberTree::tNumberVector aNumVector =
2271 pTextNd->GetNumberVector(pWrtShell->GetLayout());
2272 for( int nLevel = 0;
2273 nLevel <= pTextNd->GetActualListLevel();
2274 nLevel++ )
2276 const SwNumberTree::tSwNumTreeNumber nVal = aNumVector[nLevel] + 1;
2277 sEntry += OUString::number( nVal - pOutlRule->Get(nLevel).GetStart() ) + ".";
2280 sEntry += pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineText(nPos, pWrtShell->GetLayout(), false);
2281 sOutlineText = pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineText(nPos, pWrtShell->GetLayout());
2282 m_bIsOutlineMoveable = static_cast<SwOutlineContent*>(pCnt)->IsMoveable();
2283 bOutline = true;
2286 break;
2287 case ContentTypeId::POSTIT:
2288 case ContentTypeId::INDEX:
2289 case ContentTypeId::REFERENCE :
2290 // cannot be inserted, neither as URL nor as section
2291 break;
2292 case ContentTypeId::URLFIELD:
2293 sUrl = static_cast<SwURLFieldContent*>(pCnt)->GetURL();
2294 [[fallthrough]];
2295 case ContentTypeId::OLE:
2296 case ContentTypeId::GRAPHIC:
2297 if(GetParentWindow()->GetRegionDropMode() != RegionMode::NONE)
2298 break;
2299 else
2300 rDragMode &= ~( DND_ACTION_MOVE | DND_ACTION_LINK );
2301 [[fallthrough]];
2302 default:
2303 sEntry = m_xTreeView->get_text(*xEntry);
2306 if(!sEntry.isEmpty())
2308 const SwDocShell* pDocShell = pWrtShell->GetView().GetDocShell();
2309 if(sUrl.isEmpty())
2311 if(pDocShell->HasName())
2313 SfxMedium* pMedium = pDocShell->GetMedium();
2314 sUrl = pMedium->GetURLObject().GetURLNoMark();
2315 // only if a primarily link shall be integrated.
2316 bRet = true;
2318 else if ( nActType == ContentTypeId::REGION || nActType == ContentTypeId::BOOKMARK )
2320 // For field and bookmarks a link is also allowed
2321 // without a filename into its own document.
2322 bRet = true;
2324 else if (State::CONSTANT == m_eState &&
2325 ( !::GetActiveView() ||
2326 m_pActiveShell != ::GetActiveView()->GetWrtShellPtr()))
2328 // Urls of inactive views cannot dragged without
2329 // file names, also.
2330 bRet = false;
2332 else
2334 bRet = GetParentWindow()->GetRegionDropMode() == RegionMode::NONE;
2335 rDragMode = DND_ACTION_MOVE;
2338 const OUString& rToken = pCnt->GetParent()->GetTypeToken();
2339 sUrl += "#" + sEntry;
2340 if(!rToken.isEmpty())
2342 sUrl += OUStringChar(cMarkSeparator) + rToken;
2345 else
2346 bRet = true;
2348 if( bRet )
2350 // In Outlines of heading text must match
2351 // the real number into the description.
2352 if(bOutline)
2353 sEntry = sOutlineText;
2356 NaviContentBookmark aBmk( sUrl, sEntry,
2357 GetParentWindow()->GetRegionDropMode(),
2358 pDocShell);
2359 aBmk.Copy( rTransfer );
2362 // An INetBookmark must a be delivered to foreign DocShells
2363 if( pDocShell->HasName() )
2365 INetBookmark aBkmk( sUrl, sEntry );
2366 rTransfer.CopyINetBookmark( aBkmk );
2370 return bRet;
2373 void SwContentTree::ToggleToRoot()
2375 if(!m_bIsRoot)
2377 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
2378 bool bEntry = m_xTreeView->get_cursor(xEntry.get());
2379 if (bEntry)
2381 const SwContentType* pCntType;
2382 if (lcl_IsContentType(*xEntry, *m_xTreeView))
2384 assert(dynamic_cast<SwContentType*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
2385 pCntType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xEntry).toInt64());
2387 else
2389 assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
2390 pCntType = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetParent();
2392 m_nRootType = pCntType->GetType();
2393 m_bIsRoot = true;
2394 Display(State::HIDDEN != m_eState);
2395 if (m_nRootType == ContentTypeId::OUTLINE)
2397 m_xTreeView->set_selection_mode(SelectionMode::Multiple);
2401 else
2403 m_xTreeView->set_selection_mode(SelectionMode::Single);
2404 m_nRootType = ContentTypeId::UNKNOWN;
2405 m_bIsRoot = false;
2406 FindActiveTypeAndRemoveUserData();
2407 Display(State::HIDDEN != m_eState);
2409 m_pConfig->SetRootType( m_nRootType );
2410 weld::Toolbar* pBox = GetParentWindow()->m_xContent5ToolBox.get();
2411 pBox->set_item_active("root", m_bIsRoot);
2414 bool SwContentTree::HasContentChanged()
2416 bool bContentChanged = false;
2418 // - Run through the local array and the Treelistbox in parallel.
2419 // - Are the records not expanded, they are discarded only in the array
2420 // and the content type will be set as the new UserData.
2421 // - Is the root mode is active only this will be updated.
2423 // Valid for the displayed content types is:
2424 // the Memberlist will be erased and the membercount will be updated
2425 // If content will be checked, the memberlists will be replenished
2426 // at the same time. Once a difference occurs it will be only replenished
2427 // no longer checked. Finally, the box is filled again.
2429 // bVisibilityChanged gets set to true if some element, like a section,
2430 // changed visibility and should have its name rerendered with a new
2431 // grayed-out state
2432 bool bVisibilityChanged = false;
2434 if (State::HIDDEN == m_eState)
2436 for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
2438 if(m_aActiveContentArr[i])
2439 m_aActiveContentArr[i]->Invalidate();
2442 // root content navigation view
2443 else if(m_bIsRoot)
2445 std::unique_ptr<weld::TreeIter> xRootEntry(m_xTreeView->make_iterator());
2446 if (!m_xTreeView->get_iter_first(*xRootEntry))
2447 bContentChanged = true;
2448 else
2450 assert(dynamic_cast<SwContentType*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xRootEntry).toInt64())));
2451 const ContentTypeId nType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xRootEntry).toInt64())->GetType();
2452 SwContentType* pArrType = m_aActiveContentArr[nType].get();
2453 if (!pArrType)
2454 bContentChanged = true;
2455 else
2457 // start check if first selected outline level has changed
2458 bool bCheckChanged = m_nRootType == ContentTypeId::OUTLINE && !m_xTreeView->has_focus();
2459 if (bCheckChanged)
2461 std::unique_ptr<weld::TreeIter> xFirstSel(m_xTreeView->make_iterator());
2462 bool bFirstSel = m_xTreeView->get_selected(xFirstSel.get());
2463 if (bFirstSel && lcl_IsContent(*xFirstSel, *m_xTreeView))
2465 assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xFirstSel).toInt64())));
2466 const auto nSelLevel = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xFirstSel).toInt64())->GetOutlineLevel();
2467 SwWrtShell* pSh = GetWrtShell();
2468 const SwOutlineNodes::size_type nOutlinePos = pSh->GetOutlinePos(MAXLEVEL);
2469 if (nOutlinePos != SwOutlineNodes::npos && pSh->getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos) != nSelLevel)
2470 bContentChanged = true;
2473 // end check if first selected outline level has changed
2475 pArrType->Init(&bVisibilityChanged);
2476 pArrType->FillMemberList();
2477 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pArrType)));
2478 m_xTreeView->set_id(*xRootEntry, sId);
2479 if (!bContentChanged)
2481 const size_t nChildCount = GetChildCount(*xRootEntry);
2482 if (nChildCount != pArrType->GetMemberCount())
2483 bContentChanged = true;
2484 else
2486 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(xRootEntry.get()));
2487 for (size_t j = 0; j < nChildCount; ++j)
2489 m_xTreeView->iter_next(*xEntry);
2490 const SwContent* pCnt = pArrType->GetMember(j);
2491 OUString sSubId(OUString::number(reinterpret_cast<sal_Int64>(pCnt)));
2492 m_xTreeView->set_id(*xEntry, sSubId);
2493 OUString sEntryText = m_xTreeView->get_text(*xEntry);
2494 if( sEntryText != pCnt->GetName() &&
2495 !(sEntryText == m_sSpace && pCnt->GetName().isEmpty()))
2496 bContentChanged = true;
2503 // all content navigation view
2504 else
2506 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
2507 bool bEntry = m_xTreeView->get_iter_first(*xEntry);
2508 while (bEntry)
2510 bool bNext = true; // at least a next must be
2511 assert(dynamic_cast<SwContentType*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
2512 SwContentType* pCntType = reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xEntry).toInt64());
2513 const size_t nCntCount = pCntType->GetMemberCount();
2514 const ContentTypeId nType = pCntType->GetType();
2515 SwContentType* pArrType = m_aActiveContentArr[nType].get();
2516 if (!pArrType)
2517 bContentChanged = true;
2518 else
2520 pArrType->Init(&bVisibilityChanged);
2521 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pArrType)));
2522 m_xTreeView->set_id(*xEntry, sId);
2523 if (m_xTreeView->get_row_expanded(*xEntry))
2525 bool bLevelOrVisibilityChanged = false;
2526 // bLevelOrVisibilityChanged is set if outlines have changed their level
2527 // or if the visibility of objects (frames, sections, tables) has changed
2528 // i.e. in header/footer
2529 pArrType->FillMemberList(&bLevelOrVisibilityChanged);
2530 const size_t nChildCount = GetChildCount(*xEntry);
2531 if (bLevelOrVisibilityChanged)
2533 if (nType == ContentTypeId::OUTLINE)
2534 bContentChanged = true;
2535 else
2536 bVisibilityChanged = true;
2539 if(nChildCount != pArrType->GetMemberCount())
2540 bContentChanged = true;
2541 else
2543 for(size_t j = 0; j < nChildCount; ++j)
2545 bEntry = m_xTreeView->iter_next(*xEntry);
2546 bNext = false;
2547 const SwContent* pCnt = pArrType->GetMember(j);
2548 OUString sSubId(OUString::number(reinterpret_cast<sal_Int64>(pCnt)));
2549 m_xTreeView->set_id(*xEntry, sSubId);
2550 OUString sEntryText = m_xTreeView->get_text(*xEntry);
2551 if( sEntryText != pCnt->GetName() &&
2552 !(sEntryText == m_sSpace && pCnt->GetName().isEmpty()))
2553 bContentChanged = true;
2557 // not expanded and has children
2558 else if (m_xTreeView->iter_has_child(*xEntry))
2560 // was the entry once opened, then must also the
2561 // invisible records be examined.
2562 // At least the user data must be updated.
2563 bool bLevelOrVisibilityChanged = false;
2564 // bLevelOrVisibilityChanged is set if outlines have changed their level
2565 // or if the visibility of objects (frames, sections, tables) has changed
2566 // i.e. in header/footer
2567 pArrType->FillMemberList(&bLevelOrVisibilityChanged);
2568 bool bRemoveChildren = false;
2569 const size_t nOldChildCount = GetChildCount(*xEntry);
2570 const size_t nNewChildCount = pArrType->GetMemberCount();
2571 if (nOldChildCount != nNewChildCount)
2573 bRemoveChildren = true;
2575 else
2577 std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(xEntry.get()));
2578 (void)m_xTreeView->iter_children(*xChild);
2579 for (size_t j = 0; j < nOldChildCount; ++j)
2581 const SwContent* pCnt = pArrType->GetMember(j);
2582 OUString sSubId(OUString::number(reinterpret_cast<sal_Int64>(pCnt)));
2583 m_xTreeView->set_id(*xChild, sSubId);
2584 OUString sEntryText = m_xTreeView->get_text(*xChild);
2585 if( sEntryText != pCnt->GetName() &&
2586 !(sEntryText == m_sSpace && pCnt->GetName().isEmpty()))
2587 bRemoveChildren = true;
2588 (void)m_xTreeView->iter_next(*xChild);
2591 if (bRemoveChildren)
2593 std::unique_ptr<weld::TreeIter> xRemove(m_xTreeView->make_iterator(xEntry.get()));
2594 while (m_xTreeView->iter_children(*xRemove))
2596 remove(*xRemove);
2597 m_xTreeView->copy_iterator(*xEntry, *xRemove);
2599 m_xTreeView->set_children_on_demand(*xEntry, nNewChildCount != 0);
2602 else if((nCntCount != 0)
2603 != (pArrType->GetMemberCount()!=0))
2605 bContentChanged = true;
2608 // The Root-Entry has to be found now
2609 while (bEntry && (bNext || m_xTreeView->get_iter_depth(*xEntry)))
2611 bEntry = m_xTreeView->iter_next(*xEntry);
2612 bNext = false;
2617 if (!bContentChanged && bVisibilityChanged)
2618 m_aUpdTimer.Start();
2620 return bContentChanged || bVisibilityChanged;
2623 void SwContentTree::UpdateLastSelType()
2625 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
2626 if (m_xTreeView->get_selected(xEntry.get()))
2628 while (m_xTreeView->get_iter_depth(*xEntry))
2629 m_xTreeView->iter_parent(*xEntry);
2630 sal_Int64 nId = m_xTreeView->get_id(*xEntry).toInt64();
2631 if (nId && lcl_IsContentType(*xEntry, *m_xTreeView))
2633 assert(dynamic_cast<SwContentType*>(reinterpret_cast<SwTypeNumber*>(nId)));
2634 m_nLastSelType = reinterpret_cast<SwContentType*>(nId)->GetType();
2639 void SwContentTree::FindActiveTypeAndRemoveUserData()
2641 UpdateLastSelType();
2643 // If clear is called by TimerUpdate:
2644 // Only for root can the validity of the UserData be guaranteed.
2645 m_xTreeView->all_foreach([this](weld::TreeIter& rEntry){
2646 m_xTreeView->set_id(rEntry, "");
2647 return false;
2651 void SwContentTree::SetHiddenShell(SwWrtShell* pSh)
2653 m_pHiddenShell = pSh;
2654 m_eState = State::HIDDEN;
2655 FindActiveTypeAndRemoveUserData();
2656 for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
2658 m_aHiddenContentArr[i].reset();
2660 Display(false);
2662 GetParentWindow()->UpdateListBox();
2665 void SwContentTree::SetActiveShell(SwWrtShell* pSh)
2667 bool bClear = m_pActiveShell != pSh;
2668 if (State::ACTIVE == m_eState && bClear)
2670 if (m_pActiveShell)
2671 EndListening(*m_pActiveShell->GetView().GetDocShell());
2672 m_pActiveShell = pSh;
2673 FindActiveTypeAndRemoveUserData();
2674 clear();
2676 else if (State::CONSTANT == m_eState)
2678 if (m_pActiveShell)
2679 EndListening(*m_pActiveShell->GetView().GetDocShell());
2680 m_pActiveShell = pSh;
2681 m_eState = State::ACTIVE;
2682 bClear = true;
2684 // Only if it is the active view, the array will be deleted and
2685 // the screen filled new.
2686 if (State::ACTIVE == m_eState && bClear)
2688 if (m_pActiveShell)
2689 StartListening(*m_pActiveShell->GetView().GetDocShell());
2690 FindActiveTypeAndRemoveUserData();
2691 for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
2693 m_aActiveContentArr[i].reset();
2695 Display(true);
2699 void SwContentTree::SetConstantShell(SwWrtShell* pSh)
2701 if (m_pActiveShell)
2702 EndListening(*m_pActiveShell->GetView().GetDocShell());
2703 m_pActiveShell = pSh;
2704 m_eState = State::CONSTANT;
2705 StartListening(*m_pActiveShell->GetView().GetDocShell());
2706 FindActiveTypeAndRemoveUserData();
2707 for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
2709 m_aActiveContentArr[i].reset();
2711 Display(true);
2714 void SwContentTree::Notify(SfxBroadcaster & rBC, SfxHint const& rHint)
2716 SfxViewEventHint const*const pVEHint(dynamic_cast<SfxViewEventHint const*>(&rHint));
2717 SwXTextView* pDyingShell = nullptr;
2718 if (m_pActiveShell && pVEHint && pVEHint->GetEventName() == "OnViewClosed")
2719 pDyingShell = dynamic_cast<SwXTextView*>(pVEHint->GetController().get());
2720 if (pDyingShell && pDyingShell->GetView() == &m_pActiveShell->GetView())
2722 SetActiveShell(nullptr); // our view is dying, clear our pointers to it
2724 else
2726 SfxListener::Notify(rBC, rHint);
2728 switch (rHint.GetId())
2730 case SfxHintId::SwNavigatorUpdateTracking:
2731 UpdateTracking();
2732 break;
2733 case SfxHintId::SwNavigatorSelectOutlinesWithSelections:
2735 if (m_nRootType == ContentTypeId::OUTLINE)
2737 SelectOutlinesWithSelection();
2738 // make first selected entry visible
2739 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
2740 if (xEntry && m_xTreeView->get_selected(xEntry.get()))
2741 m_xTreeView->scroll_to_row(*xEntry);
2743 else if (m_nRootType == ContentTypeId::UNKNOWN)
2744 m_xTreeView->unselect_all();
2745 break;
2747 case SfxHintId::DocChanged:
2748 if (!m_bIgnoreViewChange)
2750 m_bViewHasChanged = true;
2751 TimerUpdate(&m_aUpdTimer);
2753 break;
2754 case SfxHintId::ModeChanged:
2755 if (SwWrtShell* pShell = GetWrtShell())
2757 const bool bReadOnly = pShell->GetView().GetDocShell()->IsReadOnly();
2758 if (bReadOnly != m_bIsLastReadOnly)
2760 m_bIsLastReadOnly = bReadOnly;
2762 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
2763 if (m_xTreeView->get_cursor(xEntry.get()))
2765 m_xTreeView->select(*xEntry);
2766 Select();
2768 else
2769 m_xTreeView->unselect_all();
2772 break;
2773 default:
2774 break;
2778 void SwContentTree::ExecCommand(std::string_view rCmd, bool bOutlineWithChildren)
2780 const bool bUp = rCmd == "chapterup";
2781 const bool bUpDown = bUp || rCmd == "chapterdown";
2782 const bool bLeft = rCmd == "promote";
2783 const bool bLeftRight = bLeft || rCmd == "demote";
2784 if (!bUpDown && !bLeftRight)
2785 return;
2786 if (GetWrtShell()->GetView().GetDocShell()->IsReadOnly() ||
2787 (State::ACTIVE != m_eState &&
2788 (State::CONSTANT != m_eState || m_pActiveShell != GetParentWindow()->GetCreateView()->GetWrtShellPtr())))
2790 return;
2793 m_bIgnoreViewChange = true;
2795 SwWrtShell *const pShell = GetWrtShell();
2796 sal_Int8 nActOutlineLevel = m_nOutlineLevel;
2797 SwOutlineNodes::size_type nActPos = pShell->GetOutlinePos(nActOutlineLevel);
2799 std::vector<SwTextNode*> selectedOutlineNodes;
2800 std::vector<std::unique_ptr<weld::TreeIter>> selected;
2802 m_xTreeView->selected_foreach([this, pShell, &bLeftRight, &bOutlineWithChildren, &selected, &selectedOutlineNodes](weld::TreeIter& rEntry){
2803 // it's possible to select the root node too which is a really bad idea
2804 bool bSkip = lcl_IsContentType(rEntry, *m_xTreeView);
2805 // filter out children of selected parents so they don't get promoted
2806 // or moved twice (except if there is Ctrl modifier, since in that
2807 // case children are re-parented)
2808 if ((bLeftRight || bOutlineWithChildren) && !selected.empty())
2810 std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rEntry));
2811 for (bool bParent = m_xTreeView->iter_parent(*xParent); bParent; bParent = m_xTreeView->iter_parent(*xParent))
2813 if (m_xTreeView->iter_compare(*selected.back(), *xParent) == 0)
2815 bSkip = true;
2816 break;
2820 if (!bSkip)
2822 selected.emplace_back(m_xTreeView->make_iterator(&rEntry));
2823 const SwNodes& rNodes = pShell->GetNodes();
2824 const size_t nPos = GetAbsPos(rEntry) - 1;
2825 if (nPos < rNodes.GetOutLineNds().size())
2827 SwNode* pNode = rNodes.GetOutLineNds()[ nPos ];
2828 if (pNode)
2830 selectedOutlineNodes.push_back(pNode->GetTextNode());
2834 return false;
2837 if (bUpDown && !bUp)
2838 { // to move down, start at the end!
2839 std::reverse(selected.begin(), selected.end());
2842 SwOutlineNodes::difference_type nDirLast = bUp ? -1 : 1;
2843 bool bStartedAction = false;
2844 std::vector<SwNode*> aOutlineNdsArray;
2845 for (auto const& pCurrentEntry : selected)
2847 assert(pCurrentEntry && lcl_IsContent(*pCurrentEntry, *m_xTreeView));
2848 if (lcl_IsContent(*pCurrentEntry, *m_xTreeView))
2850 assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*pCurrentEntry).toInt64())));
2851 if ((m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE) ||
2852 reinterpret_cast<SwContent*>(m_xTreeView->get_id(*pCurrentEntry).toInt64())->GetParent()->GetType()
2853 == ContentTypeId::OUTLINE)
2855 nActPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*pCurrentEntry).toInt64())->GetOutlinePos();
2858 if (nActPos == SwOutlineNodes::npos || (bUpDown && !pShell->IsOutlineMovable(nActPos)))
2860 continue;
2863 if (!bStartedAction)
2865 pShell->StartAllAction();
2866 if (bUpDown)
2868 if (pShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
2870 // make all outline nodes content visible before move
2871 // restore outline nodes content visible state after move
2872 SwOutlineNodes rOutlineNds = pShell->GetDoc()->GetNodes().GetOutLineNds();
2873 for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos)
2875 SwNode* pNd = rOutlineNds[nPos];
2876 if (pNd->IsTextNode()) // should always be true
2878 bool bOutlineContentVisibleAttr = true;
2879 pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
2880 if (!bOutlineContentVisibleAttr)
2882 aOutlineNdsArray.push_back(pNd);
2883 pShell->ToggleOutlineContentVisibility(nPos);
2889 pShell->StartUndo(bLeftRight ? SwUndoId::OUTLINE_LR : SwUndoId::OUTLINE_UD);
2890 bStartedAction = true;
2892 pShell->GotoOutline( nActPos); // If text selection != box selection
2893 pShell->Push();
2894 pShell->MakeOutlineSel(nActPos, nActPos, bOutlineWithChildren);
2895 if (bUpDown)
2897 const size_t nEntryAbsPos(GetAbsPos(*pCurrentEntry));
2898 SwOutlineNodes::difference_type nDir = bUp ? -1 : 1;
2899 if (!bOutlineWithChildren && ((nDir == -1 && nActPos > 0) ||
2900 (nDir == 1 && nEntryAbsPos < GetEntryCount() - 2)))
2902 pShell->MoveOutlinePara( nDir );
2903 // Set cursor back to the current position
2904 pShell->GotoOutline( nActPos + nDir);
2906 else if (bOutlineWithChildren)
2908 SwOutlineNodes::size_type nActEndPos = nActPos;
2909 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pCurrentEntry.get()));
2910 assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*pCurrentEntry).toInt64())));
2911 const auto nActLevel = reinterpret_cast<SwOutlineContent*>(
2912 m_xTreeView->get_id(*pCurrentEntry).toInt64())->GetOutlineLevel();
2913 bool bEntry = m_xTreeView->iter_next(*xEntry);
2914 while (bEntry && lcl_IsContent(*xEntry, *m_xTreeView))
2916 assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
2917 if (nActLevel >= reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlineLevel())
2918 break;
2919 nActEndPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlinePos();
2920 bEntry = m_xTreeView->iter_next(*xEntry);
2922 if (nDir == 1) // move down
2924 std::unique_ptr<weld::TreeIter> xNextSibling(m_xTreeView->make_iterator(pCurrentEntry.get()));
2925 if (m_xTreeView->iter_next_sibling(*xNextSibling) && m_xTreeView->is_selected(*xNextSibling))
2926 nDir = nDirLast;
2927 else
2929 // If the last entry is to be moved we're done
2930 if (bEntry && lcl_IsContent(*xEntry, *m_xTreeView))
2932 // xEntry now points to the entry following the last
2933 // selected entry.
2934 SwOutlineNodes::size_type nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlinePos();
2935 // here needs to found the next entry after next.
2936 // The selection must be inserted in front of that.
2937 while (bEntry)
2939 bEntry = m_xTreeView->iter_next(*xEntry);
2940 assert(!bEntry || !lcl_IsContent(*xEntry, *m_xTreeView)||
2941 dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
2942 // nDest++ may only executed if bEntry
2943 if (bEntry)
2945 if (!lcl_IsContent(*xEntry, *m_xTreeView))
2946 break;
2947 else if (nActLevel >= reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlineLevel())
2949 // nDest needs adjusted if there are selected entries (including ancestral lineage)
2950 // immediately before the current moved entry.
2951 std::unique_ptr<weld::TreeIter> xTmp(m_xTreeView->make_iterator(xEntry.get()));
2952 bool bTmp = m_xTreeView->iter_previous(*xTmp);
2953 while (bTmp && lcl_IsContent(*xTmp, *m_xTreeView) &&
2954 nActLevel < reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlineLevel())
2956 while (bTmp && lcl_IsContent(*xTmp, *m_xTreeView) && !m_xTreeView->is_selected(*xTmp) &&
2957 nActLevel < reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlineLevel())
2959 bTmp = m_xTreeView->iter_parent(*xTmp);
2961 if (!bTmp || !m_xTreeView->is_selected(*xTmp))
2962 break;
2963 bTmp = m_xTreeView->iter_previous(*xTmp);
2964 nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlinePos();
2966 std::unique_ptr<weld::TreeIter> xPrevSibling(m_xTreeView->make_iterator(xEntry.get()));
2967 if (!m_xTreeView->iter_previous_sibling(*xPrevSibling) || !m_xTreeView->is_selected(*xPrevSibling))
2968 break;
2970 else
2972 nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlinePos();
2976 nDirLast = nDir = nDest - nActEndPos;
2977 // If no entry was found that allows insertion before
2978 // it, we just move it to the end.
2980 else
2981 nDirLast = nDir = 0;
2984 else // move up
2986 std::unique_ptr<weld::TreeIter> xPrevSibling(m_xTreeView->make_iterator(pCurrentEntry.get()));
2987 if (m_xTreeView->iter_previous_sibling(*xPrevSibling) && m_xTreeView->is_selected(*xPrevSibling))
2988 nDir = nDirLast;
2989 else
2991 SwOutlineNodes::size_type nDest = nActPos;
2992 bEntry = true;
2993 m_xTreeView->copy_iterator(*pCurrentEntry, *xEntry);
2994 while (bEntry && nDest)
2996 bEntry = m_xTreeView->iter_previous(*xEntry);
2997 assert(!bEntry || !lcl_IsContent(*xEntry, *m_xTreeView) ||
2998 dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
2999 if (bEntry && lcl_IsContent(*xEntry, *m_xTreeView))
3001 nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlinePos();
3003 else
3005 nDest = 0; // presumably?
3007 if (bEntry)
3009 if (!lcl_IsContent(*xEntry, *m_xTreeView))
3010 break;
3011 else if (nActLevel >= reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetOutlineLevel())
3013 // nDest needs adjusted if there are selected entries immediately
3014 // after the level change.
3015 std::unique_ptr<weld::TreeIter> xTmp(m_xTreeView->make_iterator(xEntry.get()));
3016 bool bTmp = m_xTreeView->iter_next(*xTmp);
3017 while (bTmp && lcl_IsContent(*xTmp, *m_xTreeView) &&
3018 nActLevel < reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlineLevel() &&
3019 m_xTreeView->is_selected(*xTmp))
3021 nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlinePos();
3022 const auto nLevel = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlineLevel();
3023 // account for selected entries' descendent lineage
3024 bTmp = m_xTreeView->iter_next(*xTmp);
3025 while (bTmp && lcl_IsContent(*xTmp, *m_xTreeView) &&
3026 nLevel < reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlineLevel())
3028 nDest = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xTmp).toInt64())->GetOutlinePos();
3029 bTmp = m_xTreeView->iter_next(*xTmp);
3032 break;
3036 nDirLast = nDir = nDest - nActPos;
3039 if (nDir)
3041 pShell->MoveOutlinePara( nDir );
3042 // Set cursor back to the current position
3043 pShell->GotoOutline(nActPos + nDir);
3047 else
3049 if (!pShell->IsProtectedOutlinePara())
3050 pShell->OutlineUpDown(bLeft ? -1 : 1);
3053 pShell->ClearMark();
3054 pShell->Pop(SwCursorShell::PopMode::DeleteCurrent); // Cursor is now back at the current heading.
3057 if (bStartedAction)
3059 pShell->EndUndo();
3060 if (bUpDown)
3062 if (pShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
3064 // restore state of outline content visibility to before move
3065 for (SwNode* pNd : aOutlineNdsArray)
3066 pShell->ToggleOutlineContentVisibility(pNd, true);
3069 pShell->EndAllAction();
3070 if (m_aActiveContentArr[ContentTypeId::OUTLINE])
3071 m_aActiveContentArr[ContentTypeId::OUTLINE]->Invalidate();
3073 // clear all selections to prevent the Display function from trying to reselect selected entries
3074 m_xTreeView->unselect_all();
3075 Display(true);
3077 // reselect entries
3078 const SwOutlineNodes::size_type nCurrPos = pShell->GetOutlinePos(MAXLEVEL);
3079 std::unique_ptr<weld::TreeIter> xListEntry(m_xTreeView->make_iterator());
3080 bool bListEntry = m_xTreeView->get_iter_first(*xListEntry);
3081 while ((bListEntry = m_xTreeView->iter_next(*xListEntry)) && lcl_IsContent(*xListEntry, *m_xTreeView))
3083 assert(dynamic_cast<SwOutlineContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xListEntry).toInt64())));
3084 if (reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xListEntry).toInt64())->GetOutlinePos() == nCurrPos)
3086 std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(xListEntry.get()));
3087 if (m_xTreeView->iter_parent(*xParent) && !m_xTreeView->get_row_expanded(*xParent))
3088 m_xTreeView->expand_row(*xParent);
3089 m_xTreeView->set_cursor(*xListEntry); // unselect all entries, make entry visible, set focus, and select
3090 Select();
3091 break;
3095 if (m_bIsRoot)
3097 const SwOutlineNodes& rOutLineNds = pShell->GetNodes().GetOutLineNds();
3098 for (SwTextNode* pNode : selectedOutlineNodes)
3100 SwOutlineNodes::const_iterator aFndIt = rOutLineNds.find(pNode);
3101 if(aFndIt == rOutLineNds.end())
3102 continue;
3103 const size_t nFndPos = aFndIt - rOutLineNds.begin();
3104 std::unique_ptr<weld::TreeIter> xEntry = GetEntryAtAbsPos(nFndPos + 1);
3105 if (xEntry)
3107 m_xTreeView->select(*xEntry);
3108 std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(xEntry.get()));
3109 if (m_xTreeView->iter_parent(*xParent) && !m_xTreeView->get_row_expanded(*xParent))
3110 m_xTreeView->expand_row(*xParent);
3115 m_bIgnoreViewChange = false;
3118 void SwContentTree::ShowTree()
3120 m_xTreeView->show();
3121 m_aUpdTimer.Start();
3124 void SwContentTree::HideTree()
3126 // folded together will not be idled
3127 m_aUpdTimer.Stop();
3128 m_xTreeView->hide();
3131 static void lcl_SelectByContentTypeAndName(SwContentTree* pThis, weld::TreeView& rContentTree,
3132 std::u16string_view rContentTypeName, std::u16string_view rName)
3134 if (!rName.empty())
3136 // find content type entry
3137 std::unique_ptr<weld::TreeIter> xIter(rContentTree.make_iterator());
3138 bool bFoundEntry = rContentTree.get_iter_first(*xIter);
3139 while (bFoundEntry && rContentTypeName != rContentTree.get_text(*xIter))
3140 bFoundEntry = rContentTree.iter_next_sibling(*xIter);
3141 // find content type content entry and select it
3142 if (bFoundEntry)
3144 rContentTree.expand_row(*xIter); // assure content type entry is expanded
3145 while (rContentTree.iter_next(*xIter) && lcl_IsContent(*xIter, rContentTree))
3147 if (rName == rContentTree.get_text(*xIter))
3149 // get first selected for comparison
3150 std::unique_ptr<weld::TreeIter> xFirstSelected(rContentTree.make_iterator());
3151 if (!rContentTree.get_selected(xFirstSelected.get()))
3152 xFirstSelected.reset();
3153 if (rContentTree.count_selected_rows() != 1 ||
3154 rContentTree.iter_compare(*xIter, *xFirstSelected) != 0)
3156 // unselect all entries and make passed entry visible and selected
3157 rContentTree.set_cursor(*xIter);
3158 pThis->Select();
3160 break;
3167 /** No idle with focus or while dragging */
3168 IMPL_LINK_NOARG(SwContentTree, TimerUpdate, Timer *, void)
3170 // No update while focus is not in document.
3171 // No update while drag and drop.
3172 // Query view because the Navigator is cleared too late.
3173 SwView* pView = GetParentWindow()->GetCreateView();
3174 if(pView && pView->GetWrtShellPtr() && pView->GetWrtShellPtr()->GetWin() &&
3175 (pView->GetWrtShellPtr()->GetWin()->HasFocus() || m_bViewHasChanged) &&
3176 !IsInDrag() && !pView->GetWrtShellPtr()->ActionPend())
3178 m_bViewHasChanged = false;
3179 m_bIsIdleClear = false;
3180 SwWrtShell* pActShell = pView->GetWrtShellPtr();
3181 if (State::CONSTANT == m_eState && !lcl_FindShell(m_pActiveShell))
3183 SetActiveShell(pActShell);
3184 GetParentWindow()->UpdateListBox();
3187 if (State::ACTIVE == m_eState && pActShell != GetWrtShell())
3189 SetActiveShell(pActShell);
3191 else if ((State::ACTIVE == m_eState || (State::CONSTANT == m_eState && pActShell == GetWrtShell())) &&
3192 HasContentChanged())
3194 FindActiveTypeAndRemoveUserData();
3195 Display(true);
3198 UpdateTracking();
3200 else if (!pView && State::ACTIVE == m_eState && !m_bIsIdleClear)
3202 if(m_pActiveShell)
3204 SetActiveShell(nullptr);
3206 clear();
3207 m_bIsIdleClear = true;
3211 void SwContentTree::UpdateTracking()
3213 if (State::HIDDEN == m_eState || !m_pActiveShell)
3214 return;
3216 // m_bIgnoreViewChange is set on delete
3217 if (m_bIgnoreViewChange)
3219 m_bIgnoreViewChange = false;
3220 return;
3223 // drawing
3224 if ((m_pActiveShell->GetSelectionType() & (SelectionType::DrawObject |
3225 SelectionType::DrawObjectEditMode |
3226 SelectionType::DbForm)) &&
3227 !(m_bIsRoot && m_nRootType != ContentTypeId::DRAWOBJECT))
3229 SdrView* pSdrView = m_pActiveShell->GetDrawView();
3230 if(pSdrView && 1 == pSdrView->GetMarkedObjectCount())
3232 SdrObject* pSelected = pSdrView->GetMarkedObjectByIndex(0);
3233 OUString aName(pSelected->GetName());
3234 lcl_SelectByContentTypeAndName(this, *m_xTreeView,
3235 SwResId(STR_CONTENT_TYPE_DRAWOBJECT), aName);
3237 return;
3239 // graphic, frame, and ole
3240 OUString aContentTypeName;
3241 if (m_pActiveShell->GetSelectionType() == SelectionType::Graphic &&
3242 !(m_bIsRoot && m_nRootType != ContentTypeId::GRAPHIC))
3243 aContentTypeName = SwResId(STR_CONTENT_TYPE_GRAPHIC);
3244 else if (m_pActiveShell->GetSelectionType() == SelectionType::Frame &&
3245 !(m_bIsRoot && m_nRootType != ContentTypeId::FRAME))
3246 aContentTypeName = SwResId(STR_CONTENT_TYPE_FRAME);
3247 else if (m_pActiveShell->GetSelectionType() == SelectionType::Ole &&
3248 !(m_bIsRoot && m_nRootType != ContentTypeId::OLE))
3249 aContentTypeName = SwResId(STR_CONTENT_TYPE_OLE);
3250 if (!aContentTypeName.isEmpty())
3252 OUString aName(m_pActiveShell->GetFlyName());
3253 lcl_SelectByContentTypeAndName(this, *m_xTreeView, aContentTypeName, aName);
3254 return;
3256 // table
3257 if (m_pActiveShell->IsCursorInTable() &&
3258 !(m_bIsRoot && m_nRootType != ContentTypeId::TABLE))
3260 if(m_pActiveShell->GetTableFormat())
3262 OUString aName = m_pActiveShell->GetTableFormat()->GetName();
3263 lcl_SelectByContentTypeAndName(this, *m_xTreeView, SwResId(STR_CONTENT_TYPE_TABLE),
3264 aName);
3266 return;
3268 // outline
3269 // find out where the cursor is
3270 const SwOutlineNodes::size_type nActPos = GetWrtShell()->GetOutlinePos(MAXLEVEL);
3271 if (!((m_bIsRoot && m_nRootType != ContentTypeId::OUTLINE) ||
3272 m_nOutlineTracking == 3 || nActPos == SwOutlineNodes::npos))
3274 // assure outline content type is expanded
3275 // this assumes outline content type is first in treeview
3276 std::unique_ptr<weld::TreeIter> xFirstEntry(m_xTreeView->make_iterator());
3277 if (m_xTreeView->get_iter_first(*xFirstEntry))
3278 m_xTreeView->expand_row(*xFirstEntry);
3280 m_xTreeView->all_foreach([this, nActPos](weld::TreeIter& rEntry){
3281 bool bRet = false;
3282 if (lcl_IsContent(rEntry, *m_xTreeView) && reinterpret_cast<SwContent*>(
3283 m_xTreeView->get_id(rEntry).toInt64())->GetParent()->GetType() ==
3284 ContentTypeId::OUTLINE)
3286 if (reinterpret_cast<SwOutlineContent*>(
3287 m_xTreeView->get_id(rEntry).toInt64())->GetOutlinePos() == nActPos)
3289 std::unique_ptr<weld::TreeIter> xFirstSelected(
3290 m_xTreeView->make_iterator());
3291 if (!m_xTreeView->get_selected(xFirstSelected.get()))
3292 xFirstSelected.reset();
3293 // only select if not already selected or tree has multiple entries selected
3294 if (m_xTreeView->count_selected_rows() != 1 ||
3295 m_xTreeView->iter_compare(rEntry, *xFirstSelected) != 0)
3297 if (m_nOutlineTracking == 2) // focused outline tracking
3299 // collapse to children of root node
3300 std::unique_ptr<weld::TreeIter> xChildEntry(
3301 m_xTreeView->make_iterator());
3302 if (m_xTreeView->get_iter_first(*xChildEntry) &&
3303 m_xTreeView->iter_children(*xChildEntry))
3307 if (reinterpret_cast<SwContent*>(
3308 m_xTreeView->get_id(*xChildEntry).toInt64())->
3309 GetParent()->GetType() == ContentTypeId::OUTLINE)
3310 m_xTreeView->collapse_row(*xChildEntry);
3311 else
3312 break;
3314 while (m_xTreeView->iter_next(*xChildEntry));
3317 // unselect all entries, make pEntry visible, and select
3318 m_xTreeView->set_cursor(rEntry);
3319 Select();
3321 bRet = true;
3324 else
3326 // use of this break assumes outline content type is first in tree
3327 if (lcl_IsContentType(rEntry, *m_xTreeView) &&
3328 reinterpret_cast<SwContentType*>(
3329 m_xTreeView->get_id(rEntry).toInt64())->GetType() !=
3330 ContentTypeId::OUTLINE)
3331 bRet = true;
3333 return bRet;
3336 else
3338 // clear treeview selections
3339 m_xTreeView->unselect_all();
3340 Select();
3344 void SwContentTree::SelectOutlinesWithSelection()
3346 SwCursor* pFirstCursor = m_pActiveShell->GetSwCursor();
3347 SwCursor* pCursor = pFirstCursor;
3348 std::vector<SwOutlineNodes::size_type> aOutlinePositions;
3351 if (pCursor)
3353 if (pCursor->HasMark())
3355 aOutlinePositions.push_back(m_pActiveShell->GetOutlinePos(UCHAR_MAX, pCursor));
3357 pCursor = pCursor->GetNext();
3359 } while (pCursor && pCursor != pFirstCursor);
3361 if (!aOutlinePositions.empty())
3363 // remove duplicates before selecting
3364 aOutlinePositions.erase(std::unique(aOutlinePositions.begin(), aOutlinePositions.end()),
3365 aOutlinePositions.end());
3367 m_xTreeView->unselect_all();
3369 for (auto nOutlinePosition : aOutlinePositions)
3371 m_xTreeView->all_foreach([this, nOutlinePosition](const weld::TreeIter& rEntry){
3372 if (lcl_IsContent(rEntry, *m_xTreeView) &&
3373 reinterpret_cast<SwContent*>(
3374 m_xTreeView->get_id(rEntry).toInt64())->GetParent()->GetType() ==
3375 ContentTypeId::OUTLINE)
3377 if (reinterpret_cast<SwOutlineContent*>(
3378 m_xTreeView->get_id(rEntry).toInt64())->GetOutlinePos() ==
3379 nOutlinePosition)
3381 std::unique_ptr<weld::TreeIter> xParent =
3382 m_xTreeView->make_iterator(&rEntry);
3383 if (m_xTreeView->iter_parent(*xParent) &&
3384 !m_xTreeView->get_row_expanded(*xParent))
3385 m_xTreeView->expand_row(*xParent);
3386 m_xTreeView->select(rEntry);
3387 return true;
3390 return false;
3394 Select();
3398 void SwContentTree::MoveOutline(SwOutlineNodes::size_type nTargetPos)
3400 SwWrtShell *const pShell = GetWrtShell();
3401 pShell->StartAllAction();
3402 std::vector<SwNode*> aOutlineNdsArray;
3404 if (pShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
3406 // make all outline nodes content visible before move
3407 // restore outline nodes content visible state after move
3408 SwOutlineNodes rOutlineNds = pShell->GetDoc()->GetNodes().GetOutLineNds();
3409 for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos)
3411 SwNode* pNd = rOutlineNds[nPos];
3412 if (pNd->IsTextNode()) // should always be true
3414 bool bOutlineContentVisibleAttr = true;
3415 pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
3416 if (!bOutlineContentVisibleAttr)
3418 aOutlineNdsArray.push_back(pNd);
3419 pShell->ToggleOutlineContentVisibility(nPos);
3424 pShell->StartUndo(SwUndoId::OUTLINE_UD);
3426 SwOutlineNodes::size_type nPrevSourcePos = SwOutlineNodes::npos;
3427 SwOutlineNodes::size_type nPrevTargetPosOrOffset = SwOutlineNodes::npos;
3429 bool bFirstMove = true;
3431 for (const auto& source : m_aDndOutlinesSelected)
3433 SwOutlineNodes::size_type nSourcePos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*source).toInt64())->GetOutlinePos();
3435 // Done on the first selection move
3436 if (bFirstMove) // only do once
3438 if (nTargetPos == SwOutlineNodes::npos || nSourcePos > nTargetPos)
3440 // Up moves
3441 // The first up move sets the up move amount for the remaining selected outlines to be moved
3442 if (nTargetPos != SwOutlineNodes::npos)
3443 nPrevTargetPosOrOffset = nSourcePos - nTargetPos;
3444 else
3445 nPrevTargetPosOrOffset = nSourcePos + 1;
3447 else if (nSourcePos < nTargetPos)
3449 // Down moves
3450 // The first down move sets the source and target positions for the remaining selected outlines to be moved
3451 nPrevSourcePos = nSourcePos;
3452 nPrevTargetPosOrOffset = nTargetPos;
3454 bFirstMove = false;
3456 else
3458 if (nTargetPos == SwOutlineNodes::npos || nSourcePos > nTargetPos)
3460 // Move up
3461 nTargetPos = nSourcePos - nPrevTargetPosOrOffset;
3463 else if (nSourcePos < nTargetPos)
3465 // Move down
3466 nSourcePos = nPrevSourcePos;
3467 nTargetPos = nPrevTargetPosOrOffset;
3470 GetParentWindow()->MoveOutline(nSourcePos, nTargetPos);
3473 pShell->EndUndo();
3474 if (pShell->GetViewOptions()->IsShowOutlineContentVisibilityButton())
3476 // restore state of outline content visibility to before move
3477 for (SwNode* pNd : aOutlineNdsArray)
3478 pShell->ToggleOutlineContentVisibility(pNd, true);
3480 pShell->EndAllAction();
3481 m_aActiveContentArr[ContentTypeId::OUTLINE]->Invalidate();
3482 Display(true);
3483 m_aDndOutlinesSelected.clear();
3486 // Update immediately
3487 IMPL_LINK_NOARG(SwContentTree, FocusHdl, weld::Widget&, void)
3489 SwView* pActView = GetParentWindow()->GetCreateView();
3490 if(pActView)
3492 SwWrtShell* pActShell = pActView->GetWrtShellPtr();
3493 if (State::CONSTANT == m_eState && !lcl_FindShell(m_pActiveShell))
3495 SetActiveShell(pActShell);
3498 if (State::ACTIVE == m_eState && pActShell != GetWrtShell())
3499 SetActiveShell(pActShell);
3500 else if ((State::ACTIVE == m_eState || (State::CONSTANT == m_eState && pActShell == GetWrtShell())) &&
3501 HasContentChanged())
3503 Display(true);
3506 else if (State::ACTIVE == m_eState)
3507 clear();
3510 IMPL_LINK(SwContentTree, KeyInputHdl, const KeyEvent&, rEvent, bool)
3512 bool bConsumed = true;
3514 const vcl::KeyCode aCode = rEvent.GetKeyCode();
3515 if (aCode.GetCode() == KEY_MULTIPLY && aCode.IsMod1())
3517 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
3518 if (m_xTreeView->get_selected(xEntry.get()))
3519 ExpandOrCollapseAll(*m_xTreeView, *xEntry);
3521 else if (aCode.GetCode() == KEY_RETURN)
3523 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
3524 if (m_xTreeView->get_selected(xEntry.get()))
3526 switch(aCode.GetModifier())
3528 case KEY_MOD2:
3529 // Switch boxes
3530 GetParentWindow()->ToggleTree();
3531 break;
3532 case KEY_MOD1:
3533 // Switch RootMode
3534 ToggleToRoot();
3535 break;
3536 case 0:
3537 if (lcl_IsContentType(*xEntry, *m_xTreeView))
3539 m_xTreeView->get_row_expanded(*xEntry) ? m_xTreeView->collapse_row(*xEntry)
3540 : m_xTreeView->expand_row(*xEntry);
3542 else
3543 ContentDoubleClickHdl(*m_xTreeView);
3544 break;
3548 else if(aCode.GetCode() == KEY_DELETE && 0 == aCode.GetModifier())
3550 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
3551 if (m_xTreeView->get_selected(xEntry.get()) && lcl_IsContent(*xEntry, *m_xTreeView))
3553 assert(dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64())));
3554 if (reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64())->GetParent()->IsDeletable() &&
3555 !m_pActiveShell->GetView().GetDocShell()->IsReadOnly())
3557 EditEntry(*xEntry, EditEntryMode::DELETE);
3561 //Make KEY_SPACE has same function as DoubleClick ,
3562 //and realize multi-selection .
3563 else if (aCode.GetCode() == KEY_SPACE && 0 == aCode.GetModifier())
3565 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
3566 if (m_xTreeView->get_cursor(xEntry.get()))
3568 if (State::HIDDEN != m_eState)
3570 if (State::CONSTANT == m_eState)
3572 m_pActiveShell->GetView().GetViewFrame()->GetWindow().ToTop();
3575 SwContent* pCnt = dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64()));
3577 if (pCnt && pCnt->GetParent()->GetType() == ContentTypeId::DRAWOBJECT)
3579 SdrView* pDrawView = m_pActiveShell->GetDrawView();
3580 if (pDrawView)
3582 pDrawView->SdrEndTextEdit();
3584 SwDrawModel* pDrawModel = m_pActiveShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
3585 SdrPage* pPage = pDrawModel->GetPage(0);
3586 const size_t nCount = pPage->GetObjCount();
3587 bool hasObjectMarked = false;
3589 if (SdrObject* pObject = GetDrawingObjectsByContent(pCnt))
3591 SdrPageView* pPV = pDrawView->GetSdrPageView/*GetPageViewPvNum*/(/*0*/);
3592 if( pPV )
3594 bool bUnMark = pDrawView->IsObjMarked(pObject);
3595 pDrawView->MarkObj( pObject, pPV, bUnMark);
3599 for( size_t i=0; i<nCount; ++i )
3601 SdrObject* pTemp = pPage->GetObj(i);
3602 bool bMark = pDrawView->IsObjMarked(pTemp);
3603 switch( pTemp->GetObjIdentifier() )
3605 case OBJ_GRUP:
3606 case OBJ_TEXT:
3607 case OBJ_LINE:
3608 case OBJ_RECT:
3609 case OBJ_CIRC:
3610 case OBJ_SECT:
3611 case OBJ_CARC:
3612 case OBJ_CCUT:
3613 case OBJ_POLY:
3614 case OBJ_PLIN:
3615 case OBJ_PATHLINE:
3616 case OBJ_PATHFILL:
3617 case OBJ_FREELINE:
3618 case OBJ_FREEFILL:
3619 case OBJ_PATHPOLY:
3620 case OBJ_PATHPLIN:
3621 case OBJ_CAPTION:
3622 case OBJ_CUSTOMSHAPE:
3623 if( bMark )
3624 hasObjectMarked = true;
3625 break;
3626 default:
3627 if ( bMark )
3629 SdrPageView* pPV = pDrawView->GetSdrPageView/*GetPageViewPvNum*/(/*0*/);
3630 if (pPV)
3632 pDrawView->MarkObj(pTemp, pPV, true);
3636 //mod end
3638 if ( !hasObjectMarked )
3640 SwEditWin& rEditWindow = m_pActiveShell->GetView().GetEditWin();
3641 vcl::KeyCode tempKeycode( KEY_ESCAPE );
3642 KeyEvent rKEvt( 0 , tempKeycode );
3643 static_cast<vcl::Window*>(&rEditWindow)->KeyInput( rKEvt );
3648 m_bViewHasChanged = true;
3652 else
3654 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
3655 if (m_xTreeView->get_cursor(xEntry.get()))
3657 SwContent* pCnt = dynamic_cast<SwContent*>(reinterpret_cast<SwTypeNumber*>(m_xTreeView->get_id(*xEntry).toInt64()));
3658 if (pCnt && pCnt->GetParent()->GetType() == ContentTypeId::OUTLINE)
3660 if (m_bIsRoot && aCode.GetCode() == KEY_LEFT && aCode.GetModifier() == 0)
3662 m_xTreeView->unselect_all();
3663 bConsumed = false;
3665 else if (aCode.IsMod1())
3667 if (aCode.GetCode() == KEY_LEFT)
3668 ExecCommand("promote", !aCode.IsShift());
3669 else if (aCode.GetCode() == KEY_RIGHT)
3670 ExecCommand("demote", !aCode.IsShift());
3671 else if (aCode.GetCode() == KEY_UP)
3672 ExecCommand("chapterup", !aCode.IsShift());
3673 else if (aCode.GetCode() == KEY_DOWN)
3674 ExecCommand("chapterdown", !aCode.IsShift());
3675 else
3676 bConsumed = false;
3678 else
3679 bConsumed = false;
3681 else
3682 bConsumed = false;
3684 else
3685 bConsumed = false;
3687 return bConsumed;
3690 IMPL_LINK(SwContentTree, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUString)
3692 ContentTypeId nType;
3693 bool bContent = false;
3694 void* pUserData = reinterpret_cast<void*>(m_xTreeView->get_id(rEntry).toInt64());
3695 if (lcl_IsContentType(rEntry, *m_xTreeView))
3697 assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pUserData)));
3698 nType = static_cast<SwContentType*>(pUserData)->GetType();
3700 else
3702 assert(dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pUserData)));
3703 nType = static_cast<SwContent*>(pUserData)->GetParent()->GetType();
3704 bContent = true;
3706 OUString sEntry;
3707 if(bContent)
3709 switch( nType )
3711 case ContentTypeId::URLFIELD:
3712 assert(dynamic_cast<SwURLFieldContent*>(static_cast<SwTypeNumber*>(pUserData)));
3713 sEntry = static_cast<SwURLFieldContent*>(pUserData)->GetURL();
3714 break;
3716 case ContentTypeId::POSTIT:
3717 assert(dynamic_cast<SwPostItContent*>(static_cast<SwTypeNumber*>(pUserData)));
3718 sEntry = static_cast<SwPostItContent*>(pUserData)->GetName();
3719 break;
3720 case ContentTypeId::OUTLINE:
3721 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pUserData)));
3722 sEntry = static_cast<SwOutlineContent*>(pUserData)->GetName();
3723 break;
3724 case ContentTypeId::GRAPHIC:
3725 assert(dynamic_cast<SwGraphicContent*>(static_cast<SwTypeNumber*>(pUserData)));
3726 sEntry = static_cast<SwGraphicContent*>(pUserData)->GetLink();
3727 break;
3728 case ContentTypeId::REGION:
3730 assert(dynamic_cast<SwRegionContent*>(static_cast<SwTypeNumber*>(pUserData)));
3731 sEntry = static_cast<SwRegionContent*>(pUserData)->GetName();
3732 const SwSectionFormats& rFormats = GetWrtShell()->GetDoc()->GetSections();
3733 for (SwSectionFormats::size_type n = rFormats.size(); n;)
3735 const SwNodeIndex* pIdx = nullptr;
3736 const SwSectionFormat* pFormat = rFormats[--n];
3737 const SwSection* pSect;
3738 if (nullptr != (pSect = pFormat->GetSection()) &&
3739 pSect->GetSectionName() == sEntry &&
3740 nullptr != (pIdx = pFormat->GetContent().GetContentIdx()) &&
3741 pIdx->GetNode().GetNodes().IsDocNodes())
3743 SwDocStat aDocStat;
3744 SwPaM aPaM(*pIdx, *pIdx->GetNode().EndOfSectionNode());
3745 SwDoc::CountWords(aPaM, aDocStat);
3746 sEntry = SwResId(STR_REGION_DEFNAME) + ": " + sEntry + "\n" +
3747 SwResId(FLD_STAT_WORD) + ": " + OUString::number(aDocStat.nWord) + "\n" +
3748 SwResId(FLD_STAT_CHAR) + ": " + OUString::number(aDocStat.nChar);
3749 break;
3753 break;
3754 default: break;
3756 if(static_cast<SwContent*>(pUserData)->IsInvisible())
3758 if(!sEntry.isEmpty())
3759 sEntry += ", ";
3760 sEntry += m_sInvisible;
3763 else
3765 const size_t nMemberCount = static_cast<SwContentType*>(pUserData)->GetMemberCount();
3766 sEntry = OUString::number(nMemberCount) + " " +
3767 (nMemberCount == 1
3768 ? static_cast<SwContentType*>(pUserData)->GetSingleName()
3769 : static_cast<SwContentType*>(pUserData)->GetName());
3772 return sEntry;
3775 void SwContentTree::ExecuteContextMenuAction(const OString& rSelectedPopupEntry)
3777 std::unique_ptr<weld::TreeIter> xFirst(m_xTreeView->make_iterator());
3778 if (!m_xTreeView->get_selected(xFirst.get()))
3779 xFirst.reset();
3781 auto nSelectedPopupEntry = rSelectedPopupEntry.toUInt32();
3782 switch (nSelectedPopupEntry)
3784 case 1512: // toggle outline content visibility of the selected outline entry
3785 case 1513: // make the outline content of the selected outline entry and children not visible
3786 case 1514: // make the outline content of the selected entry and children visible
3788 m_pActiveShell->EnterStdMode();
3789 m_bIgnoreViewChange = true;
3790 SwOutlineContent* pCntFirst = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(*xFirst).toInt64());
3791 if (nSelectedPopupEntry == 1512)
3793 m_pActiveShell->ToggleOutlineContentVisibility(pCntFirst->GetOutlinePos());
3795 else
3797 // with subs
3798 SwOutlineNodes::size_type nPos = pCntFirst->GetOutlinePos();
3799 if (lcl_IsContentType(*xFirst, *m_xTreeView)) // Headings root entry
3800 nPos = SwOutlineNodes::npos;
3801 SwOutlineNodes::size_type nOutlineNodesCount = m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
3802 int nLevel = -1;
3803 if (nPos != SwOutlineNodes::npos) // not root
3804 nLevel = m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos);
3805 else
3806 nPos = 0;
3807 bool bShow(nSelectedPopupEntry == 1514);
3810 if (m_pActiveShell->IsOutlineContentVisible(nPos) != bShow)
3811 m_pActiveShell->ToggleOutlineContentVisibility(nPos);
3812 } while (++nPos < nOutlineNodesCount
3813 && (nLevel == -1 || m_pActiveShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nLevel));
3815 // show in the document what was toggled
3816 if (lcl_IsContentType(*xFirst, *m_xTreeView)) // Headings root entry
3817 m_pActiveShell->GotoPage(1, true);
3818 else
3819 GotoContent(pCntFirst);
3820 grab_focus();
3821 m_bIgnoreViewChange = false;
3823 break;
3824 case 11:
3825 case 12:
3826 case 13:
3827 nSelectedPopupEntry -= 10;
3828 if(m_nOutlineTracking != nSelectedPopupEntry)
3829 m_nOutlineTracking = nSelectedPopupEntry;
3830 break;
3831 //Outlinelevel
3832 case 101:
3833 case 102:
3834 case 103:
3835 case 104:
3836 case 105:
3837 case 106:
3838 case 107:
3839 case 108:
3840 case 109:
3841 case 110:
3842 nSelectedPopupEntry -= 100;
3843 if(m_nOutlineLevel != nSelectedPopupEntry )
3844 SetOutlineLevel(static_cast<sal_Int8>(nSelectedPopupEntry));
3845 break;
3846 case 201:
3847 case 202:
3848 case 203:
3849 GetParentWindow()->SetRegionDropMode(static_cast<RegionMode>(nSelectedPopupEntry - 201));
3850 break;
3851 case 401:
3852 case 402:
3853 EditEntry(*xFirst, nSelectedPopupEntry == 401 ? EditEntryMode::RMV_IDX : EditEntryMode::UPD_IDX);
3854 break;
3855 // Edit entry
3856 case 403:
3857 EditEntry(*xFirst, EditEntryMode::EDIT);
3858 break;
3859 case 404:
3860 EditEntry(*xFirst, EditEntryMode::UNPROTECT_TABLE);
3861 break;
3862 case 405 :
3864 const SwTOXBase* pBase = reinterpret_cast<SwTOXBaseContent*>(m_xTreeView->get_id(*xFirst).toInt64())
3865 ->GetTOXBase();
3866 m_pActiveShell->SetTOXBaseReadonly(*pBase, !SwEditShell::IsTOXBaseReadonly(*pBase));
3868 break;
3869 case 4:
3870 break;
3871 case 501:
3872 EditEntry(*xFirst, EditEntryMode::DELETE);
3873 break;
3874 case 502 :
3875 EditEntry(*xFirst, EditEntryMode::RENAME);
3876 break;
3877 case 600:
3878 m_pActiveShell->GetView().GetPostItMgr()->Show();
3879 break;
3880 case 601:
3881 m_pActiveShell->GetView().GetPostItMgr()->Hide();
3882 break;
3883 case 602:
3885 m_pActiveShell->GetView().GetPostItMgr()->SetActiveSidebarWin(nullptr);
3886 m_pActiveShell->GetView().GetPostItMgr()->Delete();
3887 break;
3889 case 700:
3891 m_pActiveShell->GetView().GetViewFrame()->GetDispatcher()->Execute(FN_OUTLINE_TO_CLIPBOARD);
3892 break;
3894 case 800:
3895 ExpandOrCollapseAll(*m_xTreeView, *xFirst);
3896 break;
3897 case 801:
3898 ExecCommand("chapterup", true);
3899 break;
3900 case 802:
3901 ExecCommand("chapterdown", true);
3902 break;
3903 case 803:
3904 ExecCommand("promote", true);
3905 break;
3906 case 804:
3907 ExecCommand("demote", true);
3908 break;
3909 case 805:
3911 m_pActiveShell->KillPams();
3912 m_pActiveShell->ClearMark();
3913 m_pActiveShell->EnterAddMode();
3914 SwContent* pCnt = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xFirst).toInt64());
3915 const ContentTypeId eTypeId = pCnt->GetParent()->GetType();
3916 if (eTypeId == ContentTypeId::OUTLINE)
3918 m_xTreeView->selected_foreach([this](weld::TreeIter& rEntry){
3919 m_pActiveShell->SttSelect();
3920 SwOutlineNodes::size_type nActPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(rEntry).toInt64())->GetOutlinePos();
3921 m_pActiveShell->MakeOutlineSel(nActPos, nActPos, !m_xTreeView->get_row_expanded(rEntry), false); // select children if not expanded
3922 m_pActiveShell->EndSelect();
3923 return false;
3926 else if (eTypeId == ContentTypeId::TABLE)
3928 m_pActiveShell->GotoTable(pCnt->GetName());
3929 m_pActiveShell->SelAll();
3931 else if (eTypeId == ContentTypeId::REGION)
3933 m_pActiveShell->EnterStdMode();
3934 m_pActiveShell->GotoRegion(pCnt->GetName());
3935 GotoCurrRegionAndSkip(m_pActiveShell->GetCurrentShellCursor(), fnRegionEnd, m_pActiveShell->IsReadOnlyAvailable());
3936 m_pActiveShell->SttSelect();
3937 GotoCurrRegionAndSkip(m_pActiveShell->GetCurrentShellCursor(), fnRegionStart, m_pActiveShell->IsReadOnlyAvailable());
3938 m_pActiveShell->EndSelect();
3939 m_pActiveShell->UpdateCursor();
3941 m_pActiveShell->LeaveAddMode();
3943 break;
3944 case 806:
3945 // Delete outline selections
3946 EditEntry(*xFirst, EditEntryMode::DELETE);
3947 break;
3948 case 900:
3950 SwContent* pCnt = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xFirst).toInt64());
3951 GotoContent(pCnt);
3953 break;
3954 //Display
3955 default:
3956 if(nSelectedPopupEntry > 300 && nSelectedPopupEntry < 400)
3958 nSelectedPopupEntry -= 300;
3959 SwView *pView = SwModule::GetFirstView();
3960 while (pView)
3962 nSelectedPopupEntry --;
3963 if(nSelectedPopupEntry == 0)
3965 SetConstantShell(&pView->GetWrtShell());
3966 break;
3968 pView = SwModule::GetNextView(pView);
3970 if(nSelectedPopupEntry)
3972 m_bViewHasChanged = nSelectedPopupEntry == 1;
3973 m_eState = (nSelectedPopupEntry == 1) ? State::ACTIVE : State::HIDDEN;
3974 Display(nSelectedPopupEntry == 1);
3978 GetParentWindow()->UpdateListBox();
3981 void SwContentTree::DeleteOutlineSelections()
3983 m_pActiveShell->StartAction();
3984 m_pActiveShell->EnterAddMode();
3985 auto nChapters(0);
3987 m_xTreeView->selected_foreach([this, &nChapters](weld::TreeIter& rEntry){
3988 ++nChapters;
3989 if (m_xTreeView->iter_has_child(rEntry) &&
3990 !m_xTreeView->get_row_expanded(rEntry)) // only count children if not expanded
3992 nChapters += m_xTreeView->iter_n_children(rEntry);
3994 m_pActiveShell->SttSelect();
3995 SwOutlineNodes::size_type nActPos = reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(rEntry).toInt64())->GetOutlinePos();
3996 m_pActiveShell->MakeOutlineSel(nActPos, nActPos, !m_xTreeView->get_row_expanded(rEntry), false); // select children if not expanded
3997 m_pActiveShell->EndSelect();
3998 return false;
4000 m_pActiveShell->LeaveAddMode();
4001 SwRewriter aRewriter;
4002 aRewriter.AddRule(UndoArg1, SwResId(STR_CHAPTERS, nChapters));
4003 m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
4004 m_pActiveShell->SetTextFormatColl(nullptr);
4005 m_pActiveShell->Delete();
4006 m_pActiveShell->ClearMark();
4007 m_pActiveShell->EndUndo();
4008 m_pActiveShell->EndAction();
4011 void SwContentTree::SetOutlineLevel(sal_uInt8 nSet)
4013 m_nOutlineLevel = nSet;
4014 m_pConfig->SetOutlineLevel( m_nOutlineLevel );
4015 std::unique_ptr<SwContentType>& rpContentT = (State::ACTIVE == m_eState)
4016 ? m_aActiveContentArr[ContentTypeId::OUTLINE]
4017 : m_aHiddenContentArr[ContentTypeId::OUTLINE];
4018 if(rpContentT)
4020 rpContentT->SetOutlineLevel(m_nOutlineLevel);
4021 rpContentT->Init();
4023 Display(State::ACTIVE == m_eState);
4026 // Mode Change: Show dropped Doc
4027 void SwContentTree::ShowHiddenShell()
4029 if(m_pHiddenShell)
4031 m_eState = State::HIDDEN;
4032 Display(false);
4036 // Mode Change: Show active view
4037 void SwContentTree::ShowActualView()
4039 m_eState = State::ACTIVE;
4040 Display(true);
4041 GetParentWindow()->UpdateListBox();
4044 IMPL_LINK_NOARG(SwContentTree, SelectHdl, weld::TreeView&, void)
4046 Select();
4049 // Here the buttons for moving outlines are en-/disabled.
4050 void SwContentTree::Select()
4052 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
4053 if (!m_xTreeView->get_selected(xEntry.get()))
4054 return;
4056 bool bEnable = false;
4057 std::unique_ptr<weld::TreeIter> xParentEntry(m_xTreeView->make_iterator(xEntry.get()));
4058 bool bParentEntry = m_xTreeView->iter_parent(*xParentEntry);
4059 while (bParentEntry && (!lcl_IsContentType(*xParentEntry, *m_xTreeView)))
4060 bParentEntry = m_xTreeView->iter_parent(*xParentEntry);
4061 if (!m_bIsLastReadOnly)
4063 if (!m_xTreeView->get_visible())
4064 bEnable = true;
4065 else if (bParentEntry)
4067 if ((m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE) ||
4068 (lcl_IsContent(*xEntry, *m_xTreeView) &&
4069 reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xParentEntry).toInt64())->GetType() == ContentTypeId::OUTLINE))
4071 bEnable = true;
4075 SwNavigationPI* pNavi = GetParentWindow();
4076 pNavi->m_xContent6ToolBox->set_item_sensitive("chapterup", bEnable);
4077 pNavi->m_xContent6ToolBox->set_item_sensitive("chapterdown", bEnable);
4078 pNavi->m_xContent6ToolBox->set_item_sensitive("promote", bEnable);
4079 pNavi->m_xContent6ToolBox->set_item_sensitive("demote", bEnable);
4082 void SwContentTree::SetRootType(ContentTypeId nType)
4084 m_nRootType = nType;
4085 m_bIsRoot = true;
4086 m_pConfig->SetRootType( m_nRootType );
4089 OUString SwContentType::RemoveNewline(const OUString& rEntry)
4091 if (rEntry.isEmpty())
4092 return rEntry;
4094 OUStringBuffer aEntry(rEntry);
4095 for (sal_Int32 i = 0; i < rEntry.getLength(); ++i)
4096 if(aEntry[i] == 10 || aEntry[i] == 13)
4097 aEntry[i] = 0x20;
4099 return aEntry.makeStringAndClear();
4102 void SwContentTree::EditEntry(const weld::TreeIter& rEntry, EditEntryMode nMode)
4104 SwContent* pCnt = reinterpret_cast<SwContent*>(m_xTreeView->get_id(rEntry).toInt64());
4105 GotoContent(pCnt);
4106 const ContentTypeId nType = pCnt->GetParent()->GetType();
4107 sal_uInt16 nSlot = 0;
4109 if(EditEntryMode::DELETE == nMode)
4110 m_bIgnoreViewChange = true;
4112 uno::Reference< container::XNameAccess > xNameAccess, xSecond, xThird;
4113 switch(nType)
4115 case ContentTypeId::OUTLINE :
4116 if(nMode == EditEntryMode::DELETE)
4118 DeleteOutlineSelections();
4120 break;
4122 case ContentTypeId::TABLE :
4123 if(nMode == EditEntryMode::UNPROTECT_TABLE)
4125 m_pActiveShell->GetView().GetDocShell()->
4126 GetDoc()->UnProtectCells( pCnt->GetName());
4128 else if(nMode == EditEntryMode::DELETE)
4130 m_pActiveShell->StartAction();
4131 OUString sTable = SwResId(STR_TABLE_NAME);
4132 SwRewriter aRewriterTableName;
4133 aRewriterTableName.AddRule(UndoArg1, SwResId(STR_START_QUOTE));
4134 aRewriterTableName.AddRule(UndoArg2, pCnt->GetName());
4135 aRewriterTableName.AddRule(UndoArg3, SwResId(STR_END_QUOTE));
4136 sTable = aRewriterTableName.Apply(sTable);
4138 SwRewriter aRewriter;
4139 aRewriter.AddRule(UndoArg1, sTable);
4140 m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
4141 m_pActiveShell->GetView().GetViewFrame()->GetDispatcher()->Execute(FN_TABLE_SELECT_ALL);
4142 m_pActiveShell->DeleteRow();
4143 m_pActiveShell->EndUndo();
4144 m_pActiveShell->EndAction();
4146 else if(nMode == EditEntryMode::RENAME)
4148 uno::Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
4149 uno::Reference< text::XTextTablesSupplier > xTables(xModel, uno::UNO_QUERY);
4150 xNameAccess = xTables->getTextTables();
4152 else
4153 nSlot = FN_FORMAT_TABLE_DLG;
4154 break;
4156 case ContentTypeId::GRAPHIC :
4157 if(nMode == EditEntryMode::DELETE)
4159 m_pActiveShell->DelRight();
4161 else if(nMode == EditEntryMode::RENAME)
4163 uno::Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
4164 uno::Reference< text::XTextGraphicObjectsSupplier > xGraphics(xModel, uno::UNO_QUERY);
4165 xNameAccess = xGraphics->getGraphicObjects();
4166 uno::Reference< text::XTextFramesSupplier > xFrames(xModel, uno::UNO_QUERY);
4167 xSecond = xFrames->getTextFrames();
4168 uno::Reference< text::XTextEmbeddedObjectsSupplier > xObjs(xModel, uno::UNO_QUERY);
4169 xThird = xObjs->getEmbeddedObjects();
4171 else
4172 nSlot = FN_FORMAT_GRAFIC_DLG;
4173 break;
4175 case ContentTypeId::FRAME :
4176 case ContentTypeId::OLE :
4177 if(nMode == EditEntryMode::DELETE)
4179 m_pActiveShell->DelRight();
4181 else if(nMode == EditEntryMode::RENAME)
4183 uno::Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
4184 uno::Reference< text::XTextFramesSupplier > xFrames(xModel, uno::UNO_QUERY);
4185 uno::Reference< text::XTextEmbeddedObjectsSupplier > xObjs(xModel, uno::UNO_QUERY);
4186 if(ContentTypeId::FRAME == nType)
4188 xNameAccess = xFrames->getTextFrames();
4189 xSecond = xObjs->getEmbeddedObjects();
4191 else
4193 xNameAccess = xObjs->getEmbeddedObjects();
4194 xSecond = xFrames->getTextFrames();
4196 uno::Reference< text::XTextGraphicObjectsSupplier > xGraphics(xModel, uno::UNO_QUERY);
4197 xThird = xGraphics->getGraphicObjects();
4199 else
4200 nSlot = FN_FORMAT_FRAME_DLG;
4201 break;
4202 case ContentTypeId::BOOKMARK :
4203 assert(!m_pActiveShell->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS));
4204 if(nMode == EditEntryMode::DELETE)
4206 IDocumentMarkAccess* const pMarkAccess = m_pActiveShell->getIDocumentMarkAccess();
4207 pMarkAccess->deleteMark( pMarkAccess->findMark(pCnt->GetName()) );
4209 else if(nMode == EditEntryMode::RENAME)
4211 uno::Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
4212 uno::Reference< text::XBookmarksSupplier > xBkms(xModel, uno::UNO_QUERY);
4213 xNameAccess = xBkms->getBookmarks();
4215 else
4216 nSlot = FN_INSERT_BOOKMARK;
4217 break;
4219 case ContentTypeId::REGION :
4220 if(nMode == EditEntryMode::RENAME)
4222 uno::Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
4223 uno::Reference< text::XTextSectionsSupplier > xSects(xModel, uno::UNO_QUERY);
4224 xNameAccess = xSects->getTextSections();
4226 else
4227 nSlot = FN_EDIT_REGION;
4228 break;
4230 case ContentTypeId::URLFIELD:
4231 if (nMode == EditEntryMode::DELETE)
4232 nSlot = SID_REMOVE_HYPERLINK;
4233 else
4234 nSlot = SID_EDIT_HYPERLINK;
4235 break;
4236 case ContentTypeId::REFERENCE:
4237 nSlot = FN_EDIT_FIELD;
4238 break;
4240 case ContentTypeId::POSTIT:
4241 m_pActiveShell->GetView().GetPostItMgr()->AssureStdModeAtShell();
4242 if(nMode == EditEntryMode::DELETE)
4244 m_pActiveShell->GetView().GetPostItMgr()->SetActiveSidebarWin(nullptr);
4245 m_pActiveShell->DelRight();
4247 else
4249 nSlot = FN_POSTIT;
4251 break;
4252 case ContentTypeId::INDEX:
4254 const SwTOXBase* pBase = static_cast<SwTOXBaseContent*>(pCnt)->GetTOXBase();
4255 switch(nMode)
4257 case EditEntryMode::EDIT:
4258 if(pBase)
4260 SwPtrItem aPtrItem( FN_INSERT_MULTI_TOX, const_cast<SwTOXBase *>(pBase));
4261 m_pActiveShell->GetView().GetViewFrame()->
4262 GetDispatcher()->ExecuteList(FN_INSERT_MULTI_TOX,
4263 SfxCallMode::ASYNCHRON, { &aPtrItem });
4266 break;
4267 case EditEntryMode::RMV_IDX:
4268 case EditEntryMode::DELETE:
4270 if( pBase )
4271 m_pActiveShell->DeleteTOX(*pBase, EditEntryMode::DELETE == nMode);
4273 break;
4274 case EditEntryMode::UPD_IDX:
4275 case EditEntryMode::RENAME:
4277 Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
4278 Reference< XDocumentIndexesSupplier > xIndexes(xModel, UNO_QUERY);
4279 Reference< XIndexAccess> xIdxAcc(xIndexes->getDocumentIndexes());
4280 Reference< XNameAccess >xLocalNameAccess(xIdxAcc, UNO_QUERY);
4281 if(EditEntryMode::RENAME == nMode)
4282 xNameAccess = xLocalNameAccess;
4283 else if(xLocalNameAccess.is() && xLocalNameAccess->hasByName(pBase->GetTOXName()))
4285 Any aIdx = xLocalNameAccess->getByName(pBase->GetTOXName());
4286 Reference< XDocumentIndex> xIdx;
4287 if(aIdx >>= xIdx)
4288 xIdx->update();
4291 break;
4292 default: break;
4295 break;
4296 case ContentTypeId::DRAWOBJECT :
4297 if(EditEntryMode::DELETE == nMode)
4298 nSlot = SID_DELETE;
4299 else if(nMode == EditEntryMode::RENAME)
4300 nSlot = FN_NAME_SHAPE;
4301 break;
4302 default: break;
4304 if(nSlot)
4305 m_pActiveShell->GetView().GetViewFrame()->
4306 GetDispatcher()->Execute(nSlot, SfxCallMode::SYNCHRON);
4307 else if(xNameAccess.is())
4309 uno::Any aObj = xNameAccess->getByName(pCnt->GetName());
4310 uno::Reference< uno::XInterface > xTmp;
4311 aObj >>= xTmp;
4312 uno::Reference< container::XNamed > xNamed(xTmp, uno::UNO_QUERY);
4313 SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
4314 ScopedVclPtr<AbstractSwRenameXNamedDlg> pDlg(pFact->CreateSwRenameXNamedDlg(GetParentWindow()->GetFrameWeld(), xNamed, xNameAccess));
4315 if(xSecond.is())
4316 pDlg->SetAlternativeAccess( xSecond, xThird);
4318 OUString sForbiddenChars;
4319 if(ContentTypeId::BOOKMARK == nType)
4321 sForbiddenChars = "/\\@:*?\";,.#";
4323 else if(ContentTypeId::TABLE == nType)
4325 sForbiddenChars = " .<>";
4327 pDlg->SetForbiddenChars(sForbiddenChars);
4328 pDlg->Execute();
4330 if(EditEntryMode::DELETE == nMode)
4332 m_bViewHasChanged = true;
4333 GetParentWindow()->UpdateListBox();
4334 TimerUpdate(&m_aUpdTimer);
4335 grab_focus();
4339 static void lcl_AssureStdModeAtShell(SwWrtShell* pWrtShell)
4341 // deselect any drawing or frame and leave editing mode
4342 SdrView* pSdrView = pWrtShell->GetDrawView();
4343 if (pSdrView && pSdrView->IsTextEdit() )
4345 bool bLockView = pWrtShell->IsViewLocked();
4346 pWrtShell->LockView(true);
4347 pWrtShell->EndTextEdit();
4348 pWrtShell->LockView(bLockView);
4351 if (pWrtShell->IsSelFrameMode() || pWrtShell->IsObjSelected())
4353 pWrtShell->UnSelectFrame();
4354 pWrtShell->LeaveSelFrameMode();
4355 pWrtShell->GetView().LeaveDrawCreate();
4356 pWrtShell->EnterStdMode();
4357 pWrtShell->DrawSelChanged();
4358 pWrtShell->GetView().StopShellTimer();
4360 else
4361 pWrtShell->EnterStdMode();
4364 void SwContentTree::GotoContent(const SwContent* pCnt)
4366 lcl_AssureStdModeAtShell(m_pActiveShell);
4367 switch(pCnt->GetParent()->GetType())
4369 case ContentTypeId::OUTLINE :
4371 m_pActiveShell->GotoOutline(static_cast<const SwOutlineContent*>(pCnt)->GetOutlinePos());
4373 break;
4374 case ContentTypeId::TABLE :
4376 m_pActiveShell->GotoTable(pCnt->GetName());
4378 break;
4379 case ContentTypeId::FRAME :
4380 case ContentTypeId::GRAPHIC :
4381 case ContentTypeId::OLE :
4383 m_pActiveShell->GotoFly(pCnt->GetName());
4385 break;
4386 case ContentTypeId::BOOKMARK:
4388 m_pActiveShell->GotoMark(pCnt->GetName());
4390 break;
4391 case ContentTypeId::REGION :
4393 m_pActiveShell->GotoRegion(pCnt->GetName());
4395 break;
4396 case ContentTypeId::URLFIELD:
4398 if(m_pActiveShell->GotoINetAttr(
4399 *static_cast<const SwURLFieldContent*>(pCnt)->GetINetAttr() ))
4401 m_pActiveShell->Right( CRSR_SKIP_CHARS, true, 1, false);
4402 m_pActiveShell->SwCursorShell::SelectTextAttr( RES_TXTATR_INETFMT, true );
4405 break;
4406 case ContentTypeId::REFERENCE:
4408 m_pActiveShell->GotoRefMark(pCnt->GetName());
4410 break;
4411 case ContentTypeId::INDEX:
4413 const OUString& sName(pCnt->GetName());
4414 if (!m_pActiveShell->GotoNextTOXBase(&sName))
4415 m_pActiveShell->GotoPrevTOXBase(&sName);
4417 break;
4418 case ContentTypeId::POSTIT:
4419 m_pActiveShell->GotoFormatField(*static_cast<const SwPostItContent*>(pCnt)->GetPostIt());
4420 break;
4421 case ContentTypeId::DRAWOBJECT:
4423 m_pActiveShell->GotoDrawingObject(pCnt->GetName());
4425 break;
4426 default: break;
4429 if (m_pActiveShell->IsFrameSelected() || m_pActiveShell->IsObjSelected())
4431 m_pActiveShell->HideCursor();
4432 m_pActiveShell->EnterSelFrameMode();
4435 SwView& rView = m_pActiveShell->GetView();
4436 rView.StopShellTimer();
4437 rView.GetPostItMgr()->SetActiveSidebarWin(nullptr);
4438 rView.GetEditWin().GrabFocus();
4440 // assure visible view area is at cursor position
4441 if (!m_pActiveShell->IsCursorVisible() && !m_pActiveShell->IsFrameSelected() &&
4442 !m_pActiveShell->IsObjSelected())
4444 Point rPoint = m_pActiveShell->GetCursorDocPos();
4445 rPoint.setX(0);
4446 rView.SetVisArea(rPoint);
4450 // Now even the matching text::Bookmark
4451 NaviContentBookmark::NaviContentBookmark()
4453 nDocSh(0),
4454 nDefDrag( RegionMode::NONE )
4458 NaviContentBookmark::NaviContentBookmark( const OUString &rUrl,
4459 const OUString& rDesc,
4460 RegionMode nDragType,
4461 const SwDocShell* pDocSh ) :
4462 aUrl( rUrl ),
4463 aDescr(rDesc),
4464 nDocSh(reinterpret_cast<sal_IntPtr>(pDocSh)),
4465 nDefDrag( nDragType )
4469 void NaviContentBookmark::Copy( TransferDataContainer& rData ) const
4471 rtl_TextEncoding eSysCSet = osl_getThreadTextEncoding();
4473 OString sStrBuf(OUStringToOString(aUrl, eSysCSet) + OStringChar(NAVI_BOOKMARK_DELIM) +
4474 OUStringToOString(aDescr, eSysCSet) + OStringChar(NAVI_BOOKMARK_DELIM) +
4475 OString::number(static_cast<int>(nDefDrag)) + OStringChar(NAVI_BOOKMARK_DELIM) +
4476 OString::number(nDocSh));
4477 rData.CopyByteString(SotClipboardFormatId::SONLK, sStrBuf);
4480 bool NaviContentBookmark::Paste( TransferableDataHelper& rData )
4482 OUString sStr;
4483 bool bRet = rData.GetString( SotClipboardFormatId::SONLK, sStr );
4484 if( bRet )
4486 sal_Int32 nPos = 0;
4487 aUrl = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos );
4488 aDescr = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos );
4489 nDefDrag= static_cast<RegionMode>( sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos ).toInt32() );
4490 nDocSh = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos ).toInt32();
4492 return bRet;
4495 SwNavigationPI* SwContentTree::GetParentWindow()
4497 return m_xDialog;
4500 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */