/* -*- 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 <memory>
#include <sal/config.h>
 
#include <osl/diagnose.h>
#include <osl/file.hxx>
#include <tools/urlobj.hxx>
#include <sfx2/fcontnr.hxx>
#include <svl/stritem.hxx>
#include <sfx2/docfile.hxx>
#include <svl/intitem.hxx>
#include <sfx2/dispatch.hxx>
 
#include <sfx2/viewfrm.hxx>
 
#include <pres.hxx>
#include <navigatr.hxx>
#include <pgjump.hxx>
#include <app.hrc>
 
#include <bitmaps.hlst>
#include <drawdoc.hxx>
#include <DrawDocShell.hxx>
#include <ViewShell.hxx>
#include <ViewShellBase.hxx>
#include <slideshow.hxx>
#include <FrameView.hxx>
#include <Window.hxx>
 
#include <DrawViewShell.hxx>
#include <utility>
 
#include <vcl/commandevent.hxx>
#include <comphelper/lok.hxx>
 
#include <sdpage.hxx>
 
/**
 * SdNavigatorWin - FloatingWindow
 */
SdNavigatorWin::SdNavigatorWin(weld::Widget* pParent, SfxBindings* pInBindings, SfxNavigator* pNavigatorDlg)
    : PanelLayout(pParent, u"NavigatorPanel"_ustr, u"modules/simpress/ui/navigatorpanel.ui"_ustr)
    , mxToolbox(m_xBuilder->weld_toolbar(u"toolbox"_ustr))
    , mxTlbObjects(new SdPageObjsTLV(m_xBuilder->weld_tree_view(u"tree"_ustr)))
    , mxLbDocs(m_xBuilder->weld_combo_box(u"documents"_ustr))
    , mxDragModeMenu(m_xBuilder->weld_menu(u"dragmodemenu"_ustr))
    , mxShapeMenu(m_xBuilder->weld_menu(u"shapemenu"_ustr))
    , mxNavigatorDlg(pNavigatorDlg)
    , mbDocImported ( false )
      // On changes of the DragType: adjust SelectionMode of TLB!
    , meDragType ( NAVIGATOR_DRAGTYPE_EMBEDDED )
    , mpBindings ( pInBindings )
{
    mxTlbObjects->SetViewFrame( mpBindings->GetDispatcher()->GetFrame() );
 
    mxTlbObjects->connect_row_activated(LINK(this, SdNavigatorWin, ClickObjectHdl));
    mxTlbObjects->set_selection_mode(SelectionMode::Multiple);
    mxTlbObjects->connect_mouse_release(LINK(this, SdNavigatorWin, MouseReleaseHdl));
    mxTlbObjects->connect_popup_menu(LINK(this, SdNavigatorWin, CommandHdl));
 
    mxToolbox->connect_clicked(LINK(this, SdNavigatorWin, SelectToolboxHdl));
    mxToolbox->connect_menu_toggled(LINK(this, SdNavigatorWin, DropdownClickToolBoxHdl));
 
    mxToolbox->set_item_menu(u"dragmode"_ustr, mxDragModeMenu.get());
    mxDragModeMenu->connect_activate(LINK(this, SdNavigatorWin, MenuSelectHdl));
 
    // Shape filter drop down menu.
    mxToolbox->set_item_menu(u"shapes"_ustr, mxShapeMenu.get());
    mxShapeMenu->connect_activate(LINK(this, SdNavigatorWin, ShapeFilterCallback));
 
    mxTlbObjects->SetSdNavigator(this);
 
    // DragTypeListBox
    mxLbDocs->set_size_request(42, -1); // set a nominal width so it takes width of surroundings
    mxLbDocs->connect_changed(LINK(this, SdNavigatorWin, SelectDocumentHdl));
 
    SetDragImage();
 
    mxToolbox->connect_key_press(LINK(this, SdNavigatorWin, KeyInputHdl));
    mxTlbObjects->connect_key_press(LINK(this, SdNavigatorWin, KeyInputHdl));
    mxLbDocs->connect_key_press(LINK(this, SdNavigatorWin, KeyInputHdl));
    if(comphelper::LibreOfficeKit::isActive())
    {
        mxToolbox->hide();
        mxLbDocs->hide();
    }
}
 
void SdNavigatorWin::FirstFocus()
{
    // set focus to listbox, otherwise it is in the toolbox which is only useful
    // for keyboard navigation
    mxTlbObjects->grab_focus();
}
 
weld::Window* SdNavigatorWin::GetFrameWeld() const
{
    if (mxNavigatorDlg)
        return mxNavigatorDlg->GetFrameWeld();
    return PanelLayout::GetFrameWeld();
}
 
void SdNavigatorWin::SetUpdateRequestFunctor(const UpdateRequestFunctor& rUpdateRequest)
{
    mpNavigatorCtrlItem.reset( new SdNavigatorControllerItem(SID_NAVIGATOR_STATE, this, mpBindings, rUpdateRequest) );
    mpPageNameCtrlItem.reset( new SdPageNameControllerItem(SID_NAVIGATOR_PAGENAME, this, mpBindings) );
 
    // InitTlb; is initiated over Slot
    if (rUpdateRequest)
        rUpdateRequest();
}
 
SdNavigatorWin::~SdNavigatorWin()
{
    mpNavigatorCtrlItem.reset();
    mpPageNameCtrlItem.reset();
    mxDragModeMenu.reset();
    mxShapeMenu.reset();
    mxToolbox.reset();
    mxTlbObjects.reset();
    mxLbDocs.reset();
}
 
static void lcl_select_marked_objects(sd::ViewShell* pViewShell, SdPageObjsTLV* pTlbObjects)
{
    if (const SdrView* pView = pViewShell->GetDrawView())
    {
        auto vMarkedObjects = pView->GetMarkedObjects();
        if (vMarkedObjects.size())
        {
            pTlbObjects->unselect_all();
            for (auto rMarkedObject: vMarkedObjects)
                pTlbObjects->SelectEntry(rMarkedObject);
        }
        else
        {
            if (SdPage* pPage = pViewShell->GetActualPage())
                pTlbObjects->SelectEntry(pPage->GetName());
        }
    }
}
 
void SdNavigatorWin::InitTreeLB( const SdDrawDocument* pDoc )
{
    SdDrawDocument* pNonConstDoc = const_cast<SdDrawDocument*>(pDoc); // const as const can...
    ::sd::DrawDocShell* pDocShell = pNonConstDoc->GetDocSh();
    OUString aDocShName( pDocShell->GetName() );
    ::sd::ViewShell* pViewShell = pDocShell->GetViewShell();
 
    // tdf#160190
    if (!pViewShell)
        return;
 
    // tdf#139944 disable navigator in master mode
    if (const sd::DrawViewShell* pDrawViewShell = static_cast<::sd::DrawViewShell*>(pViewShell))
    {
        if (pDrawViewShell->GetEditMode() == EditMode::MasterPage)
        {
            m_xContainer->set_sensitive(false);
            mxTlbObjects->clear();
            RefreshDocumentLB();
            return;
        }
        else
            m_xContainer->set_sensitive(true);
    }
 
    // Restore the 'ShowAllShapes' flag from the last time (in this session)
    // that the navigator was shown.
    ::sd::FrameView* pFrameView = pViewShell->GetFrameView();
    if (pFrameView != nullptr)
        mxTlbObjects->SetShowAllShapes(pFrameView->IsNavigatorShowingAllShapes(), false);
 
    // Disable the shape filter drop down menu when there is a running slide
    // show.
    if (sd::SlideShow::IsRunning( pViewShell->GetViewShellBase() )
        && !sd::SlideShow::IsInteractiveSlideshow( &pViewShell->GetViewShellBase() ) ) // IASS
        mxToolbox->set_item_sensitive(u"shapes"_ustr, false);
    else
        mxToolbox->set_item_sensitive(u"shapes"_ustr, true);
 
    if( !mxTlbObjects->IsEqualToDoc( pDoc ) )
    {
        OUString aDocName = pDocShell->GetMedium()->GetName();
        mxTlbObjects->clear();
        mxTlbObjects->Fill( pDoc, false, aDocName ); // only normal pages
 
        RefreshDocumentLB();
        mxLbDocs->set_active_text(aDocShName);
    }
    else
    {
        mxLbDocs->set_active(-1);
        mxLbDocs->set_active_text(aDocShName);
 
// commented in order to fix 30246
//        if( mxLbDocs->get_active() == -1 )
        {
            RefreshDocumentLB();
            mxLbDocs->set_active_text(aDocShName);
        }
    }
 
    lcl_select_marked_objects(pViewShell, mxTlbObjects.get());
}
 
/**
 * DragType is set on dependence if a Drag is even possible. For example,
 * under certain circumstances, it is not allowed to drag graphics (#31038#).
 */
