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