1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <fmdocumentclassification.hxx>
24 #include <fmpgeimp.hxx>
26 #include <svx/strings.hrc>
27 #include <fmservs.hxx>
28 #include <fmshimp.hxx>
29 #include <svx/fmtools.hxx>
30 #include <fmvwimp.hxx>
31 #include <formcontrolfactory.hxx>
32 #include <svx/sdrpaintwindow.hxx>
33 #include <svx/svditer.hxx>
34 #include <svx/dataaccessdescriptor.hxx>
35 #include <svx/dialmgr.hxx>
36 #include <svx/svdobjkind.hxx>
37 #include <svx/fmmodel.hxx>
38 #include <svx/fmpage.hxx>
39 #include <svx/fmshell.hxx>
40 #include <svx/fmview.hxx>
41 #include <svx/sdrpagewindow.hxx>
42 #include <svx/svdogrp.hxx>
43 #include <svx/svdpagv.hxx>
44 #include <svx/xmlexchg.hxx>
45 #include <toolkit/helper/vclunohelper.hxx>
47 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
48 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
49 #include <com/sun/star/sdbc/XRowSet.hpp>
50 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
51 #include <com/sun/star/util/XNumberFormats.hpp>
52 #include <com/sun/star/sdb/CommandType.hpp>
53 #include <com/sun/star/sdbc/DataType.hpp>
54 #include <com/sun/star/form/FormComponentType.hpp>
55 #include <com/sun/star/form/FormButtonType.hpp>
56 #include <com/sun/star/form/binding/XBindableValue.hpp>
57 #include <com/sun/star/form/binding/XValueBinding.hpp>
58 #include <com/sun/star/form/runtime/FormController.hpp>
59 #include <com/sun/star/form/submission/XSubmissionSupplier.hpp>
60 #include <com/sun/star/awt/XTabControllerModel.hpp>
61 #include <com/sun/star/awt/XControlContainer.hpp>
62 #include <com/sun/star/awt/XTabController.hpp>
63 #include <com/sun/star/container/XIndexAccess.hpp>
64 #include <com/sun/star/awt/XControl.hpp>
65 #include <com/sun/star/sdbc/SQLException.hpp>
66 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
67 #include <com/sun/star/container/XContainer.hpp>
69 #include <comphelper/namedvaluecollection.hxx>
70 #include <comphelper/property.hxx>
71 #include <comphelper/processfactory.hxx>
72 #include <comphelper/types.hxx>
73 #include <cppuhelper/exc_hlp.hxx>
74 #include <unotools/moduleoptions.hxx>
75 #include <tools/debug.hxx>
76 #include <tools/diagnose_ex.h>
77 #include <sal/log.hxx>
78 #include <vcl/svapp.hxx>
79 #include <vcl/stdtext.hxx>
80 #include <vcl/window.hxx>
81 #include <connectivity/dbtools.hxx>
85 using namespace ::comphelper
;
86 using namespace ::svx
;
87 using namespace ::svxform
;
88 using namespace ::dbtools
;
90 using namespace ::com::sun::star
;
91 using ::com::sun::star::uno::Exception
;
92 using ::com::sun::star::uno::XInterface
;
93 using ::com::sun::star::uno::Sequence
;
94 using ::com::sun::star::uno::UNO_QUERY
;
95 using ::com::sun::star::uno::UNO_QUERY_THROW
;
96 using ::com::sun::star::uno::UNO_SET_THROW
;
97 using ::com::sun::star::uno::Type
;
98 using ::com::sun::star::uno::Reference
;
99 using ::com::sun::star::uno::Any
;
100 using ::com::sun::star::uno::makeAny
;
101 using ::com::sun::star::uno::XComponentContext
;
102 using ::com::sun::star::form::FormButtonType_SUBMIT
;
103 using ::com::sun::star::form::binding::XValueBinding
;
104 using ::com::sun::star::form::binding::XBindableValue
;
105 using ::com::sun::star::lang::XComponent
;
106 using ::com::sun::star::container::XIndexAccess
;
107 using ::com::sun::star::form::runtime::FormController
;
108 using ::com::sun::star::form::runtime::XFormController
;
109 using ::com::sun::star::script::XEventAttacherManager
;
110 using ::com::sun::star::awt::XTabControllerModel
;
111 using ::com::sun::star::container::XChild
;
112 using ::com::sun::star::task::XInteractionHandler
;
113 using ::com::sun::star::awt::XTabController
;
114 using ::com::sun::star::awt::XControlContainer
;
115 using ::com::sun::star::awt::XControl
;
116 using ::com::sun::star::form::XFormComponent
;
117 using ::com::sun::star::form::XForm
;
118 using ::com::sun::star::lang::IndexOutOfBoundsException
;
119 using ::com::sun::star::container::XContainer
;
120 using ::com::sun::star::container::ContainerEvent
;
121 using ::com::sun::star::lang::EventObject
;
122 using ::com::sun::star::sdb::SQLErrorEvent
;
123 using ::com::sun::star::sdbc::XRowSet
;
124 using ::com::sun::star::beans::XPropertySet
;
125 using ::com::sun::star::container::XElementAccess
;
126 using ::com::sun::star::awt::XWindow
;
127 using ::com::sun::star::awt::FocusEvent
;
128 using ::com::sun::star::ui::dialogs::XExecutableDialog
;
129 using ::com::sun::star::sdbc::XDataSource
;
130 using ::com::sun::star::container::XIndexContainer
;
131 using ::com::sun::star::sdbc::XConnection
;
132 using ::com::sun::star::container::XNameAccess
;
133 using ::com::sun::star::sdbc::SQLException
;
134 using ::com::sun::star::util::XNumberFormatsSupplier
;
135 using ::com::sun::star::util::XNumberFormats
;
136 using ::com::sun::star::beans::XPropertySetInfo
;
138 namespace FormComponentType
= ::com::sun::star::form::FormComponentType
;
139 namespace CommandType
= ::com::sun::star::sdb::CommandType
;
140 namespace DataType
= ::com::sun::star::sdbc::DataType
;
143 class FmXFormView::ObjectRemoveListener
: public SfxListener
145 FmXFormView
* m_pParent
;
147 explicit ObjectRemoveListener( FmXFormView
* pParent
);
148 virtual void Notify( SfxBroadcaster
& rBC
, const SfxHint
& rHint
) override
;
151 FormViewPageWindowAdapter::FormViewPageWindowAdapter( const css::uno::Reference
<css::uno::XComponentContext
>& _rContext
, const SdrPageWindow
& _rWindow
, FmXFormView
* _pViewImpl
)
152 : m_xControlContainer( _rWindow
.GetControlContainer() ),
153 m_xContext( _rContext
),
154 m_pViewImpl( _pViewImpl
),
155 m_pWindow( _rWindow
.GetPaintWindow().GetOutputDevice().GetOwnerWindow() )
158 // create an XFormController for every form
159 FmFormPage
* pFormPage
= dynamic_cast< FmFormPage
* >( _rWindow
.GetPageView().GetPage() );
160 DBG_ASSERT( pFormPage
, "FormViewPageWindowAdapter::FormViewPageWindowAdapter: no FmFormPage found!" );
166 Reference
< XIndexAccess
> xForms( pFormPage
->GetForms(), UNO_QUERY_THROW
);
167 sal_uInt32 nLength
= xForms
->getCount();
168 for (sal_uInt32 i
= 0; i
< nLength
; i
++)
170 Reference
< XForm
> xForm( xForms
->getByIndex(i
), UNO_QUERY
);
172 setController( xForm
, nullptr );
175 catch (const Exception
&)
177 DBG_UNHANDLED_EXCEPTION("svx");
181 FormViewPageWindowAdapter::~FormViewPageWindowAdapter()
185 void FormViewPageWindowAdapter::dispose()
187 for ( ::std::vector
< Reference
< XFormController
> >::const_iterator i
= m_aControllerList
.begin();
188 i
!= m_aControllerList
.end();
194 Reference
< XFormController
> xController( *i
, UNO_SET_THROW
);
196 // detaching the events
197 Reference
< XChild
> xControllerModel( xController
->getModel(), UNO_QUERY
);
198 if ( xControllerModel
.is() )
200 Reference
< XEventAttacherManager
> xEventManager( xControllerModel
->getParent(), UNO_QUERY_THROW
);
201 Reference
< XInterface
> xControllerNormalized( xController
, UNO_QUERY_THROW
);
202 xEventManager
->detach( i
- m_aControllerList
.begin(), xControllerNormalized
);
205 // dispose the formcontroller
206 xController
->dispose();
208 catch (const Exception
&)
210 DBG_UNHANDLED_EXCEPTION("svx");
214 m_aControllerList
.clear();
217 sal_Bool SAL_CALL
FormViewPageWindowAdapter::hasElements()
219 return getCount() != 0;
222 Type SAL_CALL
FormViewPageWindowAdapter::getElementType()
224 return cppu::UnoType
<XFormController
>::get();
228 sal_Int32 SAL_CALL
FormViewPageWindowAdapter::getCount()
230 return m_aControllerList
.size();
233 Any SAL_CALL
FormViewPageWindowAdapter::getByIndex(sal_Int32 nIndex
)
236 nIndex
>= getCount())
237 throw IndexOutOfBoundsException();
240 aElement
<<= m_aControllerList
[nIndex
];
244 void SAL_CALL
FormViewPageWindowAdapter::makeVisible( const Reference
< XControl
>& Control
)
246 SolarMutexGuard aSolarGuard
;
248 Reference
< XWindow
> xWindow( Control
, UNO_QUERY
);
249 if ( xWindow
.is() && m_pViewImpl
->getView() && m_pWindow
)
251 awt::Rectangle aRect
= xWindow
->getPosSize();
252 ::tools::Rectangle
aNewRect( aRect
.X
, aRect
.Y
, aRect
.X
+ aRect
.Width
, aRect
.Y
+ aRect
.Height
);
253 aNewRect
= m_pWindow
->PixelToLogic( aNewRect
);
254 m_pViewImpl
->getView()->MakeVisible( aNewRect
, *m_pWindow
);
258 static Reference
< XFormController
> getControllerSearchChildren( const Reference
< XIndexAccess
> & xIndex
, const Reference
< XTabControllerModel
> & xModel
)
260 if (xIndex
.is() && xIndex
->getCount())
262 Reference
< XFormController
> xController
;
264 for (sal_Int32 n
= xIndex
->getCount(); n
-- && !xController
.is(); )
266 xIndex
->getByIndex(n
) >>= xController
;
267 if (xModel
.get() == xController
->getModel().get())
271 xController
= getControllerSearchChildren(xController
, xModel
);
272 if ( xController
.is() )
277 return Reference
< XFormController
> ();
280 // Search the according controller
281 Reference
< XFormController
> FormViewPageWindowAdapter::getController( const Reference
< XForm
> & xForm
) const
283 Reference
< XTabControllerModel
> xModel(xForm
, UNO_QUERY
);
284 for (const auto& rpController
: m_aControllerList
)
286 if (rpController
->getModel().get() == xModel
.get())
289 // the current-round controller isn't the right one. perhaps one of its children ?
290 Reference
< XFormController
> xChildSearch
= getControllerSearchChildren(Reference
< XIndexAccess
> (rpController
, UNO_QUERY
), xModel
);
291 if (xChildSearch
.is())
294 return Reference
< XFormController
> ();
298 void FormViewPageWindowAdapter::setController(const Reference
< XForm
> & xForm
, const Reference
< XFormController
>& _rxParentController
)
300 DBG_ASSERT( xForm
.is(), "FormViewPageWindowAdapter::setController: there should be a form!" );
301 Reference
< XIndexAccess
> xFormCps(xForm
, UNO_QUERY
);
305 Reference
< XTabControllerModel
> xTabOrder(xForm
, UNO_QUERY
);
307 // create a form controller
308 Reference
< XFormController
> xController( FormController::create(m_xContext
) );
310 Reference
< XInteractionHandler
> xHandler
;
311 if ( _rxParentController
.is() )
312 xHandler
= _rxParentController
->getInteractionHandler();
315 // TODO: should we create a default handler? Not really necessary, since the
316 // FormController itself has a default fallback
319 xController
->setInteractionHandler( xHandler
);
321 xController
->setContext( this );
323 xController
->setModel( xTabOrder
);
324 xController
->setContainer( m_xControlContainer
);
325 xController
->activateTabOrder();
326 xController
->addActivateListener( m_pViewImpl
);
328 if ( _rxParentController
.is() )
329 _rxParentController
->addChildController( xController
);
332 m_aControllerList
.push_back(xController
);
334 xController
->setParent( *this );
336 // attaching the events
337 Reference
< XEventAttacherManager
> xEventManager( xForm
->getParent(), UNO_QUERY
);
338 xEventManager
->attach(m_aControllerList
.size() - 1, Reference
<XInterface
>( xController
, UNO_QUERY
), makeAny(xController
) );
341 // now go through the subforms
342 sal_uInt32 nLength
= xFormCps
->getCount();
343 Reference
< XForm
> xSubForm
;
344 for (sal_uInt32 i
= 0; i
< nLength
; i
++)
346 if ( xFormCps
->getByIndex(i
) >>= xSubForm
)
347 setController( xSubForm
, xController
);
352 void FormViewPageWindowAdapter::updateTabOrder( const Reference
< XForm
>& _rxForm
)
354 OSL_PRECOND( _rxForm
.is(), "FormViewPageWindowAdapter::updateTabOrder: illegal argument!" );
360 Reference
< XTabController
> xTabCtrl( getController( _rxForm
) );
362 { // if there already is a TabController for this form, then delegate the "updateTabOrder" request
363 xTabCtrl
->activateTabOrder();
366 { // otherwise, create a TabController
368 // if it's a sub form, then we must ensure there exist TabControllers
369 // for all its ancestors, too
370 Reference
< XForm
> xParentForm( _rxForm
->getParent(), UNO_QUERY
);
371 // there is a parent form -> look for the respective controller
372 Reference
< XFormController
> xParentController
;
373 if ( xParentForm
.is() )
374 xParentController
= getController( xParentForm
);
376 setController( _rxForm
, xParentController
);
379 catch (const Exception
&)
381 DBG_UNHANDLED_EXCEPTION("svx");
386 FmXFormView::FmXFormView(FmFormView
* _pView
)
387 :m_pMarkedGrid(nullptr)
389 ,m_nActivationEvent(nullptr)
390 ,m_nErrorMessageEvent( nullptr )
391 ,m_nAutoFocusEvent( nullptr )
392 ,m_nControlWizardEvent( nullptr )
393 ,m_bFirstActivation( true )
394 ,m_isTabOrderUpdateSuspended( false )
399 void FmXFormView::cancelEvents()
401 if ( m_nActivationEvent
)
403 Application::RemoveUserEvent( m_nActivationEvent
);
404 m_nActivationEvent
= nullptr;
407 if ( m_nErrorMessageEvent
)
409 Application::RemoveUserEvent( m_nErrorMessageEvent
);
410 m_nErrorMessageEvent
= nullptr;
413 if ( m_nAutoFocusEvent
)
415 Application::RemoveUserEvent( m_nAutoFocusEvent
);
416 m_nAutoFocusEvent
= nullptr;
419 if ( m_nControlWizardEvent
)
421 Application::RemoveUserEvent( m_nControlWizardEvent
);
422 m_nControlWizardEvent
= nullptr;
427 void FmXFormView::notifyViewDying( )
429 DBG_ASSERT( m_pView
, "FmXFormView::notifyViewDying: my view already died!" );
435 FmXFormView::~FmXFormView()
437 DBG_ASSERT( m_aPageWindowAdapters
.empty(), "FmXFormView::~FmXFormView: Window list not empty!" );
438 for (const auto& rpAdapter
: m_aPageWindowAdapters
)
440 rpAdapter
->dispose();
448 void SAL_CALL
FmXFormView::disposing(const EventObject
& Source
)
450 if ( m_xWindow
.is() && Source
.Source
== m_xWindow
)
452 m_xWindow
->removeFocusListener(this);
455 m_pView
->SetMoveOutside( false, FmFormView::ImplAccess() );
461 // XFormControllerListener
463 void SAL_CALL
FmXFormView::formActivated(const EventObject
& rEvent
)
465 if ( m_pView
&& m_pView
->GetFormShell() && m_pView
->GetFormShell()->GetImpl() )
466 m_pView
->GetFormShell()->GetImpl()->formActivated( rEvent
);
470 void SAL_CALL
FmXFormView::formDeactivated(const EventObject
& rEvent
)
472 if ( m_pView
&& m_pView
->GetFormShell() && m_pView
->GetFormShell()->GetImpl() )
473 m_pView
->GetFormShell()->GetImpl()->formDeactivated( rEvent
);
476 // XContainerListener
478 void SAL_CALL
FmXFormView::elementInserted(const ContainerEvent
& evt
)
482 Reference
< XControlContainer
> xControlContainer( evt
.Source
, UNO_QUERY_THROW
);
483 Reference
< XControl
> xControl( evt
.Element
, UNO_QUERY_THROW
);
484 Reference
< XFormComponent
> xControlModel( xControl
->getModel(), UNO_QUERY_THROW
);
485 Reference
< XForm
> xForm( xControlModel
->getParent(), UNO_QUERY_THROW
);
487 if ( m_isTabOrderUpdateSuspended
)
489 // remember the container and the control, so we can update the tab order on resumeTabOrderUpdate
490 m_aNeedTabOrderUpdate
[ xControlContainer
].insert( xForm
);
494 rtl::Reference
< FormViewPageWindowAdapter
> pAdapter
= findWindow( xControlContainer
);
496 pAdapter
->updateTabOrder( xForm
);
499 catch (const Exception
&)
501 DBG_UNHANDLED_EXCEPTION("svx");
506 void SAL_CALL
FmXFormView::elementReplaced(const ContainerEvent
& evt
)
508 elementInserted(evt
);
512 void SAL_CALL
FmXFormView::elementRemoved(const ContainerEvent
& /*evt*/)
517 rtl::Reference
< FormViewPageWindowAdapter
> FmXFormView::findWindow( const Reference
< XControlContainer
>& _rxCC
) const
519 auto i
= std::find_if(m_aPageWindowAdapters
.begin(), m_aPageWindowAdapters
.end(),
520 [&_rxCC
](const rtl::Reference
< FormViewPageWindowAdapter
>& rpAdapter
) { return _rxCC
== rpAdapter
->getControlContainer(); });
521 if (i
!= m_aPageWindowAdapters
.end())
527 void FmXFormView::addWindow(const SdrPageWindow
& rWindow
)
529 FmFormPage
* pFormPage
= dynamic_cast<FmFormPage
*>( rWindow
.GetPageView().GetPage() );
533 const Reference
< XControlContainer
>& xCC
= rWindow
.GetControlContainer();
535 && ( !findWindow( xCC
).is() )
538 rtl::Reference
< FormViewPageWindowAdapter
> pAdapter
= new FormViewPageWindowAdapter( comphelper::getProcessComponentContext(), rWindow
, this );
539 m_aPageWindowAdapters
.push_back( pAdapter
);
541 // listen at the ControlContainer to notice changes
542 Reference
< XContainer
> xContainer( xCC
, UNO_QUERY
);
543 if ( xContainer
.is() )
544 xContainer
->addContainerListener( this );
549 void FmXFormView::removeWindow( const Reference
< XControlContainer
>& _rxCC
)
552 // - the design mode is being switched to
553 // - a window is deleted while in the design mode
554 // - the control container for a window is removed while the active mode is on
556 auto i
= std::find_if(m_aPageWindowAdapters
.begin(), m_aPageWindowAdapters
.end(),
557 [&_rxCC
](const rtl::Reference
< FormViewPageWindowAdapter
>& rpAdapter
) { return _rxCC
== rpAdapter
->getControlContainer(); });
558 if (i
!= m_aPageWindowAdapters
.end())
560 Reference
< XContainer
> xContainer( _rxCC
, UNO_QUERY
);
561 if ( xContainer
.is() )
562 xContainer
->removeContainerListener( this );
565 m_aPageWindowAdapters
.erase( i
);
569 void FmXFormView::displayAsyncErrorMessage( const SQLErrorEvent
& _rEvent
)
571 DBG_ASSERT( nullptr == m_nErrorMessageEvent
, "FmXFormView::displayAsyncErrorMessage: not too fast, please!" );
572 // This should not happen - usually, the PostUserEvent is faster than any possible user
573 // interaction which could trigger a new error. If it happens, we need a queue for the events.
574 m_aAsyncError
= _rEvent
;
575 m_nErrorMessageEvent
= Application::PostUserEvent( LINK( this, FmXFormView
, OnDelayedErrorMessage
) );
578 IMPL_LINK_NOARG(FmXFormView
, OnDelayedErrorMessage
, void*, void)
580 m_nErrorMessageEvent
= nullptr;
581 displayException(m_aAsyncError
, GetParentWindow());
584 void FmXFormView::onFirstViewActivation( const FmFormModel
* _pDocModel
)
586 if ( _pDocModel
&& _pDocModel
->GetAutoControlFocus() )
587 m_nAutoFocusEvent
= Application::PostUserEvent( LINK( this, FmXFormView
, OnAutoFocus
) );
590 void FmXFormView::suspendTabOrderUpdate()
592 OSL_ENSURE( !m_isTabOrderUpdateSuspended
, "FmXFormView::suspendTabOrderUpdate: nesting not allowed!" );
593 m_isTabOrderUpdateSuspended
= true;
596 void FmXFormView::resumeTabOrderUpdate()
598 OSL_ENSURE( m_isTabOrderUpdateSuspended
, "FmXFormView::resumeTabOrderUpdate: not suspended!" );
599 m_isTabOrderUpdateSuspended
= false;
601 // update the tab orders for all components which were collected since the suspendTabOrderUpdate call.
602 for (const auto& rContainer
: m_aNeedTabOrderUpdate
)
604 rtl::Reference
< FormViewPageWindowAdapter
> pAdapter
= findWindow( rContainer
.first
);
605 if ( !pAdapter
.is() )
608 for (const auto& rForm
: rContainer
.second
)
610 pAdapter
->updateTabOrder( rForm
);
613 m_aNeedTabOrderUpdate
.clear();
618 bool isActivableDatabaseForm(const Reference
< XFormController
> &xController
)
620 // only database forms are to be activated
621 Reference
< XRowSet
> xForm(xController
->getModel(), UNO_QUERY
);
622 if ( !xForm
.is() || !getConnection( xForm
).is() )
625 Reference
< XPropertySet
> xFormSet( xForm
, UNO_QUERY
);
626 if ( !xFormSet
.is() )
628 SAL_WARN( "svx.form", "FmXFormView::OnActivate: a form which does not have properties?" );
632 const OUString aSource
= ::comphelper::getString( xFormSet
->getPropertyValue( FM_PROP_COMMAND
) );
634 return !aSource
.isEmpty();
637 class find_active_databaseform
639 const Reference
< XFormController
> xActiveController
;
643 explicit find_active_databaseform( const Reference
< XFormController
>& _xActiveController
)
644 : xActiveController(_xActiveController
)
647 Reference
< XFormController
> operator() (const Reference
< XFormController
> &xController
)
649 if(xController
== xActiveController
&& isActivableDatabaseForm(xController
))
652 if ( !xController
.is() )
654 SAL_WARN( "svx.form", "FmXFormView::OnActivate: a form controller which does not have children?" );
658 for(sal_Int32 i
= 0; i
< xController
->getCount(); ++i
)
660 const Any
a(xController
->getByIndex(i
));
661 Reference
< XFormController
> xI
;
662 if ((a
>>= xI
) && xI
.is())
664 Reference
< XFormController
> xRes(operator()(xI
));
676 IMPL_LINK_NOARG(FmXFormView
, OnActivate
, void*, void)
678 m_nActivationEvent
= nullptr;
682 OSL_FAIL( "FmXFormView::OnActivate: well... seems we have a timing problem (the view already died)!" );
686 // setting the controller to activate
687 if (!(m_pView
->GetFormShell() && m_pView
->GetActualOutDev() && m_pView
->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW
))
690 FmXFormShell
* const pShImpl
= m_pView
->GetFormShell()->GetImpl();
695 find_active_databaseform
fad(pShImpl
->getActiveController_Lock());
697 vcl::Window
* pWindow
= m_pView
->GetActualOutDev()->GetOwnerWindow();
698 rtl::Reference
< FormViewPageWindowAdapter
> pAdapter
= m_aPageWindowAdapters
.empty() ? nullptr : m_aPageWindowAdapters
[0];
699 for (const auto& rpPageWindowAdapter
: m_aPageWindowAdapters
)
701 if ( pWindow
== rpPageWindowAdapter
->getWindow() )
702 pAdapter
= rpPageWindowAdapter
;
705 if ( !pAdapter
.is() )
708 Reference
< XFormController
> xControllerToActivate
;
709 for (const Reference
< XFormController
> & xController
: pAdapter
->GetList())
711 if ( !xController
.is() )
715 Reference
< XFormController
> xActiveController(fad(xController
));
716 if (xActiveController
.is())
718 xControllerToActivate
= xActiveController
;
723 if(xControllerToActivate
.is() || !isActivableDatabaseForm(xController
))
726 xControllerToActivate
= xController
;
728 pShImpl
->setActiveController_Lock(xControllerToActivate
);
732 void FmXFormView::Activate(bool bSync
)
734 if (m_nActivationEvent
)
736 Application::RemoveUserEvent(m_nActivationEvent
);
737 m_nActivationEvent
= nullptr;
742 LINK(this,FmXFormView
,OnActivate
).Call(nullptr);
745 m_nActivationEvent
= Application::PostUserEvent(LINK(this,FmXFormView
,OnActivate
));
749 void FmXFormView::Deactivate(bool bDeactivateController
)
751 if (m_nActivationEvent
)
753 Application::RemoveUserEvent(m_nActivationEvent
);
754 m_nActivationEvent
= nullptr;
757 FmXFormShell
* pShImpl
= m_pView
->GetFormShell() ? m_pView
->GetFormShell()->GetImpl() : nullptr;
758 if (pShImpl
&& bDeactivateController
)
759 pShImpl
->setActiveController_Lock(nullptr);
763 FmFormShell
* FmXFormView::GetFormShell() const
765 return m_pView
? m_pView
->GetFormShell() : nullptr;
768 void FmXFormView::AutoFocus()
770 if (m_nAutoFocusEvent
)
771 Application::RemoveUserEvent(m_nAutoFocusEvent
);
773 m_nAutoFocusEvent
= Application::PostUserEvent(LINK(this, FmXFormView
, OnAutoFocus
));
777 bool FmXFormView::isFocusable( const Reference
< XControl
>& i_rControl
)
779 if ( !i_rControl
.is() )
784 Reference
< XPropertySet
> xModelProps( i_rControl
->getModel(), UNO_QUERY_THROW
);
786 // only enabled controls are allowed to participate
787 bool bEnabled
= false;
788 OSL_VERIFY( xModelProps
->getPropertyValue( FM_PROP_ENABLED
) >>= bEnabled
);
792 // check the class id of the control model
793 sal_Int16 nClassId
= FormComponentType::CONTROL
;
794 OSL_VERIFY( xModelProps
->getPropertyValue( FM_PROP_CLASSID
) >>= nClassId
);
796 // controls which are not focussable
797 if ( ( FormComponentType::CONTROL
!= nClassId
)
798 && ( FormComponentType::IMAGEBUTTON
!= nClassId
)
799 && ( FormComponentType::GROUPBOX
!= nClassId
)
800 && ( FormComponentType::FIXEDTEXT
!= nClassId
)
801 && ( FormComponentType::HIDDENCONTROL
!= nClassId
)
802 && ( FormComponentType::IMAGECONTROL
!= nClassId
)
803 && ( FormComponentType::SCROLLBAR
!= nClassId
)
804 && ( FormComponentType::SPINBUTTON
!= nClassId
)
810 catch (const Exception
&)
812 DBG_UNHANDLED_EXCEPTION("svx");
818 static Reference
< XControl
> lcl_firstFocussableControl( const Sequence
< Reference
< XControl
> >& _rControls
)
820 Reference
< XControl
> xReturn
;
822 // loop through all the controls
823 for ( auto const & control
: _rControls
)
828 if ( FmXFormView::isFocusable( control
) )
835 if ( !xReturn
.is() && _rControls
.hasElements() )
836 xReturn
= _rControls
[0];
845 void lcl_ensureControlsOfFormExist_nothrow( const SdrPage
& _rPage
, const SdrView
& _rView
, const vcl::Window
& _rWindow
, const Reference
< XForm
>& _rxForm
)
849 Reference
< XInterface
> xNormalizedForm( _rxForm
, UNO_QUERY_THROW
);
851 SdrObjListIter
aSdrObjectLoop( &_rPage
, SdrIterMode::DeepNoGroups
);
852 while ( aSdrObjectLoop
.IsMore() )
854 FmFormObj
* pFormObject
= FmFormObj::GetFormObject( aSdrObjectLoop
.Next() );
858 Reference
< XChild
> xModel( pFormObject
->GetUnoControlModel(), UNO_QUERY_THROW
);
859 Reference
< XInterface
> xModelParent( xModel
->getParent(), UNO_QUERY
);
861 if ( xNormalizedForm
.get() != xModelParent
.get() )
864 pFormObject
->GetUnoControl( _rView
, *_rWindow
.GetOutDev() );
867 catch (const Exception
&)
869 DBG_UNHANDLED_EXCEPTION("svx");
875 Reference
< XFormController
> FmXFormView::getFormController( const Reference
< XForm
>& _rxForm
, const OutputDevice
& _rDevice
) const
877 Reference
< XFormController
> xController
;
879 for (const rtl::Reference
< FormViewPageWindowAdapter
>& pAdapter
: m_aPageWindowAdapters
)
883 SAL_WARN( "svx.form", "FmXFormView::getFormController: invalid page window adapter!" );
887 if ( pAdapter
->getWindow() != _rDevice
.GetOwnerWindow() )
891 xController
= pAdapter
->getController( _rxForm
);
892 if ( xController
.is() )
899 IMPL_LINK_NOARG(FmXFormView
, OnAutoFocus
, void*, void)
901 m_nAutoFocusEvent
= nullptr;
903 // go to the first form of our page, examine it's TabController, go to its first (in terms of the tab order)
904 // control, give it the focus
906 SdrPageView
*pPageView
= m_pView
? m_pView
->GetSdrPageView() : nullptr;
907 SdrPage
*pSdrPage
= pPageView
? pPageView
->GetPage() : nullptr;
908 // get the forms collection of the page we belong to
909 FmFormPage
* pPage
= dynamic_cast<FmFormPage
*>( pSdrPage
);
910 Reference
< XIndexAccess
> xForms( pPage
? Reference
< XIndexAccess
>( pPage
->GetForms() ) : Reference
< XIndexAccess
>() );
912 const rtl::Reference
< FormViewPageWindowAdapter
> pAdapter
= m_aPageWindowAdapters
.empty() ? nullptr : m_aPageWindowAdapters
[0];
913 const vcl::Window
* pWindow
= pAdapter
? pAdapter
->getWindow() : nullptr;
915 ENSURE_OR_RETURN_VOID( xForms
.is() && pWindow
, "FmXFormView::OnAutoFocus: could not collect all essentials!" );
919 // go for the tab controller of the first form
920 if ( !xForms
->getCount() )
922 Reference
< XForm
> xForm( xForms
->getByIndex( 0 ), UNO_QUERY_THROW
);
923 Reference
< XTabController
> xTabController( pAdapter
->getController( xForm
), UNO_QUERY_THROW
);
925 // go for the first control of the controller
926 Sequence
< Reference
< XControl
> > aControls( xTabController
->getControls() );
927 if ( !aControls
.hasElements() )
929 Reference
< XElementAccess
> xFormElementAccess( xForm
, UNO_QUERY_THROW
);
930 if (xFormElementAccess
->hasElements() && pPage
&& m_pView
)
932 // there are control models in the form, but no controls, yet.
933 // Well, since some time controls are created on demand only. In particular,
934 // they're normally created when they're first painted.
935 // Unfortunately, the FormController does not have any way to
936 // trigger the creation itself, so we must hack this ...
937 lcl_ensureControlsOfFormExist_nothrow( *pPage
, *m_pView
, *pWindow
, xForm
);
938 aControls
= xTabController
->getControls();
939 OSL_ENSURE( aControls
.hasElements(), "FmXFormView::OnAutoFocus: no controls at all!" );
943 // set the focus to this first control
944 Reference
< XWindow
> xControlWindow( lcl_firstFocussableControl( aControls
), UNO_QUERY
);
945 if ( !xControlWindow
.is() )
948 xControlWindow
->setFocus();
950 // ensure that the control is visible
951 // 80210 - 12/07/00 - FS
952 const OutputDevice
* pOut
= m_pView
? m_pView
->GetActualOutDev() : nullptr;
953 const vcl::Window
* pCurrentWindow
= pOut
? pOut
->GetOwnerWindow() : nullptr;
954 if ( pCurrentWindow
)
956 awt::Rectangle aRect
= xControlWindow
->getPosSize();
957 ::tools::Rectangle
aNonUnoRect( aRect
.X
, aRect
.Y
, aRect
.X
+ aRect
.Width
, aRect
.Y
+ aRect
.Height
);
958 m_pView
->MakeVisible( pCurrentWindow
->PixelToLogic( aNonUnoRect
), *const_cast< vcl::Window
* >( pCurrentWindow
) );
961 catch (const Exception
&)
963 DBG_UNHANDLED_EXCEPTION("svx");
968 void FmXFormView::onCreatedFormObject( FmFormObj
const & _rFormObject
)
970 FmFormShell
* pShell
= m_pView
? m_pView
->GetFormShell() : nullptr;
971 FmXFormShell
* pShellImpl
= pShell
? pShell
->GetImpl() : nullptr;
972 OSL_ENSURE( pShellImpl
, "FmXFormView::onCreatedFormObject: no form shell!" );
976 // it is valid that the form shell's forms collection is not initialized, yet
977 pShellImpl
->UpdateForms_Lock(true);
979 m_xLastCreatedControlModel
.set( _rFormObject
.GetUnoControlModel(), UNO_QUERY
);
980 if ( !m_xLastCreatedControlModel
.is() )
983 // some initial property defaults
984 FormControlFactory aControlFactory
;
985 aControlFactory
.initializeControlModel(pShellImpl
->getDocumentType_Lock(), _rFormObject
);
987 if (!pShellImpl
->GetWizardUsing_Lock())
990 // #i31958# don't call wizards in XForms mode
991 if (pShellImpl
->isEnhancedForm_Lock())
994 // #i46898# no wizards if there is no Base installed - currently, all wizards are
996 if ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE
) )
999 if ( m_nControlWizardEvent
)
1000 Application::RemoveUserEvent( m_nControlWizardEvent
);
1001 m_nControlWizardEvent
= Application::PostUserEvent( LINK( this, FmXFormView
, OnStartControlWizard
) );
1004 void FmXFormView::breakCreateFormObject()
1006 if (m_nControlWizardEvent
!= nullptr)
1008 Application::RemoveUserEvent(m_nControlWizardEvent
);
1009 m_nControlWizardEvent
= nullptr;
1011 m_xLastCreatedControlModel
.clear();
1014 Reference
<XWindow
> FmXFormView::GetParentWindow() const
1016 const OutputDevice
* pOut
= m_pView
? m_pView
->GetActualOutDev() : nullptr;
1017 const vcl::Window
* pCurrentWindow
= pOut
? pOut
->GetOwnerWindow() : nullptr;
1018 return VCLUnoHelper::GetInterface(const_cast<vcl::Window
*>(pCurrentWindow
));
1021 IMPL_LINK_NOARG( FmXFormView
, OnStartControlWizard
, void*, void )
1023 m_nControlWizardEvent
= nullptr;
1024 OSL_PRECOND( m_xLastCreatedControlModel
.is(), "FmXFormView::OnStartControlWizard: illegal call!" );
1025 if ( !m_xLastCreatedControlModel
.is() )
1028 sal_Int16 nClassId
= FormComponentType::CONTROL
;
1031 OSL_VERIFY( m_xLastCreatedControlModel
->getPropertyValue( FM_PROP_CLASSID
) >>= nClassId
);
1033 catch (const Exception
&)
1035 DBG_UNHANDLED_EXCEPTION("svx");
1038 const char* pWizardAsciiName
= nullptr;
1041 case FormComponentType::GRIDCONTROL
:
1042 pWizardAsciiName
= "com.sun.star.sdb.GridControlAutoPilot";
1044 case FormComponentType::LISTBOX
:
1045 case FormComponentType::COMBOBOX
:
1046 pWizardAsciiName
= "com.sun.star.sdb.ListComboBoxAutoPilot";
1048 case FormComponentType::GROUPBOX
:
1049 pWizardAsciiName
= "com.sun.star.sdb.GroupBoxAutoPilot";
1053 if ( pWizardAsciiName
)
1055 // build the argument list
1056 ::comphelper::NamedValueCollection aWizardArgs
;
1057 aWizardArgs
.put("ObjectModel", m_xLastCreatedControlModel
);
1058 aWizardArgs
.put("ParentWindow", GetParentWindow());
1060 // create the wizard object
1061 Reference
< XExecutableDialog
> xWizard
;
1064 Reference
<XComponentContext
> xContext
= comphelper::getProcessComponentContext();
1065 xWizard
.set( xContext
->getServiceManager()->createInstanceWithArgumentsAndContext( OUString::createFromAscii(pWizardAsciiName
), aWizardArgs
.getWrappedPropertyValues(), xContext
), UNO_QUERY
);
1067 catch (const Exception
&)
1069 DBG_UNHANDLED_EXCEPTION("svx");
1072 if ( !xWizard
.is() )
1074 ShowServiceNotAvailableError( nullptr, OUString::createFromAscii(pWizardAsciiName
), true );
1078 // execute the wizard
1083 catch (const Exception
&)
1085 DBG_UNHANDLED_EXCEPTION("svx");
1090 m_xLastCreatedControlModel
.clear();
1096 void lcl_insertIntoFormComponentHierarchy_throw( const FmFormView
& _rView
, const SdrUnoObj
& _rSdrObj
,
1097 const Reference
< XDataSource
>& _rxDataSource
, const OUString
& _rDataSourceName
,
1098 const OUString
& _rCommand
, const sal_Int32 _nCommandType
)
1100 FmFormPage
& rPage
= static_cast< FmFormPage
& >( *_rView
.GetSdrPageView()->GetPage() );
1102 Reference
< XFormComponent
> xFormComponent( _rSdrObj
.GetUnoControlModel(), UNO_QUERY_THROW
);
1103 Reference
< XForm
> xTargetForm(
1104 rPage
.GetImpl().findPlaceInFormComponentHierarchy( xFormComponent
, _rxDataSource
, _rDataSourceName
, _rCommand
, _nCommandType
),
1107 FmFormPageImpl::setUniqueName( xFormComponent
, xTargetForm
);
1109 Reference
< XIndexContainer
> xFormAsContainer( xTargetForm
, UNO_QUERY_THROW
);
1110 xFormAsContainer
->insertByIndex( xFormAsContainer
->getCount(), makeAny( xFormComponent
) );
1115 SdrObjectUniquePtr
FmXFormView::implCreateFieldControl( const svx::ODataAccessDescriptor
& _rColumnDescriptor
)
1117 // not if we're in design mode
1118 if ( !m_pView
->IsDesignMode() )
1121 OUString sCommand
, sFieldName
;
1122 sal_Int32 nCommandType
= CommandType::COMMAND
;
1123 SharedConnection xConnection
;
1125 OUString sDataSource
= _rColumnDescriptor
.getDataSource();
1126 _rColumnDescriptor
[ DataAccessDescriptorProperty::Command
] >>= sCommand
;
1127 _rColumnDescriptor
[ DataAccessDescriptorProperty::ColumnName
] >>= sFieldName
;
1128 _rColumnDescriptor
[ DataAccessDescriptorProperty::CommandType
] >>= nCommandType
;
1130 Reference
< XConnection
> xExternalConnection
;
1131 _rColumnDescriptor
[ DataAccessDescriptorProperty::Connection
] >>= xExternalConnection
;
1132 xConnection
.reset( xExternalConnection
, SharedConnection::NoTakeOwnership
);
1135 if ( sCommand
.isEmpty()
1136 || sFieldName
.isEmpty()
1137 || ( sDataSource
.isEmpty()
1138 && !xConnection
.is()
1142 OSL_FAIL( "FmXFormView::implCreateFieldControl: nonsense!" );
1145 Reference
< XDataSource
> xDataSource
;
1146 SQLErrorEvent aError
;
1149 if ( xConnection
.is() && !xDataSource
.is() && sDataSource
.isEmpty() )
1151 Reference
< XChild
> xChild( xConnection
, UNO_QUERY
);
1153 xDataSource
.set(xChild
->getParent(), css::uno::UNO_QUERY
);
1156 // obtain the data source
1157 if ( !xDataSource
.is() )
1158 xDataSource
= getDataSource( sDataSource
, comphelper::getProcessComponentContext() );
1160 // and the connection, if necessary
1161 if ( !xConnection
.is() )
1162 xConnection
.reset( getConnection_withFeedback(
1166 comphelper::getProcessComponentContext(),
1170 catch (const SQLException
&)
1172 aError
.Reason
= ::cppu::getCaughtException();
1174 catch (const Exception
& )
1176 /* will be asserted below */
1178 if (aError
.Reason
.hasValue())
1180 displayAsyncErrorMessage( aError
);
1184 // need a data source and a connection here
1185 if (!xDataSource
.is() || !xConnection
.is())
1187 OSL_FAIL("FmXFormView::implCreateFieldControl : could not retrieve the data source or the connection!");
1191 Reference
< XComponent
> xKeepFieldsAlive
;
1195 // determine the table/query field which we should create a control for
1196 Reference
< XPropertySet
> xField
;
1198 Reference
< XNameAccess
> xFields
= getFieldsByCommandDescriptor(
1199 xConnection
, nCommandType
, sCommand
, xKeepFieldsAlive
);
1201 if (xFields
.is() && xFields
->hasByName(sFieldName
))
1202 xFields
->getByName(sFieldName
) >>= xField
;
1206 Reference
< XNumberFormatsSupplier
> xSupplier( getNumberFormats( xConnection
), UNO_SET_THROW
);
1207 Reference
< XNumberFormats
> xNumberFormats( xSupplier
->getNumberFormats(), UNO_SET_THROW
);
1209 OUString sLabelPostfix
;
1212 // only for text size
1213 OutputDevice
* pOutDev
= nullptr;
1214 if (m_pView
->GetActualOutDev() && m_pView
->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW
)
1215 pOutDev
= const_cast<OutputDevice
*>(m_pView
->GetActualOutDev());
1218 if (SdrPageView
* pPageView
= m_pView
->GetSdrPageView())
1220 // const SdrPageViewWinList& rWinList = pPageView->GetWinList();
1221 // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows();
1223 for( sal_uInt32 i
= 0; i
< pPageView
->PageWindowCount(); i
++ )
1225 const SdrPageWindow
& rPageWindow
= *pPageView
->GetPageWindow(i
);
1227 if( rPageWindow
.GetPaintWindow().OutputToWindow())
1229 pOutDev
= &rPageWindow
.GetPaintWindow().GetOutputDevice();
1239 sal_Int32 nDataType
= ::comphelper::getINT32(xField
->getPropertyValue(FM_PROP_FIELDTYPE
));
1240 if ((DataType::BINARY
== nDataType
) || (DataType::VARBINARY
== nDataType
))
1244 // determine the control type by examining the data type of the bound column
1245 SdrObjKind nOBJID
= OBJ_NONE
;
1246 bool bDateNTimeField
= false;
1248 bool bIsCurrency
= false;
1249 if (::comphelper::hasProperty(FM_PROP_ISCURRENCY
, xField
))
1250 bIsCurrency
= ::comphelper::getBOOL(xField
->getPropertyValue(FM_PROP_ISCURRENCY
));
1253 nOBJID
= OBJ_FM_CURRENCYFIELD
;
1257 case DataType::BLOB
:
1258 case DataType::LONGVARBINARY
:
1259 nOBJID
= OBJ_FM_IMAGECONTROL
;
1261 case DataType::LONGVARCHAR
:
1262 case DataType::CLOB
:
1263 nOBJID
= OBJ_FM_EDIT
;
1265 case DataType::BINARY
:
1266 case DataType::VARBINARY
:
1269 case DataType::BOOLEAN
:
1270 nOBJID
= OBJ_FM_CHECKBOX
;
1272 case DataType::TINYINT
:
1273 case DataType::SMALLINT
:
1274 case DataType::INTEGER
:
1275 nOBJID
= OBJ_FM_NUMERICFIELD
;
1277 case DataType::REAL
:
1278 case DataType::DOUBLE
:
1279 case DataType::NUMERIC
:
1280 case DataType::DECIMAL
:
1281 nOBJID
= OBJ_FM_FORMATTEDFIELD
;
1283 case DataType::TIMESTAMP
:
1284 bDateNTimeField
= true;
1285 sLabelPostfix
= SvxResId(RID_STR_POSTFIX_DATE
);
1287 case DataType::DATE
:
1288 nOBJID
= OBJ_FM_DATEFIELD
;
1290 case DataType::TIME
:
1291 nOBJID
= OBJ_FM_TIMEFIELD
;
1293 case DataType::CHAR
:
1294 case DataType::VARCHAR
:
1296 nOBJID
= OBJ_FM_EDIT
;
1302 std::unique_ptr
<SdrUnoObj
, SdrObjectFreeOp
> pLabel
;
1303 std::unique_ptr
<SdrUnoObj
, SdrObjectFreeOp
> pControl
;
1304 if ( !createControlLabelPair( *pOutDev
, 0, 0, xField
, xNumberFormats
, nOBJID
, sLabelPostfix
,
1305 pLabel
, pControl
, xDataSource
, sDataSource
, sCommand
, nCommandType
)
1313 bool bCheckbox
= ( OBJ_FM_CHECKBOX
== nOBJID
);
1314 OSL_ENSURE( !bCheckbox
|| !pLabel
, "FmXFormView::implCreateFieldControl: why was there a label created for a check box?" );
1316 return SdrObjectUniquePtr(pControl
.release());
1318 SdrObjGroup
* pGroup
= new SdrObjGroup(getView()->getSdrModelFromSdrView());
1319 SdrObjList
* pObjList
= pGroup
->GetSubList();
1320 pObjList
->InsertObject( pLabel
.release() );
1321 pObjList
->InsertObject( pControl
.release() );
1323 if ( bDateNTimeField
)
1324 { // so far we created a date field only, but we also need a time field
1325 if ( createControlLabelPair( *pOutDev
, 0, 1000, xField
, xNumberFormats
, OBJ_FM_TIMEFIELD
,
1326 SvxResId(RID_STR_POSTFIX_TIME
), pLabel
, pControl
,
1327 xDataSource
, sDataSource
, sCommand
, nCommandType
)
1330 pObjList
->InsertObject( pLabel
.release() );
1331 pObjList
->InsertObject( pControl
.release() );
1335 return SdrObjectUniquePtr(pGroup
); // and done
1337 catch (const Exception
&)
1339 DBG_UNHANDLED_EXCEPTION("svx");
1347 SdrObjectUniquePtr
FmXFormView::implCreateXFormsControl( const svx::OXFormsDescriptor
&_rDesc
)
1349 // not if we're in design mode
1350 if ( !m_pView
->IsDesignMode() )
1356 // determine the table/query field which we should create a control for
1357 Reference
< XNumberFormats
> xNumberFormats
;
1358 OUString sLabelPostfix
= _rDesc
.szName
;
1361 // only for text size
1362 OutputDevice
* pOutDev
= nullptr;
1363 if (m_pView
->GetActualOutDev() && m_pView
->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW
)
1364 pOutDev
= const_cast<OutputDevice
*>(m_pView
->GetActualOutDev());
1367 if (SdrPageView
* pPageView
= m_pView
->GetSdrPageView())
1369 // const SdrPageViewWinList& rWinList = pPageView->GetWinList();
1370 // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows();
1372 for( sal_uInt32 i
= 0; i
< pPageView
->PageWindowCount(); i
++ )
1374 const SdrPageWindow
& rPageWindow
= *pPageView
->GetPageWindow(i
);
1376 if( rPageWindow
.GetPaintWindow().GetOutputDevice().GetOutDevType() == OUTDEV_WINDOW
)
1378 pOutDev
= &rPageWindow
.GetPaintWindow().GetOutputDevice();
1389 // The service name decides which control should be created
1390 SdrObjKind nOBJID
= OBJ_FM_EDIT
;
1391 if(_rDesc
.szServiceName
== FM_SUN_COMPONENT_NUMERICFIELD
)
1392 nOBJID
= OBJ_FM_NUMERICFIELD
;
1393 if(_rDesc
.szServiceName
== FM_SUN_COMPONENT_CHECKBOX
)
1394 nOBJID
= OBJ_FM_CHECKBOX
;
1395 if(_rDesc
.szServiceName
== FM_COMPONENT_COMMANDBUTTON
)
1396 nOBJID
= OBJ_FM_BUTTON
;
1398 Reference
< css::form::submission::XSubmission
> xSubmission(_rDesc
.xPropSet
, UNO_QUERY
);
1400 // xform control or submission button?
1401 if ( !xSubmission
.is() )
1403 std::unique_ptr
<SdrUnoObj
, SdrObjectFreeOp
> pLabel
;
1404 std::unique_ptr
<SdrUnoObj
, SdrObjectFreeOp
> pControl
;
1405 if ( !createControlLabelPair( *pOutDev
, 0, 0, nullptr, xNumberFormats
, nOBJID
, sLabelPostfix
,
1406 pLabel
, pControl
, nullptr, "", "", -1 )
1413 // Now build the connection between the control and the data item.
1414 Reference
< XValueBinding
> xValueBinding(_rDesc
.xPropSet
,UNO_QUERY
);
1415 Reference
< XBindableValue
> xBindableValue(pControl
->GetUnoControlModel(),UNO_QUERY
);
1417 DBG_ASSERT( xBindableValue
.is(), "FmXFormView::implCreateXFormsControl: control's not bindable!" );
1418 if ( xBindableValue
.is() )
1419 xBindableValue
->setValueBinding(xValueBinding
);
1421 bool bCheckbox
= ( OBJ_FM_CHECKBOX
== nOBJID
);
1422 OSL_ENSURE( !bCheckbox
|| !pLabel
, "FmXFormView::implCreateXFormsControl: why was there a label created for a check box?" );
1424 return SdrObjectUniquePtr(pControl
.release());
1428 SdrObjGroup
* pGroup
= new SdrObjGroup(getView()->getSdrModelFromSdrView());
1429 SdrObjList
* pObjList
= pGroup
->GetSubList();
1430 pObjList
->InsertObject(pLabel
.release());
1431 pObjList
->InsertObject(pControl
.release());
1433 return SdrObjectUniquePtr(pGroup
);
1437 // create a button control
1438 const MapMode
& eTargetMode( pOutDev
->GetMapMode() );
1439 const MapMode
eSourceMode(MapUnit::Map100thMM
);
1440 const SdrObjKind nObjID
= OBJ_FM_BUTTON
;
1441 ::Size
controlSize(4000, 500);
1442 FmFormObj
*pControl
= static_cast<FmFormObj
*>(
1443 SdrObjFactory::MakeNewObject(
1444 getView()->getSdrModelFromSdrView(),
1445 SdrInventor::FmForm
,
1447 controlSize
.setWidth( tools::Long(controlSize
.Width() * eTargetMode
.GetScaleX()) );
1448 controlSize
.setHeight( tools::Long(controlSize
.Height() * eTargetMode
.GetScaleY()) );
1449 ::Point
controlPos( OutputDevice::LogicToLogic( ::Point( controlSize
.Width(), 0 ), eSourceMode
, eTargetMode
) );
1450 ::tools::Rectangle
controlRect( controlPos
, OutputDevice::LogicToLogic( controlSize
, eSourceMode
, eTargetMode
) );
1451 pControl
->SetLogicRect(controlRect
);
1453 // set the button label
1454 Reference
< XPropertySet
> xControlSet(pControl
->GetUnoControlModel(), UNO_QUERY
);
1455 xControlSet
->setPropertyValue(FM_PROP_LABEL
, makeAny(_rDesc
.szName
));
1457 // connect the submission with the submission supplier (aka the button)
1458 xControlSet
->setPropertyValue( FM_PROP_BUTTON_TYPE
,
1459 makeAny( FormButtonType_SUBMIT
) );
1460 Reference
< css::form::submission::XSubmissionSupplier
> xSubmissionSupplier(pControl
->GetUnoControlModel(), UNO_QUERY
);
1461 xSubmissionSupplier
->setSubmission(xSubmission
);
1463 return SdrObjectUniquePtr(pControl
);
1466 catch (const Exception
&)
1468 TOOLS_WARN_EXCEPTION("svx.form", "caught an exception while creating the control !");
1475 bool FmXFormView::createControlLabelPair( OutputDevice
const & _rOutDev
, sal_Int32 _nXOffsetMM
, sal_Int32 _nYOffsetMM
,
1476 const Reference
< XPropertySet
>& _rxField
, const Reference
< XNumberFormats
>& _rxNumberFormats
,
1477 SdrObjKind _nControlObjectID
, std::u16string_view _rFieldPostfix
,
1478 std::unique_ptr
<SdrUnoObj
, SdrObjectFreeOp
>& _rpLabel
,
1479 std::unique_ptr
<SdrUnoObj
, SdrObjectFreeOp
>& _rpControl
,
1480 const Reference
< XDataSource
>& _rxDataSource
, const OUString
& _rDataSourceName
,
1481 const OUString
& _rCommand
, const sal_Int32 _nCommandType
)
1483 if(!createControlLabelPair(
1491 SdrInventor::FmForm
,
1494 // tdf#118963 Hand over a SdrModel to SdrObject-creation. It uses the local m_pView
1495 // and already returning false when nullptr == getView() could be done, but m_pView
1496 // is already dereferenced here in many places (see below), so just use it for now.
1497 getView()->getSdrModelFromSdrView(),
1505 // insert the control model(s) into the form component hierarchy
1507 lcl_insertIntoFormComponentHierarchy_throw( *m_pView
, *_rpLabel
, _rxDataSource
, _rDataSourceName
, _rCommand
, _nCommandType
);
1508 lcl_insertIntoFormComponentHierarchy_throw( *m_pView
, *_rpControl
, _rxDataSource
, _rDataSourceName
, _rCommand
, _nCommandType
);
1510 // some context-dependent initializations
1511 FormControlFactory aControlFactory
;
1513 aControlFactory
.initializeControlModel( impl_getDocumentType(), *_rpLabel
);
1514 aControlFactory
.initializeControlModel( impl_getDocumentType(), *_rpControl
);
1520 bool FmXFormView::createControlLabelPair( OutputDevice
const & _rOutDev
, sal_Int32 _nXOffsetMM
, sal_Int32 _nYOffsetMM
,
1521 const Reference
< XPropertySet
>& _rxField
,
1522 const Reference
< XNumberFormats
>& _rxNumberFormats
, SdrObjKind _nControlObjectID
,
1523 std::u16string_view _rFieldPostfix
, SdrInventor _nInventor
, SdrObjKind _nLabelObjectID
,
1525 std::unique_ptr
<SdrUnoObj
, SdrObjectFreeOp
>& _rpLabel
, std::unique_ptr
<SdrUnoObj
, SdrObjectFreeOp
>& _rpControl
)
1527 sal_Int32 nDataType
= 0;
1528 OUString sFieldName
;
1530 if ( _rxField
.is() )
1532 nDataType
= ::comphelper::getINT32(_rxField
->getPropertyValue(FM_PROP_FIELDTYPE
));
1533 aFieldName
= _rxField
->getPropertyValue(FM_PROP_NAME
);
1534 aFieldName
>>= sFieldName
;
1537 // calculate the positions, respecting the settings of the target device
1538 ::Size
aTextSize( _rOutDev
.GetTextWidth(sFieldName
+ _rFieldPostfix
), _rOutDev
.GetTextHeight() );
1540 MapMode
eTargetMode( _rOutDev
.GetMapMode() ),
1541 eSourceMode( MapUnit::Map100thMM
);
1543 // text width is at least 4 centimeters
1544 // text height is always half a centimeter
1545 ::Size
aDefTxtSize(4000, 500);
1546 ::Size
aDefSize(4000, 500);
1547 ::Size
aDefImageSize(4000, 4000);
1549 ::Size aRealSize
= OutputDevice::LogicToLogic(aTextSize
, eTargetMode
, eSourceMode
);
1550 aRealSize
.setWidth( std::max(aRealSize
.Width(), aDefTxtSize
.Width()) );
1551 aRealSize
.setHeight( aDefSize
.Height() );
1553 // adjust to scaling of the target device (#53523#)
1554 aRealSize
.setWidth( tools::Long(Fraction(aRealSize
.Width(), 1) * eTargetMode
.GetScaleX()) );
1555 aRealSize
.setHeight( tools::Long(Fraction(aRealSize
.Height(), 1) * eTargetMode
.GetScaleY()) );
1557 // for boolean fields, we do not create a label, but just a checkbox
1558 bool bNeedLabel
= ( _nControlObjectID
!= OBJ_FM_CHECKBOX
);
1561 ::std::unique_ptr
< SdrUnoObj
, SdrObjectFreeOp
> pLabel
;
1562 Reference
< XPropertySet
> xLabelModel
;
1566 pLabel
.reset( dynamic_cast< SdrUnoObj
* >(
1567 SdrObjFactory::MakeNewObject(
1572 OSL_ENSURE(pLabel
, "FmXFormView::createControlLabelPair: could not create the label!");
1577 xLabelModel
.set( pLabel
->GetUnoControlModel(), UNO_QUERY
);
1578 if ( xLabelModel
.is() )
1581 if ( _rxField
.is() && _rxField
->getPropertySetInfo()->hasPropertyByName(FM_PROP_LABEL
) )
1582 _rxField
->getPropertyValue(FM_PROP_LABEL
) >>= sLabel
;
1583 if ( sLabel
.isEmpty() )
1584 sLabel
= sFieldName
;
1586 xLabelModel
->setPropertyValue( FM_PROP_LABEL
, makeAny( sLabel
+ _rFieldPostfix
) );
1587 OUString
sObjectLabel(SvxResId(RID_STR_OBJECT_LABEL
).replaceAll("#object#", sFieldName
));
1588 xLabelModel
->setPropertyValue(FM_PROP_NAME
, makeAny(sObjectLabel
));
1591 pLabel
->SetLogicRect( ::tools::Rectangle(
1592 OutputDevice::LogicToLogic( ::Point( _nXOffsetMM
, _nYOffsetMM
), eSourceMode
, eTargetMode
),
1593 OutputDevice::LogicToLogic( aRealSize
, eSourceMode
, eTargetMode
)
1598 ::std::unique_ptr
< SdrUnoObj
, SdrObjectFreeOp
> pControl( dynamic_cast< SdrUnoObj
* >(
1599 SdrObjFactory::MakeNewObject(
1602 _nControlObjectID
)));
1604 OSL_ENSURE(pControl
, "FmXFormView::createControlLabelPair: could not create the control!");
1609 Reference
< XPropertySet
> xControlSet( pControl
->GetUnoControlModel(), UNO_QUERY
);
1610 if ( !xControlSet
.is() )
1613 // size of the control
1614 ::Size
aControlSize( aDefSize
);
1615 switch ( nDataType
)
1618 case DataType::BOOLEAN
:
1619 aControlSize
= aDefSize
;
1621 case DataType::LONGVARCHAR
:
1622 case DataType::CLOB
:
1623 case DataType::LONGVARBINARY
:
1624 case DataType::BLOB
:
1625 aControlSize
= aDefImageSize
;
1629 if ( OBJ_FM_IMAGECONTROL
== _nControlObjectID
)
1630 aControlSize
= aDefImageSize
;
1632 aControlSize
.setWidth( tools::Long(Fraction(aControlSize
.Width(), 1) * eTargetMode
.GetScaleX()) );
1633 aControlSize
.setHeight( tools::Long(Fraction(aControlSize
.Height(), 1) * eTargetMode
.GetScaleY()) );
1635 pControl
->SetLogicRect( ::tools::Rectangle(
1636 OutputDevice::LogicToLogic( ::Point( aRealSize
.Width() + _nXOffsetMM
, _nYOffsetMM
), eSourceMode
, eTargetMode
),
1637 OutputDevice::LogicToLogic( aControlSize
, eSourceMode
, eTargetMode
)
1640 // some initializations
1641 Reference
< XPropertySetInfo
> xControlPropInfo
= xControlSet
->getPropertySetInfo();
1643 if ( aFieldName
.hasValue() )
1645 xControlSet
->setPropertyValue( FM_PROP_CONTROLSOURCE
, aFieldName
);
1646 xControlSet
->setPropertyValue( FM_PROP_NAME
, aFieldName
);
1649 // no dedicated label control => use the label property
1650 if ( xControlPropInfo
->hasPropertyByName( FM_PROP_LABEL
) )
1651 xControlSet
->setPropertyValue( FM_PROP_LABEL
, makeAny( sFieldName
+ _rFieldPostfix
) );
1653 OSL_FAIL( "FmXFormView::createControlLabelPair: can't set a label for the control!" );
1657 if ( (nDataType
== DataType::LONGVARCHAR
|| nDataType
== DataType::CLOB
) && xControlPropInfo
->hasPropertyByName( FM_PROP_MULTILINE
) )
1659 xControlSet
->setPropertyValue( FM_PROP_MULTILINE
, makeAny( true ) );
1662 // announce the label to the control
1663 if ( xControlPropInfo
->hasPropertyByName( FM_PROP_CONTROLLABEL
) && xLabelModel
.is() )
1667 xControlSet
->setPropertyValue( FM_PROP_CONTROLLABEL
, makeAny( xLabelModel
) );
1669 catch (const Exception
&)
1671 DBG_UNHANDLED_EXCEPTION("svx");
1675 if ( _rxField
.is() )
1677 FormControlFactory::initializeFieldDependentProperties( _rxField
, xControlSet
, _rxNumberFormats
);
1680 _rpLabel
= std::move(pLabel
);
1681 _rpControl
= std::move(pControl
);
1686 FmXFormView::ObjectRemoveListener::ObjectRemoveListener( FmXFormView
* pParent
)
1687 :m_pParent( pParent
)
1692 void FmXFormView::ObjectRemoveListener::Notify( SfxBroadcaster
& /*rBC*/, const SfxHint
& rHint
)
1694 if (rHint
.GetId() != SfxHintId::ThisIsAnSdrHint
)
1696 const SdrHint
* pSdrHint
= static_cast<const SdrHint
*>(&rHint
);
1697 if (pSdrHint
->GetKind() == SdrHintKind::ObjectRemoved
)
1698 m_pParent
->ObjectRemovedInAliveMode(pSdrHint
->GetObject());
1702 void FmXFormView::ObjectRemovedInAliveMode( const SdrObject
* pObject
)
1704 // if the remote object in my MarkList, which I have memorized when switching to the
1705 // Alive mode, I have to take it out now, because I otherwise try to set the mark
1706 // again when switching back (interestingly, this fails only with grouped objects
1707 // (when accessing their ObjList GPF), not with individual ones)
1709 const size_t nCount
= m_aMark
.GetMarkCount();
1710 for (size_t i
= 0; i
< nCount
; ++i
)
1712 SdrMark
* pMark
= m_aMark
.GetMark(i
);
1713 SdrObject
* pCurrent
= pMark
->GetMarkedSdrObj();
1714 if (pObject
== pCurrent
)
1716 m_aMark
.DeleteMark(i
);
1719 // I do not need to descend into GroupObjects: if an object is deleted there,
1720 // then the pointer, which I have, to the GroupObject still remains valid ...
1725 void FmXFormView::stopMarkListWatching()
1727 if ( m_pWatchStoredList
)
1729 m_pWatchStoredList
->EndListeningAll();
1730 m_pWatchStoredList
.reset();
1735 void FmXFormView::startMarkListWatching()
1737 if ( !m_pWatchStoredList
)
1739 FmFormModel
* pModel
= GetFormShell() ? GetFormShell()->GetFormModel() : nullptr;
1740 DBG_ASSERT( pModel
!= nullptr, "FmXFormView::startMarkListWatching: shell has no model!" );
1743 m_pWatchStoredList
.reset(new ObjectRemoveListener( this ));
1744 m_pWatchStoredList
->StartListening( *static_cast< SfxBroadcaster
* >( pModel
) );
1749 OSL_FAIL( "FmXFormView::startMarkListWatching: already listening!" );
1753 void FmXFormView::saveMarkList()
1757 m_aMark
= m_pView
->GetMarkedObjectList();
1758 const size_t nCount
= m_aMark
.GetMarkCount( );
1759 for ( size_t i
= 0; i
< nCount
; ++i
)
1761 SdrMark
* pMark
= m_aMark
.GetMark(i
);
1762 SdrObject
* pObj
= pMark
->GetMarkedSdrObj();
1764 if ( m_pView
->IsObjMarked( pObj
) )
1766 if ( pObj
->IsGroupObject() )
1768 SdrObjListIter
aIter( pObj
->GetSubList() );
1769 bool bMixed
= false;
1770 while ( aIter
.IsMore() && !bMixed
)
1771 bMixed
= ( aIter
.Next()->GetObjInventor() != SdrInventor::FmForm
);
1775 // all objects in the group are form objects
1776 m_pView
->MarkObj( pMark
->GetMarkedSdrObj(), pMark
->GetPageView(), true /* unmark! */ );
1781 if ( pObj
->GetObjInventor() == SdrInventor::FmForm
)
1782 { // this is a form layer object
1783 m_pView
->MarkObj( pMark
->GetMarkedSdrObj(), pMark
->GetPageView(), true /* unmark! */ );
1791 OSL_FAIL( "FmXFormView::saveMarkList: invalid view!" );
1796 static bool lcl_hasObject( SdrObjListIter
& rIter
, SdrObject
const * pObj
)
1798 bool bFound
= false;
1799 while (rIter
.IsMore() && !bFound
)
1800 bFound
= pObj
== rIter
.Next();
1807 void FmXFormView::restoreMarkList( SdrMarkList
& _rRestoredMarkList
)
1812 _rRestoredMarkList
.Clear();
1814 const SdrMarkList
& rCurrentList
= m_pView
->GetMarkedObjectList();
1815 FmFormPage
* pPage
= GetFormShell() ? GetFormShell()->GetCurPage() : nullptr;
1819 if (rCurrentList
.GetMarkCount())
1820 { // there is a current mark ... hmm. Is it a subset of the mark we remembered in saveMarkList?
1821 bool bMisMatch
= false;
1823 // loop through all current marks
1824 const size_t nCurrentCount
= rCurrentList
.GetMarkCount();
1825 for ( size_t i
=0; i
<nCurrentCount
&& !bMisMatch
; ++i
)
1827 const SdrObject
* pCurrentMarked
= rCurrentList
.GetMark( i
)->GetMarkedSdrObj();
1829 // loop through all saved marks, check for equality
1830 bool bFound
= false;
1831 const size_t nSavedCount
= m_aMark
.GetMarkCount();
1832 for ( size_t j
=0; j
<nSavedCount
&& !bFound
; ++j
)
1834 if ( m_aMark
.GetMark( j
)->GetMarkedSdrObj() == pCurrentMarked
)
1838 // did not find a current mark in the saved marks
1846 _rRestoredMarkList
= rCurrentList
;
1850 // it is important that the objects of the mark list are not accessed,
1851 // because they can be already destroyed
1852 SdrPageView
* pCurPageView
= m_pView
->GetSdrPageView();
1853 SdrObjListIter
aPageIter( pPage
);
1856 // do all objects still exist
1857 const size_t nCount
= m_aMark
.GetMarkCount();
1858 for (size_t i
= 0; i
< nCount
&& bFound
; ++i
)
1860 SdrMark
* pMark
= m_aMark
.GetMark(i
);
1861 SdrObject
* pObj
= pMark
->GetMarkedSdrObj();
1862 if (pObj
->IsGroupObject())
1864 SdrObjListIter
aIter(pObj
->GetSubList());
1865 while (aIter
.IsMore() && bFound
)
1866 bFound
= lcl_hasObject(aPageIter
, aIter
.Next());
1869 bFound
= lcl_hasObject(aPageIter
, pObj
);
1871 bFound
= bFound
&& pCurPageView
== pMark
->GetPageView();
1876 // evaluate the LastObject
1877 if (nCount
) // now mark the objects
1879 for (size_t i
= 0; i
< nCount
; ++i
)
1881 SdrMark
* pMark
= m_aMark
.GetMark(i
);
1882 SdrObject
* pObj
= pMark
->GetMarkedSdrObj();
1883 if ( pObj
->GetObjInventor() == SdrInventor::FmForm
)
1884 if ( !m_pView
->IsObjMarked( pObj
) )
1885 m_pView
->MarkObj( pObj
, pMark
->GetPageView() );
1888 _rRestoredMarkList
= m_aMark
;
1894 void SAL_CALL
FmXFormView::focusGained( const FocusEvent
& /*e*/ )
1896 if ( m_xWindow
.is() && m_pView
)
1898 m_pView
->SetMoveOutside( true, FmFormView::ImplAccess() );
1902 void SAL_CALL
FmXFormView::focusLost( const FocusEvent
& /*e*/ )
1904 // when switch the focus outside the office the mark didn't change
1905 // so we can not remove us as focus listener
1906 if ( m_xWindow
.is() && m_pView
)
1908 m_pView
->SetMoveOutside( false, FmFormView::ImplAccess() );
1912 DocumentType
FmXFormView::impl_getDocumentType() const
1914 if ( GetFormShell() && GetFormShell()->GetImpl() )
1915 return GetFormShell()->GetImpl()->getDocumentType_Lock();
1916 return eUnknownDocumentType
;
1919 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */