1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 
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>
47 
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>
75 
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>
88 
89 #include <algorithm>
90 
91 using namespace ::comphelper;
92 using namespace ::svx;
93 using namespace ::svxform;
94 using namespace ::dbtools;
95 
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;
145 
146     namespace FormComponentType = ::com::sun::star::form::FormComponentType;
147     namespace CommandType = ::com::sun::star::sdb::CommandType;
148     namespace DataType = ::com::sun::star::sdbc::DataType;
149 
150 
151 class FmXFormView::ObjectRemoveListener : public SfxListener
152 {
153     FmXFormView* m_pParent;
154 public:
155     explicit ObjectRemoveListener( FmXFormView* pParent );
156     virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
157 };
158 
FormViewPageWindowAdapter(const css::uno::Reference<css::uno::XComponentContext> & _rContext,const SdrPageWindow & _rWindow,FmXFormView * _pViewImpl)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() ) )
164 {
165 
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 )
170     {
171         try
172         {
173             Reference< XIndexAccess > xForms( pFormPage->GetForms(), UNO_QUERY_THROW );
174             sal_uInt32 nLength = xForms->getCount();
175             for (sal_uInt32 i = 0; i < nLength; i++)
176             {
177                 Reference< XForm > xForm( xForms->getByIndex(i), UNO_QUERY );
178                 if ( xForm.is() )
179                     setController( xForm, nullptr );
180             }
181         }
182         catch (const Exception&)
183         {
184             DBG_UNHANDLED_EXCEPTION("svx");
185         }
186     }
187 }
188 
~FormViewPageWindowAdapter()189 FormViewPageWindowAdapter::~FormViewPageWindowAdapter()
190 {
191 }
192 
dispose()193 void FormViewPageWindowAdapter::dispose()
194 {
195     for (   ::std::vector< Reference< XFormController > >::const_iterator i = m_aControllerList.begin();
196             i != m_aControllerList.end();
197             ++i
198         )
199     {
200         try
201         {
202             Reference< XFormController > xController( *i, UNO_SET_THROW );
203 
204             // detaching the events
205             Reference< XChild > xControllerModel( xController->getModel(), UNO_QUERY );
206             if ( xControllerModel.is() )
207             {
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 );
211             }
212 
213             // dispose the formcontroller
214             xController->dispose();
215         }
216         catch (const Exception&)
217         {
218             DBG_UNHANDLED_EXCEPTION("svx");
219         }
220     }
221 
222     m_aControllerList.clear();
223 }
224 
hasElements()225 sal_Bool SAL_CALL FormViewPageWindowAdapter::hasElements()
226 {
227     return getCount() != 0;
228 }
229 
getElementType()230 Type SAL_CALL  FormViewPageWindowAdapter::getElementType()
231 {
232     return cppu::UnoType<XFormController>::get();
233 }
234 
235 // XIndexAccess
getCount()236 sal_Int32 SAL_CALL FormViewPageWindowAdapter::getCount()
237 {
238     return m_aControllerList.size();
239 }
240 
getByIndex(sal_Int32 nIndex)241 Any SAL_CALL FormViewPageWindowAdapter::getByIndex(sal_Int32 nIndex)
242 {
243     if (nIndex < 0 ||
244         nIndex >= getCount())
245         throw IndexOutOfBoundsException();
246 
247     Any aElement;
248     aElement <<= m_aControllerList[nIndex];
249     return aElement;
250 }
251 
makeVisible(const Reference<XControl> & Control)252 void SAL_CALL FormViewPageWindowAdapter::makeVisible( const Reference< XControl >& Control )
253 {
254     SolarMutexGuard aSolarGuard;
255 
256     Reference< XWindow >  xWindow( Control, UNO_QUERY );
257     if ( xWindow.is() && m_pViewImpl->getView() && m_pWindow )
258     {
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 );
263     }
264 }
265 
getControllerSearchChildren(const Reference<XIndexAccess> & xIndex,const Reference<XTabControllerModel> & xModel)266 static Reference< XFormController >  getControllerSearchChildren( const Reference< XIndexAccess > & xIndex, const Reference< XTabControllerModel > & xModel)
267 {
268     if (xIndex.is() && xIndex->getCount())
269     {
270         Reference< XFormController >  xController;
271 
272         for (sal_Int32 n = xIndex->getCount(); n-- && !xController.is(); )
273         {
274             xIndex->getByIndex(n) >>= xController;
275             if (xModel.get() == xController->getModel().get())
276                 return xController;
277             else
278             {
279                 xController = getControllerSearchChildren(xController, xModel);
280                 if ( xController.is() )
281                     return xController;
282             }
283         }
284     }
285     return Reference< XFormController > ();
286 }
287 
288 // Search the according controller
getController(const Reference<XForm> & xForm) const289 Reference< XFormController >  FormViewPageWindowAdapter::getController( const Reference< XForm > & xForm ) const
290 {
291     Reference< XTabControllerModel >  xModel(xForm, UNO_QUERY);
292     for (const auto& rpController : m_aControllerList)
293     {
294         if (rpController->getModel().get() == xModel.get())
295             return rpController;
296 
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;
301     }
302     return Reference< XFormController > ();
303 }
304 
305 
setController(const Reference<XForm> & xForm,const Reference<XFormController> & _rxParentController)306 void FormViewPageWindowAdapter::setController(const Reference< XForm > & xForm, const Reference< XFormController >& _rxParentController )
307 {
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;
312 
313     Reference< XTabControllerModel >  xTabOrder(xForm, UNO_QUERY);
314 
315     // create a form controller
316     Reference< XFormController > xController( FormController::create(m_xContext) );
317 
318     Reference< XInteractionHandler > xHandler;
319     if ( _rxParentController.is() )
320         xHandler = _rxParentController->getInteractionHandler();
321     else
322     {
323         // TODO: should we create a default handler? Not really necessary, since the
324         // FormController itself has a default fallback
325     }
326     if ( xHandler.is() )
327         xController->setInteractionHandler( xHandler );
328 
329     xController->setContext( this );
330 
331     xController->setModel( xTabOrder );
332     xController->setContainer( m_xControlContainer );
333     xController->activateTabOrder();
334     xController->addActivateListener( m_pViewImpl );
335 
336     if ( _rxParentController.is() )
337         _rxParentController->addChildController( xController );
338     else
339     {
340         m_aControllerList.push_back(xController);
341 
342         xController->setParent( *this );
343 
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) );
347     }
348 
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++)
353     {
354         if ( xFormCps->getByIndex(i) >>= xSubForm )
355             setController( xSubForm, xController );
356     }
357 }
358 
359 
updateTabOrder(const Reference<XForm> & _rxForm)360 void FormViewPageWindowAdapter::updateTabOrder( const Reference< XForm >& _rxForm )
361 {
362     OSL_PRECOND( _rxForm.is(), "FormViewPageWindowAdapter::updateTabOrder: illegal argument!" );
363     if ( !_rxForm.is() )
364         return;
365 
366     try
367     {
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();
372         }
373         else
374         {   // otherwise, create a TabController
375 
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 );
383 
384             setController( _rxForm, xParentController );
385         }
386     }
387     catch (const Exception&)
388     {
389         DBG_UNHANDLED_EXCEPTION("svx");
390     }
391 }
392 
393 
FmXFormView(FmFormView * _pView)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 )
403 {
404 }
405 
406 
cancelEvents()407 void FmXFormView::cancelEvents()
408 {
409     if ( m_nActivationEvent )
410     {
411         Application::RemoveUserEvent( m_nActivationEvent );
412         m_nActivationEvent = nullptr;
413     }
414 
415     if ( m_nErrorMessageEvent )
416     {
417         Application::RemoveUserEvent( m_nErrorMessageEvent );
418         m_nErrorMessageEvent = nullptr;
419     }
420 
421     if ( m_nAutoFocusEvent )
422     {
423         Application::RemoveUserEvent( m_nAutoFocusEvent );
424         m_nAutoFocusEvent = nullptr;
425     }
426 
427     if ( m_nControlWizardEvent )
428     {
429         Application::RemoveUserEvent( m_nControlWizardEvent );
430         m_nControlWizardEvent = nullptr;
431     }
432 }
433 
434 
notifyViewDying()435 void FmXFormView::notifyViewDying( )
436 {
437     DBG_ASSERT( m_pView, "FmXFormView::notifyViewDying: my view already died!" );
438     m_pView = nullptr;
439     cancelEvents();
440 }
441 
442 
~FmXFormView()443 FmXFormView::~FmXFormView()
444 {
445     DBG_ASSERT( m_aPageWindowAdapters.empty(), "FmXFormView::~FmXFormView: Window list not empty!" );
446     for (const auto& rpAdapter : m_aPageWindowAdapters)
447     {
448         rpAdapter->dispose();
449     }
450 
451     cancelEvents();
452 }
453 
454 //      EventListener
455 
disposing(const EventObject & Source)456 void SAL_CALL FmXFormView::disposing(const EventObject& Source)
457 {
458     if ( m_xWindow.is() && Source.Source == m_xWindow )
459     {
460         m_xWindow->removeFocusListener(this);
461         if ( m_pView )
462         {
463             m_pView->SetMoveOutside( false, FmFormView::ImplAccess() );
464         }
465         m_xWindow = nullptr;
466     }
467 }
468 
469 // XFormControllerListener
470 
formActivated(const EventObject & rEvent)471 void SAL_CALL FmXFormView::formActivated(const EventObject& rEvent)
472 {
473     if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() )
474         m_pView->GetFormShell()->GetImpl()->formActivated( rEvent );
475 }
476 
477 
formDeactivated(const EventObject & rEvent)478 void SAL_CALL FmXFormView::formDeactivated(const EventObject& rEvent)
479 {
480     if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() )
481         m_pView->GetFormShell()->GetImpl()->formDeactivated( rEvent );
482 }
483 
484 // XContainerListener
485 
elementInserted(const ContainerEvent & evt)486 void SAL_CALL FmXFormView::elementInserted(const ContainerEvent& evt)
487 {
488     try
489     {
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 );
494 
495         if ( m_isTabOrderUpdateSuspended )
496         {
497             // remember the container and the control, so we can update the tab order on resumeTabOrderUpdate
498             m_aNeedTabOrderUpdate[ xControlContainer ].insert( xForm );
499         }
500         else
501         {
502             PFormViewPageWindowAdapter pAdapter = findWindow( xControlContainer );
503             if ( pAdapter.is() )
504                 pAdapter->updateTabOrder( xForm );
505         }
506     }
507     catch (const Exception&)
508     {
509         DBG_UNHANDLED_EXCEPTION("svx");
510     }
511 }
512 
513 
elementReplaced(const ContainerEvent & evt)514 void SAL_CALL FmXFormView::elementReplaced(const ContainerEvent& evt)
515 {
516     elementInserted(evt);
517 }
518 
519 
elementRemoved(const ContainerEvent &)520 void SAL_CALL FmXFormView::elementRemoved(const ContainerEvent& /*evt*/)
521 {
522 }
523 
524 
findWindow(const Reference<XControlContainer> & _rxCC) const525 PFormViewPageWindowAdapter FmXFormView::findWindow( const Reference< XControlContainer >& _rxCC )  const
526 {
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;
532 }
533 
534 
addWindow(const SdrPageWindow & rWindow)535 void FmXFormView::addWindow(const SdrPageWindow& rWindow)
536 {
537     FmFormPage* pFormPage = dynamic_cast<FmFormPage*>( rWindow.GetPageView().GetPage()  );
538     if ( !pFormPage )
539         return;
540 
541     const Reference< XControlContainer >& xCC = rWindow.GetControlContainer();
542     if  (   xCC.is()
543         &&  ( !findWindow( xCC ).is() )
544         )
545     {
546         PFormViewPageWindowAdapter pAdapter = new FormViewPageWindowAdapter( comphelper::getProcessComponentContext(), rWindow, this );
547         m_aPageWindowAdapters.push_back( pAdapter );
548 
549         // listen at the ControlContainer to notice changes
550         Reference< XContainer >  xContainer( xCC, UNO_QUERY );
551         if ( xContainer.is() )
552             xContainer->addContainerListener( this );
553     }
554 }
555 
556 
removeWindow(const Reference<XControlContainer> & _rxCC)557 void FmXFormView::removeWindow( const Reference< XControlContainer >& _rxCC )
558 {
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
563 
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())
567     {
568         Reference< XContainer >  xContainer( _rxCC, UNO_QUERY );
569         if ( xContainer.is() )
570             xContainer->removeContainerListener( this );
571 
572         (*i)->dispose();
573         m_aPageWindowAdapters.erase( i );
574     }
575 }
576 
577 
displayAsyncErrorMessage(const SQLErrorEvent & _rEvent)578 void FmXFormView::displayAsyncErrorMessage( const SQLErrorEvent& _rEvent )
579 {
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 ) );
585 }
586 
587 
IMPL_LINK_NOARG(FmXFormView,OnDelayedErrorMessage,void *,void)588 IMPL_LINK_NOARG(FmXFormView, OnDelayedErrorMessage, void*, void)
589 {
590     m_nErrorMessageEvent = nullptr;
591     displayException( m_aAsyncError );
592 }
593 
594 
onFirstViewActivation(const FmFormModel * _pDocModel)595 void FmXFormView::onFirstViewActivation( const FmFormModel* _pDocModel )
596 {
597     if ( _pDocModel && _pDocModel->GetAutoControlFocus() )
598         m_nAutoFocusEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnAutoFocus ) );
599 }
600 
601 
suspendTabOrderUpdate()602 void FmXFormView::suspendTabOrderUpdate()
603 {
604     OSL_ENSURE( !m_isTabOrderUpdateSuspended, "FmXFormView::suspendTabOrderUpdate: nesting not allowed!" );
605     m_isTabOrderUpdateSuspended = true;
606 }
607 
608 
resumeTabOrderUpdate()609 void FmXFormView::resumeTabOrderUpdate()
610 {
611     OSL_ENSURE( m_isTabOrderUpdateSuspended, "FmXFormView::resumeTabOrderUpdate: not suspended!" );
612     m_isTabOrderUpdateSuspended = false;
613 
614     // update the tab orders for all components which were collected since the suspendTabOrderUpdate call.
615     for (const auto& rContainer : m_aNeedTabOrderUpdate)
616     {
617         PFormViewPageWindowAdapter pAdapter = findWindow( rContainer.first );
618         if ( !pAdapter.is() )
619             continue;
620 
621         for (const auto& rForm : rContainer.second)
622         {
623             pAdapter->updateTabOrder( rForm );
624         }
625     }
626     m_aNeedTabOrderUpdate.clear();
627 }
628 
629 namespace
630 {
isActivableDatabaseForm(const Reference<XFormController> & xController)631     bool isActivableDatabaseForm(const Reference< XFormController > &xController)
632     {
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;
637 
638         Reference< XPropertySet > xFormSet( xForm, UNO_QUERY );
639         if ( !xFormSet.is() )
640         {
641             SAL_WARN( "svx.form", "FmXFormView::OnActivate: a form which does not have properties?" );
642             return false;
643         }
644 
645         const OUString aSource = ::comphelper::getString( xFormSet->getPropertyValue( FM_PROP_COMMAND ) );
646 
647         return !aSource.isEmpty();
648     }
649 
650     class find_active_databaseform
651     {
652         const Reference< XFormController > xActiveController;
653 
654     public:
655 
find_active_databaseform(const Reference<XFormController> & _xActiveController)656         explicit find_active_databaseform( const Reference< XFormController >& _xActiveController )
657             : xActiveController(_xActiveController )
658         {}
659 
operator ()(const Reference<XFormController> & xController)660         Reference < XFormController > operator() (const Reference< XFormController > &xController)
661         {
662             if(xController == xActiveController && isActivableDatabaseForm(xController))
663                 return xController;
664 
665             if ( !xController.is() )
666             {
667                 SAL_WARN( "svx.form", "FmXFormView::OnActivate: a form controller which does not have children?" );
668                 return nullptr;
669             }
670 
671             for(sal_Int32 i = 0; i < xController->getCount(); ++i)
672             {
673                 const Any a(xController->getByIndex(i));
674                 Reference < XFormController > xI;
675                 if ((a >>= xI) && xI.is())
676                 {
677                     Reference < XFormController > xRes(operator()(xI));
678                     if (xRes.is())
679                         return xRes;
680                 }
681             }
682 
683             return nullptr;
684         }
685     };
686 }
687 
688 
IMPL_LINK_NOARG(FmXFormView,OnActivate,void *,void)689 IMPL_LINK_NOARG(FmXFormView, OnActivate, void*, void)
690 {
691     m_nActivationEvent = nullptr;
692 
693     if ( !m_pView )
694     {
695         OSL_FAIL( "FmXFormView::OnActivate: well... seems we have a timing problem (the view already died)!" );
696         return;
697     }
698 
699     // setting the controller to activate
700     if (m_pView->GetFormShell() && m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
701     {
702         FmXFormShell* const pShImpl =  m_pView->GetFormShell()->GetImpl();
703 
704         if(!pShImpl)
705             return;
706 
707         find_active_databaseform fad(pShImpl->getActiveController_Lock());
708 
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)
712         {
713             if ( pWindow == rpPageWindowAdapter->getWindow() )
714                 pAdapter = rpPageWindowAdapter;
715         }
716 
717         if ( pAdapter.is() )
718         {
719             Reference< XFormController > xControllerToActivate;
720             for (const Reference< XFormController > & xController : pAdapter->GetList())
721             {
722                 if ( !xController.is() )
723                     continue;
724 
725                 {
726                     Reference< XFormController > xActiveController(fad(xController));
727                     if (xActiveController.is())
728                     {
729                         xControllerToActivate = xActiveController;
730                         break;
731                     }
732                 }
733 
734                 if(xControllerToActivate.is() || !isActivableDatabaseForm(xController))
735                     continue;
736 
737                 xControllerToActivate = xController;
738             }
739             pShImpl->setActiveController_Lock(xControllerToActivate);
740         }
741     }
742 }
743 
744 
Activate(bool bSync)745 void FmXFormView::Activate(bool bSync)
746 {
747     if (m_nActivationEvent)
748     {
749         Application::RemoveUserEvent(m_nActivationEvent);
750         m_nActivationEvent = nullptr;
751     }
752 
753     if (bSync)
754     {
755         LINK(this,FmXFormView,OnActivate).Call(nullptr);
756     }
757     else
758         m_nActivationEvent = Application::PostUserEvent(LINK(this,FmXFormView,OnActivate));
759 }
760 
761 
Deactivate(bool bDeactivateController)762 void FmXFormView::Deactivate(bool bDeactivateController)
763 {
764     if (m_nActivationEvent)
765     {
766         Application::RemoveUserEvent(m_nActivationEvent);
767         m_nActivationEvent = nullptr;
768     }
769 
770     FmXFormShell* pShImpl =  m_pView->GetFormShell() ? m_pView->GetFormShell()->GetImpl() : nullptr;
771     if (pShImpl && bDeactivateController)
772         pShImpl->setActiveController_Lock(nullptr);
773 }
774 
775 
GetFormShell() const776 FmFormShell* FmXFormView::GetFormShell() const
777 {
778     return m_pView ? m_pView->GetFormShell() : nullptr;
779 }
780 
AutoFocus()781 void FmXFormView::AutoFocus()
782 {
783     if (m_nAutoFocusEvent)
784         Application::RemoveUserEvent(m_nAutoFocusEvent);
785 
786     m_nAutoFocusEvent = Application::PostUserEvent(LINK(this, FmXFormView, OnAutoFocus));
787 }
788 
789 
isFocusable(const Reference<XControl> & i_rControl)790 bool FmXFormView::isFocusable( const Reference< XControl >& i_rControl )
791 {
792     if ( !i_rControl.is() )
793         return false;
794 
795     try
796     {
797         Reference< XPropertySet > xModelProps( i_rControl->getModel(), UNO_QUERY_THROW );
798 
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;
804 
805         // check the class id of the control model
806         sal_Int16 nClassId = FormComponentType::CONTROL;
807         OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
808 
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 )
818             )
819         {
820             return true;
821         }
822     }
823     catch (const Exception&)
824     {
825         DBG_UNHANDLED_EXCEPTION("svx");
826     }
827     return false;
828 }
829 
830 
lcl_firstFocussableControl(const Sequence<Reference<XControl>> & _rControls)831 static Reference< XControl > lcl_firstFocussableControl( const Sequence< Reference< XControl > >& _rControls )
832 {
833     Reference< XControl > xReturn;
834 
835     // loop through all the controls
836     for ( auto const & control : _rControls )
837     {
838         if ( !control.is() )
839             continue;
840 
841         if ( FmXFormView::isFocusable( control ) )
842         {
843             xReturn = control;
844             break;
845         }
846     }
847 
848     if ( !xReturn.is() && _rControls.hasElements() )
849         xReturn = _rControls[0];
850 
851     return xReturn;
852 }
853 
854 
855 namespace
856 {
857 
lcl_ensureControlsOfFormExist_nothrow(const SdrPage & _rPage,const SdrView & _rView,const vcl::Window & _rWindow,const Reference<XForm> & _rxForm)858     void lcl_ensureControlsOfFormExist_nothrow( const SdrPage& _rPage, const SdrView& _rView, const vcl::Window& _rWindow, const Reference< XForm >& _rxForm )
859     {
860         try
861         {
862             Reference< XInterface > xNormalizedForm( _rxForm, UNO_QUERY_THROW );
863 
864             SdrObjListIter aSdrObjectLoop( &_rPage, SdrIterMode::DeepNoGroups );
865             while ( aSdrObjectLoop.IsMore() )
866             {
867                 FmFormObj* pFormObject = FmFormObj::GetFormObject( aSdrObjectLoop.Next() );
868                 if ( !pFormObject )
869                     continue;
870 
871                 Reference< XChild > xModel( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW );
872                 Reference< XInterface > xModelParent( xModel->getParent(), UNO_QUERY );
873 
874                 if ( xNormalizedForm.get() != xModelParent.get() )
875                     continue;
876 
877                 pFormObject->GetUnoControl( _rView, _rWindow );
878             }
879         }
880         catch (const Exception&)
881         {
882             DBG_UNHANDLED_EXCEPTION("svx");
883         }
884     }
885 }
886 
887 
getFormController(const Reference<XForm> & _rxForm,const OutputDevice & _rDevice) const888 Reference< XFormController > FmXFormView::getFormController( const Reference< XForm >& _rxForm, const OutputDevice& _rDevice ) const
889 {
890     Reference< XFormController > xController;
891 
892     for (const PFormViewPageWindowAdapter& pAdapter : m_aPageWindowAdapters)
893     {
894         if ( !pAdapter.get() )
895         {
896             SAL_WARN( "svx.form", "FmXFormView::getFormController: invalid page window adapter!" );
897             continue;
898         }
899 
900         if ( pAdapter->getWindow() != &_rDevice )
901             // wrong device
902             continue;
903 
904         xController = pAdapter->getController( _rxForm );
905         if ( xController.is() )
906             break;
907     }
908     return xController;
909 }
910 
911 
IMPL_LINK_NOARG(FmXFormView,OnAutoFocus,void *,void)912 IMPL_LINK_NOARG(FmXFormView, OnAutoFocus, void*, void)
913 {
914     m_nAutoFocusEvent = nullptr;
915 
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
918 
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 >() );
924 
925     const PFormViewPageWindowAdapter pAdapter = m_aPageWindowAdapters.empty() ? nullptr : m_aPageWindowAdapters[0];
926     const vcl::Window* pWindow = pAdapter.get() ? pAdapter->getWindow() : nullptr;
927 
928     ENSURE_OR_RETURN_VOID( xForms.is() && pWindow, "FmXFormView::OnAutoFocus: could not collect all essentials!" );
929 
930     try
931     {
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 );
937 
938         // go for the first control of the controller
939         Sequence< Reference< XControl > > aControls( xTabController->getControls() );
940         if ( !aControls.hasElements() )
941         {
942             Reference< XElementAccess > xFormElementAccess( xForm, UNO_QUERY_THROW );
943             if (xFormElementAccess->hasElements() && pPage && m_pView)
944             {
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!" );
953             }
954         }
955 
956         // set the focus to this first control
957         Reference< XWindow > xControlWindow( lcl_firstFocussableControl( aControls ), UNO_QUERY );
958         if ( !xControlWindow.is() )
959             return;
960 
961         xControlWindow->setFocus();
962 
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 )
967         {
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 ) );
971         }
972     }
973     catch (const Exception&)
974     {
975         DBG_UNHANDLED_EXCEPTION("svx");
976     }
977 }
978 
979 
onCreatedFormObject(FmFormObj const & _rFormObject)980 void FmXFormView::onCreatedFormObject( FmFormObj const & _rFormObject )
981 {
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;
987 
988     // it is valid that the form shell's forms collection is not initialized, yet
989     pShellImpl->UpdateForms_Lock(true);
990 
991     m_xLastCreatedControlModel.set( _rFormObject.GetUnoControlModel(), UNO_QUERY );
992     if ( !m_xLastCreatedControlModel.is() )
993         return;
994 
995     // some initial property defaults
996     FormControlFactory aControlFactory;
997     aControlFactory.initializeControlModel(pShellImpl->getDocumentType_Lock(), _rFormObject);
998 
999     if (!pShellImpl->GetWizardUsing_Lock())
1000         return;
1001 
1002     // #i31958# don't call wizards in XForms mode
1003     if (pShellImpl->isEnhancedForm_Lock())
1004         return;
1005 
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;
1010 
1011     if ( m_nControlWizardEvent )
1012         Application::RemoveUserEvent( m_nControlWizardEvent );
1013     m_nControlWizardEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnStartControlWizard ) );
1014 }
1015 
breakCreateFormObject()1016 void FmXFormView::breakCreateFormObject()
1017 {
1018     if (m_nControlWizardEvent != nullptr)
1019     {
1020         Application::RemoveUserEvent(m_nControlWizardEvent);
1021         m_nControlWizardEvent = nullptr;
1022     }
1023     m_xLastCreatedControlModel.clear();
1024 }
1025 
IMPL_LINK_NOARG(FmXFormView,OnStartControlWizard,void *,void)1026 IMPL_LINK_NOARG( FmXFormView, OnStartControlWizard, void*, void )
1027 {
1028     m_nControlWizardEvent = nullptr;
1029     OSL_PRECOND( m_xLastCreatedControlModel.is(), "FmXFormView::OnStartControlWizard: illegal call!" );
1030     if ( !m_xLastCreatedControlModel.is() )
1031         return;
1032 
1033     sal_Int16 nClassId = FormComponentType::CONTROL;
1034     try
1035     {
1036         OSL_VERIFY( m_xLastCreatedControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
1037     }
1038     catch (const Exception&)
1039     {
1040         DBG_UNHANDLED_EXCEPTION("svx");
1041     }
1042 
1043     const sal_Char* pWizardAsciiName = nullptr;
1044     switch ( nClassId )
1045     {
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;
1056     }
1057 
1058     if ( pWizardAsciiName )
1059     {
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)));
1065 
1066         // create the wizard object
1067         Reference< XExecutableDialog > xWizard;
1068         try
1069         {
1070             Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
1071             xWizard.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext( OUString::createFromAscii(pWizardAsciiName), aWizardArgs.getWrappedPropertyValues(), xContext ), UNO_QUERY);
1072         }
1073         catch (const Exception&)
1074         {
1075             DBG_UNHANDLED_EXCEPTION("svx");
1076         }
1077 
1078         if ( !xWizard.is() )
1079         {
1080             ShowServiceNotAvailableError( nullptr, OUString::createFromAscii(pWizardAsciiName), true );
1081         }
1082         else
1083         {
1084             // execute the wizard
1085             try
1086             {
1087                 xWizard->execute();
1088             }
1089             catch (const Exception&)
1090             {
1091                 DBG_UNHANDLED_EXCEPTION("svx");
1092             }
1093         }
1094     }
1095 
1096     m_xLastCreatedControlModel.clear();
1097 }
1098 
1099 
1100 namespace
1101 {
lcl_insertIntoFormComponentHierarchy_throw(const FmFormView & _rView,const SdrUnoObj & _rSdrObj,const Reference<XDataSource> & _rxDataSource,const OUString & _rDataSourceName,const OUString & _rCommand,const sal_Int32 _nCommandType)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 )
1105     {
1106         FmFormPage& rPage = static_cast< FmFormPage& >( *_rView.GetSdrPageView()->GetPage() );
1107 
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 );
1112 
1113         FmFormPageImpl::setUniqueName( xFormComponent, xTargetForm );
1114 
1115         Reference< XIndexContainer > xFormAsContainer( xTargetForm, UNO_QUERY_THROW );
1116         xFormAsContainer->insertByIndex( xFormAsContainer->getCount(), makeAny( xFormComponent ) );
1117     }
1118 }
1119 
1120 
implCreateFieldControl(const svx::ODataAccessDescriptor & _rColumnDescriptor)1121 SdrObjectUniquePtr FmXFormView::implCreateFieldControl( const svx::ODataAccessDescriptor& _rColumnDescriptor )
1122 {
1123     // not if we're in design mode
1124     if ( !m_pView->IsDesignMode() )
1125         return nullptr;
1126 
1127     OUString sCommand, sFieldName;
1128     sal_Int32 nCommandType = CommandType::COMMAND;
1129     SharedConnection xConnection;
1130 
1131     OUString sDataSource = _rColumnDescriptor.getDataSource();
1132     _rColumnDescriptor[ DataAccessDescriptorProperty::Command ]     >>= sCommand;
1133     _rColumnDescriptor[ DataAccessDescriptorProperty::ColumnName ]  >>= sFieldName;
1134     _rColumnDescriptor[ DataAccessDescriptorProperty::CommandType ] >>= nCommandType;
1135     {
1136         Reference< XConnection > xExternalConnection;
1137         _rColumnDescriptor[ DataAccessDescriptorProperty::Connection ]  >>= xExternalConnection;
1138         xConnection.reset( xExternalConnection, SharedConnection::NoTakeOwnership );
1139     }
1140 
1141     if  (   sCommand.isEmpty()
1142         ||  sFieldName.isEmpty()
1143         ||  (   sDataSource.isEmpty()
1144             &&  !xConnection.is()
1145             )
1146         )
1147     {
1148         OSL_FAIL( "FmXFormView::implCreateFieldControl: nonsense!" );
1149     }
1150 
1151     Reference< XDataSource > xDataSource;
1152     SQLErrorEvent aError;
1153     try
1154     {
1155         if ( xConnection.is() && !xDataSource.is() && sDataSource.isEmpty() )
1156         {
1157             Reference< XChild > xChild( xConnection, UNO_QUERY );
1158             if ( xChild.is() )
1159                 xDataSource.set(xChild->getParent(), css::uno::UNO_QUERY);
1160         }
1161 
1162         // obtain the data source
1163         if ( !xDataSource.is() )
1164             xDataSource = getDataSource( sDataSource, comphelper::getProcessComponentContext() );
1165 
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             ) );
1175     }
1176     catch (const SQLException&)
1177     {
1178         aError.Reason = ::cppu::getCaughtException();
1179     }
1180     catch (const Exception& )
1181     {
1182         /* will be asserted below */
1183     }
1184     if (aError.Reason.hasValue())
1185     {
1186         displayAsyncErrorMessage( aError );
1187         return nullptr;
1188     }
1189 
1190     // need a data source and a connection here
1191     if (!xDataSource.is() || !xConnection.is())
1192     {
1193         OSL_FAIL("FmXFormView::implCreateFieldControl : could not retrieve the data source or the connection!");
1194         return nullptr;
1195     }
1196 
1197     Reference< XComponent > xKeepFieldsAlive;
1198     // go
1199     try
1200     {
1201         // determine the table/query field which we should create a control for
1202         Reference< XPropertySet >   xField;
1203 
1204         Reference< XNameAccess >    xFields = getFieldsByCommandDescriptor(
1205             xConnection, nCommandType, sCommand, xKeepFieldsAlive );
1206 
1207         if (xFields.is() && xFields->hasByName(sFieldName))
1208             xFields->getByName(sFieldName) >>= xField;
1209         if ( !xField.is() )
1210             return nullptr;
1211 
1212         Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( xConnection ), UNO_SET_THROW );
1213         Reference< XNumberFormats >  xNumberFormats( xSupplier->getNumberFormats(), UNO_SET_THROW );
1214 
1215         OUString sLabelPostfix;
1216 
1217 
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())
1225             {
1226                 // const SdrPageViewWinList& rWinList = pPageView->GetWinList();
1227                 // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows();
1228 
1229                 for( sal_uInt32 i = 0; i < pPageView->PageWindowCount(); i++ )
1230                 {
1231                     const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);
1232 
1233                     if( rPageWindow.GetPaintWindow().OutputToWindow())
1234                     {
1235                         pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice();
1236                         break;
1237                     }
1238                 }
1239             }
1240         }
1241 
1242         if ( !pOutDev )
1243             return nullptr;
1244 
1245         sal_Int32 nDataType = ::comphelper::getINT32(xField->getPropertyValue(FM_PROP_FIELDTYPE));
1246         if ((DataType::BINARY == nDataType) || (DataType::VARBINARY == nDataType))
1247             return nullptr;
1248 
1249 
1250         // determine the control type by examining the data type of the bound column
1251         sal_uInt16 nOBJID = 0;
1252         bool bDateNTimeField = false;
1253 
1254         bool bIsCurrency = false;
1255         if (::comphelper::hasProperty(FM_PROP_ISCURRENCY, xField))
1256             bIsCurrency = ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISCURRENCY));
1257 
1258         if (bIsCurrency)
1259             nOBJID = OBJ_FM_CURRENCYFIELD;
1260         else
1261             switch (nDataType)
1262             {
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;
1304             }
1305         if (!nOBJID)
1306             return nullptr;
1307 
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 )
1312             )
1313         {
1314             return nullptr;
1315         }
1316 
1317 
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());
1323 
1324         SdrObjGroup* pGroup  = new SdrObjGroup(getView()->getSdrModelFromSdrView());
1325         SdrObjList* pObjList = pGroup->GetSubList();
1326         pObjList->InsertObject( pLabel.release() );
1327         pObjList->InsertObject( pControl.release() );
1328 
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 )
1334                 )
1335             {
1336                 pObjList->InsertObject( pLabel.release() );
1337                 pObjList->InsertObject( pControl.release() );
1338             }
1339         }
1340 
1341         return SdrObjectUniquePtr(pGroup); // and done
1342     }
1343     catch (const Exception&)
1344     {
1345         DBG_UNHANDLED_EXCEPTION("svx");
1346     }
1347 
1348 
1349     return nullptr;
1350 }
1351 
1352 
implCreateXFormsControl(const svx::OXFormsDescriptor & _rDesc)1353 SdrObjectUniquePtr FmXFormView::implCreateXFormsControl( const svx::OXFormsDescriptor &_rDesc )
1354 {
1355     // not if we're in design mode
1356     if ( !m_pView->IsDesignMode() )
1357         return nullptr;
1358 
1359     // go
1360     try
1361     {
1362         // determine the table/query field which we should create a control for
1363         Reference< XNumberFormats > xNumberFormats;
1364         OUString sLabelPostfix = _rDesc.szName;
1365 
1366 
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())
1374             {
1375                 // const SdrPageViewWinList& rWinList = pPageView->GetWinList();
1376                 // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows();
1377 
1378                 for( sal_uInt32 i = 0; i < pPageView->PageWindowCount(); i++ )
1379                 {
1380                     const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);
1381 
1382                     if( rPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType() == OUTDEV_WINDOW)
1383                     {
1384                         pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice();
1385                         break;
1386                     }
1387                 }
1388             }
1389         }
1390 
1391         if ( !pOutDev )
1392             return nullptr;
1393 
1394 
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;
1403 
1404         Reference< css::form::submission::XSubmission > xSubmission(_rDesc.xPropSet, UNO_QUERY);
1405 
1406         // xform control or submission button?
1407         if ( !xSubmission.is() )
1408         {
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 )
1413                 )
1414             {
1415                 return nullptr;
1416             }
1417 
1418 
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);
1422 
1423             DBG_ASSERT( xBindableValue.is(), "FmXFormView::implCreateXFormsControl: control's not bindable!" );
1424             if ( xBindableValue.is() )
1425                 xBindableValue->setValueBinding(xValueBinding);
1426 
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());
1431 
1432 
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());
1438 
1439             return SdrObjectUniquePtr(pGroup);
1440         }
1441         else {
1442 
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);
1458 
1459             // set the button label
1460             Reference< XPropertySet > xControlSet(pControl->GetUnoControlModel(), UNO_QUERY);
1461             xControlSet->setPropertyValue(FM_PROP_LABEL, makeAny(_rDesc.szName));
1462 
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);
1468 
1469             return SdrObjectUniquePtr(pControl);
1470         }
1471     }
1472     catch (const Exception&)
1473     {
1474         OSL_FAIL("FmXFormView::implCreateXFormsControl: caught an exception while creating the control !");
1475     }
1476 
1477 
1478     return nullptr;
1479 }
1480 
1481 
createControlLabelPair(OutputDevice const & _rOutDev,sal_Int32 _nXOffsetMM,sal_Int32 _nYOffsetMM,const Reference<XPropertySet> & _rxField,const Reference<XNumberFormats> & _rxNumberFormats,sal_uInt16 _nControlObjectID,const OUString & _rFieldPostfix,std::unique_ptr<SdrUnoObj,SdrObjectFreeOp> & _rpLabel,std::unique_ptr<SdrUnoObj,SdrObjectFreeOp> & _rpControl,const Reference<XDataSource> & _rxDataSource,const OUString & _rDataSourceName,const OUString & _rCommand,const sal_Int32 _nCommandType)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 )
1489 {
1490     if(!createControlLabelPair(
1491         _rOutDev,
1492         _nXOffsetMM,
1493         _nYOffsetMM,
1494         _rxField,
1495         _rxNumberFormats,
1496         _nControlObjectID,
1497         _rFieldPostfix,
1498         SdrInventor::FmForm,
1499         OBJ_FM_FIXEDTEXT,
1500 
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(),
1505 
1506         _rpLabel,
1507         _rpControl))
1508     {
1509         return false;
1510     }
1511 
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 );
1516 
1517     // some context-dependent initializations
1518     FormControlFactory aControlFactory;
1519     if ( _rpLabel )
1520         aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpLabel );
1521     aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpControl );
1522 
1523     return true;
1524 }
1525 
1526 
createControlLabelPair(OutputDevice const & _rOutDev,sal_Int32 _nXOffsetMM,sal_Int32 _nYOffsetMM,const Reference<XPropertySet> & _rxField,const Reference<XNumberFormats> & _rxNumberFormats,sal_uInt16 _nControlObjectID,const OUString & _rFieldPostfix,SdrInventor _nInventor,sal_uInt16 _nLabelObjectID,SdrModel & _rModel,std::unique_ptr<SdrUnoObj,SdrObjectFreeOp> & _rpLabel,std::unique_ptr<SdrUnoObj,SdrObjectFreeOp> & _rpControl)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)
1533 {
1534     sal_Int32 nDataType = 0;
1535     OUString sFieldName;
1536     Any aFieldName;
1537     if ( _rxField.is() )
1538     {
1539         nDataType = ::comphelper::getINT32(_rxField->getPropertyValue(FM_PROP_FIELDTYPE));
1540         aFieldName = _rxField->getPropertyValue(FM_PROP_NAME);
1541         aFieldName >>= sFieldName;
1542     }
1543 
1544     // calculate the positions, respecting the settings of the target device
1545     ::Size aTextSize( _rOutDev.GetTextWidth(sFieldName + _rFieldPostfix), _rOutDev.GetTextHeight() );
1546 
1547     MapMode   eTargetMode( _rOutDev.GetMapMode() ),
1548               eSourceMode( MapUnit::Map100thMM );
1549 
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);
1555 
1556     ::Size aRealSize = OutputDevice::LogicToLogic(aTextSize, eTargetMode, eSourceMode);
1557     aRealSize.setWidth( std::max(aRealSize.Width(), aDefTxtSize.Width()) );
1558     aRealSize.setHeight( aDefSize.Height() );
1559 
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()) );
1563 
1564     // for boolean fields, we do not create a label, but just a checkbox
1565     bool bNeedLabel = ( _nControlObjectID != OBJ_FM_CHECKBOX );
1566 
1567     // the label
1568     ::std::unique_ptr< SdrUnoObj, SdrObjectFreeOp > pLabel;
1569     Reference< XPropertySet > xLabelModel;
1570 
1571     if ( bNeedLabel )
1572     {
1573         pLabel.reset( dynamic_cast< SdrUnoObj* >(
1574             SdrObjFactory::MakeNewObject(
1575                 _rModel,
1576                 _nInventor,
1577                 _nLabelObjectID)));
1578 
1579         OSL_ENSURE(pLabel, "FmXFormView::createControlLabelPair: could not create the label!");
1580 
1581         if (!pLabel)
1582             return false;
1583 
1584         xLabelModel.set( pLabel->GetUnoControlModel(), UNO_QUERY );
1585         if ( xLabelModel.is() )
1586         {
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;
1592 
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));
1596         }
1597 
1598         pLabel->SetLogicRect( ::tools::Rectangle(
1599             OutputDevice::LogicToLogic( ::Point( _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ),
1600             OutputDevice::LogicToLogic( aRealSize, eSourceMode, eTargetMode )
1601         ) );
1602     }
1603 
1604     // the control
1605     ::std::unique_ptr< SdrUnoObj, SdrObjectFreeOp > pControl( dynamic_cast< SdrUnoObj* >(
1606         SdrObjFactory::MakeNewObject(
1607             _rModel,
1608              _nInventor,
1609              _nControlObjectID)));
1610 
1611     OSL_ENSURE(pControl, "FmXFormView::createControlLabelPair: could not create the control!");
1612 
1613     if (!pControl)
1614         return false;
1615 
1616     Reference< XPropertySet > xControlSet( pControl->GetUnoControlModel(), UNO_QUERY );
1617     if ( !xControlSet.is() )
1618         return false;
1619 
1620     // size of the control
1621     ::Size aControlSize( aDefSize );
1622     switch ( nDataType )
1623     {
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;
1634     }
1635 
1636     if ( OBJ_FM_IMAGECONTROL == _nControlObjectID )
1637         aControlSize = aDefImageSize;
1638 
1639     aControlSize.setWidth( long(Fraction(aControlSize.Width(), 1) * eTargetMode.GetScaleX()) );
1640     aControlSize.setHeight( long(Fraction(aControlSize.Height(), 1) * eTargetMode.GetScaleY()) );
1641 
1642     pControl->SetLogicRect( ::tools::Rectangle(
1643         OutputDevice::LogicToLogic( ::Point( aRealSize.Width() + _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ),
1644         OutputDevice::LogicToLogic( aControlSize, eSourceMode, eTargetMode )
1645     ) );
1646 
1647     // some initializations
1648     Reference< XPropertySetInfo > xControlPropInfo = xControlSet->getPropertySetInfo();
1649 
1650     if ( aFieldName.hasValue() )
1651     {
1652         xControlSet->setPropertyValue( FM_PROP_CONTROLSOURCE, aFieldName );
1653         xControlSet->setPropertyValue( FM_PROP_NAME, aFieldName );
1654         if ( !bNeedLabel )
1655         {
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!" );
1661         }
1662     }
1663 
1664     if ( (nDataType == DataType::LONGVARCHAR || nDataType == DataType::CLOB) && xControlPropInfo->hasPropertyByName( FM_PROP_MULTILINE ) )
1665     {
1666         xControlSet->setPropertyValue( FM_PROP_MULTILINE, makeAny( true ) );
1667     }
1668 
1669     // announce the label to the control
1670     if ( xControlPropInfo->hasPropertyByName( FM_PROP_CONTROLLABEL ) && xLabelModel.is() )
1671     {
1672         try
1673         {
1674             xControlSet->setPropertyValue( FM_PROP_CONTROLLABEL, makeAny( xLabelModel ) );
1675         }
1676         catch (const Exception&)
1677         {
1678             DBG_UNHANDLED_EXCEPTION("svx");
1679         }
1680     }
1681 
1682     if ( _rxField.is() )
1683     {
1684         FormControlFactory::initializeFieldDependentProperties( _rxField, xControlSet, _rxNumberFormats );
1685     }
1686 
1687     _rpLabel = std::move(pLabel);
1688     _rpControl = std::move(pControl);
1689     return true;
1690 }
1691 
1692 
ObjectRemoveListener(FmXFormView * pParent)1693 FmXFormView::ObjectRemoveListener::ObjectRemoveListener( FmXFormView* pParent )
1694     :m_pParent( pParent )
1695 {
1696 }
1697 
1698 
Notify(SfxBroadcaster &,const SfxHint & rHint)1699 void FmXFormView::ObjectRemoveListener::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
1700 {
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());
1706 }
1707 
1708 
ObjectRemovedInAliveMode(const SdrObject * pObject)1709 void FmXFormView::ObjectRemovedInAliveMode( const SdrObject* pObject )
1710 {
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)
1715 
1716     const size_t nCount = m_aMark.GetMarkCount();
1717     for (size_t i = 0; i < nCount; ++i)
1718     {
1719         SdrMark* pMark = m_aMark.GetMark(i);
1720         SdrObject* pCurrent = pMark->GetMarkedSdrObj();
1721         if (pObject == pCurrent)
1722         {
1723             m_aMark.DeleteMark(i);
1724             return;
1725         }
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 ...
1728     }
1729 }
1730 
1731 
stopMarkListWatching()1732 void FmXFormView::stopMarkListWatching()
1733 {
1734     if ( m_pWatchStoredList )
1735     {
1736         m_pWatchStoredList->EndListeningAll();
1737         m_pWatchStoredList.reset();
1738     }
1739 }
1740 
1741 
startMarkListWatching()1742 void FmXFormView::startMarkListWatching()
1743 {
1744     if ( !m_pWatchStoredList )
1745     {
1746         FmFormModel* pModel = GetFormShell() ? GetFormShell()->GetFormModel() : nullptr;
1747         DBG_ASSERT( pModel != nullptr, "FmXFormView::startMarkListWatching: shell has no model!" );
1748         if (pModel)
1749         {
1750             m_pWatchStoredList.reset(new ObjectRemoveListener( this ));
1751             m_pWatchStoredList->StartListening( *static_cast< SfxBroadcaster* >( pModel ) );
1752         }
1753     }
1754     else
1755     {
1756         OSL_FAIL( "FmXFormView::startMarkListWatching: already listening!" );
1757     }
1758 }
1759 
saveMarkList()1760 void FmXFormView::saveMarkList()
1761 {
1762     if ( m_pView )
1763     {
1764         m_aMark = m_pView->GetMarkedObjectList();
1765         const size_t nCount = m_aMark.GetMarkCount( );
1766         for ( size_t i = 0; i < nCount; ++i )
1767         {
1768             SdrMark*   pMark = m_aMark.GetMark(i);
1769             SdrObject* pObj  = pMark->GetMarkedSdrObj();
1770 
1771             if ( m_pView->IsObjMarked( pObj ) )
1772             {
1773                 if ( pObj->IsGroupObject() )
1774                 {
1775                     SdrObjListIter aIter( pObj->GetSubList() );
1776                     bool bMixed = false;
1777                     while ( aIter.IsMore() && !bMixed )
1778                         bMixed = ( aIter.Next()->GetObjInventor() != SdrInventor::FmForm );
1779 
1780                     if ( !bMixed )
1781                     {
1782                         // all objects in the group are form objects
1783                         m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), true /* unmark! */ );
1784                     }
1785                 }
1786                 else
1787                 {
1788                     if ( pObj->GetObjInventor() == SdrInventor::FmForm )
1789                     {   // this is a form layer object
1790                         m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), true /* unmark! */ );
1791                     }
1792                 }
1793             }
1794         }
1795     }
1796     else
1797     {
1798         OSL_FAIL( "FmXFormView::saveMarkList: invalid view!" );
1799         m_aMark.Clear();
1800     }
1801 }
1802 
lcl_hasObject(SdrObjListIter & rIter,SdrObject const * pObj)1803 static bool lcl_hasObject( SdrObjListIter& rIter, SdrObject const * pObj )
1804 {
1805     bool bFound = false;
1806     while (rIter.IsMore() && !bFound)
1807         bFound = pObj == rIter.Next();
1808 
1809     rIter.Reset();
1810     return bFound;
1811 }
1812 
1813 
restoreMarkList(SdrMarkList & _rRestoredMarkList)1814 void FmXFormView::restoreMarkList( SdrMarkList& _rRestoredMarkList )
1815 {
1816     if ( !m_pView )
1817         return;
1818 
1819     _rRestoredMarkList.Clear();
1820 
1821     const SdrMarkList& rCurrentList = m_pView->GetMarkedObjectList();
1822     FmFormPage* pPage = GetFormShell() ? GetFormShell()->GetCurPage() : nullptr;
1823     if (pPage)
1824     {
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;
1828 
1829             // loop through all current marks
1830             const size_t nCurrentCount = rCurrentList.GetMarkCount();
1831             for ( size_t i=0; i<nCurrentCount && !bMisMatch; ++i )
1832             {
1833                 const SdrObject* pCurrentMarked = rCurrentList.GetMark( i )->GetMarkedSdrObj();
1834 
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 )
1839                 {
1840                     if ( m_aMark.GetMark( j )->GetMarkedSdrObj() == pCurrentMarked )
1841                         bFound = true;
1842                 }
1843 
1844                 // did not find a current mark in the saved marks
1845                 if ( !bFound )
1846                     bMisMatch = true;
1847             }
1848 
1849             if ( bMisMatch )
1850             {
1851                 m_aMark.Clear();
1852                 _rRestoredMarkList = rCurrentList;
1853                 return;
1854             }
1855         }
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;
1861 
1862         // do all objects still exist
1863         const size_t nCount = m_aMark.GetMarkCount();
1864         for (size_t i = 0; i < nCount && bFound; ++i)
1865         {
1866             SdrMark*   pMark = m_aMark.GetMark(i);
1867             SdrObject* pObj  = pMark->GetMarkedSdrObj();
1868             if (pObj->IsGroupObject())
1869             {
1870                 SdrObjListIter aIter(pObj->GetSubList());
1871                 while (aIter.IsMore() && bFound)
1872                     bFound = lcl_hasObject(aPageIter, aIter.Next());
1873             }
1874             else
1875                 bFound = lcl_hasObject(aPageIter, pObj);
1876 
1877             bFound = bFound && pCurPageView == pMark->GetPageView();
1878         }
1879 
1880         if (bFound)
1881         {
1882             // evaluate the LastObject
1883             if (nCount) // now mark the objects
1884             {
1885                 for (size_t i = 0; i < nCount; ++i)
1886                 {
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() );
1892                 }
1893 
1894                 _rRestoredMarkList = m_aMark;
1895             }
1896         }
1897         m_aMark.Clear();
1898     }
1899 }
1900 
focusGained(const FocusEvent &)1901 void SAL_CALL FmXFormView::focusGained( const FocusEvent& /*e*/ )
1902 {
1903     if ( m_xWindow.is() && m_pView )
1904     {
1905         m_pView->SetMoveOutside( true, FmFormView::ImplAccess() );
1906     }
1907 }
1908 
focusLost(const FocusEvent &)1909 void SAL_CALL FmXFormView::focusLost( const FocusEvent& /*e*/ )
1910 {
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 )
1914     {
1915         m_pView->SetMoveOutside( false, FmFormView::ImplAccess() );
1916     }
1917 }
1918 
impl_getDocumentType() const1919 DocumentType FmXFormView::impl_getDocumentType() const
1920 {
1921     if ( GetFormShell() && GetFormShell()->GetImpl() )
1922         return GetFormShell()->GetImpl()->getDocumentType_Lock();
1923     return eUnknownDocumentType;
1924 }
1925 
1926 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1927