tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / navipi / content.cxx
blob51e7347b7254d09cff814f2efc55f03df411d3e5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <string_view>
24 #include <svx/svditer.hxx>
25 #include <svx/svdobj.hxx>
26 #include <svx/svdview.hxx>
27 #include <sfx2/linkmgr.hxx>
28 #include <sfx2/docfile.hxx>
29 #include <sfx2/viewfrm.hxx>
30 #include <vcl/commandevent.hxx>
31 #include <vcl/svapp.hxx>
32 #include <osl/diagnose.h>
33 #include <tools/urlobj.hxx>
34 #include <sal/log.hxx>
35 #include <unotools/charclass.hxx>
37 #include <content.hxx>
38 #include <navipi.hxx>
39 #include <global.hxx>
40 #include <docsh.hxx>
41 #include <docfunc.hxx>
42 #include <scmod.hxx>
43 #include <rangenam.hxx>
44 #include <dbdata.hxx>
45 #include <drwlayer.hxx>
46 #include <transobj.hxx>
47 #include <drwtrans.hxx>
48 #include <lnktrans.hxx>
49 #include <strings.hrc>
50 #include <scresid.hxx>
51 #include <bitmaps.hlst>
52 #include <arealink.hxx>
53 #include <navicfg.hxx>
54 #include <navsett.hxx>
55 #include <postit.hxx>
56 #include <tabvwsh.hxx>
57 #include <drawview.hxx>
58 #include <clipparam.hxx>
59 #include <markdata.hxx>
61 using namespace com::sun::star;
63 // order of the categories in navigator -------------------------------------
65 const ScContentId pTypeList[int(ScContentId::LAST) + 1] =
67 ScContentId::ROOT, // ROOT (0) has to be at the front
68 ScContentId::TABLE,
69 ScContentId::RANGENAME,
70 ScContentId::DBAREA,
71 ScContentId::AREALINK,
72 ScContentId::GRAPHIC,
73 ScContentId::OLEOBJECT,
74 ScContentId::NOTE,
75 ScContentId::DRAWING
78 constexpr OUString aContentBmps[]=
80 RID_BMP_CONTENT_TABLE,
81 RID_BMP_CONTENT_RANGENAME,
82 RID_BMP_CONTENT_DBAREA,
83 RID_BMP_CONTENT_GRAPHIC,
84 RID_BMP_CONTENT_OLEOBJECT,
85 RID_BMP_CONTENT_NOTE,
86 RID_BMP_CONTENT_AREALINK,
87 RID_BMP_CONTENT_DRAWING
90 ScDocShell* ScContentTree::GetManualOrCurrent()
92 ScDocShell* pSh = nullptr;
93 if ( !aManualDoc.isEmpty() )
95 SfxObjectShell* pObjSh = SfxObjectShell::GetFirst( checkSfxObjectShell<ScDocShell> );
96 while ( pObjSh && !pSh )
98 if ( pObjSh->GetTitle() == aManualDoc )
99 pSh = dynamic_cast<ScDocShell*>( pObjSh );
100 pObjSh = SfxObjectShell::GetNext( *pObjSh, checkSfxObjectShell<ScDocShell> );
103 else
105 // only current when manual isn't set
106 // (so it's detected when the documents don't exists any longer)
108 SfxViewShell* pViewSh = SfxViewShell::Current();
109 if ( pViewSh )
111 SfxObjectShell* pObjSh = pViewSh->GetViewFrame().GetObjectShell();
112 pSh = dynamic_cast<ScDocShell*>( pObjSh );
116 return pSh;
119 // ScContentTree
121 ScContentTree::ScContentTree(std::unique_ptr<weld::TreeView> xTreeView, ScNavigatorDlg* pNavigatorDlg)
122 : m_xTreeView(std::move(xTreeView))
123 , m_xScratchIter(m_xTreeView->make_iterator())
124 , m_xTransferObj(new ScLinkTransferObj)
125 , pParentWindow(pNavigatorDlg)
126 , nRootType(ScContentId::ROOT)
127 , bIsInNavigatorDlg(false)
128 , m_bFreeze(false)
129 , m_nAsyncMouseReleaseId(nullptr)
131 for (sal_uInt16 i = 0; i <= int(ScContentId::LAST); ++i)
132 pPosList[pTypeList[i]] = i; // inverse for searching
134 m_aRootNodes[ScContentId::ROOT] = nullptr;
135 for (sal_uInt16 i = 1; i < int(ScContentId::LAST); ++i)
136 InitRoot(static_cast<ScContentId>(i));
138 m_xTreeView->connect_row_activated(LINK(this, ScContentTree, ContentDoubleClickHdl));
139 m_xTreeView->connect_mouse_release(LINK(this, ScContentTree, MouseReleaseHdl));
140 m_xTreeView->connect_key_press(LINK(this, ScContentTree, KeyInputHdl));
141 m_xTreeView->connect_popup_menu(LINK(this, ScContentTree, CommandHdl));
142 m_xTreeView->connect_query_tooltip(LINK(this, ScContentTree, QueryTooltipHdl));
144 rtl::Reference<TransferDataContainer> xHelper(m_xTransferObj);
145 m_xTreeView->enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
147 m_xTreeView->connect_drag_begin(LINK(this, ScContentTree, DragBeginHdl));
149 m_xTreeView->set_selection_mode( SelectionMode::Single );
151 m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 30,
152 m_xTreeView->get_text_height() * 13);
155 ScContentTree::~ScContentTree()
157 if (m_nAsyncMouseReleaseId)
159 Application::RemoveUserEvent(m_nAsyncMouseReleaseId);
160 m_nAsyncMouseReleaseId = nullptr;
164 const TranslateId SCSTR_CONTENT_ARY[] =
166 SCSTR_CONTENT_ROOT,
167 SCSTR_CONTENT_TABLE,
168 SCSTR_CONTENT_RANGENAME,
169 SCSTR_CONTENT_DBAREA,
170 SCSTR_CONTENT_GRAPHIC,
171 SCSTR_CONTENT_OLEOBJECT,
172 SCSTR_CONTENT_NOTE,
173 SCSTR_CONTENT_AREALINK,
174 SCSTR_CONTENT_DRAWING
177 void ScContentTree::InitRoot( ScContentId nType )
179 if ( nType == ScContentId::ROOT )
180 return;
182 if ( nRootType != ScContentId::ROOT && nRootType != nType ) // hidden ?
184 m_aRootNodes[nType] = nullptr;
185 return;
188 auto const & aImage = aContentBmps[static_cast<int>(nType) - 1];
190 OUString aName;
191 if(comphelper::LibreOfficeKit::isActive())
193 //In case of LOK we may have many different ScContentTrees in different languages.
194 //At creation time, we store what language we use, and then use it later too.
195 //It does not work in the constructor, that is why it is here.
196 if (!m_pResLocaleForLOK)
198 m_pResLocaleForLOK = std::make_unique<std::locale>(ScModule::get()->GetResLocale());
200 aName = Translate::get(SCSTR_CONTENT_ARY[static_cast<int>(nType)], *m_pResLocaleForLOK);
202 else
204 aName = ScResId(SCSTR_CONTENT_ARY[static_cast<int>(nType)]);
206 // back to the correct position:
207 sal_uInt16 nPos = nRootType != ScContentId::ROOT ? 0 : pPosList[nType]-1;
208 m_aRootNodes[nType] = m_xTreeView->make_iterator();
209 m_xTreeView->insert(nullptr, nPos, &aName, nullptr, nullptr, nullptr, false, m_aRootNodes[nType].get());
210 m_xTreeView->set_image(*m_aRootNodes[nType], aImage);
213 void ScContentTree::ClearAll()
215 //There are one method in Control::SetUpdateMode(), and one override method SvTreeListBox::SetUpdateMode(). Here although
216 //SvTreeListBox::SetUpdateMode() is called in refresh method, it only call SvTreeListBox::SetUpdateMode(), not Control::SetUpdateMode().
217 //In m_xTreeView->clear(), Broadcast( LISTACTION_CLEARED ) will be called and finally, it will be trapped into the event yield() loop. And
218 //the InitRoot() method won't be called. Then if a user click or press key to update the navigator tree, crash happens.
219 //So the solution is to disable the UpdateMode of Control, then call Clear(), then recover the update mode
220 bool bWasFrozen = m_bFreeze;
221 if (!bWasFrozen)
222 freeze();
223 m_xTreeView->clear();
224 if (!bWasFrozen)
225 thaw();
226 for (sal_uInt16 i=1; i<=int(ScContentId::LAST); i++)
227 InitRoot(static_cast<ScContentId>(i));
230 void ScContentTree::ClearType(ScContentId nType)
232 if (nType == ScContentId::ROOT)
233 ClearAll();
234 else
236 weld::TreeIter* pParent = m_aRootNodes[nType].get();
237 if (!pParent || m_xTreeView->iter_has_child(*pParent)) // not if no children existing
239 if (pParent)
240 m_xTreeView->remove(*pParent); // with all children
241 InitRoot( nType ); // if needed insert anew
246 void ScContentTree::InsertContent( ScContentId nType, const OUString& rValue )
248 weld::TreeIter* pParent = m_aRootNodes[nType].get();
249 if (pParent)
251 m_xTreeView->insert(pParent, -1, &rValue, nullptr, nullptr, nullptr, false, m_xScratchIter.get());
252 m_xTreeView->set_sensitive(*m_xScratchIter, true);
254 else
256 OSL_FAIL("InsertContent without parent");
260 void ScContentTree::GetEntryIndexes(ScContentId& rnRootIndex, sal_uLong& rnChildIndex, const weld::TreeIter* pEntry) const
262 rnRootIndex = ScContentId::ROOT;
263 rnChildIndex = SC_CONTENT_NOCHILD;
265 if( !pEntry )
266 return;
268 std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(pEntry));
269 if (!m_xTreeView->iter_parent(*xParent))
270 xParent.reset();
271 bool bFound = false;
272 for( int i = 1; !bFound && (i <= int(ScContentId::LAST)); ++i )
274 ScContentId nRoot = static_cast<ScContentId>(i);
275 if (!m_aRootNodes[nRoot])
276 continue;
277 if (m_xTreeView->iter_compare(*pEntry, *m_aRootNodes[nRoot]) == 0)
279 rnRootIndex = nRoot;
280 rnChildIndex = ~0UL;
281 bFound = true;
283 else if (xParent && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[nRoot]) == 0)
285 rnRootIndex = nRoot;
287 // search the entry in all child entries of the parent
288 sal_uLong nEntry = 0;
289 std::unique_ptr<weld::TreeIter> xIterEntry(m_xTreeView->make_iterator(xParent.get()));
290 bool bIterEntry = m_xTreeView->iter_children(*xIterEntry);
291 while (!bFound && bIterEntry)
293 if (m_xTreeView->iter_compare(*pEntry, *xIterEntry) == 0)
295 rnChildIndex = nEntry;
296 bFound = true; // exit the while loop
298 bIterEntry = m_xTreeView->iter_next_sibling(*xIterEntry);
299 ++nEntry;
302 bFound = true; // exit the for loop
307 sal_uLong ScContentTree::GetChildIndex(const weld::TreeIter* pEntry) const
309 ScContentId nRoot;
310 sal_uLong nChild;
311 GetEntryIndexes(nRoot, nChild, pEntry);
312 return nChild;
315 static OUString lcl_GetDBAreaRange( const ScDocument* pDoc, const OUString& rDBName )
317 OUString aRet;
318 if (pDoc)
320 ScDBCollection* pDbNames = pDoc->GetDBCollection();
321 const ScDBData* pData = pDbNames->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rDBName));
322 if (pData)
324 ScRange aRange;
325 pData->GetArea(aRange);
326 aRet = aRange.Format(*pDoc, ScRefFlags::RANGE_ABS_3D);
329 return aRet;
332 IMPL_LINK_NOARG(ScContentTree, ContentDoubleClickHdl, weld::TreeView&, bool)
334 ScContentId nType;
335 sal_uLong nChild;
336 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
337 if (!m_xTreeView->get_cursor(xEntry.get()))
338 xEntry.reset();
339 GetEntryIndexes(nType, nChild, xEntry.get());
341 if (xEntry && (nType != ScContentId::ROOT) && (nChild != SC_CONTENT_NOCHILD))
343 OUString aText(m_xTreeView->get_text(*xEntry));
345 if ( !aManualDoc.isEmpty() )
346 pParentWindow->SetCurrentDoc( aManualDoc );
348 switch( nType )
350 case ScContentId::TABLE:
352 // tdf#133159 store current config before changing sheet
353 // plausible that this should be done for all cases, but this
354 // is the known case that needs it
355 StoreNavigatorSettings();
356 pParentWindow->SetCurrentTableStr( aText );
358 break;
360 case ScContentId::RANGENAME:
361 pParentWindow->SetCurrentCellStr( aText );
362 break;
364 case ScContentId::DBAREA:
366 // If the same names of area and DB exists, then
367 // SID_CURRENTCELL takes the area name.
368 // Therefore for DB areas access them directly via address.
370 OUString aRangeStr = lcl_GetDBAreaRange( GetSourceDocument(), aText );
371 if (!aRangeStr.isEmpty())
372 pParentWindow->SetCurrentCellStr( aRangeStr );
374 break;
376 case ScContentId::OLEOBJECT:
377 case ScContentId::GRAPHIC:
378 case ScContentId::DRAWING:
379 pParentWindow->SetCurrentObject( aText );
380 break;
382 case ScContentId::NOTE:
384 ScAddress aPos = GetNotePos( nChild );
385 pParentWindow->SetCurrentTable( aPos.Tab() );
386 pParentWindow->SetCurrentCell( aPos.Col(), aPos.Row() );
387 // Check whether the comment is currently visible and toggle its visibility
388 ScDocument* pSrcDoc = GetSourceDocument();
389 if (ScPostIt* pNote = pSrcDoc ? pSrcDoc->GetNote(aPos.Col(), aPos.Row(), aPos.Tab()) : nullptr)
391 bool bVisible = pNote->IsCaptionShown();
392 // Effectivelly set the visibility of the comment
393 GetManualOrCurrent()->GetDocFunc().ShowNote(aPos, !bVisible);
394 // Put the note in edit mode
395 ScTabViewShell* pScTabViewShell = ScNavigatorDlg::GetTabViewShell();
396 pScTabViewShell->EditNote();
399 break;
401 case ScContentId::AREALINK:
403 const ScAreaLink* pLink = GetLink(nChild);
404 ScDocument* pSrcDoc = GetSourceDocument();
405 if (pLink && pSrcDoc)
407 const ScRange& aRange = pLink->GetDestArea();
408 OUString aRangeStr(aRange.Format(*pSrcDoc, ScRefFlags::RANGE_ABS_3D, pSrcDoc->GetAddressConvention()));
409 pParentWindow->SetCurrentCellStr( aRangeStr );
412 break;
413 default: break;
416 ScNavigatorDlg::ReleaseFocus(); // set focus into document
419 return false;
422 void ScContentTree::LaunchAsyncStoreNavigatorSettings()
424 if (!m_nAsyncMouseReleaseId)
425 m_nAsyncMouseReleaseId = Application::PostUserEvent(LINK(this, ScContentTree, AsyncStoreNavigatorSettings));
428 IMPL_LINK_NOARG(ScContentTree, MouseReleaseHdl, const MouseEvent&, bool)
430 LaunchAsyncStoreNavigatorSettings();
431 return false;
434 IMPL_LINK_NOARG(ScContentTree, AsyncStoreNavigatorSettings, void*, void)
436 m_nAsyncMouseReleaseId = nullptr;
437 StoreNavigatorSettings();
440 IMPL_LINK(ScContentTree, KeyInputHdl, const KeyEvent&, rKEvt, bool)
442 bool bUsed = false;
444 const vcl::KeyCode aCode = rKEvt.GetKeyCode();
445 if (aCode.GetCode() == KEY_RETURN)
447 switch (aCode.GetModifier())
449 case KEY_MOD1:
450 ToggleRoot(); // toggle root mode (as in Writer)
451 bUsed = true;
452 break;
453 case 0:
455 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
456 if (!m_xTreeView->get_cursor(xEntry.get()))
457 xEntry.reset();
458 if (xEntry)
460 ScContentId nType;
461 sal_uLong nChild;
462 GetEntryIndexes(nType, nChild, xEntry.get());
464 if (nType != ScContentId::ROOT && nChild == SC_CONTENT_NOCHILD)
466 if (m_xTreeView->get_row_expanded(*xEntry))
467 m_xTreeView->collapse_row(*xEntry);
468 else
469 m_xTreeView->expand_row(*xEntry);
471 else
472 ContentDoubleClickHdl(*m_xTreeView); // select content as if double clicked
475 bUsed = true;
477 break;
480 //Make KEY_SPACE has same function as DoubleClick, and realize
481 //multi-selection.
482 if ( bIsInNavigatorDlg )
484 if(aCode.GetCode() == KEY_SPACE )
486 bUsed = true;
487 ScContentId nType;
488 sal_uLong nChild;
489 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
490 if (!m_xTreeView->get_cursor(xEntry.get()))
491 xEntry.reset();
492 GetEntryIndexes(nType, nChild, xEntry.get());
494 if (xEntry && (nType != ScContentId::ROOT) && (nChild != SC_CONTENT_NOCHILD))
496 OUString aText(m_xTreeView->get_text(*xEntry));
497 if (!aManualDoc.isEmpty())
498 pParentWindow->SetCurrentDoc( aManualDoc );
499 switch (nType)
501 case ScContentId::OLEOBJECT:
502 case ScContentId::GRAPHIC:
503 case ScContentId::DRAWING:
505 ScDrawView* pScDrawView = nullptr;
506 ScTabViewShell* pScTabViewShell = ScNavigatorDlg::GetTabViewShell();
507 if (pScTabViewShell)
508 pScDrawView = pScTabViewShell->GetViewData().GetScDrawView();
509 if (pScDrawView)
511 pScDrawView->SelectCurrentViewObject(aText);
512 bool bHasMakredObject = false;
513 weld::TreeIter* pParent = m_aRootNodes[nType].get();
514 std::unique_ptr<weld::TreeIter> xBeginEntry(m_xTreeView->make_iterator(pParent));
515 bool bBeginEntry = false;
516 if (pParent)
517 bBeginEntry = m_xTreeView->iter_children(*xBeginEntry);
518 while (bBeginEntry)
520 OUString aTempText(m_xTreeView->get_text(*xBeginEntry));
521 if( pScDrawView->GetObjectIsMarked( pScDrawView->GetObjectByName( aTempText ) ) )
523 bHasMakredObject = true;
524 break;
526 bBeginEntry = m_xTreeView->iter_next(*xBeginEntry);
528 if (!bHasMakredObject && pScTabViewShell)
529 pScTabViewShell->SetDrawShell(false);
531 break;
533 default:
534 break;
540 if (!bUsed)
542 if (aCode.GetCode() == KEY_F5)
543 StoreNavigatorSettings();
544 else
545 LaunchAsyncStoreNavigatorSettings();
548 return bUsed;
551 IMPL_LINK(ScContentTree, CommandHdl, const CommandEvent&, rCEvt, bool)
553 bool bDone = false;
555 ScContentId nType;
556 sal_uLong nChild;
557 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
558 if (!m_xTreeView->get_cursor(xEntry.get()))
559 xEntry.reset();
560 GetEntryIndexes(nType, nChild, xEntry.get());
562 switch ( rCEvt.GetCommand() )
564 case CommandEventId::ContextMenu:
566 // drag-and-drop mode
567 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), u"modules/scalc/ui/dropmenu.ui"_ustr));
568 std::unique_ptr<weld::Menu> xPop(xBuilder->weld_menu(u"contextmenu"_ustr));
569 std::unique_ptr<weld::Menu> xDropMenu(xBuilder->weld_menu(u"dragmodesubmenu"_ustr));
571 switch (pParentWindow->GetDropMode())
573 case 0:
574 xDropMenu->set_active(u"hyperlink"_ustr, true);
575 break;
576 case 1:
577 xDropMenu->set_active(u"link"_ustr, true);
578 break;
579 case 2:
580 xDropMenu->set_active(u"copy"_ustr, true);
581 break;
584 // displayed document
585 std::unique_ptr<weld::Menu> xDocMenu(xBuilder->weld_menu(u"displaymenu"_ustr));
586 sal_uInt16 i=0;
587 OUString sActive;
588 OUString sId;
589 // loaded documents
590 ScDocShell* pCurrentSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
591 SfxObjectShell* pSh = SfxObjectShell::GetFirst();
592 while ( pSh )
594 if ( dynamic_cast<const ScDocShell*>( pSh) != nullptr )
596 OUString aName = pSh->GetTitle();
597 OUString aEntry = aName;
598 if ( pSh == pCurrentSh )
599 aEntry += pParentWindow->aStrActive;
600 else
601 aEntry += pParentWindow->aStrNotActive;
602 ++i;
603 sId = "document" + OUString::number(i);
604 xDocMenu->append_radio(sId, aEntry);
605 if (aName == aManualDoc)
606 sActive = sId;
608 pSh = SfxObjectShell::GetNext( *pSh );
610 // "active window"
611 ++i;
612 sId = "document" + OUString::number(i);
613 xDocMenu->append_radio(sId, pParentWindow->aStrActiveWin);
614 if (aManualDoc.isEmpty())
615 sActive = sId;
616 xDocMenu->set_active(sActive, true);
618 // Edit/Delete Comments are only visible for comments
619 if (nType != ScContentId::NOTE)
621 xPop->set_visible(u"edit"_ustr, false);
622 xPop->set_visible(u"delete"_ustr, false);
625 OUString sIdent = xPop->popup_at_rect(m_xTreeView.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1)));
626 if (sIdent == "hyperlink")
627 pParentWindow->SetDropMode(0);
628 else if (sIdent == "link")
629 pParentWindow->SetDropMode(1);
630 else if (sIdent == "copy")
631 pParentWindow->SetDropMode(2);
632 else if (sIdent.startsWith("document"))
634 OUString aName = xDocMenu->get_label(sIdent);
635 SelectDoc(aName);
637 else if (sIdent == "edit")
639 ScAddress aPos = GetNotePos( nChild );
640 pParentWindow->SetCurrentTable( aPos.Tab() );
641 pParentWindow->SetCurrentCell( aPos.Col(), aPos.Row() );
642 ScDocument* pSrcDoc = GetSourceDocument();
643 if (pSrcDoc->GetNote(aPos.Col(), aPos.Row(), aPos.Tab()))
645 // Make the note visible and put it in edit mode
646 GetManualOrCurrent()->GetDocFunc().ShowNote(aPos, true);
647 ScTabViewShell* pScTabViewShell = ScNavigatorDlg::GetTabViewShell();
648 pScTabViewShell->EditNote();
649 bDone = true;
652 else if (sIdent == "delete")
654 ScAddress aPos = GetNotePos(nChild);
655 pParentWindow->SetCurrentTable(aPos.Tab());
656 pParentWindow->SetCurrentCell(aPos.Col(), aPos.Row());
657 ScTabViewShell* pScTabViewShell = ScNavigatorDlg::GetTabViewShell();
658 pScTabViewShell->DeleteContents(InsertDeleteFlags::NOTE);
661 break;
662 default: break;
665 return bDone;
668 IMPL_LINK(ScContentTree, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUString)
670 OUString aHelpText;
672 std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rEntry));
673 if (!m_xTreeView->iter_parent(*xParent))
674 xParent.reset();
676 if (!xParent) // Top-Level ?
678 aHelpText = OUString::number(m_xTreeView->iter_n_children(rEntry)) +
679 " " + m_xTreeView->get_text(rEntry);
681 else if (m_aRootNodes[ScContentId::NOTE] && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[ScContentId::NOTE]) == 0)
683 aHelpText = m_xTreeView->get_text(rEntry); // notes as help text
685 else if (m_aRootNodes[ScContentId::AREALINK] && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[ScContentId::AREALINK]) == 0)
687 auto nIndex = GetChildIndex(&rEntry);
688 if (nIndex != SC_CONTENT_NOCHILD)
690 const ScAreaLink* pLink = GetLink(nIndex);
691 if (pLink)
693 aHelpText = pLink->GetFile(); // source file as help text
698 return aHelpText;
701 ScDocument* ScContentTree::GetSourceDocument()
703 ScDocShell* pSh = GetManualOrCurrent();
704 if (pSh)
705 return &pSh->GetDocument();
706 return nullptr;
709 void ScContentTree::Refresh( ScContentId nType )
711 // if nothing has changed the cancel right away (against flicker)
712 if ( nType == ScContentId::NOTE )
713 if (!NoteStringsChanged())
714 return;
715 if ( nType == ScContentId::GRAPHIC )
716 if (!DrawNamesChanged(ScContentId::GRAPHIC))
717 return;
718 if ( nType == ScContentId::OLEOBJECT )
719 if (!DrawNamesChanged(ScContentId::OLEOBJECT))
720 return;
721 if ( nType == ScContentId::DRAWING )
722 if (!DrawNamesChanged(ScContentId::DRAWING))
723 return;
725 freeze();
727 ClearType( nType );
729 if ( nType == ScContentId::ROOT || nType == ScContentId::TABLE )
730 GetTableNames();
731 if ( nType == ScContentId::ROOT || nType == ScContentId::RANGENAME )
732 GetAreaNames();
733 if ( nType == ScContentId::ROOT || nType == ScContentId::DBAREA )
734 GetDbNames();
735 if ( nType == ScContentId::ROOT || nType == ScContentId::GRAPHIC )
736 GetGraphicNames();
737 if ( nType == ScContentId::ROOT || nType == ScContentId::OLEOBJECT )
738 GetOleNames();
739 if ( nType == ScContentId::ROOT || nType == ScContentId::DRAWING )
740 GetDrawingNames();
741 if ( nType == ScContentId::ROOT || nType == ScContentId::NOTE )
742 GetNoteStrings();
743 if ( nType == ScContentId::ROOT || nType == ScContentId::AREALINK )
744 GetLinkNames();
746 thaw();
748 ApplyNavigatorSettings();
751 void ScContentTree::GetTableNames()
753 if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::TABLE ) // hidden ?
754 return;
756 ScDocument* pDoc = GetSourceDocument();
757 if (!pDoc)
758 return;
760 OUString aName;
761 SCTAB nCount = pDoc->GetTableCount();
762 for ( SCTAB i=0; i<nCount; i++ )
764 pDoc->GetName( i, aName );
765 InsertContent( ScContentId::TABLE, aName );
769 namespace {
771 OUString createLocalRangeName(std::u16string_view rName, std::u16string_view rTableName)
773 return OUString::Concat(rName) + " (" + rTableName + ")";
777 void ScContentTree::GetAreaNames()
779 if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::RANGENAME ) // hidden ?
780 return;
782 ScDocument* pDoc = GetSourceDocument();
783 if (!pDoc)
784 return;
786 ScRange aDummy;
787 std::set<OUString> aSet;
788 ScRangeName* pRangeNames = pDoc->GetRangeName();
789 for (const auto& rEntry : *pRangeNames)
791 if (rEntry.second->IsValidReference(aDummy))
792 aSet.insert(rEntry.second->GetName());
794 for (SCTAB i = 0; i < pDoc->GetTableCount(); ++i)
796 ScRangeName* pLocalRangeName = pDoc->GetRangeName(i);
797 if (pLocalRangeName && !pLocalRangeName->empty())
799 OUString aTableName;
800 pDoc->GetName(i, aTableName);
801 for (const auto& rEntry : *pLocalRangeName)
803 if (rEntry.second->IsValidReference(aDummy))
804 aSet.insert(createLocalRangeName(rEntry.second->GetName(), aTableName));
809 for (const auto& rItem : aSet)
811 InsertContent(ScContentId::RANGENAME, rItem);
815 void ScContentTree::GetDbNames()
817 if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::DBAREA ) // hidden ?
818 return;
820 ScDocument* pDoc = GetSourceDocument();
821 if (!pDoc)
822 return;
824 ScDBCollection* pDbNames = pDoc->GetDBCollection();
825 const ScDBCollection::NamedDBs& rDBs = pDbNames->getNamedDBs();
826 for (const auto& rxDB : rDBs)
828 const OUString& aStrName = rxDB->GetName();
829 InsertContent(ScContentId::DBAREA, aStrName);
833 bool ScContentTree::IsPartOfType( ScContentId nContentType, SdrObjKind nObjIdentifier )
835 bool bRet = false;
836 switch ( nContentType )
838 case ScContentId::GRAPHIC:
839 bRet = ( nObjIdentifier == SdrObjKind::Graphic );
840 break;
841 case ScContentId::OLEOBJECT:
842 bRet = ( nObjIdentifier == SdrObjKind::OLE2 );
843 break;
844 case ScContentId::DRAWING:
845 bRet = ( nObjIdentifier != SdrObjKind::Graphic && nObjIdentifier != SdrObjKind::OLE2 ); // everything else
846 break;
847 default:
848 OSL_FAIL("unknown content type");
850 return bRet;
853 constexpr int MAX_TREE_NODES = 1000;
855 void ScContentTree::GetDrawNames( ScContentId nType )
857 if (!bIsInNavigatorDlg)
858 return;
860 if ( nRootType != ScContentId::ROOT && nRootType != nType ) // hidden ?
861 return;
863 ScDocument* pDoc = GetSourceDocument();
864 if (!pDoc)
865 return;
867 ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
868 if (!pDrawLayer)
869 return;
871 ScDocShell* pShell = pDoc->GetDocumentShell();
872 if (!pShell)
873 return;
875 // iterate in flat mode for groups
876 SdrIterMode eIter = ( nType == ScContentId::DRAWING ) ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups;
878 std::vector<OUString> aNames;
879 SCTAB nTabCount = pDoc->GetTableCount();
880 for (SCTAB nTab=0; nTab<nTabCount; nTab++)
882 SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
883 OSL_ENSURE(pPage,"Page ?");
884 if (!pPage)
885 continue;
886 SdrObjListIter aIter(pPage, eIter);
887 SdrObject* pObject = aIter.Next();
888 while (pObject)
890 if (IsPartOfType(nType, pObject->GetObjIdentifier()))
892 OUString aName = ScDrawLayer::GetVisibleName(pObject);
893 if (!aName.isEmpty())
894 aNames.push_back(aName);
895 if (aNames.size() > MAX_TREE_NODES)
897 SAL_WARN("sc", "too many tree nodes, ignoring the rest");
898 break;
901 pObject = aIter.Next();
905 weld::TreeIter* pParent = m_aRootNodes[nType].get();
906 assert(pParent && "InsertContent without parent");
907 // insert all of these in one go under pParent
908 m_xTreeView->bulk_insert_for_each(aNames.size(), [this, &aNames](weld::TreeIter& rIter, int nIndex) {
909 m_xTreeView->set_text(rIter, aNames[nIndex], 0);
910 m_xTreeView->set_sensitive(rIter, true);
911 }, pParent);
914 void ScContentTree::GetGraphicNames()
916 GetDrawNames( ScContentId::GRAPHIC );
919 void ScContentTree::GetOleNames()
921 GetDrawNames( ScContentId::OLEOBJECT );
924 void ScContentTree::GetDrawingNames()
926 GetDrawNames( ScContentId::DRAWING );
929 void ScContentTree::GetLinkNames()
931 if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::AREALINK ) // hidden ?
932 return;
934 ScDocument* pDoc = GetSourceDocument();
935 if (!pDoc)
936 return;
938 sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager();
939 assert(pLinkManager && "no LinkManager on document?");
940 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
941 sal_uInt16 nCount = rLinks.size();
942 for (sal_uInt16 i=0; i<nCount; i++)
944 ::sfx2::SvBaseLink* pBase = rLinks[i].get();
945 if (auto pScAreaLink = dynamic_cast<const ScAreaLink*>( pBase))
946 InsertContent( ScContentId::AREALINK, pScAreaLink->GetSource() );
948 // insert in list the names of source areas
952 const ScAreaLink* ScContentTree::GetLink( sal_uLong nIndex )
954 ScDocument* pDoc = GetSourceDocument();
955 if (!pDoc)
956 return nullptr;
958 sal_uLong nFound = 0;
959 sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager();
960 assert(pLinkManager && "no LinkManager on document?");
961 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
962 sal_uInt16 nCount = rLinks.size();
963 for (sal_uInt16 i=0; i<nCount; i++)
965 ::sfx2::SvBaseLink* pBase = rLinks[i].get();
966 if (auto pAreaLink = dynamic_cast<const ScAreaLink*>( pBase))
968 if (nFound == nIndex)
969 return pAreaLink;
970 ++nFound;
974 OSL_FAIL("link not found");
975 return nullptr;
978 static OUString lcl_NoteString( const ScPostIt& rNote )
980 return rNote.GetText().replace('\n', ' ');
983 void ScContentTree::GetNoteStrings()
985 if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::NOTE ) // hidden ?
986 return;
988 ScDocument* pDoc = GetSourceDocument();
989 if (!pDoc)
990 return;
992 // loop over cell notes
993 std::vector<sc::NoteEntry> aEntries;
994 pDoc->GetAllNoteEntries(aEntries);
995 weld::TreeIter* pParent = m_aRootNodes[ScContentId::NOTE].get();
996 for (const auto& rEntry : aEntries)
998 OUString aValue = lcl_NoteString(*rEntry.mpNote);
999 m_xTreeView->insert(pParent, -1, &aValue, nullptr, nullptr, nullptr, false, m_xScratchIter.get());
1000 m_xTreeView->set_sensitive(*m_xScratchIter, true);
1004 ScAddress ScContentTree::GetNotePos( sal_uLong nIndex )
1006 ScDocument* pDoc = GetSourceDocument();
1007 if (!pDoc)
1008 return ScAddress();
1010 return pDoc->GetNotePosition(nIndex);
1013 bool ScContentTree::NoteStringsChanged()
1015 ScDocument* pDoc = GetSourceDocument();
1016 if (!pDoc)
1017 return false;
1019 weld::TreeIter* pParent = m_aRootNodes[ScContentId::NOTE].get();
1020 if (!pParent)
1021 return false;
1023 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pParent));
1024 bool bEntry = m_xTreeView->iter_children(*xEntry);
1026 std::vector<sc::NoteEntry> aEntries;
1027 pDoc->GetAllNoteEntries(aEntries);
1028 for (const auto& rEntry : aEntries)
1030 const ScPostIt* pNote = rEntry.mpNote;
1031 if (!bEntry)
1032 return true;
1034 if (lcl_NoteString(*pNote) != m_xTreeView->get_text(*xEntry))
1035 return true;
1037 bEntry = m_xTreeView->iter_next_sibling(*xEntry);
1040 return bEntry;
1043 bool ScContentTree::DrawNamesChanged( ScContentId nType )
1045 ScDocument* pDoc = GetSourceDocument();
1046 if (!pDoc)
1047 return false;
1049 weld::TreeIter* pParent = m_aRootNodes[nType].get();
1050 if (!pParent)
1051 return false;
1053 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pParent));
1054 bool bEntry = m_xTreeView->iter_children(*xEntry);
1056 // iterate in flat mode for groups
1057 SdrIterMode eIter = ( nType == ScContentId::DRAWING ) ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups;
1059 bool bEqual = true;
1060 ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
1061 ScDocShell* pShell = pDoc->GetDocumentShell();
1062 if (pDrawLayer && pShell)
1064 SCTAB nTabCount = pDoc->GetTableCount();
1065 for (SCTAB nTab=0; nTab<nTabCount && bEqual; nTab++)
1067 SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
1068 OSL_ENSURE(pPage,"Page ?");
1069 if (pPage)
1071 SdrObjListIter aIter( pPage, eIter );
1072 SdrObject* pObject = aIter.Next();
1073 while (pObject && bEqual)
1075 if ( IsPartOfType( nType, pObject->GetObjIdentifier() ) )
1077 if ( !bEntry )
1078 bEqual = false;
1079 else
1081 if (ScDrawLayer::GetVisibleName(pObject) != m_xTreeView->get_text(*xEntry))
1082 bEqual = false;
1084 bEntry = m_xTreeView->iter_next_sibling(*xEntry);
1087 pObject = aIter.Next();
1093 if ( bEntry )
1094 bEqual = false; // anything else
1096 return !bEqual;
1099 static bool lcl_GetRange( const ScDocument& rDoc, ScContentId nType, const OUString& rName, ScRange& rRange )
1101 bool bFound = false;
1103 if ( nType == ScContentId::RANGENAME )
1105 ScRangeName* pList = rDoc.GetRangeName();
1106 if (pList)
1108 const ScRangeData* p = pList->findByUpperName(ScGlobal::getCharClass().uppercase(rName));
1109 if (p && p->IsValidReference(rRange))
1110 bFound = true;
1113 else if ( nType == ScContentId::DBAREA )
1115 ScDBCollection* pList = rDoc.GetDBCollection();
1116 if (pList)
1118 const ScDBData* p = pList->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rName));
1119 if (p)
1121 SCTAB nTab;
1122 SCCOL nCol1, nCol2;
1123 SCROW nRow1, nRow2;
1124 p->GetArea(nTab, nCol1, nRow1, nCol2, nRow2);
1125 rRange = ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
1126 bFound = true;
1131 return bFound;
1134 static bool lcl_DoDragObject( ScDocShell* pSrcShell, std::u16string_view rName, ScContentId nType, weld::TreeView& rTreeView )
1136 bool bDisallow = true;
1138 ScDocument& rSrcDoc = pSrcShell->GetDocument();
1139 ScDrawLayer* pModel = rSrcDoc.GetDrawLayer();
1140 if (pModel)
1142 bool bOle = ( nType == ScContentId::OLEOBJECT );
1143 bool bGraf = ( nType == ScContentId::GRAPHIC );
1144 SdrObjKind nDrawId = bOle ? SdrObjKind::OLE2 : ( bGraf ? SdrObjKind::Graphic : SdrObjKind::Group );
1145 SCTAB nTab = 0;
1146 SdrObject* pObject = pModel->GetNamedObject( rName, nDrawId, nTab );
1147 if (pObject)
1149 SdrView aEditView(*pModel);
1150 aEditView.ShowSdrPage(aEditView.GetModel().GetPage(nTab));
1151 SdrPageView* pPV = aEditView.GetSdrPageView();
1152 aEditView.MarkObj(pObject, pPV);
1154 // tdf125520 this is a D&D-start potentially with an OLE object. If
1155 // so, we need to do similar as e.g. in ScDrawView::BeginDrag so that
1156 // the temporary SdrModel for transfer does have a GetPersist() so
1157 // that the EmbeddedObjectContainer gets copied. We need no CheckOle
1158 // here, test is simpler.
1159 ScDocShellRef aDragShellRef;
1160 if(SdrObjKind::OLE2 == pObject->GetObjIdentifier())
1162 aDragShellRef = new ScDocShell; // DocShell needs a Ref immediately
1163 aDragShellRef->DoInitNew();
1166 ScDrawLayer::SetGlobalDrawPersist(aDragShellRef.get());
1167 std::unique_ptr<SdrModel> pDragModel(aEditView.CreateMarkedObjModel());
1168 ScDrawLayer::SetGlobalDrawPersist(nullptr);
1170 TransferableObjectDescriptor aObjDesc;
1171 pSrcShell->FillTransferableObjectDescriptor( aObjDesc );
1172 aObjDesc.maDisplayName = pSrcShell->GetMedium()->GetURLObject().GetURLNoPass();
1173 // maSize is set in ScDrawTransferObj ctor
1175 rtl::Reference<ScDrawTransferObj> pTransferObj = new ScDrawTransferObj( std::move(pDragModel), pSrcShell, std::move(aObjDesc) );
1177 pTransferObj->SetDragSourceObj( *pObject, nTab );
1178 pTransferObj->SetDragSourceFlags(ScDragSrc::Navigator);
1180 ScModule::get()->SetDragObject(nullptr, pTransferObj.get());
1182 rtl::Reference<TransferDataContainer> xHelper(pTransferObj);
1183 rTreeView.enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
1185 bDisallow = false;
1189 return bDisallow;
1192 static bool lcl_DoDragCells( ScDocShell* pSrcShell, const ScRange& rRange, ScDragSrc nFlags, weld::TreeView& rTreeView )
1194 bool bDisallow = true;
1196 ScDocument& rSrcDoc = pSrcShell->GetDocument();
1197 ScMarkData aMark(rSrcDoc.GetSheetLimits());
1198 aMark.SelectTable( rRange.aStart.Tab(), true );
1199 aMark.SetMarkArea( rRange );
1201 if ( !rSrcDoc.HasSelectedBlockMatrixFragment( rRange.aStart.Col(), rRange.aStart.Row(),
1202 rRange.aEnd.Col(), rRange.aEnd.Row(),
1203 aMark ) )
1205 ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
1206 ScClipParam aClipParam(rRange, false);
1207 rSrcDoc.CopyToClip(aClipParam, pClipDoc.get(), &aMark, false, false);
1208 // pClipDoc->ExtendMerge( rRange, sal_True );
1210 TransferableObjectDescriptor aObjDesc;
1211 pSrcShell->FillTransferableObjectDescriptor( aObjDesc );
1212 aObjDesc.maDisplayName = pSrcShell->GetMedium()->GetURLObject().GetURLNoPass();
1213 // maSize is set in ScTransferObj ctor
1215 rtl::Reference<ScTransferObj> pTransferObj = new ScTransferObj( std::move(pClipDoc), std::move(aObjDesc) );
1217 pTransferObj->SetDragSource( pSrcShell, aMark );
1218 pTransferObj->SetDragSourceFlags( nFlags );
1220 ScModule::get()->SetDragObject(pTransferObj.get(), nullptr); // for internal D&D
1222 rtl::Reference<TransferDataContainer> xHelper(pTransferObj);
1223 rTreeView.enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
1225 bDisallow = false;
1228 return bDisallow;
1231 IMPL_LINK(ScContentTree, DragBeginHdl, bool&, rUnsetDragIcon, bool)
1233 rUnsetDragIcon = true;
1235 StoreNavigatorSettings();
1237 bool bDisallow = true;
1239 ScModule* pScMod = ScModule::get();
1241 ScContentId nType;
1242 sal_uLong nChild;
1244 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
1245 if (!m_xTreeView->get_cursor(xEntry.get()))
1246 xEntry.reset();
1248 GetEntryIndexes(nType, nChild, xEntry.get());
1250 if( xEntry &&
1251 (nChild != SC_CONTENT_NOCHILD) &&
1252 (nType != ScContentId::ROOT) &&
1253 (nType != ScContentId::NOTE) &&
1254 (nType != ScContentId::AREALINK) )
1256 OUString aText(m_xTreeView->get_text(*xEntry));
1258 ScDocument* pLocalDoc = nullptr; // for URL drop
1259 OUString aDocName;
1260 ScDocShell* pDocSh = GetManualOrCurrent();
1261 if (pDocSh)
1263 if (pDocSh->HasName())
1264 aDocName = pDocSh->GetMedium()->GetName();
1265 else
1266 pLocalDoc = &pDocSh->GetDocument(); // drop only in this document
1269 bool bDoLinkTrans = false; // use ScLinkTransferObj
1270 OUString aLinkURL; // for ScLinkTransferObj
1271 OUString aLinkText;
1273 sal_uInt16 nDropMode = pParentWindow->GetDropMode();
1274 switch ( nDropMode )
1276 case SC_DROPMODE_URL:
1278 OUString aUrl = aDocName + "#" + aText;
1280 pScMod->SetDragJump( pLocalDoc, aUrl, aText );
1282 if (!aDocName.isEmpty())
1284 // provide URL to outside only if the document has a name
1285 // (without name, only internal D&D via SetDragJump)
1287 aLinkURL = aUrl;
1288 aLinkText = aText;
1290 bDoLinkTrans = true;
1292 break;
1293 case SC_DROPMODE_LINK:
1295 if ( !aDocName.isEmpty() ) // link only to named documents
1297 // for internal D&D, set flag to insert a link
1299 switch ( nType )
1301 case ScContentId::TABLE:
1302 pScMod->SetDragLink( aDocName, aText, OUString() );
1303 bDoLinkTrans = true;
1304 break;
1305 case ScContentId::RANGENAME:
1306 case ScContentId::DBAREA:
1307 pScMod->SetDragLink( aDocName, OUString(), aText );
1308 bDoLinkTrans = true;
1309 break;
1311 // other types cannot be linked
1312 default: break;
1316 break;
1317 case SC_DROPMODE_COPY:
1319 ScDocShell* pSrcShell = GetManualOrCurrent();
1320 if ( pSrcShell )
1322 ScDocument& rSrcDoc = pSrcShell->GetDocument();
1323 if ( nType == ScContentId::RANGENAME || nType == ScContentId::DBAREA )
1325 ScRange aRange;
1326 if ( lcl_GetRange( rSrcDoc, nType, aText, aRange ) )
1328 bDisallow = lcl_DoDragCells( pSrcShell, aRange, ScDragSrc::Navigator, *m_xTreeView );
1331 else if ( nType == ScContentId::TABLE )
1333 SCTAB nTab;
1334 if ( rSrcDoc.GetTable( aText, nTab ) )
1336 ScRange aRange(0, 0, nTab, rSrcDoc.MaxCol(), rSrcDoc.MaxRow(), nTab);
1337 bDisallow = lcl_DoDragCells( pSrcShell, aRange, (ScDragSrc::Navigator | ScDragSrc::Table), *m_xTreeView );
1340 else if ( nType == ScContentId::GRAPHIC || nType == ScContentId::OLEOBJECT ||
1341 nType == ScContentId::DRAWING )
1343 bDisallow = lcl_DoDragObject( pSrcShell, aText, nType, *m_xTreeView );
1345 // during ExecuteDrag the navigator can be deleted
1346 // -> don't access member anymore !!!
1350 break;
1353 if (bDoLinkTrans)
1355 if (!aLinkURL.isEmpty())
1356 m_xTransferObj->SetLinkURL(aLinkURL, aLinkText);
1358 rtl::Reference<TransferDataContainer> xHelper(m_xTransferObj);
1359 m_xTreeView->enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
1361 bDisallow = false;
1365 return bDisallow;
1368 void ScContentTree::SetRootType( ScContentId nNew )
1370 if ( nNew != nRootType )
1372 nRootType = nNew;
1373 Refresh();
1375 ScNavipiCfg& rCfg = ScModule::get()->GetNavipiCfg();
1376 rCfg.SetRootType( nRootType );
1380 void ScContentTree::ToggleRoot() // after selection
1382 ScContentId nNew = ScContentId::ROOT;
1383 if ( nRootType == ScContentId::ROOT )
1385 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
1386 if (m_xTreeView->get_cursor(xEntry.get()))
1388 std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(xEntry.get()));
1389 if (!m_xTreeView->iter_parent(*xParent))
1390 xParent.reset();
1392 for (sal_uInt16 i=1; i<=int(ScContentId::LAST); i++)
1394 if (!m_aRootNodes[static_cast<ScContentId>(i)])
1395 continue;
1396 if ((m_xTreeView->iter_compare(*xEntry, *m_aRootNodes[static_cast<ScContentId>(i)]) == 0) ||
1397 (xParent && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[static_cast<ScContentId>(i)]) == 0))
1399 nNew = static_cast<ScContentId>(i);
1405 SetRootType( nNew );
1408 void ScContentTree::ResetManualDoc()
1410 aManualDoc.clear();
1412 ActiveDocChanged();
1415 bool ScContentTree::ActiveDocChanged()
1417 bool bRefreshed = false;
1419 if (aManualDoc.isEmpty())
1421 Refresh(); // content only if automatic
1422 bRefreshed = true;
1425 // if flag active Listbox must be updated
1427 OUString aCurrent;
1429 ScDocShell* pSh = GetManualOrCurrent();
1430 if (pSh)
1431 aCurrent = pSh->GetTitle();
1432 else
1434 // document is no longer available
1436 aManualDoc.clear(); // again automatically
1437 Refresh();
1438 bRefreshed = true;
1439 pSh = GetManualOrCurrent(); // should be active now
1440 if (pSh)
1441 aCurrent = pSh->GetTitle();
1444 pParentWindow->GetDocNames( &aCurrent ); // select
1446 return bRefreshed;
1449 void ScContentTree::SetManualDoc(const OUString& rName)
1451 aManualDoc = rName;
1452 Refresh();
1453 pParentWindow->GetDocNames( &aManualDoc ); // select
1456 void ScContentTree::SelectDoc(const OUString& rName) // rName like shown in Menu/Listbox
1458 if ( rName == pParentWindow->aStrActiveWin )
1460 ResetManualDoc();
1461 return;
1464 // omit "active" or "inactive"
1466 OUString aRealName = rName;
1467 sal_Int32 nLen = rName.getLength();
1468 sal_Int32 nActiveStart = nLen - pParentWindow->aStrActive.getLength();
1469 if ( rName.subView( nActiveStart ) == pParentWindow->aStrActive )
1470 aRealName = rName.copy( 0, nActiveStart );
1471 sal_Int32 nNotActiveStart = nLen - pParentWindow->aStrNotActive.getLength();
1472 if ( rName.subView( nNotActiveStart ) == pParentWindow->aStrNotActive )
1473 aRealName = rName.copy( 0, nNotActiveStart );
1475 bool bLoaded = false;
1477 // Is it a normally loaded document?
1479 SfxObjectShell* pSh = SfxObjectShell::GetFirst();
1480 while ( pSh && !bLoaded )
1482 if ( dynamic_cast<const ScDocShell*>( pSh) != nullptr )
1483 if ( pSh->GetTitle() == aRealName )
1484 bLoaded = true;
1485 pSh = SfxObjectShell::GetNext( *pSh );
1488 if (bLoaded)
1490 SetManualDoc(aRealName);
1492 else
1494 OSL_FAIL("SelectDoc: not found");
1498 void ScContentTree::SelectEntryByName(const ScContentId nRoot, std::u16string_view rName)
1500 weld::TreeIter* pParent = m_aRootNodes[nRoot].get();
1502 if (!pParent || !m_xTreeView->iter_has_child(*pParent))
1503 return;
1505 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pParent));
1506 bool bEntry = m_xTreeView->iter_children(*xEntry);
1508 while (bEntry)
1510 if (m_xTreeView->get_text(*xEntry) == rName)
1512 m_xTreeView->select(*xEntry);
1513 m_xTreeView->set_cursor(*xEntry);
1515 // Scroll to the selected item
1516 m_xTreeView->scroll_to_row(*xEntry);
1518 StoreNavigatorSettings();
1520 return;
1522 bEntry = m_xTreeView->iter_next(*xEntry);
1526 void ScContentTree::ApplyNavigatorSettings()
1528 const ScNavigatorSettings* pSettings = ScNavigatorDlg::GetNavigatorSettings();
1529 if( !pSettings )
1530 return;
1532 ScContentId nRootSel = pSettings->GetRootSelected();
1533 auto nChildSel = pSettings->GetChildSelected();
1535 // tdf#133079 ensure Sheet root is selected if nothing
1536 // else would be
1537 if (nRootSel == ScContentId::ROOT)
1539 nRootSel = ScContentId::TABLE;
1540 nChildSel = SC_CONTENT_NOCHILD;
1543 for( int i = 1; i <= int(ScContentId::LAST); ++i )
1545 ScContentId nEntry = static_cast<ScContentId>(i);
1546 if( m_aRootNodes[ nEntry ] )
1548 // gray or ungray
1549 if (!m_xTreeView->iter_has_child(*m_aRootNodes[nEntry]))
1550 m_xTreeView->set_sensitive(*m_aRootNodes[nEntry], false);
1551 else
1552 m_xTreeView->set_sensitive(*m_aRootNodes[nEntry], true);
1554 // expand
1555 bool bExp = pSettings->IsExpanded( nEntry );
1556 if (bExp != m_xTreeView->get_row_expanded(*m_aRootNodes[nEntry]))
1558 if( bExp )
1559 m_xTreeView->expand_row(*m_aRootNodes[nEntry]);
1560 else
1561 m_xTreeView->collapse_row(*m_aRootNodes[nEntry]);
1564 // select
1565 if( nRootSel == nEntry )
1567 std::unique_ptr<weld::TreeIter> xEntry;
1568 if (bExp && (nChildSel != SC_CONTENT_NOCHILD))
1570 xEntry = m_xTreeView->make_iterator(m_aRootNodes[nEntry].get());
1571 if (!m_xTreeView->iter_children(*xEntry) || !m_xTreeView->iter_nth_sibling(*xEntry, nChildSel))
1572 xEntry.reset();
1574 m_xTreeView->select(xEntry ? *xEntry : *m_aRootNodes[nEntry]);
1575 m_xTreeView->set_cursor(xEntry ? *xEntry : *m_aRootNodes[nEntry]);
1581 void ScContentTree::StoreNavigatorSettings()
1583 if (m_nAsyncMouseReleaseId)
1585 Application::RemoveUserEvent(m_nAsyncMouseReleaseId);
1586 m_nAsyncMouseReleaseId = nullptr;
1589 ScNavigatorSettings* pSettings = ScNavigatorDlg::GetNavigatorSettings();
1590 if( !pSettings )
1591 return;
1593 for( int i = 1; i <= int(ScContentId::LAST); ++i )
1595 ScContentId nEntry = static_cast<ScContentId>(i);
1596 bool bExp = m_aRootNodes[nEntry] && m_xTreeView->get_row_expanded(*m_aRootNodes[nEntry]);
1597 pSettings->SetExpanded( nEntry, bExp );
1600 std::unique_ptr<weld::TreeIter> xCurEntry(m_xTreeView->make_iterator());
1601 if (!m_xTreeView->get_cursor(xCurEntry.get()))
1602 xCurEntry.reset();
1604 ScContentId nRoot;
1605 sal_uLong nChild;
1606 GetEntryIndexes(nRoot, nChild, xCurEntry.get());
1608 pSettings->SetRootSelected( nRoot );
1609 pSettings->SetChildSelected( nChild );
1612 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */