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/help.hxx>
32 #include <vcl/settings.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 <txtatr.hxx>
47 #include <IMark.hxx>
48 #include <section.hxx>
49 #include <tox.hxx>
50 #include <navipi.hxx>
51 #include <navicont.hxx>
52 #include <navicfg.hxx>
53 #include <edtwin.hxx>
54 #include <doc.hxx>
55 #include <IDocumentDrawModelAccess.hxx>
56 #include <IDocumentOutlineNodes.hxx>
57 #include <unotools.hxx>
58 #include <unotxvw.hxx>
59 #include <cmdid.h>
60 #include <helpids.h>
61 #include <strings.hrc>
62 #include <com/sun/star/text/XTextSectionsSupplier.hpp>
63 #include <com/sun/star/text/XTextGraphicObjectsSupplier.hpp>
64 #include <com/sun/star/text/XTextTablesSupplier.hpp>
65 #include <com/sun/star/text/XDocumentIndexesSupplier.hpp>
66 #include <com/sun/star/text/XDocumentIndex.hpp>
67 #include <com/sun/star/text/XBookmarksSupplier.hpp>
68 #include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
69 #include <com/sun/star/text/XTextFramesSupplier.hpp>
70 #include <dcontact.hxx>
71 #include <svx/svdogrp.hxx>
72 #include <svx/svdmodel.hxx>
73 #include <svx/svdpage.hxx>
74 #include <svx/svdview.hxx>
75 #include <svx/svxids.hrc>
76 #include <vcl/scrbar.hxx>
77 #include <SwRewriter.hxx>
78 #include <hints.hxx>
79 #include <numrule.hxx>
80 #include <swundo.hxx>
81 #include <ndtxt.hxx>
82 #include <fmtcntnt.hxx>
83 #include <PostItMgr.hxx>
84 #include <postithelper.hxx>
85 #include <redline.hxx>
86 #include <docary.hxx>
87 #include <vcl/treelistentry.hxx>
88
89 #include <swabstdlg.hxx>
90 #include <globals.hrc>
91 #include <bitmaps.hlst>
92 #include <unomid.h>
93
94 #include <navmgr.hxx>
95 #include <AnnotationWin.hxx>
96 #include <memory>
97
98 #define CTYPE_CNT 0
99 #define CTYPE_CTT 1
100
101 using namespace ::std;
102 using namespace ::com::sun::star;
103 using namespace ::com::sun::star::text;
104 using namespace ::com::sun::star::uno;
105 using namespace ::com::sun::star::container;
106
107 namespace {
108
109 constexpr char NAVI_BOOKMARK_DELIM = '\x01';
110
111 }
112
113 class SwContentArr
114 : public o3tl::sorted_vector<std::unique_ptr<SwContent>, o3tl::less_uniqueptr_to<SwContent>,
115 o3tl::find_partialorder_ptrequals>
116 {
117 };
118
119 bool SwContentTree::bIsInDrag = false;
120
121 namespace
122 {
lcl_IsContent(const SvTreeListEntry * pEntry)123 bool lcl_IsContent(const SvTreeListEntry* pEntry)
124 {
125 return static_cast<const SwTypeNumber*>(pEntry->GetUserData())->GetTypeId() == CTYPE_CNT;
126 }
127
lcl_IsContentType(const SvTreeListEntry * pEntry)128 bool lcl_IsContentType(const SvTreeListEntry* pEntry)
129 {
130 return static_cast<const SwTypeNumber*>(pEntry->GetUserData())->GetTypeId() == CTYPE_CTT;
131 }
132
lcl_FindShell(SwWrtShell const * pShell)133 bool lcl_FindShell(SwWrtShell const * pShell)
134 {
135 bool bFound = false;
136 SwView *pView = SwModule::GetFirstView();
137 while (pView)
138 {
139 if(pShell == &pView->GetWrtShell())
140 {
141 bFound = true;
142 break;
143 }
144 pView = SwModule::GetNextView(pView);
145 }
146 return bFound;
147 }
148
lcl_IsUiVisibleBookmark(const::sw::mark::IMark * pMark)149 bool lcl_IsUiVisibleBookmark(const ::sw::mark::IMark* pMark)
150 {
151 return IDocumentMarkAccess::GetType(*pMark) == IDocumentMarkAccess::MarkType::BOOKMARK;
152 }
153
lcl_InsertURLFieldContent(SwContentArr * pMember,SwWrtShell * pWrtShell,const SwContentType * pCntType)154 size_t lcl_InsertURLFieldContent(
155 SwContentArr *pMember,
156 SwWrtShell* pWrtShell,
157 const SwContentType *pCntType)
158 {
159 SwGetINetAttrs aArr;
160 pWrtShell->GetINetAttrs( aArr );
161 const SwGetINetAttrs::size_type nCount {aArr.size()};
162 for( SwGetINetAttrs::size_type n = 0; n < nCount; ++n )
163 {
164 SwGetINetAttr* p = &aArr[ n ];
165 std::unique_ptr<SwURLFieldContent> pCnt(new SwURLFieldContent(
166 pCntType,
167 p->sText,
168 INetURLObject::decode(
169 p->rINetAttr.GetINetFormat().GetValue(),
170 INetURLObject::DecodeMechanism::Unambiguous ),
171 &p->rINetAttr,
172 n ));
173 pMember->insert( std::move(pCnt) );
174 }
175 return nCount;
176 }
177 }
178
179 // Content, contains names and reference at the content type.
180
SwContent(const SwContentType * pCnt,const OUString & rName,long nYPos)181 SwContent::SwContent(const SwContentType* pCnt, const OUString& rName, long nYPos) :
182 SwTypeNumber(CTYPE_CNT),
183 pParent(pCnt),
184 sContentName(rName),
185 nYPosition(nYPos),
186 bInvisible(false)
187 {
188 }
189
190
~SwTypeNumber()191 SwTypeNumber::~SwTypeNumber()
192 {
193 }
194
IsProtect() const195 bool SwContent::IsProtect() const
196 {
197 return false;
198 }
199
IsProtect() const200 bool SwPostItContent::IsProtect() const
201 {
202 return pField->IsProtect();
203 }
204
IsProtect() const205 bool SwURLFieldContent::IsProtect() const
206 {
207 return pINetAttr->IsProtect();
208 }
209
~SwGraphicContent()210 SwGraphicContent::~SwGraphicContent()
211 {
212 }
213
~SwTOXBaseContent()214 SwTOXBaseContent::~SwTOXBaseContent()
215 {
216 }
217
218 static const char* STR_CONTENT_TYPE_ARY[] =
219 {
220 STR_CONTENT_TYPE_OUTLINE,
221 STR_CONTENT_TYPE_TABLE,
222 STR_CONTENT_TYPE_FRAME,
223 STR_CONTENT_TYPE_GRAPHIC,
224 STR_CONTENT_TYPE_OLE,
225 STR_CONTENT_TYPE_BOOKMARK,
226 STR_CONTENT_TYPE_REGION,
227 STR_CONTENT_TYPE_URLFIELD,
228 STR_CONTENT_TYPE_REFERENCE,
229 STR_CONTENT_TYPE_INDEX,
230 STR_CONTENT_TYPE_POSTIT,
231 STR_CONTENT_TYPE_DRAWOBJECT
232 };
233
234 static const char* STR_CONTENT_TYPE_SINGLE_ARY[] =
235 {
236 STR_CONTENT_TYPE_SINGLE_OUTLINE,
237 STR_CONTENT_TYPE_SINGLE_TABLE,
238 STR_CONTENT_TYPE_SINGLE_FRAME,
239 STR_CONTENT_TYPE_SINGLE_GRAPHIC,
240 STR_CONTENT_TYPE_SINGLE_OLE,
241 STR_CONTENT_TYPE_SINGLE_BOOKMARK,
242 STR_CONTENT_TYPE_SINGLE_REGION,
243 STR_CONTENT_TYPE_SINGLE_URLFIELD,
244 STR_CONTENT_TYPE_SINGLE_REFERENCE,
245 STR_CONTENT_TYPE_SINGLE_INDEX,
246 STR_CONTENT_TYPE_SINGLE_POSTIT,
247 STR_CONTENT_TYPE_SINGLE_DRAWOBJECT
248 };
249
250 namespace
251 {
checkVisibilityChanged(const SwContentArr & rSwContentArrA,const SwContentArr & rSwContentArrB)252 bool checkVisibilityChanged(
253 const SwContentArr& rSwContentArrA,
254 const SwContentArr& rSwContentArrB)
255 {
256 if(rSwContentArrA.size() != rSwContentArrB.size())
257 {
258 return true;
259 }
260
261 for(size_t a(0); a < rSwContentArrA.size(); a++)
262 {
263 if(rSwContentArrA[a]->IsInvisible() != rSwContentArrB[a]->IsInvisible())
264 {
265 return true;
266 }
267 }
268
269 return false;
270 }
271 } // end of anonymous namespace
272
SwContentType(SwWrtShell * pShell,ContentTypeId nType,sal_uInt8 nLevel)273 SwContentType::SwContentType(SwWrtShell* pShell, ContentTypeId nType, sal_uInt8 nLevel) :
274 SwTypeNumber(CTYPE_CTT),
275 m_pWrtShell(pShell),
276 m_sContentTypeName(SwResId(STR_CONTENT_TYPE_ARY[static_cast<int>(nType)])),
277 m_sSingleContentTypeName(SwResId(STR_CONTENT_TYPE_SINGLE_ARY[static_cast<int>(nType)])),
278 m_nMemberCount(0),
279 m_nContentType(nType),
280 m_nOutlineLevel(nLevel),
281 m_bDataValid(false),
282 m_bEdit(false),
283 m_bDelete(true)
284 {
285 Init();
286 }
287
Init(bool * pbInvalidateWindow)288 void SwContentType::Init(bool* pbInvalidateWindow)
289 {
290 // if the MemberCount is changing ...
291 size_t nOldMemberCount = m_nMemberCount;
292 m_nMemberCount = 0;
293 switch(m_nContentType)
294 {
295 case ContentTypeId::OUTLINE :
296 {
297 m_sTypeToken = "outline";
298 m_nMemberCount = m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
299 if (m_nMemberCount < MAXLEVEL)
300 {
301 const size_t nOutlineCount = m_nMemberCount;
302 for(size_t j = 0; j < nOutlineCount; ++j)
303 {
304 if (m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(j) > m_nOutlineLevel
305 || !m_pWrtShell->getIDocumentOutlineNodesAccess()->isOutlineInLayout(j, *m_pWrtShell->GetLayout()))
306 {
307 m_nMemberCount --;
308 }
309 }
310 }
311 m_bDelete = false;
312 }
313 break;
314
315 case ContentTypeId::TABLE :
316 m_sTypeToken = "table";
317 m_nMemberCount = m_pWrtShell->GetTableFrameFormatCount(true);
318 m_bEdit = true;
319 break;
320
321 case ContentTypeId::FRAME :
322 case ContentTypeId::GRAPHIC :
323 case ContentTypeId::OLE :
324 {
325 FlyCntType eType = FLYCNTTYPE_FRM;
326 m_sTypeToken = "frame";
327 if(m_nContentType == ContentTypeId::OLE)
328 {
329 eType = FLYCNTTYPE_OLE;
330 m_sTypeToken = "ole";
331 }
332 else if(m_nContentType == ContentTypeId::GRAPHIC)
333 {
334 eType = FLYCNTTYPE_GRF;
335 m_sTypeToken = "graphic";
336 }
337 m_nMemberCount = m_pWrtShell->GetFlyCount(eType, /*bIgnoreTextBoxes=*/true);
338 m_bEdit = true;
339 }
340 break;
341 case ContentTypeId::BOOKMARK:
342 {
343 IDocumentMarkAccess* const pMarkAccess = m_pWrtShell->getIDocumentMarkAccess();
344 m_nMemberCount = count_if(
345 pMarkAccess->getBookmarksBegin(),
346 pMarkAccess->getBookmarksEnd(),
347 &lcl_IsUiVisibleBookmark);
348 m_sTypeToken.clear();
349 m_bEdit = true;
350 }
351 break;
352 case ContentTypeId::REGION :
353 {
354 std::unique_ptr<SwContentArr> pOldMember;
355 if(!m_pMember)
356 m_pMember.reset( new SwContentArr );
357 else if(!m_pMember->empty())
358 {
359 pOldMember = std::move(m_pMember);
360 m_pMember.reset( new SwContentArr );
361 }
362 const Point aNullPt;
363 m_nMemberCount = m_pWrtShell->GetSectionFormatCount();
364 for(size_t i = 0; i < m_nMemberCount; ++i)
365 {
366 const SwSectionFormat* pFormat;
367 SectionType eTmpType;
368 if( (pFormat = &m_pWrtShell->GetSectionFormat(i))->IsInNodesArr() &&
369 (eTmpType = pFormat->GetSection()->GetType()) != TOX_CONTENT_SECTION
370 && TOX_HEADER_SECTION != eTmpType )
371 {
372 const OUString& rSectionName =
373 pFormat->GetSection()->GetSectionName();
374 sal_uInt8 nLevel = 0;
375 SwSectionFormat* pParentFormat = pFormat->GetParent();
376 while(pParentFormat)
377 {
378 nLevel++;
379 pParentFormat = pParentFormat->GetParent();
380 }
381
382 std::unique_ptr<SwContent> pCnt(new SwRegionContent(this, rSectionName,
383 nLevel,
384 pFormat->FindLayoutRect( false, &aNullPt ).Top()));
385
386 SwPtrMsgPoolItem aAskItem( RES_CONTENT_VISIBLE, nullptr );
387 if( !pFormat->GetInfo( aAskItem ) &&
388 !aAskItem.pObject ) // not visible
389 pCnt->SetInvisible();
390 m_pMember->insert(std::move(pCnt));
391 }
392 }
393 m_nMemberCount = m_pMember->size();
394 m_sTypeToken = "region";
395 m_bEdit = true;
396 m_bDelete = false;
397 if(pOldMember)
398 {
399 if(nullptr != pbInvalidateWindow)
400 {
401 // need to check visibility (and equal entry number) after
402 // creation due to a sorted list being used here (before,
403 // entries with same index were compared already at creation
404 // time what worked before a sorted list was used)
405 *pbInvalidateWindow = checkVisibilityChanged(
406 *pOldMember,
407 *m_pMember);
408 }
409 }
410 }
411 break;
412 case ContentTypeId::INDEX:
413 {
414 m_nMemberCount = m_pWrtShell->GetTOXCount();
415 m_bEdit = true;
416 m_bDelete = false;
417 }
418 break;
419 case ContentTypeId::REFERENCE:
420 {
421 m_nMemberCount = m_pWrtShell->GetRefMarks();
422 m_bDelete = false;
423 }
424 break;
425 case ContentTypeId::URLFIELD:
426 {
427 m_nMemberCount = 0;
428 if(!m_pMember)
429 m_pMember.reset( new SwContentArr );
430 else
431 m_pMember->clear();
432
433 m_nMemberCount = lcl_InsertURLFieldContent(m_pMember.get(), m_pWrtShell, this);
434
435 m_bEdit = true;
436 nOldMemberCount = m_nMemberCount;
437 m_bDelete = false;
438 }
439 break;
440 case ContentTypeId::POSTIT:
441 {
442 m_nMemberCount = 0;
443 if(!m_pMember)
444 m_pMember.reset( new SwContentArr );
445 else
446 m_pMember->clear();
447
448 SwPostItMgr* aMgr = m_pWrtShell->GetView().GetPostItMgr();
449 if (aMgr)
450 {
451 for(SwPostItMgr::const_iterator i = aMgr->begin(); i != aMgr->end(); ++i)
452 {
453 if (const SwFormatField* pFormatField = dynamic_cast<const SwFormatField *>((*i)->GetBroadcaster())) // SwPostit
454 {
455 if (pFormatField->GetTextField() && pFormatField->IsFieldInDoc() &&
456 (*i)->mLayoutStatus!=SwPostItHelper::INVISIBLE )
457 {
458 OUString sEntry = pFormatField->GetField()->GetPar2();
459 sEntry = RemoveNewline(sEntry);
460 std::unique_ptr<SwPostItContent> pCnt(new SwPostItContent(
461 this,
462 sEntry,
463 pFormatField,
464 m_nMemberCount));
465 m_pMember->insert(std::move(pCnt));
466 m_nMemberCount++;
467 }
468 }
469 }
470 }
471 m_sTypeToken.clear();
472 m_bEdit = true;
473 nOldMemberCount = m_nMemberCount;
474 }
475 break;
476 case ContentTypeId::DRAWOBJECT:
477 {
478 m_sTypeToken.clear();
479 m_nMemberCount = 0;
480 SwDrawModel* pModel = m_pWrtShell->getIDocumentDrawModelAccess().GetDrawModel();
481 if(pModel)
482 {
483 SdrPage* pPage = pModel->GetPage(0);
484 const size_t nCount = pPage->GetObjCount();
485 for( size_t i=0; i<nCount; ++i )
486 {
487 SdrObject* pTemp = pPage->GetObj(i);
488 // #i51726# - all drawing objects can be named now
489 if (!pTemp->GetName().isEmpty())
490 m_nMemberCount++;
491 }
492 }
493 }
494 break;
495 default: break;
496 }
497 // ... then, the data can also no longer be valid,
498 // apart from those which have already been corrected,
499 // then nOldMemberCount is nevertheless not so old.
500 if( nOldMemberCount != m_nMemberCount )
501 m_bDataValid = false;
502 }
503
~SwContentType()504 SwContentType::~SwContentType()
505 {
506 }
507
GetMember(size_t nIndex)508 const SwContent* SwContentType::GetMember(size_t nIndex)
509 {
510 if(!m_bDataValid || !m_pMember)
511 {
512 FillMemberList();
513 }
514 if(nIndex < m_pMember->size())
515 return (*m_pMember)[nIndex].get();
516
517 return nullptr;
518 }
519
Invalidate()520 void SwContentType::Invalidate()
521 {
522 m_bDataValid = false;
523 }
524
FillMemberList(bool * pbLevelOrVisibilityChanged)525 void SwContentType::FillMemberList(bool* pbLevelOrVisibilityChanged)
526 {
527 std::unique_ptr<SwContentArr> pOldMember;
528 size_t nOldMemberCount = 0;
529 SwPtrMsgPoolItem aAskItem( RES_CONTENT_VISIBLE, nullptr );
530 if(m_pMember && pbLevelOrVisibilityChanged)
531 {
532 pOldMember = std::move(m_pMember);
533 nOldMemberCount = pOldMember->size();
534 m_pMember.reset( new SwContentArr );
535 *pbLevelOrVisibilityChanged = false;
536 }
537 else if(!m_pMember)
538 m_pMember.reset( new SwContentArr );
539 else
540 m_pMember->clear();
541 switch(m_nContentType)
542 {
543 case ContentTypeId::OUTLINE :
544 {
545 const size_t nOutlineCount = m_nMemberCount =
546 m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
547
548 size_t nPos = 0;
549 for (size_t i = 0; i < nOutlineCount; ++i)
550 {
551 const sal_Int8 nLevel = static_cast<sal_Int8>(m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineLevel(i));
552 if(nLevel >= m_nOutlineLevel )
553 m_nMemberCount--;
554 else
555 {
556 if (!m_pWrtShell->getIDocumentOutlineNodesAccess()->isOutlineInLayout(i, *m_pWrtShell->GetLayout()))
557 {
558 --m_nMemberCount;
559 continue; // don't hide it, just skip it
560 }
561 OUString aEntry(comphelper::string::stripStart(
562 m_pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineText(i, m_pWrtShell->GetLayout()), ' '));
563 aEntry = SwNavigationPI::CleanEntry(aEntry);
564 std::unique_ptr<SwOutlineContent> pCnt(new SwOutlineContent(this, aEntry, i, nLevel,
565 m_pWrtShell->IsOutlineMovable( i ), nPos ));
566 m_pMember->insert(std::move(pCnt));
567 // with the same number and existing "pOldMember" the
568 // old one is compared with the new OutlinePos.
569 if (nOldMemberCount > nPos && static_cast<SwOutlineContent*>((*pOldMember)[nPos].get())->GetOutlineLevel() != nLevel)
570 *pbLevelOrVisibilityChanged = true;
571
572 nPos++;
573 }
574 }
575
576 }
577 break;
578
579 case ContentTypeId::TABLE :
580 {
581 const size_t nCount = m_pWrtShell->GetTableFrameFormatCount(true);
582 OSL_ENSURE(m_nMemberCount == nCount, "MemberCount differs");
583 Point aNullPt;
584 m_nMemberCount = nCount;
585 for(size_t i = 0; i < m_nMemberCount; ++i)
586 {
587 const SwFrameFormat& rTableFormat = m_pWrtShell->GetTableFrameFormat(i, true);
588 const OUString& sTableName( rTableFormat.GetName() );
589
590 SwContent* pCnt = new SwContent(this, sTableName,
591 rTableFormat.FindLayoutRect(false, &aNullPt).Top() );
592 if( !rTableFormat.GetInfo( aAskItem ) &&
593 !aAskItem.pObject ) // not visible
594 pCnt->SetInvisible();
595
596 m_pMember->insert(std::unique_ptr<SwContent>(pCnt));
597
598 if(nOldMemberCount > i &&
599 (*pOldMember)[i]->IsInvisible() != pCnt->IsInvisible())
600 *pbLevelOrVisibilityChanged = true;
601 }
602 }
603 break;
604 case ContentTypeId::OLE :
605 case ContentTypeId::FRAME :
606 case ContentTypeId::GRAPHIC :
607 {
608 FlyCntType eType = FLYCNTTYPE_FRM;
609 if(m_nContentType == ContentTypeId::OLE)
610 eType = FLYCNTTYPE_OLE;
611 else if(m_nContentType == ContentTypeId::GRAPHIC)
612 eType = FLYCNTTYPE_GRF;
613 Point aNullPt;
614 m_nMemberCount = m_pWrtShell->GetFlyCount(eType, /*bIgnoreTextBoxes=*/true);
615 std::vector<SwFrameFormat const*> formats(m_pWrtShell->GetFlyFrameFormats(eType, /*bIgnoreTextBoxes=*/true));
616 SAL_WARN_IF(m_nMemberCount != formats.size(), "sw.ui", "MemberCount differs");
617 m_nMemberCount = formats.size();
618 for (size_t i = 0; i < m_nMemberCount; ++i)
619 {
620 SwFrameFormat const*const pFrameFormat = formats[i];
621 const OUString sFrameName = pFrameFormat->GetName();
622
623 SwContent* pCnt;
624 if(ContentTypeId::GRAPHIC == m_nContentType)
625 {
626 OUString sLink;
627 m_pWrtShell->GetGrfNms( &sLink, nullptr, static_cast<const SwFlyFrameFormat*>( pFrameFormat));
628 pCnt = new SwGraphicContent(this, sFrameName,
629 INetURLObject::decode( sLink,
630 INetURLObject::DecodeMechanism::Unambiguous ),
631 pFrameFormat->FindLayoutRect(false, &aNullPt).Top());
632 }
633 else
634 {
635 pCnt = new SwContent(this, sFrameName,
636 pFrameFormat->FindLayoutRect(false, &aNullPt).Top() );
637 }
638 if( !pFrameFormat->GetInfo( aAskItem ) &&
639 !aAskItem.pObject ) // not visible
640 pCnt->SetInvisible();
641 m_pMember->insert(std::unique_ptr<SwContent>(pCnt));
642 if (nOldMemberCount > i &&
643 (*pOldMember)[i]->IsInvisible() != pCnt->IsInvisible())
644 *pbLevelOrVisibilityChanged = true;
645 }
646 }
647 break;
648 case ContentTypeId::BOOKMARK:
649 {
650 IDocumentMarkAccess* const pMarkAccess = m_pWrtShell->getIDocumentMarkAccess();
651 for(IDocumentMarkAccess::const_iterator_t ppBookmark = pMarkAccess->getBookmarksBegin();
652 ppBookmark != pMarkAccess->getBookmarksEnd();
653 ++ppBookmark)
654 {
655 if(lcl_IsUiVisibleBookmark(*ppBookmark))
656 {
657 const OUString& rBkmName = (*ppBookmark)->GetName();
658 //nYPos from 0 -> text::Bookmarks will be sorted alphabetically
659 std::unique_ptr<SwContent> pCnt(new SwContent(this, rBkmName, 0));
660 m_pMember->insert(std::move(pCnt));
661 }
662 }
663 }
664 break;
665 case ContentTypeId::REGION :
666 {
667 const Point aNullPt;
668 m_nMemberCount = m_pWrtShell->GetSectionFormatCount();
669 for(size_t i = 0; i < m_nMemberCount; ++i)
670 {
671 const SwSectionFormat* pFormat;
672 SectionType eTmpType;
673 if( (pFormat = &m_pWrtShell->GetSectionFormat(i))->IsInNodesArr() &&
674 (eTmpType = pFormat->GetSection()->GetType()) != TOX_CONTENT_SECTION
675 && TOX_HEADER_SECTION != eTmpType )
676 {
677 OUString sSectionName = pFormat->GetSection()->GetSectionName();
678
679 sal_uInt8 nLevel = 0;
680 SwSectionFormat* pParentFormat = pFormat->GetParent();
681 while(pParentFormat)
682 {
683 nLevel++;
684 pParentFormat = pParentFormat->GetParent();
685 }
686
687 std::unique_ptr<SwContent> pCnt(new SwRegionContent(this, sSectionName,
688 nLevel,
689 pFormat->FindLayoutRect( false, &aNullPt ).Top()));
690 if( !pFormat->GetInfo( aAskItem ) &&
691 !aAskItem.pObject ) // not visible
692 pCnt->SetInvisible();
693 m_pMember->insert(std::move(pCnt));
694 }
695
696 if(nullptr != pbLevelOrVisibilityChanged)
697 {
698 assert(pOldMember);
699 // need to check visibility (and equal entry number) after
700 // creation due to a sorted list being used here (before,
701 // entries with same index were compared already at creation
702 // time what worked before a sorted list was used)
703 *pbLevelOrVisibilityChanged = checkVisibilityChanged(
704 *pOldMember,
705 *m_pMember);
706 }
707 }
708 m_nMemberCount = m_pMember->size();
709 }
710 break;
711 case ContentTypeId::REFERENCE:
712 {
713 std::vector<OUString> aRefMarks;
714 m_nMemberCount = m_pWrtShell->GetRefMarks( &aRefMarks );
715
716 for (const auto& rRefMark : aRefMarks)
717 {
718 // References sorted alphabetically
719 m_pMember->insert(std::make_unique<SwContent>(this, rRefMark, 0));
720 }
721 }
722 break;
723 case ContentTypeId::URLFIELD:
724 m_nMemberCount = lcl_InsertURLFieldContent(m_pMember.get(), m_pWrtShell, this);
725 break;
726 case ContentTypeId::INDEX:
727 {
728
729 const sal_uInt16 nCount = m_pWrtShell->GetTOXCount();
730 m_nMemberCount = nCount;
731 for ( sal_uInt16 nTox = 0; nTox < nCount; nTox++ )
732 {
733 const SwTOXBase* pBase = m_pWrtShell->GetTOX( nTox );
734 OUString sTOXNm( pBase->GetTOXName() );
735
736 SwContent* pCnt = new SwTOXBaseContent(
737 this, sTOXNm, nTox, *pBase);
738
739 if( !pBase->GetInfo( aAskItem ) &&
740 !aAskItem.pObject ) // not visible
741 pCnt->SetInvisible();
742
743 m_pMember->insert( std::unique_ptr<SwContent>(pCnt) );
744 const size_t nPos = m_pMember->size() - 1;
745 if(nOldMemberCount > nPos &&
746 (*pOldMember)[nPos]->IsInvisible()
747 != pCnt->IsInvisible())
748 *pbLevelOrVisibilityChanged = true;
749 }
750 }
751 break;
752 case ContentTypeId::POSTIT:
753 {
754 m_nMemberCount = 0;
755 m_pMember->clear();
756 SwPostItMgr* aMgr = m_pWrtShell->GetView().GetPostItMgr();
757 if (aMgr)
758 {
759 for(SwPostItMgr::const_iterator i = aMgr->begin(); i != aMgr->end(); ++i)
760 {
761 if (const SwFormatField* pFormatField = dynamic_cast<const SwFormatField *>((*i)->GetBroadcaster())) // SwPostit
762 {
763 if (pFormatField->GetTextField() && pFormatField->IsFieldInDoc() &&
764 (*i)->mLayoutStatus!=SwPostItHelper::INVISIBLE )
765 {
766 OUString sEntry = pFormatField->GetField()->GetPar2();
767 sEntry = RemoveNewline(sEntry);
768 std::unique_ptr<SwPostItContent> pCnt(new SwPostItContent(
769 this,
770 sEntry,
771 pFormatField,
772 m_nMemberCount));
773 m_pMember->insert(std::move(pCnt));
774 m_nMemberCount++;
775 }
776 }
777 }
778 }
779 }
780 break;
781 case ContentTypeId::DRAWOBJECT:
782 {
783 m_nMemberCount = 0;
784 m_pMember->clear();
785
786 IDocumentDrawModelAccess& rIDDMA = m_pWrtShell->getIDocumentDrawModelAccess();
787 SwDrawModel* pModel = rIDDMA.GetDrawModel();
788 if(pModel)
789 {
790 SdrPage* pPage = pModel->GetPage(0);
791 const size_t nCount = pPage->GetObjCount();
792 for( size_t i=0; i<nCount; ++i )
793 {
794 SdrObject* pTemp = pPage->GetObj(i);
795 // #i51726# - all drawing objects can be named now
796 if (!pTemp->GetName().isEmpty())
797 {
798 SwContact* pContact = static_cast<SwContact*>(pTemp->GetUserCall());
799 long nYPos = 0;
800 const Point aNullPt;
801 if(pContact && pContact->GetFormat())
802 nYPos = pContact->GetFormat()->FindLayoutRect(false, &aNullPt).Top();
803 SwContent* pCnt = new SwContent(
804 this,
805 pTemp->GetName(),
806 nYPos);
807 if(!rIDDMA.IsVisibleLayerId(pTemp->GetLayer()))
808 pCnt->SetInvisible();
809 m_pMember->insert(std::unique_ptr<SwContent>(pCnt));
810 m_nMemberCount++;
811 if (nOldMemberCount > i &&
812 (*pOldMember)[i]->IsInvisible() != pCnt->IsInvisible() )
813 *pbLevelOrVisibilityChanged = true;
814 }
815 }
816 }
817 }
818 break;
819 default: break;
820 }
821 m_bDataValid = true;
822 }
823
824 enum STR_CONTEXT_IDX
825 {
826 IDX_STR_OUTLINE_LEVEL = 0,
827 IDX_STR_DRAGMODE = 1,
828 IDX_STR_HYPERLINK = 2,
829 IDX_STR_LINK_REGION = 3,
830 IDX_STR_COPY_REGION = 4,
831 IDX_STR_DISPLAY = 5,
832 IDX_STR_ACTIVE_VIEW = 6,
833 IDX_STR_HIDDEN = 7,
834 IDX_STR_ACTIVE = 8,
835 IDX_STR_INACTIVE = 9,
836 IDX_STR_EDIT_ENTRY = 10,
837 IDX_STR_DELETE_ENTRY = 11,
838 IDX_STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY = 12
839 };
840
841 static const char* STR_CONTEXT_ARY[] =
842 {
843 STR_OUTLINE_LEVEL,
844 STR_DRAGMODE,
845 STR_HYPERLINK,
846 STR_LINK_REGION,
847 STR_COPY_REGION,
848 STR_DISPLAY,
849 STR_ACTIVE_VIEW,
850 STR_HIDDEN,
851 STR_ACTIVE,
852 STR_INACTIVE,
853 STR_EDIT_ENTRY,
854 STR_DELETE_ENTRY,
855 STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY
856 };
857
SwContentTree(vcl::Window * pParent,SwNavigationPI * pDialog)858 SwContentTree::SwContentTree(vcl::Window* pParent, SwNavigationPI* pDialog)
859 : SvTreeListBox(pParent)
860 , m_xDialog(pDialog)
861 , m_sSpace(OUString(" "))
862 , m_sRemoveIdx(SwResId(STR_REMOVE_INDEX))
863 , m_sUpdateIdx(SwResId(STR_UPDATE))
864 , m_sUnprotTable(SwResId(STR_REMOVE_TBL_PROTECTION))
865 , m_sRename(SwResId(STR_RENAME))
866 , m_sReadonlyIdx(SwResId(STR_READONLY_IDX))
867 , m_sInvisible(SwResId(STR_INVISIBLE))
868 , m_sPostItShow(SwResId(STR_POSTIT_SHOW))
869 , m_sPostItHide(SwResId(STR_POSTIT_HIDE))
870 , m_sPostItDelete(SwResId(STR_POSTIT_DELETE))
871 , m_pHiddenShell(nullptr)
872 , m_pActiveShell(nullptr)
873 , m_pConfig(SW_MOD()->GetNavigationConfig())
874 , m_nActiveBlock(0)
875 , m_nHiddenBlock(0)
876 , m_nRootType(ContentTypeId::UNKNOWN)
877 , m_nLastSelType(ContentTypeId::UNKNOWN)
878 , m_nOutlineLevel(MAXLEVEL)
879 , m_eState(State::ACTIVE)
880 , m_bDocChgdInDragging(false)
881 , m_bIsInternalDrag(false)
882 , m_bIsRoot(false)
883 , m_bIsIdleClear(false)
884 , m_bIsLastReadOnly(false)
885 , m_bIsOutlineMoveable(true)
886 , m_bViewHasChanged(false)
887 , m_bIsKeySpace(false)
888 {
889 SetHelpId(HID_NAVIGATOR_TREELIST);
890
891 SetNodeDefaultImages();
892 SetDoubleClickHdl(LINK(this, SwContentTree, ContentDoubleClickHdl));
893 SetDragDropMode(DragDropMode::APP_COPY);
894 for (ContentTypeId i : o3tl::enumrange<ContentTypeId>())
895 {
896 m_aActiveContentArr[i] = nullptr;
897 m_aHiddenContentArr[i] = nullptr;
898 }
899 for (int i = 0; i < CONTEXT_COUNT; ++i)
900 {
901 m_aContextStrings[i] = SwResId(STR_CONTEXT_ARY[i]);
902 }
903 m_nActiveBlock = m_pConfig->GetActiveBlock();
904 m_aUpdTimer.SetInvokeHandler(LINK(this, SwContentTree, TimerUpdate));
905 m_aUpdTimer.SetTimeout(1000);
906 Clear();
907 EnableContextMenuHandling();
908 SetQuickSearch(true);
909 }
910
~SwContentTree()911 SwContentTree::~SwContentTree()
912 {
913 disposeOnce();
914 }
915
dispose()916 void SwContentTree::dispose()
917 {
918 Clear(); // If applicable erase content types previously.
919 bIsInDrag = false;
920 m_aUpdTimer.Stop();
921 SetActiveShell(nullptr);
922 m_xDialog.clear();
923 SvTreeListBox::dispose();
924 }
925
GetOptimalSize() const926 Size SwContentTree::GetOptimalSize() const
927 {
928 return LogicToPixel(Size(110, 112), MapMode(MapUnit::MapAppFont));
929 }
930
GetEntryAltText(SvTreeListEntry * pEntry) const931 OUString SwContentTree::GetEntryAltText( SvTreeListEntry* pEntry ) const
932 {
933 if (pEntry == nullptr || !lcl_IsContent(pEntry))
934 return OUString();
935
936 assert(pEntry->GetUserData() == nullptr || dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
937 SwContent* pCnt = static_cast<SwContent*>(pEntry->GetUserData());
938 if( pCnt == nullptr || pCnt->GetParent() == nullptr)
939 return OUString();
940
941 ContentTypeId nJumpType = pCnt->GetParent()->GetType();
942 SdrObject* pTemp;
943
944 switch(nJumpType)
945 {
946 case ContentTypeId::DRAWOBJECT:
947 {
948 SdrView* pDrawView = m_pActiveShell->GetDrawView();
949 if (pDrawView)
950 {
951 SwDrawModel* pDrawModel = m_pActiveShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
952 SdrPage* pPage = pDrawModel->GetPage(0);
953 const size_t nCount = pPage->GetObjCount();
954 for( size_t i=0; i<nCount; ++i )
955 {
956 pTemp = pPage->GetObj(i);
957 sal_uInt16 nCmpId;
958 switch( pTemp->GetObjIdentifier() )
959 {
960 case OBJ_GRUP:
961 case OBJ_TEXT:
962 case OBJ_LINE:
963 case OBJ_RECT:
964 case OBJ_CUSTOMSHAPE:
965 case OBJ_CIRC:
966 case OBJ_SECT:
967 case OBJ_CARC:
968 case OBJ_CCUT:
969 case OBJ_POLY:
970 case OBJ_PLIN:
971 case OBJ_PATHLINE:
972 case OBJ_PATHFILL:
973 case OBJ_FREELINE:
974 case OBJ_FREEFILL:
975 case OBJ_PATHPOLY:
976 case OBJ_PATHPLIN:
977 case OBJ_CAPTION:
978 nCmpId = OBJ_GRUP;
979 break;
980 default:
981 nCmpId = pTemp->GetObjIdentifier();
982 }
983 if(nCmpId == OBJ_GRUP && pTemp->GetName() == pCnt->GetName())
984 {
985 return pTemp->GetTitle();
986 }
987 }
988 }
989 }
990 break;
991 case ContentTypeId::GRAPHIC :
992 {
993 if( m_pActiveShell && m_pActiveShell->GetDoc() )
994 {
995 const SwFlyFrameFormat* pFrameFormat = m_pActiveShell->GetDoc()->FindFlyByName( pCnt->GetName());
996 if( pFrameFormat )
997 return pFrameFormat->GetObjTitle();
998 }
999 }
1000 break;
1001 case ContentTypeId::OLE :
1002 case ContentTypeId::FRAME :
1003 {
1004 //Can't find the GetAlternateText function. Need to verify again.
1005 const SwFlyFrameFormat* pFlyFormat = m_pActiveShell->GetDoc()->FindFlyByName( pCnt->GetName());
1006 if( pFlyFormat )
1007 return pFlyFormat->/*GetAlternateText*/GetName();
1008 }
1009 break;
1010 default: break;
1011 }
1012 return OUString();
1013 }
1014
GetEntryLongDescription(SvTreeListEntry * pEntry) const1015 OUString SwContentTree::GetEntryLongDescription( SvTreeListEntry* pEntry ) const
1016 {
1017 if( pEntry == nullptr)
1018 return OUString();
1019
1020 assert(pEntry->GetUserData() == nullptr || dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
1021 SwContent* pCnt = static_cast<SwContent*>(pEntry->GetUserData());
1022 if( pCnt == nullptr || pCnt->GetParent() == nullptr)
1023 return OUString();
1024
1025 SdrObject* pTemp;
1026
1027 switch(pCnt->GetParent()->GetType())
1028 {
1029 case ContentTypeId::DRAWOBJECT:
1030 {
1031 SdrView* pDrawView = m_pActiveShell->GetDrawView();
1032 if (pDrawView)
1033 {
1034 SwDrawModel* pDrawModel = m_pActiveShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
1035 SdrPage* pPage = pDrawModel->GetPage(0);
1036 const size_t nCount = pPage->GetObjCount();
1037 for( size_t i=0; i<nCount; ++i )
1038 {
1039 pTemp = pPage->GetObj(i);
1040 sal_uInt16 nCmpId;
1041 switch( pTemp->GetObjIdentifier() )
1042 {
1043 case OBJ_GRUP:
1044 case OBJ_TEXT:
1045 case OBJ_LINE:
1046 case OBJ_RECT:
1047 case OBJ_CUSTOMSHAPE:
1048 case OBJ_CIRC:
1049 case OBJ_SECT:
1050 case OBJ_CARC:
1051 case OBJ_CCUT:
1052 case OBJ_POLY:
1053 case OBJ_PLIN:
1054 case OBJ_PATHLINE:
1055 case OBJ_PATHFILL:
1056 case OBJ_FREELINE:
1057 case OBJ_FREEFILL:
1058 case OBJ_PATHPOLY:
1059 case OBJ_PATHPLIN:
1060 case OBJ_CAPTION:
1061 nCmpId = OBJ_GRUP;
1062 break;
1063 default:
1064 nCmpId = pTemp->GetObjIdentifier();
1065 }
1066 if(nCmpId == OBJ_GRUP /*dynamic_cast< const SdrObjGroup *>( pTemp ) != nullptr*/ && pTemp->GetName() == pCnt->GetName())
1067 {
1068 return pTemp->GetDescription();
1069 }
1070 }
1071 }
1072 }
1073 break;
1074 case ContentTypeId::GRAPHIC :
1075 case ContentTypeId::OLE :
1076 case ContentTypeId::FRAME :
1077 {
1078 //Can't find the function "GetLongDescription". Need to verify again.
1079 const SwFlyFrameFormat* pFlyFormat = m_pActiveShell->GetDoc()->FindFlyByName( pCnt->GetName());
1080 if( pFlyFormat )
1081 return pFlyFormat->GetDescription();
1082 }
1083 break;
1084 default: break;
1085 }
1086 return OUString();
1087 }
1088
1089 // Drag&Drop methods
1090
StartDrag(sal_Int8 nAction,const Point & rPosPixel)1091 void SwContentTree::StartDrag( sal_Int8 nAction, const Point& rPosPixel )
1092 {
1093 if( !m_bIsRoot || m_nRootType != ContentTypeId::OUTLINE )
1094 {
1095 ReleaseMouse();
1096
1097 rtl::Reference<TransferDataContainer> pContainer = new TransferDataContainer;
1098
1099 sal_Int8 nDragMode = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
1100 if( FillTransferData( *pContainer, nDragMode ))
1101 {
1102 SwContentTree::SetInDrag(true);
1103 pContainer->StartDrag( this, nDragMode, GetDragFinishedHdl() );
1104 }
1105 }
1106 else
1107 {
1108 SwWrtShell *const pShell = GetWrtShell();
1109 pShell->StartAllAction();
1110 pShell->StartUndo(SwUndoId::OUTLINE_UD);
1111 // Only move drag entry and continuous selected siblings:
1112 m_aDndOutlinesSelected.clear();
1113 SvTreeListEntry* pEntry = GetEntry(rPosPixel);
1114 // Find first selected of continuous siblings
1115 while (pEntry && IsSelected(pEntry->PrevSibling()))
1116 {
1117 pEntry = pEntry->PrevSibling();
1118 }
1119 // Record continuous selected siblings
1120 if (pEntry)
1121 {
1122 m_aDndOutlinesSelected.push_back(pEntry);
1123 while (pEntry && IsSelected(pEntry->NextSibling()))
1124 {
1125 pEntry = pEntry->NextSibling();
1126 m_aDndOutlinesSelected.push_back(pEntry);
1127 }
1128 }
1129 SvTreeListBox::StartDrag( nAction, rPosPixel );
1130 }
1131 }
1132
DragFinished(sal_Int8 nAction)1133 void SwContentTree::DragFinished( sal_Int8 nAction )
1134 {
1135 if (m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE)
1136 {
1137 SwWrtShell *const pShell = GetWrtShell();
1138 pShell->EndUndo();
1139 pShell->EndAllAction();
1140 m_aActiveContentArr[ContentTypeId::OUTLINE]->Invalidate();
1141 Display(true);
1142 m_aDndOutlinesSelected.clear();
1143 }
1144
1145 // To prevent the removing of the selected entry in external drag and drop
1146 // the drag action mustn't be MOVE.
1147 SvTreeListBox::DragFinished( m_bIsInternalDrag ? nAction : DND_ACTION_COPY );
1148 SwContentTree::SetInDrag(false);
1149 m_bIsInternalDrag = false;
1150 }
1151
1152 // QueryDrop will be executed in the navigator
1153
AcceptDrop(const AcceptDropEvent & rEvt)1154 sal_Int8 SwContentTree::AcceptDrop( const AcceptDropEvent& rEvt )
1155 {
1156 sal_Int8 nRet = DND_ACTION_NONE;
1157 if( m_bIsRoot )
1158 {
1159 if( m_bIsOutlineMoveable )
1160 nRet = SvTreeListBox::AcceptDrop( rEvt );
1161 }
1162 else if( !bIsInDrag )
1163 nRet = GetParentWindow()->AcceptDrop();
1164 return nRet;
1165 }
1166
1167 // Drop will be executed in the navigator
1168
lcl_GetOutlineKey(SwContentTree * pTree,SwOutlineContent const * pContent)1169 static void* lcl_GetOutlineKey( SwContentTree* pTree, SwOutlineContent const * pContent)
1170 {
1171 void* key = nullptr;
1172 if( pTree && pContent )
1173 {
1174 SwWrtShell* pShell = pTree->GetWrtShell();
1175 auto const nPos = pContent->GetOutlinePos();
1176
1177 key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
1178 }
1179 return key;
1180 }
1181
ExecuteDrop(const ExecuteDropEvent & rEvt)1182 sal_Int8 SwContentTree::ExecuteDrop( const ExecuteDropEvent& rEvt )
1183 {
1184 SvTreeListEntry* pEntry = pTargetEntry;
1185 if( pEntry && ( m_nRootType == ContentTypeId::OUTLINE ) && lcl_IsContent( pEntry ) )
1186 {
1187 assert(pEntry->GetUserData() == nullptr || dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
1188 SwOutlineContent* pOutlineContent = static_cast<SwOutlineContent*>(pEntry->GetUserData());
1189 if( pOutlineContent )
1190 {
1191 void* key = lcl_GetOutlineKey(this, pOutlineContent);
1192 if( !mOutLineNodeMap[key] )
1193 {
1194 while( pEntry->HasChildren() )
1195 {
1196 SvTreeListEntry* pChildEntry = FirstChild( pEntry );
1197 while( pChildEntry )
1198 {
1199 pEntry = pChildEntry;
1200 pChildEntry = pChildEntry->NextSibling();
1201 }
1202 }
1203 pTargetEntry = pEntry;
1204 }
1205 }
1206 }
1207 if( m_bIsRoot )
1208 return SvTreeListBox::ExecuteDrop( rEvt );
1209 return bIsInDrag ? DND_ACTION_NONE : GetParentWindow()->ExecuteDrop(rEvt);
1210 }
1211
1212 // Handler for Dragging and ContextMenu
1213
lcl_InsertExpandCollapseAllItem(SwContentTree * pContentTree,SvTreeListEntry * pEntry,PopupMenu * pPop)1214 static void lcl_InsertExpandCollapseAllItem(SwContentTree* pContentTree, SvTreeListEntry* pEntry, PopupMenu* pPop)
1215 {
1216 if(pEntry->HasChildren() || pEntry->HasChildrenOnDemand())
1217 {
1218 pPop->InsertSeparator();
1219 pPop->InsertItem(800, pContentTree->IsAllExpanded(pEntry) ? SwResId(STR_COLLAPSEALL) : SwResId(STR_EXPANDALL));
1220 pPop->SetAccelKey(800, vcl::KeyCode(KEY_MULTIPLY, false, true, false, false));
1221 }
1222 }
1223
CreateContextMenu()1224 VclPtr<PopupMenu> SwContentTree::CreateContextMenu()
1225 {
1226 auto pPop = VclPtr<PopupMenu>::Create();
1227 VclPtrInstance<PopupMenu> pSubPop1;
1228 VclPtrInstance<PopupMenu> pSubPop2;
1229 VclPtrInstance<PopupMenu> pSubPop3;
1230 VclPtrInstance<PopupMenu> pSubPop4; // Edit
1231 bool bSubPop4 = false;
1232
1233 for(int i = 1; i <= MAXLEVEL; ++i)
1234 {
1235 pSubPop1->InsertItem(i + 100, OUString::number(i), MenuItemBits::AUTOCHECK | MenuItemBits::RADIOCHECK);
1236 }
1237 pSubPop1->CheckItem(100 + m_nOutlineLevel);
1238 for(int i=0; i < 3; ++i)
1239 {
1240 pSubPop2->InsertItem(i + 201, m_aContextStrings[
1241 IDX_STR_HYPERLINK + i], MenuItemBits::AUTOCHECK | MenuItemBits::RADIOCHECK);
1242 }
1243 pSubPop2->CheckItem(201 + static_cast<int>(GetParentWindow()->GetRegionDropMode()));
1244 // Insert the list of the open files
1245 sal_uInt16 nId = 301;
1246 const SwView* pActiveView = ::GetActiveView();
1247 SwView *pView = SwModule::GetFirstView();
1248 while (pView)
1249 {
1250 OUString sInsert = pView->GetDocShell()->GetTitle();
1251 if(pView == pActiveView)
1252 {
1253 sInsert += "(" +
1254 m_aContextStrings[IDX_STR_ACTIVE] +
1255 ")";
1256 }
1257 pSubPop3->InsertItem(nId, sInsert, MenuItemBits::AUTOCHECK | MenuItemBits::RADIOCHECK);
1258 if (State::CONSTANT == m_eState && m_pActiveShell == &pView->GetWrtShell())
1259 pSubPop3->CheckItem(nId);
1260 pView = SwModule::GetNextView(pView);
1261 nId++;
1262 }
1263 pSubPop3->InsertItem(nId++, m_aContextStrings[IDX_STR_ACTIVE_VIEW], MenuItemBits::AUTOCHECK | MenuItemBits::RADIOCHECK);
1264 if(m_pHiddenShell)
1265 {
1266 OUString sHiddenEntry = m_pHiddenShell->GetView().GetDocShell()->GetTitle() +
1267 " ( " +
1268 m_aContextStrings[IDX_STR_HIDDEN] +
1269 " )";
1270 pSubPop3->InsertItem(nId, sHiddenEntry, MenuItemBits::AUTOCHECK | MenuItemBits::RADIOCHECK);
1271 }
1272
1273 if (State::ACTIVE == m_eState)
1274 pSubPop3->CheckItem( --nId );
1275 else if (State::HIDDEN == m_eState)
1276 pSubPop3->CheckItem( nId );
1277
1278 pPop->InsertItem( 1, m_aContextStrings[IDX_STR_OUTLINE_LEVEL]);
1279 pPop->InsertItem(2, m_aContextStrings[IDX_STR_DRAGMODE]);
1280 pPop->InsertItem(3, m_aContextStrings[IDX_STR_DISPLAY]);
1281 // Now edit
1282 SvTreeListEntry* pEntry = nullptr;
1283 // Edit only if the shown content is coming from the current view.
1284 if ((State::ACTIVE == m_eState || m_pActiveShell == pActiveView->GetWrtShellPtr())
1285 && nullptr != (pEntry = FirstSelected()) && lcl_IsContent(pEntry))
1286 {
1287 assert(dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
1288 const SwContentType* pContType = static_cast<SwContent*>(pEntry->GetUserData())->GetParent();
1289 const ContentTypeId nContentType = pContType->GetType();
1290 bool bReadonly = m_pActiveShell->GetView().GetDocShell()->IsReadOnly();
1291 bool bVisible = !static_cast<SwContent*>(pEntry->GetUserData())->IsInvisible();
1292 bool bProtected = static_cast<SwContent*>(pEntry->GetUserData())->IsProtect();
1293 bool bEditable = pContType->IsEditable() &&
1294 ((bVisible && !bProtected) ||ContentTypeId::REGION == nContentType);
1295 bool bDeletable = pContType->IsDeletable() &&
1296 ((bVisible && !bProtected) ||ContentTypeId::REGION == nContentType);
1297 bool bRenamable = bEditable && !bReadonly &&
1298 (ContentTypeId::TABLE == nContentType ||
1299 ContentTypeId::FRAME == nContentType ||
1300 ContentTypeId::GRAPHIC == nContentType ||
1301 ContentTypeId::OLE == nContentType ||
1302 ContentTypeId::BOOKMARK == nContentType ||
1303 ContentTypeId::REGION == nContentType||
1304 ContentTypeId::INDEX == nContentType);
1305
1306 if(!bReadonly && (bEditable || bDeletable))
1307 {
1308 if(ContentTypeId::INDEX == nContentType)
1309 {
1310 bSubPop4 = true;
1311 pSubPop4->InsertItem(401, m_sRemoveIdx);
1312 pSubPop4->InsertItem(402, m_sUpdateIdx);
1313
1314 const SwTOXBase* pBase = static_cast<SwTOXBaseContent*>(pEntry->GetUserData())->GetTOXBase();
1315 if(!pBase->IsTOXBaseInReadonly())
1316 pSubPop4->InsertItem(403, m_aContextStrings[IDX_STR_EDIT_ENTRY]);
1317 pSubPop4->InsertItem(405, m_sReadonlyIdx);
1318
1319 pSubPop4->CheckItem( 405, SwEditShell::IsTOXBaseReadonly(*pBase));
1320 pSubPop4->InsertItem(501, m_aContextStrings[IDX_STR_DELETE_ENTRY]);
1321 }
1322 else if(ContentTypeId::TABLE == nContentType)
1323 {
1324 bSubPop4 = true;
1325 pSubPop4->InsertItem(403, m_aContextStrings[IDX_STR_EDIT_ENTRY]);
1326 pSubPop4->InsertItem(404, m_sUnprotTable);
1327 bool bFull = false;
1328 OUString sTableName = static_cast<SwContent*>(pEntry->GetUserData())->GetName();
1329 bool bProt = m_pActiveShell->HasTableAnyProtection( &sTableName, &bFull );
1330 pSubPop4->EnableItem(403, !bFull );
1331 pSubPop4->EnableItem(404, bProt );
1332 pSubPop4->InsertItem(501, m_aContextStrings[IDX_STR_DELETE_ENTRY]);
1333 }
1334 else
1335 {
1336
1337 if(bEditable && bDeletable)
1338 {
1339 pSubPop4->InsertItem(403, m_aContextStrings[IDX_STR_EDIT_ENTRY]);
1340 pSubPop4->InsertItem(501, m_aContextStrings[IDX_STR_DELETE_ENTRY]);
1341 bSubPop4 = true;
1342 }
1343 else if(bEditable)
1344 pPop->InsertItem(403, m_aContextStrings[IDX_STR_EDIT_ENTRY]);
1345 else if(bDeletable)
1346 {
1347 pSubPop4->InsertItem(501, m_aContextStrings[IDX_STR_DELETE_ENTRY]);
1348 }
1349 }
1350 //Rename object
1351 if(bRenamable)
1352 {
1353 if(bSubPop4)
1354 pSubPop4->InsertItem(502, m_sRename);
1355 else
1356 pPop->InsertItem(502, m_sRename);
1357 }
1358
1359 if(bSubPop4)
1360 {
1361 pPop->InsertItem(4, pContType->GetSingleName());
1362 pPop->SetPopupMenu(4, pSubPop4);
1363 }
1364 }
1365 else if(ContentTypeId::OUTLINE == nContentType)
1366 lcl_InsertExpandCollapseAllItem(this, pEntry, pPop);
1367 }
1368 else if( pEntry )
1369 {
1370 assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
1371 SwContentType* pType = static_cast<SwContentType*>(pEntry->GetUserData());
1372 if(ContentTypeId::OUTLINE == pType->GetType())
1373 {
1374 lcl_InsertExpandCollapseAllItem(this, pEntry, pPop);
1375 pPop->InsertSeparator();
1376 pPop->InsertItem(700, m_aContextStrings[IDX_STR_SEND_OUTLINE_TO_CLIPBOARD_ENTRY]);
1377 }
1378 if ( (pType->GetType() == ContentTypeId::POSTIT) && (!m_pActiveShell->GetView().GetDocShell()->IsReadOnly()) && ( pType->GetMemberCount() > 0) )
1379 {
1380 bSubPop4 = true;
1381 pSubPop4->InsertItem(600, m_sPostItShow );
1382 pSubPop4->InsertItem(601, m_sPostItHide );
1383 pSubPop4->InsertItem(602, m_sPostItDelete );
1384 pPop->InsertItem(4, pType->GetSingleName());
1385 pPop->SetPopupMenu(4, pSubPop4);
1386 }
1387 }
1388
1389 pPop->SetPopupMenu( 1, pSubPop1 );
1390 pPop->SetPopupMenu( 2, pSubPop2 );
1391 pPop->SetPopupMenu( 3, pSubPop3 );
1392 if (!bSubPop4)
1393 pSubPop4.disposeAndClear();
1394 return pPop;
1395 }
1396
1397 // Indentation for outlines (and sections)
1398
GetTabPos(SvTreeListEntry * pEntry,SvLBoxTab * pTab)1399 sal_IntPtr SwContentTree::GetTabPos( SvTreeListEntry* pEntry, SvLBoxTab* pTab)
1400 {
1401 sal_IntPtr nLevel = 0;
1402 if(lcl_IsContent(pEntry))
1403 {
1404 nLevel++;
1405 assert(pEntry->GetUserData() == nullptr || dynamic_cast<SwContent *>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
1406 SwContent* pCnt = static_cast<SwContent *>(pEntry->GetUserData());
1407 const SwContentType* pParent;
1408 if(pCnt && nullptr != (pParent = pCnt->GetParent()))
1409 {
1410 if(pParent->GetType() == ContentTypeId::OUTLINE)
1411 nLevel = nLevel + static_cast<SwOutlineContent*>(pCnt)->GetOutlineLevel();
1412 else if(pParent->GetType() == ContentTypeId::REGION)
1413 nLevel = nLevel + static_cast<SwRegionContent*>(pCnt)->GetRegionLevel();
1414 }
1415 }
1416 return nLevel * 10 + (m_bIsRoot ? 0 : 5) + pTab->GetPos(); //determined empirically
1417 }
1418
1419 // Content will be integrated into the Box only on demand.
1420
RequestingChildren(SvTreeListEntry * pParent)1421 void SwContentTree::RequestingChildren( SvTreeListEntry* pParent )
1422 {
1423 // Is this a content type?
1424 if(lcl_IsContentType(pParent))
1425 {
1426 if(!pParent->HasChildren())
1427 {
1428 assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pParent->GetUserData())));
1429 SwContentType* pCntType = static_cast<SwContentType*>(pParent->GetUserData());
1430
1431 const size_t nCount = pCntType->GetMemberCount();
1432 // Add for outline plus/minus
1433 if(pCntType->GetType() == ContentTypeId::OUTLINE)
1434 {
1435 SvTreeListEntry* pChild = nullptr;
1436 for(size_t i = 0; i < nCount; ++i)
1437 {
1438 const SwContent* pCnt = pCntType->GetMember(i);
1439 if(pCnt)
1440 {
1441 const auto nLevel = static_cast<const SwOutlineContent*>(pCnt)->GetOutlineLevel();
1442 OUString sEntry = pCnt->GetName();
1443 if(sEntry.isEmpty())
1444 sEntry = m_sSpace;
1445 if(!pChild || (nLevel == 0))
1446 pChild = InsertEntry(sEntry, pParent, false, TREELIST_APPEND,const_cast<SwContent *>(pCnt));
1447 else
1448 {
1449 //back search parent.
1450 if(static_cast<const SwOutlineContent*>(pCntType->GetMember(i-1))->GetOutlineLevel() < nLevel)
1451 pChild = InsertEntry(sEntry, pChild, false, TREELIST_APPEND, const_cast<SwContent *>(pCnt));
1452 else
1453 {
1454 pChild = Prev(pChild);
1455 assert(!pChild || lcl_IsContentType(pChild) || dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pChild->GetUserData())));
1456 while(pChild &&
1457 lcl_IsContent(pChild) &&
1458 (static_cast<SwOutlineContent*>(pChild->GetUserData())->GetOutlineLevel() >= nLevel)
1459 )
1460 {
1461 pChild = Prev(pChild);
1462 }
1463 if(pChild)
1464 pChild = InsertEntry(sEntry, pChild,
1465 false, TREELIST_APPEND, const_cast<SwContent *>(pCnt));
1466 }
1467 }
1468 }
1469 }
1470 }
1471 else
1472 {
1473 for(size_t i = 0; i < nCount; ++i)
1474 {
1475 const SwContent* pCnt = pCntType->GetMember(i);
1476 if (pCnt)
1477 {
1478 OUString sEntry = pCnt->GetName();
1479 if (sEntry.isEmpty())
1480 sEntry = m_sSpace;
1481 InsertEntry(sEntry, pParent, false, TREELIST_APPEND, const_cast<SwContent *>(pCnt));
1482 }
1483 }
1484 }
1485 }
1486 }
1487 }
1488
GetDrawingObjectsByContent(const SwContent * pCnt)1489 SdrObject* SwContentTree::GetDrawingObjectsByContent(const SwContent *pCnt)
1490 {
1491 SdrObject *pRetObj = nullptr;
1492 switch(pCnt->GetParent()->GetType())
1493 {
1494 case ContentTypeId::DRAWOBJECT:
1495 {
1496 SdrView* pDrawView = m_pActiveShell->GetDrawView();
1497 if (pDrawView)
1498 {
1499 SwDrawModel* pDrawModel = m_pActiveShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
1500 SdrPage* pPage = pDrawModel->GetPage(0);
1501 const size_t nCount = pPage->GetObjCount();
1502
1503 for( size_t i=0; i<nCount; ++i )
1504 {
1505 SdrObject* pTemp = pPage->GetObj(i);
1506 if( pTemp->GetName() == pCnt->GetName())
1507 {
1508 pRetObj = pTemp;
1509 break;
1510 }
1511 }
1512 }
1513 break;
1514 }
1515 default:
1516 pRetObj = nullptr;
1517 }
1518 return pRetObj;
1519 }
1520
Expand(SvTreeListEntry * pParent)1521 bool SwContentTree::Expand( SvTreeListEntry* pParent )
1522 {
1523 if (!(pParent->HasChildren() || pParent->HasChildrenOnDemand()))
1524 return SvTreeListBox::Expand(pParent);
1525
1526 if (!m_bIsRoot
1527 || (lcl_IsContentType(pParent) && static_cast<SwContentType*>(pParent->GetUserData())->GetType() == ContentTypeId::OUTLINE)
1528 || (m_nRootType == ContentTypeId::OUTLINE))
1529 {
1530 if(lcl_IsContentType(pParent))
1531 {
1532 SwContentType* pCntType = static_cast<SwContentType*>(pParent->GetUserData());
1533 const sal_Int32 nOr = 1 << static_cast<int>(pCntType->GetType()); //linear -> Bitposition
1534 if (State::HIDDEN != m_eState)
1535 {
1536 m_nActiveBlock |= nOr;
1537 m_pConfig->SetActiveBlock(m_nActiveBlock);
1538 }
1539 else
1540 m_nHiddenBlock |= nOr;
1541 if(pCntType->GetType() == ContentTypeId::OUTLINE)
1542 {
1543 std::map< void*, bool > aCurrOutLineNodeMap;
1544
1545 SwWrtShell* pShell = GetWrtShell();
1546 bool bBool = SvTreeListBox::Expand(pParent);
1547 SvTreeListEntry* pChild = Next(pParent);
1548 while(pChild && lcl_IsContent(pChild) && pParent->HasChildren())
1549 {
1550 if(pChild->HasChildren())
1551 {
1552 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pChild->GetUserData())));
1553 auto const nPos = static_cast<SwOutlineContent*>(pChild->GetUserData())->GetOutlinePos();
1554 void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
1555 aCurrOutLineNodeMap.emplace( key, false );
1556 std::map<void*, bool>::iterator iter = mOutLineNodeMap.find( key );
1557 if( iter != mOutLineNodeMap.end() && mOutLineNodeMap[key])
1558 {
1559 aCurrOutLineNodeMap[key] = true;
1560 SvTreeListBox::Expand(pChild);
1561 }
1562 }
1563 pChild = Next(pChild);
1564 }
1565 mOutLineNodeMap = aCurrOutLineNodeMap;
1566 return bBool;
1567 }
1568
1569 }
1570 else if( lcl_IsContent(pParent) && static_cast<SwContentType*>(pParent->GetUserData())->GetType() == ContentTypeId::OUTLINE)
1571 {
1572 SwWrtShell* pShell = GetWrtShell();
1573 // paranoid assert now that outline type is checked
1574 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pParent->GetUserData())));
1575 auto const nPos = static_cast<SwOutlineContent*>(pParent->GetUserData())->GetOutlinePos();
1576 void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
1577 mOutLineNodeMap[key] = true;
1578 }
1579 }
1580 return SvTreeListBox::Expand(pParent);
1581 }
1582
Collapse(SvTreeListEntry * pParent)1583 bool SwContentTree::Collapse( SvTreeListEntry* pParent )
1584 {
1585 if (!m_bIsRoot
1586 || (lcl_IsContentType(pParent) && static_cast<SwContentType*>(pParent->GetUserData())->GetType() == ContentTypeId::OUTLINE)
1587 || (m_nRootType == ContentTypeId::OUTLINE))
1588 {
1589 if(lcl_IsContentType(pParent))
1590 {
1591 if(m_bIsRoot)
1592 return false;
1593 SwContentType* pCntType = static_cast<SwContentType*>(pParent->GetUserData());
1594 const sal_Int32 nAnd = ~(1 << static_cast<int>(pCntType->GetType()));
1595 if (State::HIDDEN != m_eState)
1596 {
1597 m_nActiveBlock &= nAnd;
1598 m_pConfig->SetActiveBlock(m_nActiveBlock);
1599 }
1600 else
1601 m_nHiddenBlock &= nAnd;
1602 }
1603 else if( lcl_IsContent(pParent) )
1604 {
1605 SwWrtShell* pShell = GetWrtShell();
1606 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pParent->GetUserData())));
1607 auto const nPos = static_cast<SwOutlineContent*>(pParent->GetUserData())->GetOutlinePos();
1608 void* key = static_cast<void*>(pShell->getIDocumentOutlineNodesAccess()->getOutlineNode( nPos ));
1609 mOutLineNodeMap[key] = false;
1610 }
1611 }
1612
1613 return SvTreeListBox::Collapse(pParent);
1614 }
1615
1616 // Also on double click will be initially opened only.
1617
IMPL_LINK_NOARG(SwContentTree,ContentDoubleClickHdl,SvTreeListBox *,bool)1618 IMPL_LINK_NOARG(SwContentTree, ContentDoubleClickHdl, SvTreeListBox*, bool)
1619 {
1620 SvTreeListEntry* pEntry = GetCurEntry();
1621 // Is it a content type?
1622 OSL_ENSURE(pEntry, "no current entry!");
1623 if(pEntry)
1624 {
1625 if(lcl_IsContentType(pEntry) && !pEntry->HasChildren())
1626 {
1627 RequestingChildren(pEntry);
1628 }
1629 else if (!lcl_IsContentType(pEntry) && (State::HIDDEN != m_eState))
1630 {
1631 if (State::CONSTANT == m_eState)
1632 {
1633 m_pActiveShell->GetView().GetViewFrame()->GetWindow().ToTop();
1634 }
1635 //Jump to content type:
1636 assert(dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
1637 SwContent* pCnt = static_cast<SwContent*>(pEntry->GetUserData());
1638 OSL_ENSURE( pCnt, "no UserData");
1639 GotoContent(pCnt);
1640 if(pCnt->GetParent()->GetType() == ContentTypeId::FRAME)
1641 m_pActiveShell->EnterStdMode();
1642 return false; // treelist processing finished
1643 }
1644 return true; // signal more to be done, i.e. expand/collapse children
1645 }
1646 return false;
1647 }
1648
1649 namespace
1650 {
GetBitmapForContentTypeId(ContentTypeId eType)1651 BitmapEx GetBitmapForContentTypeId(ContentTypeId eType)
1652 {
1653 OUString sResId;
1654
1655 switch (eType)
1656 {
1657 case ContentTypeId::OUTLINE:
1658 sResId = RID_BMP_NAVI_OUTLINE;
1659 break;
1660 case ContentTypeId::TABLE:
1661 sResId = RID_BMP_NAVI_TABLE;
1662 break;
1663 case ContentTypeId::FRAME:
1664 sResId = RID_BMP_NAVI_FRAME;
1665 break;
1666 case ContentTypeId::GRAPHIC:
1667 sResId = RID_BMP_NAVI_GRAPHIC;
1668 break;
1669 case ContentTypeId::OLE:
1670 sResId = RID_BMP_NAVI_OLE;
1671 break;
1672 case ContentTypeId::BOOKMARK:
1673 sResId = RID_BMP_NAVI_BOOKMARK;
1674 break;
1675 case ContentTypeId::REGION:
1676 sResId = RID_BMP_NAVI_REGION;
1677 break;
1678 case ContentTypeId::URLFIELD:
1679 sResId = RID_BMP_NAVI_URLFIELD;
1680 break;
1681 case ContentTypeId::REFERENCE:
1682 sResId = RID_BMP_NAVI_REFERENCE;
1683 break;
1684 case ContentTypeId::INDEX:
1685 sResId = RID_BMP_NAVI_INDEX;
1686 break;
1687 case ContentTypeId::POSTIT:
1688 sResId = RID_BMP_NAVI_POSTIT;
1689 break;
1690 case ContentTypeId::DRAWOBJECT:
1691 sResId = RID_BMP_NAVI_DRAWOBJECT;
1692 break;
1693 case ContentTypeId::UNKNOWN:
1694 SAL_WARN("sw.ui", "ContentTypeId::UNKNOWN has no bitmap preview");
1695 break;
1696 }
1697
1698 return BitmapEx(sResId);
1699 };
1700 }
1701
Display(bool bActive)1702 void SwContentTree::Display( bool bActive )
1703 {
1704 // First read the selected entry to select it later again if necessary
1705 // -> the user data here are no longer valid!
1706 SvTreeListEntry* pOldSelEntry = FirstSelected();
1707 OUString sEntryName; // Name of the entry
1708 sal_uLong nEntryRelPos = 0; // relative position to their parent
1709 sal_uInt32 nOldEntryCount = GetEntryCount();
1710 sal_Int32 nOldScrollPos = 0;
1711 if(pOldSelEntry)
1712 {
1713 ScrollBar* pVScroll = GetVScroll();
1714 if(pVScroll && pVScroll->IsVisible())
1715 nOldScrollPos = pVScroll->GetThumbPos();
1716
1717 sEntryName = GetEntryText(pOldSelEntry);
1718 SvTreeListEntry* pParantEntry = pOldSelEntry;
1719 while( GetParent(pParantEntry))
1720 {
1721 pParantEntry = GetParent(pParantEntry);
1722 }
1723 if(GetParent(pOldSelEntry))
1724 {
1725 nEntryRelPos = GetModel()->GetAbsPos(pOldSelEntry) - GetModel()->GetAbsPos(pParantEntry);
1726 }
1727 }
1728 Clear();
1729 SetUpdateMode( false );
1730 if (!bActive)
1731 m_eState = State::HIDDEN;
1732 else if (State::HIDDEN == m_eState)
1733 m_eState = State::ACTIVE;
1734 SwWrtShell* pShell = GetWrtShell();
1735 const bool bReadOnly = !pShell || pShell->GetView().GetDocShell()->IsReadOnly();
1736 if(bReadOnly != m_bIsLastReadOnly)
1737 {
1738 m_bIsLastReadOnly = bReadOnly;
1739 bool bDisable = pShell == nullptr || bReadOnly;
1740 SwNavigationPI* pNavi = GetParentWindow();
1741 pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("up"), !bDisable);
1742 pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("down"), !bDisable);
1743 pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("promote"), !bDisable);
1744 pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("demote"), !bDisable);
1745 pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("reminder"), !bDisable);
1746 }
1747 if(pShell)
1748 {
1749 SvTreeListEntry* pSelEntry = nullptr;
1750 if(m_nRootType == ContentTypeId::UNKNOWN)
1751 {
1752 for( ContentTypeId nCntType : o3tl::enumrange<ContentTypeId>() )
1753 {
1754 std::unique_ptr<SwContentType>& rpContentT = bActive ?
1755 m_aActiveContentArr[nCntType] :
1756 m_aHiddenContentArr[nCntType];
1757 if(!rpContentT)
1758 rpContentT.reset(new SwContentType(pShell, nCntType, m_nOutlineLevel ));
1759
1760 OUString sEntry = rpContentT->GetName();
1761 SvTreeListEntry* pEntry;
1762 Image aImage(GetBitmapForContentTypeId(nCntType));
1763 bool bChOnDemand = 0 != rpContentT->GetMemberCount();
1764 pEntry = InsertEntry(sEntry, aImage, aImage,
1765 nullptr, bChOnDemand, TREELIST_APPEND, rpContentT.get());
1766 if(pEntry && !pEntry->HasChildren() && !pEntry->HasChildrenOnDemand())
1767 {
1768 pEntry->SetFlags(pEntry->GetFlags() | SvTLEntryFlags::SEMITRANSPARENT);
1769 pEntry->SetTextColor(COL_GRAY);
1770 }
1771 if(nCntType == m_nLastSelType)
1772 pSelEntry = pEntry;
1773 sal_Int32 nExpandOptions = (State::HIDDEN == m_eState)
1774 ? m_nHiddenBlock
1775 : m_nActiveBlock;
1776 if(nExpandOptions & (1 << static_cast<int>(nCntType)))
1777 {
1778 Expand(pEntry);
1779 if(nEntryRelPos && nCntType == m_nLastSelType)
1780 {
1781 // Now maybe select an additional child
1782 SvTreeListEntry* pChild = pEntry;
1783 SvTreeListEntry* pTemp = nullptr;
1784 sal_uLong nPos = 1;
1785 while(nullptr != (pChild = Next(pChild)))
1786 {
1787 // The old text will be slightly favored
1788 if(sEntryName == GetEntryText(pChild) ||
1789 nPos == nEntryRelPos )
1790 {
1791 pSelEntry = pChild;
1792 break;
1793 }
1794 pTemp = pChild;
1795 nPos++;
1796 }
1797 if(!pSelEntry || lcl_IsContentType(pSelEntry))
1798 pSelEntry = pTemp;
1799 }
1800
1801 }
1802 }
1803 if(pSelEntry)
1804 {
1805 MakeVisible(pSelEntry);
1806 Select(pSelEntry);
1807 }
1808 else
1809 nOldScrollPos = 0;
1810 }
1811 else
1812 {
1813 std::unique_ptr<SwContentType>& rpRootContentT = bActive ?
1814 m_aActiveContentArr[m_nRootType] :
1815 m_aHiddenContentArr[m_nRootType];
1816 if(!rpRootContentT)
1817 rpRootContentT.reset(new SwContentType(pShell, m_nRootType, m_nOutlineLevel ));
1818 Image aImage(GetBitmapForContentTypeId(m_nRootType));
1819 SvTreeListEntry* pParent = InsertEntry(
1820 rpRootContentT->GetName(), aImage, aImage,
1821 nullptr, false, TREELIST_APPEND, rpRootContentT.get());
1822
1823 if(m_nRootType != ContentTypeId::OUTLINE)
1824 {
1825 for(size_t i = 0; i < rpRootContentT->GetMemberCount(); ++i)
1826 {
1827 const SwContent* pCnt = rpRootContentT->GetMember(i);
1828 if(pCnt)
1829 {
1830 OUString sEntry = pCnt->GetName();
1831 if(sEntry.isEmpty())
1832 sEntry = m_sSpace;
1833 InsertEntry( sEntry, pParent,
1834 false, TREELIST_APPEND, const_cast<SwContent *>(pCnt));
1835 }
1836 }
1837 }
1838 else
1839 RequestingChildren(pParent);
1840 Expand(pParent);
1841 if (m_nRootType == ContentTypeId::OUTLINE && State::ACTIVE == m_eState)
1842 {
1843 // find out where the cursor is
1844 const SwOutlineNodes::size_type nActPos = pShell->GetOutlinePos(MAXLEVEL);
1845 SvTreeListEntry* pEntry = First();
1846
1847 while( nullptr != (pEntry = Next(pEntry)) )
1848 {
1849 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
1850 if (static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlinePos() == nActPos)
1851 {
1852 MakeVisible(pEntry);
1853 Select(pEntry);
1854 SetCurEntry(pEntry);
1855 }
1856 }
1857
1858 }
1859 else
1860 {
1861 // Now maybe select an additional child
1862 SvTreeListEntry* pChild = pParent;
1863 SvTreeListEntry* pTemp = nullptr;
1864 sal_uLong nPos = 1;
1865 while(nullptr != (pChild = Next(pChild)))
1866 {
1867 // The old text will be slightly favored
1868 if(sEntryName == GetEntryText(pChild) ||
1869 nPos == nEntryRelPos )
1870 {
1871 pSelEntry = pChild;
1872 break;
1873 }
1874 pTemp = pChild;
1875 nPos++;
1876 }
1877 if(!pSelEntry)
1878 pSelEntry = pTemp;
1879 if(pSelEntry)
1880 {
1881 MakeVisible(pSelEntry);
1882 Select(pSelEntry);
1883 }
1884 }
1885 }
1886 }
1887 SetUpdateMode( true );
1888 ScrollBar* pVScroll = GetVScroll();
1889 if(GetEntryCount() == nOldEntryCount &&
1890 nOldScrollPos && pVScroll && pVScroll->IsVisible()
1891 && pVScroll->GetThumbPos() != nOldScrollPos)
1892 {
1893 sal_Int32 nDelta = pVScroll->GetThumbPos() - nOldScrollPos;
1894 ScrollOutputArea( static_cast<short>(nDelta) );
1895 }
1896 }
1897
Clear()1898 void SwContentTree::Clear()
1899 {
1900 SetUpdateMode(false);
1901 SvTreeListBox::Clear();
1902 SetUpdateMode(true);
1903 }
1904
FillTransferData(TransferDataContainer & rTransfer,sal_Int8 & rDragMode)1905 bool SwContentTree::FillTransferData( TransferDataContainer& rTransfer,
1906 sal_Int8& rDragMode )
1907 {
1908 SwWrtShell* pWrtShell = GetWrtShell();
1909 OSL_ENSURE(pWrtShell, "no Shell!");
1910 SvTreeListEntry* pEntry = GetCurEntry();
1911 if(!pEntry || lcl_IsContentType(pEntry) || !pWrtShell)
1912 return false;
1913 OUString sEntry;
1914 assert(dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
1915 SwContent* pCnt = static_cast<SwContent*>(pEntry->GetUserData());
1916
1917 const ContentTypeId nActType = pCnt->GetParent()->GetType();
1918 OUString sUrl;
1919 bool bOutline = false;
1920 OUString sOutlineText;
1921 switch( nActType )
1922 {
1923 case ContentTypeId::OUTLINE:
1924 {
1925 const SwOutlineNodes::size_type nPos = static_cast<SwOutlineContent*>(pCnt)->GetOutlinePos();
1926 OSL_ENSURE(nPos < pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNodesCount(),
1927 "outlinecnt changed");
1928
1929 // make sure outline may actually be copied
1930 if( pWrtShell->IsOutlineCopyable( nPos ) )
1931 {
1932 const SwNumRule* pOutlRule = pWrtShell->GetOutlineNumRule();
1933 const SwTextNode* pTextNd =
1934 pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineNode(nPos);
1935 if (pTextNd && pOutlRule && pTextNd->IsNumbered(pWrtShell->GetLayout()))
1936 {
1937 SwNumberTree::tNumberVector aNumVector =
1938 pTextNd->GetNumberVector(pWrtShell->GetLayout());
1939 for( int nLevel = 0;
1940 nLevel <= pTextNd->GetActualListLevel();
1941 nLevel++ )
1942 {
1943 const SwNumberTree::tSwNumTreeNumber nVal = aNumVector[nLevel] + 1;
1944 sEntry += OUString::number( nVal - pOutlRule->Get(nLevel).GetStart() ) + ".";
1945 }
1946 }
1947 sEntry += pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineText(nPos, pWrtShell->GetLayout(), false);
1948 sOutlineText = pWrtShell->getIDocumentOutlineNodesAccess()->getOutlineText(nPos, pWrtShell->GetLayout());
1949 m_bIsOutlineMoveable = static_cast<SwOutlineContent*>(pCnt)->IsMoveable();
1950 bOutline = true;
1951 }
1952 }
1953 break;
1954 case ContentTypeId::POSTIT:
1955 case ContentTypeId::INDEX:
1956 case ContentTypeId::REFERENCE :
1957 // cannot be inserted, neither as URL nor as section
1958 break;
1959 case ContentTypeId::URLFIELD:
1960 sUrl = static_cast<SwURLFieldContent*>(pCnt)->GetURL();
1961 [[fallthrough]];
1962 case ContentTypeId::OLE:
1963 case ContentTypeId::GRAPHIC:
1964 if(GetParentWindow()->GetRegionDropMode() != RegionMode::NONE)
1965 break;
1966 else
1967 rDragMode &= ~( DND_ACTION_MOVE | DND_ACTION_LINK );
1968 [[fallthrough]];
1969 default:
1970 sEntry = GetEntryText(pEntry);
1971 }
1972
1973 bool bRet = false;
1974 if(!sEntry.isEmpty())
1975 {
1976 const SwDocShell* pDocShell = pWrtShell->GetView().GetDocShell();
1977 if(sUrl.isEmpty())
1978 {
1979 if(pDocShell->HasName())
1980 {
1981 SfxMedium* pMedium = pDocShell->GetMedium();
1982 sUrl = pMedium->GetURLObject().GetURLNoMark();
1983 // only if a primarily link shall be integrated.
1984 bRet = true;
1985 }
1986 else if ( nActType == ContentTypeId::REGION || nActType == ContentTypeId::BOOKMARK )
1987 {
1988 // For field and bookmarks a link is also allowed
1989 // without a filename into its own document.
1990 bRet = true;
1991 }
1992 else if (State::CONSTANT == m_eState &&
1993 ( !::GetActiveView() ||
1994 m_pActiveShell != ::GetActiveView()->GetWrtShellPtr()))
1995 {
1996 // Urls of inactive views cannot dragged without
1997 // file names, also.
1998 bRet = false;
1999 }
2000 else
2001 {
2002 bRet = GetParentWindow()->GetRegionDropMode() == RegionMode::NONE;
2003 rDragMode = DND_ACTION_MOVE;
2004 }
2005
2006 const OUString& rToken = pCnt->GetParent()->GetTypeToken();
2007 sUrl += "#" + sEntry;
2008 if(!rToken.isEmpty())
2009 {
2010 sUrl += OUStringChar(cMarkSeparator) + rToken;
2011 }
2012 }
2013 else
2014 bRet = true;
2015
2016 if( bRet )
2017 {
2018 // In Outlines of heading text must match
2019 // the real number into the description.
2020 if(bOutline)
2021 sEntry = sOutlineText;
2022
2023 {
2024 NaviContentBookmark aBmk( sUrl, sEntry,
2025 GetParentWindow()->GetRegionDropMode(),
2026 pDocShell);
2027 aBmk.Copy( rTransfer );
2028 }
2029
2030 // An INetBookmark must a be delivered to foreign DocShells
2031 if( pDocShell->HasName() )
2032 {
2033 INetBookmark aBkmk( sUrl, sEntry );
2034 rTransfer.CopyINetBookmark( aBkmk );
2035 }
2036 }
2037 }
2038 return bRet;
2039 }
2040
ToggleToRoot()2041 void SwContentTree::ToggleToRoot()
2042 {
2043 if(!m_bIsRoot)
2044 {
2045 SvTreeListEntry* pEntry = GetCurEntry();
2046 const SwContentType* pCntType;
2047 if(pEntry)
2048 {
2049 if(lcl_IsContentType(pEntry))
2050 {
2051 assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2052 pCntType = static_cast<SwContentType*>(pEntry->GetUserData());
2053 }
2054 else
2055 {
2056 assert(dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2057 pCntType = static_cast<SwContent*>(pEntry->GetUserData())->GetParent();
2058 }
2059 m_nRootType = pCntType->GetType();
2060 m_bIsRoot = true;
2061 Display(State::HIDDEN != m_eState);
2062 if (m_nRootType == ContentTypeId::OUTLINE)
2063 {
2064 SetSelectionMode(SelectionMode::Multiple);
2065 SetDragDropMode(DragDropMode::CTRL_MOVE |
2066 DragDropMode::CTRL_COPY |
2067 DragDropMode::ENABLE_TOP);
2068 }
2069 }
2070 }
2071 else
2072 {
2073 SetSelectionMode(SelectionMode::Single);
2074 m_nRootType = ContentTypeId::UNKNOWN;
2075 m_bIsRoot = false;
2076 FindActiveTypeAndRemoveUserData();
2077 Display(State::HIDDEN != m_eState);
2078 if( m_bIsKeySpace )
2079 {
2080 HideFocus();
2081 ShowFocus( m_aOldRectangle);
2082 m_bIsKeySpace = false;
2083 }
2084 }
2085 m_pConfig->SetRootType( m_nRootType );
2086 VclPtr<SwNavHelpToolBox> xBox = GetParentWindow()->m_aContentToolBox;
2087 xBox->CheckItem(xBox->GetItemId("root"), m_bIsRoot);
2088 }
2089
HasContentChanged()2090 bool SwContentTree::HasContentChanged()
2091 {
2092
2093 // - Run through the local array and the Treelistbox in parallel.
2094 // - Are the records not expanded, they are discarded only in the array
2095 // and the content type will be set as the new UserData.
2096 // - Is the root mode is active only this will be updated.
2097
2098 // Valid for the displayed content types is:
2099 // the Memberlist will be erased and the membercount will be updated
2100 // If content will be checked, the memberlists will be replenished
2101 // at the same time. Once a difference occurs it will be only replenished
2102 // no longer checked. Finally, the box is filled again.
2103
2104 bool bRepaint = false;
2105 bool bInvalidate = false;
2106
2107 if (State::HIDDEN == m_eState)
2108 {
2109 for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
2110 {
2111 if(m_aActiveContentArr[i])
2112 m_aActiveContentArr[i]->Invalidate();
2113 }
2114 }
2115 else if(m_bIsRoot)
2116 {
2117 bool bOutline = false;
2118 SvTreeListEntry* pEntry = First();
2119 if(!pEntry)
2120 bRepaint = true;
2121 else
2122 {
2123 assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2124 const ContentTypeId nType = static_cast<SwContentType*>(pEntry->GetUserData())->GetType();
2125 bOutline = m_nRootType == ContentTypeId::OUTLINE;
2126 SwContentType* pArrType = m_aActiveContentArr[nType].get();
2127 if(!pArrType)
2128 bRepaint = true;
2129 else
2130 {
2131 SvTreeListEntry* pFirstSel;
2132 if(bOutline && !HasFocus() &&
2133 nullptr != ( pFirstSel = FirstSelected()) &&
2134 lcl_IsContent(pFirstSel))
2135 {
2136 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pFirstSel->GetUserData())));
2137 const auto nSelLevel =
2138 static_cast<SwOutlineContent*>(pFirstSel->GetUserData())->GetOutlineLevel();
2139 SwWrtShell* pSh = GetWrtShell();
2140 const SwOutlineNodes::size_type nOutlinePos = pSh->GetOutlinePos(MAXLEVEL);
2141 if (nOutlinePos != SwOutlineNodes::npos &&
2142 pSh->getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos) != nSelLevel)
2143 bRepaint = true;
2144 }
2145
2146 pArrType->Init(&bInvalidate);
2147 pArrType->FillMemberList();
2148 pEntry->SetUserData(static_cast<void*>(pArrType));
2149 if(!bRepaint)
2150 {
2151 if(GetChildCount(pEntry) != pArrType->GetMemberCount())
2152 bRepaint = true;
2153 else
2154 {
2155 const size_t nChildCount = GetChildCount(pEntry);
2156 for(size_t j = 0; j < nChildCount; ++j)
2157 {
2158 pEntry = Next(pEntry);
2159 assert(pEntry);
2160 const SwContent* pCnt = pArrType->GetMember(j);
2161 pEntry->SetUserData(const_cast<SwContent *>(pCnt));
2162 OUString sEntryText = GetEntryText(pEntry);
2163 if( sEntryText != pCnt->GetName() &&
2164 !(sEntryText == m_sSpace && pCnt->GetName().isEmpty()))
2165 bRepaint = true;
2166 }
2167 }
2168 }
2169 }
2170 }
2171 if( !bRepaint && bOutline && !HasFocus() )
2172 {
2173 // find out where the cursor is
2174 const SwOutlineNodes::size_type nActPos = GetWrtShell()->GetOutlinePos(MAXLEVEL);
2175 SvTreeListEntry* pFirstEntry = First();
2176
2177 while( nullptr != (pFirstEntry = Next(pFirstEntry)) )
2178 {
2179 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pFirstEntry->GetUserData())));
2180 if (static_cast<SwOutlineContent*>(pFirstEntry->GetUserData())->GetOutlinePos() == nActPos)
2181 {
2182 if(FirstSelected() != pFirstEntry)
2183 {
2184 Select(pFirstEntry);
2185 MakeVisible(pFirstEntry);
2186 }
2187 }
2188 else if (IsSelected(pFirstEntry))
2189 {
2190 SvTreeListBox::SelectListEntry(pFirstEntry, false);
2191 bInvalidate = true;
2192 }
2193 }
2194
2195 }
2196
2197 }
2198 else
2199 {
2200 SvTreeListEntry* pEntry = First();
2201 while ( pEntry )
2202 {
2203 bool bNext = true; // at least a next must be
2204 assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2205 SwContentType* pTreeType = static_cast<SwContentType*>(pEntry->GetUserData());
2206 const size_t nTreeCount = pTreeType->GetMemberCount();
2207 const ContentTypeId nType = pTreeType->GetType();
2208 SwContentType* pArrType = m_aActiveContentArr[nType].get();
2209 if(!pArrType)
2210 bRepaint = true;
2211 else
2212 {
2213 pArrType->Init(&bInvalidate);
2214 pEntry->SetUserData(static_cast<void*>(pArrType));
2215 if(IsExpanded(pEntry))
2216 {
2217 bool bLevelOrVisibiblityChanged = false;
2218 // bLevelOrVisibiblityChanged is set if outlines have changed their level
2219 // or if the visibility of objects (frames, sections, tables) has changed
2220 // i.e. in header/footer
2221 pArrType->FillMemberList(&bLevelOrVisibiblityChanged);
2222 const size_t nChildCount = GetChildCount(pEntry);
2223 if((nType == ContentTypeId::OUTLINE) && bLevelOrVisibiblityChanged)
2224 bRepaint = true;
2225 if(bLevelOrVisibiblityChanged)
2226 bInvalidate = true;
2227
2228 if(nChildCount != pArrType->GetMemberCount())
2229 bRepaint = true;
2230 else
2231 {
2232 for(size_t j = 0; j < nChildCount; ++j)
2233 {
2234 pEntry = Next(pEntry);
2235 assert(pEntry);
2236 bNext = false;
2237 const SwContent* pCnt = pArrType->GetMember(j);
2238 pEntry->SetUserData(const_cast<SwContent *>(pCnt));
2239 OUString sEntryText = GetEntryText(pEntry);
2240 if( sEntryText != pCnt->GetName() &&
2241 !(sEntryText == m_sSpace && pCnt->GetName().isEmpty()))
2242 bRepaint = true;
2243 }
2244 }
2245
2246 }
2247 else if(pEntry->HasChildren())
2248 {
2249 // was the entry once opened, then must also the
2250 // invisible records be examined.
2251 // At least the user data must be updated.
2252 bool bLevelOrVisibiblityChanged = false;
2253 // bLevelOrVisibiblityChanged is set if outlines have changed their level
2254 // or if the visibility of objects (frames, sections, tables) has changed
2255 // i.e. in header/footer
2256 pArrType->FillMemberList(&bLevelOrVisibiblityChanged);
2257 bool bRemoveChildren = false;
2258 const size_t nChildCount = GetChildCount(pEntry);
2259 if( nChildCount != pArrType->GetMemberCount() )
2260 {
2261 bRemoveChildren = true;
2262 }
2263 else
2264 {
2265 SvTreeListEntry* pChild = FirstChild(pEntry);
2266 for(size_t j = 0; j < nChildCount; ++j)
2267 {
2268 const SwContent* pCnt = pArrType->GetMember(j);
2269 assert(pChild);
2270 pChild->SetUserData(const_cast<SwContent *>(pCnt));
2271 OUString sEntryText = GetEntryText(pChild);
2272 if( sEntryText != pCnt->GetName() &&
2273 !(sEntryText == m_sSpace && pCnt->GetName().isEmpty()))
2274 bRemoveChildren = true;
2275 pChild = Next(pChild);
2276 }
2277 }
2278 if(bRemoveChildren)
2279 {
2280 while (SvTreeListEntry *const pRemove = FirstChild(pEntry))
2281 RemoveEntry(pRemove);
2282 }
2283 if(!nChildCount)
2284 {
2285 pEntry->EnableChildrenOnDemand(false);
2286 InvalidateEntry(pEntry);
2287 }
2288
2289 }
2290 else if((nTreeCount != 0)
2291 != (pArrType->GetMemberCount()!=0))
2292 {
2293 bRepaint = true;
2294 }
2295 }
2296 // The Root-Entry has to be found now
2297 while( pEntry && (bNext || GetParent(pEntry ) ))
2298 {
2299 pEntry = Next(pEntry);
2300 bNext = false;
2301 }
2302 }
2303 }
2304 if(!bRepaint && bInvalidate)
2305 Invalidate();
2306 return bRepaint;
2307 }
2308
FindActiveTypeAndRemoveUserData()2309 void SwContentTree::FindActiveTypeAndRemoveUserData()
2310 {
2311 SvTreeListEntry* pEntry = FirstSelected();
2312 if(pEntry)
2313 {
2314 // If clear is called by TimerUpdate:
2315 // Only for root can the validity of the UserData be guaranteed.
2316 SvTreeListEntry* pParent;
2317 while(nullptr != (pParent = GetParent(pEntry)))
2318 pEntry = pParent;
2319 if(pEntry->GetUserData() && lcl_IsContentType(pEntry))
2320 {
2321 assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2322 m_nLastSelType = static_cast<SwContentType*>(pEntry->GetUserData())->GetType();
2323 }
2324 }
2325 pEntry = First();
2326 while(pEntry)
2327 {
2328 pEntry->SetUserData(nullptr);
2329 pEntry = Next(pEntry);
2330 }
2331 }
2332
SetHiddenShell(SwWrtShell * pSh)2333 void SwContentTree::SetHiddenShell(SwWrtShell* pSh)
2334 {
2335 m_pHiddenShell = pSh;
2336 m_eState = State::HIDDEN;
2337 FindActiveTypeAndRemoveUserData();
2338 for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
2339 {
2340 m_aHiddenContentArr[i].reset();
2341 }
2342 Display(false);
2343
2344 GetParentWindow()->UpdateListBox();
2345 }
2346
SetActiveShell(SwWrtShell * pSh)2347 void SwContentTree::SetActiveShell(SwWrtShell* pSh)
2348 {
2349 if(m_bIsInternalDrag)
2350 m_bDocChgdInDragging = true;
2351 bool bClear = m_pActiveShell != pSh;
2352 if (State::ACTIVE == m_eState && bClear)
2353 {
2354 if (m_pActiveShell)
2355 EndListening(*m_pActiveShell->GetView().GetDocShell());
2356 m_pActiveShell = pSh;
2357 FindActiveTypeAndRemoveUserData();
2358 Clear();
2359 }
2360 else if (State::CONSTANT == m_eState)
2361 {
2362 if (m_pActiveShell)
2363 EndListening(*m_pActiveShell->GetView().GetDocShell());
2364 m_pActiveShell = pSh;
2365 m_eState = State::ACTIVE;
2366 bClear = true;
2367 }
2368 // Only if it is the active view, the array will be deleted and
2369 // the screen filled new.
2370 if (State::ACTIVE == m_eState && bClear)
2371 {
2372 if (m_pActiveShell)
2373 StartListening(*m_pActiveShell->GetView().GetDocShell());
2374 FindActiveTypeAndRemoveUserData();
2375 for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
2376 {
2377 m_aActiveContentArr[i].reset();
2378 }
2379 Display(true);
2380 }
2381 }
2382
SetConstantShell(SwWrtShell * pSh)2383 void SwContentTree::SetConstantShell(SwWrtShell* pSh)
2384 {
2385 if (m_pActiveShell)
2386 EndListening(*m_pActiveShell->GetView().GetDocShell());
2387 m_pActiveShell = pSh;
2388 m_eState = State::CONSTANT;
2389 StartListening(*m_pActiveShell->GetView().GetDocShell());
2390 FindActiveTypeAndRemoveUserData();
2391 for(ContentTypeId i : o3tl::enumrange<ContentTypeId>())
2392 {
2393 m_aActiveContentArr[i].reset();
2394 }
2395 Display(true);
2396 }
2397
2398
Notify(SfxBroadcaster & rBC,SfxHint const & rHint)2399 void SwContentTree::Notify(SfxBroadcaster & rBC, SfxHint const& rHint)
2400 {
2401 SfxViewEventHint const*const pVEHint(dynamic_cast<SfxViewEventHint const*>(&rHint));
2402 SwXTextView* pDyingShell = nullptr;
2403 if (m_pActiveShell && pVEHint && pVEHint->GetEventName() == "OnViewClosed")
2404 pDyingShell = dynamic_cast<SwXTextView*>(pVEHint->GetController().get());
2405 if (pDyingShell && pDyingShell->GetView() == &m_pActiveShell->GetView())
2406 {
2407 SetActiveShell(nullptr); // our view is dying, clear our pointers to it
2408 }
2409 else
2410 {
2411 SfxListener::Notify(rBC, rHint);
2412 }
2413 switch (rHint.GetId())
2414 {
2415 case SfxHintId::DocChanged:
2416 if (!(m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE && HasFocus()))
2417 {
2418 m_bViewHasChanged = true;
2419 }
2420 break;
2421 case SfxHintId::ModeChanged:
2422 if (SwWrtShell* pShell = GetWrtShell())
2423 {
2424 const bool bReadOnly = pShell->GetView().GetDocShell()->IsReadOnly();
2425 if (bReadOnly != m_bIsLastReadOnly)
2426 {
2427 m_bIsLastReadOnly = bReadOnly;
2428 Select(GetCurEntry());
2429 }
2430 }
2431 break;
2432 default:
2433 break;
2434 }
2435 }
2436
2437
2438
ExecCommand(const OUString & rCmd,bool bOutlineWithChildren)2439 void SwContentTree::ExecCommand(const OUString& rCmd, bool bOutlineWithChildren)
2440 {
2441 const bool bUp = rCmd == "up";
2442 const bool bUpDown = bUp || rCmd == "down";
2443 const bool bLeft = rCmd == "promote";
2444 const bool bLeftRight = bLeft || rCmd == "demote";
2445 if (!bUpDown && !bLeftRight)
2446 return;
2447 if (GetWrtShell()->GetView().GetDocShell()->IsReadOnly() ||
2448 (State::ACTIVE != m_eState &&
2449 (State::CONSTANT != m_eState || m_pActiveShell != GetParentWindow()->GetCreateView()->GetWrtShellPtr())))
2450 {
2451 return;
2452 }
2453
2454 SwWrtShell *const pShell = GetWrtShell();
2455 sal_Int8 nActOutlineLevel = m_nOutlineLevel;
2456 SwOutlineNodes::size_type nActPos = pShell->GetOutlinePos(nActOutlineLevel);
2457
2458 std::vector<SwTextNode*> selectedOutlineNodes;
2459 std::vector<SvTreeListEntry*> selected;
2460 for (SvTreeListEntry * pEntry = FirstSelected(); pEntry; pEntry = NextSelected(pEntry))
2461 {
2462 // it's possible to select the root node too which is a really bad idea
2463 bool bSkip = lcl_IsContentType(pEntry);
2464 // filter out children of selected parents so they don't get promoted
2465 // or moved twice (except if there is Ctrl modifier, since in that
2466 // case children are re-parented)
2467 if ((bLeftRight || bOutlineWithChildren) && !selected.empty())
2468 {
2469 for (auto pParent = GetParent(pEntry); pParent; pParent = GetParent(pParent))
2470 {
2471 if (selected.back() == pParent)
2472 {
2473 bSkip = true;
2474 break;
2475 }
2476 }
2477 }
2478 if (!bSkip)
2479 {
2480 selected.push_back(pEntry);
2481 const SwNodes& rNodes = pShell->GetNodes();
2482 const sal_uLong nPos = GetAbsPos(pEntry) - 1;
2483 if (nPos < rNodes.GetOutLineNds().size())
2484 {
2485 SwNode* pNode = rNodes.GetOutLineNds()[ nPos ];
2486 if (pNode)
2487 {
2488 selectedOutlineNodes.push_back(pNode->GetTextNode());
2489 }
2490 }
2491 }
2492 }
2493 if (bUpDown && !bUp)
2494 { // to move down, start at the end!
2495 std::reverse(selected.begin(), selected.end());
2496 }
2497
2498 SwOutlineNodes::difference_type nDirLast = bUp ? -1 : 1;
2499 bool bStartedAction = false;
2500 for (auto const pCurrentEntry : selected)
2501 {
2502 assert(pCurrentEntry && lcl_IsContent(pCurrentEntry));
2503 if (lcl_IsContent(pCurrentEntry))
2504 {
2505 assert(dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pCurrentEntry->GetUserData())));
2506 if ((m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE) ||
2507 static_cast<SwContent*>(pCurrentEntry->GetUserData())->GetParent()->GetType()
2508 == ContentTypeId::OUTLINE)
2509 {
2510 nActPos = static_cast<SwOutlineContent*>(pCurrentEntry->GetUserData())->GetOutlinePos();
2511 }
2512 }
2513 if (nActPos == SwOutlineNodes::npos || (bUpDown && !pShell->IsOutlineMovable(nActPos)))
2514 {
2515 continue;
2516 }
2517
2518 if (!bStartedAction)
2519 {
2520 pShell->StartAllAction();
2521 pShell->StartUndo(bLeftRight ? SwUndoId::OUTLINE_LR : SwUndoId::OUTLINE_UD);
2522 bStartedAction = true;
2523 }
2524 pShell->GotoOutline( nActPos); // If text selection != box selection
2525 pShell->Push();
2526 pShell->MakeOutlineSel(nActPos, nActPos, bOutlineWithChildren);
2527 if (bUpDown)
2528 {
2529 sal_uLong const nEntryAbsPos(GetModel()->GetAbsPos(pCurrentEntry));
2530 SwOutlineNodes::difference_type nDir = bUp ? -1 : 1;
2531 if (!bOutlineWithChildren && ((nDir == -1 && nActPos > 0) ||
2532 (nDir == 1 && nEntryAbsPos < GetEntryCount() - 2)))
2533 {
2534 pShell->MoveOutlinePara( nDir );
2535 // Set cursor back to the current position
2536 pShell->GotoOutline( nActPos + nDir);
2537 }
2538 else if (bOutlineWithChildren)
2539 {
2540 SwOutlineNodes::size_type nActEndPos = nActPos;
2541 SvTreeListEntry* pEntry = pCurrentEntry;
2542 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pCurrentEntry->GetUserData())));
2543 const auto nActLevel = static_cast<SwOutlineContent*>(
2544 pCurrentEntry->GetUserData())->GetOutlineLevel();
2545 pEntry = Next(pEntry);
2546 while (pEntry && lcl_IsContent(pEntry))
2547 {
2548 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2549 if (nActLevel >= static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlineLevel())
2550 break;
2551 nActEndPos = static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlinePos();
2552 pEntry = Next(pEntry);
2553 }
2554 if (nDir == 1) // move down
2555 {
2556 if (IsSelected(pCurrentEntry->NextSibling()))
2557 nDir = nDirLast;
2558 else
2559 {
2560 // If the last entry is to be moved we're done
2561 if (pEntry && lcl_IsContent(pEntry))
2562 {
2563 // pEntry now points to the entry following the last
2564 // selected entry.
2565 SwOutlineNodes::size_type nDest = static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlinePos();
2566 // here needs to found the next entry after next.
2567 // The selection must be inserted in front of that.
2568 while (pEntry)
2569 {
2570 pEntry = Next(pEntry);
2571 assert(pEntry == nullptr || !lcl_IsContent(pEntry) || dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2572 // nDest++ may only executed if pEntry != 0
2573 if (pEntry)
2574 {
2575 if (!lcl_IsContent(pEntry))
2576 break;
2577 else if (nActLevel >= static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlineLevel())
2578 {
2579 // nDest needs adjusted if there are selected entries (including ancestral lineage)
2580 // immediately before the current moved entry.
2581 SvTreeListEntry* pTmp = Prev(pEntry);
2582 while (pTmp && lcl_IsContent(pTmp) &&
2583 nActLevel < static_cast<SwOutlineContent*>(pTmp->GetUserData())->GetOutlineLevel())
2584 {
2585 while (pTmp && lcl_IsContent(pTmp) && !IsSelected(pTmp) &&
2586 nActLevel < static_cast<SwOutlineContent*>(pTmp->GetUserData())->GetOutlineLevel())
2587 {
2588 pTmp = GetParent(pTmp);
2589 }
2590 if (!IsSelected(pTmp))
2591 break;
2592 pTmp = Prev(pTmp);
2593 nDest = static_cast<SwOutlineContent*>(pTmp->GetUserData())->GetOutlinePos();
2594 }
2595 if (!IsSelected(pEntry->PrevSibling()))
2596 break;
2597 }
2598 else
2599 {
2600 nDest = static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlinePos();
2601 }
2602 }
2603 }
2604 nDirLast = nDir = nDest - nActEndPos;
2605 // If no entry was found that allows insertion before
2606 // it, we just move it to the end.
2607 }
2608 else
2609 nDirLast = nDir = 0;
2610 }
2611 }
2612 else // move up
2613 {
2614 if (IsSelected(pCurrentEntry->PrevSibling()))
2615 nDir = nDirLast;
2616 else
2617 {
2618 SwOutlineNodes::size_type nDest = nActPos;
2619 pEntry = pCurrentEntry;
2620 while (pEntry && nDest)
2621 {
2622 pEntry = Prev(pEntry);
2623 assert(pEntry == nullptr || !lcl_IsContent(pEntry) || dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2624 if (pEntry && lcl_IsContent(pEntry))
2625 {
2626 nDest = static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlinePos();
2627 }
2628 else
2629 {
2630 nDest = 0; // presumably?
2631 }
2632 if (pEntry)
2633 {
2634 if (!lcl_IsContent(pEntry))
2635 break;
2636 else if (nActLevel >= static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlineLevel())
2637 {
2638 // nDest needs adjusted if there are selected entries immediately
2639 // after the level change.
2640 SvTreeListEntry* pTmp = Next(pEntry);
2641 while (pTmp && lcl_IsContent(pTmp) &&
2642 nActLevel < static_cast<SwOutlineContent*>(pTmp->GetUserData())->GetOutlineLevel() &&
2643 IsSelected(pTmp))
2644 {
2645 nDest = static_cast<SwOutlineContent*>(pTmp->GetUserData())->GetOutlinePos();
2646 const auto nLevel = static_cast<SwOutlineContent*>(pTmp->GetUserData())->GetOutlineLevel();
2647 // account for selected entries' descendent lineage
2648 pTmp = Next(pTmp);
2649 while (pTmp && lcl_IsContent(pTmp) &&
2650 nLevel < static_cast<SwOutlineContent*>(pTmp->GetUserData())->GetOutlineLevel())
2651 {
2652 nDest = static_cast<SwOutlineContent*>(pTmp->GetUserData())->GetOutlinePos();
2653 pTmp = Next(pTmp);
2654 }
2655 }
2656 break;
2657 }
2658 }
2659 }
2660 nDirLast = nDir = nDest - nActPos;
2661 }
2662 }
2663 if (nDir)
2664 {
2665 pShell->MoveOutlinePara( nDir );
2666 // Set cursor back to the current position
2667 pShell->GotoOutline(nActPos + nDir);
2668 }
2669 }
2670 }
2671 else
2672 {
2673 if (!pShell->IsProtectedOutlinePara())
2674 pShell->OutlineUpDown(bLeft ? -1 : 1);
2675 }
2676
2677 pShell->ClearMark();
2678 pShell->Pop(SwCursorShell::PopMode::DeleteCurrent); // Cursor is now back at the current heading.
2679 }
2680
2681 if (bStartedAction)
2682 {
2683 pShell->EndUndo();
2684 pShell->EndAllAction();
2685 if (m_aActiveContentArr[ContentTypeId::OUTLINE])
2686 m_aActiveContentArr[ContentTypeId::OUTLINE]->Invalidate();
2687 Display(true);
2688 if (!m_bIsRoot)
2689 {
2690 const SwOutlineNodes::size_type nCurrPos = pShell->GetOutlinePos(MAXLEVEL);
2691 SvTreeListEntry* pFirst = First();
2692
2693 while (nullptr != (pFirst = Next(pFirst)) && lcl_IsContent(pFirst))
2694 {
2695 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pFirst->GetUserData())));
2696 if (static_cast<SwOutlineContent*>(pFirst->GetUserData())->GetOutlinePos() == nCurrPos)
2697 {
2698 Select(pFirst);
2699 MakeVisible(pFirst);
2700 }
2701 }
2702 }
2703 else
2704 {
2705 // Reselect entries
2706 const SwOutlineNodes& rOutLineNds = pShell->GetNodes().GetOutLineNds();
2707 for (SwTextNode* pNode : selectedOutlineNodes)
2708 {
2709 SwOutlineNodes::const_iterator aFndIt = rOutLineNds.find(pNode);
2710 if(aFndIt == rOutLineNds.end())
2711 continue;
2712 const size_t nFndPos = aFndIt - rOutLineNds.begin();
2713 SvTreeListEntry* pEntry = GetEntryAtAbsPos(nFndPos + 1);
2714 if (pEntry)
2715 {
2716 SvTreeListBox::SelectListEntry(pEntry, true);
2717 if (!IsExpanded(pEntry->GetParent()))
2718 Expand(pEntry->GetParent());
2719 }
2720 }
2721 SvTreeListBox::Invalidate();
2722 }
2723 }
2724 }
2725
ShowTree()2726 void SwContentTree::ShowTree()
2727 {
2728 SvTreeListBox::Show();
2729 }
2730
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle & rRect)2731 void SwContentTree::Paint( vcl::RenderContext& rRenderContext,
2732 const tools::Rectangle& rRect )
2733 {
2734 // Start the update timer on the first paint; avoids
2735 // flicker on the first reveal.
2736 m_aUpdTimer.Start();
2737 SvTreeListBox::Paint( rRenderContext, rRect );
2738 }
2739
HideTree()2740 void SwContentTree::HideTree()
2741 {
2742 m_aUpdTimer.Stop();
2743 SvTreeListBox::Hide();
2744 }
2745
2746 /** No idle with focus or while dragging */
IMPL_LINK_NOARG(SwContentTree,TimerUpdate,Timer *,void)2747 IMPL_LINK_NOARG(SwContentTree, TimerUpdate, Timer *, void)
2748 {
2749 if (IsDisposed())
2750 return;
2751
2752 // No update while focus is not in document.
2753 // No update while drag and drop.
2754 // Query view because the Navigator is cleared too late.
2755 SwView* pView = GetParentWindow()->GetCreateView();
2756
2757 if(pView && pView->GetWrtShellPtr() &&
2758 ((pView->GetWrtShellPtr()->GetWin() == GetFocusedWindow()) || m_bViewHasChanged) &&
2759 !bIsInDrag && !m_bIsInternalDrag && !pView->GetWrtShellPtr()->ActionPend())
2760 {
2761 m_bViewHasChanged = false;
2762 m_bIsIdleClear = false;
2763 SwWrtShell* pActShell = pView->GetWrtShellPtr();
2764 if (State::CONSTANT == m_eState && !lcl_FindShell(m_pActiveShell))
2765 {
2766 SetActiveShell(pActShell);
2767 GetParentWindow()->UpdateListBox();
2768 }
2769
2770 if (State::ACTIVE == m_eState && pActShell != GetWrtShell())
2771 {
2772 SetActiveShell(pActShell);
2773 }
2774 else if ((State::ACTIVE == m_eState || (State::CONSTANT == m_eState && pActShell == GetWrtShell())) &&
2775 HasContentChanged())
2776 {
2777 FindActiveTypeAndRemoveUserData();
2778 Display(true);
2779 }
2780 }
2781 else if (!pView && State::ACTIVE == m_eState && !m_bIsIdleClear)
2782 {
2783 if(m_pActiveShell)
2784 {
2785 SetActiveShell(nullptr);
2786 }
2787 Clear();
2788 m_bIsIdleClear = true;
2789 }
2790 }
2791
NotifyStartDrag(TransferDataContainer & rContainer,SvTreeListEntry * pEntry)2792 DragDropMode SwContentTree::NotifyStartDrag(
2793 TransferDataContainer& rContainer,
2794 SvTreeListEntry* pEntry )
2795 {
2796 DragDropMode eMode = DragDropMode(0);
2797 if (State::ACTIVE == m_eState && m_nRootType == ContentTypeId::OUTLINE &&
2798 GetModel()->GetAbsPos( pEntry ) > 0
2799 && !GetWrtShell()->GetView().GetDocShell()->IsReadOnly())
2800 {
2801 eMode = GetDragDropMode();
2802 if (m_bIsRoot)
2803 {
2804 // Restore selection for multiple selected outlines.
2805 for (const auto pSelected : m_aDndOutlinesSelected)
2806 SelectListEntry(pSelected, true);
2807 }
2808 }
2809 else if (State::ACTIVE != m_eState && GetWrtShell()->GetView().GetDocShell()->HasName())
2810 eMode = DragDropMode::APP_COPY;
2811
2812 sal_Int8 nDragMode;
2813 FillTransferData( rContainer, nDragMode );
2814 m_bDocChgdInDragging = false;
2815 m_bIsInternalDrag = true;
2816 return eMode;
2817 }
2818 // After the drag the current paragraph will be moved w i t h the children.
2819
NotifyMoving(SvTreeListEntry * pTarget,SvTreeListEntry * pEntry,SvTreeListEntry * &,sal_uLong &)2820 TriState SwContentTree::NotifyMoving( SvTreeListEntry* pTarget,
2821 SvTreeListEntry* pEntry, SvTreeListEntry*& , sal_uLong& )
2822 {
2823 static SwOutlineNodes::size_type nStaticSourcePos = SwOutlineNodes::npos;
2824 static SwOutlineNodes::size_type nStaticTargetPosOrOffset = SwOutlineNodes::npos;
2825 if(!m_bDocChgdInDragging)
2826 {
2827 SwOutlineNodes::size_type nTargetPos = 0;
2828 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2829 SwOutlineNodes::size_type nSourcePos = static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlinePos();
2830 if(!lcl_IsContent(pTarget))
2831 nTargetPos = SwOutlineNodes::npos;
2832 else
2833 {
2834 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pTarget->GetUserData())));
2835 nTargetPos = static_cast<SwOutlineContent*>(pTarget->GetUserData())->GetOutlinePos();
2836 }
2837 if( MAXLEVEL > m_nOutlineLevel && // Not all layers are displayed.
2838 nTargetPos != SwOutlineNodes::npos)
2839 {
2840 SvTreeListEntry* pNext = Next(pTarget);
2841 if(pNext)
2842 {
2843 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pNext->GetUserData())));
2844 nTargetPos = static_cast<SwOutlineContent*>(pNext->GetUserData())->GetOutlinePos() - 1;
2845 }
2846 else
2847 nTargetPos = GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineNodesCount() - 1;
2848 }
2849
2850 OSL_ENSURE( pEntry &&
2851 lcl_IsContent(pEntry),"Source == 0 or Source has no Content" );
2852
2853 if (nStaticTargetPosOrOffset != SwOutlineNodes::npos)
2854 {
2855 if (nTargetPos == SwOutlineNodes::npos || nSourcePos > nTargetPos)
2856 {
2857 // Move up
2858 nTargetPos = nSourcePos - nStaticTargetPosOrOffset;
2859 }
2860 else if (nSourcePos < nTargetPos)
2861 {
2862 // Move down
2863 nSourcePos = nStaticSourcePos;
2864 nTargetPos = nStaticTargetPosOrOffset;
2865 }
2866 }
2867 // Done on the first selection move
2868 if (nTargetPos == SwOutlineNodes::npos || (nStaticTargetPosOrOffset == SwOutlineNodes::npos && nSourcePos > nTargetPos)) // only do once
2869 {
2870 // Up moves
2871 // The first up move sets the up move amount for the remaining selected outlines to be moved
2872 if (nTargetPos != SwOutlineNodes::npos)
2873 nStaticTargetPosOrOffset = nSourcePos - nTargetPos;
2874 else
2875 nStaticTargetPosOrOffset = nSourcePos + 1;
2876 }
2877 else if (nStaticTargetPosOrOffset == SwOutlineNodes::npos && nSourcePos < nTargetPos)
2878 {
2879 // Down moves
2880 // The first down move sets the source and target positions for the remaining selected outlines to be moved
2881 nStaticSourcePos = nSourcePos;
2882 nStaticTargetPosOrOffset = nTargetPos;
2883 }
2884 // Done on the last selection move
2885 if (!IsSelected(pEntry->NextSibling()))
2886 nStaticTargetPosOrOffset = SwOutlineNodes::npos;
2887
2888 GetParentWindow()->MoveOutline( nSourcePos,
2889 nTargetPos,
2890 true);
2891 }
2892 //TreeListBox will be reloaded from the document
2893 return TRISTATE_FALSE;
2894 }
2895
2896 // After the drag the current paragraph will be moved w i t h o u t the children.
2897
NotifyCopying(SvTreeListEntry * pTarget,SvTreeListEntry * pEntry,SvTreeListEntry * &,sal_uLong &)2898 TriState SwContentTree::NotifyCopying( SvTreeListEntry* pTarget,
2899 SvTreeListEntry* pEntry, SvTreeListEntry*& , sal_uLong& )
2900 {
2901 if(!m_bDocChgdInDragging)
2902 {
2903 SwOutlineNodes::size_type nTargetPos = 0;
2904 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
2905 SwOutlineNodes::size_type nSourcePos = static_cast<SwOutlineContent*>(pEntry->GetUserData())->GetOutlinePos();
2906 if(!lcl_IsContent(pTarget))
2907 nTargetPos = SwOutlineNodes::npos;
2908 else
2909 {
2910 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pTarget->GetUserData())));
2911 nTargetPos = static_cast<SwOutlineContent*>(pTarget->GetUserData())->GetOutlinePos();
2912 }
2913
2914 if( MAXLEVEL > m_nOutlineLevel && // Not all layers are displayed.
2915 nTargetPos != SwOutlineNodes::npos)
2916 {
2917 SvTreeListEntry* pNext = Next(pTarget);
2918 if(pNext)
2919 {
2920 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pNext->GetUserData())));
2921 nTargetPos = static_cast<SwOutlineContent*>(pNext->GetUserData())->GetOutlinePos() - 1;
2922 }
2923 else
2924 nTargetPos = GetWrtShell()->getIDocumentOutlineNodesAccess()->getOutlineNodesCount() - 1;
2925 }
2926
2927 OSL_ENSURE( pEntry &&
2928 lcl_IsContent(pEntry),"Source == 0 or Source has no Content" );
2929 GetParentWindow()->MoveOutline( nSourcePos, nTargetPos, false);
2930
2931 //TreeListBox will be reloaded from the document
2932 m_aActiveContentArr[ContentTypeId::OUTLINE]->Invalidate();
2933 Display(true);
2934 }
2935 return TRISTATE_FALSE;
2936 }
2937
2938 // No drop before the first entry - it's a SwContentType
2939
NotifyAcceptDrop(SvTreeListEntry * pEntry)2940 bool SwContentTree::NotifyAcceptDrop( SvTreeListEntry* pEntry)
2941 {
2942 return pEntry != nullptr;
2943 }
2944
2945 // If a Ctrl + DoubleClick are executed in an open area,
2946 // then the base function of the control is to be called.
2947
MouseButtonDown(const MouseEvent & rMEvt)2948 void SwContentTree::MouseButtonDown( const MouseEvent& rMEvt )
2949 {
2950 Point aPos( rMEvt.GetPosPixel());
2951 SvTreeListEntry* pEntry = GetEntry( aPos, true );
2952 if( !pEntry && rMEvt.IsLeft() && rMEvt.IsMod1() && (rMEvt.GetClicks() % 2) == 0)
2953 Control::MouseButtonDown( rMEvt );
2954 else
2955 {
2956 if( pEntry && (rMEvt.GetClicks() % 2) == 0)
2957 {
2958 SwContent* pCnt = static_cast<SwContent*>(pEntry->GetUserData());
2959 const ContentTypeId nActType = pCnt->GetParent()->GetType();
2960 SetSublistDontOpenWithDoubleClick( nActType == ContentTypeId::OUTLINE );
2961 }
2962 SvTreeListBox::MouseButtonDown( rMEvt );
2963 }
2964 }
2965
2966 // Update immediately
2967
GetFocus()2968 void SwContentTree::GetFocus()
2969 {
2970 SwView* pActView = GetParentWindow()->GetCreateView();
2971 if(pActView)
2972 {
2973 SwWrtShell* pActShell = pActView->GetWrtShellPtr();
2974 if (State::CONSTANT == m_eState && !lcl_FindShell(m_pActiveShell))
2975 {
2976 SetActiveShell(pActShell);
2977 }
2978
2979 if (State::ACTIVE == m_eState && pActShell != GetWrtShell())
2980 SetActiveShell(pActShell);
2981 else if ((State::ACTIVE == m_eState || (State::CONSTANT == m_eState && pActShell == GetWrtShell())) &&
2982 HasContentChanged())
2983 {
2984 Display(true);
2985 }
2986 }
2987 else if (State::ACTIVE == m_eState)
2988 Clear();
2989 SvTreeListBox::GetFocus();
2990 }
2991
KeyInput(const KeyEvent & rEvent)2992 void SwContentTree::KeyInput(const KeyEvent& rEvent)
2993 {
2994 const vcl::KeyCode aCode = rEvent.GetKeyCode();
2995 if(aCode.GetCode() == KEY_RETURN)
2996 {
2997 SvTreeListEntry* pEntry = FirstSelected();
2998 if ( pEntry )
2999 {
3000 switch(aCode.GetModifier())
3001 {
3002 case KEY_MOD2:
3003 // Switch boxes
3004 GetParentWindow()->ToggleTree();
3005 break;
3006 case KEY_MOD1:
3007 // Switch RootMode
3008 ToggleToRoot();
3009 break;
3010 case 0:
3011 if(lcl_IsContentType(pEntry))
3012 {
3013 IsExpanded(pEntry) ? Collapse(pEntry) : Expand(pEntry);
3014 }
3015 else
3016 ContentDoubleClickHdl(nullptr);
3017 break;
3018 }
3019 }
3020 }
3021 else if(aCode.GetCode() == KEY_DELETE && 0 == aCode.GetModifier())
3022 {
3023 SvTreeListEntry* pEntry = FirstSelected();
3024 assert(!pEntry || dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData())));
3025 if(pEntry &&
3026 lcl_IsContent(pEntry) &&
3027 static_cast<SwContent*>(pEntry->GetUserData())->GetParent()->IsDeletable() &&
3028 !m_pActiveShell->GetView().GetDocShell()->IsReadOnly())
3029 {
3030 EditEntry(pEntry, EditEntryMode::DELETE);
3031 m_bViewHasChanged = true;
3032 GetParentWindow()->UpdateListBox();
3033 TimerUpdate(&m_aUpdTimer);
3034 GrabFocus();
3035 }
3036 }
3037 //Make KEY_SPACE has same function as DoubleClick ,
3038 //and realize multi-selection .
3039 else if(aCode.GetCode() == KEY_SPACE && 0 == aCode.GetModifier())
3040 {
3041 SvTreeListEntry* pEntry = GetCurEntry();
3042 if(pEntry)
3043 {
3044 if( GetChildCount( pEntry ) == 0 )
3045 m_bIsKeySpace = true;
3046 Point tempPoint = GetEntryPosition( pEntry );//Change from "GetEntryPos" to "GetEntryPosition" for acc migration
3047 m_aOldRectangle = GetFocusRect(pEntry, tempPoint.Y());
3048
3049 if (State::HIDDEN != m_eState)
3050 {
3051 if (State::CONSTANT == m_eState)
3052 {
3053 m_pActiveShell->GetView().GetViewFrame()->GetWindow().ToTop();
3054 }
3055
3056 SwContent* pCnt = dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pEntry->GetUserData()));
3057
3058 if (pCnt && pCnt->GetParent()->GetType() == ContentTypeId::DRAWOBJECT)
3059 {
3060 SdrView* pDrawView = m_pActiveShell->GetDrawView();
3061 if (pDrawView)
3062 {
3063 pDrawView->SdrEndTextEdit();
3064
3065 SwDrawModel* pDrawModel = m_pActiveShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
3066 SdrPage* pPage = pDrawModel->GetPage(0);
3067 const size_t nCount = pPage->GetObjCount();
3068 bool hasObjectMarked = false;
3069
3070 if (SdrObject* pObject = GetDrawingObjectsByContent(pCnt))
3071 {
3072 SdrPageView* pPV = pDrawView->GetSdrPageView/*GetPageViewPvNum*/(/*0*/);
3073 if( pPV )
3074 {
3075 bool bUnMark = pDrawView->IsObjMarked(pObject);
3076 pDrawView->MarkObj( pObject, pPV, bUnMark);
3077
3078 }
3079 }
3080 for( size_t i=0; i<nCount; ++i )
3081 {
3082 SdrObject* pTemp = pPage->GetObj(i);
3083 bool bMark = pDrawView->IsObjMarked(pTemp);
3084 switch( pTemp->GetObjIdentifier() )
3085 {
3086 case OBJ_GRUP:
3087 case OBJ_TEXT:
3088 case OBJ_LINE:
3089 case OBJ_RECT:
3090 case OBJ_CIRC:
3091 case OBJ_SECT:
3092 case OBJ_CARC:
3093 case OBJ_CCUT:
3094 case OBJ_POLY:
3095 case OBJ_PLIN:
3096 case OBJ_PATHLINE:
3097 case OBJ_PATHFILL:
3098 case OBJ_FREELINE:
3099 case OBJ_FREEFILL:
3100 case OBJ_PATHPOLY:
3101 case OBJ_PATHPLIN:
3102 case OBJ_CAPTION:
3103 case OBJ_CUSTOMSHAPE:
3104 if( bMark )
3105 hasObjectMarked = true;
3106 break;
3107 default:
3108 if ( bMark )
3109 {
3110 SdrPageView* pPV = pDrawView->GetSdrPageView/*GetPageViewPvNum*/(/*0*/);
3111 if (pPV)
3112 {
3113 pDrawView->MarkObj(pTemp, pPV, true);
3114 }
3115 }
3116 }
3117 //mod end
3118 }
3119 if ( !hasObjectMarked )
3120 {
3121 SwEditWin& rEditWindow = m_pActiveShell->GetView().GetEditWin();
3122 vcl::KeyCode tempKeycode( KEY_ESCAPE );
3123 KeyEvent rKEvt( 0 , tempKeycode );
3124 static_cast<vcl::Window*>(&rEditWindow)->KeyInput( rKEvt );
3125 }
3126 }
3127 }
3128
3129 m_bViewHasChanged = true;
3130 }
3131 }
3132
3133 }
3134 else if (m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE && aCode.GetCode() == KEY_LEFT)
3135 {
3136 SelectAll(false);
3137 SvTreeListBox::KeyInput(rEvent);
3138 }
3139 else
3140 SvTreeListBox::KeyInput(rEvent);
3141
3142 }
3143
RequestHelp(const HelpEvent & rHEvt)3144 void SwContentTree::RequestHelp( const HelpEvent& rHEvt )
3145 {
3146 bool bCallBase = true;
3147 if( rHEvt.GetMode() & HelpEventMode::QUICK )
3148 {
3149 Point aPos( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ));
3150 SvTreeListEntry* pEntry = GetEntry( aPos );
3151 if( pEntry )
3152 {
3153 ContentTypeId nType;
3154 bool bBalloon = false;
3155 bool bContent = false;
3156 void* pUserData = pEntry->GetUserData();
3157 if(lcl_IsContentType(pEntry))
3158 {
3159 assert(dynamic_cast<SwContentType*>(static_cast<SwTypeNumber*>(pUserData)));
3160 nType = static_cast<SwContentType*>(pUserData)->GetType();
3161 }
3162 else
3163 {
3164 assert(dynamic_cast<SwContent*>(static_cast<SwTypeNumber*>(pUserData)));
3165 nType = static_cast<SwContent*>(pUserData)->GetParent()->GetType();
3166 bContent = true;
3167 }
3168 OUString sEntry;
3169 bool bRet = false;
3170 if(bContent)
3171 {
3172 switch( nType )
3173 {
3174 case ContentTypeId::URLFIELD:
3175 assert(dynamic_cast<SwURLFieldContent*>(static_cast<SwTypeNumber*>(pUserData)));
3176 sEntry = static_cast<SwURLFieldContent*>(pUserData)->GetURL();
3177 bRet = true;
3178 break;
3179
3180 case ContentTypeId::POSTIT:
3181 assert(dynamic_cast<SwPostItContent*>(static_cast<SwTypeNumber*>(pUserData)));
3182 sEntry = static_cast<SwPostItContent*>(pUserData)->GetName();
3183 bRet = true;
3184 if(Help::IsBalloonHelpEnabled())
3185 bBalloon = true;
3186 break;
3187 case ContentTypeId::OUTLINE:
3188 assert(dynamic_cast<SwOutlineContent*>(static_cast<SwTypeNumber*>(pUserData)));
3189 sEntry = static_cast<SwOutlineContent*>(pUserData)->GetName();
3190 bRet = true;
3191 break;
3192 case ContentTypeId::GRAPHIC:
3193 assert(dynamic_cast<SwGraphicContent*>(static_cast<SwTypeNumber*>(pUserData)));
3194 sEntry = static_cast<SwGraphicContent*>(pUserData)->GetLink();
3195 bRet = true;
3196 break;
3197 default: break;
3198 }
3199 if(static_cast<SwContent*>(pUserData)->IsInvisible())
3200 {
3201 if(!sEntry.isEmpty())
3202 sEntry += ", ";
3203 sEntry += m_sInvisible;
3204 bRet = true;
3205 }
3206 }
3207 else
3208 {
3209 const size_t nMemberCount = static_cast<SwContentType*>(pUserData)->GetMemberCount();
3210 sEntry = OUString::number(nMemberCount) + " " +
3211 (nMemberCount == 1
3212 ? static_cast<SwContentType*>(pUserData)->GetSingleName()
3213 : static_cast<SwContentType*>(pUserData)->GetName());
3214 bRet = true;
3215 }
3216 if(bRet)
3217 {
3218 SvLBoxTab* pTab;
3219 SvLBoxItem* pItem = GetItem( pEntry, aPos.X(), &pTab );
3220 if (pItem && SvLBoxItemType::String == pItem->GetType())
3221 {
3222 aPos = GetEntryPosition( pEntry );
3223
3224 aPos.setX( GetTabPos( pEntry, pTab ) );
3225 Size aSize(pItem->GetWidth(this, pEntry), pItem->GetHeight(this, pEntry));
3226
3227 if((aPos.X() + aSize.Width()) > GetSizePixel().Width())
3228 aSize.setWidth( GetSizePixel().Width() - aPos.X() );
3229
3230 aPos = OutputToScreenPixel(aPos);
3231 tools::Rectangle aItemRect( aPos, aSize );
3232 if(bBalloon)
3233 {
3234 aPos.AdjustX(aSize.Width() );
3235 Help::ShowBalloon( this, aPos, aItemRect, sEntry );
3236 }
3237 else
3238 Help::ShowQuickHelp( this, aItemRect, sEntry,
3239 QuickHelpFlags::Left|QuickHelpFlags::VCenter );
3240 bCallBase = false;
3241 }
3242 }
3243 else
3244 {
3245 Help::ShowQuickHelp( this, tools::Rectangle(), OUString() );
3246 bCallBase = false;
3247 }
3248 }
3249 }
3250 if( bCallBase )
3251 Window::RequestHelp( rHEvt );
3252 }
3253
ExecuteContextMenuAction(sal_uInt16 nSelectedPopupEntry)3254 void SwContentTree::ExecuteContextMenuAction( sal_uInt16 nSelectedPopupEntry )
3255 {
3256 SvTreeListEntry* pFirst = FirstSelected();
3257 switch( nSelectedPopupEntry )
3258 {
3259 //Outlinelevel
3260 case 101:
3261 case 102:
3262 case 103:
3263 case 104:
3264 case 105:
3265 case 106:
3266 case 107:
3267 case 108:
3268 case 109:
3269 case 110:
3270 nSelectedPopupEntry -= 100;
3271 if(m_nOutlineLevel != nSelectedPopupEntry )
3272 SetOutlineLevel(static_cast<sal_Int8>(nSelectedPopupEntry));
3273 break;
3274 case 201:
3275 case 202:
3276 case 203:
3277 GetParentWindow()->SetRegionDropMode(static_cast<RegionMode>(nSelectedPopupEntry - 201));
3278 break;
3279 case 401:
3280 case 402:
3281 EditEntry(pFirst, nSelectedPopupEntry == 401 ? EditEntryMode::RMV_IDX : EditEntryMode::UPD_IDX);
3282 break;
3283 // Edit entry
3284 case 403:
3285 EditEntry(pFirst, EditEntryMode::EDIT);
3286 break;
3287 case 404:
3288 EditEntry(pFirst, EditEntryMode::UNPROTECT_TABLE);
3289 break;
3290 case 405 :
3291 {
3292 const SwTOXBase* pBase = static_cast<SwTOXBaseContent*>(pFirst->GetUserData())
3293 ->GetTOXBase();
3294 m_pActiveShell->SetTOXBaseReadonly(*pBase, !SwEditShell::IsTOXBaseReadonly(*pBase));
3295 }
3296 break;
3297 case 4:
3298 break;
3299 case 501:
3300 EditEntry(pFirst, EditEntryMode::DELETE);
3301 break;
3302 case 502 :
3303 EditEntry(pFirst, EditEntryMode::RENAME);
3304 break;
3305 case 600:
3306 m_pActiveShell->GetView().GetPostItMgr()->Show();
3307 break;
3308 case 601:
3309 m_pActiveShell->GetView().GetPostItMgr()->Hide();
3310 break;
3311 case 602:
3312 {
3313 m_pActiveShell->GetView().GetPostItMgr()->SetActiveSidebarWin(nullptr);
3314 m_pActiveShell->GetView().GetPostItMgr()->Delete();
3315 break;
3316 }
3317 case 700:
3318 {
3319 m_pActiveShell->GetView().GetViewFrame()->GetDispatcher()->Execute(FN_OUTLINE_TO_CLIPBOARD);
3320 break;
3321 }
3322 case 800:
3323 KeyInput(KeyEvent(0, KEY_MOD1|KEY_MULTIPLY));
3324 break;
3325 //Display
3326 default:
3327 if(nSelectedPopupEntry > 300 && nSelectedPopupEntry < 400)
3328 {
3329 nSelectedPopupEntry -= 300;
3330 SwView *pView = SwModule::GetFirstView();
3331 while (pView)
3332 {
3333 nSelectedPopupEntry --;
3334 if(nSelectedPopupEntry == 0)
3335 {
3336 SetConstantShell(&pView->GetWrtShell());
3337 break;
3338 }
3339 pView = SwModule::GetNextView(pView);
3340 }
3341 if(nSelectedPopupEntry)
3342 {
3343 m_bViewHasChanged = nSelectedPopupEntry == 1;
3344 m_eState = (nSelectedPopupEntry == 1) ? State::ACTIVE : State::HIDDEN;
3345 Display(nSelectedPopupEntry == 1);
3346 }
3347 }
3348 }
3349 GetParentWindow()->UpdateListBox();
3350 }
3351
SetOutlineLevel(sal_uInt8 nSet)3352 void SwContentTree::SetOutlineLevel(sal_uInt8 nSet)
3353 {
3354 m_nOutlineLevel = nSet;
3355 m_pConfig->SetOutlineLevel( m_nOutlineLevel );
3356 std::unique_ptr<SwContentType>& rpContentT = (State::ACTIVE == m_eState)
3357 ? m_aActiveContentArr[ContentTypeId::OUTLINE]
3358 : m_aHiddenContentArr[ContentTypeId::OUTLINE];
3359 if(rpContentT)
3360 {
3361 rpContentT->SetOutlineLevel(m_nOutlineLevel);
3362 rpContentT->Init();
3363 }
3364 Display(State::ACTIVE == m_eState);
3365 }
3366
3367 // Mode Change: Show dropped Doc
3368
ShowHiddenShell()3369 void SwContentTree::ShowHiddenShell()
3370 {
3371 if(m_pHiddenShell)
3372 {
3373 m_eState = State::HIDDEN;
3374 Display(false);
3375 }
3376 }
3377
3378 // Mode Change: Show active view
3379
ShowActualView()3380 void SwContentTree::ShowActualView()
3381 {
3382 m_eState = State::ACTIVE;
3383 Display(true);
3384 GetParentWindow()->UpdateListBox();
3385 }
3386
3387 // Here the buttons for moving outlines are en-/disabled.
Select(SvTreeListEntry * pEntry,bool bSelect)3388 bool SwContentTree::Select( SvTreeListEntry* pEntry, bool bSelect )
3389 {
3390 if(!pEntry)
3391 return false;
3392 bool bEnable = false;
3393 SvTreeListEntry* pParentEntry = GetParent(pEntry);
3394 while(pParentEntry && (!lcl_IsContentType(pParentEntry)))
3395 {
3396 pParentEntry = GetParent(pParentEntry);
3397 }
3398 if (!m_bIsLastReadOnly)
3399 {
3400 if (!IsVisible())
3401 bEnable = true;
3402 else if (pParentEntry)
3403 {
3404 if ((m_bIsRoot && m_nRootType == ContentTypeId::OUTLINE) ||
3405 (lcl_IsContent(pEntry) &&
3406 static_cast<SwContentType*>(pParentEntry->GetUserData())->GetType() == ContentTypeId::OUTLINE))
3407 {
3408 bEnable = true;
3409 }
3410 }
3411 }
3412 SwNavigationPI* pNavi = GetParentWindow();
3413 pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("up"), bEnable);
3414 pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("down"), bEnable);
3415 pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("promote"), bEnable);
3416 pNavi->m_aContentToolBox->EnableItem(pNavi->m_aContentToolBox->GetItemId("demote"), bEnable);
3417
3418 return SvTreeListBox::Select(pEntry, bSelect);
3419 }
3420
SetRootType(ContentTypeId nType)3421 void SwContentTree::SetRootType(ContentTypeId nType)
3422 {
3423 m_nRootType = nType;
3424 m_bIsRoot = true;
3425 m_pConfig->SetRootType( m_nRootType );
3426 }
3427
RemoveNewline(const OUString & rEntry)3428 OUString SwContentType::RemoveNewline(const OUString& rEntry)
3429 {
3430 if (rEntry.isEmpty())
3431 return rEntry;
3432
3433 OUStringBuffer aEntry(rEntry);
3434 for (sal_Int32 i = 0; i < rEntry.getLength(); ++i)
3435 if(aEntry[i] == 10 || aEntry[i] == 13)
3436 aEntry[i] = 0x20;
3437
3438 return aEntry.makeStringAndClear();
3439 }
3440
EditEntry(SvTreeListEntry const * pEntry,EditEntryMode nMode)3441 void SwContentTree::EditEntry(SvTreeListEntry const * pEntry, EditEntryMode nMode)
3442 {
3443 SwContent* pCnt = static_cast<SwContent*>(pEntry->GetUserData());
3444 GotoContent(pCnt);
3445 const ContentTypeId nType = pCnt->GetParent()->GetType();
3446 sal_uInt16 nSlot = 0;
3447
3448 uno::Reference< container::XNameAccess > xNameAccess, xSecond, xThird;
3449 switch(nType)
3450 {
3451 case ContentTypeId::TABLE :
3452 if(nMode == EditEntryMode::UNPROTECT_TABLE)
3453 {
3454 m_pActiveShell->GetView().GetDocShell()->
3455 GetDoc()->UnProtectCells( pCnt->GetName());
3456 }
3457 else if(nMode == EditEntryMode::DELETE)
3458 {
3459 m_pActiveShell->StartAction();
3460 OUString sTable = SwResId(STR_TABLE_NAME);
3461 SwRewriter aRewriterTableName;
3462 aRewriterTableName.AddRule(UndoArg1, SwResId(STR_START_QUOTE));
3463 aRewriterTableName.AddRule(UndoArg2, pCnt->GetName());
3464 aRewriterTableName.AddRule(UndoArg3, SwResId(STR_END_QUOTE));
3465 sTable = aRewriterTableName.Apply(sTable);
3466
3467 SwRewriter aRewriter;
3468 aRewriter.AddRule(UndoArg1, sTable);
3469 m_pActiveShell->StartUndo(SwUndoId::DELETE, &aRewriter);
3470 m_pActiveShell->GetView().GetViewFrame()->GetDispatcher()->Execute(FN_TABLE_SELECT_ALL);
3471 m_pActiveShell->DeleteRow();
3472 m_pActiveShell->EndUndo();
3473 m_pActiveShell->EndAction();
3474 }
3475 else if(nMode == EditEntryMode::RENAME)
3476 {
3477 uno::Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
3478 uno::Reference< text::XTextTablesSupplier > xTables(xModel, uno::UNO_QUERY);
3479 xNameAccess = xTables->getTextTables();
3480 }
3481 else
3482 nSlot = FN_FORMAT_TABLE_DLG;
3483 break;
3484
3485 case ContentTypeId::GRAPHIC :
3486 if(nMode == EditEntryMode::DELETE)
3487 {
3488 m_pActiveShell->DelRight();
3489 }
3490 else if(nMode == EditEntryMode::RENAME)
3491 {
3492 uno::Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
3493 uno::Reference< text::XTextGraphicObjectsSupplier > xGraphics(xModel, uno::UNO_QUERY);
3494 xNameAccess = xGraphics->getGraphicObjects();
3495 uno::Reference< text::XTextFramesSupplier > xFrames(xModel, uno::UNO_QUERY);
3496 xSecond = xFrames->getTextFrames();
3497 uno::Reference< text::XTextEmbeddedObjectsSupplier > xObjs(xModel, uno::UNO_QUERY);
3498 xThird = xObjs->getEmbeddedObjects();
3499 }
3500 else
3501 nSlot = FN_FORMAT_GRAFIC_DLG;
3502 break;
3503
3504 case ContentTypeId::FRAME :
3505 case ContentTypeId::OLE :
3506 if(nMode == EditEntryMode::DELETE)
3507 {
3508 m_pActiveShell->DelRight();
3509 }
3510 else if(nMode == EditEntryMode::RENAME)
3511 {
3512 uno::Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
3513 uno::Reference< text::XTextFramesSupplier > xFrames(xModel, uno::UNO_QUERY);
3514 uno::Reference< text::XTextEmbeddedObjectsSupplier > xObjs(xModel, uno::UNO_QUERY);
3515 if(ContentTypeId::FRAME == nType)
3516 {
3517 xNameAccess = xFrames->getTextFrames();
3518 xSecond = xObjs->getEmbeddedObjects();
3519 }
3520 else
3521 {
3522 xNameAccess = xObjs->getEmbeddedObjects();
3523 xSecond = xFrames->getTextFrames();
3524 }
3525 uno::Reference< text::XTextGraphicObjectsSupplier > xGraphics(xModel, uno::UNO_QUERY);
3526 xThird = xGraphics->getGraphicObjects();
3527 }
3528 else
3529 nSlot = FN_FORMAT_FRAME_DLG;
3530 break;
3531 case ContentTypeId::BOOKMARK :
3532 if(nMode == EditEntryMode::DELETE)
3533 {
3534 IDocumentMarkAccess* const pMarkAccess = m_pActiveShell->getIDocumentMarkAccess();
3535 pMarkAccess->deleteMark( pMarkAccess->findMark(pCnt->GetName()) );
3536 }
3537 else if(nMode == EditEntryMode::RENAME)
3538 {
3539 uno::Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
3540 uno::Reference< text::XBookmarksSupplier > xBkms(xModel, uno::UNO_QUERY);
3541 xNameAccess = xBkms->getBookmarks();
3542 }
3543 else
3544 nSlot = FN_INSERT_BOOKMARK;
3545 break;
3546
3547 case ContentTypeId::REGION :
3548 if(nMode == EditEntryMode::RENAME)
3549 {
3550 uno::Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
3551 uno::Reference< text::XTextSectionsSupplier > xSects(xModel, uno::UNO_QUERY);
3552 xNameAccess = xSects->getTextSections();
3553 }
3554 else
3555 nSlot = FN_EDIT_REGION;
3556 break;
3557
3558 case ContentTypeId::URLFIELD:
3559 nSlot = SID_EDIT_HYPERLINK;
3560 break;
3561 case ContentTypeId::REFERENCE:
3562 nSlot = FN_EDIT_FIELD;
3563 break;
3564
3565 case ContentTypeId::POSTIT:
3566 m_pActiveShell->GetView().GetPostItMgr()->AssureStdModeAtShell();
3567 if(nMode == EditEntryMode::DELETE)
3568 {
3569 m_pActiveShell->GetView().GetPostItMgr()->SetActiveSidebarWin(nullptr);
3570 m_pActiveShell->DelRight();
3571 }
3572 else
3573 {
3574 nSlot = FN_POSTIT;
3575 }
3576 break;
3577 case ContentTypeId::INDEX:
3578 {
3579 const SwTOXBase* pBase = static_cast<SwTOXBaseContent*>(pCnt)->GetTOXBase();
3580 switch(nMode)
3581 {
3582 case EditEntryMode::EDIT:
3583 if(pBase)
3584 {
3585 SwPtrItem aPtrItem( FN_INSERT_MULTI_TOX, const_cast<SwTOXBase *>(pBase));
3586 m_pActiveShell->GetView().GetViewFrame()->
3587 GetDispatcher()->ExecuteList(FN_INSERT_MULTI_TOX,
3588 SfxCallMode::ASYNCHRON, { &aPtrItem });
3589
3590 }
3591 break;
3592 case EditEntryMode::RMV_IDX:
3593 case EditEntryMode::DELETE:
3594 {
3595 if( pBase )
3596 m_pActiveShell->DeleteTOX(*pBase, EditEntryMode::DELETE == nMode);
3597 }
3598 break;
3599 case EditEntryMode::UPD_IDX:
3600 case EditEntryMode::RENAME:
3601 {
3602 Reference< frame::XModel > xModel = m_pActiveShell->GetView().GetDocShell()->GetBaseModel();
3603 Reference< XDocumentIndexesSupplier > xIndexes(xModel, UNO_QUERY);
3604 Reference< XIndexAccess> xIdxAcc(xIndexes->getDocumentIndexes());
3605 Reference< XNameAccess >xLocalNameAccess(xIdxAcc, UNO_QUERY);
3606 if(EditEntryMode::RENAME == nMode)
3607 xNameAccess = xLocalNameAccess;
3608 else if(xLocalNameAccess.is() && xLocalNameAccess->hasByName(pBase->GetTOXName()))
3609 {
3610 Any aIdx = xLocalNameAccess->getByName(pBase->GetTOXName());
3611 Reference< XDocumentIndex> xIdx;
3612 if(aIdx >>= xIdx)
3613 xIdx->update();
3614 }
3615 }
3616 break;
3617 default: break;
3618 }
3619 }
3620 break;
3621 case ContentTypeId::DRAWOBJECT :
3622 if(EditEntryMode::DELETE == nMode)
3623 nSlot = SID_DELETE;
3624 break;
3625 default: break;
3626 }
3627 if(nSlot)
3628 m_pActiveShell->GetView().GetViewFrame()->
3629 GetDispatcher()->Execute(nSlot, SfxCallMode::ASYNCHRON);
3630 else if(xNameAccess.is())
3631 {
3632 uno::Any aObj = xNameAccess->getByName(pCnt->GetName());
3633 uno::Reference< uno::XInterface > xTmp;
3634 aObj >>= xTmp;
3635 uno::Reference< container::XNamed > xNamed(xTmp, uno::UNO_QUERY);
3636 SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
3637 ScopedVclPtr<AbstractSwRenameXNamedDlg> pDlg(pFact->CreateSwRenameXNamedDlg(GetFrameWeld(), xNamed, xNameAccess));
3638 if(xSecond.is())
3639 pDlg->SetAlternativeAccess( xSecond, xThird);
3640
3641 OUString sForbiddenChars;
3642 if(ContentTypeId::BOOKMARK == nType)
3643 {
3644 sForbiddenChars = "/\\@:*?\";,.#";
3645 }
3646 else if(ContentTypeId::TABLE == nType)
3647 {
3648 sForbiddenChars = " .<>";
3649 }
3650 pDlg->SetForbiddenChars(sForbiddenChars);
3651 pDlg->Execute();
3652 }
3653 }
3654
GotoContent(const SwContent * pCnt)3655 void SwContentTree::GotoContent(const SwContent* pCnt)
3656 {
3657 m_pActiveShell->EnterStdMode();
3658
3659 bool bSel = false;
3660 switch(pCnt->GetParent()->GetType())
3661 {
3662 case ContentTypeId::OUTLINE :
3663 {
3664 m_pActiveShell->GotoOutline(static_cast<const SwOutlineContent*>(pCnt)->GetOutlinePos());
3665 }
3666 break;
3667 case ContentTypeId::TABLE :
3668 {
3669 m_pActiveShell->GotoTable(pCnt->GetName());
3670 }
3671 break;
3672 case ContentTypeId::FRAME :
3673 case ContentTypeId::GRAPHIC :
3674 case ContentTypeId::OLE :
3675 {
3676 if(m_pActiveShell->GotoFly(pCnt->GetName()))
3677 bSel = true;
3678 }
3679 break;
3680 case ContentTypeId::BOOKMARK:
3681 {
3682 m_pActiveShell->GotoMark(pCnt->GetName());
3683 }
3684 break;
3685 case ContentTypeId::REGION :
3686 {
3687 m_pActiveShell->GotoRegion(pCnt->GetName());
3688 }
3689 break;
3690 case ContentTypeId::URLFIELD:
3691 {
3692 if(m_pActiveShell->GotoINetAttr(
3693 *static_cast<const SwURLFieldContent*>(pCnt)->GetINetAttr() ))
3694 {
3695 m_pActiveShell->Right( CRSR_SKIP_CHARS, true, 1, false);
3696 m_pActiveShell->SwCursorShell::SelectTextAttr( RES_TXTATR_INETFMT, true );
3697 }
3698
3699 }
3700 break;
3701 case ContentTypeId::REFERENCE:
3702 {
3703 m_pActiveShell->GotoRefMark(pCnt->GetName());
3704 }
3705 break;
3706 case ContentTypeId::INDEX:
3707 {
3708 const OUString& sName(pCnt->GetName());
3709 if (!m_pActiveShell->GotoNextTOXBase(&sName))
3710 m_pActiveShell->GotoPrevTOXBase(&sName);
3711 }
3712 break;
3713 case ContentTypeId::POSTIT:
3714 m_pActiveShell->GetView().GetPostItMgr()->AssureStdModeAtShell();
3715 m_pActiveShell->GotoFormatField(*static_cast<const SwPostItContent*>(pCnt)->GetPostIt());
3716 break;
3717 case ContentTypeId::DRAWOBJECT:
3718 {
3719 SwPosition aPos = *m_pActiveShell->GetCursor()->GetPoint();
3720 SdrView* pDrawView = m_pActiveShell->GetDrawView();
3721 if (pDrawView)
3722 {
3723 pDrawView->SdrEndTextEdit();
3724 pDrawView->UnmarkAll();
3725 SwDrawModel* _pModel = m_pActiveShell->getIDocumentDrawModelAccess().GetDrawModel();
3726 SdrPage* pPage = _pModel->GetPage(0);
3727 const size_t nCount = pPage->GetObjCount();
3728 for( size_t i=0; i<nCount; ++i )
3729 {
3730 SdrObject* pTemp = pPage->GetObj(i);
3731 if (pTemp->GetName() == pCnt->GetName())
3732 {
3733 SdrPageView* pPV = pDrawView->GetSdrPageView();
3734 if( pPV )
3735 {
3736 pDrawView->MarkObj( pTemp, pPV );
3737 }
3738 }
3739 }
3740 m_pActiveShell->GetNavigationMgr().addEntry(aPos);
3741 m_pActiveShell->EnterStdMode();
3742 bSel = true;
3743 }
3744 }
3745 break;
3746 default: break;
3747 }
3748 if(bSel)
3749 {
3750 m_pActiveShell->HideCursor();
3751 m_pActiveShell->EnterSelFrameMode();
3752 }
3753 SwView& rView = m_pActiveShell->GetView();
3754 rView.StopShellTimer();
3755 rView.GetPostItMgr()->SetActiveSidebarWin(nullptr);
3756 rView.GetEditWin().GrabFocus();
3757
3758 // force scroll to cursor position when navigating to inactive document
3759 if(!bSel)
3760 {
3761 Point rPoint = m_pActiveShell->GetCursorDocPos();
3762 rPoint.setX(0);
3763 rView.SetVisArea(rPoint);
3764 }
3765 }
3766
3767 // Now even the matching text::Bookmark
NaviContentBookmark()3768 NaviContentBookmark::NaviContentBookmark()
3769 :
3770 nDocSh(0),
3771 nDefDrag( RegionMode::NONE )
3772 {
3773 }
3774
NaviContentBookmark(const OUString & rUrl,const OUString & rDesc,RegionMode nDragType,const SwDocShell * pDocSh)3775 NaviContentBookmark::NaviContentBookmark( const OUString &rUrl,
3776 const OUString& rDesc,
3777 RegionMode nDragType,
3778 const SwDocShell* pDocSh ) :
3779 aUrl( rUrl ),
3780 aDescr(rDesc),
3781 nDocSh(reinterpret_cast<sal_IntPtr>(pDocSh)),
3782 nDefDrag( nDragType )
3783 {
3784 }
3785
Copy(TransferDataContainer & rData) const3786 void NaviContentBookmark::Copy( TransferDataContainer& rData ) const
3787 {
3788 rtl_TextEncoding eSysCSet = osl_getThreadTextEncoding();
3789
3790 OString sStrBuf(OUStringToOString(aUrl, eSysCSet) + OStringChar(NAVI_BOOKMARK_DELIM) +
3791 OUStringToOString(aDescr, eSysCSet) + OStringChar(NAVI_BOOKMARK_DELIM) +
3792 OString::number(static_cast<int>(nDefDrag)) + OStringChar(NAVI_BOOKMARK_DELIM) +
3793 OString::number(nDocSh));
3794 rData.CopyByteString(SotClipboardFormatId::SONLK, sStrBuf);
3795 }
3796
Paste(TransferableDataHelper & rData)3797 bool NaviContentBookmark::Paste( TransferableDataHelper& rData )
3798 {
3799 OUString sStr;
3800 bool bRet = rData.GetString( SotClipboardFormatId::SONLK, sStr );
3801 if( bRet )
3802 {
3803 sal_Int32 nPos = 0;
3804 aUrl = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos );
3805 aDescr = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos );
3806 nDefDrag= static_cast<RegionMode>( sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos ).toInt32() );
3807 nDocSh = sStr.getToken(0, NAVI_BOOKMARK_DELIM, nPos ).toInt32();
3808 }
3809 return bRet;
3810 }
3811
3812 class SwContentLBoxString : public SvLBoxString
3813 {
3814 public:
SwContentLBoxString(const OUString & rStr)3815 explicit SwContentLBoxString(const OUString& rStr) : SvLBoxString(rStr) {}
3816
3817 virtual void Paint(const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext,
3818 const SvViewDataEntry* pView, const SvTreeListEntry& rEntry) override;
3819 };
3820
InitEntry(SvTreeListEntry * pEntry,const OUString & rStr,const Image & rImg1,const Image & rImg2)3821 void SwContentTree::InitEntry(SvTreeListEntry* pEntry,
3822 const OUString& rStr ,const Image& rImg1,const Image& rImg2)
3823 {
3824 const size_t nColToHilite = 1; //0==Bitmap;1=="Column1";2=="Column2"
3825 SvTreeListBox::InitEntry( pEntry, rStr, rImg1, rImg2 );
3826 SvLBoxString& rCol = static_cast<SvLBoxString&>(pEntry->GetItem( nColToHilite ));
3827 pEntry->ReplaceItem(std::make_unique<SwContentLBoxString>(rCol.GetText()), nColToHilite);
3828 }
3829
Paint(const Point & rPos,SvTreeListBox & rDev,vcl::RenderContext & rRenderContext,const SvViewDataEntry * pView,const SvTreeListEntry & rEntry)3830 void SwContentLBoxString::Paint(const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext,
3831 const SvViewDataEntry* pView, const SvTreeListEntry& rEntry)
3832 {
3833 if (lcl_IsContent(&rEntry) && static_cast<SwContent *>(rEntry.GetUserData())->IsInvisible())
3834 {
3835 vcl::Font aOldFont(rRenderContext.GetFont());
3836 vcl::Font aFont(aOldFont);
3837 aFont.SetColor(COL_LIGHTGRAY);
3838 rRenderContext.SetFont(aFont );
3839 rRenderContext.DrawText(rPos, GetText());
3840 rRenderContext.SetFont(aOldFont);
3841 }
3842 else
3843 {
3844 SvLBoxString::Paint(rPos, rDev, rRenderContext, pView, rEntry);
3845 }
3846 }
3847
DataChanged(const DataChangedEvent & rDCEvt)3848 void SwContentTree::DataChanged(const DataChangedEvent& rDCEvt)
3849 {
3850 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
3851 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
3852 {
3853 FindActiveTypeAndRemoveUserData();
3854
3855 Display(true);
3856 }
3857
3858 SvTreeListBox::DataChanged( rDCEvt );
3859 }
3860
GetParentWindow()3861 SwNavigationPI* SwContentTree::GetParentWindow()
3862 {
3863 return m_xDialog;
3864 }
3865
3866 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3867