Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/svx/source/form/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 65 kB image not shown  

Quelle  fmvwimp.cxx

  Sprache: C
 

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */



#include <memory>
#include <fmdocumentclassification.hxx>
#include <fmobj.hxx>
#include <fmpgeimp.hxx>
#include <fmprop.hxx>
#include <svx/strings.hrc>
#include <fmservs.hxx>
#include <fmshimp.hxx>
#include <svx/fmtools.hxx>
#include <fmvwimp.hxx>
#include <formcontrolfactory.hxx>
#include <svx/sdrpaintwindow.hxx>
#include <svx/svditer.hxx>
#include <svx/dataaccessdescriptor.hxx>
#include <svx/dialmgr.hxx>
#include <svx/svdobjkind.hxx>
#include <svx/fmmodel.hxx>
#include <svx/fmpage.hxx>
#include <svx/fmshell.hxx>
#include <svx/fmview.hxx>
#include <svx/sdrpagewindow.hxx>
#include <svx/svdogrp.hxx>
#include <svx/svdpagv.hxx>
#include <svx/xmlexchg.hxx>
#include <toolkit/helper/vclunohelper.hxx>

#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
#include <com/sun/star/sdbc/XRowSet.hpp>
#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
#include <com/sun/star/util/XNumberFormats.hpp>
#include <com/sun/star/sdb/CommandType.hpp>
#include <com/sun/star/sdbc/DataType.hpp>
#include <com/sun/star/form/FormComponentType.hpp>
#include <com/sun/star/form/FormButtonType.hpp>
#include <com/sun/star/form/binding/XBindableValue.hpp>
#include <com/sun/star/form/binding/XValueBinding.hpp>
#include <com/sun/star/form/runtime/FormController.hpp>
#include <com/sun/star/form/submission/XSubmissionSupplier.hpp>
#include <com/sun/star/awt/XTabControllerModel.hpp>
#include <com/sun/star/awt/XControlContainer.hpp>
#include <com/sun/star/awt/XTabController.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/awt/XControl.hpp>
#include <com/sun/star/sdbc/SQLException.hpp>
#include <com/sun/star/container/XContainer.hpp>

#include <comphelper/namedvaluecollection.hxx>
#include <comphelper/property.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/types.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <unotools/moduleoptions.hxx>
#include <tools/debug.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <sal/log.hxx>
#include <utility>
#include <vcl/svapp.hxx>
#include <vcl/stdtext.hxx>
#include <vcl/window.hxx>
#include <connectivity/dbtools.hxx>

#include <algorithm>

using namespace ::comphelper;
using namespace ::svx;
using namespace ::svxform;
using namespace ::dbtools;

    using namespace ::com::sun::star;
    using ::com::sun::star::uno::Exception;
    using ::com::sun::star::uno::XInterface;
    using ::com::sun::star::uno::Sequence;
    using ::com::sun::star::uno::UNO_QUERY;
    using ::com::sun::star::uno::UNO_QUERY_THROW;
    using ::com::sun::star::uno::UNO_SET_THROW;
    using ::com::sun::star::uno::Type;
    using ::com::sun::star::uno::Reference;
    using ::com::sun::star::uno::Any;
    using ::com::sun::star::uno::XComponentContext;
    using ::com::sun::star::form::FormButtonType_SUBMIT;
    using ::com::sun::star::form::binding::XValueBinding;
    using ::com::sun::star::form::binding::XBindableValue;
    using ::com::sun::star::lang::XComponent;
    using ::com::sun::star::container::XIndexAccess;
    using ::com::sun::star::form::runtime::FormController;
    using ::com::sun::star::form::runtime::XFormController;
    using ::com::sun::star::script::XEventAttacherManager;
    using ::com::sun::star::awt::XTabControllerModel;
    using ::com::sun::star::container::XChild;
    using ::com::sun::star::task::XInteractionHandler;
    using ::com::sun::star::awt::XTabController;
    using ::com::sun::star::awt::XControlContainer;
    using ::com::sun::star::awt::XControl;
    using ::com::sun::star::form::XFormComponent;
    using ::com::sun::star::form::XForm;
    using ::com::sun::star::lang::IndexOutOfBoundsException;
    using ::com::sun::star::container::XContainer;
    using ::com::sun::star::container::ContainerEvent;
    using ::com::sun::star::lang::EventObject;
    using ::com::sun::star::sdb::SQLErrorEvent;
    using ::com::sun::star::sdbc::XRowSet;
    using ::com::sun::star::beans::XPropertySet;
    using ::com::sun::star::container::XElementAccess;
    using ::com::sun::star::awt::XWindow;
    using ::com::sun::star::awt::FocusEvent;
    using ::com::sun::star::ui::dialogs::XExecutableDialog;
    using ::com::sun::star::sdbc::XDataSource;
    using ::com::sun::star::container::XIndexContainer;
    using ::com::sun::star::sdbc::XConnection;
    using ::com::sun::star::container::XNameAccess;
    using ::com::sun::star::sdbc::SQLException;
    using ::com::sun::star::util::XNumberFormatsSupplier;
    using ::com::sun::star::util::XNumberFormats;
    using ::com::sun::star::beans::XPropertySetInfo;

    namespace FormComponentType = ::com::sun::star::form::FormComponentType;
    namespace CommandType = ::com::sun::star::sdb::CommandType;
    namespace DataType = ::com::sun::star::sdbc::DataType;


class FmXFormView::ObjectRemoveListener : public SfxListener
{
    FmXFormView* m_pParent;
public:
    explicit ObjectRemoveListener( FmXFormView* pParent );
    virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
};

FormViewPageWindowAdapter::FormViewPageWindowAdapter( css::uno::Reference<css::uno::XComponentContext> _xContext, const SdrPageWindow& _rWindow, FmXFormView* _pViewImpl )
:   m_xControlContainer( _rWindow.GetControlContainer() ),
    m_xContext(std::move( _xContext )),
    m_pViewImpl( _pViewImpl ),
    m_pWindow( _rWindow.GetPaintWindow().GetOutputDevice().GetOwnerWindow() )
{

    // create an XFormController for every form
    FmFormPage* pFormPage = dynamic_cast< FmFormPage* >( _rWindow.GetPageView().GetPage() );
    DBG_ASSERT( pFormPage, "FormViewPageWindowAdapter::FormViewPageWindowAdapter: no FmFormPage found!" );
    if ( !pFormPage )
        return;

    try
    {
        Reference< XIndexAccess > xForms( pFormPage->GetForms(), UNO_QUERY_THROW );
        sal_uInt32 nLength = xForms->getCount();
        for (sal_uInt32 i = 0; i < nLength; i++)
        {
            Reference< XForm > xForm( xForms->getByIndex(i), UNO_QUERY );
            if ( xForm.is() )
                setController( xForm, nullptr );
        }
    }
    catch (const Exception&)
    {
        DBG_UNHANDLED_EXCEPTION("svx");
    }
}

FormViewPageWindowAdapter::~FormViewPageWindowAdapter()
{
}

void FormViewPageWindowAdapter::dispose()
{
    for (   ::std::vector< Reference< XFormController > >::const_iterator i = m_aControllerList.begin();
            i != m_aControllerList.end();
            ++i
        )
    {
        try
        {
            Reference< XFormController > xController( *i, UNO_SET_THROW );

            // detaching the events
            Reference< XChild > xControllerModel( xController->getModel(), UNO_QUERY );
            if ( xControllerModel.is() )
            {
                Reference< XEventAttacherManager >  xEventManager( xControllerModel->getParent(), UNO_QUERY_THROW );
                Reference< XInterface > xControllerNormalized( xController, UNO_QUERY_THROW );
                xEventManager->detach( i - m_aControllerList.begin(), xControllerNormalized );
            }

            // dispose the formcontroller
            xController->dispose();
        }
        catch (const Exception&)
        {
            DBG_UNHANDLED_EXCEPTION("svx");
        }
    }

    m_aControllerList.clear();
}

sal_Bool SAL_CALL FormViewPageWindowAdapter::hasElements()
{
    return getCount() != 0;
}

Type SAL_CALL  FormViewPageWindowAdapter::getElementType()
{
    return cppu::UnoType<XFormController>::get();
}

// XIndexAccess
sal_Int32 SAL_CALL FormViewPageWindowAdapter::getCount()
{
    return m_aControllerList.size();
}

Any SAL_CALL FormViewPageWindowAdapter::getByIndex(sal_Int32 nIndex)
{
    if (nIndex < 0 ||
        nIndex >= getCount())
        throw IndexOutOfBoundsException();

    Any aElement;
    aElement <<= m_aControllerList[nIndex];
    return aElement;
}

void SAL_CALL FormViewPageWindowAdapter::makeVisible( const Reference< XControl >& Control )
{
    SolarMutexGuard aSolarGuard;

    Reference< XWindow >  xWindow( Control, UNO_QUERY );
    if ( xWindow.is() && m_pViewImpl->getView() && m_pWindow )
    {
        awt::Rectangle aRect = xWindow->getPosSize();
        ::tools::Rectangle aNewRect( aRect.X, aRect.Y, aRect.X + aRect.Width, aRect.Y + aRect.Height );
        aNewRect = m_pWindow->PixelToLogic( aNewRect );
        m_pViewImpl->getView()->MakeVisible( aNewRect, *m_pWindow );
    }
}

static Reference< XFormController >  getControllerSearchChildren( const Reference< XIndexAccess > & xIndex, const Reference< XTabControllerModel > & xModel)
{
    if (xIndex.is() && xIndex->getCount())
    {
        Reference< XFormController >  xController;

        for (sal_Int32 n = xIndex->getCount(); n-- && !xController.is(); )
        {
            xIndex->getByIndex(n) >>= xController;
            if (xModel.get() == xController->getModel().get())
                return xController;
            else
            {
                xController = getControllerSearchChildren(xController, xModel);
                if ( xController.is() )
                    return xController;
            }
        }
    }
    return Reference< XFormController > ();
}

// Search the according controller
Reference< XFormController >  FormViewPageWindowAdapter::getController( const Reference< XForm > & xForm ) const
{
    Reference< XTabControllerModel >  xModel(xForm, UNO_QUERY);
    for (const auto& rpController : m_aControllerList)
    {
        if (rpController->getModel().get() == xModel.get())
            return rpController;

        // the current-round controller isn't the right one. perhaps one of its children ?
        Reference< XFormController >  xChildSearch = getControllerSearchChildren(Reference< XIndexAccess > (rpController, UNO_QUERY), xModel);
        if (xChildSearch.is())
            return xChildSearch;
    }
    return Reference< XFormController > ();
}


void FormViewPageWindowAdapter::setController(const Reference< XForm > & xForm, const Reference< XFormController >& _rxParentController )
{
    DBG_ASSERT( xForm.is(), "FormViewPageWindowAdapter::setController: there should be a form!" );
    Reference< XIndexAccess >  xFormCps(xForm, UNO_QUERY);
    if (!xFormCps.is())
        return;

    Reference< XTabControllerModel >  xTabOrder(xForm, UNO_QUERY);

    // create a form controller
    Reference< XFormController > xController( FormController::create(m_xContext) );

    Reference< XInteractionHandler > xHandler;
    if ( _rxParentController.is() )
        xHandler = _rxParentController->getInteractionHandler();
    else
    {
        // TODO: should we create a default handler? Not really necessary, since the
        // FormController itself has a default fallback
    }
    if ( xHandler.is() )
        xController->setInteractionHandler( xHandler );

    xController->setContext( this );

    xController->setModel( xTabOrder );
    xController->setContainer( m_xControlContainer );
    xController->activateTabOrder();
    xController->addActivateListener( m_pViewImpl );

    if ( _rxParentController.is() )
        _rxParentController->addChildController( xController );
    else
    {
        m_aControllerList.push_back(xController);

        xController->setParent( *this );

        // attaching the events
        Reference< XEventAttacherManager > xEventManager( xForm->getParent(), UNO_QUERY );
        xEventManager->attach(m_aControllerList.size() - 1, Reference<XInterface>( xController, UNO_QUERY ), Any(xController) );
    }

    // now go through the subforms
    sal_uInt32 nLength = xFormCps->getCount();
    Reference< XForm >  xSubForm;
    for (sal_uInt32 i = 0; i < nLength; i++)
    {
        if ( xFormCps->getByIndex(i) >>= xSubForm )
            setController( xSubForm, xController );
    }
}


void FormViewPageWindowAdapter::updateTabOrder( const Reference< XForm >& _rxForm )
{
    OSL_PRECOND( _rxForm.is(), "FormViewPageWindowAdapter::updateTabOrder: illegal argument!" );
    if ( !_rxForm.is() )
        return;

    try
    {
        Reference< XTabController > xTabCtrl( getController( _rxForm ) );
        if ( xTabCtrl.is() )
        {   // if there already is a TabController for this form, then delegate the "updateTabOrder" request
            xTabCtrl->activateTabOrder();
        }
        else
        {   // otherwise, create a TabController

            // if it's a sub form, then we must ensure there exist TabControllers
            // for all its ancestors, too
            Reference< XForm > xParentForm( _rxForm->getParent(), UNO_QUERY );
            // there is a parent form -> look for the respective controller
            Reference< XFormController > xParentController;
            if ( xParentForm.is() )
                xParentController = getController( xParentForm );

            setController( _rxForm, xParentController );
        }
    }
    catch (const Exception&)
    {
        DBG_UNHANDLED_EXCEPTION("svx");
    }
}


FmXFormView::FmXFormView(FmFormView* _pView )
    :m_pMarkedGrid(nullptr)
    ,m_pView(_pView)
    ,m_nActivationEvent(nullptr)
    ,m_nErrorMessageEvent( nullptr )
    ,m_nAutoFocusEvent( nullptr )
    ,m_nControlWizardEvent( nullptr )
    ,m_bFirstActivation( true )
    ,m_isTabOrderUpdateSuspended( false )
{
}


void FmXFormView::cancelEvents()
{
    if ( m_nActivationEvent )
    {
        Application::RemoveUserEvent( m_nActivationEvent );
        m_nActivationEvent = nullptr;
    }

    if ( m_nErrorMessageEvent )
    {
        Application::RemoveUserEvent( m_nErrorMessageEvent );
        m_nErrorMessageEvent = nullptr;
    }

    if ( m_nAutoFocusEvent )
    {
        Application::RemoveUserEvent( m_nAutoFocusEvent );
        m_nAutoFocusEvent = nullptr;
    }

    if ( m_nControlWizardEvent )
    {
        Application::RemoveUserEvent( m_nControlWizardEvent );
        m_nControlWizardEvent = nullptr;
    }
}


void FmXFormView::notifyViewDying( )
{
    DBG_ASSERT( m_pView, "FmXFormView::notifyViewDying: my view already died!" );
    m_pView = nullptr;
    cancelEvents();
}


FmXFormView::~FmXFormView()
{
    DBG_ASSERT( m_aPageWindowAdapters.empty(), "FmXFormView::~FmXFormView: Window list not empty!" );
    for (const auto& rpAdapter : m_aPageWindowAdapters)
    {
        rpAdapter->dispose();
    }

    cancelEvents();
}

//      EventListener

void SAL_CALL FmXFormView::disposing(const EventObject& Source)
{
    if ( m_xWindow.is() && Source.Source == m_xWindow )
    {
        m_xWindow->removeFocusListener(this);
        if ( m_pView )
        {
            m_pView->SetMoveOutside( false, FmFormView::ImplAccess() );
        }
        m_xWindow = nullptr;
    }
}

// XFormControllerListener

void SAL_CALL FmXFormView::formActivated(const EventObject& rEvent)
{
    if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() )
        m_pView->GetFormShell()->GetImpl()->formActivated( rEvent );
}


void SAL_CALL FmXFormView::formDeactivated(const EventObject& rEvent)
{
    if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() )
        m_pView->GetFormShell()->GetImpl()->formDeactivated( rEvent );
}

// XContainerListener

void SAL_CALL FmXFormView::elementInserted(const ContainerEvent& evt)
{
    try
    {
        Reference< XControlContainer > xControlContainer( evt.Source, UNO_QUERY_THROW );
        Reference< XControl > xControl( evt.Element, UNO_QUERY_THROW );
        Reference< XFormComponent > xControlModel( xControl->getModel(), UNO_QUERY_THROW );
        Reference< XForm > xForm( xControlModel->getParent(), UNO_QUERY_THROW );

        if ( m_isTabOrderUpdateSuspended )
        {
            // remember the container and the control, so we can update the tab order on resumeTabOrderUpdate
            m_aNeedTabOrderUpdate[ xControlContainer ].insert( xForm );
        }
        else
        {
            rtl::Reference< FormViewPageWindowAdapter > pAdapter = findWindow( xControlContainer );
            if ( pAdapter.is() )
                pAdapter->updateTabOrder( xForm );
        }
    }
    catch (const Exception&)
    {
        DBG_UNHANDLED_EXCEPTION("svx");
    }
}


void SAL_CALL FmXFormView::elementReplaced(const ContainerEvent& evt)
{
    elementInserted(evt);
}


void SAL_CALL FmXFormView::elementRemoved(const ContainerEvent& /*evt*/)
{
}


rtl::Reference< FormViewPageWindowAdapter > FmXFormView::findWindow( const Reference< XControlContainer >& _rxCC )  const
{
    auto i = std::find_if(m_aPageWindowAdapters.begin(), m_aPageWindowAdapters.end(),
        [&_rxCC](const rtl::Reference< FormViewPageWindowAdapter >& rpAdapter) { return _rxCC == rpAdapter->getControlContainer(); });
    if (i != m_aPageWindowAdapters.end())
        return *i;
    return nullptr;
}


void FmXFormView::addWindow(const SdrPageWindow& rWindow)
{
    FmFormPage* pFormPage = dynamic_cast<FmFormPage*>( rWindow.GetPageView().GetPage()  );
    if ( !pFormPage )
        return;

    const Reference< XControlContainer >& xCC = rWindow.GetControlContainer();
    if  (   xCC.is()
        &&  ( !findWindow( xCC ).is() )
        )
    {
        rtl::Reference< FormViewPageWindowAdapter > pAdapter = new FormViewPageWindowAdapter( comphelper::getProcessComponentContext(), rWindow, this );
        m_aPageWindowAdapters.push_back( pAdapter );

        // listen at the ControlContainer to notice changes
        Reference< XContainer >  xContainer( xCC, UNO_QUERY );
        if ( xContainer.is() )
            xContainer->addContainerListener( this );
    }
}


void FmXFormView::removeWindow( const Reference< XControlContainer >& _rxCC )
{
    // Is called if
    // - the design mode is being switched to
    // - a window is deleted while in the design mode
    // - the control container for a window is removed while the active mode is on

    auto i = std::find_if(m_aPageWindowAdapters.begin(), m_aPageWindowAdapters.end(),
        [&_rxCC](const rtl::Reference< FormViewPageWindowAdapter >& rpAdapter) { return _rxCC == rpAdapter->getControlContainer(); });
    if (i != m_aPageWindowAdapters.end())
    {
        Reference< XContainer >  xContainer( _rxCC, UNO_QUERY );
        if ( xContainer.is() )
            xContainer->removeContainerListener( this );

        (*i)->dispose();
        m_aPageWindowAdapters.erase( i );
    }
}

void FmXFormView::displayAsyncErrorMessage( const SQLErrorEvent& _rEvent )
{
    DBG_ASSERT( nullptr == m_nErrorMessageEvent, "FmXFormView::displayAsyncErrorMessage: not too fast, please!" );
        // This should not happen - usually, the PostUserEvent is faster than any possible user
        // interaction which could trigger a new error. If it happens, we need a queue for the events.
    m_aAsyncError = _rEvent;
    m_nErrorMessageEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnDelayedErrorMessage ) );
}

IMPL_LINK_NOARG(FmXFormView, OnDelayedErrorMessage, void*, void)
{
    m_nErrorMessageEvent = nullptr;
    displayException(m_aAsyncError, GetParentWindow());
}

void FmXFormView::onFirstViewActivation( const FmFormModel* _pDocModel )
{
    if ( _pDocModel && _pDocModel->GetAutoControlFocus() )
        m_nAutoFocusEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnAutoFocus ) );
}

void FmXFormView::suspendTabOrderUpdate()
{
    OSL_ENSURE( !m_isTabOrderUpdateSuspended, "FmXFormView::suspendTabOrderUpdate: nesting not allowed!" );
    m_isTabOrderUpdateSuspended = true;
}

void FmXFormView::resumeTabOrderUpdate()
{
    OSL_ENSURE( m_isTabOrderUpdateSuspended, "FmXFormView::resumeTabOrderUpdate: not suspended!" );
    m_isTabOrderUpdateSuspended = false;

    // update the tab orders for all components which were collected since the suspendTabOrderUpdate call.
    for (const auto& rContainer : m_aNeedTabOrderUpdate)
    {
        rtl::Reference< FormViewPageWindowAdapter > pAdapter = findWindow( rContainer.first );
        if ( !pAdapter.is() )
            continue;

        for (const auto& rForm : rContainer.second)
        {
            pAdapter->updateTabOrder( rForm );
        }
    }
    m_aNeedTabOrderUpdate.clear();
}

namespace
{
    bool isActivableDatabaseForm(const Reference< XFormController > &xController)
    {
        // only database forms are to be activated
        Reference< XRowSet >  xForm(xController->getModel(), UNO_QUERY);
        if ( !xForm.is() || !getConnection( xForm ).is() )
            return false;

        Reference< XPropertySet > xFormSet( xForm, UNO_QUERY );
        if ( !xFormSet.is() )
        {
            SAL_WARN( "svx.form""FmXFormView::OnActivate: a form which does not have properties?" );
            return false;
        }

        const OUString aSource = ::comphelper::getString( xFormSet->getPropertyValue( FM_PROP_COMMAND ) );

        return !aSource.isEmpty();
    }

    class find_active_databaseform
    {
        const Reference< XFormController > xActiveController;

    public:

        explicit find_active_databaseform( const Reference< XFormController >& _xActiveController )
            : xActiveController(_xActiveController )
        {}

        Reference < XFormController > operator() (const Reference< XFormController > &xController)
        {
            if(xController == xActiveController && isActivableDatabaseForm(xController))
                return xController;

            if ( !xController.is() )
            {
                SAL_WARN( "svx.form""FmXFormView::OnActivate: a form controller which does not have children?" );
                return nullptr;
            }

            for(sal_Int32 i = 0; i < xController->getCount(); ++i)
            {
                const Any a(xController->getByIndex(i));
                Reference < XFormController > xI;
                if ((a >>= xI) && xI.is())
                {
                    Reference < XFormController > xRes(operator()(xI));
                    if (xRes.is())
                        return xRes;
                }
            }

            return nullptr;
        }
    };
}


IMPL_LINK_NOARG(FmXFormView, OnActivate, void*, void)
{
    m_nActivationEvent = nullptr;

    if ( !m_pView )
    {
        OSL_FAIL( "FmXFormView::OnActivate: well... seems we have a timing problem (the view already died)!" );
        return;
    }

    // setting the controller to activate
    if (!(m_pView->GetFormShell() && m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW))
        return;

    FmXFormShell* const pShImpl =  m_pView->GetFormShell()->GetImpl();

    if(!pShImpl)
        return;

    find_active_databaseform fad(pShImpl->getActiveController_Lock());

    vcl::Window* pWindow = m_pView->GetActualOutDev()->GetOwnerWindow();
    rtl::Reference< FormViewPageWindowAdapter > pAdapter = m_aPageWindowAdapters.empty() ? nullptr : m_aPageWindowAdapters[0];
    for (const auto& rpPageWindowAdapter : m_aPageWindowAdapters)
    {
        if ( pWindow == rpPageWindowAdapter->getWindow() )
            pAdapter = rpPageWindowAdapter;
    }

    if ( !pAdapter.is() )
        return;

    Reference< XFormController > xControllerToActivate;
    for (const Reference< XFormController > & xController : pAdapter->GetList())
    {
        if ( !xController.is() )
            continue;

        {
            Reference< XFormController > xActiveController(fad(xController));
            if (xActiveController.is())
            {
                xControllerToActivate = std::move(xActiveController);
                break;
            }
        }

        if(xControllerToActivate.is() || !isActivableDatabaseForm(xController))
            continue;

        xControllerToActivate = xController;
    }
    pShImpl->setActiveController_Lock(xControllerToActivate);
}


void FmXFormView::Activate(bool bSync)
{
    if (m_nActivationEvent)
    {
        Application::RemoveUserEvent(m_nActivationEvent);
        m_nActivationEvent = nullptr;
    }

    if (bSync)
    {
        LINK(this,FmXFormView,OnActivate).Call(nullptr);
    }
    else
        m_nActivationEvent = Application::PostUserEvent(LINK(this,FmXFormView,OnActivate));
}


