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