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