void FmXFormView::Deactivate(bool bDeactivateController)
{
    if (m_nActivationEvent)
    {
        Application::RemoveUserEvent(m_nActivationEvent);
        m_nActivationEvent = nullptr;
    }

    FmXFormShell* pShImpl =  m_pView->GetFormShell() ? m_pView->GetFormShell()->GetImpl() : nullptr;
    if (pShImpl && bDeactivateController)
        pShImpl->setActiveController_Lock(nullptr);
}


FmFormShell* FmXFormView::GetFormShell() const
{
    return m_pView ? m_pView->GetFormShell() : nullptr;
}

void FmXFormView::AutoFocus()
{
    if (m_nAutoFocusEvent)
        Application::RemoveUserEvent(m_nAutoFocusEvent);

    m_nAutoFocusEvent = Application::PostUserEvent(LINK(this, FmXFormView, OnAutoFocus));
}


bool FmXFormView::isFocusable( const Reference< XControl >& i_rControl )
{
    if ( !i_rControl.is() )
        return false;

    try
    {
        Reference< XPropertySet > xModelProps( i_rControl->getModel(), UNO_QUERY_THROW );

        // only enabled controls are allowed to participate
        bool bEnabled = false;
        OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_ENABLED ) >>= bEnabled );
        if ( !bEnabled )
            return false;

        // check the class id of the control model
        sal_Int16 nClassId = FormComponentType::CONTROL;
        OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );

        // controls which are not focussable
        if  (   ( FormComponentType::CONTROL != nClassId )
            &&  ( FormComponentType::IMAGEBUTTON != nClassId )
            &&  ( FormComponentType::GROUPBOX != nClassId )
            &&  ( FormComponentType::FIXEDTEXT != nClassId )
            &&  ( FormComponentType::HIDDENCONTROL != nClassId )
            &&  ( FormComponentType::IMAGECONTROL != nClassId )
            &&  ( FormComponentType::SCROLLBAR != nClassId )
            &&  ( FormComponentType::SPINBUTTON!= nClassId )
            )
        {
            return true;
        }
    }
    catch (const Exception&)
    {
        DBG_UNHANDLED_EXCEPTION("svx");
    }
    return false;
}


static Reference< XControl > lcl_firstFocussableControl( const Sequence< Reference< XControl > >&&nbsp;_rControls )
{
    Reference< XControl > xReturn;

    // loop through all the controls
    for ( auto const & control : _rControls )
    {
        if ( !control.is() )
            continue;

        if ( FmXFormView::isFocusable( control ) )
        {
            xReturn = control;
            break;
        }
    }

    if ( !xReturn.is() && _rControls.hasElements() )
        xReturn = _rControls[0];

    return xReturn;
}


namespace
{

    void lcl_ensureControlsOfFormExist_nothrow( const SdrPage& _rPage, const SdrView&&nbsp;_rView, const vcl::Window& _rWindow, const Reference< XForm >& _rxForm )
    {
        try
        {
            Reference< XInterface > xNormalizedForm( _rxForm, UNO_QUERY_THROW );

            SdrObjListIter aSdrObjectLoop( &_rPage, SdrIterMode::DeepNoGroups );
            while ( aSdrObjectLoop.IsMore() )
            {
                FmFormObj* pFormObject = FmFormObj::GetFormObject( aSdrObjectLoop.Next() );
                if ( !pFormObject )
                    continue;

                Reference< XChild > xModel( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW );
                Reference< XInterface > xModelParent( xModel->getParent(), UNO_QUERY );

                if ( xNormalizedForm.get() != xModelParent.get() )
                    continue;

                pFormObject->GetUnoControl( _rView, *_rWindow.GetOutDev() );
            }
        }
        catch (const Exception&)
        {
            DBG_UNHANDLED_EXCEPTION("svx");
        }
    }
}


Reference< XFormController > FmXFormView::getFormController( const Reference< XForm >& _rxForm, const OutputDevice& _rDevice ) const
{
    Reference< XFormController > xController;

    for (const rtl::Reference< FormViewPageWindowAdapter >& pAdapter : m_aPageWindowAdapters)
    {
        if ( !pAdapter )
        {
            SAL_WARN( "svx.form""FmXFormView::getFormController: invalid page window adapter!" );
            continue;
        }

        if ( pAdapter->getWindow() != _rDevice.GetOwnerWindow() )
            // wrong device
            continue;

        xController = pAdapter->getController( _rxForm );
        if ( xController.is() )
            break;
    }
    return xController;
}


IMPL_LINK_NOARG(FmXFormView, OnAutoFocus, void*, void)
{
    m_nAutoFocusEvent = nullptr;

    // go to the first form of our page, examine it's TabController, go to its first (in terms of the tab order)
    // control, give it the focus

    SdrPageView *pPageView = m_pView ? m_pView->GetSdrPageView() : nullptr;
    SdrPage *pSdrPage = pPageView ? pPageView->GetPage() : nullptr;
    // get the forms collection of the page we belong to
    FmFormPage* pPage = dynamic_cast<FmFormPage*>( pSdrPage  );
    Reference< XIndexAccess > xForms( pPage ? Reference< XIndexAccess >( pPage->GetForms() ) : Reference< XIndexAccess >() );

    const rtl::Reference< FormViewPageWindowAdapter > pAdapter = m_aPageWindowAdapters.empty() ? nullptr : m_aPageWindowAdapters[0];
    const vcl::Window* pWindow = pAdapter ? pAdapter->getWindow() : nullptr;

    ENSURE_OR_RETURN_VOID( xForms.is() && pWindow, "FmXFormView::OnAutoFocus: could not collect all essentials!" );

    try
    {
        // go for the tab controller of the first form
        if ( !xForms->getCount() )
            return;
        Reference< XForm > xForm( xForms->getByIndex( 0 ), UNO_QUERY_THROW );
        Reference< XTabController > xTabController( pAdapter->getController( xForm ), UNO_QUERY_THROW );

        // go for the first control of the controller
        Sequence< Reference< XControl > > aControls( xTabController->getControls() );
        if ( !aControls.hasElements() )
        {
            Reference< XElementAccess > xFormElementAccess( xForm, UNO_QUERY_THROW );
            if (xFormElementAccess->hasElements() && pPage && m_pView)
            {
                // there are control models in the form, but no controls, yet.
                // Well, since some time controls are created on demand only. In particular,
                // they're normally created when they're first painted.
                // Unfortunately, the FormController does not have any way to
                // trigger the creation itself, so we must hack this ...
                lcl_ensureControlsOfFormExist_nothrow( *pPage, *m_pView, *pWindow, xForm );
                aControls = xTabController->getControls();
                OSL_ENSURE( aControls.hasElements(), "FmXFormView::OnAutoFocus: no controls at all!" );
            }
        }

        // set the focus to this first control
        Reference< XWindow > xControlWindow( lcl_firstFocussableControl( aControls ), UNO_QUERY );
        if ( !xControlWindow.is() )
            return;

        xControlWindow->setFocus();

        // ensure that the control is visible
        // 80210 - 12/07/00 - FS
        const OutputDevice* pOut = m_pView ? m_pView->GetActualOutDev() : nullptr;
        const vcl::Window* pCurrentWindow = pOut ? pOut->GetOwnerWindow() : nullptr;
        if ( pCurrentWindow )
        {
            awt::Rectangle aRect = xControlWindow->getPosSize();
            ::tools::Rectangle aNonUnoRect( aRect.X, aRect.Y, aRect.X + aRect.Width, aRect.Y + aRect.Height );
            m_pView->MakeVisible( pCurrentWindow->PixelToLogic( aNonUnoRect ), *const_cast< vcl::Window* >( pCurrentWindow ) );
        }
    }
    catch (const Exception&)
    {
        DBG_UNHANDLED_EXCEPTION("svx");
    }
}


void FmXFormView::onCreatedFormObject( FmFormObj const & _rFormObject )
{
    FmFormShell* pShell = m_pView ? m_pView->GetFormShell() : nullptr;
    FmXFormShell* pShellImpl = pShell ? pShell->GetImpl() : nullptr;
    OSL_ENSURE( pShellImpl, "FmXFormView::onCreatedFormObject: no form shell!" );
    if ( !pShellImpl )
        return;

    // it is valid that the form shell's forms collection is not initialized, yet
    pShellImpl->UpdateForms_Lock(true);

    m_xLastCreatedControlModel.set( _rFormObject.GetUnoControlModel(), UNO_QUERY );
    if ( !m_xLastCreatedControlModel.is() )
        return;

    // some initial property defaults
    FormControlFactory aControlFactory;
    aControlFactory.initializeControlModel(pShellImpl->getDocumentType_Lock(), _rFormObject);

    if (!pShellImpl->GetWizardUsing_Lock())
        return;

    // #i31958# don't call wizards in XForms mode
    if (pShellImpl->isEnhancedForm_Lock())
        return;

    // #i46898# no wizards if there is no Base installed - currently, all wizards are
    // database related
    if (!SvtModuleOptions().IsDataBaseInstalled())
        return;

    if ( m_nControlWizardEvent )
        Application::RemoveUserEvent( m_nControlWizardEvent );
    m_nControlWizardEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnStartControlWizard ) );
}

void FmXFormView::breakCreateFormObject()
{
    if (m_nControlWizardEvent != nullptr)
    {
        Application::RemoveUserEvent(m_nControlWizardEvent);
        m_nControlWizardEvent = nullptr;
    }
    m_xLastCreatedControlModel.clear();
}

Reference<XWindow> FmXFormView::GetParentWindow() const
{
    const OutputDevice* pOut = m_pView ? m_pView->GetActualOutDev() : nullptr;
    const vcl::Window* pCurrentWindow = pOut ? pOut->GetOwnerWindow() : nullptr;
    return VCLUnoHelper::GetInterface(const_cast<vcl::Window*>(pCurrentWindow));
}

IMPL_LINK_NOARG( FmXFormView, OnStartControlWizard, void*, void )
{
    m_nControlWizardEvent = nullptr;
    OSL_PRECOND( m_xLastCreatedControlModel.is(), "FmXFormView::OnStartControlWizard: illegal call!" );
    if ( !m_xLastCreatedControlModel.is() )
        return;

    sal_Int16 nClassId = FormComponentType::CONTROL;
    try
    {
        OSL_VERIFY( m_xLastCreatedControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
    }
    catch (const Exception&)
    {
        DBG_UNHANDLED_EXCEPTION("svx");
    }

    const char* pWizardAsciiName = nullptr;
    switch ( nClassId )
    {
        case FormComponentType::GRIDCONTROL:
            pWizardAsciiName = "com.sun.star.sdb.GridControlAutoPilot";
            break;
        case FormComponentType::LISTBOX:
        case FormComponentType::COMBOBOX:
            pWizardAsciiName = "com.sun.star.sdb.ListComboBoxAutoPilot";
            break;
        case FormComponentType::GROUPBOX:
            pWizardAsciiName = "com.sun.star.sdb.GroupBoxAutoPilot";
            break;
    }

    if ( pWizardAsciiName )
    {
        // build the argument list
        ::comphelper::NamedValueCollection aWizardArgs;
        aWizardArgs.put(u"ObjectModel"_ustr, m_xLastCreatedControlModel);
        aWizardArgs.put(u"ParentWindow"_ustr, GetParentWindow());

        // create the wizard object
        Reference< XExecutableDialog > xWizard;
        try
        {
            const Reference<XComponentContext>& xContext = comphelper::getProcessComponentContext();
            xWizard.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext( OUString::createFromAscii(pWizardAsciiName), aWizardArgs.getWrappedPropertyValues(), xContext ), UNO_QUERY);
        }
        catch (const Exception&)
        {
            DBG_UNHANDLED_EXCEPTION("svx");
        }

        if ( !xWizard.is() )
        {
            ShowServiceNotAvailableError( nullptr, OUString::createFromAscii(pWizardAsciiName)true );
        }
        else
        {
            // execute the wizard
            try
            {
                xWizard->execute();
            }
            catch (const Exception&)
            {
                DBG_UNHANDLED_EXCEPTION("svx");
            }
        }
    }

    m_xLastCreatedControlModel.clear();
}


namespace
{
    void lcl_insertIntoFormComponentHierarchy_throw( const FmFormView& _rView, const SdrUnoObj& _rSdrObj,
        const Reference< XDataSource >& _rxDataSource, const OUString& _rDataSourceName,
        const OUString& _rCommand, const sal_Int32 _nCommandType )
    {
        FmFormPage& rPage = static_cast< FmFormPage& >( *_rView.GetSdrPageView()->GetPage() );

        Reference< XFormComponent > xFormComponent( _rSdrObj.GetUnoControlModel(), UNO_QUERY_THROW );
        Reference< XForm > xTargetForm(
            rPage.GetImpl().findPlaceInFormComponentHierarchy( xFormComponent, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType ),
            UNO_SET_THROW );

        FmFormPageImpl::setUniqueName( xFormComponent, xTargetForm );

        Reference< XIndexContainer > xFormAsContainer( xTargetForm, UNO_QUERY_THROW );
        xFormAsContainer->insertByIndex( xFormAsContainer->getCount(), Any( xFormComponent ) );
    }
}


rtl::Reference<SdrObject> FmXFormView::implCreateFieldControl( const svx::ODataAccessDescriptor& _rColumnDescriptor )
{
    // not if we're in design mode
    if ( !m_pView->IsDesignMode() )
        return nullptr;

    OUString sCommand, sFieldName;
    sal_Int32 nCommandType = CommandType::COMMAND;
    SharedConnection xConnection;

    OUString sDataSource = _rColumnDescriptor.getDataSource();
    _rColumnDescriptor[ DataAccessDescriptorProperty::Command ]     >>= sCommand;
    _rColumnDescriptor[ DataAccessDescriptorProperty::ColumnName ]  >>= sFieldName;
    _rColumnDescriptor[ DataAccessDescriptorProperty::CommandType ] >>= nCommandType;
    {
        Reference< XConnection > xExternalConnection;
        _rColumnDescriptor[ DataAccessDescriptorProperty::Connection ]  >>= xExternalConnection;
        xConnection.reset( xExternalConnection, SharedConnection::NoTakeOwnership );
    }

    if  (   sCommand.isEmpty()
        ||  sFieldName.isEmpty()
        ||  (   sDataSource.isEmpty()
            &&  !xConnection.is()
            )
        )
    {
        OSL_FAIL( "FmXFormView::implCreateFieldControl: nonsense!" );
    }

    Reference< XDataSource > xDataSource;
    SQLErrorEvent aError;
    try
    {
        if ( xConnection.is() && !xDataSource.is() && sDataSource.isEmpty() )
        {
            Reference< XChild > xChild( xConnection, UNO_QUERY );
            if ( xChild.is() )
                xDataSource.set(xChild->getParent(), css::uno::UNO_QUERY);
        }

        // obtain the data source
        if ( !xDataSource.is() )
            xDataSource = getDataSource( sDataSource, comphelper::getProcessComponentContext() );

        // and the connection, if necessary
        if ( !xConnection.is() )
            xConnection.reset( getConnection_withFeedback(
                sDataSource,
                OUString(),
                OUString(),
                comphelper::getProcessComponentContext(),
                nullptr
            ) );
    }
    catch (const SQLException&)
    {
        aError.Reason = ::cppu::getCaughtException();
    }
    catch (const Exception& )
    {
        /* will be asserted below */
    }
    if (aError.Reason.hasValue())
    {
        displayAsyncErrorMessage( aError );
        return nullptr;
    }

    // need a data source and a connection here
    if (!xDataSource.is() || !xConnection.is())
    {
        OSL_FAIL("FmXFormView::implCreateFieldControl : could not retrieve the data source or the connection!");
        return nullptr;
    }

    Reference< XComponent > xKeepFieldsAlive;
    // go
    try
    {
        // determine the table/query field which we should create a control for
        Reference< XPropertySet >   xField;

        Reference< XNameAccess >    xFields = getFieldsByCommandDescriptor(
            xConnection, nCommandType, sCommand, xKeepFieldsAlive );

        if (xFields.is() && xFields->hasByName(sFieldName))
            xFields->getByName(sFieldName) >>= xField;
        if ( !xField.is() )
            return nullptr;

        Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( xConnection ), UNO_SET_THROW );
        Reference< XNumberFormats >  xNumberFormats( xSupplier->getNumberFormats(), UNO_SET_THROW );

        OUString sLabelPostfix;


        // only for text size
        OutputDevice* pOutDev = nullptr;
        if (m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
            pOutDev = const_cast<OutputDevice*>(m_pView->GetActualOutDev());
        else
        {// find OutDev
            if (SdrPageView* pPageView = m_pView->GetSdrPageView())
            {
                // const SdrPageViewWinList& rWinList = pPageView->GetWinList();
                // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows();

                for( sal_uInt32 i = 0; i < pPageView->PageWindowCount(); i++ )
                {
                    const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);

                    if( rPageWindow.GetPaintWindow().OutputToWindow())
                    {
                        pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice();
                        break;
                    }
                }
            }
        }

        if ( !pOutDev )
            return nullptr;

        sal_Int32 nDataType = ::comphelper::getINT32(xField->getPropertyValue(FM_PROP_FIELDTYPE));
        if ((DataType::BINARY == nDataType) || (DataType::VARBINARY == nDataType))
            return nullptr;


        // determine the control type by examining the data type of the bound column
        SdrObjKind nOBJID = SdrObjKind::NONE;
        bool bDateNTimeField = false;

        bool bIsCurrency = false;
        if (::comphelper::hasProperty(FM_PROP_ISCURRENCY, xField))
            bIsCurrency = ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISCURRENCY));

        if (bIsCurrency)
            nOBJID = SdrObjKind::FormCurrencyField;
        else
            switch (nDataType)
            {
                case DataType::BLOB:
                case DataType::LONGVARBINARY:
                    nOBJID = SdrObjKind::FormImageControl;
                    break;
                case DataType::LONGVARCHAR:
                case DataType::CLOB:
                    nOBJID = SdrObjKind::FormEdit;
                    break;
                case DataType::BINARY:
                case DataType::VARBINARY:
                    return nullptr;
                case DataType::BIT:
                case DataType::BOOLEAN:
                    nOBJID = SdrObjKind::FormCheckbox;
                    break;
                case DataType::TINYINT:
                case DataType::SMALLINT:
                case DataType::INTEGER:
                    nOBJID = SdrObjKind::FormNumericField;
                    break;
                case DataType::REAL:
                case DataType::DOUBLE:
                case DataType::NUMERIC:
                case DataType::DECIMAL:
                    nOBJID = SdrObjKind::FormFormattedField;
                    break;
                case DataType::TIMESTAMP:
                    bDateNTimeField = true;
                    sLabelPostfix = SvxResId(RID_STR_POSTFIX_DATE);
                    [[fallthrough]];
                case DataType::DATE:
                    nOBJID = SdrObjKind::FormDateField;
                    break;
                case DataType::TIME:
                    nOBJID = SdrObjKind::FormTimeField;
                    break;
                case DataType::CHAR:
                case DataType::VARCHAR:
                default:
                    nOBJID = SdrObjKind::FormEdit;
                    break;
            }
        if (nOBJID == SdrObjKind::NONE)
            return nullptr;

        rtl::Reference<SdrUnoObj> pLabel;
        rtl::Reference<SdrUnoObj> pControl;
        if  (   !createControlLabelPair( *pOutDev, 0, 0, xField, xNumberFormats, nOBJID, sLabelPostfix,
                    pLabel, pControl, xDataSource, sDataSource, sCommand, nCommandType )
            )
        {
            return nullptr;
        }


        // group objects
        bool bCheckbox = ( SdrObjKind::FormCheckbox == nOBJID );
        OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateFieldControl: why was there a label created for a check box?" );
        if ( bCheckbox )
            return pControl;

        rtl::Reference<SdrObjGroup> pGroup  = new SdrObjGroup(getView()->getSdrModelFromSdrView());
        SdrObjList* pObjList = pGroup->GetSubList();
        pObjList->InsertObject( pLabel.get() );
        pObjList->InsertObject( pControl.get() );

        if ( bDateNTimeField )
        {   // so far we created a date field only, but we also need a time field
            if  (   createControlLabelPair( *pOutDev, 0, 1000, xField, xNumberFormats, SdrObjKind::FormTimeField,
                        SvxResId(RID_STR_POSTFIX_TIME), pLabel, pControl,
                        xDataSource, sDataSource, sCommand, nCommandType )
                )
            {
                pObjList->InsertObject( pLabel.get() );
                pObjList->InsertObject( pControl.get() );
            }
        }

        return pGroup; // and done
    }
    catch (const Exception&)
    {
        DBG_UNHANDLED_EXCEPTION("svx");
    }


    return nullptr;
}


rtl::Reference<SdrObject> FmXFormView::implCreateXFormsControl( const svx::OXFormsDescriptor &_rDesc )
{
    // not if we're in design mode
    if ( !m_pView->IsDesignMode() )
        return nullptr;

    // go
    try
    {
        // determine the table/query field which we should create a control for
        Reference< XNumberFormats > xNumberFormats;
        OUString sLabelPostfix = _rDesc.szName;


        // only for text size
        OutputDevice* pOutDev = nullptr;
        if (m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
            pOutDev = const_cast<OutputDevice*>(m_pView->GetActualOutDev());
        else
        {// find OutDev
            if (SdrPageView* pPageView = m_pView->GetSdrPageView())
            {
                // const SdrPageViewWinList& rWinList = pPageView->GetWinList();
                // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows();

                for( sal_uInt32 i = 0; i < pPageView->PageWindowCount(); i++ )
                {
                    const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);

                    if( rPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType() == OUTDEV_WINDOW)
                    {
                        pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice();
                        break;
                    }
                }
            }
        }

        if ( !pOutDev )
            return nullptr;


        // The service name decides which control should be created
        SdrObjKind nOBJID = SdrObjKind::FormEdit;
        if(_rDesc.szServiceName == FM_SUN_COMPONENT_NUMERICFIELD)
            nOBJID = SdrObjKind::FormNumericField;
        if(_rDesc.szServiceName == FM_SUN_COMPONENT_CHECKBOX)
            nOBJID = SdrObjKind::FormCheckbox;
        if(_rDesc.szServiceName == FM_COMPONENT_COMMANDBUTTON)
            nOBJID = SdrObjKind::FormButton;

        Reference< css::form::submission::XSubmission > xSubmission(_rDesc.xPropSet, UNO_QUERY);

        // xform control or submission button?
        if ( !xSubmission.is() )
        {
            rtl::Reference<SdrUnoObj> pLabel;
            rtl::Reference<SdrUnoObj> pControl;
            if  (   !createControlLabelPair( *pOutDev, 0, 0, nullptr, xNumberFormats, nOBJID, sLabelPostfix,
                        pLabel, pControl, nullptr, u""_ustr, u""_ustr, -1 )
                )
            {
                return nullptr;
            }


            // Now build the connection between the control and the data item.
            Reference< XValueBinding > xValueBinding(_rDesc.xPropSet,UNO_QUERY);
            Reference< XBindableValue > xBindableValue(pControl->GetUnoControlModel(),UNO_QUERY);

            DBG_ASSERT( xBindableValue.is(), "FmXFormView::implCreateXFormsControl: control's not bindable!" );
            if ( xBindableValue.is() )
                xBindableValue->setValueBinding(xValueBinding);

            bool bCheckbox = ( SdrObjKind::FormCheckbox == nOBJID );
            OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateXFormsControl: why was there a label created for a check box?" );
            if ( bCheckbox )
                return pControl;


            // group objects
            rtl::Reference<SdrObjGroup> pGroup  = new SdrObjGroup(getView()->getSdrModelFromSdrView());
            SdrObjList* pObjList = pGroup->GetSubList();
            pObjList->InsertObject(pLabel.get());
            pObjList->InsertObject(pControl.get());

            return pGroup;
        }
        else {

            // create a button control
            const MapMode& eTargetMode( pOutDev->GetMapMode() );
            const MapMode eSourceMode(MapUnit::Map100thMM);
            const SdrObjKind nObjID = SdrObjKind::FormButton;
            ::Size controlSize(4000, 500);
            rtl::Reference<FmFormObj> pControl = static_cast<FmFormObj*>(
                SdrObjFactory::MakeNewObject(
                    getView()->getSdrModelFromSdrView(),
                    SdrInventor::FmForm,
                    nObjID).get());
            controlSize.setWidth( tools::Long(controlSize.Width() * eTargetMode.GetScaleX()) );
            controlSize.setHeight( tools::Long(controlSize.Height() * eTargetMode.GetScaleY()) );
            ::Point controlPos( OutputDevice::LogicToLogic( ::Point( controlSize.Width(), 0 ), eSourceMode, eTargetMode ) );
            ::tools::Rectangle controlRect( controlPos, OutputDevice::LogicToLogic( controlSize, eSourceMode, eTargetMode ) );
            pControl->SetLogicRect(controlRect);

            // set the button label
            Reference< XPropertySet > xControlSet(pControl->GetUnoControlModel(), UNO_QUERY);
            xControlSet->setPropertyValue(FM_PROP_LABEL, Any(_rDesc.szName));

            // connect the submission with the submission supplier (aka the button)
            xControlSet->setPropertyValue( FM_PROP_BUTTON_TYPE,
                                           Any( FormButtonType_SUBMIT ) );
            Reference< css::form::submission::XSubmissionSupplier > xSubmissionSupplier(pControl->GetUnoControlModel(), UNO_QUERY);
            xSubmissionSupplier->setSubmission(xSubmission);

            return rtl::Reference<SdrObject>(pControl);
        }
    }
    catch (const Exception&)
    {
        TOOLS_WARN_EXCEPTION("svx.form""caught an exception while creating the control !");
    }


    return nullptr;
}

