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