Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  content.cxx   Sprache: C

 
/* -*- 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 <docfunc.hxx>
#include <scmod.hxx>
#include <rangenam.hxx>
#include <dbdata.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 OUString 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)
    , 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;
    if(comphelper::LibreOfficeKit::isActive())
    {
        //In case of LOK we may have many different ScContentTrees in different languages.
        //At creation time, we store what language we use, and then use it later too.
        //It does not work in the constructor, that is why it is here.
        if (!m_pResLocaleForLOK)
        {
            m_pResLocaleForLOK = std::make_unique<std::locale>(ScModule::get()->GetResLocale());
        }
        aName = Translate::get(SCSTR_CONTENT_ARY[static_cast<int>(nType)], *m_pResLocaleForLOK);
    }
    else
    {
        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], 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;
    forint 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))
    {
        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() );
                // Check whether the comment is currently visible and toggle its visibility
                ScDocument* pSrcDoc = GetSourceDocument();
                if (ScPostIt* pNote = pSrcDoc ? pSrcDoc->GetNote(aPos.Col(), aPos.Row(), aPos.Tab()) : nullptr)
                {
                    bool bVisible = pNote->IsCaptionShown();
                    // Effectivelly set the visibility of the comment
                    GetManualOrCurrent()->GetDocFunc().ShowNote(aPos, !bVisible);
                    // Put the note in edit mode
                    ScTabViewShell* pScTabViewShell = ScNavigatorDlg::GetTabViewShell();
                    pScTabViewShell->EditNote();
                }
            }
            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;
            defaultbreak;
        }

        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))
            {
                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;

    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());

    switch ( rCEvt.GetCommand() )
    {
        case CommandEventId::ContextMenu:
            {
                //  drag-and-drop mode
                std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), u"modules/scalc/ui/dropmenu.ui"_ustr));
                std::unique_ptr<weld::Menu> xPop(xBuilder->weld_menu(u"contextmenu"_ustr));
                std::unique_ptr<weld::Menu> xDropMenu(xBuilder->weld_menu(u"dragmodesubmenu"_ustr));

                switch (pParentWindow->GetDropMode())
                {
                    case 0:
                        xDropMenu->set_active(u"hyperlink"_ustr, true);
                        break;
                    case 1:
                        xDropMenu->set_active(u"link"_ustr, true);
                        break;
                    case 2:
                        xDropMenu->set_active(u"copy"_ustr, true);
                        break;
                }

                //  displayed document
                std::unique_ptr<weld::Menu> xDocMenu(xBuilder->weld_menu(u"displaymenu"_ustr));
                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 (aName == aManualDoc)
                            sActive = sId;
                    }
                    pSh = SfxObjectShell::GetNext( *pSh );
                }
                //  "active window"
                ++i;
                sId = "document" + OUString::number(i);
                xDocMenu->append_radio(sId, pParentWindow->aStrActiveWin);
                if (aManualDoc.isEmpty())
                    sActive = sId;
                xDocMenu->set_active(sActive, true);

                // Edit/Delete Comments are only visible for comments
                if (nType != ScContentId::NOTE)
                {
                    xPop->set_visible(u"edit"_ustr, false);
                    xPop->set_visible(u"delete"_ustr, false);
                }

                OUString 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);
                }
                else if (sIdent == "edit")
                {
                    ScAddress aPos = GetNotePos( nChild );
                    pParentWindow->SetCurrentTable( aPos.Tab() );
                    pParentWindow->SetCurrentCell( aPos.Col(), aPos.Row() );
                    ScDocument* pSrcDoc = GetSourceDocument();
                    if (pSrcDoc->GetNote(aPos.Col(), aPos.Row(), aPos.Tab()))
                    {
                        // Make the note visible and put it in edit mode
                        GetManualOrCurrent()->GetDocFunc().ShowNote(aPos, true);
                        ScTabViewShell* pScTabViewShell = ScNavigatorDlg::GetTabViewShell();
                        pScTabViewShell->EditNote();
                        bDone = true;
                    }
                }
                else if (sIdent == "delete")
                {
                    ScAddress aPos = GetNotePos(nChild);
                    pParentWindow->SetCurrentTable(aPos.Tab());
                    pParentWindow->SetCurrentCell(aPos.Col(), aPos.Row());
                    ScTabViewShell* pScTabViewShell = ScNavigatorDlg::GetTabViewShell();
                    pScTabViewShell->DeleteContents(InsertDeleteFlags::NOTE);
                }
            }
            break;
            defaultbreak;
    }

    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()
{
    ScDocShell* pSh = GetManualOrCurrent();
    if (pSh)
        return &pSh->GetDocument();
    return nullptr;
}

void ScContentTree::Refresh( ScContentId nType )
{
    //  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;

    ScDocShell* 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();
    assert(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();
    assert(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 )
{
    return rNote.GetText().replace('\n'' ');
}

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();
    ScDocShell* 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&&nbsp;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& rSrcShell, std::u16string_view rName, ScContentId nType, weld::TreeView& rTreeView )
{
    bool bDisallow = true;

    ScDocument& rSrcDoc = rSrcShell.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;
            rSrcShell.FillTransferableObjectDescriptor( aObjDesc );
            aObjDesc.maDisplayName = rSrcShell.GetMedium()->GetURLObject().GetURLNoPass();
            // maSize is set in ScDrawTransferObj ctor

            rtl::Reference<ScDrawTransferObj> pTransferObj = new ScDrawTransferObj( std::move(pDragModel), rSrcShell, std::move(aObjDesc) );

            pTransferObj->SetDragSourceObj( *pObject, nTab );
            pTransferObj->SetDragSourceFlags(ScDragSrc::Navigator);

            ScModule::get()->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& rSrcShell, const ScRange& rRange, ScDragSrc nFlags, weld::TreeView& rTreeView )
{
    bool bDisallow = true;

    ScDocument& rSrcDoc = rSrcShell.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, falsefalse);
        // pClipDoc->ExtendMerge( rRange, sal_True );

        TransferableObjectDescriptor aObjDesc;
        rSrcShell.FillTransferableObjectDescriptor( aObjDesc );
        aObjDesc.maDisplayName = rSrcShell.GetMedium()->GetURLObject().GetURLNoPass();
        // maSize is set in ScTransferObj ctor

        rtl::Reference<ScTransferObj> pTransferObj = new ScTransferObj( std::move(pClipDoc), std::move(aObjDesc) );

        pTransferObj->SetDragSource( &rSrcShell, aMark );
        pTransferObj->SetDragSourceFlags( nFlags );

        ScModule::get()->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;

    ScModule* pScMod = ScModule::get();

    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;
        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
                            defaultbreak;
                        }
                    }
                }
                break;
            case SC_DROPMODE_COPY:
                {
                    ScDocShell* 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::SetRootType( ScContentId nNew )
{
    if ( nNew != nRootType )
    {
        nRootType = nNew;
        Refresh();

        ScNavipiCfg& rCfg = ScModule::get()->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();

    ActiveDocChanged();
}

bool ScContentTree::ActiveDocChanged()
{
    bool bRefreshed = false;

    if (aManualDoc.isEmpty())
    {
        Refresh();                                  // content only if automatic
        bRefreshed = true;
    }

        //  if flag active Listbox must be updated

    OUString aCurrent;

    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;
    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)
    {
        SetManualDoc(aRealName);
    }
    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;
    }

    forint 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;

    forint 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: */

Messung V0.5
C=94 H=96 G=94

¤ Dauer der Verarbeitung: 0.28 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge