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