bool FmXFormView::createControlLabelPair( OutputDevice const & _rOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM,
        const Reference< XPropertySet >& _rxField, const Reference< XNumberFormats >& _rxNumberFormats,
        SdrObjKind _nControlObjectID, std::u16string_view _rFieldPostfix,
        rtl::Reference<SdrUnoObj>& _rpLabel,
        rtl::Reference<SdrUnoObj>& _rpControl,
        const Reference< XDataSource >& _rxDataSource, const OUString& _rDataSourceName,
        const OUString& _rCommand, const sal_Int32 _nCommandType )
{
    if(!createControlLabelPair(
        _rOutDev,
        _nXOffsetMM,
        _nYOffsetMM,
        _rxField,
        _rxNumberFormats,
        _nControlObjectID,
        _rFieldPostfix,
        SdrInventor::FmForm,
        SdrObjKind::FormFixedText,

        // tdf#118963 Hand over a SdrModel to SdrObject-creation. It uses the local m_pView
        // and already returning false when nullptr == getView() could be done, but m_pView
        // is already dereferenced here in many places (see below), so just use it for now.
        getView()->getSdrModelFromSdrView(),

        _rpLabel,
        _rpControl))
    {
        return false;
    }

    // insert the control model(s) into the form component hierarchy
    if ( _rpLabel )
        lcl_insertIntoFormComponentHierarchy_throw( *m_pView, *_rpLabel, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType );
    lcl_insertIntoFormComponentHierarchy_throw( *m_pView, *_rpControl, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType );

    // some context-dependent initializations
    FormControlFactory aControlFactory;
    if ( _rpLabel )
        aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpLabel );
    aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpControl );

    return true;
}


bool FmXFormView::createControlLabelPair( OutputDevice const & _rOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM,
    const Reference< XPropertySet >& _rxField,
    const Reference< XNumberFormats >& _rxNumberFormats, SdrObjKind _nControlObjectID,
    std::u16string_view _rFieldPostfix, SdrInventor _nInventor, SdrObjKind _nLabelObjectID,
    SdrModel& _rModel,
    rtl::Reference<SdrUnoObj>& _rpLabel, rtl::Reference<SdrUnoObj>& _rpControl)
{
    sal_Int32 nDataType = 0;
    OUString sFieldName;
    Any aFieldName;
    if ( _rxField.is() )
    {
        nDataType = ::comphelper::getINT32(_rxField->getPropertyValue(FM_PROP_FIELDTYPE));
        aFieldName = _rxField->getPropertyValue(FM_PROP_NAME);
        aFieldName >>= sFieldName;
    }

    // calculate the positions, respecting the settings of the target device
    ::Size aTextSize( _rOutDev.GetTextWidth(sFieldName + _rFieldPostfix), _rOutDev.GetTextHeight() );

    const MapMode & eTargetMode( _rOutDev.GetMapMode() );
    MapMode eSourceMode( MapUnit::Map100thMM );

    // text width is at least 4 centimeters
    // text height is always half a centimeter
    ::Size aDefTxtSize(4000, 500);
    ::Size aDefSize(4000, 500);
    ::Size aDefImageSize(4000, 4000);

    ::Size aRealSize = OutputDevice::LogicToLogic(aTextSize, eTargetMode, eSourceMode);
    aRealSize.setWidth( std::max(aRealSize.Width(), aDefTxtSize.Width()) );
    aRealSize.setHeight( aDefSize.Height() );

    // adjust to scaling of the target device (#53523#)
    aRealSize.setWidth( tools::Long(Fraction(aRealSize.Width(), 1) * eTargetMode.GetScaleX()) );
    aRealSize.setHeight( tools::Long(Fraction(aRealSize.Height(), 1) * eTargetMode.GetScaleY()) );

    // for boolean fields, we do not create a label, but just a checkbox
    bool bNeedLabel = ( _nControlObjectID != SdrObjKind::FormCheckbox );

    // the label
    rtl::Reference< SdrUnoObj > pLabel;
    Reference< XPropertySet > xLabelModel;

    if ( bNeedLabel )
    {
        pLabel = dynamic_cast< SdrUnoObj* >(
            SdrObjFactory::MakeNewObject(
                _rModel,
                _nInventor,
                _nLabelObjectID).get() );

        OSL_ENSURE(pLabel, "FmXFormView::createControlLabelPair: could not create the label!");

        if (!pLabel)
            return false;

        xLabelModel.set( pLabel->GetUnoControlModel(), UNO_QUERY );
        if ( xLabelModel.is() )
        {
            OUString sLabel;
            if ( _rxField.is() && _rxField->getPropertySetInfo()->hasPropertyByName(FM_PROP_LABEL) )
                _rxField->getPropertyValue(FM_PROP_LABEL) >>= sLabel;
            if ( sLabel.isEmpty() )
                sLabel = sFieldName;

            xLabelModel->setPropertyValue( FM_PROP_LABEL, Any( sLabel + _rFieldPostfix ) );
            OUString sObjectLabel(SvxResId(RID_STR_OBJECT_LABEL).replaceAll("#object#", sFieldName));
            xLabelModel->setPropertyValue(FM_PROP_NAME, Any(sObjectLabel));
        }

        pLabel->SetLogicRect( ::tools::Rectangle(
            OutputDevice::LogicToLogic( ::Point( _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ),
            OutputDevice::LogicToLogic( aRealSize, eSourceMode, eTargetMode )
        ) );
    }

    // the control
    rtl::Reference< SdrUnoObj > pControl( dynamic_cast< SdrUnoObj* >(
        SdrObjFactory::MakeNewObject(
            _rModel,
             _nInventor,
             _nControlObjectID).get() ));

    OSL_ENSURE(pControl, "FmXFormView::createControlLabelPair: could not create the control!");

    if (!pControl)
        return false;

    Reference< XPropertySet > xControlSet( pControl->GetUnoControlModel(), UNO_QUERY );
    if ( !xControlSet.is() )
        return false;

    // size of the control
    ::Size aControlSize( aDefSize );
    switch ( nDataType )
    {
    case DataType::BIT:
    case DataType::BOOLEAN:
        aControlSize = aDefSize;
        break;
    case DataType::LONGVARCHAR:
    case DataType::CLOB:
    case DataType::LONGVARBINARY:
    case DataType::BLOB:
        aControlSize = aDefImageSize;
        break;
    }

    if ( SdrObjKind::FormImageControl == _nControlObjectID )
        aControlSize = aDefImageSize;

    aControlSize.setWidth( tools::Long(Fraction(aControlSize.Width(), 1) * eTargetMode.GetScaleX()) );
    aControlSize.setHeight( tools::Long(Fraction(aControlSize.Height(), 1) * eTargetMode.GetScaleY()) );

    pControl->SetLogicRect( ::tools::Rectangle(
        OutputDevice::LogicToLogic( ::Point( aRealSize.Width() + _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ),
        OutputDevice::LogicToLogic( aControlSize, eSourceMode, eTargetMode )
    ) );

    // some initializations
    Reference< XPropertySetInfo > xControlPropInfo = xControlSet->getPropertySetInfo();

    if ( aFieldName.hasValue() )
    {
        xControlSet->setPropertyValue( FM_PROP_CONTROLSOURCE, aFieldName );
        xControlSet->setPropertyValue( FM_PROP_NAME, aFieldName );
        if ( !bNeedLabel )
        {
            // no dedicated label control => use the label property
            if ( xControlPropInfo->hasPropertyByName( FM_PROP_LABEL ) )
                xControlSet->setPropertyValue( FM_PROP_LABEL, Any( sFieldName + _rFieldPostfix ) );
            else
                OSL_FAIL( "FmXFormView::createControlLabelPair: can't set a label for the control!" );
        }
    }

    if ( (nDataType == DataType::LONGVARCHAR || nDataType == DataType::CLOB) && xControlPropInfo->hasPropertyByName( FM_PROP_MULTILINE ) )
    {
        xControlSet->setPropertyValue( FM_PROP_MULTILINE, Any( true ) );
    }

    // announce the label to the control
    if ( xControlPropInfo->hasPropertyByName( FM_PROP_CONTROLLABEL ) && xLabelModel.is() )
    {
        try
        {
            xControlSet->setPropertyValue( FM_PROP_CONTROLLABEL, Any( xLabelModel ) );
        }
        catch (const Exception&)
        {
            DBG_UNHANDLED_EXCEPTION("svx");
        }
    }

    if ( _rxField.is() )
    {
        FormControlFactory::initializeFieldDependentProperties( _rxField, xControlSet, _rxNumberFormats );
    }

    _rpLabel = std::move(pLabel);
    _rpControl = std::move(pControl);
    return true;
}


FmXFormView::ObjectRemoveListener::ObjectRemoveListener( FmXFormView* pParent )
    :m_pParent( pParent )
{
}


void FmXFormView::ObjectRemoveListener::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
{
    if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
        return;
    const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
    if (pSdrHint->GetKind() == SdrHintKind::ObjectRemoved)
        m_pParent->ObjectRemovedInAliveMode(pSdrHint->GetObject());
}


void FmXFormView::ObjectRemovedInAliveMode( const SdrObject* pObject )
{
    // if the remote object in my MarkList, which I have memorized when switching to the
    // Alive mode, I have to take it out now, because I otherwise try to set the mark
    // again when switching back (interestingly, this fails only with grouped objects
    // (when accessing their ObjList GPF), not with individual ones)

    const size_t nCount = m_aMark.GetMarkCount();
    for (size_t i = 0; i < nCount; ++i)
    {
        SdrMark* pMark = m_aMark.GetMark(i);
        SdrObject* pCurrent = pMark->GetMarkedSdrObj();
        if (pObject == pCurrent)
        {
            m_aMark.DeleteMark(i);
            return;
        }
        // I do not need to descend into GroupObjects: if an object is deleted there,
        // then the pointer, which I have, to the GroupObject still remains valid ...
    }
}


void FmXFormView::stopMarkListWatching()
{
    if ( m_pWatchStoredList )
    {
        m_pWatchStoredList->EndListeningAll();
        m_pWatchStoredList.reset();
    }
}


void FmXFormView::startMarkListWatching()
{
    if ( !m_pWatchStoredList )
    {
        FmFormModel* pModel = GetFormShell() ? GetFormShell()->GetFormModel() : nullptr;
        DBG_ASSERT( pModel != nullptr, "FmXFormView::startMarkListWatching: shell has no model!" );
        if (pModel)
        {
            m_pWatchStoredList.reset(new ObjectRemoveListener( this ));
            m_pWatchStoredList->StartListening( *static_cast< SfxBroadcaster* >( pModel ) );
        }
    }
    else
    {
        OSL_FAIL( "FmXFormView::startMarkListWatching: already listening!" );
    }
}

void FmXFormView::saveMarkList()
{
    if ( m_pView )
    {
        m_aMark = m_pView->GetMarkedObjectList();
        const size_t nCount = m_aMark.GetMarkCount( );
        for ( size_t i = 0; i < nCount; ++i )
        {
            SdrMark*   pMark = m_aMark.GetMark(i);
            SdrObject* pObj  = pMark->GetMarkedSdrObj();

            if ( m_pView->IsObjMarked( pObj ) )
            {
                if ( pObj->IsGroupObject() )
                {
                    SdrObjListIter aIter( pObj->GetSubList() );
                    bool bMixed = false;
                    while ( aIter.IsMore() && !bMixed )
                        bMixed = ( aIter.Next()->GetObjInventor() != SdrInventor::FmForm );

                    if ( !bMixed )
                    {
                        // all objects in the group are form objects
                        m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), true /* unmark! */ );
                    }
                }
                else
                {
                    if ( pObj->GetObjInventor() == SdrInventor::FmForm )
                    {   // this is a form layer object
                        m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), true /* unmark! */ );
                    }
                }
            }
        }
    }
    else
    {
        OSL_FAIL( "FmXFormView::saveMarkList: invalid view!" );
        m_aMark.Clear();
    }
}