NavigatorDragType SdNavigatorWin::GetNavigatorDragType()
{
    NavigatorDragType   eDT = meDragType;
    NavDocInfo*         pInfo = GetDocInfo();
 
    if( ( eDT == NAVIGATOR_DRAGTYPE_LINK ) && ( ( pInfo && !pInfo->HasName() ) || !mxTlbObjects->IsLinkableSelected() ) )
        eDT = NAVIGATOR_DRAGTYPE_NONE;
 
    return eDT;
}
 
SdPageObjsTLV& SdNavigatorWin::GetObjects()
{
    return *mxTlbObjects;
}
 
IMPL_STATIC_LINK_NOARG(SdNavigatorWin, MouseReleaseHdl, const MouseEvent&, bool)
{
    return true;
}
 
IMPL_LINK(SdNavigatorWin, CommandHdl, const CommandEvent&, rCEvt, bool)
{
    if (NavDocInfo* pInfo = GetDocInfo(); !pInfo || !pInfo->IsActive())
        return false;
    if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
        return false;
    weld::TreeView& rTreeView = GetObjects().get_treeview();
    std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(&rTreeView,
                                            u"modules/sdraw/ui/navigatorcontextmenu.ui"_ustr));
    std::unique_ptr<weld::Menu> xPop = xBuilder->weld_menu(u"navmenu"_ustr);
    OUString sCommand = xPop->popup_at_rect(&rTreeView,
                                           tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
    if (!sCommand.isEmpty())
        ExecuteContextMenuAction(sCommand);
    return true;
}
 
void SdNavigatorWin::ExecuteContextMenuAction(std::u16string_view rSelectedPopupEntry)
{
    if (rSelectedPopupEntry == u"rename")
    {
        weld::TreeView& rTreeView = GetObjects().get_treeview();
        std::unique_ptr<weld::TreeIter> xIter(rTreeView.make_iterator());
        if (rTreeView.get_selected(xIter.get()))
        {
            // grab the shell focus so the navigator will update
            if (SfxViewShell* pCurSh = SfxViewShell::Current())
            {
                if (vcl::Window* pShellWnd = pCurSh->GetWindow())
                    pShellWnd->GrabFocus();
            }
            if (rTreeView.get_iter_depth(*xIter) > 0)
                mpBindings->Execute(SID_NAME_GROUP);
            else
                mpBindings->Execute(SID_RENAMEPAGE);
        }
    }
}
 
IMPL_LINK(SdNavigatorWin, SelectToolboxHdl, const OUString&, rCommand, void)
{
    PageJump ePage = PAGE_NONE;
 
    if (rCommand == "first")
        ePage = PAGE_FIRST;
    else if (rCommand == "previous")
        ePage = PAGE_PREVIOUS;
    else if (rCommand == "next")
        ePage = PAGE_NEXT;
    else if (rCommand == "last")
        ePage = PAGE_LAST;
    else if (rCommand == "dragmode")
        mxToolbox->set_menu_item_active(u"dragmode"_ustr, !mxToolbox->get_menu_item_active(u"dragmode"_ustr));
    else if (rCommand == "shapes")
        mxToolbox->set_menu_item_active(u"shapes"_ustr, !mxToolbox->get_menu_item_active(u"shapes"_ustr));
 
    if (ePage != PAGE_NONE)
    {
        SfxUInt16Item aItem( SID_NAVIGATOR_PAGE, static_cast<sal_uInt16>(ePage) );
        mpBindings->GetDispatcher()->ExecuteList(SID_NAVIGATOR_PAGE,
                SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem });
    }
}
 
IMPL_LINK(SdNavigatorWin, DropdownClickToolBoxHdl, const OUString&, rCommand, void)
{
    if (!mxToolbox->get_menu_item_active(rCommand))
        return;
 
    if (rCommand == "dragmode")
    {
        NavDocInfo* pInfo = GetDocInfo();
        if( ( pInfo && !pInfo->HasName() ) || !mxTlbObjects->IsLinkableSelected() )
        {
            mxDragModeMenu->set_sensitive(OUString::number(NAVIGATOR_DRAGTYPE_LINK), false);
            mxDragModeMenu->set_sensitive(OUString::number(NAVIGATOR_DRAGTYPE_URL), false);
            meDragType = NAVIGATOR_DRAGTYPE_EMBEDDED;
        }
 
        mxDragModeMenu->set_active(OUString::number(meDragType), true);
    }
    else if (rCommand == "shapes")
    {
        bool bAll = mxTlbObjects->GetShowAllShapes();
        mxShapeMenu->set_active(u"named"_ustr, !bAll);
        mxShapeMenu->set_active(u"all"_ustr, bAll);
        bool bOrderFrontToBack = mxTlbObjects->GetOrderFrontToBack();
        mxShapeMenu->set_active(u"fronttoback"_ustr, bOrderFrontToBack);
        mxShapeMenu->set_active(u"backtofront"_ustr, !bOrderFrontToBack);
    }
}
 
IMPL_LINK_NOARG(SdNavigatorWin, ClickObjectHdl, weld::TreeView&, bool)
{
    if( !mbDocImported || mxLbDocs->get_active() != 0 )
    {
        NavDocInfo* pInfo = GetDocInfo();
 
        // if it is the active window, we jump to the page
        if( pInfo && pInfo->IsActive() )
        {
            OUString aStr(mxTlbObjects->get_cursor_text());
 
            if( !aStr.isEmpty() )
            {
                sd::DrawDocShell* pDocShell = pInfo->mpDocShell;
                if (!pDocShell)
                    return false;
                sd::ViewShell* pViewShell = pDocShell->GetViewShell();
                if (!pViewShell)
                    return false;
                SdrView* pDrawView = pViewShell->GetDrawView();
                if (!pDrawView)
                    return false;
 
                // Save the selected tree entries re-mark the objects in the view after navigation.
                auto vSelectedEntryIds = mxTlbObjects->GetSelectedEntryIds();
 
                // Page entries in the tree have id value 1. Object entries have id value of
                // the address of the pointer to the object.
                const auto aCursorEntryId = mxTlbObjects->get_cursor_id();
                auto nCursorEntryId = aCursorEntryId.toInt64();
                SdrObject* pCursorEntryObject = weld::fromId<SdrObject*>(aCursorEntryId);
 
                bool bIsCursorEntrySelected(std::find(vSelectedEntryIds.begin(),
                                                      vSelectedEntryIds.end(),
                                                      aCursorEntryId) != vSelectedEntryIds.end());
 
                if (bIsCursorEntrySelected)
                {
                    // Set a temporary name, if need be, so the object can be navigated to.
                    bool bCursorEntryObjectHasEmptyName = false;
                    if (nCursorEntryId != 1 && pCursorEntryObject
                            && pCursorEntryObject->GetName().isEmpty())
                    {
                        bCursorEntryObjectHasEmptyName = true;
                        bool bUndo = pCursorEntryObject->getSdrModelFromSdrObject().IsUndoEnabled();
                        pCursorEntryObject->getSdrModelFromSdrObject().EnableUndo(false);
                        pCursorEntryObject->SetName(aStr, false);
                        pCursorEntryObject->getSdrModelFromSdrObject().EnableUndo(bUndo);
                    }
 
                    // All objects are unmarked when navigating to an object.
                    SfxStringItem aItem(SID_NAVIGATOR_OBJECT, aStr);
                    mpBindings->GetDispatcher()->ExecuteList(SID_NAVIGATOR_OBJECT,
                                            SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem });
 
                    if (bCursorEntryObjectHasEmptyName)
                    {
                        bool bUndo = pCursorEntryObject->getSdrModelFromSdrObject().IsUndoEnabled();
                        pCursorEntryObject->getSdrModelFromSdrObject().EnableUndo(false);
                        pCursorEntryObject->SetName(OUString(), false);
                        pCursorEntryObject->getSdrModelFromSdrObject().EnableUndo(bUndo);
                    }
 
                    // re-mark the objects
                    if (bIsCursorEntrySelected)
                    {
                        // Mark the objects in the view that are selected in the Navigator tree.
                        for (auto& rEntryId: vSelectedEntryIds)
                        {
                            if (rEntryId != "1")
                            {
                                SdrObject* pEntryObject = weld::fromId<SdrObject*>(rEntryId);
                                if (pEntryObject)
                                    pDrawView->MarkObj(pEntryObject, pDrawView->GetSdrPageView());
                            }
                        }
                    }
                }
                else if (nCursorEntryId != 1 && pCursorEntryObject)
                {
                    // unmark
                    pDrawView->MarkObj(pCursorEntryObject, pDrawView->GetSdrPageView(), true);
                }
 
                // SID_NAVIGATOR_STATE invalidate is done in DrawViewShell::ExecNavigatorWin
                // and DrawDocShell::GotoBookmark. Update the bindings here to speed up Navigator
                // state update.
                mpBindings->Update();
 
                if (mxTlbObjects->IsNavigationGrabsFocus())
                {
                    // moved here from SetGetFocusHdl. Reset the
                    // focus only if something has been selected in the
                    // document.
                    SfxViewShell* pCurSh = SfxViewShell::Current();
 
                    if ( pCurSh )
                    {
                        vcl::Window* pShellWnd = pCurSh->GetWindow();
                        if ( pShellWnd )
                            pShellWnd->GrabFocus();
                    }
 
                    // We navigated to an object, but the current shell may be
                    // still the slide sorter. Explicitly try to grab the draw
                    // shell focus, so follow-up operations work with the object
                    // and not with the whole slide.
                    vcl::Window* pWindow = pViewShell->GetActiveWindow();
                    if (pWindow)
                        pWindow->GrabFocus();
                }
            }
        }
    }
    return false;
}
 
IMPL_LINK_NOARG(SdNavigatorWin, SelectDocumentHdl, weld::ComboBox&, void)
{
    OUString aStrLb = mxLbDocs->get_active_text();
    tools::Long   nPos = mxLbDocs->get_active();
    bool   bFound = false;
    ::sd::DrawDocShell* pDocShell = nullptr;
    NavDocInfo* pInfo = GetDocInfo();
 
    // is it a dragged object?
    if( mbDocImported && nPos == 0 )
    {
        // construct document in TLB
        InsertFile( aStrLb );
    }
    else if (pInfo)
    {
        pDocShell = pInfo->mpDocShell;
 
        bFound = true;
    }
 
    if( bFound )
    {
        SdDrawDocument* pDoc = pDocShell->GetDoc();
        if( !mxTlbObjects->IsEqualToDoc( pDoc ) )
        {
            SdDrawDocument* pNonConstDoc = pDoc; // const as const can...
            ::sd::DrawDocShell* pNCDocShell = pNonConstDoc->GetDocSh();
            OUString aDocName = pNCDocShell->GetMedium()->GetName();
            mxTlbObjects->clear();
            mxTlbObjects->Fill( pDoc, false, aDocName ); // only normal pages
        }
    }
 
    // check if link or url is possible
    if( ( pInfo && !pInfo->HasName() ) || !mxTlbObjects->IsLinkableSelected() || ( meDragType != NAVIGATOR_DRAGTYPE_EMBEDDED ) )
    {
        meDragType = NAVIGATOR_DRAGTYPE_EMBEDDED;
        SetDragImage();
    }
}
 
/**
 * Set DrageType and set image accordingly to it.
 */
IMPL_LINK(SdNavigatorWin, MenuSelectHdl, const OUString&, rIdent, void)
{
    sal_uInt32 nMenuId = rIdent.toUInt32();
 
    NavigatorDragType eDT = static_cast<NavigatorDragType>(nMenuId);
    if( meDragType == eDT )
        return;
 
    meDragType = eDT;
    SetDragImage();
 
    if( meDragType == NAVIGATOR_DRAGTYPE_URL )
    {
        // patch, prevents endless loop
        if (mxTlbObjects->count_selected_rows() > 1)
            mxTlbObjects->unselect_all();
 
        mxTlbObjects->set_selection_mode(SelectionMode::Single);
    }
    else
        mxTlbObjects->set_selection_mode(SelectionMode::Multiple);
}
 
IMPL_LINK( SdNavigatorWin, ShapeFilterCallback, const OUString&, rIdent, void )
{
    bool bShowAllShapes(mxTlbObjects->GetShowAllShapes());
    bool bOrderFrontToBack(mxTlbObjects->GetOrderFrontToBack());
    if (rIdent == "named")
        bShowAllShapes = false;
    else if (rIdent == "all")
        bShowAllShapes = true;
    else if (rIdent == "fronttoback")
        bOrderFrontToBack = true;
    else if (rIdent == "backtofront")
        bOrderFrontToBack = false;
    else
        OSL_FAIL("SdNavigatorWin::ShapeFilterCallback called for unknown menu entry");
 
    mxTlbObjects->SetOrderFrontToBack(bOrderFrontToBack);
    mxTlbObjects->SetShowAllShapes(bShowAllShapes, true);
 
    // Remember the selection in the FrameView.
    NavDocInfo* pInfo = GetDocInfo();
    if (pInfo == nullptr)
        return;
 
    ::sd::DrawDocShell* pDocShell = pInfo->mpDocShell;
    if (pDocShell != nullptr)
    {
        ::sd::ViewShell* pViewShell = pDocShell->GetViewShell();
        if (pViewShell != nullptr)
        {
            ::sd::FrameView* pFrameView = pViewShell->GetFrameView();
            if (pFrameView != nullptr)
            {
                pFrameView->SetIsNavigatorShowingAllShapes(bShowAllShapes);
            }
            lcl_select_marked_objects(pViewShell, mxTlbObjects.get());
        }
    }
}
 
bool SdNavigatorWin::InsertFile(const OUString& rFileName)
{
    INetURLObject   aURL( rFileName );
 
    if( aURL.GetProtocol() == INetProtocol::NotValid )
    {
        OUString aURLStr;
        osl::FileBase::getFileURLFromSystemPath( rFileName, aURLStr );
        aURL = INetURLObject( aURLStr );
    }
 
    // get adjusted FileName
    OUString aFileName( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
 
    if (aFileName.isEmpty())
    {
        // show actual document again
        maDropFileName = aFileName;
    }
    else
    {
        // show dragged-in document
        std::shared_ptr<const SfxFilter> pFilter;
        ErrCode nErr = ERRCODE_NONE;
 
        if (aFileName != maDropFileName)
        {
            SfxMedium aMed(aFileName, (StreamMode::READ | StreamMode::SHARE_DENYNONE));
            SfxFilterMatcher aMatch( u"simpress"_ustr );
            aMed.UseInteractionHandler( true );
            nErr = aMatch.GuessFilter(aMed, pFilter);
        }
 
        if ((pFilter && !nErr) || aFileName == maDropFileName)
        {
            // The medium may be opened with READ/WRITE. Therefore, we first
            // check if it contains a Storage.
            std::unique_ptr<SfxMedium> xMedium(new SfxMedium(aFileName,
                                                StreamMode::READ | StreamMode::NOCREATE));
 
            if (xMedium->IsStorage())
            {
                // Now depending on mode:
                // mxTlbObjects->set_selection_mode(SelectionMode::Multiple);
                // handover of ownership of xMedium;
                SdDrawDocument* pDropDoc = mxTlbObjects->GetBookmarkDoc(xMedium.release());
 
                if (pDropDoc)
                {
                    mxTlbObjects->clear();
                    maDropFileName = aFileName;
 
                    if( !mxTlbObjects->IsEqualToDoc( pDropDoc ) )
                    {
                        // only normal pages
                        mxTlbObjects->Fill(pDropDoc, false, maDropFileName);
                        RefreshDocumentLB( &maDropFileName );
                    }
                }
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
 
    return true;
}
 
void SdNavigatorWin::RefreshDocumentLB( const OUString* pDocName )
{
    sal_Int32 nPos = 0;
 
    if( pDocName )
    {
        if( mbDocImported )
            mxLbDocs->remove(0);
 
        mxLbDocs->insert_text(0, *pDocName);
        mbDocImported = true;
    }
    else
    {
        nPos = mxLbDocs->get_active();
        if (nPos == -1)
            nPos = 0;
 
        OUString aStr;
        if( mbDocImported )
            aStr = mxLbDocs->get_text(0);
 
        mxLbDocs->clear();
 
        // delete list of DocInfos
        maDocList.clear();
 
        if( mbDocImported )
            mxLbDocs->insert_text(0, aStr);
 
        ::sd::DrawDocShell* pCurrentDocShell =
              dynamic_cast< ::sd::DrawDocShell *>( SfxObjectShell::Current() );
        SfxObjectShell* pSfxDocShell = SfxObjectShell::GetFirst();
        while( pSfxDocShell )
        {
            ::sd::DrawDocShell* pDocShell = dynamic_cast< ::sd::DrawDocShell *>( pSfxDocShell );
            if( pDocShell  && !pDocShell->IsInDestruction() && ( pDocShell->GetCreateMode() != SfxObjectCreateMode::EMBEDDED ) )
            {
                NavDocInfo aInfo ;
                aInfo.mpDocShell = pDocShell;
 
                SfxMedium *pMedium = pDocShell->GetMedium();
                aStr = pMedium ? pMedium->GetName() : OUString();
                if( !aStr.isEmpty() )
                    aInfo.SetName( true );
                else
                    aInfo.SetName( false );
                // at the moment, we use the name of the shell again (i.e.
                // without path) since Koose thinks it is an error if the path
                // is shown in url notation!
                aStr = pDocShell->GetName();
 
                mxLbDocs->append_text(aStr);
 
                if( pDocShell == pCurrentDocShell )
                    aInfo.SetActive( true );
                else
                    aInfo.SetActive( false );
 
                maDocList.push_back( aInfo );
            }
            pSfxDocShell = SfxObjectShell::GetNext(*pSfxDocShell);
        }
    }
    mxLbDocs->set_active(nPos);
}
 
const OUString & SdNavigatorWin::GetDragTypeSdBmpId(NavigatorDragType eDT)
{
    switch( eDT )
    {
        case NAVIGATOR_DRAGTYPE_NONE:
                return EMPTY_OUSTRING;
        case NAVIGATOR_DRAGTYPE_URL:
                return BMP_HYPERLINK;
        case NAVIGATOR_DRAGTYPE_EMBEDDED:
                return BMP_EMBEDDED;
        case NAVIGATOR_DRAGTYPE_LINK:
                return BMP_LINK;
        default: OSL_FAIL( "No resource for DragType available!" );
    }
    return EMPTY_OUSTRING;
}
 
NavDocInfo* SdNavigatorWin::GetDocInfo()
{
    sal_uInt32 nPos = mxLbDocs->get_active();
 
    if( mbDocImported )
    {
        if( nPos == 0 )
        {
            return nullptr;
        }
        nPos--;
    }
 
    return nPos < maDocList.size() ? &(maDocList[ nPos ]) : nullptr;
}
 
/**
 * catch ESCAPE in order to end show
 */
IMPL_LINK(SdNavigatorWin, KeyInputHdl, const KeyEvent&, rKEvt, bool)
{
    bool bConsumed = false;
 
    if (KEY_ESCAPE == rKEvt.GetKeyCode().GetCode())
    {
        // during drag'n'drop we just stop the drag but do not close the navigator
        if (!SdPageObjsTLV::IsInDrag() && !GetObjects().IsEditingActive())
        {
            ::sd::ViewShellBase* pBase = ::sd::ViewShellBase::GetViewShellBase( mpBindings->GetDispatcher()->GetFrame());
            if (pBase)
                sd::SlideShow::Stop(*pBase);
            bConsumed = true;
        }
    }
 
    return bConsumed;
}
 
void SdNavigatorWin::SetDragImage()
{
    mxToolbox->set_item_icon_name(u"dragmode"_ustr, GetDragTypeSdBmpId(meDragType));
}
 
// for the sidebar to make the panel invisible when the shell type is outline or slide sorter
void SdNavigatorWin::HandleContextChange(const vcl::EnumContext& eContext)
{
    if (eContext.GetApplication() != vcl::EnumContext::Application::Impress)
        return;
 
    ::sd::DrawDocShell* pCurrentDocShell
            = dynamic_cast<::sd::DrawDocShell*>(SfxObjectShell::Current());
    if (!pCurrentDocShell)
        return;
 
    const ::sd::DrawViewShell* pDrawViewShell
            = static_cast<::sd::DrawViewShell*>(pCurrentDocShell->GetViewShell());
    if (!pDrawViewShell)
        return;
 
    sd::ViewShell::ShellType eShellType = pDrawViewShell->GetShellType();
    m_xContainer->set_visible(eShellType != sd::ViewShell::ST_OUTLINE
            && eShellType != sd::ViewShell::ST_SLIDE_SORTER);
}
 
/**
 * ControllerItem for Navigator
 */
SdNavigatorControllerItem::SdNavigatorControllerItem(
    sal_uInt16 _nId,
    SdNavigatorWin* pNavWin,
    SfxBindings*    _pBindings,
    SdNavigatorWin::UpdateRequestFunctor aUpdateRequest)
    : SfxControllerItem( _nId, *_pBindings ),
      pNavigatorWin( pNavWin ),
      maUpdateRequest(std::move(aUpdateRequest))
{
}
 
void SdNavigatorControllerItem::StateChangedAtToolBoxControl( sal_uInt16 nSId,
                        SfxItemState eState, const SfxPoolItem* pItem )
{
    if( eState < SfxItemState::DEFAULT || nSId != SID_NAVIGATOR_STATE )
        return;
 
    // only if doc in LB is the active
    NavDocInfo* pInfo = pNavigatorWin->GetDocInfo();
    if( !(pInfo && pInfo->IsActive()) )
        return;
 
    const SfxUInt32Item& rStateItem = dynamic_cast<const SfxUInt32Item&>(*pItem);
    NavState nState = static_cast<NavState>(rStateItem.GetValue());
 
    // First
    if (nState & NavState::BtnFirstEnabled &&
        !pNavigatorWin->mxToolbox->get_item_sensitive(u"first"_ustr))
        pNavigatorWin->mxToolbox->set_item_sensitive(u"first"_ustr, true);
    if (nState & NavState::BtnFirstDisabled &&
        pNavigatorWin->mxToolbox->get_item_sensitive(u"first"_ustr))
        pNavigatorWin->mxToolbox->set_item_sensitive(u"first"_ustr, false);
 
    // Prev
    if (nState & NavState::BtnPrevEnabled &&
        !pNavigatorWin->mxToolbox->get_item_sensitive(u"previous"_ustr))
        pNavigatorWin->mxToolbox->set_item_sensitive(u"previous"_ustr, true);
    if (nState & NavState::BtnPrevDisabled &&
        pNavigatorWin->mxToolbox->get_item_sensitive(u"previous"_ustr))
        pNavigatorWin->mxToolbox->set_item_sensitive(u"previous"_ustr, false);
 
    // Last
    if (nState & NavState::BtnLastEnabled &&
        !pNavigatorWin->mxToolbox->get_item_sensitive(u"last"_ustr))
        pNavigatorWin->mxToolbox->set_item_sensitive(u"last"_ustr, true);
    if (nState & NavState::BtnLastDisabled &&
        pNavigatorWin->mxToolbox->get_item_sensitive(u"last"_ustr))
        pNavigatorWin->mxToolbox->set_item_sensitive(u"last"_ustr, false);
 
    // Next
    if (nState & NavState::BtnNextEnabled &&
        !pNavigatorWin->mxToolbox->get_item_sensitive(u"next"_ustr))
        pNavigatorWin->mxToolbox->set_item_sensitive(u"next"_ustr, true);
    if (nState & NavState::BtnNextDisabled &&
        pNavigatorWin->mxToolbox->get_item_sensitive(u"next"_ustr))
        pNavigatorWin->mxToolbox->set_item_sensitive(u"next"_ustr, false);
 
    if (nState & NavState::TableUpdate)
    {
        // InitTlb; is initiated by Slot
        if (maUpdateRequest && !pNavigatorWin->GetObjects().get_treeview().has_focus())
            maUpdateRequest();
    }
}
 
/**
 * ControllerItem for Navigator to show page in TreeLB
 */
SdPageNameControllerItem::SdPageNameControllerItem(
    sal_uInt16 _nId,
    SdNavigatorWin* pNavWin,
    SfxBindings*    _pBindings)
    : SfxControllerItem( _nId, *_pBindings ),
      pNavigatorWin( pNavWin )
{
}
 
void SdPageNameControllerItem::StateChangedAtToolBoxControl( sal_uInt16 nSId,
                        SfxItemState eState, const SfxPoolItem* pItem )
{
    if( eState < SfxItemState::DEFAULT || nSId != SID_NAVIGATOR_PAGENAME )
        return;
 
    // only if doc in LB is the active
    NavDocInfo* pInfo = pNavigatorWin->GetDocInfo();
    if( !(pInfo && pInfo->IsActive()) )
        return;
 
    // Without a test for marked objects the page name entry is not selected when there are no
    // marked objects. The HasSelectedChildren test is required when in 'Named Shapes' mode in
    // order to select the page name when none of the marked objects have a name.
    bool bDrawViewHasMarkedObjects = false;
    if (pInfo->GetDrawDocShell() && pInfo->GetDrawDocShell()->GetViewShell())
    {
        const SdrView* pDrawView = pInfo->GetDrawDocShell()->GetViewShell()->GetDrawView();
        if (pDrawView && pDrawView->GetMarkedObjectList().GetMarkCount())
            bDrawViewHasMarkedObjects = true;
    }
 
    const SfxStringItem& rStateItem = dynamic_cast<const SfxStringItem&>(*pItem);
    const OUString& aPageName = rStateItem.GetValue();
 
    if (!bDrawViewHasMarkedObjects || !pNavigatorWin->mxTlbObjects->HasSelectedChildren(aPageName))
    {
        if (pNavigatorWin->mxTlbObjects->get_selection_mode() == SelectionMode::Multiple)
        {
            // because otherwise it is always additional select
            pNavigatorWin->mxTlbObjects->unselect_all();
        }
        pNavigatorWin->mxTlbObjects->SelectEntry( aPageName );
    }
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V530 The return value of function 'ExecuteList' is required to be utilized.

V530 The return value of function 'ExecuteList' is required to be utilized.

V547 Expression 'pViewShell' is always true.

V547 Expression 'bIsCursorEntrySelected' is always true.