summaryrefslogtreecommitdiffstats
path: root/sc/source/ui/navipi/content.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/ui/navipi/content.cxx')
-rw-r--r--sc/source/ui/navipi/content.cxx1637
1 files changed, 1637 insertions, 0 deletions
diff --git a/sc/source/ui/navipi/content.cxx b/sc/source/ui/navipi/content.cxx
new file mode 100644
index 000000000..2c8336fd3
--- /dev/null
+++ b/sc/source/ui/navipi/content.cxx
@@ -0,0 +1,1637 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <svx/svditer.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdview.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/diagnose.h>
+#include <tools/urlobj.hxx>
+#include <sal/log.hxx>
+#include <unotools/charclass.hxx>
+
+#include <content.hxx>
+#include <navipi.hxx>
+#include <global.hxx>
+#include <docsh.hxx>
+#include <scmod.hxx>
+#include <rangenam.hxx>
+#include <dbdata.hxx>
+#include <tablink.hxx>
+#include <drwlayer.hxx>
+#include <transobj.hxx>
+#include <drwtrans.hxx>
+#include <lnktrans.hxx>
+#include <strings.hrc>
+#include <scresid.hxx>
+#include <bitmaps.hlst>
+#include <arealink.hxx>
+#include <navicfg.hxx>
+#include <navsett.hxx>
+#include <postit.hxx>
+#include <tabvwsh.hxx>
+#include <drawview.hxx>
+#include <clipparam.hxx>
+#include <markdata.hxx>
+
+using namespace com::sun::star;
+
+// order of the categories in navigator -------------------------------------
+
+const ScContentId pTypeList[int(ScContentId::LAST) + 1] =
+{
+ ScContentId::ROOT, // ROOT (0) has to be at the front
+ ScContentId::TABLE,
+ ScContentId::RANGENAME,
+ ScContentId::DBAREA,
+ ScContentId::AREALINK,
+ ScContentId::GRAPHIC,
+ ScContentId::OLEOBJECT,
+ ScContentId::NOTE,
+ ScContentId::DRAWING
+};
+
+constexpr rtl::OUStringConstExpr aContentBmps[]=
+{
+ RID_BMP_CONTENT_TABLE,
+ RID_BMP_CONTENT_RANGENAME,
+ RID_BMP_CONTENT_DBAREA,
+ RID_BMP_CONTENT_GRAPHIC,
+ RID_BMP_CONTENT_OLEOBJECT,
+ RID_BMP_CONTENT_NOTE,
+ RID_BMP_CONTENT_AREALINK,
+ RID_BMP_CONTENT_DRAWING
+};
+
+ScDocShell* ScContentTree::GetManualOrCurrent()
+{
+ ScDocShell* pSh = nullptr;
+ if ( !aManualDoc.isEmpty() )
+ {
+ SfxObjectShell* pObjSh = SfxObjectShell::GetFirst( checkSfxObjectShell<ScDocShell> );
+ while ( pObjSh && !pSh )
+ {
+ if ( pObjSh->GetTitle() == aManualDoc )
+ pSh = dynamic_cast<ScDocShell*>( pObjSh );
+ pObjSh = SfxObjectShell::GetNext( *pObjSh, checkSfxObjectShell<ScDocShell> );
+ }
+ }
+ else
+ {
+ // only current when manual isn't set
+ // (so it's detected when the documents don't exists any longer)
+
+ SfxViewShell* pViewSh = SfxViewShell::Current();
+ if ( pViewSh )
+ {
+ SfxObjectShell* pObjSh = pViewSh->GetViewFrame()->GetObjectShell();
+ pSh = dynamic_cast<ScDocShell*>( pObjSh );
+ }
+ }
+
+ return pSh;
+}
+
+// ScContentTree
+
+ScContentTree::ScContentTree(std::unique_ptr<weld::TreeView> xTreeView, ScNavigatorDlg* pNavigatorDlg)
+ : m_xTreeView(std::move(xTreeView))
+ , m_xScratchIter(m_xTreeView->make_iterator())
+ , m_xTransferObj(new ScLinkTransferObj)
+ , pParentWindow(pNavigatorDlg)
+ , nRootType(ScContentId::ROOT)
+ , bHiddenDoc(false)
+ , pHiddenDocument(nullptr)
+ , bIsInNavigatorDlg(false)
+ , m_bFreeze(false)
+ , m_nAsyncMouseReleaseId(nullptr)
+{
+ for (sal_uInt16 i = 0; i <= int(ScContentId::LAST); ++i)
+ pPosList[pTypeList[i]] = i; // inverse for searching
+
+ m_aRootNodes[ScContentId::ROOT] = nullptr;
+ for (sal_uInt16 i = 1; i < int(ScContentId::LAST); ++i)
+ InitRoot(static_cast<ScContentId>(i));
+
+ m_xTreeView->connect_row_activated(LINK(this, ScContentTree, ContentDoubleClickHdl));
+ m_xTreeView->connect_mouse_release(LINK(this, ScContentTree, MouseReleaseHdl));
+ m_xTreeView->connect_key_press(LINK(this, ScContentTree, KeyInputHdl));
+ m_xTreeView->connect_popup_menu(LINK(this, ScContentTree, CommandHdl));
+ m_xTreeView->connect_query_tooltip(LINK(this, ScContentTree, QueryTooltipHdl));
+
+ rtl::Reference<TransferDataContainer> xHelper(m_xTransferObj);
+ m_xTreeView->enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
+
+ m_xTreeView->connect_drag_begin(LINK(this, ScContentTree, DragBeginHdl));
+
+ m_xTreeView->set_selection_mode( SelectionMode::Single );
+
+ m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 30,
+ m_xTreeView->get_text_height() * 13);
+}
+
+ScContentTree::~ScContentTree()
+{
+ if (m_nAsyncMouseReleaseId)
+ {
+ Application::RemoveUserEvent(m_nAsyncMouseReleaseId);
+ m_nAsyncMouseReleaseId = nullptr;
+ }
+}
+
+const TranslateId SCSTR_CONTENT_ARY[] =
+{
+ SCSTR_CONTENT_ROOT,
+ SCSTR_CONTENT_TABLE,
+ SCSTR_CONTENT_RANGENAME,
+ SCSTR_CONTENT_DBAREA,
+ SCSTR_CONTENT_GRAPHIC,
+ SCSTR_CONTENT_OLEOBJECT,
+ SCSTR_CONTENT_NOTE,
+ SCSTR_CONTENT_AREALINK,
+ SCSTR_CONTENT_DRAWING
+};
+
+void ScContentTree::InitRoot( ScContentId nType )
+{
+ if ( nType == ScContentId::ROOT )
+ return;
+
+ if ( nRootType != ScContentId::ROOT && nRootType != nType ) // hidden ?
+ {
+ m_aRootNodes[nType] = nullptr;
+ return;
+ }
+
+ auto const aImage(aContentBmps[static_cast<int>(nType) - 1]);
+ OUString aName(ScResId(SCSTR_CONTENT_ARY[static_cast<int>(nType)]));
+ // back to the correct position:
+ sal_uInt16 nPos = nRootType != ScContentId::ROOT ? 0 : pPosList[nType]-1;
+ m_aRootNodes[nType] = m_xTreeView->make_iterator();
+ m_xTreeView->insert(nullptr, nPos, &aName, nullptr, nullptr, nullptr, false, m_aRootNodes[nType].get());
+ m_xTreeView->set_image(*m_aRootNodes[nType], OUString(aImage));
+}
+
+void ScContentTree::ClearAll()
+{
+ //There are one method in Control::SetUpdateMode(), and one override method SvTreeListBox::SetUpdateMode(). Here although
+ //SvTreeListBox::SetUpdateMode() is called in refresh method, it only call SvTreeListBox::SetUpdateMode(), not Control::SetUpdateMode().
+ //In m_xTreeView->clear(), Broadcast( LISTACTION_CLEARED ) will be called and finally, it will be trapped into the event yield() loop. And
+ //the InitRoot() method won't be called. Then if a user click or press key to update the navigator tree, crash happens.
+ //So the solution is to disable the UpdateMode of Control, then call Clear(), then recover the update mode
+ bool bWasFrozen = m_bFreeze;
+ if (!bWasFrozen)
+ freeze();
+ m_xTreeView->clear();
+ if (!bWasFrozen)
+ thaw();
+ for (sal_uInt16 i=1; i<=int(ScContentId::LAST); i++)
+ InitRoot(static_cast<ScContentId>(i));
+}
+
+void ScContentTree::ClearType(ScContentId nType)
+{
+ if (nType == ScContentId::ROOT)
+ ClearAll();
+ else
+ {
+ weld::TreeIter* pParent = m_aRootNodes[nType].get();
+ if (!pParent || m_xTreeView->iter_has_child(*pParent)) // not if no children existing
+ {
+ if (pParent)
+ m_xTreeView->remove(*pParent); // with all children
+ InitRoot( nType ); // if needed insert anew
+ }
+ }
+}
+
+void ScContentTree::InsertContent( ScContentId nType, const OUString& rValue )
+{
+ weld::TreeIter* pParent = m_aRootNodes[nType].get();
+ if (pParent)
+ {
+ m_xTreeView->insert(pParent, -1, &rValue, nullptr, nullptr, nullptr, false, m_xScratchIter.get());
+ m_xTreeView->set_sensitive(*m_xScratchIter, true);
+ }
+ else
+ {
+ OSL_FAIL("InsertContent without parent");
+ }
+}
+
+void ScContentTree::GetEntryIndexes(ScContentId& rnRootIndex, sal_uLong& rnChildIndex, const weld::TreeIter* pEntry) const
+{
+ rnRootIndex = ScContentId::ROOT;
+ rnChildIndex = SC_CONTENT_NOCHILD;
+
+ if( !pEntry )
+ return;
+
+ std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(pEntry));
+ if (!m_xTreeView->iter_parent(*xParent))
+ xParent.reset();
+ bool bFound = false;
+ for( int i = 1; !bFound && (i <= int(ScContentId::LAST)); ++i )
+ {
+ ScContentId nRoot = static_cast<ScContentId>(i);
+ if (!m_aRootNodes[nRoot])
+ continue;
+ if (m_xTreeView->iter_compare(*pEntry, *m_aRootNodes[nRoot]) == 0)
+ {
+ rnRootIndex = nRoot;
+ rnChildIndex = ~0UL;
+ bFound = true;
+ }
+ else if (xParent && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[nRoot]) == 0)
+ {
+ rnRootIndex = nRoot;
+
+ // search the entry in all child entries of the parent
+ sal_uLong nEntry = 0;
+ std::unique_ptr<weld::TreeIter> xIterEntry(m_xTreeView->make_iterator(xParent.get()));
+ bool bIterEntry = m_xTreeView->iter_children(*xIterEntry);
+ while (!bFound && bIterEntry)
+ {
+ if (m_xTreeView->iter_compare(*pEntry, *xIterEntry) == 0)
+ {
+ rnChildIndex = nEntry;
+ bFound = true; // exit the while loop
+ }
+ bIterEntry = m_xTreeView->iter_next_sibling(*xIterEntry);
+ ++nEntry;
+ }
+
+ bFound = true; // exit the for loop
+ }
+ }
+}
+
+sal_uLong ScContentTree::GetChildIndex(const weld::TreeIter* pEntry) const
+{
+ ScContentId nRoot;
+ sal_uLong nChild;
+ GetEntryIndexes(nRoot, nChild, pEntry);
+ return nChild;
+}
+
+static OUString lcl_GetDBAreaRange( const ScDocument* pDoc, const OUString& rDBName )
+{
+ OUString aRet;
+ if (pDoc)
+ {
+ ScDBCollection* pDbNames = pDoc->GetDBCollection();
+ const ScDBData* pData = pDbNames->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rDBName));
+ if (pData)
+ {
+ ScRange aRange;
+ pData->GetArea(aRange);
+ aRet = aRange.Format(*pDoc, ScRefFlags::RANGE_ABS_3D);
+ }
+ }
+ return aRet;
+}
+
+IMPL_LINK_NOARG(ScContentTree, ContentDoubleClickHdl, weld::TreeView&, bool)
+{
+ ScContentId nType;
+ sal_uLong nChild;
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_cursor(xEntry.get()))
+ xEntry.reset();
+ GetEntryIndexes(nType, nChild, xEntry.get());
+
+ if (xEntry && (nType != ScContentId::ROOT) && (nChild != SC_CONTENT_NOCHILD))
+ {
+ if ( bHiddenDoc )
+ return false; //! later...
+
+ OUString aText(m_xTreeView->get_text(*xEntry));
+
+ if ( !aManualDoc.isEmpty() )
+ pParentWindow->SetCurrentDoc( aManualDoc );
+
+ switch( nType )
+ {
+ case ScContentId::TABLE:
+ {
+ // tdf#133159 store current config before changing sheet
+ // plausible that this should be done for all cases, but this
+ // is the known case that needs it
+ StoreNavigatorSettings();
+ pParentWindow->SetCurrentTableStr( aText );
+ }
+ break;
+
+ case ScContentId::RANGENAME:
+ pParentWindow->SetCurrentCellStr( aText );
+ break;
+
+ case ScContentId::DBAREA:
+ {
+ // If the same names of area and DB exists, then
+ // SID_CURRENTCELL takes the area name.
+ // Therefore for DB areas access them directly via address.
+
+ OUString aRangeStr = lcl_GetDBAreaRange( GetSourceDocument(), aText );
+ if (!aRangeStr.isEmpty())
+ pParentWindow->SetCurrentCellStr( aRangeStr );
+ }
+ break;
+
+ case ScContentId::OLEOBJECT:
+ case ScContentId::GRAPHIC:
+ case ScContentId::DRAWING:
+ pParentWindow->SetCurrentObject( aText );
+ break;
+
+ case ScContentId::NOTE:
+ {
+ ScAddress aPos = GetNotePos( nChild );
+ pParentWindow->SetCurrentTable( aPos.Tab() );
+ pParentWindow->SetCurrentCell( aPos.Col(), aPos.Row() );
+ }
+ break;
+
+ case ScContentId::AREALINK:
+ {
+ const ScAreaLink* pLink = GetLink(nChild);
+ ScDocument* pSrcDoc = GetSourceDocument();
+ if (pLink && pSrcDoc)
+ {
+ const ScRange& aRange = pLink->GetDestArea();
+ OUString aRangeStr(aRange.Format(*pSrcDoc, ScRefFlags::RANGE_ABS_3D, pSrcDoc->GetAddressConvention()));
+ pParentWindow->SetCurrentCellStr( aRangeStr );
+ }
+ }
+ break;
+ default: break;
+ }
+
+ ScNavigatorDlg::ReleaseFocus(); // set focus into document
+ }
+
+ return false;
+}
+
+void ScContentTree::LaunchAsyncStoreNavigatorSettings()
+{
+ if (!m_nAsyncMouseReleaseId)
+ m_nAsyncMouseReleaseId = Application::PostUserEvent(LINK(this, ScContentTree, AsyncStoreNavigatorSettings));
+}
+
+IMPL_LINK_NOARG(ScContentTree, MouseReleaseHdl, const MouseEvent&, bool)
+{
+ LaunchAsyncStoreNavigatorSettings();
+ return false;
+}
+
+IMPL_LINK_NOARG(ScContentTree, AsyncStoreNavigatorSettings, void*, void)
+{
+ m_nAsyncMouseReleaseId = nullptr;
+ StoreNavigatorSettings();
+}
+
+IMPL_LINK(ScContentTree, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ bool bUsed = false;
+
+ const vcl::KeyCode aCode = rKEvt.GetKeyCode();
+ if (aCode.GetCode() == KEY_RETURN)
+ {
+ switch (aCode.GetModifier())
+ {
+ case KEY_MOD1:
+ ToggleRoot(); // toggle root mode (as in Writer)
+ bUsed = true;
+ break;
+ case 0:
+ {
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_cursor(xEntry.get()))
+ xEntry.reset();
+ if (xEntry)
+ {
+ ScContentId nType;
+ sal_uLong nChild;
+ GetEntryIndexes(nType, nChild, xEntry.get());
+
+ if (nType != ScContentId::ROOT && nChild == SC_CONTENT_NOCHILD)
+ {
+ if (m_xTreeView->get_row_expanded(*xEntry))
+ m_xTreeView->collapse_row(*xEntry);
+ else
+ m_xTreeView->expand_row(*xEntry);
+ }
+ else
+ ContentDoubleClickHdl(*m_xTreeView); // select content as if double clicked
+ }
+
+ bUsed = true;
+ }
+ break;
+ }
+ }
+ //Make KEY_SPACE has same function as DoubleClick, and realize
+ //multi-selection.
+ if ( bIsInNavigatorDlg )
+ {
+ if(aCode.GetCode() == KEY_SPACE )
+ {
+ bUsed = true;
+ ScContentId nType;
+ sal_uLong nChild;
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_cursor(xEntry.get()))
+ xEntry.reset();
+ GetEntryIndexes(nType, nChild, xEntry.get());
+
+ if (xEntry && (nType != ScContentId::ROOT) && (nChild != SC_CONTENT_NOCHILD))
+ {
+ if ( bHiddenDoc )
+ return true; //! later...
+ OUString aText(m_xTreeView->get_text(*xEntry));
+ if (!aManualDoc.isEmpty())
+ pParentWindow->SetCurrentDoc( aManualDoc );
+ switch (nType)
+ {
+ case ScContentId::OLEOBJECT:
+ case ScContentId::GRAPHIC:
+ case ScContentId::DRAWING:
+ {
+ ScDrawView* pScDrawView = nullptr;
+ ScTabViewShell* pScTabViewShell = ScNavigatorDlg::GetTabViewShell();
+ if (pScTabViewShell)
+ pScDrawView = pScTabViewShell->GetViewData().GetScDrawView();
+ if (pScDrawView)
+ {
+ pScDrawView->SelectCurrentViewObject(aText);
+ bool bHasMakredObject = false;
+ weld::TreeIter* pParent = m_aRootNodes[nType].get();
+ std::unique_ptr<weld::TreeIter> xBeginEntry(m_xTreeView->make_iterator(pParent));
+ bool bBeginEntry = false;
+ if (pParent)
+ bBeginEntry = m_xTreeView->iter_children(*xBeginEntry);
+ while (bBeginEntry)
+ {
+ OUString aTempText(m_xTreeView->get_text(*xBeginEntry));
+ if( pScDrawView->GetObjectIsMarked( pScDrawView->GetObjectByName( aTempText ) ) )
+ {
+ bHasMakredObject = true;
+ break;
+ }
+ bBeginEntry = m_xTreeView->iter_next(*xBeginEntry);
+ }
+ if (!bHasMakredObject && pScTabViewShell)
+ pScTabViewShell->SetDrawShell(false);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (!bUsed)
+ {
+ if (aCode.GetCode() == KEY_F5)
+ StoreNavigatorSettings();
+ else
+ LaunchAsyncStoreNavigatorSettings();
+ }
+
+ return bUsed;
+}
+
+IMPL_LINK(ScContentTree, CommandHdl, const CommandEvent&, rCEvt, bool)
+{
+ bool bDone = false;
+
+ switch ( rCEvt.GetCommand() )
+ {
+ case CommandEventId::ContextMenu:
+ {
+ // drag-and-drop mode
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), "modules/scalc/ui/dropmenu.ui"));
+ std::unique_ptr<weld::Menu> xPop(xBuilder->weld_menu("contextmenu"));
+ std::unique_ptr<weld::Menu> xDropMenu(xBuilder->weld_menu("dragmodesubmenu"));
+
+ switch (pParentWindow->GetDropMode())
+ {
+ case 0:
+ xDropMenu->set_active("hyperlink", true);
+ break;
+ case 1:
+ xDropMenu->set_active("link", true);
+ break;
+ case 2:
+ xDropMenu->set_active("copy", true);
+ break;
+ }
+
+ // displayed document
+ std::unique_ptr<weld::Menu> xDocMenu(xBuilder->weld_menu("displaymenu"));
+ sal_uInt16 i=0;
+ OUString sActive;
+ OUString sId;
+ // loaded documents
+ ScDocShell* pCurrentSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
+ SfxObjectShell* pSh = SfxObjectShell::GetFirst();
+ while ( pSh )
+ {
+ if ( dynamic_cast<const ScDocShell*>( pSh) != nullptr )
+ {
+ OUString aName = pSh->GetTitle();
+ OUString aEntry = aName;
+ if ( pSh == pCurrentSh )
+ aEntry += pParentWindow->aStrActive;
+ else
+ aEntry += pParentWindow->aStrNotActive;
+ ++i;
+ sId = "document" + OUString::number(i);
+ xDocMenu->append_radio(sId, aEntry);
+ if ( !bHiddenDoc && aName == aManualDoc )
+ sActive = sId;
+ }
+ pSh = SfxObjectShell::GetNext( *pSh );
+ }
+ // "active window"
+ ++i;
+ sId = "document" + OUString::number(i);
+ xDocMenu->append_radio(sId, pParentWindow->aStrActiveWin);
+ if (!bHiddenDoc && aManualDoc.isEmpty())
+ sActive = sId;
+ // hidden document
+ if ( !aHiddenTitle.isEmpty() )
+ {
+ OUString aEntry = aHiddenTitle + pParentWindow->aStrHidden;
+ ++i;
+ sId = "document" + OUString::number(i);
+ xDocMenu->append_radio(sId, aEntry);
+ if (bHiddenDoc)
+ sActive = sId;
+ }
+ xDocMenu->set_active(sActive.toUtf8(), true);
+
+ OString sIdent = xPop->popup_at_rect(m_xTreeView.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1)));
+ if (sIdent == "hyperlink")
+ pParentWindow->SetDropMode(0);
+ else if (sIdent == "link")
+ pParentWindow->SetDropMode(1);
+ else if (sIdent == "copy")
+ pParentWindow->SetDropMode(2);
+ else if (sIdent.startsWith("document"))
+ {
+ OUString aName = xDocMenu->get_label(sIdent);
+ SelectDoc(aName);
+ }
+ }
+ break;
+ default: break;
+ }
+
+ return bDone;
+}
+
+IMPL_LINK(ScContentTree, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUString)
+{
+ OUString aHelpText;
+
+ std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rEntry));
+ if (!m_xTreeView->iter_parent(*xParent))
+ xParent.reset();
+
+ if (!xParent) // Top-Level ?
+ {
+ aHelpText = OUString::number(m_xTreeView->iter_n_children(rEntry)) +
+ " " + m_xTreeView->get_text(rEntry);
+ }
+ else if (m_aRootNodes[ScContentId::NOTE] && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[ScContentId::NOTE]) == 0)
+ {
+ aHelpText = m_xTreeView->get_text(rEntry); // notes as help text
+ }
+ else if (m_aRootNodes[ScContentId::AREALINK] && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[ScContentId::AREALINK]) == 0)
+ {
+ auto nIndex = GetChildIndex(&rEntry);
+ if (nIndex != SC_CONTENT_NOCHILD)
+ {
+ const ScAreaLink* pLink = GetLink(nIndex);
+ if (pLink)
+ {
+ aHelpText = pLink->GetFile(); // source file as help text
+ }
+ }
+ }
+
+ return aHelpText;
+}
+
+ScDocument* ScContentTree::GetSourceDocument()
+{
+ if (bHiddenDoc)
+ return pHiddenDocument;
+ else
+ {
+ ScDocShell* pSh = GetManualOrCurrent();
+ if (pSh)
+ return &pSh->GetDocument();
+
+ }
+ return nullptr;
+}
+
+void ScContentTree::Refresh( ScContentId nType )
+{
+ if ( bHiddenDoc && !pHiddenDocument )
+ return; // other document displayed
+
+ // if nothing has changed the cancel right away (against flicker)
+
+ if ( nType == ScContentId::NOTE )
+ if (!NoteStringsChanged())
+ return;
+ if ( nType == ScContentId::GRAPHIC )
+ if (!DrawNamesChanged(ScContentId::GRAPHIC))
+ return;
+ if ( nType == ScContentId::OLEOBJECT )
+ if (!DrawNamesChanged(ScContentId::OLEOBJECT))
+ return;
+ if ( nType == ScContentId::DRAWING )
+ if (!DrawNamesChanged(ScContentId::DRAWING))
+ return;
+
+ freeze();
+
+ ClearType( nType );
+
+ if ( nType == ScContentId::ROOT || nType == ScContentId::TABLE )
+ GetTableNames();
+ if ( nType == ScContentId::ROOT || nType == ScContentId::RANGENAME )
+ GetAreaNames();
+ if ( nType == ScContentId::ROOT || nType == ScContentId::DBAREA )
+ GetDbNames();
+ if ( nType == ScContentId::ROOT || nType == ScContentId::GRAPHIC )
+ GetGraphicNames();
+ if ( nType == ScContentId::ROOT || nType == ScContentId::OLEOBJECT )
+ GetOleNames();
+ if ( nType == ScContentId::ROOT || nType == ScContentId::DRAWING )
+ GetDrawingNames();
+ if ( nType == ScContentId::ROOT || nType == ScContentId::NOTE )
+ GetNoteStrings();
+ if ( nType == ScContentId::ROOT || nType == ScContentId::AREALINK )
+ GetLinkNames();
+
+ thaw();
+
+ ApplyNavigatorSettings();
+}
+
+void ScContentTree::GetTableNames()
+{
+ if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::TABLE ) // hidden ?
+ return;
+
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return;
+
+ OUString aName;
+ SCTAB nCount = pDoc->GetTableCount();
+ for ( SCTAB i=0; i<nCount; i++ )
+ {
+ pDoc->GetName( i, aName );
+ InsertContent( ScContentId::TABLE, aName );
+ }
+}
+
+namespace {
+
+OUString createLocalRangeName(std::u16string_view rName, std::u16string_view rTableName)
+{
+ return OUString::Concat(rName) + " (" + rTableName + ")";
+}
+}
+
+void ScContentTree::GetAreaNames()
+{
+ if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::RANGENAME ) // hidden ?
+ return;
+
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return;
+
+ ScRange aDummy;
+ std::set<OUString> aSet;
+ ScRangeName* pRangeNames = pDoc->GetRangeName();
+ for (const auto& rEntry : *pRangeNames)
+ {
+ if (rEntry.second->IsValidReference(aDummy))
+ aSet.insert(rEntry.second->GetName());
+ }
+ for (SCTAB i = 0; i < pDoc->GetTableCount(); ++i)
+ {
+ ScRangeName* pLocalRangeName = pDoc->GetRangeName(i);
+ if (pLocalRangeName && !pLocalRangeName->empty())
+ {
+ OUString aTableName;
+ pDoc->GetName(i, aTableName);
+ for (const auto& rEntry : *pLocalRangeName)
+ {
+ if (rEntry.second->IsValidReference(aDummy))
+ aSet.insert(createLocalRangeName(rEntry.second->GetName(), aTableName));
+ }
+ }
+ }
+
+ for (const auto& rItem : aSet)
+ {
+ InsertContent(ScContentId::RANGENAME, rItem);
+ }
+}
+
+void ScContentTree::GetDbNames()
+{
+ if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::DBAREA ) // hidden ?
+ return;
+
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return;
+
+ ScDBCollection* pDbNames = pDoc->GetDBCollection();
+ const ScDBCollection::NamedDBs& rDBs = pDbNames->getNamedDBs();
+ for (const auto& rxDB : rDBs)
+ {
+ const OUString& aStrName = rxDB->GetName();
+ InsertContent(ScContentId::DBAREA, aStrName);
+ }
+}
+
+bool ScContentTree::IsPartOfType( ScContentId nContentType, SdrObjKind nObjIdentifier )
+{
+ bool bRet = false;
+ switch ( nContentType )
+ {
+ case ScContentId::GRAPHIC:
+ bRet = ( nObjIdentifier == SdrObjKind::Graphic );
+ break;
+ case ScContentId::OLEOBJECT:
+ bRet = ( nObjIdentifier == SdrObjKind::OLE2 );
+ break;
+ case ScContentId::DRAWING:
+ bRet = ( nObjIdentifier != SdrObjKind::Graphic && nObjIdentifier != SdrObjKind::OLE2 ); // everything else
+ break;
+ default:
+ OSL_FAIL("unknown content type");
+ }
+ return bRet;
+}
+
+constexpr int MAX_TREE_NODES = 1000;
+
+void ScContentTree::GetDrawNames( ScContentId nType )
+{
+ if (!bIsInNavigatorDlg)
+ return;
+
+ if ( nRootType != ScContentId::ROOT && nRootType != nType ) // hidden ?
+ return;
+
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return;
+
+ ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
+ if (!pDrawLayer)
+ return;
+
+ SfxObjectShell* pShell = pDoc->GetDocumentShell();
+ if (!pShell)
+ return;
+
+ // iterate in flat mode for groups
+ SdrIterMode eIter = ( nType == ScContentId::DRAWING ) ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups;
+
+ std::vector<OUString> aNames;
+ SCTAB nTabCount = pDoc->GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ OSL_ENSURE(pPage,"Page ?");
+ if (!pPage)
+ continue;
+ SdrObjListIter aIter(pPage, eIter);
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if (IsPartOfType(nType, pObject->GetObjIdentifier()))
+ {
+ OUString aName = ScDrawLayer::GetVisibleName(pObject);
+ if (!aName.isEmpty())
+ aNames.push_back(aName);
+ if (aNames.size() > MAX_TREE_NODES)
+ {
+ SAL_WARN("sc", "too many tree nodes, ignoring the rest");
+ break;
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+
+ weld::TreeIter* pParent = m_aRootNodes[nType].get();
+ assert(pParent && "InsertContent without parent");
+ // insert all of these in one go under pParent
+ m_xTreeView->bulk_insert_for_each(aNames.size(), [this, &aNames](weld::TreeIter& rIter, int nIndex) {
+ m_xTreeView->set_text(rIter, aNames[nIndex], 0);
+ m_xTreeView->set_sensitive(rIter, true);
+ }, pParent);
+}
+
+void ScContentTree::GetGraphicNames()
+{
+ GetDrawNames( ScContentId::GRAPHIC );
+}
+
+void ScContentTree::GetOleNames()
+{
+ GetDrawNames( ScContentId::OLEOBJECT );
+}
+
+void ScContentTree::GetDrawingNames()
+{
+ GetDrawNames( ScContentId::DRAWING );
+}
+
+void ScContentTree::GetLinkNames()
+{
+ if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::AREALINK ) // hidden ?
+ return;
+
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return;
+
+ sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager();
+ OSL_ENSURE(pLinkManager, "no LinkManager on document?");
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.size();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = rLinks[i].get();
+ if (auto pScAreaLink = dynamic_cast<const ScAreaLink*>( pBase))
+ InsertContent( ScContentId::AREALINK, pScAreaLink->GetSource() );
+
+ // insert in list the names of source areas
+ }
+}
+
+const ScAreaLink* ScContentTree::GetLink( sal_uLong nIndex )
+{
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return nullptr;
+
+ sal_uLong nFound = 0;
+ sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager();
+ OSL_ENSURE(pLinkManager, "no LinkManager on document?");
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.size();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = rLinks[i].get();
+ if (auto pAreaLink = dynamic_cast<const ScAreaLink*>( pBase))
+ {
+ if (nFound == nIndex)
+ return pAreaLink;
+ ++nFound;
+ }
+ }
+
+ OSL_FAIL("link not found");
+ return nullptr;
+}
+
+static OUString lcl_NoteString( const ScPostIt& rNote )
+{
+ OUString aText = rNote.GetText();
+ sal_Int32 nAt;
+ while ( (nAt = aText.indexOf( '\n' )) != -1 )
+ aText = aText.replaceAt( nAt, 1, u" " );
+ return aText;
+}
+
+void ScContentTree::GetNoteStrings()
+{
+ if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::NOTE ) // hidden ?
+ return;
+
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return;
+
+ // loop over cell notes
+ std::vector<sc::NoteEntry> aEntries;
+ pDoc->GetAllNoteEntries(aEntries);
+ weld::TreeIter* pParent = m_aRootNodes[ScContentId::NOTE].get();
+ for (const auto& rEntry : aEntries)
+ {
+ OUString aValue = lcl_NoteString(*rEntry.mpNote);
+ m_xTreeView->insert(pParent, -1, &aValue, nullptr, nullptr, nullptr, false, m_xScratchIter.get());
+ m_xTreeView->set_sensitive(*m_xScratchIter, true);
+ }
+}
+
+ScAddress ScContentTree::GetNotePos( sal_uLong nIndex )
+{
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return ScAddress();
+
+ return pDoc->GetNotePosition(nIndex);
+}
+
+bool ScContentTree::NoteStringsChanged()
+{
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return false;
+
+ weld::TreeIter* pParent = m_aRootNodes[ScContentId::NOTE].get();
+ if (!pParent)
+ return false;
+
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pParent));
+ bool bEntry = m_xTreeView->iter_children(*xEntry);
+
+ std::vector<sc::NoteEntry> aEntries;
+ pDoc->GetAllNoteEntries(aEntries);
+ for (const auto& rEntry : aEntries)
+ {
+ const ScPostIt* pNote = rEntry.mpNote;
+ if (!bEntry)
+ return true;
+
+ if (lcl_NoteString(*pNote) != m_xTreeView->get_text(*xEntry))
+ return true;
+
+ bEntry = m_xTreeView->iter_next_sibling(*xEntry);
+ }
+
+ return bEntry;
+}
+
+bool ScContentTree::DrawNamesChanged( ScContentId nType )
+{
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return false;
+
+ weld::TreeIter* pParent = m_aRootNodes[nType].get();
+ if (!pParent)
+ return false;
+
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pParent));
+ bool bEntry = m_xTreeView->iter_children(*xEntry);
+
+ // iterate in flat mode for groups
+ SdrIterMode eIter = ( nType == ScContentId::DRAWING ) ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups;
+
+ bool bEqual = true;
+ ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
+ SfxObjectShell* pShell = pDoc->GetDocumentShell();
+ if (pDrawLayer && pShell)
+ {
+ SCTAB nTabCount = pDoc->GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount && bEqual; nTab++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ OSL_ENSURE(pPage,"Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, eIter );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && bEqual)
+ {
+ if ( IsPartOfType( nType, pObject->GetObjIdentifier() ) )
+ {
+ if ( !bEntry )
+ bEqual = false;
+ else
+ {
+ if (ScDrawLayer::GetVisibleName(pObject) != m_xTreeView->get_text(*xEntry))
+ bEqual = false;
+
+ bEntry = m_xTreeView->iter_next_sibling(*xEntry);
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+ }
+
+ if ( bEntry )
+ bEqual = false; // anything else
+
+ return !bEqual;
+}
+
+static bool lcl_GetRange( const ScDocument& rDoc, ScContentId nType, const OUString& rName, ScRange& rRange )
+{
+ bool bFound = false;
+
+ if ( nType == ScContentId::RANGENAME )
+ {
+ ScRangeName* pList = rDoc.GetRangeName();
+ if (pList)
+ {
+ const ScRangeData* p = pList->findByUpperName(ScGlobal::getCharClass().uppercase(rName));
+ if (p && p->IsValidReference(rRange))
+ bFound = true;
+ }
+ }
+ else if ( nType == ScContentId::DBAREA )
+ {
+ ScDBCollection* pList = rDoc.GetDBCollection();
+ if (pList)
+ {
+ const ScDBData* p = pList->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rName));
+ if (p)
+ {
+ SCTAB nTab;
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ p->GetArea(nTab, nCol1, nRow1, nCol2, nRow2);
+ rRange = ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
+ bFound = true;
+ }
+ }
+ }
+
+ return bFound;
+}
+
+static bool lcl_DoDragObject( ScDocShell* pSrcShell, std::u16string_view rName, ScContentId nType, weld::TreeView& rTreeView )
+{
+ bool bDisallow = true;
+
+ ScDocument& rSrcDoc = pSrcShell->GetDocument();
+ ScDrawLayer* pModel = rSrcDoc.GetDrawLayer();
+ if (pModel)
+ {
+ bool bOle = ( nType == ScContentId::OLEOBJECT );
+ bool bGraf = ( nType == ScContentId::GRAPHIC );
+ SdrObjKind nDrawId = bOle ? SdrObjKind::OLE2 : ( bGraf ? SdrObjKind::Graphic : SdrObjKind::Group );
+ SCTAB nTab = 0;
+ SdrObject* pObject = pModel->GetNamedObject( rName, nDrawId, nTab );
+ if (pObject)
+ {
+ SdrView aEditView(*pModel);
+ aEditView.ShowSdrPage(aEditView.GetModel()->GetPage(nTab));
+ SdrPageView* pPV = aEditView.GetSdrPageView();
+ aEditView.MarkObj(pObject, pPV);
+
+ // tdf125520 this is a D&D-start potentially with an OLE object. If
+ // so, we need to do similar as e.g. in ScDrawView::BeginDrag so that
+ // the temporary SdrModel for transfer does have a GetPersist() so
+ // that the EmbeddedObjectContainer gets copied. We need no CheckOle
+ // here, test is simpler.
+ ScDocShellRef aDragShellRef;
+ if(SdrObjKind::OLE2 == pObject->GetObjIdentifier())
+ {
+ aDragShellRef = new ScDocShell; // DocShell needs a Ref immediately
+ aDragShellRef->DoInitNew();
+ }
+
+ ScDrawLayer::SetGlobalDrawPersist(aDragShellRef.get());
+ std::unique_ptr<SdrModel> pDragModel(aEditView.CreateMarkedObjModel());
+ ScDrawLayer::SetGlobalDrawPersist(nullptr);
+
+ TransferableObjectDescriptor aObjDesc;
+ pSrcShell->FillTransferableObjectDescriptor( aObjDesc );
+ aObjDesc.maDisplayName = pSrcShell->GetMedium()->GetURLObject().GetURLNoPass();
+ // maSize is set in ScDrawTransferObj ctor
+
+ rtl::Reference<ScDrawTransferObj> pTransferObj = new ScDrawTransferObj( std::move(pDragModel), pSrcShell, aObjDesc );
+
+ pTransferObj->SetDragSourceObj( *pObject, nTab );
+ pTransferObj->SetDragSourceFlags(ScDragSrc::Navigator);
+
+ SC_MOD()->SetDragObject( nullptr, pTransferObj.get() );
+
+ rtl::Reference<TransferDataContainer> xHelper(pTransferObj);
+ rTreeView.enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
+
+ bDisallow = false;
+ }
+ }
+
+ return bDisallow;
+}
+
+static bool lcl_DoDragCells( ScDocShell* pSrcShell, const ScRange& rRange, ScDragSrc nFlags, weld::TreeView& rTreeView )
+{
+ bool bDisallow = true;
+
+ ScDocument& rSrcDoc = pSrcShell->GetDocument();
+ ScMarkData aMark(rSrcDoc.GetSheetLimits());
+ aMark.SelectTable( rRange.aStart.Tab(), true );
+ aMark.SetMarkArea( rRange );
+
+ if ( !rSrcDoc.HasSelectedBlockMatrixFragment( rRange.aStart.Col(), rRange.aStart.Row(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(),
+ aMark ) )
+ {
+ ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
+ ScClipParam aClipParam(rRange, false);
+ rSrcDoc.CopyToClip(aClipParam, pClipDoc.get(), &aMark, false, false);
+ // pClipDoc->ExtendMerge( rRange, sal_True );
+
+ TransferableObjectDescriptor aObjDesc;
+ pSrcShell->FillTransferableObjectDescriptor( aObjDesc );
+ aObjDesc.maDisplayName = pSrcShell->GetMedium()->GetURLObject().GetURLNoPass();
+ // maSize is set in ScTransferObj ctor
+
+ rtl::Reference<ScTransferObj> pTransferObj = new ScTransferObj( std::move(pClipDoc), aObjDesc );
+
+ pTransferObj->SetDragSource( pSrcShell, aMark );
+ pTransferObj->SetDragSourceFlags( nFlags );
+
+ SC_MOD()->SetDragObject( pTransferObj.get(), nullptr ); // for internal D&D
+
+ rtl::Reference<TransferDataContainer> xHelper(pTransferObj);
+ rTreeView.enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
+
+ bDisallow = false;
+ }
+
+ return bDisallow;
+}
+
+IMPL_LINK(ScContentTree, DragBeginHdl, bool&, rUnsetDragIcon, bool)
+{
+ rUnsetDragIcon = true;
+
+ StoreNavigatorSettings();
+
+ bool bDisallow = true;
+
+ std::unique_ptr<ScDocumentLoader> pDocLoader;
+
+ ScModule* pScMod = SC_MOD();
+
+ ScContentId nType;
+ sal_uLong nChild;
+
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_cursor(xEntry.get()))
+ xEntry.reset();
+
+ GetEntryIndexes(nType, nChild, xEntry.get());
+
+ if( xEntry &&
+ (nChild != SC_CONTENT_NOCHILD) &&
+ (nType != ScContentId::ROOT) &&
+ (nType != ScContentId::NOTE) &&
+ (nType != ScContentId::AREALINK) )
+ {
+ OUString aText(m_xTreeView->get_text(*xEntry));
+
+ ScDocument* pLocalDoc = nullptr; // for URL drop
+ OUString aDocName;
+ if (bHiddenDoc)
+ aDocName = aHiddenName;
+ else
+ {
+ ScDocShell* pDocSh = GetManualOrCurrent();
+ if (pDocSh)
+ {
+ if (pDocSh->HasName())
+ aDocName = pDocSh->GetMedium()->GetName();
+ else
+ pLocalDoc = &pDocSh->GetDocument(); // drop only in this document
+ }
+ }
+
+ bool bDoLinkTrans = false; // use ScLinkTransferObj
+ OUString aLinkURL; // for ScLinkTransferObj
+ OUString aLinkText;
+
+ sal_uInt16 nDropMode = pParentWindow->GetDropMode();
+ switch ( nDropMode )
+ {
+ case SC_DROPMODE_URL:
+ {
+ OUString aUrl = aDocName + "#" + aText;
+
+ pScMod->SetDragJump( pLocalDoc, aUrl, aText );
+
+ if (!aDocName.isEmpty())
+ {
+ // provide URL to outside only if the document has a name
+ // (without name, only internal D&D via SetDragJump)
+
+ aLinkURL = aUrl;
+ aLinkText = aText;
+ }
+ bDoLinkTrans = true;
+ }
+ break;
+ case SC_DROPMODE_LINK:
+ {
+ if ( !aDocName.isEmpty() ) // link only to named documents
+ {
+ // for internal D&D, set flag to insert a link
+
+ switch ( nType )
+ {
+ case ScContentId::TABLE:
+ pScMod->SetDragLink( aDocName, aText, OUString() );
+ bDoLinkTrans = true;
+ break;
+ case ScContentId::RANGENAME:
+ case ScContentId::DBAREA:
+ pScMod->SetDragLink( aDocName, OUString(), aText );
+ bDoLinkTrans = true;
+ break;
+
+ // other types cannot be linked
+ default: break;
+ }
+ }
+ }
+ break;
+ case SC_DROPMODE_COPY:
+ {
+ ScDocShell* pSrcShell = nullptr;
+ if ( bHiddenDoc )
+ {
+ OUString aFilter, aOptions;
+ OUString aURL = aHiddenName;
+ pDocLoader.reset(new ScDocumentLoader( aURL, aFilter, aOptions ));
+ if (!pDocLoader->IsError())
+ pSrcShell = pDocLoader->GetDocShell();
+ }
+ else
+ pSrcShell = GetManualOrCurrent();
+
+ if ( pSrcShell )
+ {
+ ScDocument& rSrcDoc = pSrcShell->GetDocument();
+ if ( nType == ScContentId::RANGENAME || nType == ScContentId::DBAREA )
+ {
+ ScRange aRange;
+ if ( lcl_GetRange( rSrcDoc, nType, aText, aRange ) )
+ {
+ bDisallow = lcl_DoDragCells( pSrcShell, aRange, ScDragSrc::Navigator, *m_xTreeView );
+ }
+ }
+ else if ( nType == ScContentId::TABLE )
+ {
+ SCTAB nTab;
+ if ( rSrcDoc.GetTable( aText, nTab ) )
+ {
+ ScRange aRange(0, 0, nTab, rSrcDoc.MaxCol(), rSrcDoc.MaxRow(), nTab);
+ bDisallow = lcl_DoDragCells( pSrcShell, aRange, (ScDragSrc::Navigator | ScDragSrc::Table), *m_xTreeView );
+ }
+ }
+ else if ( nType == ScContentId::GRAPHIC || nType == ScContentId::OLEOBJECT ||
+ nType == ScContentId::DRAWING )
+ {
+ bDisallow = lcl_DoDragObject( pSrcShell, aText, nType, *m_xTreeView );
+
+ // during ExecuteDrag the navigator can be deleted
+ // -> don't access member anymore !!!
+ }
+ }
+ }
+ break;
+ }
+
+ if (bDoLinkTrans)
+ {
+ if (!aLinkURL.isEmpty())
+ m_xTransferObj->SetLinkURL(aLinkURL, aLinkText);
+
+ rtl::Reference<TransferDataContainer> xHelper(m_xTransferObj);
+ m_xTreeView->enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
+
+ bDisallow = false;
+ }
+ }
+
+ return bDisallow;
+}
+
+void ScContentTree::LoadFile( const OUString& rUrl )
+{
+ OUString aDocName = rUrl;
+ sal_Int32 nPos = aDocName.indexOf('#');
+ if ( nPos != -1 )
+ aDocName = aDocName.copy(0, nPos); // only the name without #...
+
+ OUString aURL = aDocName;
+ OUString aFilter, aOptions;
+ ScDocumentLoader aLoader( aURL, aFilter, aOptions );
+ if ( aLoader.IsError() )
+ return;
+
+ bHiddenDoc = true;
+ aHiddenName = aDocName;
+ aHiddenTitle = aLoader.GetTitle();
+ pHiddenDocument = aLoader.GetDocument();
+
+ Refresh(); // get content from loaded document
+
+ pHiddenDocument = nullptr;
+
+ pParentWindow->GetDocNames( &aHiddenTitle ); // fill list
+
+ // document is closed again by ScDocumentLoader in dtor
+}
+
+void ScContentTree::SetRootType( ScContentId nNew )
+{
+ if ( nNew != nRootType )
+ {
+ nRootType = nNew;
+ Refresh();
+
+ ScNavipiCfg& rCfg = SC_MOD()->GetNavipiCfg();
+ rCfg.SetRootType( nRootType );
+ }
+}
+
+void ScContentTree::ToggleRoot() // after selection
+{
+ ScContentId nNew = ScContentId::ROOT;
+ if ( nRootType == ScContentId::ROOT )
+ {
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+ if (m_xTreeView->get_cursor(xEntry.get()))
+ {
+ std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(xEntry.get()));
+ if (!m_xTreeView->iter_parent(*xParent))
+ xParent.reset();
+
+ for (sal_uInt16 i=1; i<=int(ScContentId::LAST); i++)
+ {
+ if (!m_aRootNodes[static_cast<ScContentId>(i)])
+ continue;
+ if ((m_xTreeView->iter_compare(*xEntry, *m_aRootNodes[static_cast<ScContentId>(i)]) == 0) ||
+ (xParent && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[static_cast<ScContentId>(i)]) == 0))
+ {
+ nNew = static_cast<ScContentId>(i);
+ }
+ }
+ }
+ }
+
+ SetRootType( nNew );
+}
+
+void ScContentTree::ResetManualDoc()
+{
+ aManualDoc.clear();
+ bHiddenDoc = false;
+
+ ActiveDocChanged();
+}
+
+bool ScContentTree::ActiveDocChanged()
+{
+ bool bRefreshed = false;
+
+ if ( !bHiddenDoc && aManualDoc.isEmpty() )
+ {
+ Refresh(); // content only if automatic
+ bRefreshed = true;
+ }
+
+ // if flag active Listbox must be updated
+
+ OUString aCurrent;
+ if ( bHiddenDoc )
+ aCurrent = aHiddenTitle;
+ else
+ {
+ ScDocShell* pSh = GetManualOrCurrent();
+ if (pSh)
+ aCurrent = pSh->GetTitle();
+ else
+ {
+ // document is no longer available
+
+ aManualDoc.clear(); // again automatically
+ Refresh();
+ bRefreshed = true;
+ pSh = GetManualOrCurrent(); // should be active now
+ if (pSh)
+ aCurrent = pSh->GetTitle();
+ }
+ }
+ pParentWindow->GetDocNames( &aCurrent ); // select
+
+ return bRefreshed;
+}
+
+void ScContentTree::SetManualDoc(const OUString& rName)
+{
+ aManualDoc = rName;
+ if (!bHiddenDoc)
+ {
+ Refresh();
+ pParentWindow->GetDocNames( &aManualDoc ); // select
+ }
+}
+
+void ScContentTree::SelectDoc(const OUString& rName) // rName like shown in Menu/Listbox
+{
+ if ( rName == pParentWindow->aStrActiveWin )
+ {
+ ResetManualDoc();
+ return;
+ }
+
+ // omit "active" or "inactive"
+
+ OUString aRealName = rName;
+ sal_Int32 nLen = rName.getLength();
+ sal_Int32 nActiveStart = nLen - pParentWindow->aStrActive.getLength();
+ if ( rName.subView( nActiveStart ) == pParentWindow->aStrActive )
+ aRealName = rName.copy( 0, nActiveStart );
+ sal_Int32 nNotActiveStart = nLen - pParentWindow->aStrNotActive.getLength();
+ if ( rName.subView( nNotActiveStart ) == pParentWindow->aStrNotActive )
+ aRealName = rName.copy( 0, nNotActiveStart );
+
+ bool bLoaded = false;
+
+ // Is it a normally loaded document?
+
+ SfxObjectShell* pSh = SfxObjectShell::GetFirst();
+ while ( pSh && !bLoaded )
+ {
+ if ( dynamic_cast<const ScDocShell*>( pSh) != nullptr )
+ if ( pSh->GetTitle() == aRealName )
+ bLoaded = true;
+ pSh = SfxObjectShell::GetNext( *pSh );
+ }
+
+ if (bLoaded)
+ {
+ bHiddenDoc = false;
+ SetManualDoc(aRealName);
+ }
+ else if (!aHiddenTitle.isEmpty()) // hidden selected
+ {
+ if (!bHiddenDoc)
+ LoadFile(aHiddenName);
+ }
+ else
+ {
+ OSL_FAIL("SelectDoc: not found");
+ }
+}
+
+void ScContentTree::SelectEntryByName(const ScContentId nRoot, std::u16string_view rName)
+{
+ weld::TreeIter* pParent = m_aRootNodes[nRoot].get();
+
+ if (pParent || !m_xTreeView->iter_has_child(*pParent))
+ return;
+
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pParent));
+ bool bEntry = m_xTreeView->iter_children(*xEntry);
+
+ while (bEntry)
+ {
+ if (m_xTreeView->get_text(*xEntry) == rName)
+ {
+ m_xTreeView->select(*xEntry);
+ m_xTreeView->set_cursor(*xEntry);
+
+ // Scroll to the selected item
+ m_xTreeView->scroll_to_row(*xEntry);
+
+ StoreNavigatorSettings();
+
+ return;
+ }
+ bEntry = m_xTreeView->iter_next(*xEntry);
+ }
+}
+
+void ScContentTree::ApplyNavigatorSettings()
+{
+ const ScNavigatorSettings* pSettings = ScNavigatorDlg::GetNavigatorSettings();
+ if( !pSettings )
+ return;
+
+ ScContentId nRootSel = pSettings->GetRootSelected();
+ auto nChildSel = pSettings->GetChildSelected();
+
+ // tdf#133079 ensure Sheet root is selected if nothing
+ // else would be
+ if (nRootSel == ScContentId::ROOT)
+ {
+ nRootSel = ScContentId::TABLE;
+ nChildSel = SC_CONTENT_NOCHILD;
+ }
+
+ for( int i = 1; i <= int(ScContentId::LAST); ++i )
+ {
+ ScContentId nEntry = static_cast<ScContentId>(i);
+ if( m_aRootNodes[ nEntry ] )
+ {
+ // gray or ungray
+ if (!m_xTreeView->iter_has_child(*m_aRootNodes[nEntry]))
+ m_xTreeView->set_sensitive(*m_aRootNodes[nEntry], false);
+ else
+ m_xTreeView->set_sensitive(*m_aRootNodes[nEntry], true);
+
+ // expand
+ bool bExp = pSettings->IsExpanded( nEntry );
+ if (bExp != m_xTreeView->get_row_expanded(*m_aRootNodes[nEntry]))
+ {
+ if( bExp )
+ m_xTreeView->expand_row(*m_aRootNodes[nEntry]);
+ else
+ m_xTreeView->collapse_row(*m_aRootNodes[nEntry]);
+ }
+
+ // select
+ if( nRootSel == nEntry )
+ {
+ std::unique_ptr<weld::TreeIter> xEntry;
+ if (bExp && (nChildSel != SC_CONTENT_NOCHILD))
+ {
+ xEntry = m_xTreeView->make_iterator(m_aRootNodes[nEntry].get());
+ if (!m_xTreeView->iter_children(*xEntry) || !m_xTreeView->iter_nth_sibling(*xEntry, nChildSel))
+ xEntry.reset();
+ }
+ m_xTreeView->select(xEntry ? *xEntry : *m_aRootNodes[nEntry]);
+ m_xTreeView->set_cursor(xEntry ? *xEntry : *m_aRootNodes[nEntry]);
+ }
+ }
+ }
+}
+
+void ScContentTree::StoreNavigatorSettings()
+{
+ if (m_nAsyncMouseReleaseId)
+ {
+ Application::RemoveUserEvent(m_nAsyncMouseReleaseId);
+ m_nAsyncMouseReleaseId = nullptr;
+ }
+
+ ScNavigatorSettings* pSettings = ScNavigatorDlg::GetNavigatorSettings();
+ if( !pSettings )
+ return;
+
+ for( int i = 1; i <= int(ScContentId::LAST); ++i )
+ {
+ ScContentId nEntry = static_cast<ScContentId>(i);
+ bool bExp = m_aRootNodes[nEntry] && m_xTreeView->get_row_expanded(*m_aRootNodes[nEntry]);
+ pSettings->SetExpanded( nEntry, bExp );
+ }
+
+ std::unique_ptr<weld::TreeIter> xCurEntry(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_cursor(xCurEntry.get()))
+ xCurEntry.reset();
+
+ ScContentId nRoot;
+ sal_uLong nChild;
+ GetEntryIndexes(nRoot, nChild, xCurEntry.get());
+
+ pSettings->SetRootSelected( nRoot );
+ pSettings->SetChildSelected( nChild );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */