Bump version to 6.4-15
[LibreOffice.git] / svx / source / form / fmvwimp.cxx
blob691bb8b6427d95464ebf08a4ce7a1f00e7ddaa20
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #include <memory>
22 #include <fmdocumentclassification.hxx>
23 #include <fmobj.hxx>
24 #include <fmpgeimp.hxx>
25 #include <fmprop.hxx>
26 #include <svx/strings.hrc>
27 #include <fmservs.hxx>
28 #include <fmshimp.hxx>
29 #include <svx/fmtools.hxx>
30 #include <fmundo.hxx>
31 #include <fmvwimp.hxx>
32 #include <formcontrolfactory.hxx>
33 #include <svx/sdrpaintwindow.hxx>
34 #include <svx/svditer.hxx>
35 #include <svx/dataaccessdescriptor.hxx>
36 #include <svx/dialmgr.hxx>
37 #include <svx/fmglob.hxx>
38 #include <svx/fmmodel.hxx>
39 #include <svx/fmpage.hxx>
40 #include <svx/fmshell.hxx>
41 #include <svx/fmview.hxx>
42 #include <svx/sdrpagewindow.hxx>
43 #include <svx/svdogrp.hxx>
44 #include <svx/svdpagv.hxx>
45 #include <svx/xmlexchg.hxx>
46 #include <toolkit/helper/vclunohelper.hxx>
48 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
49 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
50 #include <com/sun/star/sdbc/XRowSet.hpp>
51 #include <com/sun/star/form/XLoadable.hpp>
52 #include <com/sun/star/awt/VisualEffect.hpp>
53 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
54 #include <com/sun/star/util/XNumberFormats.hpp>
55 #include <com/sun/star/sdb/CommandType.hpp>
56 #include <com/sun/star/sdbc/DataType.hpp>
57 #include <com/sun/star/sdbc/ColumnValue.hpp>
58 #include <com/sun/star/form/FormComponentType.hpp>
59 #include <com/sun/star/form/FormButtonType.hpp>
60 #include <com/sun/star/form/XReset.hpp>
61 #include <com/sun/star/form/binding/XBindableValue.hpp>
62 #include <com/sun/star/form/binding/XValueBinding.hpp>
63 #include <com/sun/star/form/runtime/FormController.hpp>
64 #include <com/sun/star/form/submission/XSubmissionSupplier.hpp>
65 #include <com/sun/star/awt/XTabControllerModel.hpp>
66 #include <com/sun/star/awt/XControlContainer.hpp>
67 #include <com/sun/star/awt/XTabController.hpp>
68 #include <com/sun/star/container/XIndexAccess.hpp>
69 #include <com/sun/star/awt/XControl.hpp>
70 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
71 #include <com/sun/star/sdbc/SQLException.hpp>
72 #include <com/sun/star/sdbc/XPreparedStatement.hpp>
73 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
74 #include <com/sun/star/container/XContainer.hpp>
76 #include <comphelper/namedvaluecollection.hxx>
77 #include <comphelper/property.hxx>
78 #include <comphelper/processfactory.hxx>
79 #include <comphelper/types.hxx>
80 #include <cppuhelper/exc_hlp.hxx>
81 #include <unotools/moduleoptions.hxx>
82 #include <tools/debug.hxx>
83 #include <tools/diagnose_ex.h>
84 #include <sal/log.hxx>
85 #include <vcl/svapp.hxx>
86 #include <vcl/stdtext.hxx>
87 #include <connectivity/dbtools.hxx>
89 #include <algorithm>
91 using namespace ::comphelper;
92 using namespace ::svx;
93 using namespace ::svxform;
94 using namespace ::dbtools;
96 using namespace ::com::sun::star;
97 using ::com::sun::star::uno::Exception;
98 using ::com::sun::star::uno::RuntimeException;
99 using ::com::sun::star::uno::XInterface;
100 using ::com::sun::star::uno::Sequence;
101 using ::com::sun::star::uno::UNO_QUERY;
102 using ::com::sun::star::uno::UNO_QUERY_THROW;
103 using ::com::sun::star::uno::UNO_SET_THROW;
104 using ::com::sun::star::uno::Type;
105 using ::com::sun::star::uno::Reference;
106 using ::com::sun::star::uno::Any;
107 using ::com::sun::star::uno::makeAny;
108 using ::com::sun::star::uno::XComponentContext;
109 using ::com::sun::star::form::FormButtonType_SUBMIT;
110 using ::com::sun::star::form::binding::XValueBinding;
111 using ::com::sun::star::form::binding::XBindableValue;
112 using ::com::sun::star::lang::XComponent;
113 using ::com::sun::star::container::XIndexAccess;
114 using ::com::sun::star::form::runtime::FormController;
115 using ::com::sun::star::form::runtime::XFormController;
116 using ::com::sun::star::script::XEventAttacherManager;
117 using ::com::sun::star::awt::XTabControllerModel;
118 using ::com::sun::star::container::XChild;
119 using ::com::sun::star::task::XInteractionHandler;
120 using ::com::sun::star::awt::XTabController;
121 using ::com::sun::star::awt::XControlContainer;
122 using ::com::sun::star::awt::XControl;
123 using ::com::sun::star::form::XFormComponent;
124 using ::com::sun::star::form::XForm;
125 using ::com::sun::star::lang::IndexOutOfBoundsException;
126 using ::com::sun::star::lang::WrappedTargetException;
127 using ::com::sun::star::container::XContainer;
128 using ::com::sun::star::container::ContainerEvent;
129 using ::com::sun::star::lang::EventObject;
130 using ::com::sun::star::sdb::SQLErrorEvent;
131 using ::com::sun::star::sdbc::XRowSet;
132 using ::com::sun::star::beans::XPropertySet;
133 using ::com::sun::star::container::XElementAccess;
134 using ::com::sun::star::awt::XWindow;
135 using ::com::sun::star::awt::FocusEvent;
136 using ::com::sun::star::ui::dialogs::XExecutableDialog;
137 using ::com::sun::star::sdbc::XDataSource;
138 using ::com::sun::star::container::XIndexContainer;
139 using ::com::sun::star::sdbc::XConnection;
140 using ::com::sun::star::container::XNameAccess;
141 using ::com::sun::star::sdbc::SQLException;
142 using ::com::sun::star::util::XNumberFormatsSupplier;
143 using ::com::sun::star::util::XNumberFormats;
144 using ::com::sun::star::beans::XPropertySetInfo;
146 namespace FormComponentType = ::com::sun::star::form::FormComponentType;
147 namespace CommandType = ::com::sun::star::sdb::CommandType;
148 namespace DataType = ::com::sun::star::sdbc::DataType;
151 class FmXFormView::ObjectRemoveListener : public SfxListener
153 FmXFormView* m_pParent;
154 public:
155 explicit ObjectRemoveListener( FmXFormView* pParent );
156 virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
159 FormViewPageWindowAdapter::FormViewPageWindowAdapter( const css::uno::Reference<css::uno::XComponentContext>& _rContext, const SdrPageWindow& _rWindow, FmXFormView* _pViewImpl )
160 : m_xControlContainer( _rWindow.GetControlContainer() ),
161 m_xContext( _rContext ),
162 m_pViewImpl( _pViewImpl ),
163 m_pWindow( dynamic_cast< vcl::Window* >( &_rWindow.GetPaintWindow().GetOutputDevice() ) )
166 // create an XFormController for every form
167 FmFormPage* pFormPage = dynamic_cast< FmFormPage* >( _rWindow.GetPageView().GetPage() );
168 DBG_ASSERT( pFormPage, "FormViewPageWindowAdapter::FormViewPageWindowAdapter: no FmFormPage found!" );
169 if ( pFormPage )
173 Reference< XIndexAccess > xForms( pFormPage->GetForms(), UNO_QUERY_THROW );
174 sal_uInt32 nLength = xForms->getCount();
175 for (sal_uInt32 i = 0; i < nLength; i++)
177 Reference< XForm > xForm( xForms->getByIndex(i), UNO_QUERY );
178 if ( xForm.is() )
179 setController( xForm, nullptr );
182 catch (const Exception&)
184 DBG_UNHANDLED_EXCEPTION("svx");
189 FormViewPageWindowAdapter::~FormViewPageWindowAdapter()
193 void FormViewPageWindowAdapter::dispose()
195 for ( ::std::vector< Reference< XFormController > >::const_iterator i = m_aControllerList.begin();
196 i != m_aControllerList.end();
202 Reference< XFormController > xController( *i, UNO_SET_THROW );
204 // detaching the events
205 Reference< XChild > xControllerModel( xController->getModel(), UNO_QUERY );
206 if ( xControllerModel.is() )
208 Reference< XEventAttacherManager > xEventManager( xControllerModel->getParent(), UNO_QUERY_THROW );
209 Reference< XInterface > xControllerNormalized( xController, UNO_QUERY_THROW );
210 xEventManager->detach( i - m_aControllerList.begin(), xControllerNormalized );
213 // dispose the formcontroller
214 xController->dispose();
216 catch (const Exception&)
218 DBG_UNHANDLED_EXCEPTION("svx");
222 m_aControllerList.clear();
225 sal_Bool SAL_CALL FormViewPageWindowAdapter::hasElements()
227 return getCount() != 0;
230 Type SAL_CALL FormViewPageWindowAdapter::getElementType()
232 return cppu::UnoType<XFormController>::get();
235 // XIndexAccess
236 sal_Int32 SAL_CALL FormViewPageWindowAdapter::getCount()
238 return m_aControllerList.size();
241 Any SAL_CALL FormViewPageWindowAdapter::getByIndex(sal_Int32 nIndex)
243 if (nIndex < 0 ||
244 nIndex >= getCount())
245 throw IndexOutOfBoundsException();
247 Any aElement;
248 aElement <<= m_aControllerList[nIndex];
249 return aElement;
252 void SAL_CALL FormViewPageWindowAdapter::makeVisible( const Reference< XControl >& Control )
254 SolarMutexGuard aSolarGuard;
256 Reference< XWindow > xWindow( Control, UNO_QUERY );
257 if ( xWindow.is() && m_pViewImpl->getView() && m_pWindow )
259 awt::Rectangle aRect = xWindow->getPosSize();
260 ::tools::Rectangle aNewRect( aRect.X, aRect.Y, aRect.X + aRect.Width, aRect.Y + aRect.Height );
261 aNewRect = m_pWindow->PixelToLogic( aNewRect );
262 m_pViewImpl->getView()->MakeVisible( aNewRect, *m_pWindow );
266 static Reference< XFormController > getControllerSearchChildren( const Reference< XIndexAccess > & xIndex, const Reference< XTabControllerModel > & xModel)
268 if (xIndex.is() && xIndex->getCount())
270 Reference< XFormController > xController;
272 for (sal_Int32 n = xIndex->getCount(); n-- && !xController.is(); )
274 xIndex->getByIndex(n) >>= xController;
275 if (xModel.get() == xController->getModel().get())
276 return xController;
277 else
279 xController = getControllerSearchChildren(xController, xModel);
280 if ( xController.is() )
281 return xController;
285 return Reference< XFormController > ();
288 // Search the according controller
289 Reference< XFormController > FormViewPageWindowAdapter::getController( const Reference< XForm > & xForm ) const
291 Reference< XTabControllerModel > xModel(xForm, UNO_QUERY);
292 for (const auto& rpController : m_aControllerList)
294 if (rpController->getModel().get() == xModel.get())
295 return rpController;
297 // the current-round controller isn't the right one. perhaps one of its children ?
298 Reference< XFormController > xChildSearch = getControllerSearchChildren(Reference< XIndexAccess > (rpController, UNO_QUERY), xModel);
299 if (xChildSearch.is())
300 return xChildSearch;
302 return Reference< XFormController > ();
306 void FormViewPageWindowAdapter::setController(const Reference< XForm > & xForm, const Reference< XFormController >& _rxParentController )
308 DBG_ASSERT( xForm.is(), "FormViewPageWindowAdapter::setController: there should be a form!" );
309 Reference< XIndexAccess > xFormCps(xForm, UNO_QUERY);
310 if (!xFormCps.is())
311 return;
313 Reference< XTabControllerModel > xTabOrder(xForm, UNO_QUERY);
315 // create a form controller
316 Reference< XFormController > xController( FormController::create(m_xContext) );
318 Reference< XInteractionHandler > xHandler;
319 if ( _rxParentController.is() )
320 xHandler = _rxParentController->getInteractionHandler();
321 else
323 // TODO: should we create a default handler? Not really necessary, since the
324 // FormController itself has a default fallback
326 if ( xHandler.is() )
327 xController->setInteractionHandler( xHandler );
329 xController->setContext( this );
331 xController->setModel( xTabOrder );
332 xController->setContainer( m_xControlContainer );
333 xController->activateTabOrder();
334 xController->addActivateListener( m_pViewImpl );
336 if ( _rxParentController.is() )
337 _rxParentController->addChildController( xController );
338 else
340 m_aControllerList.push_back(xController);
342 xController->setParent( *this );
344 // attaching the events
345 Reference< XEventAttacherManager > xEventManager( xForm->getParent(), UNO_QUERY );
346 xEventManager->attach(m_aControllerList.size() - 1, Reference<XInterface>( xController, UNO_QUERY ), makeAny(xController) );
349 // now go through the subforms
350 sal_uInt32 nLength = xFormCps->getCount();
351 Reference< XForm > xSubForm;
352 for (sal_uInt32 i = 0; i < nLength; i++)
354 if ( xFormCps->getByIndex(i) >>= xSubForm )
355 setController( xSubForm, xController );
360 void FormViewPageWindowAdapter::updateTabOrder( const Reference< XForm >& _rxForm )
362 OSL_PRECOND( _rxForm.is(), "FormViewPageWindowAdapter::updateTabOrder: illegal argument!" );
363 if ( !_rxForm.is() )
364 return;
368 Reference< XTabController > xTabCtrl( getController( _rxForm ).get() );
369 if ( xTabCtrl.is() )
370 { // if there already is a TabController for this form, then delegate the "updateTabOrder" request
371 xTabCtrl->activateTabOrder();
373 else
374 { // otherwise, create a TabController
376 // if it's a sub form, then we must ensure there exist TabControllers
377 // for all its ancestors, too
378 Reference< XForm > xParentForm( _rxForm->getParent(), UNO_QUERY );
379 // there is a parent form -> look for the respective controller
380 Reference< XFormController > xParentController;
381 if ( xParentForm.is() )
382 xParentController = getController( xParentForm );
384 setController( _rxForm, xParentController );
387 catch (const Exception&)
389 DBG_UNHANDLED_EXCEPTION("svx");
394 FmXFormView::FmXFormView(FmFormView* _pView )
395 :m_pMarkedGrid(nullptr)
396 ,m_pView(_pView)
397 ,m_nActivationEvent(nullptr)
398 ,m_nErrorMessageEvent( nullptr )
399 ,m_nAutoFocusEvent( nullptr )
400 ,m_nControlWizardEvent( nullptr )
401 ,m_bFirstActivation( true )
402 ,m_isTabOrderUpdateSuspended( false )
407 void FmXFormView::cancelEvents()
409 if ( m_nActivationEvent )
411 Application::RemoveUserEvent( m_nActivationEvent );
412 m_nActivationEvent = nullptr;
415 if ( m_nErrorMessageEvent )
417 Application::RemoveUserEvent( m_nErrorMessageEvent );
418 m_nErrorMessageEvent = nullptr;
421 if ( m_nAutoFocusEvent )
423 Application::RemoveUserEvent( m_nAutoFocusEvent );
424 m_nAutoFocusEvent = nullptr;
427 if ( m_nControlWizardEvent )
429 Application::RemoveUserEvent( m_nControlWizardEvent );
430 m_nControlWizardEvent = nullptr;
435 void FmXFormView::notifyViewDying( )
437 DBG_ASSERT( m_pView, "FmXFormView::notifyViewDying: my view already died!" );
438 m_pView = nullptr;
439 cancelEvents();
443 FmXFormView::~FmXFormView()
445 DBG_ASSERT( m_aPageWindowAdapters.empty(), "FmXFormView::~FmXFormView: Window list not empty!" );
446 for (const auto& rpAdapter : m_aPageWindowAdapters)
448 rpAdapter->dispose();
451 cancelEvents();
454 // EventListener
456 void SAL_CALL FmXFormView::disposing(const EventObject& Source)
458 if ( m_xWindow.is() && Source.Source == m_xWindow )
460 m_xWindow->removeFocusListener(this);
461 if ( m_pView )
463 m_pView->SetMoveOutside( false, FmFormView::ImplAccess() );
465 m_xWindow = nullptr;
469 // XFormControllerListener
471 void SAL_CALL FmXFormView::formActivated(const EventObject& rEvent)
473 if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() )
474 m_pView->GetFormShell()->GetImpl()->formActivated( rEvent );
478 void SAL_CALL FmXFormView::formDeactivated(const EventObject& rEvent)
480 if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() )
481 m_pView->GetFormShell()->GetImpl()->formDeactivated( rEvent );
484 // XContainerListener
486 void SAL_CALL FmXFormView::elementInserted(const ContainerEvent& evt)
490 Reference< XControlContainer > xControlContainer( evt.Source, UNO_QUERY_THROW );
491 Reference< XControl > xControl( evt.Element, UNO_QUERY_THROW );
492 Reference< XFormComponent > xControlModel( xControl->getModel(), UNO_QUERY_THROW );
493 Reference< XForm > xForm( xControlModel->getParent(), UNO_QUERY_THROW );
495 if ( m_isTabOrderUpdateSuspended )
497 // remember the container and the control, so we can update the tab order on resumeTabOrderUpdate
498 m_aNeedTabOrderUpdate[ xControlContainer ].insert( xForm );
500 else
502 PFormViewPageWindowAdapter pAdapter = findWindow( xControlContainer );
503 if ( pAdapter.is() )
504 pAdapter->updateTabOrder( xForm );
507 catch (const Exception&)
509 DBG_UNHANDLED_EXCEPTION("svx");
514 void SAL_CALL FmXFormView::elementReplaced(const ContainerEvent& evt)
516 elementInserted(evt);
520 void SAL_CALL FmXFormView::elementRemoved(const ContainerEvent& /*evt*/)
525 PFormViewPageWindowAdapter FmXFormView::findWindow( const Reference< XControlContainer >& _rxCC ) const
527 auto i = std::find_if(m_aPageWindowAdapters.begin(), m_aPageWindowAdapters.end(),
528 [&_rxCC](const PFormViewPageWindowAdapter& rpAdapter) { return _rxCC == rpAdapter->getControlContainer(); });
529 if (i != m_aPageWindowAdapters.end())
530 return *i;
531 return nullptr;
535 void FmXFormView::addWindow(const SdrPageWindow& rWindow)
537 FmFormPage* pFormPage = dynamic_cast<FmFormPage*>( rWindow.GetPageView().GetPage() );
538 if ( !pFormPage )
539 return;
541 const Reference< XControlContainer >& xCC = rWindow.GetControlContainer();
542 if ( xCC.is()
543 && ( !findWindow( xCC ).is() )
546 PFormViewPageWindowAdapter pAdapter = new FormViewPageWindowAdapter( comphelper::getProcessComponentContext(), rWindow, this );
547 m_aPageWindowAdapters.push_back( pAdapter );
549 // listen at the ControlContainer to notice changes
550 Reference< XContainer > xContainer( xCC, UNO_QUERY );
551 if ( xContainer.is() )
552 xContainer->addContainerListener( this );
557 void FmXFormView::removeWindow( const Reference< XControlContainer >& _rxCC )
559 // Is called if
560 // - the design mode is being switched to
561 // - a window is deleted while in the design mode
562 // - the control container for a window is removed while the active mode is on
564 auto i = std::find_if(m_aPageWindowAdapters.begin(), m_aPageWindowAdapters.end(),
565 [&_rxCC](const PFormViewPageWindowAdapter& rpAdapter) { return _rxCC == rpAdapter->getControlContainer(); });
566 if (i != m_aPageWindowAdapters.end())
568 Reference< XContainer > xContainer( _rxCC, UNO_QUERY );
569 if ( xContainer.is() )
570 xContainer->removeContainerListener( this );
572 (*i)->dispose();
573 m_aPageWindowAdapters.erase( i );
578 void FmXFormView::displayAsyncErrorMessage( const SQLErrorEvent& _rEvent )
580 DBG_ASSERT( nullptr == m_nErrorMessageEvent, "FmXFormView::displayAsyncErrorMessage: not too fast, please!" );
581 // This should not happen - usually, the PostUserEvent is faster than any possible user
582 // interaction which could trigger a new error. If it happens, we need a queue for the events.
583 m_aAsyncError = _rEvent;
584 m_nErrorMessageEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnDelayedErrorMessage ) );
588 IMPL_LINK_NOARG(FmXFormView, OnDelayedErrorMessage, void*, void)
590 m_nErrorMessageEvent = nullptr;
591 displayException( m_aAsyncError );
595 void FmXFormView::onFirstViewActivation( const FmFormModel* _pDocModel )
597 if ( _pDocModel && _pDocModel->GetAutoControlFocus() )
598 m_nAutoFocusEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnAutoFocus ) );
602 void FmXFormView::suspendTabOrderUpdate()
604 OSL_ENSURE( !m_isTabOrderUpdateSuspended, "FmXFormView::suspendTabOrderUpdate: nesting not allowed!" );
605 m_isTabOrderUpdateSuspended = true;
609 void FmXFormView::resumeTabOrderUpdate()
611 OSL_ENSURE( m_isTabOrderUpdateSuspended, "FmXFormView::resumeTabOrderUpdate: not suspended!" );
612 m_isTabOrderUpdateSuspended = false;
614 // update the tab orders for all components which were collected since the suspendTabOrderUpdate call.
615 for (const auto& rContainer : m_aNeedTabOrderUpdate)
617 PFormViewPageWindowAdapter pAdapter = findWindow( rContainer.first );
618 if ( !pAdapter.is() )
619 continue;
621 for (const auto& rForm : rContainer.second)
623 pAdapter->updateTabOrder( rForm );
626 m_aNeedTabOrderUpdate.clear();
629 namespace
631 bool isActivableDatabaseForm(const Reference< XFormController > &xController)
633 // only database forms are to be activated
634 Reference< XRowSet > xForm(xController->getModel(), UNO_QUERY);
635 if ( !xForm.is() || !getConnection( xForm ).is() )
636 return false;
638 Reference< XPropertySet > xFormSet( xForm, UNO_QUERY );
639 if ( !xFormSet.is() )
641 SAL_WARN( "svx.form", "FmXFormView::OnActivate: a form which does not have properties?" );
642 return false;
645 const OUString aSource = ::comphelper::getString( xFormSet->getPropertyValue( FM_PROP_COMMAND ) );
647 return !aSource.isEmpty();
650 class find_active_databaseform
652 const Reference< XFormController > xActiveController;
654 public:
656 explicit find_active_databaseform( const Reference< XFormController >& _xActiveController )
657 : xActiveController(_xActiveController )
660 Reference < XFormController > operator() (const Reference< XFormController > &xController)
662 if(xController == xActiveController && isActivableDatabaseForm(xController))
663 return xController;
665 if ( !xController.is() )
667 SAL_WARN( "svx.form", "FmXFormView::OnActivate: a form controller which does not have children?" );
668 return nullptr;
671 for(sal_Int32 i = 0; i < xController->getCount(); ++i)
673 const Any a(xController->getByIndex(i));
674 Reference < XFormController > xI;
675 if ((a >>= xI) && xI.is())
677 Reference < XFormController > xRes(operator()(xI));
678 if (xRes.is())
679 return xRes;
683 return nullptr;
689 IMPL_LINK_NOARG(FmXFormView, OnActivate, void*, void)
691 m_nActivationEvent = nullptr;
693 if ( !m_pView )
695 OSL_FAIL( "FmXFormView::OnActivate: well... seems we have a timing problem (the view already died)!" );
696 return;
699 // setting the controller to activate
700 if (m_pView->GetFormShell() && m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
702 FmXFormShell* const pShImpl = m_pView->GetFormShell()->GetImpl();
704 if(!pShImpl)
705 return;
707 find_active_databaseform fad(pShImpl->getActiveController_Lock());
709 vcl::Window* pWindow = const_cast<vcl::Window*>(static_cast<const vcl::Window*>(m_pView->GetActualOutDev()));
710 PFormViewPageWindowAdapter pAdapter = m_aPageWindowAdapters.empty() ? nullptr : m_aPageWindowAdapters[0];
711 for (const auto& rpPageWindowAdapter : m_aPageWindowAdapters)
713 if ( pWindow == rpPageWindowAdapter->getWindow() )
714 pAdapter = rpPageWindowAdapter;
717 if ( pAdapter.is() )
719 Reference< XFormController > xControllerToActivate;
720 for (const Reference< XFormController > & xController : pAdapter->GetList())
722 if ( !xController.is() )
723 continue;
726 Reference< XFormController > xActiveController(fad(xController));
727 if (xActiveController.is())
729 xControllerToActivate = xActiveController;
730 break;
734 if(xControllerToActivate.is() || !isActivableDatabaseForm(xController))
735 continue;
737 xControllerToActivate = xController;
739 pShImpl->setActiveController_Lock(xControllerToActivate);
745 void FmXFormView::Activate(bool bSync)
747 if (m_nActivationEvent)
749 Application::RemoveUserEvent(m_nActivationEvent);
750 m_nActivationEvent = nullptr;
753 if (bSync)
755 LINK(this,FmXFormView,OnActivate).Call(nullptr);
757 else
758 m_nActivationEvent = Application::PostUserEvent(LINK(this,FmXFormView,OnActivate));
762 void FmXFormView::Deactivate(bool bDeactivateController)
764 if (m_nActivationEvent)
766 Application::RemoveUserEvent(m_nActivationEvent);
767 m_nActivationEvent = nullptr;
770 FmXFormShell* pShImpl = m_pView->GetFormShell() ? m_pView->GetFormShell()->GetImpl() : nullptr;
771 if (pShImpl && bDeactivateController)
772 pShImpl->setActiveController_Lock(nullptr);
776 FmFormShell* FmXFormView::GetFormShell() const
778 return m_pView ? m_pView->GetFormShell() : nullptr;
781 void FmXFormView::AutoFocus()
783 if (m_nAutoFocusEvent)
784 Application::RemoveUserEvent(m_nAutoFocusEvent);
786 m_nAutoFocusEvent = Application::PostUserEvent(LINK(this, FmXFormView, OnAutoFocus));
790 bool FmXFormView::isFocusable( const Reference< XControl >& i_rControl )
792 if ( !i_rControl.is() )
793 return false;
797 Reference< XPropertySet > xModelProps( i_rControl->getModel(), UNO_QUERY_THROW );
799 // only enabled controls are allowed to participate
800 bool bEnabled = false;
801 OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_ENABLED ) >>= bEnabled );
802 if ( !bEnabled )
803 return false;
805 // check the class id of the control model
806 sal_Int16 nClassId = FormComponentType::CONTROL;
807 OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
809 // controls which are not focussable
810 if ( ( FormComponentType::CONTROL != nClassId )
811 && ( FormComponentType::IMAGEBUTTON != nClassId )
812 && ( FormComponentType::GROUPBOX != nClassId )
813 && ( FormComponentType::FIXEDTEXT != nClassId )
814 && ( FormComponentType::HIDDENCONTROL != nClassId )
815 && ( FormComponentType::IMAGECONTROL != nClassId )
816 && ( FormComponentType::SCROLLBAR != nClassId )
817 && ( FormComponentType::SPINBUTTON!= nClassId )
820 return true;
823 catch (const Exception&)
825 DBG_UNHANDLED_EXCEPTION("svx");
827 return false;
831 static Reference< XControl > lcl_firstFocussableControl( const Sequence< Reference< XControl > >& _rControls )
833 Reference< XControl > xReturn;
835 // loop through all the controls
836 for ( auto const & control : _rControls )
838 if ( !control.is() )
839 continue;
841 if ( FmXFormView::isFocusable( control ) )
843 xReturn = control;
844 break;
848 if ( !xReturn.is() && _rControls.hasElements() )
849 xReturn = _rControls[0];
851 return xReturn;
855 namespace
858 void lcl_ensureControlsOfFormExist_nothrow( const SdrPage& _rPage, const SdrView& _rView, const vcl::Window& _rWindow, const Reference< XForm >& _rxForm )
862 Reference< XInterface > xNormalizedForm( _rxForm, UNO_QUERY_THROW );
864 SdrObjListIter aSdrObjectLoop( &_rPage, SdrIterMode::DeepNoGroups );
865 while ( aSdrObjectLoop.IsMore() )
867 FmFormObj* pFormObject = FmFormObj::GetFormObject( aSdrObjectLoop.Next() );
868 if ( !pFormObject )
869 continue;
871 Reference< XChild > xModel( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW );
872 Reference< XInterface > xModelParent( xModel->getParent(), UNO_QUERY );
874 if ( xNormalizedForm.get() != xModelParent.get() )
875 continue;
877 pFormObject->GetUnoControl( _rView, _rWindow );
880 catch (const Exception&)
882 DBG_UNHANDLED_EXCEPTION("svx");
888 Reference< XFormController > FmXFormView::getFormController( const Reference< XForm >& _rxForm, const OutputDevice& _rDevice ) const
890 Reference< XFormController > xController;
892 for (const PFormViewPageWindowAdapter& pAdapter : m_aPageWindowAdapters)
894 if ( !pAdapter.get() )
896 SAL_WARN( "svx.form", "FmXFormView::getFormController: invalid page window adapter!" );
897 continue;
900 if ( pAdapter->getWindow() != &_rDevice )
901 // wrong device
902 continue;
904 xController = pAdapter->getController( _rxForm );
905 if ( xController.is() )
906 break;
908 return xController;
912 IMPL_LINK_NOARG(FmXFormView, OnAutoFocus, void*, void)
914 m_nAutoFocusEvent = nullptr;
916 // go to the first form of our page, examine it's TabController, go to its first (in terms of the tab order)
917 // control, give it the focus
919 SdrPageView *pPageView = m_pView ? m_pView->GetSdrPageView() : nullptr;
920 SdrPage *pSdrPage = pPageView ? pPageView->GetPage() : nullptr;
921 // get the forms collection of the page we belong to
922 FmFormPage* pPage = dynamic_cast<FmFormPage*>( pSdrPage );
923 Reference< XIndexAccess > xForms( pPage ? Reference< XIndexAccess >( pPage->GetForms() ) : Reference< XIndexAccess >() );
925 const PFormViewPageWindowAdapter pAdapter = m_aPageWindowAdapters.empty() ? nullptr : m_aPageWindowAdapters[0];
926 const vcl::Window* pWindow = pAdapter.get() ? pAdapter->getWindow() : nullptr;
928 ENSURE_OR_RETURN_VOID( xForms.is() && pWindow, "FmXFormView::OnAutoFocus: could not collect all essentials!" );
932 // go for the tab controller of the first form
933 if ( !xForms->getCount() )
934 return;
935 Reference< XForm > xForm( xForms->getByIndex( 0 ), UNO_QUERY_THROW );
936 Reference< XTabController > xTabController( pAdapter->getController( xForm ), UNO_QUERY_THROW );
938 // go for the first control of the controller
939 Sequence< Reference< XControl > > aControls( xTabController->getControls() );
940 if ( !aControls.hasElements() )
942 Reference< XElementAccess > xFormElementAccess( xForm, UNO_QUERY_THROW );
943 if (xFormElementAccess->hasElements() && pPage && m_pView)
945 // there are control models in the form, but no controls, yet.
946 // Well, since some time controls are created on demand only. In particular,
947 // they're normally created when they're first painted.
948 // Unfortunately, the FormController does not have any way to
949 // trigger the creation itself, so we must hack this ...
950 lcl_ensureControlsOfFormExist_nothrow( *pPage, *m_pView, *pWindow, xForm );
951 aControls = xTabController->getControls();
952 OSL_ENSURE( aControls.hasElements(), "FmXFormView::OnAutoFocus: no controls at all!" );
956 // set the focus to this first control
957 Reference< XWindow > xControlWindow( lcl_firstFocussableControl( aControls ), UNO_QUERY );
958 if ( !xControlWindow.is() )
959 return;
961 xControlWindow->setFocus();
963 // ensure that the control is visible
964 // 80210 - 12/07/00 - FS
965 const vcl::Window* pCurrentWindow = m_pView ? dynamic_cast<const vcl::Window*>(m_pView->GetActualOutDev()) : nullptr;
966 if ( pCurrentWindow )
968 awt::Rectangle aRect = xControlWindow->getPosSize();
969 ::tools::Rectangle aNonUnoRect( aRect.X, aRect.Y, aRect.X + aRect.Width, aRect.Y + aRect.Height );
970 m_pView->MakeVisible( pCurrentWindow->PixelToLogic( aNonUnoRect ), *const_cast< vcl::Window* >( pCurrentWindow ) );
973 catch (const Exception&)
975 DBG_UNHANDLED_EXCEPTION("svx");
980 void FmXFormView::onCreatedFormObject( FmFormObj const & _rFormObject )
982 FmFormShell* pShell = m_pView ? m_pView->GetFormShell() : nullptr;
983 FmXFormShell* pShellImpl = pShell ? pShell->GetImpl() : nullptr;
984 OSL_ENSURE( pShellImpl, "FmXFormView::onCreatedFormObject: no form shell!" );
985 if ( !pShellImpl )
986 return;
988 // it is valid that the form shell's forms collection is not initialized, yet
989 pShellImpl->UpdateForms_Lock(true);
991 m_xLastCreatedControlModel.set( _rFormObject.GetUnoControlModel(), UNO_QUERY );
992 if ( !m_xLastCreatedControlModel.is() )
993 return;
995 // some initial property defaults
996 FormControlFactory aControlFactory;
997 aControlFactory.initializeControlModel(pShellImpl->getDocumentType_Lock(), _rFormObject);
999 if (!pShellImpl->GetWizardUsing_Lock())
1000 return;
1002 // #i31958# don't call wizards in XForms mode
1003 if (pShellImpl->isEnhancedForm_Lock())
1004 return;
1006 // #i46898# no wizards if there is no Base installed - currently, all wizards are
1007 // database related
1008 if ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) )
1009 return;
1011 if ( m_nControlWizardEvent )
1012 Application::RemoveUserEvent( m_nControlWizardEvent );
1013 m_nControlWizardEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnStartControlWizard ) );
1016 void FmXFormView::breakCreateFormObject()
1018 if (m_nControlWizardEvent != nullptr)
1020 Application::RemoveUserEvent(m_nControlWizardEvent);
1021 m_nControlWizardEvent = nullptr;
1023 m_xLastCreatedControlModel.clear();
1026 IMPL_LINK_NOARG( FmXFormView, OnStartControlWizard, void*, void )
1028 m_nControlWizardEvent = nullptr;
1029 OSL_PRECOND( m_xLastCreatedControlModel.is(), "FmXFormView::OnStartControlWizard: illegal call!" );
1030 if ( !m_xLastCreatedControlModel.is() )
1031 return;
1033 sal_Int16 nClassId = FormComponentType::CONTROL;
1036 OSL_VERIFY( m_xLastCreatedControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
1038 catch (const Exception&)
1040 DBG_UNHANDLED_EXCEPTION("svx");
1043 const sal_Char* pWizardAsciiName = nullptr;
1044 switch ( nClassId )
1046 case FormComponentType::GRIDCONTROL:
1047 pWizardAsciiName = "com.sun.star.sdb.GridControlAutoPilot";
1048 break;
1049 case FormComponentType::LISTBOX:
1050 case FormComponentType::COMBOBOX:
1051 pWizardAsciiName = "com.sun.star.sdb.ListComboBoxAutoPilot";
1052 break;
1053 case FormComponentType::GROUPBOX:
1054 pWizardAsciiName = "com.sun.star.sdb.GroupBoxAutoPilot";
1055 break;
1058 if ( pWizardAsciiName )
1060 // build the argument list
1061 ::comphelper::NamedValueCollection aWizardArgs;
1062 aWizardArgs.put("ObjectModel", m_xLastCreatedControlModel);
1063 const vcl::Window* pCurrentWindow = m_pView ? dynamic_cast<const vcl::Window*>(m_pView->GetActualOutDev()) : nullptr;
1064 aWizardArgs.put("ParentWindow", VCLUnoHelper::GetInterface(const_cast<vcl::Window*>(pCurrentWindow)));
1066 // create the wizard object
1067 Reference< XExecutableDialog > xWizard;
1070 Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
1071 xWizard.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext( OUString::createFromAscii(pWizardAsciiName), aWizardArgs.getWrappedPropertyValues(), xContext ), UNO_QUERY);
1073 catch (const Exception&)
1075 DBG_UNHANDLED_EXCEPTION("svx");
1078 if ( !xWizard.is() )
1080 ShowServiceNotAvailableError( nullptr, OUString::createFromAscii(pWizardAsciiName), true );
1082 else
1084 // execute the wizard
1087 xWizard->execute();
1089 catch (const Exception&)
1091 DBG_UNHANDLED_EXCEPTION("svx");
1096 m_xLastCreatedControlModel.clear();
1100 namespace
1102 void lcl_insertIntoFormComponentHierarchy_throw( const FmFormView& _rView, const SdrUnoObj& _rSdrObj,
1103 const Reference< XDataSource >& _rxDataSource, const OUString& _rDataSourceName,
1104 const OUString& _rCommand, const sal_Int32 _nCommandType )
1106 FmFormPage& rPage = static_cast< FmFormPage& >( *_rView.GetSdrPageView()->GetPage() );
1108 Reference< XFormComponent > xFormComponent( _rSdrObj.GetUnoControlModel(), UNO_QUERY_THROW );
1109 Reference< XForm > xTargetForm(
1110 rPage.GetImpl().findPlaceInFormComponentHierarchy( xFormComponent, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType ),
1111 UNO_SET_THROW );
1113 FmFormPageImpl::setUniqueName( xFormComponent, xTargetForm );
1115 Reference< XIndexContainer > xFormAsContainer( xTargetForm, UNO_QUERY_THROW );
1116 xFormAsContainer->insertByIndex( xFormAsContainer->getCount(), makeAny( xFormComponent ) );
1121 SdrObjectUniquePtr FmXFormView::implCreateFieldControl( const svx::ODataAccessDescriptor& _rColumnDescriptor )
1123 // not if we're in design mode
1124 if ( !m_pView->IsDesignMode() )
1125 return nullptr;
1127 OUString sCommand, sFieldName;
1128 sal_Int32 nCommandType = CommandType::COMMAND;
1129 SharedConnection xConnection;
1131 OUString sDataSource = _rColumnDescriptor.getDataSource();
1132 _rColumnDescriptor[ DataAccessDescriptorProperty::Command ] >>= sCommand;
1133 _rColumnDescriptor[ DataAccessDescriptorProperty::ColumnName ] >>= sFieldName;
1134 _rColumnDescriptor[ DataAccessDescriptorProperty::CommandType ] >>= nCommandType;
1136 Reference< XConnection > xExternalConnection;
1137 _rColumnDescriptor[ DataAccessDescriptorProperty::Connection ] >>= xExternalConnection;
1138 xConnection.reset( xExternalConnection, SharedConnection::NoTakeOwnership );
1141 if ( sCommand.isEmpty()
1142 || sFieldName.isEmpty()
1143 || ( sDataSource.isEmpty()
1144 && !xConnection.is()
1148 OSL_FAIL( "FmXFormView::implCreateFieldControl: nonsense!" );
1151 Reference< XDataSource > xDataSource;
1152 SQLErrorEvent aError;
1155 if ( xConnection.is() && !xDataSource.is() && sDataSource.isEmpty() )
1157 Reference< XChild > xChild( xConnection, UNO_QUERY );
1158 if ( xChild.is() )
1159 xDataSource.set(xChild->getParent(), css::uno::UNO_QUERY);
1162 // obtain the data source
1163 if ( !xDataSource.is() )
1164 xDataSource = getDataSource( sDataSource, comphelper::getProcessComponentContext() );
1166 // and the connection, if necessary
1167 if ( !xConnection.is() )
1168 xConnection.reset( getConnection_withFeedback(
1169 sDataSource,
1170 OUString(),
1171 OUString(),
1172 comphelper::getProcessComponentContext(),
1173 nullptr
1174 ) );
1176 catch (const SQLException&)
1178 aError.Reason = ::cppu::getCaughtException();
1180 catch (const Exception& )
1182 /* will be asserted below */
1184 if (aError.Reason.hasValue())
1186 displayAsyncErrorMessage( aError );
1187 return nullptr;
1190 // need a data source and a connection here
1191 if (!xDataSource.is() || !xConnection.is())
1193 OSL_FAIL("FmXFormView::implCreateFieldControl : could not retrieve the data source or the connection!");
1194 return nullptr;
1197 Reference< XComponent > xKeepFieldsAlive;
1198 // go
1201 // determine the table/query field which we should create a control for
1202 Reference< XPropertySet > xField;
1204 Reference< XNameAccess > xFields = getFieldsByCommandDescriptor(
1205 xConnection, nCommandType, sCommand, xKeepFieldsAlive );
1207 if (xFields.is() && xFields->hasByName(sFieldName))
1208 xFields->getByName(sFieldName) >>= xField;
1209 if ( !xField.is() )
1210 return nullptr;
1212 Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( xConnection ), UNO_SET_THROW );
1213 Reference< XNumberFormats > xNumberFormats( xSupplier->getNumberFormats(), UNO_SET_THROW );
1215 OUString sLabelPostfix;
1218 // only for text size
1219 OutputDevice* pOutDev = nullptr;
1220 if (m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
1221 pOutDev = const_cast<OutputDevice*>(m_pView->GetActualOutDev());
1222 else
1223 {// find OutDev
1224 if (SdrPageView* pPageView = m_pView->GetSdrPageView())
1226 // const SdrPageViewWinList& rWinList = pPageView->GetWinList();
1227 // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows();
1229 for( sal_uInt32 i = 0; i < pPageView->PageWindowCount(); i++ )
1231 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);
1233 if( rPageWindow.GetPaintWindow().OutputToWindow())
1235 pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice();
1236 break;
1242 if ( !pOutDev )
1243 return nullptr;
1245 sal_Int32 nDataType = ::comphelper::getINT32(xField->getPropertyValue(FM_PROP_FIELDTYPE));
1246 if ((DataType::BINARY == nDataType) || (DataType::VARBINARY == nDataType))
1247 return nullptr;
1250 // determine the control type by examining the data type of the bound column
1251 sal_uInt16 nOBJID = 0;
1252 bool bDateNTimeField = false;
1254 bool bIsCurrency = false;
1255 if (::comphelper::hasProperty(FM_PROP_ISCURRENCY, xField))
1256 bIsCurrency = ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISCURRENCY));
1258 if (bIsCurrency)
1259 nOBJID = OBJ_FM_CURRENCYFIELD;
1260 else
1261 switch (nDataType)
1263 case DataType::BLOB:
1264 case DataType::LONGVARBINARY:
1265 nOBJID = OBJ_FM_IMAGECONTROL;
1266 break;
1267 case DataType::LONGVARCHAR:
1268 case DataType::CLOB:
1269 nOBJID = OBJ_FM_EDIT;
1270 break;
1271 case DataType::BINARY:
1272 case DataType::VARBINARY:
1273 return nullptr;
1274 case DataType::BIT:
1275 case DataType::BOOLEAN:
1276 nOBJID = OBJ_FM_CHECKBOX;
1277 break;
1278 case DataType::TINYINT:
1279 case DataType::SMALLINT:
1280 case DataType::INTEGER:
1281 nOBJID = OBJ_FM_NUMERICFIELD;
1282 break;
1283 case DataType::REAL:
1284 case DataType::DOUBLE:
1285 case DataType::NUMERIC:
1286 case DataType::DECIMAL:
1287 nOBJID = OBJ_FM_FORMATTEDFIELD;
1288 break;
1289 case DataType::TIMESTAMP:
1290 bDateNTimeField = true;
1291 sLabelPostfix = SvxResId(RID_STR_POSTFIX_DATE);
1292 [[fallthrough]];
1293 case DataType::DATE:
1294 nOBJID = OBJ_FM_DATEFIELD;
1295 break;
1296 case DataType::TIME:
1297 nOBJID = OBJ_FM_TIMEFIELD;
1298 break;
1299 case DataType::CHAR:
1300 case DataType::VARCHAR:
1301 default:
1302 nOBJID = OBJ_FM_EDIT;
1303 break;
1305 if (!nOBJID)
1306 return nullptr;
1308 std::unique_ptr<SdrUnoObj, SdrObjectFreeOp> pLabel;
1309 std::unique_ptr<SdrUnoObj, SdrObjectFreeOp> pControl;
1310 if ( !createControlLabelPair( *pOutDev, 0, 0, xField, xNumberFormats, nOBJID, sLabelPostfix,
1311 pLabel, pControl, xDataSource, sDataSource, sCommand, nCommandType )
1314 return nullptr;
1318 // group objects
1319 bool bCheckbox = ( OBJ_FM_CHECKBOX == nOBJID );
1320 OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateFieldControl: why was there a label created for a check box?" );
1321 if ( bCheckbox )
1322 return SdrObjectUniquePtr(pControl.release());
1324 SdrObjGroup* pGroup = new SdrObjGroup(getView()->getSdrModelFromSdrView());
1325 SdrObjList* pObjList = pGroup->GetSubList();
1326 pObjList->InsertObject( pLabel.release() );
1327 pObjList->InsertObject( pControl.release() );
1329 if ( bDateNTimeField )
1330 { // so far we created a date field only, but we also need a time field
1331 if ( createControlLabelPair( *pOutDev, 0, 1000, xField, xNumberFormats, OBJ_FM_TIMEFIELD,
1332 SvxResId(RID_STR_POSTFIX_TIME), pLabel, pControl,
1333 xDataSource, sDataSource, sCommand, nCommandType )
1336 pObjList->InsertObject( pLabel.release() );
1337 pObjList->InsertObject( pControl.release() );
1341 return SdrObjectUniquePtr(pGroup); // and done
1343 catch (const Exception&)
1345 DBG_UNHANDLED_EXCEPTION("svx");
1349 return nullptr;
1353 SdrObjectUniquePtr FmXFormView::implCreateXFormsControl( const svx::OXFormsDescriptor &_rDesc )
1355 // not if we're in design mode
1356 if ( !m_pView->IsDesignMode() )
1357 return nullptr;
1359 // go
1362 // determine the table/query field which we should create a control for
1363 Reference< XNumberFormats > xNumberFormats;
1364 OUString sLabelPostfix = _rDesc.szName;
1367 // only for text size
1368 OutputDevice* pOutDev = nullptr;
1369 if (m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
1370 pOutDev = const_cast<OutputDevice*>(m_pView->GetActualOutDev());
1371 else
1372 {// find OutDev
1373 if (SdrPageView* pPageView = m_pView->GetSdrPageView())
1375 // const SdrPageViewWinList& rWinList = pPageView->GetWinList();
1376 // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows();
1378 for( sal_uInt32 i = 0; i < pPageView->PageWindowCount(); i++ )
1380 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);
1382 if( rPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType() == OUTDEV_WINDOW)
1384 pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice();
1385 break;
1391 if ( !pOutDev )
1392 return nullptr;
1395 // The service name decides which control should be created
1396 sal_uInt16 nOBJID = OBJ_FM_EDIT;
1397 if(_rDesc.szServiceName == FM_SUN_COMPONENT_NUMERICFIELD)
1398 nOBJID = OBJ_FM_NUMERICFIELD;
1399 if(_rDesc.szServiceName == FM_SUN_COMPONENT_CHECKBOX)
1400 nOBJID = OBJ_FM_CHECKBOX;
1401 if(_rDesc.szServiceName == FM_COMPONENT_COMMANDBUTTON)
1402 nOBJID = OBJ_FM_BUTTON;
1404 Reference< css::form::submission::XSubmission > xSubmission(_rDesc.xPropSet, UNO_QUERY);
1406 // xform control or submission button?
1407 if ( !xSubmission.is() )
1409 std::unique_ptr<SdrUnoObj, SdrObjectFreeOp> pLabel;
1410 std::unique_ptr<SdrUnoObj, SdrObjectFreeOp> pControl;
1411 if ( !createControlLabelPair( *pOutDev, 0, 0, nullptr, xNumberFormats, nOBJID, sLabelPostfix,
1412 pLabel, pControl, nullptr, "", "", -1 )
1415 return nullptr;
1419 // Now build the connection between the control and the data item.
1420 Reference< XValueBinding > xValueBinding(_rDesc.xPropSet,UNO_QUERY);
1421 Reference< XBindableValue > xBindableValue(pControl->GetUnoControlModel(),UNO_QUERY);
1423 DBG_ASSERT( xBindableValue.is(), "FmXFormView::implCreateXFormsControl: control's not bindable!" );
1424 if ( xBindableValue.is() )
1425 xBindableValue->setValueBinding(xValueBinding);
1427 bool bCheckbox = ( OBJ_FM_CHECKBOX == nOBJID );
1428 OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateXFormsControl: why was there a label created for a check box?" );
1429 if ( bCheckbox )
1430 return SdrObjectUniquePtr(pControl.release());
1433 // group objects
1434 SdrObjGroup* pGroup = new SdrObjGroup(getView()->getSdrModelFromSdrView());
1435 SdrObjList* pObjList = pGroup->GetSubList();
1436 pObjList->InsertObject(pLabel.release());
1437 pObjList->InsertObject(pControl.release());
1439 return SdrObjectUniquePtr(pGroup);
1441 else {
1443 // create a button control
1444 const MapMode& eTargetMode( pOutDev->GetMapMode() );
1445 const MapMode eSourceMode(MapUnit::Map100thMM);
1446 const sal_uInt16 nObjID = OBJ_FM_BUTTON;
1447 ::Size controlSize(4000, 500);
1448 FmFormObj *pControl = static_cast<FmFormObj*>(
1449 SdrObjFactory::MakeNewObject(
1450 getView()->getSdrModelFromSdrView(),
1451 SdrInventor::FmForm,
1452 nObjID));
1453 controlSize.setWidth( long(controlSize.Width() * eTargetMode.GetScaleX()) );
1454 controlSize.setHeight( long(controlSize.Height() * eTargetMode.GetScaleY()) );
1455 ::Point controlPos( OutputDevice::LogicToLogic( ::Point( controlSize.Width(), 0 ), eSourceMode, eTargetMode ) );
1456 ::tools::Rectangle controlRect( controlPos, OutputDevice::LogicToLogic( controlSize, eSourceMode, eTargetMode ) );
1457 pControl->SetLogicRect(controlRect);
1459 // set the button label
1460 Reference< XPropertySet > xControlSet(pControl->GetUnoControlModel(), UNO_QUERY);
1461 xControlSet->setPropertyValue(FM_PROP_LABEL, makeAny(_rDesc.szName));
1463 // connect the submission with the submission supplier (aka the button)
1464 xControlSet->setPropertyValue( FM_PROP_BUTTON_TYPE,
1465 makeAny( FormButtonType_SUBMIT ) );
1466 Reference< css::form::submission::XSubmissionSupplier > xSubmissionSupplier(pControl->GetUnoControlModel(), UNO_QUERY);
1467 xSubmissionSupplier->setSubmission(xSubmission);
1469 return SdrObjectUniquePtr(pControl);
1472 catch (const Exception&)
1474 OSL_FAIL("FmXFormView::implCreateXFormsControl: caught an exception while creating the control !");
1478 return nullptr;
1482 bool FmXFormView::createControlLabelPair( OutputDevice const & _rOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM,
1483 const Reference< XPropertySet >& _rxField, const Reference< XNumberFormats >& _rxNumberFormats,
1484 sal_uInt16 _nControlObjectID, const OUString& _rFieldPostfix,
1485 std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpLabel,
1486 std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpControl,
1487 const Reference< XDataSource >& _rxDataSource, const OUString& _rDataSourceName,
1488 const OUString& _rCommand, const sal_Int32 _nCommandType )
1490 if(!createControlLabelPair(
1491 _rOutDev,
1492 _nXOffsetMM,
1493 _nYOffsetMM,
1494 _rxField,
1495 _rxNumberFormats,
1496 _nControlObjectID,
1497 _rFieldPostfix,
1498 SdrInventor::FmForm,
1499 OBJ_FM_FIXEDTEXT,
1501 // tdf#118963 Hand over a SdrModel to SdrObject-creation. It uses the local m_pView
1502 // and already returning false when nullptr == getView() could be done, but m_pView
1503 // is already dereferenced here in many places (see below), so just use it for now.
1504 getView()->getSdrModelFromSdrView(),
1506 _rpLabel,
1507 _rpControl))
1509 return false;
1512 // insert the control model(s) into the form component hierarchy
1513 if ( _rpLabel )
1514 lcl_insertIntoFormComponentHierarchy_throw( *m_pView, *_rpLabel, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType );
1515 lcl_insertIntoFormComponentHierarchy_throw( *m_pView, *_rpControl, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType );
1517 // some context-dependent initializations
1518 FormControlFactory aControlFactory;
1519 if ( _rpLabel )
1520 aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpLabel );
1521 aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpControl );
1523 return true;
1527 bool FmXFormView::createControlLabelPair( OutputDevice const & _rOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM,
1528 const Reference< XPropertySet >& _rxField,
1529 const Reference< XNumberFormats >& _rxNumberFormats, sal_uInt16 _nControlObjectID,
1530 const OUString& _rFieldPostfix, SdrInventor _nInventor, sal_uInt16 _nLabelObjectID,
1531 SdrModel& _rModel,
1532 std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpLabel, std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpControl)
1534 sal_Int32 nDataType = 0;
1535 OUString sFieldName;
1536 Any aFieldName;
1537 if ( _rxField.is() )
1539 nDataType = ::comphelper::getINT32(_rxField->getPropertyValue(FM_PROP_FIELDTYPE));
1540 aFieldName = _rxField->getPropertyValue(FM_PROP_NAME);
1541 aFieldName >>= sFieldName;
1544 // calculate the positions, respecting the settings of the target device
1545 ::Size aTextSize( _rOutDev.GetTextWidth(sFieldName + _rFieldPostfix), _rOutDev.GetTextHeight() );
1547 MapMode eTargetMode( _rOutDev.GetMapMode() ),
1548 eSourceMode( MapUnit::Map100thMM );
1550 // text width is at least 4 centimeters
1551 // text height is always half a centimeter
1552 ::Size aDefTxtSize(4000, 500);
1553 ::Size aDefSize(4000, 500);
1554 ::Size aDefImageSize(4000, 4000);
1556 ::Size aRealSize = OutputDevice::LogicToLogic(aTextSize, eTargetMode, eSourceMode);
1557 aRealSize.setWidth( std::max(aRealSize.Width(), aDefTxtSize.Width()) );
1558 aRealSize.setHeight( aDefSize.Height() );
1560 // adjust to scaling of the target device (#53523#)
1561 aRealSize.setWidth( long(Fraction(aRealSize.Width(), 1) * eTargetMode.GetScaleX()) );
1562 aRealSize.setHeight( long(Fraction(aRealSize.Height(), 1) * eTargetMode.GetScaleY()) );
1564 // for boolean fields, we do not create a label, but just a checkbox
1565 bool bNeedLabel = ( _nControlObjectID != OBJ_FM_CHECKBOX );
1567 // the label
1568 ::std::unique_ptr< SdrUnoObj, SdrObjectFreeOp > pLabel;
1569 Reference< XPropertySet > xLabelModel;
1571 if ( bNeedLabel )
1573 pLabel.reset( dynamic_cast< SdrUnoObj* >(
1574 SdrObjFactory::MakeNewObject(
1575 _rModel,
1576 _nInventor,
1577 _nLabelObjectID)));
1579 OSL_ENSURE(pLabel, "FmXFormView::createControlLabelPair: could not create the label!");
1581 if (!pLabel)
1582 return false;
1584 xLabelModel.set( pLabel->GetUnoControlModel(), UNO_QUERY );
1585 if ( xLabelModel.is() )
1587 OUString sLabel;
1588 if ( _rxField.is() && _rxField->getPropertySetInfo()->hasPropertyByName(FM_PROP_LABEL) )
1589 _rxField->getPropertyValue(FM_PROP_LABEL) >>= sLabel;
1590 if ( sLabel.isEmpty() )
1591 sLabel = sFieldName;
1593 xLabelModel->setPropertyValue( FM_PROP_LABEL, makeAny( sLabel + _rFieldPostfix ) );
1594 OUString sObjectLabel(SvxResId(RID_STR_OBJECT_LABEL).replaceAll("#object#", sFieldName));
1595 xLabelModel->setPropertyValue(FM_PROP_NAME, makeAny(sObjectLabel));
1598 pLabel->SetLogicRect( ::tools::Rectangle(
1599 OutputDevice::LogicToLogic( ::Point( _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ),
1600 OutputDevice::LogicToLogic( aRealSize, eSourceMode, eTargetMode )
1601 ) );
1604 // the control
1605 ::std::unique_ptr< SdrUnoObj, SdrObjectFreeOp > pControl( dynamic_cast< SdrUnoObj* >(
1606 SdrObjFactory::MakeNewObject(
1607 _rModel,
1608 _nInventor,
1609 _nControlObjectID)));
1611 OSL_ENSURE(pControl, "FmXFormView::createControlLabelPair: could not create the control!");
1613 if (!pControl)
1614 return false;
1616 Reference< XPropertySet > xControlSet( pControl->GetUnoControlModel(), UNO_QUERY );
1617 if ( !xControlSet.is() )
1618 return false;
1620 // size of the control
1621 ::Size aControlSize( aDefSize );
1622 switch ( nDataType )
1624 case DataType::BIT:
1625 case DataType::BOOLEAN:
1626 aControlSize = aDefSize;
1627 break;
1628 case DataType::LONGVARCHAR:
1629 case DataType::CLOB:
1630 case DataType::LONGVARBINARY:
1631 case DataType::BLOB:
1632 aControlSize = aDefImageSize;
1633 break;
1636 if ( OBJ_FM_IMAGECONTROL == _nControlObjectID )
1637 aControlSize = aDefImageSize;
1639 aControlSize.setWidth( long(Fraction(aControlSize.Width(), 1) * eTargetMode.GetScaleX()) );
1640 aControlSize.setHeight( long(Fraction(aControlSize.Height(), 1) * eTargetMode.GetScaleY()) );
1642 pControl->SetLogicRect( ::tools::Rectangle(
1643 OutputDevice::LogicToLogic( ::Point( aRealSize.Width() + _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ),
1644 OutputDevice::LogicToLogic( aControlSize, eSourceMode, eTargetMode )
1645 ) );
1647 // some initializations
1648 Reference< XPropertySetInfo > xControlPropInfo = xControlSet->getPropertySetInfo();
1650 if ( aFieldName.hasValue() )
1652 xControlSet->setPropertyValue( FM_PROP_CONTROLSOURCE, aFieldName );
1653 xControlSet->setPropertyValue( FM_PROP_NAME, aFieldName );
1654 if ( !bNeedLabel )
1656 // no dedicated label control => use the label property
1657 if ( xControlPropInfo->hasPropertyByName( FM_PROP_LABEL ) )
1658 xControlSet->setPropertyValue( FM_PROP_LABEL, makeAny( sFieldName + _rFieldPostfix ) );
1659 else
1660 OSL_FAIL( "FmXFormView::createControlLabelPair: can't set a label for the control!" );
1664 if ( (nDataType == DataType::LONGVARCHAR || nDataType == DataType::CLOB) && xControlPropInfo->hasPropertyByName( FM_PROP_MULTILINE ) )
1666 xControlSet->setPropertyValue( FM_PROP_MULTILINE, makeAny( true ) );
1669 // announce the label to the control
1670 if ( xControlPropInfo->hasPropertyByName( FM_PROP_CONTROLLABEL ) && xLabelModel.is() )
1674 xControlSet->setPropertyValue( FM_PROP_CONTROLLABEL, makeAny( xLabelModel ) );
1676 catch (const Exception&)
1678 DBG_UNHANDLED_EXCEPTION("svx");
1682 if ( _rxField.is() )
1684 FormControlFactory::initializeFieldDependentProperties( _rxField, xControlSet, _rxNumberFormats );
1687 _rpLabel = std::move(pLabel);
1688 _rpControl = std::move(pControl);
1689 return true;
1693 FmXFormView::ObjectRemoveListener::ObjectRemoveListener( FmXFormView* pParent )
1694 :m_pParent( pParent )
1699 void FmXFormView::ObjectRemoveListener::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
1701 if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
1702 return;
1703 const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
1704 if (pSdrHint->GetKind() == SdrHintKind::ObjectRemoved)
1705 m_pParent->ObjectRemovedInAliveMode(pSdrHint->GetObject());
1709 void FmXFormView::ObjectRemovedInAliveMode( const SdrObject* pObject )
1711 // if the remote object in my MarkList, which I have memorized when switching to the
1712 // Alive mode, I have to take it out now, because I otherwise try to set the mark
1713 // again when switching back (interestingly, this fails only with grouped objects
1714 // (when accessing their ObjList GPF), not with individual ones)
1716 const size_t nCount = m_aMark.GetMarkCount();
1717 for (size_t i = 0; i < nCount; ++i)
1719 SdrMark* pMark = m_aMark.GetMark(i);
1720 SdrObject* pCurrent = pMark->GetMarkedSdrObj();
1721 if (pObject == pCurrent)
1723 m_aMark.DeleteMark(i);
1724 return;
1726 // I do not need to descend into GroupObjects: if an object is deleted there,
1727 // then the pointer, which I have, to the GroupObject still remains valid ...
1732 void FmXFormView::stopMarkListWatching()
1734 if ( m_pWatchStoredList )
1736 m_pWatchStoredList->EndListeningAll();
1737 m_pWatchStoredList.reset();
1742 void FmXFormView::startMarkListWatching()
1744 if ( !m_pWatchStoredList )
1746 FmFormModel* pModel = GetFormShell() ? GetFormShell()->GetFormModel() : nullptr;
1747 DBG_ASSERT( pModel != nullptr, "FmXFormView::startMarkListWatching: shell has no model!" );
1748 if (pModel)
1750 m_pWatchStoredList.reset(new ObjectRemoveListener( this ));
1751 m_pWatchStoredList->StartListening( *static_cast< SfxBroadcaster* >( pModel ) );
1754 else
1756 OSL_FAIL( "FmXFormView::startMarkListWatching: already listening!" );
1760 void FmXFormView::saveMarkList()
1762 if ( m_pView )
1764 m_aMark = m_pView->GetMarkedObjectList();
1765 const size_t nCount = m_aMark.GetMarkCount( );
1766 for ( size_t i = 0; i < nCount; ++i )
1768 SdrMark* pMark = m_aMark.GetMark(i);
1769 SdrObject* pObj = pMark->GetMarkedSdrObj();
1771 if ( m_pView->IsObjMarked( pObj ) )
1773 if ( pObj->IsGroupObject() )
1775 SdrObjListIter aIter( pObj->GetSubList() );
1776 bool bMixed = false;
1777 while ( aIter.IsMore() && !bMixed )
1778 bMixed = ( aIter.Next()->GetObjInventor() != SdrInventor::FmForm );
1780 if ( !bMixed )
1782 // all objects in the group are form objects
1783 m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), true /* unmark! */ );
1786 else
1788 if ( pObj->GetObjInventor() == SdrInventor::FmForm )
1789 { // this is a form layer object
1790 m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), true /* unmark! */ );
1796 else
1798 OSL_FAIL( "FmXFormView::saveMarkList: invalid view!" );
1799 m_aMark.Clear();
1803 static bool lcl_hasObject( SdrObjListIter& rIter, SdrObject const * pObj )
1805 bool bFound = false;
1806 while (rIter.IsMore() && !bFound)
1807 bFound = pObj == rIter.Next();
1809 rIter.Reset();
1810 return bFound;
1814 void FmXFormView::restoreMarkList( SdrMarkList& _rRestoredMarkList )
1816 if ( !m_pView )
1817 return;
1819 _rRestoredMarkList.Clear();
1821 const SdrMarkList& rCurrentList = m_pView->GetMarkedObjectList();
1822 FmFormPage* pPage = GetFormShell() ? GetFormShell()->GetCurPage() : nullptr;
1823 if (pPage)
1825 if (rCurrentList.GetMarkCount())
1826 { // there is a current mark ... hmm. Is it a subset of the mark we remembered in saveMarkList?
1827 bool bMisMatch = false;
1829 // loop through all current marks
1830 const size_t nCurrentCount = rCurrentList.GetMarkCount();
1831 for ( size_t i=0; i<nCurrentCount && !bMisMatch; ++i )
1833 const SdrObject* pCurrentMarked = rCurrentList.GetMark( i )->GetMarkedSdrObj();
1835 // loop through all saved marks, check for equality
1836 bool bFound = false;
1837 const size_t nSavedCount = m_aMark.GetMarkCount();
1838 for ( size_t j=0; j<nSavedCount && !bFound; ++j )
1840 if ( m_aMark.GetMark( j )->GetMarkedSdrObj() == pCurrentMarked )
1841 bFound = true;
1844 // did not find a current mark in the saved marks
1845 if ( !bFound )
1846 bMisMatch = true;
1849 if ( bMisMatch )
1851 m_aMark.Clear();
1852 _rRestoredMarkList = rCurrentList;
1853 return;
1856 // it is important that the objects of the mark list are not accessed,
1857 // because they can be already destroyed
1858 SdrPageView* pCurPageView = m_pView->GetSdrPageView();
1859 SdrObjListIter aPageIter( pPage );
1860 bool bFound = true;
1862 // do all objects still exist
1863 const size_t nCount = m_aMark.GetMarkCount();
1864 for (size_t i = 0; i < nCount && bFound; ++i)
1866 SdrMark* pMark = m_aMark.GetMark(i);
1867 SdrObject* pObj = pMark->GetMarkedSdrObj();
1868 if (pObj->IsGroupObject())
1870 SdrObjListIter aIter(pObj->GetSubList());
1871 while (aIter.IsMore() && bFound)
1872 bFound = lcl_hasObject(aPageIter, aIter.Next());
1874 else
1875 bFound = lcl_hasObject(aPageIter, pObj);
1877 bFound = bFound && pCurPageView == pMark->GetPageView();
1880 if (bFound)
1882 // evaluate the LastObject
1883 if (nCount) // now mark the objects
1885 for (size_t i = 0; i < nCount; ++i)
1887 SdrMark* pMark = m_aMark.GetMark(i);
1888 SdrObject* pObj = pMark->GetMarkedSdrObj();
1889 if ( pObj->GetObjInventor() == SdrInventor::FmForm )
1890 if ( !m_pView->IsObjMarked( pObj ) )
1891 m_pView->MarkObj( pObj, pMark->GetPageView() );
1894 _rRestoredMarkList = m_aMark;
1897 m_aMark.Clear();
1901 void SAL_CALL FmXFormView::focusGained( const FocusEvent& /*e*/ )
1903 if ( m_xWindow.is() && m_pView )
1905 m_pView->SetMoveOutside( true, FmFormView::ImplAccess() );
1909 void SAL_CALL FmXFormView::focusLost( const FocusEvent& /*e*/ )
1911 // when switch the focus outside the office the mark didn't change
1912 // so we can not remove us as focus listener
1913 if ( m_xWindow.is() && m_pView )
1915 m_pView->SetMoveOutside( false, FmFormView::ImplAccess() );
1919 DocumentType FmXFormView::impl_getDocumentType() const
1921 if ( GetFormShell() && GetFormShell()->GetImpl() )
1922 return GetFormShell()->GetImpl()->getDocumentType_Lock();
1923 return eUnknownDocumentType;
1926 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */