/* -*- 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 <comphelper/string.hxx>
#include <svl/urlbmk.hxx>
#include <svl/stritem.hxx>
#include <vcl/graphicfilter.hxx>
#include <sot/formats.hxx>
#include <sot/filelist.hxx>
#include <sfx2/event.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/viewfrm.hxx>
#include <tools/urlobj.hxx>
#include <osl/diagnose.h>
#include <swtypes.hxx>
#include <swmodule.hxx>
#include <view.hxx>
#include <navicfg.hxx>
#include <wrtsh.hxx>
#include <docsh.hxx>
#include <navipi.hxx>
#include <edtwin.hxx>
#include <sfx2/app.hxx>
#include <cmdid.h>
#include <helpids.h>
 
#include <strings.hrc>
#include <bitmaps.hlst>
 
#include <memory>
 
#include <o3tl/enumrange.hxx>
 
#include <workctrl.hxx>
 
#include <comphelper/lok.hxx>
 
#include <swcont.hxx>
#include <content.hxx>
 
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::frame;
 
// Filter the control characters out of the Outline-Entry
OUString SwNavigationPI::CleanEntry(const OUString& rEntry)
{
    if (rEntry.isEmpty())
        return rEntry;
 
    OUStringBuffer aEntry(rEntry);
    for (sal_Int32 i = 0; i < rEntry.getLength(); ++i)
        if(aEntry[i] == 10 || aEntry[i] == 9)
            aEntry[i] = 0x20;
 
    return aEntry.makeStringAndClear();
}
 
// Execution of the drag operation with and without the children.
 
void SwNavigationPI::MoveOutline(SwOutlineNodes::size_type nSource, SwOutlineNodes::size_type nTarget)
{
    SwView *pView = GetCreateView();
    if (!pView)
        return;
    SwWrtShell &rSh = pView->GetWrtShell();
    if (nTarget == SwOutlineNodes::npos)
        nTarget = 0;
    else if (nTarget < nSource)
        nTarget++;
    if ( !rSh.IsOutlineMovable( nSource ))
        return;
 
    SwOutlineNodes::difference_type nMove = nTarget-nSource; //( nDir<0 ) ? 1 : 0 ;
    rSh.GotoOutline(nSource);
    rSh.MakeOutlineSel(nSource, nSource, true);
    // While moving, the selected children does not counting.
    const SwOutlineNodes::size_type nLastOutlinePos = rSh.GetOutlinePos(MAXLEVEL);
    if(nMove > 1 && nLastOutlinePos < nTarget)
    {
        if(!rSh.IsCursorPtAtEnd())
            rSh.SwapPam();
        nMove -= nLastOutlinePos - nSource;
    }
    if( nMove < 1 || nLastOutlinePos < nTarget )
        rSh.MoveOutlinePara( nMove );
    rSh.ClearMark();
    rSh.GotoOutline( nSource + nMove);
 
}
 
// After goto cancel the status frame selection
static void lcl_UnSelectFrame(SwWrtShell *pSh)
{
    if (pSh->IsFrameSelected())
    {
        pSh->UnSelectFrame();
        pSh->LeaveSelFrameMode();
    }
}
 
// Select the document view
IMPL_LINK(SwNavigationPI, DocListBoxSelectHdl, weld::ComboBox&, rBox, void)
{
    int nEntryIdx = rBox.get_active();
    SwView *pView ;
    pView = SwModule::GetFirstView();
    while (nEntryIdx-- && pView)
    {
        pView = SwModule::GetNextView(pView);
    }
    if(!pView)
    {
        nEntryIdx == 0 ?
            m_xContentTree->ShowHiddenShell():
                m_xContentTree->ShowActualView();
 
    }
    else
    {
        m_xContentTree->SetConstantShell(pView->GetWrtShellPtr());
    }
}
 
void SwNavigationPI::UpdateNavigateBy()
{
    if (!m_pNavigateByComboBox)
        return;
    SfxUInt32Item aParam(FN_NAV_ELEMENT, m_pNavigateByComboBox->get_active_id().toUInt32());
    const SfxPoolItem* aArgs[2];
    aArgs[0] = &aParam;
    aArgs[1] = nullptr;
    SfxDispatcher* pDispatcher = GetCreateView()->GetFrame()->GetDispatcher();
    pDispatcher->Execute(FN_NAV_ELEMENT, SfxCallMode::SYNCHRON, aArgs);
}
 
IMPL_LINK(SwNavigationPI, NavigateByComboBoxSelectHdl, weld::ComboBox&, rComboBox, void)
{
    m_xContentTree->SelectContentType(rComboBox.get_active_text());
    UpdateNavigateBy();
}
 
void SwNavigationPI::SetContent3And4ToolBoxVisibility()
{
    if (IsGlobalMode())
        return;
    bool bIsMoveTypePage = SwView::GetMoveType() == NID_PGE;
    m_xContent3ToolBox->set_visible(!bIsMoveTypePage);
    m_xContent4ToolBox->set_visible(bIsMoveTypePage);
}
 
// Filling of the list box for outline view or documents
// The PI will be set to full size
void SwNavigationPI::FillBox()
{
    if(m_pContentWrtShell)
    {
        m_xContentTree->SetHiddenShell( m_pContentWrtShell );
        m_xContentTree->Display(  false );
    }
    else
    {
        SwView *pView = GetCreateView();
        if(!pView)
        {
            m_xContentTree->SetActiveShell(nullptr);
        }
        else if( pView != m_pActContView)
        {
            SwWrtShell* pWrtShell = pView->GetWrtShellPtr();
            m_xContentTree->SetActiveShell(pWrtShell);
        }
        else
            m_xContentTree->Display( true );
        m_pActContView = pView;
        if (m_pActContView)
            m_xContentTree->UpdateTracking();
    }
}
 
// Select handler of the toolboxes
IMPL_LINK(SwNavigationPI, ToolBoxSelectHdl, const OUString&, rCommand, void)
{
    SwView *pView = GetCreateView();
    if (!pView)
        return;
    SwWrtShell &rSh = pView->GetWrtShell();
    // Get MouseModifier for Outline-Move
 
    int nFuncId = 0;
    bool bFocusToDoc = false;
    if (rCommand == "root")
    {
        m_xContentTree->ToggleToRoot();
    }
    else if (rCommand == "listbox")
    {
        if (ParentIsFloatingWindow(m_xNavigatorDlg))
        {
            if (IsZoomedIn())
            {
                ZoomOut();
            }
            else
            {
                ZoomIn();
            }
        }
        return;
    }
    // Functions that will trigger a direct action.
    else if (rCommand == "footer")
    {
        rSh.MoveCursor();
        const FrameTypeFlags eType = rSh.GetFrameType(nullptr,false);
        if (eType & FrameTypeFlags::FOOTER)
        {
            if (rSh.EndPg())
                nFuncId = FN_END_OF_PAGE;
        }
        else if (rSh.GotoFooterText())
            nFuncId = FN_TO_FOOTER;
        bFocusToDoc = true;
    }
    else if (rCommand == "header")
    {
        rSh.MoveCursor();
        const FrameTypeFlags eType = rSh.GetFrameType(nullptr,false);
        if (eType & FrameTypeFlags::HEADER)
        {
            if (rSh.SttPg())
                nFuncId = FN_START_OF_PAGE;
        }
        else if (rSh.GotoHeaderText())
            nFuncId = FN_TO_HEADER;
        bFocusToDoc = true;
    }
    else if (rCommand == "anchor")
    {
        rSh.MoveCursor();
        const FrameTypeFlags eFrameType = rSh.GetFrameType(nullptr,false);
            // Jump from the footnote to the anchor.
        if (eFrameType & FrameTypeFlags::FOOTNOTE)
        {
            if (rSh.GotoFootnoteAnchor())
                nFuncId = FN_FOOTNOTE_TO_ANCHOR;
        }
            // Otherwise, jump to the first footnote text;
            // go to the next footnote if this is not possible;
            // if this is also not possible got to the footnote before.
        else
        {
            if (rSh.GotoFootnoteText())
                nFuncId = FN_FOOTNOTE_TO_ANCHOR;
            else if (rSh.GotoNextFootnoteAnchor())
                nFuncId = FN_NEXT_FOOTNOTE;
            else if (rSh.GotoPrevFootnoteAnchor())
                nFuncId = FN_PREV_FOOTNOTE;
        }
        bFocusToDoc = true;
    }
    else if (rCommand == "reminder")
    {
        rSh.GetView().GetViewFrame().GetDispatcher()->Execute(FN_SET_REMINDER, SfxCallMode::ASYNCHRON);
    }
    else if (rCommand == "movedown" ||
             rCommand == "moveup" ||
             rCommand == "edit")
    {
        if (IsGlobalMode())
            m_xGlobalTree->ExecCommand(rCommand);
    }
    else if (rCommand == "contenttoggle" || rCommand == "globaltoggle")
    {
        ToggleTree();
        bool bGlobalMode = IsGlobalMode();
        m_pConfig->SetGlobalActive(bGlobalMode);
        m_xGlobalToolBox->set_item_active(u"globaltoggle"_ustr, bGlobalMode);
    }
    else if (rCommand == "save")
    {
        bool bSave = rSh.IsGlblDocSaveLinks();
        rSh.SetGlblDocSaveLinks( !bSave );
        m_xGlobalToolBox->set_item_active(rCommand, !bSave);
    }
    else if (rCommand == "headings")
        m_xContent5ToolBox->set_menu_item_active(u"headings"_ustr, !m_xContent5ToolBox->get_menu_item_active(u"headings"_ustr));
    else if (rCommand == "update")
        m_xGlobalToolBox->set_menu_item_active(u"update"_ustr, !m_xGlobalToolBox->get_menu_item_active(u"update"_ustr));
    else if (rCommand == "insert")
        m_xGlobalToolBox->set_menu_item_active(u"insert"_ustr, !m_xGlobalToolBox->get_menu_item_active(u"insert"_ustr));
 
    if (nFuncId)
        lcl_UnSelectFrame(&rSh);
    if (bFocusToDoc)
        pView->GetEditWin().GrabFocus();
}
 
// Click handler of the toolboxes
IMPL_LINK(SwNavigationPI, ToolBoxClickHdl, const OUString&, rCommand, void)
{
    if (!m_xGlobalToolBox->get_menu_item_active(rCommand))
        return;
 
    if (rCommand == "update")
        m_xGlobalTree->TbxMenuHdl(rCommand, *m_xUpdateMenu);
    else if (rCommand == "insert")
        m_xGlobalTree->TbxMenuHdl(rCommand, *m_xInsertMenu);
}
 
IMPL_LINK(SwNavigationPI, GlobalMenuSelectHdl, const OUString&, rIdent, void)
{
    m_xGlobalTree->ExecuteContextMenuAction(rIdent);
}
 
IMPL_LINK(SwNavigationPI, ToolBox5DropdownClickHdl, const OUString&, rCommand, void)
{
    if (!m_xContent5ToolBox->get_menu_item_active(rCommand))
        return;
 
    if (rCommand == "headings")
        m_xHeadingsMenu->set_active(OUString::number(m_xContentTree->GetOutlineLevel()), true);
}
 
void SwNavigationPI::ZoomOut()
{
    if (!IsZoomedIn())
        return;
    SfxNavigator* pNav = m_xNavigatorDlg.get();
    if (!pNav)
        return;
    m_bIsZoomedIn = false;
    FillBox();
    if (IsGlobalMode())
    {
        m_xGlobalBox->show();
        m_xGlobalTree->ShowTree();
    }
    else
    {
        m_xContentBox->show();
        m_xContentTree->ShowTree();
        m_xDocListBox->show();
    }
 
    pNav->InvalidateChildSizeCache();
    Size aOptimalSize(pNav->GetOptimalSize());
    Size aNewSize(pNav->GetOutputSizePixel());
    aNewSize.setHeight( m_aExpandedSize.Height() );
    pNav->SetMinOutputSizePixel(aOptimalSize);
    pNav->SetOutputSizePixel(aNewSize);
 
    m_xContentTree->UpdateContentFunctionsToolbar(); // Enable toolbox
    m_pConfig->SetSmall(false);
    m_xContent6ToolBox->set_item_active(u"listbox"_ustr, true);
}
 
void SwNavigationPI::ZoomIn()
{
    if (IsZoomedIn())
        return;
    SfxNavigator* pNav = m_xNavigatorDlg.get();
    if (!pNav)
        return;
 
    m_aExpandedSize = m_xNavigatorDlg->GetSizePixel();
 
    m_xContentBox->hide();
    m_xContentTree->HideTree();
    m_xGlobalBox->hide();
    m_xGlobalTree->HideTree();
    m_xDocListBox->hide();
    m_bIsZoomedIn = true;
 
    pNav->InvalidateChildSizeCache();
    Size aOptimalSize(pNav->GetOptimalSize());
    Size aNewSize(pNav->GetOutputSizePixel());
    aNewSize.setHeight( aOptimalSize.Height() );
    pNav->SetMinOutputSizePixel(aOptimalSize);
    pNav->SetOutputSizePixel(aNewSize);
 
    m_xContentTree->UpdateContentFunctionsToolbar(); // Enable toolbox
 
    m_pConfig->SetSmall(true);
    m_xContent6ToolBox->set_item_active(u"listbox"_ustr, false);
}
 
std::unique_ptr<PanelLayout> SwNavigationPI::Create(weld::Widget* pParent,
    const css::uno::Reference<css::frame::XFrame>& rxFrame,
    SfxBindings* pBindings)
{
    if( pParent == nullptr )
        throw css::lang::IllegalArgumentException(u"no parent window given to SwNavigationPI::Create"_ustr, nullptr, 0);
    if( !rxFrame.is() )
        throw css::lang::IllegalArgumentException(u"no XFrame given to SwNavigationPI::Create"_ustr, nullptr, 0);
    if( pBindings == nullptr )
        throw css::lang::IllegalArgumentException(u"no SfxBindings given to SwNavigationPI::Create"_ustr, nullptr, 0);
    return std::make_unique<SwNavigationPI>(pParent, rxFrame, pBindings, nullptr);
}
 
SwNavigationPI::SwNavigationPI(weld::Widget* pParent,
    const css::uno::Reference<css::frame::XFrame>& rxFrame,
    SfxBindings* _pBindings, SfxNavigator* pNavigatorDlg)
    : PanelLayout(pParent, u"NavigatorPanel"_ustr, u"modules/swriter/ui/navigatorpanel.ui"_ustr)
    , m_aDocFullName(SID_DOCFULLNAME, *_pBindings, *this)
    , m_aPageStats(FN_STAT_PAGE, *_pBindings, *this)
    , m_aNavElement(FN_NAV_ELEMENT, *_pBindings, *this)
    , m_xFrame(rxFrame)
    , m_xContent1ToolBox(m_xBuilder->weld_toolbar(u"content1"_ustr))
    , m_xContent2ToolBox(m_xBuilder->weld_toolbar(u"content2"_ustr))
    , m_xContent3ToolBox(m_xBuilder->weld_toolbar(u"content3"_ustr))
    , m_xContent4ToolBox(m_xBuilder->weld_toolbar(u"content4"_ustr))
    , m_xContent5ToolBox(m_xBuilder->weld_toolbar(u"content5"_ustr))
    , m_xContent6ToolBox(m_xBuilder->weld_toolbar(u"content6"_ustr))
    , m_xContent2Dispatch(new ToolbarUnoDispatcher(*m_xContent2ToolBox, *m_xBuilder, rxFrame))
    , m_xContent3Dispatch(new ToolbarUnoDispatcher(*m_xContent3ToolBox, *m_xBuilder, rxFrame))
    , m_xHeadingsMenu(m_xBuilder->weld_menu(u"headingsmenu"_ustr))
    , m_xUpdateMenu(m_xBuilder->weld_menu(u"updatemenu"_ustr))
    , m_xInsertMenu(m_xBuilder->weld_menu(u"insertmenu"_ustr))
    , m_xGlobalToolBox(m_xBuilder->weld_toolbar(u"global"_ustr))
    , m_xGotoPageSpinButton(m_xBuilder->weld_spin_button(u"gotopage"_ustr))
    , m_xContentBox(m_xBuilder->weld_widget(u"contentbox"_ustr))
    , m_xContentTree(new SwContentTree(m_xBuilder->weld_tree_view(u"contenttree"_ustr), this))
    , m_xGlobalBox(m_xBuilder->weld_widget(u"globalbox"_ustr))
    , m_xGlobalTree(new SwGlobalTree(m_xBuilder->weld_tree_view(u"globaltree"_ustr), this))
    , m_xDocListBox(m_xBuilder->weld_combo_box(u"documents"_ustr))
    , m_xNavigatorDlg(pNavigatorDlg)
    , m_pContentView(nullptr)
    , m_pContentWrtShell(nullptr)
    , m_pActContView(nullptr)
    , m_pCreateView(nullptr)
    , m_pConfig(SW_MOD()->GetNavigationConfig())
    , m_rBindings(*_pBindings)
    , m_bIsZoomedIn(false)
    , m_bGlobalMode(false)
{
    InitContentFunctionsToolbar();
 
    m_xContainer->connect_container_focus_changed(LINK(this, SwNavigationPI, SetFocusChildHdl));
 
    Reference<XToolbarController> xController =
            m_xContent2Dispatch->GetControllerForCommand(u".uno:NavElement"_ustr);
    NavElementToolBoxControl* pToolBoxControl =
            dynamic_cast<NavElementToolBoxControl*>(xController.get());
 
    // In case of LOK, the xController may not a NavElementToolBoxControl
    if (comphelper::LibreOfficeKit::isActive() && !pToolBoxControl)
    {
        m_pNavigateByComboBox = nullptr;
    }
    else
    {
        assert(pToolBoxControl);
        m_pNavigateByComboBox = pToolBoxControl->GetComboBox();
        SetContent3And4ToolBoxVisibility();
    }
 
    // Restore content tree settings before calling UpdateInitShow. UpdateInitShow calls Fillbox,
    // which calls Display and UpdateTracking. Incorrect outline levels could be displayed and
    // unexpected content tracking could occur if these content tree settings are not done before.
    m_xContentTree->SetOutlineLevel(static_cast<sal_uInt8>(m_pConfig->GetOutlineLevel()));
    m_xContentTree->SetOutlineTracking(static_cast<sal_uInt8>(m_pConfig->GetOutlineTracking()));
    for (ContentTypeId eCntTypeId : o3tl::enumrange<ContentTypeId>())
    {
        if (eCntTypeId != ContentTypeId::OUTLINE)
            m_xContentTree->SetContentTypeTracking(
                        eCntTypeId, m_pConfig->IsContentTypeTrack(eCntTypeId));
    }
 
    if (const ContentTypeId nRootType = m_pConfig->GetRootType();
            nRootType != ContentTypeId::UNKNOWN)
    {
        m_xContentTree->SetRootType(nRootType);
        m_xContent5ToolBox->set_item_active(u"root"_ustr, true);
        if (nRootType == ContentTypeId::OUTLINE || nRootType == ContentTypeId::DRAWOBJECT)
            m_xContentTree->set_selection_mode(SelectionMode::Multiple);
        else
            m_xContentTree->set_selection_mode(SelectionMode::Single);
    }
    else
        m_xContentTree->set_selection_mode(SelectionMode::Single);
 
    UpdateInitShow();
 
    GetCreateView();
 
    m_xContent1ToolBox->set_help_id(HID_NAVIGATOR_TOOLBOX);
    m_xContent2ToolBox->set_help_id(HID_NAVIGATOR_TOOLBOX);
    m_xContent3ToolBox->set_help_id(HID_NAVIGATOR_TOOLBOX);
    m_xContent4ToolBox->set_help_id(HID_NAVIGATOR_TOOLBOX);
    m_xContent5ToolBox->set_help_id(HID_NAVIGATOR_TOOLBOX);
    m_xContent6ToolBox->set_help_id(HID_NAVIGATOR_TOOLBOX);
    m_xGlobalToolBox->set_help_id(HID_NAVIGATOR_GLOBAL_TOOLBOX);
    m_xDocListBox->set_help_id(HID_NAVIGATOR_LISTBOX);
    m_xDocListBox->set_size_request(42, -1); // set a nominal width so it takes width of surroundings
 
    bool bFloatingNavigator = ParentIsFloatingWindow(m_xNavigatorDlg);
 
    m_xContentTree->ShowTree();
    m_xContent6ToolBox->set_item_active(u"listbox"_ustr, true);
    m_xContent6ToolBox->set_item_sensitive(u"listbox"_ustr, bFloatingNavigator);
 
//  TreeListBox for global document
    m_xGlobalTree->set_selection_mode(SelectionMode::Multiple);
 
//  Handler
    Link<const OUString&, void> aLk = LINK(this, SwNavigationPI, ToolBoxSelectHdl);
    m_xContent1ToolBox->connect_clicked(aLk);
    m_xContent5ToolBox->connect_clicked(aLk);
    m_xContent6ToolBox->connect_clicked(aLk);
    m_xGlobalToolBox->connect_clicked(aLk);
    m_xDocListBox->connect_changed(LINK(this, SwNavigationPI, DocListBoxSelectHdl));
    m_xContent5ToolBox->set_item_menu(u"headings"_ustr, m_xHeadingsMenu.get());
    m_xHeadingsMenu->connect_activate(LINK(this, SwNavigationPI, HeadingsMenuSelectHdl));
    m_xContent5ToolBox->connect_menu_toggled(LINK(this, SwNavigationPI, ToolBox5DropdownClickHdl));
    m_xGlobalToolBox->set_item_menu(u"update"_ustr, m_xUpdateMenu.get());
    m_xUpdateMenu->connect_activate(LINK(this, SwNavigationPI, GlobalMenuSelectHdl));
    m_xGlobalToolBox->set_item_menu(u"insert"_ustr, m_xInsertMenu.get());
    m_xInsertMenu->connect_activate(LINK(this, SwNavigationPI, GlobalMenuSelectHdl));
    m_xGlobalToolBox->connect_menu_toggled(LINK(this, SwNavigationPI, ToolBoxClickHdl));
    m_xGlobalToolBox->set_item_active(u"globaltoggle"_ustr, true);
    if (m_pNavigateByComboBox)
        m_pNavigateByComboBox->connect_changed(
            LINK(this, SwNavigationPI, NavigateByComboBoxSelectHdl));
    m_xGotoPageSpinButton->connect_value_changed(
        LINK(this, SwNavigationPI, GotoPageSpinButtonValueChangedHdl));
 
    StartListening(*SfxGetpApp());
 
    if(IsGlobalDoc())
    {
        SwView *pActView = GetCreateView();
        if (pActView && pActView->GetWrtShellPtr())
            m_xGlobalToolBox->set_item_active(u"save"_ustr,
                        pActView->GetWrtShellPtr()->IsGlblDocSaveLinks());
        if (m_pConfig->IsGlobalActive())
            ToggleTree();
        else
            m_xContent1ToolBox->set_visible(true);
        if (bFloatingNavigator)
            m_xGlobalTree->grab_focus();
    }
    else if (bFloatingNavigator)
        m_xContentTree->grab_focus();
 
    m_xContentTree->set_accessible_name(SwResId(STR_ACCESS_TL_CONTENT));
    m_xGlobalTree->set_accessible_name(SwResId(STR_ACCESS_TL_GLOBAL));
    m_xDocListBox->set_accessible_name(SwResId(STR_ACTIVE_VIEW));
 
    m_aExpandedSize = m_xContainer->get_preferred_size();
 
    if(comphelper::LibreOfficeKit::isActive())
    {
        m_xBuilder->weld_container(u"gridcontent16"_ustr)->hide();
        m_xDocListBox->hide();
        m_xGlobalBox->hide();
        m_xGlobalToolBox->hide();
        m_xGlobalTree->HideTree();
 
        //Open Headings by default
        SwView *pView = GetCreateView();
        if (pView && pView->m_nNaviExpandedStatus < 0)
        {
            pView->m_nNaviExpandedStatus = 1;
            m_xContentTree->ExpandAllHeadings();
        }
    }
}
 
void SwNavigationPI::InitContentFunctionsToolbar()
{
    m_xHeadingsContentFunctionsToolbar
        = m_xBuilder->weld_toolbar("HeadingsContentFunctionButtonsToolbar");
    m_xDeleteFunctionToolbar = m_xBuilder->weld_toolbar("DeleteFunctionButtonToolbar");
 
    const OUString sContentTypes[]
        = { "Headings",  "Tables",         "Frames",     "Images",     "OLEobjects",
            "Bookmarks", "Sections",       "Hyperlinks", "References", "Indexes",
            "Comments",  "Drawingobjects", "Fields",     "Footnotes",  "Endnotes" };
 
    for (ContentTypeId eContentTypeId : o3tl::enumrange<ContentTypeId>())
    {
        if (eContentTypeId == ContentTypeId::OUTLINE)
            continue;
        m_aContentTypeUnoToolbarMap[eContentTypeId] = m_xBuilder->weld_toolbar(
            sContentTypes[static_cast<int>(eContentTypeId)] + "ContentTypeUnoToolbar");
        m_aContentTypeToolbarUnoDispatcherMap[eContentTypeId]
            = std::make_unique<ToolbarUnoDispatcher>(*m_aContentTypeUnoToolbarMap[eContentTypeId],
                                                     *m_xBuilder, m_xFrame);
        m_aContentUnoToolbarMap[eContentTypeId] = m_xBuilder->weld_toolbar(
            sContentTypes[static_cast<int>(eContentTypeId)] + "ContentUnoToolbar");
        m_aContentToolbarUnoDispatcherMap[eContentTypeId] = std::make_unique<ToolbarUnoDispatcher>(
            *m_aContentUnoToolbarMap[eContentTypeId], *m_xBuilder, m_xFrame);
    }
 
    Link<const OUString&, void> aLink
        = LINK(this,SwNavigationPI, ContentFunctionsToolbarSelectHdl);
    m_xHeadingsContentFunctionsToolbar->connect_clicked(aLink);
    m_xDeleteFunctionToolbar->connect_clicked(aLink);
}
 
namespace
{
bool lcl_ToolbarHasItemWithIdent(weld::Toolbar& rToolbar, std::u16string_view rIdent)
{
    for (auto i = 0; i < rToolbar.get_n_items(); i++)
    {
        if (rToolbar.get_item_ident(i) == rIdent)
            return true;
    }
    return false;
}
}
 
void SwNavigationPI::UpdateContentFunctionsToolbar()
{
    m_xHeadingsContentFunctionsToolbar->hide();
    for (ContentTypeId eContentTypeId : o3tl::enumrange<ContentTypeId>())
    {
        if (eContentTypeId == ContentTypeId::OUTLINE)
            continue;
        m_aContentTypeUnoToolbarMap[eContentTypeId]->hide();
        m_aContentUnoToolbarMap[eContentTypeId]->hide();
    }
    m_xDeleteFunctionToolbar->hide();
 
    weld::TreeView& rTreeView = m_xContentTree->get_widget();
 
    if (IsZoomedIn() || !rTreeView.is_visible())
        return;
 
    std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
    if (!rTreeView.get_selected(xEntry.get()))
        return;
 
    bool bUseDeleteFunctionsToolbar = true;
    ContentTypeId eContentTypeId = ContentTypeId::UNKNOWN;
 
    const bool bContentType
        = weld::fromId<const SwTypeNumber*>(rTreeView.get_id(*xEntry))->GetTypeId() == 1;
 
    if (bContentType)
    {
        const SwContentType* pContentType = weld::fromId<SwContentType*>(rTreeView.get_id(*xEntry));
        eContentTypeId = pContentType->GetType();
        if (eContentTypeId == ContentTypeId::OUTLINE)
            return;
        weld::Toolbar& rContentTypeToolbar = *m_aContentTypeUnoToolbarMap[eContentTypeId];
        if (rContentTypeToolbar.get_n_items())
        {
            if (eContentTypeId == ContentTypeId::POSTIT)
            {
                // prefer .uno:DeleteAllNotes over delete functions toolbar
                bUseDeleteFunctionsToolbar
                    = !lcl_ToolbarHasItemWithIdent(rContentTypeToolbar, u".uno:DeleteAllNotes");
            }
            rContentTypeToolbar.show();
        }
    }
    else
    {
        const SwContentType* pContentType
            = weld::fromId<SwContent*>(rTreeView.get_id(*xEntry))->GetParent();
        eContentTypeId = pContentType->GetType();
        if (eContentTypeId == ContentTypeId::OUTLINE)
        {
            // todo: make buttons sensitive to movability (think position and protection)
            m_xHeadingsContentFunctionsToolbar->show();
        }
        else if (m_xContentTree->IsSelectedEntryCurrentDocCursorPosition(*xEntry))
        {
            weld::Toolbar& rContentTypeToolbar = *m_aContentUnoToolbarMap[eContentTypeId];
            if (rContentTypeToolbar.get_n_items())
            {
                if (eContentTypeId == ContentTypeId::TABLE)
                {
                    // prefer .uno:DeleteTable over delete functions toolbar
                    bUseDeleteFunctionsToolbar
                        = !lcl_ToolbarHasItemWithIdent(rContentTypeToolbar, u".uno:DeleteTable");
                }
                else if (eContentTypeId == ContentTypeId::INDEX)
                {
                    // prefer .uno:RemoveTableOf over delete functions toolbar
                    bUseDeleteFunctionsToolbar
                        = !lcl_ToolbarHasItemWithIdent(rContentTypeToolbar, u".uno:RemoveTableOf");
                }
                rContentTypeToolbar.show();
            }
        }
    }
 
    if (bUseDeleteFunctionsToolbar && m_xContentTree->IsDeletable(*xEntry))
    {
        OUString sToolTip;
        switch (eContentTypeId)
        {
            case ContentTypeId::OUTLINE:
                sToolTip = SwResId(STR_DELETE_OUTLINE);
                break;
            case ContentTypeId::TABLE:
                sToolTip = SwResId(bContentType ? STR_DELETE_ALL_TABLES : STR_DELETE_TABLE);
                break;
            case ContentTypeId::FRAME:
                sToolTip = SwResId(bContentType ? STR_DELETE_ALL_FRAMES : STR_DELETE_FRAME);
                break;
            case ContentTypeId::GRAPHIC:
                sToolTip = SwResId(bContentType ? STR_DELETE_ALL_GRAPHIC : STR_DELETE_GRAPHIC);
                break;
            case ContentTypeId::OLE:
                sToolTip = SwResId(bContentType ? STR_DELETE_ALL_OLE_OBJECTS : STR_DELETE_OLE_OBJECT);
                break;
            case ContentTypeId::BOOKMARK:
                sToolTip = SwResId(bContentType ? STR_DELETE_ALL_BOOKMARKS : STR_DELETE_BOOKMARK);
                break;
            case ContentTypeId::REGION:
                sToolTip = SwResId(bContentType ? STR_DELETE_ALL_REGIONS : STR_DELETE_REGION);
                break;
            case ContentTypeId::URLFIELD:
                sToolTip = SwResId(bContentType ? STR_DELETE_ALL_URLFIELDS : STR_DELETE_URLFIELD);
                break;
            case ContentTypeId::REFERENCE:
                sToolTip = SwResId(bContentType ? STR_DELETE_ALL_REFERENCES : STR_DELETE_REFERENCE);
                break;
            case ContentTypeId::INDEX:
                sToolTip = SwResId(bContentType ? STR_DELETE_ALL_INDEXES : STR_DELETE_INDEX);
                break;
            case ContentTypeId::POSTIT:
                sToolTip = SwResId(bContentType ? STR_DELETE_ALL_POSTITS : STR_DELETE_POSTIT);
                break;
            case ContentTypeId::DRAWOBJECT:
                sToolTip = SwResId(bContentType ? STR_DELETE_ALL_DRAWOBJECTS : STR_DELETE_DRAWOBJECT);
                break;
            case ContentTypeId::TEXTFIELD:
                sToolTip = SwResId(bContentType ? STR_DELETE_ALL_TEXTFIELDS : STR_DELETE_TEXTFIELD);
                break;
            case ContentTypeId::FOOTNOTE:
                sToolTip = SwResId(bContentType ? STR_DELETE_ALL_FOOTNOTES : STR_DELETE_FOOTNOTE);
                break;
            case ContentTypeId::ENDNOTE:
                sToolTip = SwResId(bContentType ? STR_DELETE_ALL_ENDNOTES : STR_DELETE_ENDNOTE);
                break;
            default:
                break;
        }
        if (!sToolTip.isEmpty())
        {
            m_xDeleteFunctionToolbar->set_item_tooltip_text("delete", sToolTip);
            m_xDeleteFunctionToolbar->show();
        }
    }
}
 
IMPL_LINK(SwNavigationPI, ContentFunctionsToolbarSelectHdl, const OUString&, rCommand, void)
{
    weld::TreeView& rTreeView = m_xContentTree->get_widget();
 
    std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
    if (!rTreeView.get_selected(xEntry.get()))
        return;
 
    const bool bContentEntry
        = weld::fromId<const SwTypeNumber*>(rTreeView.get_id(*xEntry))->GetTypeId() == 0;
 
    if (bContentEntry)
    {
        SwContent* pContent = weld::fromId<SwContent*>(rTreeView.get_id(*xEntry));
        if (pContent)
            m_xContentTree->GotoContent(pContent);
    }
 
    if (rCommand == "chapterdown" || rCommand == "chapterup" || rCommand == "promote"
        || rCommand == "demote")
    {
        // Get MouseModifier for Outline-Move
        // Standard: sublevels are taken
        // do not take sublevels with Ctrl
        bool bOutlineWithChildren = (KEY_MOD1 != m_xContent6ToolBox->get_modifier_state());
        m_xContentTree->ExecCommand(rCommand, bOutlineWithChildren);
    }
    else if (rCommand == "delete")
    {
        if (!bContentEntry)
        {
            m_xContentTree->DeleteAllContentOfEntryContentType(*xEntry);
        }
        else
        {
            m_xContentTree->EditEntry(*xEntry, EditEntryMode::DELETE);
        }
    }
}
 
weld::Window* SwNavigationPI::GetFrameWeld() const
{
    if (m_xNavigatorDlg)
        return m_xNavigatorDlg->GetFrameWeld();
    return PanelLayout::GetFrameWeld();
}
 
IMPL_LINK_NOARG(SwNavigationPI, GotoPageSpinButtonValueChangedHdl, weld::SpinButton&, void)
{
    auto nPage = m_xGotoPageSpinButton->get_value();
    SwView *pView = GetCreateView();
    SwWrtShell &rSh = pView->GetWrtShell();
    auto nPageCount = rSh.GetPageCount();
    if (nPage > nPageCount)
    {
        nPage = nPageCount;
        m_xGotoPageSpinButton->set_text(OUString::number(nPage));
    }
    rSh.LockView(true);
    rSh.GotoPage(nPage, false);
    // adjust the visible area so that the top of the page is at the top of the view
    const Point aPt(pView->GetVisArea().Left(), rSh.GetPagePos(nPage).Y());
    pView->SetVisArea(aPt);
    rSh.LockView(false);
}
 
SwNavigationPI::~SwNavigationPI()
{
    if (IsGlobalDoc() && !IsGlobalMode())
    {
        SwView *pView = GetCreateView();
        SwWrtShell &rSh = pView->GetWrtShell();
        if (!rSh.IsAllProtect())
            pView->GetDocShell()->SetReadOnlyUI(false);
    }
 
    EndListening(*SfxGetpApp());
 
    if (m_oObjectShell)
    {
        if (m_oObjectShell->Is())
            (*m_oObjectShell)->DoClose();
        m_oObjectShell.reset();
    }
 
    m_xDocListBox.reset();
    m_xGlobalTree.reset();
    m_xGlobalBox.reset();
    m_xContentTree.reset();
    m_xContentBox.reset();
    m_xGlobalToolBox.reset();
    m_xGotoPageSpinButton.reset();
    m_xHeadingsMenu.reset();
    m_xUpdateMenu.reset();
    m_xInsertMenu.reset();
    m_xContent2Dispatch.reset();
    m_xContent3Dispatch.reset();
    m_xContent1ToolBox.reset();
    m_xContent2ToolBox.reset();
    m_xContent3ToolBox.reset();
    m_xContent4ToolBox.reset();
    m_xContent5ToolBox.reset();
    m_xContent6ToolBox.reset();
 
    m_aDocFullName.dispose();
    m_aPageStats.dispose();
    m_aNavElement.dispose();
}
 
void SwNavigationPI::NotifyItemUpdate(sal_uInt16 nSID, SfxItemState /*eState*/,
                                      const SfxPoolItem* /*pState*/)
{
    switch (nSID)
    {
        case SID_DOCFULLNAME:
        {
            SwView *pActView = GetCreateView();
            if(pActView)
            {
                SwWrtShell* pWrtShell = pActView->GetWrtShellPtr();
                m_xContentTree->SetActiveShell(pWrtShell);
                if (IsGlobalDoc())
                {
                    m_xGlobalToolBox->set_item_active(u"save"_ustr, pWrtShell->IsGlblDocSaveLinks());
                }
            }
            else
            {
                m_xContentTree->SetActiveShell(nullptr);
            }
            UpdateListBox();
        }
        break;
        case FN_NAV_ELEMENT:
            SetContent3And4ToolBoxVisibility();
            [[fallthrough]];
        case FN_STAT_PAGE:
        {
            if (SwView::GetMoveType() == NID_PGE)
            {
                SwView *pView = GetCreateView();
                if (pView)
                {
                    SwWrtShell& rSh = pView->GetWrtShell();
                    // GetPageNum - return current page number:
                    // true: in which cursor is located.
                    // false: which is visible at the upper margin.
                    sal_uInt16 nPhyNum, nVirtNum;
                    rSh.GetPageNum(nPhyNum, nVirtNum, false);
                    m_xGotoPageSpinButton->set_text(OUString::number(nPhyNum));
                }
            }
        }
    }
}
 
void SwNavigationPI::UpdateInitShow()
{
    // if the parent isn't a float, then the navigator is displayed in
    // the sidebar or is otherwise docked. While the navigator could change
    // its size, the sidebar can not, and the navigator would just waste
    // space. Therefore disable this button.
    bool bParentIsFloatingWindow(ParentIsFloatingWindow(m_xNavigatorDlg));
    m_xContent6ToolBox->set_item_sensitive(u"listbox"_ustr, bParentIsFloatingWindow);
    // show content if docked
    if (!bParentIsFloatingWindow && IsZoomedIn())
        ZoomOut();
    if (!IsZoomedIn())
        FillBox();
}
 
IMPL_LINK_NOARG(SwNavigationPI, SetFocusChildHdl, weld::Container&, void)
{
    // update documents listbox
    UpdateListBox();
}
 
// Notification on modified DocInfo
void SwNavigationPI::Notify( SfxBroadcaster& rBrdc, const SfxHint& rHint )
{
    if(&rBrdc == m_pCreateView)
    {
        if (rHint.GetId() == SfxHintId::Dying)
        {
            EndListening(*m_pCreateView);
            m_pCreateView = nullptr;
            m_xContentTree->SetActiveShell(nullptr);
        }
    }
    else
    {
        if (rHint.GetId() == SfxHintId::ThisIsAnSfxEventHint)
        {
            SfxEventHintId eEventId = static_cast<const SfxEventHint&>(rHint).GetEventId();
            if (eEventId == SfxEventHintId::OpenDoc)
            {
                SwView *pActView = GetCreateView();
                if(pActView)
                {
                    SwWrtShell* pWrtShell = pActView->GetWrtShellPtr();
                    m_xContentTree->SetActiveShell(pWrtShell);
                    if (m_xGlobalTree->get_visible())
                    {
                        bool bUpdateAll = m_xGlobalTree->Update(false);
                        // If no update is needed, then update the font colors
                        // at the entries of broken links.
                        m_xGlobalTree->Display(!bUpdateAll);
                    }
                }
            }
        }
    }
}
 
IMPL_LINK( SwNavigationPI, HeadingsMenuSelectHdl, const OUString&, rMenuId, void )
{
    if (!rMenuId.isEmpty())
        m_xContentTree->SetOutlineLevel(rMenuId.toUInt32());
}
 
void SwNavigationPI::UpdateListBox()
{
    if (!m_xDocListBox) // disposed
        return;
 
    m_xDocListBox->freeze();
    m_xDocListBox->clear();
    SwView *pActView = GetCreateView();
    bool bDisable = pActView == nullptr;
    SwView *pView = SwModule::GetFirstView();
    sal_Int32 nCount = 0;
    sal_Int32 nAct = 0;
    sal_Int32 nConstPos = 0;
    const SwView* pConstView = m_xContentTree->IsConstantView() &&
                                m_xContentTree->GetActiveWrtShell() ?
                                    &m_xContentTree->GetActiveWrtShell()->GetView():
                                        nullptr;
    while (pView)
    {
        SfxObjectShell* pDoc = pView->GetDocShell();
        // #i53333# don't show help pages here
        if ( !pDoc->IsHelpDocument() )
        {
            OUString sEntry = pDoc->GetTitle() + " (";
            if (pView == pActView)
            {
                nAct = nCount;
                sEntry += SwResId(STR_ACTIVE);
            }
            else
                sEntry += SwResId(STR_INACTIVE);
            sEntry += ")";
            m_xDocListBox->append_text(sEntry);
 
            if (pConstView && pView == pConstView)
                nConstPos = nCount;
 
            nCount++;
        }
        pView = SwModule::GetNextView(pView);
    }
    m_xDocListBox->append_text(SwResId(STR_ACTIVE_VIEW)); // "Active Window"
    nCount++;
 
    if (SwWrtShell* pHiddenWrtShell = m_xContentTree->GetHiddenWrtShell())
    {
        OUString sEntry = pHiddenWrtShell->GetView().GetDocShell()->GetTitle() +
                " (" + SwResId(STR_HIDDEN) + ")";
        m_xDocListBox->append_text(sEntry);
        bDisable = false;
    }
 
    m_xDocListBox->thaw();
 
    if(m_xContentTree->IsActiveView())
    {
        //Either the name of the current Document or "Active Document".
        m_xDocListBox->set_active(pActView ? nAct : --nCount);
    }
    else if(m_xContentTree->IsHiddenView())
    {
        m_xDocListBox->set_active(nCount);
    }
    else
        m_xDocListBox->set_active(nConstPos);
 
    m_xDocListBox->set_sensitive(!bDisable);
}
 
IMPL_LINK(SwNavigationPI, DoneLink, SfxPoolItem const *, pItem, void)
{
    const SfxViewFrameItem* pFrameItem = dynamic_cast<SfxViewFrameItem const *>( pItem  );
    if( !pFrameItem )
        return;
 
    SfxViewFrame* pFrame =  pFrameItem->GetFrame();
    if(pFrame)
    {
        m_xContentTree->clear();
        m_pContentView = dynamic_cast<SwView*>( pFrame->GetViewShell() );
        OSL_ENSURE(m_pContentView, "no SwView");
        if(m_pContentView)
            m_pContentWrtShell = m_pContentView->GetWrtShellPtr();
        else
            m_pContentWrtShell = nullptr;
        m_oObjectShell.emplace( pFrame->GetObjectShell() );
        FillBox();
    }
}
 
OUString SwNavigationPI::CreateDropFileName( const TransferableDataHelper& rData )
{
    OUString sFileName;
    SotClipboardFormatId nFormat;
    if( rData.HasFormat( nFormat = SotClipboardFormatId::FILE_LIST ))
    {
        FileList aFileList;
        rData.GetFileList( nFormat, aFileList );
        sFileName = aFileList.GetFile( 0 );
    }
    else if( rData.HasFormat( nFormat = SotClipboardFormatId::STRING ) ||
              rData.HasFormat( nFormat = SotClipboardFormatId::SIMPLE_FILE ) ||
             rData.HasFormat( nFormat = SotClipboardFormatId::FILENAME ))
    {
        (void)rData.GetString(nFormat, sFileName);
    }
    else if( rData.HasFormat( nFormat = SotClipboardFormatId::SOLK ) ||
                rData.HasFormat( nFormat = SotClipboardFormatId::NETSCAPE_BOOKMARK )||
                rData.HasFormat( nFormat = SotClipboardFormatId::FILECONTENT ) ||
                rData.HasFormat( nFormat = SotClipboardFormatId::FILEGRPDESCRIPTOR ) ||
                rData.HasFormat( nFormat = SotClipboardFormatId::UNIFORMRESOURCELOCATOR ))
    {
        INetBookmark aBkmk { OUString(), OUString() };
        if (rData.GetINetBookmark(nFormat, aBkmk))
            sFileName = aBkmk.GetURL();
    }
    if( !sFileName.isEmpty() )
    {
        sFileName = INetURLObject( sFileName ).GetMainURL( INetURLObject::DecodeMechanism::NONE );
    }
    return sFileName;
}
 
sal_Int8 SwNavigationPI::AcceptDrop()
{
    return ( !m_xContentTree->IsInDrag() &&
        ( m_xContentTree->IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE ) ||
          m_xContentTree->IsDropFormatSupported( SotClipboardFormatId::STRING ) ||
          m_xContentTree->IsDropFormatSupported( SotClipboardFormatId::SOLK ) ||
           m_xContentTree->IsDropFormatSupported( SotClipboardFormatId::NETSCAPE_BOOKMARK )||
           m_xContentTree->IsDropFormatSupported( SotClipboardFormatId::FILECONTENT ) ||
           m_xContentTree->IsDropFormatSupported( SotClipboardFormatId::FILEGRPDESCRIPTOR ) ||
           m_xContentTree->IsDropFormatSupported( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) ||
           m_xContentTree->IsDropFormatSupported( SotClipboardFormatId::FILENAME )))
        ? DND_ACTION_COPY
        : DND_ACTION_NONE;
}
 
sal_Int8 SwNavigationPI::ExecuteDrop( const ExecuteDropEvent& rEvt )
{
    TransferableDataHelper aData( rEvt.maDropEvent.Transferable );
    sal_Int8 nRet = DND_ACTION_NONE;
    if (m_xContentTree->IsInDrag())
        return nRet;
 
    OUString sFileName = SwNavigationPI::CreateDropFileName(aData);
    if (sFileName.isEmpty())
        return nRet;
 
    INetURLObject aTemp(sFileName);
    GraphicDescriptor aDesc(aTemp);
    if (aDesc.Detect())   // accept no graphics
        return nRet;
 
    if (-1 != sFileName.indexOf('#'))
        return nRet;
 
    if (m_sContentFileName.isEmpty() || m_sContentFileName != sFileName)
    {
        nRet = rEvt.mnAction;
        sFileName = comphelper::string::stripEnd(sFileName, 0);
        m_sContentFileName = sFileName;
        if(m_oObjectShell)
        {
            m_xContentTree->SetHiddenShell( nullptr );
            (*m_oObjectShell)->DoClose();
            m_oObjectShell.reset();
        }
        SfxStringItem aFileItem(SID_FILE_NAME, sFileName );
        SfxStringItem aOptionsItem( SID_OPTIONS, u"HRC"_ustr );
        SfxLinkItem aLink( SID_DONELINK,
                            LINK( this, SwNavigationPI, DoneLink ) );
        if (SwView* pView = GetActiveView())
            pView->GetViewFrame().GetDispatcher()->ExecuteList(
                        SID_OPENDOC, SfxCallMode::ASYNCHRON,
                        { &aFileItem, &aOptionsItem, &aLink });
    }
    return nRet;
}
 
// toggle between showing the global tree or the content tree
void SwNavigationPI::ToggleTree()
{
    if (comphelper::LibreOfficeKit::isActive())
    {
        m_xGlobalTree->HideTree();
        return;
    }
 
    bool bGlobalDoc = IsGlobalDoc();
    if (!IsGlobalMode() && bGlobalDoc)
    {
        // toggle to global mode
        if (IsZoomedIn())
            ZoomOut();
        m_xGlobalBox->show();
        m_xGlobalTree->ShowTree();
        m_xGlobalToolBox->show();
        m_xContentBox->hide();
        m_xContentTree->HideTree();
        m_xContent1ToolBox->hide();
        m_xContent2ToolBox->hide();
        m_xContent3ToolBox->hide();
        m_xContent4ToolBox->hide();
        m_xContent5ToolBox->hide();
        m_xContent6ToolBox->hide();
        m_xDocListBox->hide();
        SetGlobalMode(true);
    }
    else
    {
        m_xGlobalBox->hide();
        m_xGlobalTree->HideTree();
        m_xGlobalToolBox->hide();
        SetGlobalMode(false);
        if (!IsZoomedIn())
        {
            m_xContentBox->show();
            m_xContentTree->ShowTree();
            m_xContent1ToolBox->show();
            m_xContent2ToolBox->show();
            SetContent3And4ToolBoxVisibility();
            m_xContent5ToolBox->show();
            m_xContent6ToolBox->show();
            m_xDocListBox->show();
        }
    }
}
 
bool SwNavigationPI::IsGlobalDoc() const
{
    bool bRet = false;
    SwView *pView = GetCreateView();
    if (pView)
    {
        SwWrtShell &rSh = pView->GetWrtShell();
        bRet = rSh.IsGlobalDoc();
    }
    return bRet;
}
 
void SwNavigationPI::SelectNavigateByContentType(const OUString& rContentTypeName)
{
    if (!m_pNavigateByComboBox)
        return;
    if (auto nPos = m_pNavigateByComboBox->find_text(rContentTypeName); nPos != -1)
    {
        m_pNavigateByComboBox->set_active(nPos);
        UpdateNavigateBy();
    }
}
 
SwView*  SwNavigationPI::GetCreateView() const
{
    if (!m_pCreateView)
    {
        SwView* pView = SwModule::GetFirstView();
        while (pView)
        {
            if(&pView->GetViewFrame().GetBindings() == &m_rBindings)
            {
                const_cast<SwNavigationPI*>(this)->m_pCreateView = pView;
                const_cast<SwNavigationPI*>(this)->StartListening(*m_pCreateView);
                break;
            }
            pView = SwModule::GetNextView(pView);
        }
    }
    return m_pCreateView;
}
 
class SwNavigatorWin : public SfxNavigator
{
private:
    std::unique_ptr<SwNavigationPI> m_xNavi;
public:
    SwNavigatorWin(SfxBindings* _pBindings, SfxChildWindow* _pMgr,
                   vcl::Window* pParent, SfxChildWinInfo* pInfo);
    virtual void StateChanged(StateChangedType nStateChange) override;
    virtual void dispose() override
    {
        m_xNavi.reset();
        SfxNavigator::dispose();
    }
    virtual ~SwNavigatorWin() override
    {
        disposeOnce();
    }
};
 
SwNavigatorWin::SwNavigatorWin(SfxBindings* _pBindings, SfxChildWindow* _pMgr,
                               vcl::Window* pParent, SfxChildWinInfo* pInfo)
    : SfxNavigator(_pBindings, _pMgr, pParent, pInfo)
    , m_xNavi(std::make_unique<SwNavigationPI>(m_xContainer.get(), _pBindings->GetActiveFrame(), _pBindings, this))
{
    _pBindings->Invalidate(SID_NAVIGATOR);
 
    SwNavigationConfig* pNaviConfig = SW_MOD()->GetNavigationConfig();
 
    SetMinOutputSizePixel(GetOptimalSize());
    if (pNaviConfig->IsSmall())
        m_xNavi->ZoomIn();
}
 
void SwNavigatorWin::StateChanged(StateChangedType nStateChange)
{
    SfxNavigator::StateChanged(nStateChange);
    if (nStateChange == StateChangedType::InitShow)
        m_xNavi->UpdateInitShow();
}
 
SFX_IMPL_DOCKINGWINDOW(SwNavigatorWrapper, SID_NAVIGATOR);
 
SwNavigatorWrapper::SwNavigatorWrapper(vcl::Window *_pParent, sal_uInt16 nId,
                                       SfxBindings* pBindings, SfxChildWinInfo* pInfo)
    : SfxNavigatorWrapper(_pParent, nId)
{
    SetWindow(VclPtr<SwNavigatorWin>::Create(pBindings, this, _pParent, pInfo));
    Initialize();
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V522 Dereferencing of the null pointer 'm_pCreateView' might take place.

V1053 Calling the 'GetOptimalSize' virtual function in the constructor may lead to unexpected result at runtime.

V522 There might be dereferencing of a potential null pointer 'pToolBoxControl'.