static bool lcl_hasObject( SdrObjListIter& rIter, SdrObject const * pObj )
{
    bool bFound = false;
    while (rIter.IsMore() && !bFound)
        bFound = pObj == rIter.Next();

    rIter.Reset();
    return bFound;
}


void FmXFormView::restoreMarkList( SdrMarkList& _rRestoredMarkList )
{
    if ( !m_pView )
        return;

    _rRestoredMarkList.Clear();

    const SdrMarkList& rCurrentList = m_pView->GetMarkedObjectList();
    FmFormPage* pPage = GetFormShell() ? GetFormShell()->GetCurPage() : nullptr;
    if (!pPage)
        return;

    if (rCurrentList.GetMarkCount())
    {   // there is a current mark ... hmm. Is it a subset of the mark we remembered in saveMarkList?
        bool bMisMatch = false;

        // loop through all current marks
        const size_t nCurrentCount = rCurrentList.GetMarkCount();
        for ( size_t i=0; i<nCurrentCount && !bMisMatch; ++i )
        {
            const SdrObject* pCurrentMarked = rCurrentList.GetMark( i )->GetMarkedSdrObj();

            // loop through all saved marks, check for equality
            bool bFound = false;
            const size_t nSavedCount = m_aMark.GetMarkCount();
            for ( size_t j=0; j<nSavedCount && !bFound; ++j )
            {
                if ( m_aMark.GetMark( j )->GetMarkedSdrObj() == pCurrentMarked )
                    bFound = true;
            }

            // did not find a current mark in the saved marks
            if ( !bFound )
                bMisMatch = true;
        }

        if ( bMisMatch )
        {
            m_aMark.Clear();
            _rRestoredMarkList = rCurrentList;
            return;
        }
    }
    // it is important that the objects of the mark list are not accessed,
    // because they can be already destroyed
    SdrPageView* pCurPageView = m_pView->GetSdrPageView();
    SdrObjListIter aPageIter( pPage );
    bool bFound = true;

    // do all objects still exist
    const size_t nCount = m_aMark.GetMarkCount();
    for (size_t i = 0; i < nCount && bFound; ++i)
    {
        SdrMark*   pMark = m_aMark.GetMark(i);
        SdrObject* pObj  = pMark->GetMarkedSdrObj();
        if (pObj->IsGroupObject())
        {
            SdrObjListIter aIter(pObj->GetSubList());
            while (aIter.IsMore() && bFound)
                bFound = lcl_hasObject(aPageIter, aIter.Next());
        }
        else
            bFound = lcl_hasObject(aPageIter, pObj);

        bFound = bFound && pCurPageView == pMark->GetPageView();
    }

    if (bFound)
    {
        // evaluate the LastObject
        if (nCount) // now mark the objects
        {
            for (size_t i = 0; i < nCount; ++i)
            {
                SdrMark* pMark = m_aMark.GetMark(i);
                SdrObject* pObj = pMark->GetMarkedSdrObj();
                if ( pObj->GetObjInventor() == SdrInventor::FmForm )
                    if ( !m_pView->IsObjMarked( pObj ) )
                        m_pView->MarkObj( pObj, pMark->GetPageView() );
            }

            _rRestoredMarkList = m_aMark;
        }
    }
    m_aMark.Clear();
}

void SAL_CALL FmXFormView::focusGained( const FocusEvent& /*e*/ )
{
    if ( m_xWindow.is() && m_pView )
    {
        m_pView->SetMoveOutside( true, FmFormView::ImplAccess() );
    }
}

void SAL_CALL FmXFormView::focusLost( const FocusEvent& /*e*/ )
{
    // when switch the focus outside the office the mark didn't change
    // so we can not remove us as focus listener
    if ( m_xWindow.is() && m_pView )
    {
        m_pView->SetMoveOutside( false, FmFormView::ImplAccess() );
    }
}

DocumentType FmXFormView::impl_getDocumentType() const
{
    if ( GetFormShell() && GetFormShell()->GetImpl() )
        return GetFormShell()->GetImpl()->getDocumentType_Lock();
    return eUnknownDocumentType;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5 in Prozent
C=94 H=93 G=93

¤ Dauer der Verarbeitung: 0.23 Sekunden  (vorverarbeitet am  2026-05-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.