3f8fc1a384
Change-Id: If7fb907575640b95399419beee5af6cfbd5fafb2 Reviewed-on: https://gerrit.libreoffice.org/85714 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
1926 lines
66 KiB
C++
1926 lines
66 KiB
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 <fmundo.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/form/XLoadable.hpp>
|
|
#include <com/sun/star/awt/VisualEffect.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/sdbc/ColumnValue.hpp>
|
|
#include <com/sun/star/form/FormComponentType.hpp>
|
|
#include <com/sun/star/form/FormButtonType.hpp>
|
|
#include <com/sun/star/form/XReset.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/sdbcx/XTablesSupplier.hpp>
|
|
#include <com/sun/star/sdbc/SQLException.hpp>
|
|
#include <com/sun/star/sdbc/XPreparedStatement.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::RuntimeException;
|
|
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::lang::WrappedTargetException;
|
|
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_SET_THROW );
|
|
|
|
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.get() )
|
|
{
|
|
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.get() ? 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: */
|