summaryrefslogtreecommitdiffstats
path: root/svx/source/form/fmvwimp.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svx/source/form/fmvwimp.cxx')
-rw-r--r--svx/source/form/fmvwimp.cxx1917
1 files changed, 1917 insertions, 0 deletions
diff --git a/svx/source/form/fmvwimp.cxx b/svx/source/form/fmvwimp.cxx
new file mode 100644
index 000000000..1ede28ae3
--- /dev/null
+++ b/svx/source/form/fmvwimp.cxx
@@ -0,0 +1,1917 @@
+/* -*- 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/fmglob.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/sdb/XQueriesSupplier.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 <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/stdtext.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::makeAny;
+ 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( const css::uno::Reference<css::uno::XComponentContext>& _rContext, const SdrPageWindow& _rWindow, FmXFormView* _pViewImpl )
+: m_xControlContainer( _rWindow.GetControlContainer() ),
+ m_xContext( _rContext ),
+ m_pViewImpl( _pViewImpl ),
+ m_pWindow( dynamic_cast< vcl::Window* >( &_rWindow.GetPaintWindow().GetOutputDevice() ) )
+{
+
+ // create an XFormController for every form
+ FmFormPage* pFormPage = dynamic_cast< FmFormPage* >( _rWindow.GetPageView().GetPage() );
+ DBG_ASSERT( pFormPage, "FormViewPageWindowAdapter::FormViewPageWindowAdapter: no FmFormPage found!" );
+ if ( pFormPage )
+ {
+ 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 ), makeAny(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 ).get() );
+ 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
+ {
+ PFormViewPageWindowAdapter 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*/)
+{
+}
+
+
+PFormViewPageWindowAdapter FmXFormView::findWindow( const Reference< XControlContainer >& _rxCC ) const
+{
+ auto i = std::find_if(m_aPageWindowAdapters.begin(), m_aPageWindowAdapters.end(),
+ [&_rxCC](const PFormViewPageWindowAdapter& 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() )
+ )
+ {
+ PFormViewPageWindowAdapter 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 PFormViewPageWindowAdapter& 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 );
+}
+
+
+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)
+ {
+ PFormViewPageWindowAdapter 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)
+ {
+ FmXFormShell* const pShImpl = m_pView->GetFormShell()->GetImpl();
+
+ if(!pShImpl)
+ return;
+
+ find_active_databaseform fad(pShImpl->getActiveController_Lock());
+
+ vcl::Window* pWindow = const_cast<vcl::Window*>(static_cast<const vcl::Window*>(m_pView->GetActualOutDev()));
+ PFormViewPageWindowAdapter pAdapter = m_aPageWindowAdapters.empty() ? nullptr : m_aPageWindowAdapters[0];
+ for (const auto& rpPageWindowAdapter : m_aPageWindowAdapters)
+ {
+ if ( pWindow == rpPageWindowAdapter->getWindow() )
+ pAdapter = rpPageWindowAdapter;
+ }
+
+ if ( pAdapter.is() )
+ {
+ Reference< XFormController > xControllerToActivate;
+ for (const Reference< XFormController > & xController : pAdapter->GetList())
+ {
+ if ( !xController.is() )
+ continue;
+
+ {
+ Reference< XFormController > xActiveController(fad(xController));
+ if (xActiveController.is())
+ {
+ xControllerToActivate = 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 > >& _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& _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 );
+ }
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+ }
+}
+
+
+Reference< XFormController > FmXFormView::getFormController( const Reference< XForm >& _rxForm, const OutputDevice& _rDevice ) const
+{
+ Reference< XFormController > xController;
+
+ for (const PFormViewPageWindowAdapter& pAdapter : m_aPageWindowAdapters)
+ {
+ if ( !pAdapter )
+ {
+ SAL_WARN( "svx.form", "FmXFormView::getFormController: invalid page window adapter!" );
+ continue;
+ }
+
+ if ( pAdapter->getWindow() != &_rDevice )
+ // 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 PFormViewPageWindowAdapter 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 vcl::Window* pCurrentWindow = m_pView ? dynamic_cast<const vcl::Window*>(m_pView->GetActualOutDev()) : 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().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) )
+ 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();
+}
+
+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("ObjectModel", m_xLastCreatedControlModel);
+ const vcl::Window* pCurrentWindow = m_pView ? dynamic_cast<const vcl::Window*>(m_pView->GetActualOutDev()) : nullptr;
+ aWizardArgs.put("ParentWindow", VCLUnoHelper::GetInterface(const_cast<vcl::Window*>(pCurrentWindow)));
+
+ // create the wizard object
+ Reference< XExecutableDialog > xWizard;
+ try
+ {
+ 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(), makeAny( xFormComponent ) );
+ }
+}
+
+
+SdrObjectUniquePtr 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
+ sal_uInt16 nOBJID = 0;
+ bool bDateNTimeField = false;
+
+ bool bIsCurrency = false;
+ if (::comphelper::hasProperty(FM_PROP_ISCURRENCY, xField))
+ bIsCurrency = ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISCURRENCY));
+
+ if (bIsCurrency)
+ nOBJID = OBJ_FM_CURRENCYFIELD;
+ else
+ switch (nDataType)
+ {
+ case DataType::BLOB:
+ case DataType::LONGVARBINARY:
+ nOBJID = OBJ_FM_IMAGECONTROL;
+ break;
+ case DataType::LONGVARCHAR:
+ case DataType::CLOB:
+ nOBJID = OBJ_FM_EDIT;
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ return nullptr;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ nOBJID = OBJ_FM_CHECKBOX;
+ break;
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ nOBJID = OBJ_FM_NUMERICFIELD;
+ break;
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ case DataType::NUMERIC:
+ case DataType::DECIMAL:
+ nOBJID = OBJ_FM_FORMATTEDFIELD;
+ break;
+ case DataType::TIMESTAMP:
+ bDateNTimeField = true;
+ sLabelPostfix = SvxResId(RID_STR_POSTFIX_DATE);
+ [[fallthrough]];
+ case DataType::DATE:
+ nOBJID = OBJ_FM_DATEFIELD;
+ break;
+ case DataType::TIME:
+ nOBJID = OBJ_FM_TIMEFIELD;
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ default:
+ nOBJID = OBJ_FM_EDIT;
+ break;
+ }
+ if (!nOBJID)
+ return nullptr;
+
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp> pLabel;
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp> pControl;
+ if ( !createControlLabelPair( *pOutDev, 0, 0, xField, xNumberFormats, nOBJID, sLabelPostfix,
+ pLabel, pControl, xDataSource, sDataSource, sCommand, nCommandType )
+ )
+ {
+ return nullptr;
+ }
+
+
+ // group objects
+ bool bCheckbox = ( OBJ_FM_CHECKBOX == nOBJID );
+ OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateFieldControl: why was there a label created for a check box?" );
+ if ( bCheckbox )
+ return SdrObjectUniquePtr(pControl.release());
+
+ SdrObjGroup* pGroup = new SdrObjGroup(getView()->getSdrModelFromSdrView());
+ SdrObjList* pObjList = pGroup->GetSubList();
+ pObjList->InsertObject( pLabel.release() );
+ pObjList->InsertObject( pControl.release() );
+
+ if ( bDateNTimeField )
+ { // so far we created a date field only, but we also need a time field
+ if ( createControlLabelPair( *pOutDev, 0, 1000, xField, xNumberFormats, OBJ_FM_TIMEFIELD,
+ SvxResId(RID_STR_POSTFIX_TIME), pLabel, pControl,
+ xDataSource, sDataSource, sCommand, nCommandType )
+ )
+ {
+ pObjList->InsertObject( pLabel.release() );
+ pObjList->InsertObject( pControl.release() );
+ }
+ }
+
+ return SdrObjectUniquePtr(pGroup); // and done
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("svx");
+ }
+
+
+ return nullptr;
+}
+
+
+SdrObjectUniquePtr 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
+ sal_uInt16 nOBJID = OBJ_FM_EDIT;
+ if(_rDesc.szServiceName == FM_SUN_COMPONENT_NUMERICFIELD)
+ nOBJID = OBJ_FM_NUMERICFIELD;
+ if(_rDesc.szServiceName == FM_SUN_COMPONENT_CHECKBOX)
+ nOBJID = OBJ_FM_CHECKBOX;
+ if(_rDesc.szServiceName == FM_COMPONENT_COMMANDBUTTON)
+ nOBJID = OBJ_FM_BUTTON;
+
+ Reference< css::form::submission::XSubmission > xSubmission(_rDesc.xPropSet, UNO_QUERY);
+
+ // xform control or submission button?
+ if ( !xSubmission.is() )
+ {
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp> pLabel;
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp> pControl;
+ if ( !createControlLabelPair( *pOutDev, 0, 0, nullptr, xNumberFormats, nOBJID, sLabelPostfix,
+ pLabel, pControl, nullptr, "", "", -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 = ( OBJ_FM_CHECKBOX == nOBJID );
+ OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateXFormsControl: why was there a label created for a check box?" );
+ if ( bCheckbox )
+ return SdrObjectUniquePtr(pControl.release());
+
+
+ // group objects
+ SdrObjGroup* pGroup = new SdrObjGroup(getView()->getSdrModelFromSdrView());
+ SdrObjList* pObjList = pGroup->GetSubList();
+ pObjList->InsertObject(pLabel.release());
+ pObjList->InsertObject(pControl.release());
+
+ return SdrObjectUniquePtr(pGroup);
+ }
+ else {
+
+ // create a button control
+ const MapMode& eTargetMode( pOutDev->GetMapMode() );
+ const MapMode eSourceMode(MapUnit::Map100thMM);
+ const sal_uInt16 nObjID = OBJ_FM_BUTTON;
+ ::Size controlSize(4000, 500);
+ FmFormObj *pControl = static_cast<FmFormObj*>(
+ SdrObjFactory::MakeNewObject(
+ getView()->getSdrModelFromSdrView(),
+ SdrInventor::FmForm,
+ nObjID));
+ controlSize.setWidth( long(controlSize.Width() * eTargetMode.GetScaleX()) );
+ controlSize.setHeight( 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, makeAny(_rDesc.szName));
+
+ // connect the submission with the submission supplier (aka the button)
+ xControlSet->setPropertyValue( FM_PROP_BUTTON_TYPE,
+ makeAny( FormButtonType_SUBMIT ) );
+ Reference< css::form::submission::XSubmissionSupplier > xSubmissionSupplier(pControl->GetUnoControlModel(), UNO_QUERY);
+ xSubmissionSupplier->setSubmission(xSubmission);
+
+ return SdrObjectUniquePtr(pControl);
+ }
+ }
+ catch (const Exception&)
+ {
+ OSL_FAIL("FmXFormView::implCreateXFormsControl: 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,
+ sal_uInt16 _nControlObjectID, const OUString& _rFieldPostfix,
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpLabel,
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _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,
+ OBJ_FM_FIXEDTEXT,
+
+ // 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, sal_uInt16 _nControlObjectID,
+ const OUString& _rFieldPostfix, SdrInventor _nInventor, sal_uInt16 _nLabelObjectID,
+ SdrModel& _rModel,
+ std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpLabel, std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _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() );
+
+ MapMode eTargetMode( _rOutDev.GetMapMode() ),
+ 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( long(Fraction(aRealSize.Width(), 1) * eTargetMode.GetScaleX()) );
+ aRealSize.setHeight( long(Fraction(aRealSize.Height(), 1) * eTargetMode.GetScaleY()) );
+
+ // for boolean fields, we do not create a label, but just a checkbox
+ bool bNeedLabel = ( _nControlObjectID != OBJ_FM_CHECKBOX );
+
+ // the label
+ ::std::unique_ptr< SdrUnoObj, SdrObjectFreeOp > pLabel;
+ Reference< XPropertySet > xLabelModel;
+
+ if ( bNeedLabel )
+ {
+ pLabel.reset( dynamic_cast< SdrUnoObj* >(
+ SdrObjFactory::MakeNewObject(
+ _rModel,
+ _nInventor,
+ _nLabelObjectID)));
+
+ 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, makeAny( sLabel + _rFieldPostfix ) );
+ OUString sObjectLabel(SvxResId(RID_STR_OBJECT_LABEL).replaceAll("#object#", sFieldName));
+ xLabelModel->setPropertyValue(FM_PROP_NAME, makeAny(sObjectLabel));
+ }
+
+ pLabel->SetLogicRect( ::tools::Rectangle(
+ OutputDevice::LogicToLogic( ::Point( _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ),
+ OutputDevice::LogicToLogic( aRealSize, eSourceMode, eTargetMode )
+ ) );
+ }
+
+ // the control
+ ::std::unique_ptr< SdrUnoObj, SdrObjectFreeOp > pControl( dynamic_cast< SdrUnoObj* >(
+ SdrObjFactory::MakeNewObject(
+ _rModel,
+ _nInventor,
+ _nControlObjectID)));
+
+ 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 ( OBJ_FM_IMAGECONTROL == _nControlObjectID )
+ aControlSize = aDefImageSize;
+
+ aControlSize.setWidth( long(Fraction(aControlSize.Width(), 1) * eTargetMode.GetScaleX()) );
+ aControlSize.setHeight( 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, makeAny( 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, makeAny( true ) );
+ }
+
+ // announce the label to the control
+ if ( xControlPropInfo->hasPropertyByName( FM_PROP_CONTROLLABEL ) && xLabelModel.is() )
+ {
+ try
+ {
+ xControlSet->setPropertyValue( FM_PROP_CONTROLLABEL, makeAny( 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)
+ {
+ 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: */