/* -*- 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 <fmvwimp.hxx>
#include <svx/fmshell.hxx>
#include <svx/fmtools.hxx>
#include <fmprop.hxx>
#include <fmundo.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/awt/XTabControllerModel.hpp>
#include <sfx2/viewfrm.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
#include <svl/whiter.hxx>
#include <sfx2/app.hxx>
#include <svl/intitem.hxx>
#include <svl/stritem.hxx>
#include <svl/visitem.hxx>
#include <unotools/moduleoptions.hxx>
#include <sfx2/objface.hxx>
#include <sfx2/request.hxx>
#include <sfx2/dispatch.hxx>
#include <svx/svdobj.hxx>
#include <svx/fmpage.hxx>
#include <svx/svditer.hxx>
 
#include <svx/svxids.hrc>
 
#include <svx/svdobjkind.hxx>
#include <svl/eitem.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <svx/svdpage.hxx>
#include <svx/fmmodel.hxx>
#include <fmshimp.hxx>
#include <svx/svdpagv.hxx>
#include <sfx2/objitem.hxx>
#include <sfx2/viewsh.hxx>
#include <fmexpl.hxx>
#include <formcontrolling.hxx>
#include <comphelper/types.hxx>
#include <fmdocumentclassification.hxx>
#include <formtoolbars.hxx>
 
#include <svx/svxdlg.hxx>
 
#include <svx/sdrobjectfilter.hxx>
 
#define ShellClass_FmFormShell
#include <svxslots.hxx>
 
#include <memory>
 
// is used for Invalidate -> maintain it as well
// sort ascending !!!!!!
sal_uInt16 const ControllerSlotMap[] =    // slots of the controller
{
    SID_FM_CONFIG,
    SID_FM_PUSHBUTTON,
    SID_FM_RADIOBUTTON,
    SID_FM_CHECKBOX,
    SID_FM_FIXEDTEXT,
    SID_FM_GROUPBOX,
    SID_FM_EDIT,
    SID_FM_LISTBOX,
    SID_FM_COMBOBOX,
    SID_FM_DBGRID,
    SID_FM_IMAGEBUTTON,
    SID_FM_FILECONTROL,
    SID_FM_NAVIGATIONBAR,
    SID_FM_CTL_PROPERTIES,
    SID_FM_PROPERTIES,
    SID_FM_TAB_DIALOG,
    SID_FM_ADD_FIELD,
    SID_FM_DESIGN_MODE,
    SID_FM_SHOW_FMEXPLORER,
    SID_FM_SHOW_PROPERTIES,
    SID_FM_FMEXPLORER_CONTROL,
    SID_FM_DATEFIELD,
    SID_FM_TIMEFIELD,
    SID_FM_NUMERICFIELD,
    SID_FM_CURRENCYFIELD,
    SID_FM_PATTERNFIELD,
    SID_FM_OPEN_READONLY,
    SID_FM_IMAGECONTROL,
    SID_FM_USE_WIZARDS,
    SID_FM_FORMATTEDFIELD,
    SID_FM_FILTER_NAVIGATOR,
    SID_FM_AUTOCONTROLFOCUS,
    SID_FM_SCROLLBAR,
    SID_FM_SPINBUTTON,
    SID_FM_SHOW_DATANAVIGATOR,
    SID_FM_DATANAVIGATOR_CONTROL,
 
    0
};
 
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::awt;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::form;
using namespace ::com::sun::star::form::runtime;
using namespace ::svxform;
 
FmDesignModeChangedHint::FmDesignModeChangedHint( bool bDesMode )
    :SfxHint(SfxHintId::FmDesignModeChanged), m_bDesignMode( bDesMode )
{
}
 
 
FmDesignModeChangedHint::~FmDesignModeChangedHint()
{
}
 
SFX_IMPL_INTERFACE(FmFormShell, SfxShell)
 
void FmFormShell::InitInterface_Impl()
{
    GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_NAVIGATION, SfxVisibilityFlags::Standard|SfxVisibilityFlags::ReadonlyDoc,
                                            ToolbarId::SvxTbx_Form_Navigation,
                                            SfxShellFeature::FormShowDatabaseBar);
 
    GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_NAVIGATION, SfxVisibilityFlags::Standard|SfxVisibilityFlags::ReadonlyDoc,
                                            ToolbarId::SvxTbx_Form_Filter,
                                            SfxShellFeature::FormShowFilterBar);
 
    GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT, SfxVisibilityFlags::Standard | SfxVisibilityFlags::ReadonlyDoc,
                                            ToolbarId::SvxTbx_Text_Control_Attributes,
                                            SfxShellFeature::FormShowTextControlBar);
 
    GetStaticInterface()->RegisterChildWindow(SID_FM_ADD_FIELD, false, SfxShellFeature::FormShowField);
    GetStaticInterface()->RegisterChildWindow(SID_FM_SHOW_PROPERTIES, false, SfxShellFeature::FormShowProperties);
    GetStaticInterface()->RegisterChildWindow(SID_FM_SHOW_FMEXPLORER, false, SfxShellFeature::FormShowExplorer);
    GetStaticInterface()->RegisterChildWindow(SID_FM_FILTER_NAVIGATOR, false, SfxShellFeature::FormShowFilterNavigator);
    GetStaticInterface()->RegisterChildWindow(SID_FM_SHOW_DATANAVIGATOR, false, SfxShellFeature::FormShowDataNavigator);
 
    GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT, SfxVisibilityFlags::Standard,
                                            ToolbarId::SvxTbx_Controls,
                                            SfxShellFeature::FormTBControls);
 
    GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT, SfxVisibilityFlags::Standard,
                                            ToolbarId::SvxTbx_FormDesign,
                                            SfxShellFeature::FormTBDesign);
}
 
 
FmFormShell::FmFormShell( SfxViewShell* _pParent, FmFormView* pView )
            :SfxShell(_pParent)
            ,m_pImpl(new FmXFormShell(*this, &_pParent->GetViewFrame()))
            ,m_pFormView( pView )
            ,m_pFormModel( nullptr )
            ,m_nLastSlot( 0 )
            ,m_bDesignMode( true )
            ,m_bHasForms(false)
{
    SetPool( &SfxGetpApp()->GetPool() );
    SetName( u"Form"_ustr );
 
    SetView(m_pFormView);
}
 
 
FmFormShell::~FmFormShell()
{
    if ( m_pFormView )
        SetView( nullptr );
 
    m_pImpl->dispose();
}
 
 
void FmFormShell::NotifyMarkListChanged(FmFormView* pWhichView)
{
    FmNavViewMarksChanged aChangeNotification(pWhichView);
    Broadcast(aChangeNotification);
}
 
 
bool FmFormShell::PrepareClose(bool bUI)
{
    if (GetImpl()->didPrepareClose_Lock())
        // we already made a PrepareClose for the current modifications of the current form
        return true;
 
    bool bResult = true;
    // Save the data records, not in DesignMode and FilterMode
    if (!m_bDesignMode && !GetImpl()->isInFilterMode_Lock() &&
        m_pFormView && m_pFormView->GetActualOutDev() &&
        m_pFormView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
    {
        SdrPageView* pCurPageView = m_pFormView->GetSdrPageView();
 
        // sal_uInt16 nPos = pCurPageView ? pCurPageView->GetWinList().Find((OutputDevice*)m_pFormView->GetActualOutDev()) : SDRPAGEVIEWWIN_NOTFOUND;
        SdrPageWindow* pWindow = pCurPageView ? pCurPageView->FindPageWindow(*const_cast<OutputDevice*>(m_pFormView->GetActualOutDev())) : nullptr;
 
        if(pWindow)
        {
            // First, the current contents of the controls are stored.
            // If everything has gone smoothly, the modified records are stored.
            if (GetImpl()->getActiveController_Lock().is())
            {
                const svx::ControllerFeatures& rController = GetImpl()->getActiveControllerFeatures_Lock();
                if ( rController->commitCurrentControl() )
                {
                    const bool bModified = rController->isModifiedRow();
 
                    if ( bModified && bUI )
                    {
                        SfxViewShell* pShell = GetViewShell();
                        vcl::Window* pShellWnd = pShell ? pShell->GetWindow() : nullptr;
                        weld::Widget* pFrameWeld = pShellWnd ? pShellWnd->GetFrameWeld() : nullptr;
                        std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pFrameWeld, u"svx/ui/savemodifieddialog.ui"_ustr));
                        std::unique_ptr<weld::MessageDialog> xQry(xBuilder->weld_message_dialog(u"SaveModifiedDialog"_ustr));
                        switch (xQry->run())
                        {
                            case RET_YES:
                                bResult = rController->commitCurrentRecord( );
                                [[fallthrough]];
                            case RET_NO:
                                GetImpl()->didPrepareClose_Lock(true);
                                break;
 
                            case RET_CANCEL:
                                return false;
                        }
                    }
                }
            }
        }
    }
    return bResult;
}
 
 
void FmFormShell::impl_setDesignMode(bool bDesign)
{
    if (m_pFormView)
    {
        if (!bDesign)
            m_nLastSlot = SID_FM_DESIGN_MODE;
 
        GetImpl()->SetDesignMode_Lock(bDesign);
        // my m_bDesignMode is also set by the Impl ...
    }
    else
    {
        m_bHasForms = false;
        m_bDesignMode = bDesign;
        UIFeatureChanged();
    }
 
    GetViewShell()->GetViewFrame().GetBindings().Invalidate(ControllerSlotMap);
}
 
bool FmFormShell::HasUIFeature(SfxShellFeature nFeature) const
{
    assert((nFeature & ~SfxShellFeature::FormMask) == SfxShellFeature::NONE);
    bool bResult = false;
    if (nFeature & SfxShellFeature::FormShowDatabaseBar)
    {
        // only if forms are also available
        bResult = !m_bDesignMode && GetImpl()->hasDatabaseBar_Lock() && !GetImpl()->isInFilterMode_Lock();
    }
    else if (nFeature & SfxShellFeature::FormShowFilterBar)
    {
        // only if forms are also available
        bResult = !m_bDesignMode && GetImpl()->hasDatabaseBar_Lock() && GetImpl()->isInFilterMode_Lock();
    }
    else if (nFeature & SfxShellFeature::FormShowFilterNavigator)
    {
        bResult = !m_bDesignMode && GetImpl()->hasDatabaseBar_Lock() && GetImpl()->isInFilterMode_Lock();
    }
    else if (nFeature & SfxShellFeature::FormShowField)
    {
        bResult = m_bDesignMode && m_pFormView && m_bHasForms;
    }
    else if (nFeature & SfxShellFeature::FormShowProperties)
    {
        bResult = m_bDesignMode && m_pFormView && m_bHasForms;
    }
    else if (nFeature & SfxShellFeature::FormShowExplorer)
    {
        bResult = m_bDesignMode; // OJ #101593# && m_pFormView && m_bHasForms;
    }
    else if (nFeature & SfxShellFeature::FormShowTextControlBar)
    {
        bResult = !GetImpl()->IsReadonlyDoc_Lock() && m_pImpl->IsActiveControl_Lock(true);
    }
    else if (nFeature & SfxShellFeature::FormShowDataNavigator)
    {
        bResult = GetImpl()->isEnhancedForm_Lock();
    }
    else if (  (nFeature & SfxShellFeature::FormTBControls)
            || (nFeature & SfxShellFeature::FormTBDesign)
            )
    {
        bResult = true;
    }
 
    return bResult;
}
 
 
void FmFormShell::Execute(SfxRequest &rReq)
{
    sal_uInt16 nSlot = rReq.GetSlot();
 
 
    // set MasterSlot
    switch( nSlot )
    {
        case SID_FM_PUSHBUTTON:
        case SID_FM_RADIOBUTTON:
        case SID_FM_CHECKBOX:
        case SID_FM_FIXEDTEXT:
        case SID_FM_GROUPBOX:
        case SID_FM_LISTBOX:
        case SID_FM_COMBOBOX:
        case SID_FM_NAVIGATIONBAR:
        case SID_FM_EDIT:
        case SID_FM_DBGRID:
        case SID_FM_IMAGEBUTTON:
        case SID_FM_IMAGECONTROL:
        case SID_FM_FILECONTROL:
        case SID_FM_DATEFIELD:
        case SID_FM_TIMEFIELD:
        case SID_FM_NUMERICFIELD:
        case SID_FM_CURRENCYFIELD:
        case SID_FM_PATTERNFIELD:
        case SID_FM_FORMATTEDFIELD:
        case SID_FM_SCROLLBAR:
        case SID_FM_SPINBUTTON:
            m_nLastSlot = nSlot;
            break;
    }
 
 
    // set the Identifier and Inventor of the Uno control
    SdrObjKind nIdentifier = SdrObjKind::NONE;
    switch( nSlot )
    {
        case SID_FM_CHECKBOX:
            nIdentifier = SdrObjKind::FormCheckbox;
            break;
        case SID_FM_PUSHBUTTON:
            nIdentifier = SdrObjKind::FormButton;
            break;
        case SID_FM_FIXEDTEXT:
            nIdentifier = SdrObjKind::FormFixedText;
            break;
        case SID_FM_LISTBOX:
            nIdentifier = SdrObjKind::FormListbox;
            break;
        case SID_FM_EDIT:
            nIdentifier = SdrObjKind::FormEdit;
            break;
        case SID_FM_RADIOBUTTON:
            nIdentifier = SdrObjKind::FormRadioButton;
            break;
        case SID_FM_GROUPBOX:
            nIdentifier = SdrObjKind::FormGroupBox;
            break;
        case SID_FM_COMBOBOX:
            nIdentifier = SdrObjKind::FormCombobox;
            break;
        case SID_FM_NAVIGATIONBAR:
            nIdentifier = SdrObjKind::FormNavigationBar;
            break;
        case SID_FM_DBGRID:
            nIdentifier = SdrObjKind::FormGrid;
            break;
        case SID_FM_IMAGEBUTTON:
            nIdentifier = SdrObjKind::FormImageButton;
            break;
        case SID_FM_IMAGECONTROL:
            nIdentifier = SdrObjKind::FormImageControl;
            break;
        case SID_FM_FILECONTROL:
            nIdentifier = SdrObjKind::FormFileControl;
            break;
        case SID_FM_DATEFIELD:
            nIdentifier = SdrObjKind::FormDateField;
            break;
        case SID_FM_TIMEFIELD:
            nIdentifier = SdrObjKind::FormTimeField;
            break;
        case SID_FM_NUMERICFIELD:
            nIdentifier = SdrObjKind::FormNumericField;
            break;
        case SID_FM_CURRENCYFIELD:
            nIdentifier = SdrObjKind::FormCurrencyField;
            break;
        case SID_FM_PATTERNFIELD:
            nIdentifier = SdrObjKind::FormPatternField;
            break;
        case SID_FM_FORMATTEDFIELD:
            nIdentifier = SdrObjKind::FormFormattedField;
            break;
        case SID_FM_SCROLLBAR:
            nIdentifier = SdrObjKind::FormScrollbar;
            break;
        case SID_FM_SPINBUTTON:
            nIdentifier = SdrObjKind::FormSpinButton;
            break;
    }
 
    switch ( nSlot )
    {
        case SID_FM_CHECKBOX:
        case SID_FM_PUSHBUTTON:
        case SID_FM_FIXEDTEXT:
        case SID_FM_LISTBOX:
        case SID_FM_EDIT:
        case SID_FM_RADIOBUTTON:
        case SID_FM_COMBOBOX:
        case SID_FM_NAVIGATIONBAR:
        case SID_FM_GROUPBOX:
        case SID_FM_DBGRID:
        case SID_FM_IMAGEBUTTON:
        case SID_FM_IMAGECONTROL:
        case SID_FM_FILECONTROL:
        case SID_FM_DATEFIELD:
        case SID_FM_TIMEFIELD:
        case SID_FM_NUMERICFIELD:
        case SID_FM_CURRENCYFIELD:
        case SID_FM_PATTERNFIELD:
        case SID_FM_FORMATTEDFIELD:
        case SID_FM_SCROLLBAR:
        case SID_FM_SPINBUTTON:
        {
            const SfxBoolItem* pGrabFocusItem = rReq.GetArg<SfxBoolItem>(SID_FM_TOGGLECONTROLFOCUS);
            if ( pGrabFocusItem && pGrabFocusItem->GetValue() )
            {   // see below
                SfxViewShell* pShell = GetViewShell();
                vcl::Window* pShellWnd = pShell ? pShell->GetWindow() : nullptr;
                if ( pShellWnd )
                    pShellWnd->GrabFocus();
                break;
            }
 
            SfxUInt16Item aIdentifierItem( SID_FM_CONTROL_IDENTIFIER, static_cast<sal_uInt16>(nIdentifier) );
            SfxUInt32Item aInventorItem( SID_FM_CONTROL_INVENTOR, sal_uInt32(SdrInventor::FmForm) );
            const SfxPoolItem* pArgs[] =
            {
                &aIdentifierItem, &aInventorItem, nullptr
            };
            const SfxPoolItem* pInternalArgs[] =
            {
                nullptr
            };
 
            GetViewShell()->GetViewFrame().GetDispatcher()->Execute( SID_FM_CREATE_CONTROL, SfxCallMode::ASYNCHRON,
                                      pArgs, rReq.GetModifier(), pInternalArgs );
 
            if ( rReq.GetModifier() & KEY_MOD1 )
            {
                //  #99013# if selected with control key, return focus to current view
                // do this asynchron, so that the creation can be finished first
                // reusing the SID_FM_TOGGLECONTROLFOCUS is somewhat hacky... which it wouldn't if it would have another
                // name, so I do not really have a big problem with this...
                SfxBoolItem aGrabFocusIndicatorItem( SID_FM_TOGGLECONTROLFOCUS, true );
                GetViewShell()->GetViewFrame().GetDispatcher()->ExecuteList(
                        nSlot, SfxCallMode::ASYNCHRON,
                        { &aGrabFocusIndicatorItem });
            }
 
            rReq.Done();
        }   break;
    }
 
    // individual actions
    switch( nSlot )
    {
        case SID_FM_FORM_DESIGN_TOOLS:
        {
            FormToolboxes aToolboxAccess(GetImpl()->getHostFrame_Lock());
            aToolboxAccess.toggleToolbox( nSlot );
            rReq.Done();
        }
        break;
 
        case SID_FM_TOGGLECONTROLFOCUS:
        {
            FmFormView* pFormView = GetFormView();
            if ( !pFormView )
                break;
 
            // if we execute this ourself, then either the application does not implement an own handling for this,
            // of we're on the top of the dispatcher stack, which means a control has the focus.
            // In the latter case, we put the focus to the document window, otherwise, we focus the first control
            const bool bHasControlFocus = GetImpl()->HasControlFocus_Lock();
            if ( bHasControlFocus )
            {
                if (m_pFormView)
                {
                    const OutputDevice* pDevice = m_pFormView->GetActualOutDev();
                    vcl::Window* pWindow = pDevice->GetOwnerWindow();
                    if ( pWindow )
                        pWindow->GrabFocus();
                }
            }
            else
            {
                pFormView->GrabFirstControlFocus( );
            }
        }
        break;
 
        case SID_FM_VIEW_AS_GRID:
            GetImpl()->CreateExternalView_Lock();
            break;
        case SID_FM_CONVERTTO_EDIT          :
        case SID_FM_CONVERTTO_BUTTON            :
        case SID_FM_CONVERTTO_FIXEDTEXT     :
        case SID_FM_CONVERTTO_LISTBOX       :
        case SID_FM_CONVERTTO_CHECKBOX      :
        case SID_FM_CONVERTTO_RADIOBUTTON   :
        case SID_FM_CONVERTTO_GROUPBOX      :
        case SID_FM_CONVERTTO_COMBOBOX      :
        case SID_FM_CONVERTTO_IMAGEBUTTON   :
        case SID_FM_CONVERTTO_FILECONTROL   :
        case SID_FM_CONVERTTO_DATE          :
        case SID_FM_CONVERTTO_TIME          :
        case SID_FM_CONVERTTO_NUMERIC       :
        case SID_FM_CONVERTTO_CURRENCY      :
        case SID_FM_CONVERTTO_PATTERN       :
        case SID_FM_CONVERTTO_IMAGECONTROL  :
        case SID_FM_CONVERTTO_FORMATTED     :
        case SID_FM_CONVERTTO_SCROLLBAR     :
        case SID_FM_CONVERTTO_SPINBUTTON    :
        case SID_FM_CONVERTTO_NAVIGATIONBAR :
            GetImpl()->executeControlConversionSlot_Lock(FmXFormShell::SlotToIdent(nSlot));
            // after the conversion, re-determine the selection, since the
            // selected object has changed
            GetImpl()->SetSelection_Lock(GetFormView()->GetMarkedObjectList());
            break;
        case SID_FM_LEAVE_CREATE:
            m_nLastSlot = 0;
            rReq.Done();
            break;
        case SID_FM_SHOW_PROPERTY_BROWSER:
        {
            const SfxBoolItem* pShowItem = rReq.GetArg<SfxBoolItem>(SID_FM_SHOW_PROPERTIES);
            bool bShow = true;
            if ( pShowItem )
                bShow = pShowItem->GetValue();
            GetImpl()->ShowSelectionProperties_Lock(bShow);
 
            rReq.Done();
        } break;
 
        case SID_FM_PROPERTIES:
        {
            // display the PropertyBrowser
            const SfxBoolItem* pShowItem = rReq.GetArg<SfxBoolItem>(nSlot);
            bool bShow = pShowItem == nullptr || pShowItem->GetValue();
 
            InterfaceBag aOnlyTheForm;
            aOnlyTheForm.insert(Reference<XInterface>(GetImpl()->getCurrentForm_Lock(), UNO_QUERY));
            GetImpl()->setCurrentSelection_Lock(std::move(aOnlyTheForm));
 
            GetImpl()->ShowSelectionProperties_Lock(bShow);
 
            rReq.Done();
        }   break;
 
        case SID_FM_CTL_PROPERTIES:
        {
            const SfxBoolItem* pShowItem = rReq.GetArg<SfxBoolItem>(nSlot);
            bool bShow = pShowItem == nullptr || pShowItem->GetValue();
 
            OSL_ENSURE( GetImpl()->onlyControlsAreMarked_Lock(), "FmFormShell::Execute: ControlProperties should be disabled!" );
            if ( bShow )
                GetImpl()->selectLastMarkedControls_Lock();
            GetImpl()->ShowSelectionProperties_Lock(bShow);
 
            rReq.Done();
        }   break;
        case SID_FM_SHOW_PROPERTIES:
        case SID_FM_ADD_FIELD:
        case SID_FM_FILTER_NAVIGATOR:
        case SID_FM_SHOW_DATANAVIGATOR :
        {
            GetViewShell()->GetViewFrame().ToggleChildWindow(nSlot);
            rReq.Done();
        }   break;
        case SID_FM_SHOW_FMEXPLORER:
        {
            if (!m_pFormView)   // force setting the view
                GetViewShell()->GetViewFrame().GetDispatcher()->Execute(SID_CREATE_SW_DRAWVIEW);
 
            GetViewShell()->GetViewFrame().ChildWindowExecute(rReq);
            rReq.Done();
        }
        break;
 
        case SID_FM_TAB_DIALOG:
        {
            GetImpl()->ExecuteTabOrderDialog_Lock(
                Reference<XTabControllerModel>(GetImpl()->getCurrentForm_Lock(), UNO_QUERY));
            rReq.Done();
        }
        break;
 
        case SID_FM_DESIGN_MODE:
        {
            const SfxBoolItem* pDesignItem = rReq.GetArg<SfxBoolItem>(nSlot);
            bool bDesignMode = pDesignItem ? pDesignItem->GetValue() : !m_bDesignMode;
            SetDesignMode( bDesignMode );
            if ( m_bDesignMode == bDesignMode )
                rReq.Done();
 
            m_nLastSlot = SID_FM_DESIGN_MODE;
        }
        break;
 
        case SID_FM_AUTOCONTROLFOCUS:
        {
            FmFormModel* pModel = GetFormModel();
            DBG_ASSERT(pModel, "FmFormShell::Execute : invalid call !");
                // should have been disabled in GetState if we don't have a FormModel
            pModel->SetAutoControlFocus( !pModel->GetAutoControlFocus() );
            GetViewShell()->GetViewFrame().GetBindings().Invalidate(SID_FM_AUTOCONTROLFOCUS);
        }
        break;
        case SID_FM_OPEN_READONLY:
        {
            FmFormModel* pModel = GetFormModel();
            DBG_ASSERT(pModel, "FmFormShell::Execute : invalid call !");
                // should have been disabled in GetState if we don't have a FormModel
            pModel->SetOpenInDesignMode( !pModel->GetOpenInDesignMode() );
            GetViewShell()->GetViewFrame().GetBindings().Invalidate(SID_FM_OPEN_READONLY);
        }
        break;
        case SID_FM_USE_WIZARDS:
        {
            GetImpl()->SetWizardUsing_Lock(!GetImpl()->GetWizardUsing_Lock());
            GetViewShell()->GetViewFrame().GetBindings().Invalidate(SID_FM_USE_WIZARDS);
        }
        break;
        case SID_FM_SEARCH:
        {
            const svx::ControllerFeatures& rController = GetImpl()->getActiveControllerFeatures_Lock();
            if ( rController->commitCurrentControl() && rController->commitCurrentRecord() )
                GetImpl()->ExecuteSearch_Lock();
            rReq.Done();
        }
        break;
 
        case SID_FM_RECORD_FIRST:
        case SID_FM_RECORD_PREV:
        case SID_FM_RECORD_NEXT:
        case SID_FM_RECORD_LAST:
        case SID_FM_RECORD_NEW:
        case SID_FM_REFRESH:
        case SID_FM_REFRESH_FORM_CONTROL:
        case SID_FM_RECORD_DELETE:
        case SID_FM_RECORD_UNDO:
        case SID_FM_RECORD_SAVE:
        case SID_FM_REMOVE_FILTER_SORT:
        case SID_FM_SORTDOWN:
        case SID_FM_SORTUP:
        case SID_FM_AUTOFILTER:
        case SID_FM_ORDERCRIT:
        case SID_FM_FORM_FILTERED:
        {
            GetImpl()->ExecuteFormSlot_Lock(nSlot);
            rReq.Done();
        }
        break;
 
        case SID_FM_RECORD_ABSOLUTE:
        {
            const svx::ControllerFeatures& rController = GetImpl()->getNavControllerFeatures_Lock();
            sal_Int32 nRecord = -1;
 
            const SfxItemSet* pArgs = rReq.GetArgs();
            if ( pArgs )
            {
                const SfxPoolItem* pItem;
                if ( ( pArgs->GetItemState( FN_PARAM_1, true, &pItem ) ) == SfxItemState::SET )
                {
                    const SfxInt32Item* pTypedItem = dynamic_cast<const SfxInt32Item* >( pItem );
                    if ( pTypedItem )
                        nRecord = std::max( pTypedItem->GetValue(), sal_Int32(0) );
                }
            }
            else
            {
                SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
                ScopedVclPtr<AbstractFmInputRecordNoDialog> dlg(pFact->CreateFmInputRecordNoDialog(rReq.GetFrameWeld()));
                dlg->SetValue( rController->getCursor()->getRow() );
                if ( dlg->Execute() == RET_OK )
                    nRecord = dlg->GetValue();
 
                rReq.AppendItem( SfxInt32Item( TypedWhichId<SfxInt32Item>(FN_PARAM_1), nRecord ) );
            }
 
            if ( nRecord != -1 )
                rController->execute( nSlot, u"Position"_ustr, Any( nRecord ) );
 
            rReq.Done();
        }   break;
        case SID_FM_FILTER_EXECUTE:
        case SID_FM_FILTER_EXIT:
        {
            bool bCancelled = ( SID_FM_FILTER_EXIT == nSlot );
            bool bReopenNavigator = false;
 
            if ( !bCancelled )
            {
                // if the filter navigator is still open, we need to close it, so it can possibly
                // commit it's most recent changes
                if (GetViewShell())
                    if ( GetViewShell()->GetViewFrame().HasChildWindow( SID_FM_FILTER_NAVIGATOR ) )
                    {
                        GetViewShell()->GetViewFrame().ToggleChildWindow( SID_FM_FILTER_NAVIGATOR );
                        bReopenNavigator = true;
                    }
 
                Reference<runtime::XFormController> const xController(GetImpl()->getActiveController_Lock());
 
                if  (   GetViewShell()->GetViewFrame().HasChildWindow( SID_FM_FILTER_NAVIGATOR )
                        // closing the window was denied, for instance because of an invalid criterion
 
                    ||  (   xController.is()
                        &&  !GetImpl()->getActiveControllerFeatures_Lock()->commitCurrentControl()
                        )
                        // committing the controller was denied
                    )
                {
                    rReq.Done();
                    break;
                }
            }
 
            GetImpl()->stopFiltering_Lock(!bCancelled);
            rReq.Done();
 
            if ( bReopenNavigator )
                // we closed the navigator only to implicitly commit it (as we do not have another
                // direct wire to it), but to the user, it should look as it was always open
                GetViewShell()->GetViewFrame().ToggleChildWindow( SID_FM_FILTER_NAVIGATOR );
        }
        break;
 
        case SID_FM_FILTER_START:
        {
            GetImpl()->startFiltering_Lock();
            rReq.Done();
 
            // initially open the filter navigator, the whole form based filter is pretty useless without it
            SfxBoolItem aIdentifierItem( SID_FM_FILTER_NAVIGATOR, true );
            GetViewShell()->GetViewFrame().GetDispatcher()->ExecuteList(
                    SID_FM_FILTER_NAVIGATOR, SfxCallMode::ASYNCHRON,
                    { &aIdentifierItem });
        }   break;
    }
}
 
 
void FmFormShell::GetState(SfxItemSet &rSet)
{
    SfxWhichIter aIter( rSet );
    sal_uInt16 nWhich = aIter.FirstWhich();
    while ( nWhich )
    {
        switch( nWhich )
        {
            case SID_FM_FORM_DESIGN_TOOLS:
            {
                FormToolboxes aToolboxAccess(GetImpl()->getHostFrame_Lock());
                rSet.Put( SfxBoolItem( nWhich, aToolboxAccess.isToolboxVisible( nWhich ) ) );
            }
            break;
 
            case SID_FM_FILTER_EXECUTE:
            case SID_FM_FILTER_EXIT:
                if (!GetImpl()->isInFilterMode_Lock())
                    rSet.DisableItem( nWhich );
                break;
 
            case SID_FM_USE_WIZARDS:
                if  ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) )
                    rSet.Put( SfxVisibilityItem( nWhich, false ) );
                else if (!GetFormModel())
                    rSet.DisableItem( nWhich );
                else
                    rSet.Put(SfxBoolItem(nWhich, GetImpl()->GetWizardUsing_Lock()));
                break;
            case SID_FM_AUTOCONTROLFOCUS:
                if (!GetFormModel())
                    rSet.DisableItem( nWhich );
                else
                    rSet.Put( SfxBoolItem(nWhich, GetFormModel()->GetAutoControlFocus() ) );
                break;
            case SID_FM_OPEN_READONLY:
                if (!GetFormModel())
                    rSet.DisableItem( nWhich );
                else
                    rSet.Put( SfxBoolItem(nWhich, GetFormModel()->GetOpenInDesignMode() ) );
                break;
 
            case SID_FM_NAVIGATIONBAR:
            case SID_FM_DBGRID:
                if ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) )
                {
                    rSet.Put( SfxVisibilityItem( nWhich, false ) );
                    break;
                }
                [[fallthrough]];
 
            case SID_FM_SCROLLBAR:
            case SID_FM_IMAGECONTROL:
            case SID_FM_FILECONTROL:
            case SID_FM_CURRENCYFIELD:
            case SID_FM_PATTERNFIELD:
            case SID_FM_IMAGEBUTTON:
            case SID_FM_RADIOBUTTON:
            case SID_FM_COMBOBOX:
            case SID_FM_GROUPBOX:
            case SID_FM_CHECKBOX:
            case SID_FM_PUSHBUTTON:
            case SID_FM_FIXEDTEXT:
            case SID_FM_LISTBOX:
            case SID_FM_EDIT:
            case SID_FM_DATEFIELD:
            case SID_FM_TIMEFIELD:
            case SID_FM_NUMERICFIELD:
            case SID_FM_FORMATTEDFIELD:
            case SID_FM_SPINBUTTON:
                if (!m_bDesignMode)
                    rSet.DisableItem( nWhich );
                else
                {
                    bool bLayerLocked = false;
                    if (m_pFormView)
                    {
                        // If the css::drawing::Layer is locked, the slots must be disabled. #36897
                        SdrPageView* pPV = m_pFormView->GetSdrPageView();
                        if (pPV != nullptr)
                            bLayerLocked = pPV->IsLayerLocked(m_pFormView->GetActiveLayer());
                    }
                    if (bLayerLocked)
                        rSet.DisableItem( nWhich );
                    else
                        rSet.Put( SfxBoolItem(nWhich, (nWhich==m_nLastSlot)) );
                }
                break;
            case SID_FM_FILTER_NAVIGATOR_CONTROL:
            {
                if (GetImpl()->isInFilterMode_Lock())
                    rSet.Put(SfxObjectItem(nWhich, this));
                else
                    rSet.Put(SfxObjectItem(nWhich));
            }   break;
            case SID_FM_FIELDS_CONTROL:
            case SID_FM_PROPERTY_CONTROL:
            {
                if (!m_bDesignMode || !m_pFormView || !m_bHasForms)
                    rSet.Put(SfxObjectItem(nWhich));
                else
                    rSet.Put(SfxObjectItem(nWhich, this));
 
            }   break;
            case SID_FM_FMEXPLORER_CONTROL:
            case SID_FM_DATANAVIGATOR_CONTROL :
            {
                if (!m_bDesignMode || !m_pFormView)
                    rSet.Put(SfxObjectItem(nWhich));
                else
                    rSet.Put(SfxObjectItem(nWhich, this));
 
            }   break;
            case SID_FM_ADD_FIELD:
            case SID_FM_SHOW_FMEXPLORER:
            case SID_FM_SHOW_PROPERTIES:
            case SID_FM_FILTER_NAVIGATOR:
            case SID_FM_SHOW_DATANAVIGATOR:
            {
                if ( GetViewShell()->GetViewFrame().KnowsChildWindow(nWhich) )
                    rSet.Put( SfxBoolItem( nWhich, GetViewShell()->GetViewFrame().HasChildWindow(nWhich)) );
                else
                    rSet.DisableItem(nWhich);
            }   break;
 
            case SID_FM_SHOW_PROPERTY_BROWSER:
            {
                rSet.Put(SfxBoolItem(nWhich, GetImpl()->IsPropBrwOpen_Lock()));
            }
            break;
 
            case SID_FM_CTL_PROPERTIES:
            {
                // potentially, give the Impl the opportunity to update its
                // current objects which are aligned with the current MarkList
                if (GetImpl()->IsSelectionUpdatePending_Lock())
                    GetImpl()->ForceUpdateSelection_Lock();
 
                if (!m_pFormView || !m_bDesignMode || !GetImpl()->onlyControlsAreMarked_Lock())
                    rSet.DisableItem( nWhich );
                else
                {
                    bool const bChecked = GetImpl()->IsPropBrwOpen_Lock() && !GetImpl()->isSolelySelected_Lock(GetImpl()->getCurrentForm_Lock());
                        // if the property browser is open, and only controls are marked, and the current selection
                        // does not consist of only the current form, then the current selection is the (composition of)
                        // the currently marked controls
                    rSet.Put( SfxBoolItem( nWhich, bChecked ) );
                }
            }   break;
 
            case SID_FM_PROPERTIES:
            {
                // potentially, give the Impl the opportunity to update its
                // current objects which are aligned with the current MarkList
                if (GetImpl()->IsSelectionUpdatePending_Lock())
                    GetImpl()->ForceUpdateSelection_Lock();
 
                if (!m_pFormView || !m_bDesignMode || !GetImpl()->getCurrentForm_Lock().is())
                    rSet.DisableItem( nWhich );
                else
                {
                    bool const bChecked = GetImpl()->IsPropBrwOpen_Lock() && GetImpl()->isSolelySelected_Lock(GetImpl()->getCurrentForm_Lock());
                    rSet.Put(SfxBoolItem(nWhich, bChecked));
                }
            }   break;
            case SID_FM_TAB_DIALOG:
                // potentially, give the Impl the opportunity to update its
                // current objects which are aligned with the current MarkList
                if (GetImpl()->IsSelectionUpdatePending_Lock())
                    GetImpl()->ForceUpdateSelection_Lock();
 
                if (!m_pFormView || !m_bDesignMode || !GetImpl()->getCurrentForm_Lock().is() )
                    rSet.DisableItem( nWhich );
                break;
            case SID_FM_DESIGN_MODE:
                if (!m_pFormView || GetImpl()->IsReadonlyDoc_Lock())
                    rSet.DisableItem( nWhich );
                else
                    rSet.Put( SfxBoolItem(nWhich, m_bDesignMode) );
                break;
            case SID_FM_SEARCH:
            case SID_FM_RECORD_FIRST:
            case SID_FM_RECORD_NEXT:
            case SID_FM_RECORD_PREV:
            case SID_FM_RECORD_LAST:
            case SID_FM_RECORD_NEW:
            case SID_FM_RECORD_DELETE:
            case SID_FM_RECORD_ABSOLUTE:
            case SID_FM_RECORD_TOTAL:
            case SID_FM_RECORD_SAVE:
            case SID_FM_RECORD_UNDO:
            case SID_FM_FORM_FILTERED:
            case SID_FM_REMOVE_FILTER_SORT:
            case SID_FM_SORTUP:
            case SID_FM_SORTDOWN:
            case SID_FM_ORDERCRIT:
            case SID_FM_FILTER_START:
            case SID_FM_AUTOFILTER:
            case SID_FM_REFRESH:
            case SID_FM_REFRESH_FORM_CONTROL:
            case SID_FM_VIEW_AS_GRID:
                GetFormState(rSet,nWhich);
                break;
 
            case SID_FM_CHANGECONTROLTYPE:
            {
                if ( !m_pFormView || !m_bDesignMode )
                    rSet.DisableItem( nWhich );
                else
                {
                    if (!GetImpl()->canConvertCurrentSelectionToControl_Lock(u"ConvertToFixed"))
                        // if it cannot be converted to a fixed text, it is no single control
                        rSet.DisableItem( nWhich );
                }
            } break;
 
            case SID_FM_CONVERTTO_FILECONTROL   :
            case SID_FM_CONVERTTO_CURRENCY      :
            case SID_FM_CONVERTTO_PATTERN       :
            case SID_FM_CONVERTTO_IMAGECONTROL  :
            case SID_FM_CONVERTTO_SCROLLBAR     :
            case SID_FM_CONVERTTO_NAVIGATIONBAR :
            case SID_FM_CONVERTTO_IMAGEBUTTON   :
            case SID_FM_CONVERTTO_EDIT          :
            case SID_FM_CONVERTTO_BUTTON        :
            case SID_FM_CONVERTTO_FIXEDTEXT     :
            case SID_FM_CONVERTTO_LISTBOX       :
            case SID_FM_CONVERTTO_CHECKBOX      :
            case SID_FM_CONVERTTO_RADIOBUTTON   :
            case SID_FM_CONVERTTO_GROUPBOX      :
            case SID_FM_CONVERTTO_COMBOBOX      :
            case SID_FM_CONVERTTO_DATE          :
            case SID_FM_CONVERTTO_TIME          :
            case SID_FM_CONVERTTO_NUMERIC       :
            case SID_FM_CONVERTTO_FORMATTED     :
            case SID_FM_CONVERTTO_SPINBUTTON    :
            {
                if (!m_pFormView || !m_bDesignMode || !GetImpl()->canConvertCurrentSelectionToControl_Lock(FmXFormShell::SlotToIdent(nWhich)))
                    rSet.DisableItem( nWhich );
                else
                {
                    rSet.Put( SfxBoolItem( nWhich, false ) );
                    // just to have a defined state (available and not checked)
                }
            }
            break;
        }
        nWhich = aIter.NextWhich();
    }
}
 
 
void FmFormShell::GetFormState(SfxItemSet &rSet, sal_uInt16 nWhich)
{
    if  (   !GetImpl()->getNavController_Lock().is()
        ||  !isRowSetAlive(GetImpl()->getNavController_Lock()->getModel())
        ||  !m_pFormView
        ||  m_bDesignMode
        ||  !GetImpl()->getActiveForm_Lock().is()
        ||  GetImpl()->isInFilterMode_Lock()
        )
        rSet.DisableItem(nWhich);
    else
    {
        bool bEnable = false;
        try
        {
            switch (nWhich)
            {
            case SID_FM_VIEW_AS_GRID:
                if (GetImpl()->getHostFrame_Lock().is() && GetImpl()->getNavController_Lock().is())
                {
                    bEnable = true;
                    bool bDisplayingCurrent =
                        GetImpl()->getInternalForm_Lock(
                            Reference<XForm>(GetImpl()->getNavController_Lock()->getModel(), UNO_QUERY)
                        ) == GetImpl()->getExternallyDisplayedForm_Lock();
                    rSet.Put(SfxBoolItem(nWhich, bDisplayingCurrent));
                }
                break;
 
            case SID_FM_SEARCH:
            {
                Reference<css::beans::XPropertySet> const xNavSet(GetImpl()->getActiveForm_Lock(), UNO_QUERY);
                sal_Int32 nCount = ::comphelper::getINT32(xNavSet->getPropertyValue(FM_PROP_ROWCOUNT));
                bEnable = nCount != 0;
            }   break;
            case SID_FM_RECORD_ABSOLUTE:
            case SID_FM_RECORD_TOTAL:
            {
                FeatureState aState;
                GetImpl()->getNavControllerFeatures_Lock()->getState( nWhich, aState );
                if ( SID_FM_RECORD_ABSOLUTE == nWhich )
                {
                    sal_Int32 nPosition = 0;
                    aState.State >>= nPosition;
                    rSet.Put( SfxInt32Item( SID_FM_RECORD_ABSOLUTE, nPosition ) );
                }
                else if ( SID_FM_RECORD_TOTAL == nWhich )
                {
                    OUString sTotalCount;
                    aState.State >>= sTotalCount;
                    rSet.Put( SfxStringItem( nWhich, sTotalCount ) );
                }
                bEnable = aState.Enabled;
            }
            break;
 
            // first, prev, next, last, and absolute affect the nav controller, not the
            // active controller
            case SID_FM_RECORD_FIRST:
            case SID_FM_RECORD_PREV:
            case SID_FM_RECORD_NEXT:
            case SID_FM_RECORD_LAST:
            case SID_FM_RECORD_NEW:
            case SID_FM_RECORD_SAVE:
            case SID_FM_RECORD_UNDO:
            case SID_FM_RECORD_DELETE:
            case SID_FM_REFRESH:
            case SID_FM_REFRESH_FORM_CONTROL:
            case SID_FM_REMOVE_FILTER_SORT:
            case SID_FM_SORTUP:
            case SID_FM_SORTDOWN:
            case SID_FM_AUTOFILTER:
            case SID_FM_ORDERCRIT:
                bEnable = GetImpl()->IsFormSlotEnabled( nWhich, nullptr );
                break;
 
            case SID_FM_FORM_FILTERED:
            {
                FeatureState aState;
                bEnable = GetImpl()->IsFormSlotEnabled( nWhich, &aState );
 
                rSet.Put( SfxBoolItem( nWhich, ::comphelper::getBOOL( aState.State ) ) );
            }
            break;
 
            case SID_FM_FILTER_START:
                bEnable = GetImpl()->getActiveControllerFeatures_Lock()->canDoFormFilter();
                break;
            }
        }
        catch( const Exception& )
        {
            TOOLS_WARN_EXCEPTION("svx.form", "caught an exception while determining the state!");
        }
        if (!bEnable)
            rSet.DisableItem(nWhich);
    }
}
 
 
FmFormPage* FmFormShell::GetCurPage() const
{
    FmFormPage* pP = nullptr;
    if (m_pFormView && m_pFormView->GetSdrPageView())
        pP = dynamic_cast<FmFormPage*>( m_pFormView->GetSdrPageView()->GetPage() );
    return pP;
}
 
 
void FmFormShell::SetView( FmFormView* _pView )
{
    if ( m_pFormView )
    {
        if ( IsActive() )
            GetImpl()->viewDeactivated_Lock(*m_pFormView);
 
        m_pFormView->SetFormShell( nullptr, FmFormView::FormShellAccess() );
        m_pFormView = nullptr;
        m_pFormModel = nullptr;
    }
 
    if ( !_pView )
        return;
 
    m_pFormView = _pView;
    m_pFormView->SetFormShell( this, FmFormView::FormShellAccess() );
    m_pFormModel = static_cast<FmFormModel*>(&m_pFormView->GetModel());
 
    impl_setDesignMode( m_pFormView->IsDesignMode() );
 
    // We activate our view if we are activated ourself, but sometimes the Activate precedes the SetView.
    // But here we know both the view and our activation state so we at least are able to pass the latter
    // to the former.
    // FS - 30.06.99 - 67308
    if ( IsActive() )
        GetImpl()->viewActivated_Lock(*m_pFormView);
}
 
 
void FmFormShell::DetermineForms(bool bInvalidate)
{
    // are there forms on the current page
    bool bForms = GetImpl()->hasForms_Lock();
    if (bForms != m_bHasForms)
    {
        m_bHasForms = bForms;
        if (bInvalidate)
            UIFeatureChanged();
    }
}
 
 
bool FmFormShell::GetY2KState(sal_uInt16& nReturn)
{
    return GetImpl()->GetY2KState_Lock(nReturn);
}
 
 
void FmFormShell::SetY2KState(sal_uInt16 n)
{
    GetImpl()->SetY2KState_Lock(n);
}
 
 
void FmFormShell::Activate(bool bMDI)
{
    SfxShell::Activate(bMDI);
 
    if ( m_pFormView )
        GetImpl()->viewActivated_Lock(*m_pFormView, true);
}
 
 
void FmFormShell::Deactivate(bool bMDI)
{
    SfxShell::Deactivate(bMDI);
 
    if ( m_pFormView )
        GetImpl()->viewDeactivated_Lock(*m_pFormView, false);
}
 
 
void FmFormShell::ExecuteTextAttribute( SfxRequest& _rReq )
{
    m_pImpl->ExecuteTextAttribute_Lock(_rReq);
}
 
 
void FmFormShell::GetTextAttributeState( SfxItemSet& _rSet )
{
    m_pImpl->GetTextAttributeState_Lock(_rSet);
}
 
 
bool FmFormShell::IsActiveControl() const
{
    return m_pImpl->IsActiveControl_Lock(false);
}
 
 
void FmFormShell::ForgetActiveControl()
{
    m_pImpl->ForgetActiveControl_Lock();
}
 
 
void FmFormShell::SetControlActivationHandler( const Link<LinkParamNone*,void>& _rHdl )
{
    m_pImpl->SetControlActivationHandler_Lock(_rHdl);
}
 
 
namespace
{
    SdrUnoObj* lcl_findUnoObject( const SdrObjList& _rObjList, const Reference< XControlModel >& _rxModel )
    {
        SdrObjListIter aIter( &_rObjList );
        while ( aIter.IsMore() )
        {
            SdrObject* pObject = aIter.Next();
            SdrUnoObj* pUnoObject = dynamic_cast<SdrUnoObj*>( pObject  );
            if ( !pUnoObject )
                continue;
 
            Reference< XControlModel > xControlModel = pUnoObject->GetUnoControlModel();
            if ( !xControlModel.is() )
                continue;
 
            if ( _rxModel == xControlModel )
                return pUnoObject;
        }
        return nullptr;
    }
}
 
 
void FmFormShell::ToggleControlFocus( const SdrUnoObj& i_rUnoObject, const SdrView& i_rView, const OutputDevice& i_rDevice ) const
{
    try
    {
        // check if the focus currently is in a control
        // Well, okay, do it the other way 'round: Check whether the current control of the active controller
        // actually has the focus. This should be equivalent.
        const bool bHasControlFocus = GetImpl()->HasControlFocus_Lock();
 
        if ( bHasControlFocus )
        {
            vcl::Window* pWindow = i_rDevice.GetOwnerWindow();
            OSL_ENSURE( pWindow, "FmFormShell::ToggleControlFocus: I need a Window, really!" );
            if ( pWindow )
                pWindow->GrabFocus();
        }
        else
        {
            Reference< XControl > xControl;
            GetFormControl( i_rUnoObject.GetUnoControlModel(), i_rView, i_rDevice, xControl );
            Reference< XWindow > xControlWindow( xControl, UNO_QUERY );
            if ( xControlWindow.is() )
                xControlWindow->setFocus();
        }
    }
    catch( const Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("svx");
    }
}
 
 
namespace
{
    class FocusableControlsFilter : public svx::ISdrObjectFilter
    {
    public:
        FocusableControlsFilter( const SdrView& i_rView, const OutputDevice& i_rDevice )
            :m_rView( i_rView )
            ,m_rDevice( i_rDevice )
        {
        }
 
    public:
        virtual bool    includeObject( const SdrObject& i_rObject ) const override
        {
            const SdrUnoObj* pUnoObj = dynamic_cast< const SdrUnoObj* >( &i_rObject );
            if ( !pUnoObj )
                return false;
 
            Reference< XControl > xControl = pUnoObj->GetUnoControl( m_rView, m_rDevice );
            return FmXFormView::isFocusable( xControl );
        }
 
    private:
        const SdrView&      m_rView;
        const OutputDevice& m_rDevice;
    };
}
 
 
::std::unique_ptr< svx::ISdrObjectFilter > FmFormShell::CreateFocusableControlFilter( const SdrView& i_rView, const OutputDevice& i_rDevice )
{
    ::std::unique_ptr< svx::ISdrObjectFilter > pFilter;
 
    if ( !i_rView.IsDesignMode() )
        pFilter.reset( new FocusableControlsFilter( i_rView, i_rDevice ) );
 
    return pFilter;
}
 
 
SdrUnoObj* FmFormShell::GetFormControl( const Reference< XControlModel >& _rxModel, const SdrView& _rView, const OutputDevice& _rDevice, Reference< XControl >& _out_rxControl ) const
{
    if ( !_rxModel.is() )
        return nullptr;
 
    // we can only retrieve controls for SdrObjects which belong to page which is actually displayed in the given view
    SdrPageView* pPageView = _rView.GetSdrPageView();
    SdrPage* pPage = pPageView ? pPageView->GetPage() : nullptr;
    OSL_ENSURE( pPage, "FmFormShell::GetFormControl: no page displayed in the given view!" );
    if ( !pPage )
        return nullptr;
 
    SdrUnoObj* pUnoObject = lcl_findUnoObject( *pPage, _rxModel );
    if ( pUnoObject )
    {
        _out_rxControl = pUnoObject->GetUnoControl( _rView, _rDevice );
        return pUnoObject;
    }
 
#if OSL_DEBUG_LEVEL > 0
    // perhaps we are fed with a control model which lives on a page other than the one displayed
    // in the given view. This is worth being reported as error, in non-product builds.
    FmFormModel* pModel = GetFormModel();
    if ( pModel )
    {
        sal_uInt16 pageCount = pModel->GetPageCount();
        for ( sal_uInt16 page = 0; page < pageCount; ++page )
        {
            pPage = pModel->GetPage( page );
            OSL_ENSURE( pPage, "FmFormShell::GetFormControl: NULL page encountered!" );
            if  ( !pPage )
                continue;
 
            pUnoObject = lcl_findUnoObject( *pPage, _rxModel );
            OSL_ENSURE( !pUnoObject, "FmFormShell::GetFormControl: the given control model belongs to a wrong page (displayed elsewhere)!" );
        }
    }
#else
    (void) this; // avoid loplugin:staticmethods
#endif
 
    return nullptr;
}
 
 
Reference< runtime::XFormController > FmFormShell::GetFormController( const Reference< XForm >& _rxForm, const SdrView& _rView, const OutputDevice& _rDevice )
{
    const FmFormView* pFormView = dynamic_cast< const FmFormView* >( &_rView );
    if ( !pFormView )
        return nullptr;
 
    return pFormView->GetFormController( _rxForm, _rDevice );
}
 
 
void FmFormShell::SetDesignMode( bool _bDesignMode )
{
    if ( _bDesignMode == m_bDesignMode )
        return;
 
    FmFormModel* pModel = GetFormModel();
    if (pModel)
        // Switch off the undo environment for the time of the transition. This ensures that
        // one can also change non-transient properties there. (It should be done with
        // caution, however, and it should always be reversed when one switches the mode back.
        // An example is the setting of the maximum text length by the OEditModel on its control.)
        pModel->GetUndoEnv().Lock();
 
    // then the actual switch
    if ( m_bDesignMode || PrepareClose() )
        impl_setDesignMode(!m_bDesignMode );
 
    // and my undo environment back on
    if ( pModel )
        pModel->GetUndoEnv().UnLock();
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

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

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

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

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

V1004 The 'GetViewShell()' pointer was used unsafely after it was verified against nullptr. Check lines: 730, 739.