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