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 <fmvwimp.hxx>
31 #include <formcontrolfactory.hxx>
32 #include <svx/sdrpaintwindow.hxx>
33 #include <svx/svditer.hxx>
34 #include <svx/dataaccessdescriptor.hxx>
35 #include <svx/dialmgr.hxx>
36 #include <svx/svdobjkind.hxx>
37 #include <svx/fmmodel.hxx>
38 #include <svx/fmpage.hxx>
39 #include <svx/fmshell.hxx>
40 #include <svx/fmview.hxx>
41 #include <svx/sdrpagewindow.hxx>
42 #include <svx/svdogrp.hxx>
43 #include <svx/svdpagv.hxx>
44 #include <svx/xmlexchg.hxx>
45 #include <toolkit/helper/vclunohelper.hxx>
46 
47 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
48 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
49 #include <com/sun/star/sdbc/XRowSet.hpp>
50 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
51 #include <com/sun/star/util/XNumberFormats.hpp>
52 #include <com/sun/star/sdb/CommandType.hpp>
53 #include <com/sun/star/sdbc/DataType.hpp>
54 #include <com/sun/star/form/FormComponentType.hpp>
55 #include <com/sun/star/form/FormButtonType.hpp>
56 #include <com/sun/star/form/binding/XBindableValue.hpp>
57 #include <com/sun/star/form/binding/XValueBinding.hpp>
58 #include <com/sun/star/form/runtime/FormController.hpp>
59 #include <com/sun/star/form/submission/XSubmissionSupplier.hpp>
60 #include <com/sun/star/awt/XTabControllerModel.hpp>
61 #include <com/sun/star/awt/XControlContainer.hpp>
62 #include <com/sun/star/awt/XTabController.hpp>
63 #include <com/sun/star/container/XIndexAccess.hpp>
64 #include <com/sun/star/awt/XControl.hpp>
65 #include <com/sun/star/sdbc/SQLException.hpp>
66 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
67 #include <com/sun/star/container/XContainer.hpp>
68 
69 #include <comphelper/namedvaluecollection.hxx>
70 #include <comphelper/property.hxx>
71 #include <comphelper/processfactory.hxx>
72 #include <comphelper/types.hxx>
73 #include <cppuhelper/exc_hlp.hxx>
74 #include <unotools/moduleoptions.hxx>
75 #include <tools/debug.hxx>
76 #include <tools/diagnose_ex.h>
77 #include <sal/log.hxx>
78 #include <vcl/svapp.hxx>
79 #include <vcl/stdtext.hxx>
80 #include <vcl/window.hxx>
81 #include <connectivity/dbtools.hxx>
82 
83 #include <algorithm>
84 
85 using namespace ::comphelper;
86 using namespace ::svx;
87 using namespace ::svxform;
88 using namespace ::dbtools;
89 
90     using namespace ::com::sun::star;
91     using ::com::sun::star::uno::Exception;
92     using ::com::sun::star::uno::XInterface;
93     using ::com::sun::star::uno::Sequence;
94     using ::com::sun::star::uno::UNO_QUERY;
95     using ::com::sun::star::uno::UNO_QUERY_THROW;
96     using ::com::sun::star::uno::UNO_SET_THROW;
97     using ::com::sun::star::uno::Type;
98     using ::com::sun::star::uno::Reference;
99     using ::com::sun::star::uno::Any;
100     using ::com::sun::star::uno::makeAny;
101     using ::com::sun::star::uno::XComponentContext;
102     using ::com::sun::star::form::FormButtonType_SUBMIT;
103     using ::com::sun::star::form::binding::XValueBinding;
104     using ::com::sun::star::form::binding::XBindableValue;
105     using ::com::sun::star::lang::XComponent;
106     using ::com::sun::star::container::XIndexAccess;
107     using ::com::sun::star::form::runtime::FormController;
108     using ::com::sun::star::form::runtime::XFormController;
109     using ::com::sun::star::script::XEventAttacherManager;
110     using ::com::sun::star::awt::XTabControllerModel;
111     using ::com::sun::star::container::XChild;
112     using ::com::sun::star::task::XInteractionHandler;
113     using ::com::sun::star::awt::XTabController;
114     using ::com::sun::star::awt::XControlContainer;
115     using ::com::sun::star::awt::XControl;
116     using ::com::sun::star::form::XFormComponent;
117     using ::com::sun::star::form::XForm;
118     using ::com::sun::star::lang::IndexOutOfBoundsException;
119     using ::com::sun::star::container::XContainer;
120     using ::com::sun::star::container::ContainerEvent;
121     using ::com::sun::star::lang::EventObject;
122     using ::com::sun::star::sdb::SQLErrorEvent;
123     using ::com::sun::star::sdbc::XRowSet;
124     using ::com::sun::star::beans::XPropertySet;
125     using ::com::sun::star::container::XElementAccess;
126     using ::com::sun::star::awt::XWindow;
127     using ::com::sun::star::awt::FocusEvent;
128     using ::com::sun::star::ui::dialogs::XExecutableDialog;
129     using ::com::sun::star::sdbc::XDataSource;
130     using ::com::sun::star::container::XIndexContainer;
131     using ::com::sun::star::sdbc::XConnection;
132     using ::com::sun::star::container::XNameAccess;
133     using ::com::sun::star::sdbc::SQLException;
134     using ::com::sun::star::util::XNumberFormatsSupplier;
135     using ::com::sun::star::util::XNumberFormats;
136     using ::com::sun::star::beans::XPropertySetInfo;
137 
138     namespace FormComponentType = ::com::sun::star::form::FormComponentType;
139     namespace CommandType = ::com::sun::star::sdb::CommandType;
140     namespace DataType = ::com::sun::star::sdbc::DataType;
141 
142 
143 class FmXFormView::ObjectRemoveListener : public SfxListener
144 {
145     FmXFormView* m_pParent;
146 public:
147     explicit ObjectRemoveListener( FmXFormView* pParent );
148     virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
149 };
150 
FormViewPageWindowAdapter(const css::uno::Reference<css::uno::XComponentContext> & _rContext,const SdrPageWindow & _rWindow,FmXFormView * _pViewImpl)151 FormViewPageWindowAdapter::FormViewPageWindowAdapter( const css::uno::Reference<css::uno::XComponentContext>& _rContext, const SdrPageWindow& _rWindow, FmXFormView* _pViewImpl )
152 :   m_xControlContainer( _rWindow.GetControlContainer() ),
153     m_xContext( _rContext ),
154     m_pViewImpl( _pViewImpl ),
155     m_pWindow( _rWindow.GetPaintWindow().GetOutputDevice().GetOwnerWindow() )
156 {
157 
158     // create an XFormController for every form
159     FmFormPage* pFormPage = dynamic_cast< FmFormPage* >( _rWindow.GetPageView().GetPage() );
160     DBG_ASSERT( pFormPage, "FormViewPageWindowAdapter::FormViewPageWindowAdapter: no FmFormPage found!" );
161     if ( !pFormPage )
162         return;
163 
164     try
165     {
166         Reference< XIndexAccess > xForms( pFormPage->GetForms(), UNO_QUERY_THROW );
167         sal_uInt32 nLength = xForms->getCount();
168         for (sal_uInt32 i = 0; i < nLength; i++)
169         {
170             Reference< XForm > xForm( xForms->getByIndex(i), UNO_QUERY );
171             if ( xForm.is() )
172                 setController( xForm, nullptr );
173         }
174     }
175     catch (const Exception&)
176     {
177         DBG_UNHANDLED_EXCEPTION("svx");
178     }
179 }
180 
~FormViewPageWindowAdapter()181 FormViewPageWindowAdapter::~FormViewPageWindowAdapter()
182 {
183 }
184 
dispose()185 void FormViewPageWindowAdapter::dispose()
186 {
187     for (   ::std::vector< Reference< XFormController > >::const_iterator i = m_aControllerList.begin();
188             i != m_aControllerList.end();
189             ++i
190         )
191     {
192         try
193         {
194             Reference< XFormController > xController( *i, UNO_SET_THROW );
195 
196             // detaching the events
197             Reference< XChild > xControllerModel( xController->getModel(), UNO_QUERY );
198             if ( xControllerModel.is() )
199             {
200                 Reference< XEventAttacherManager >  xEventManager( xControllerModel->getParent(), UNO_QUERY_THROW );
201                 Reference< XInterface > xControllerNormalized( xController, UNO_QUERY_THROW );
202                 xEventManager->detach( i - m_aControllerList.begin(), xControllerNormalized );
203             }
204 
205             // dispose the formcontroller
206             xController->dispose();
207         }
208         catch (const Exception&)
209         {
210             DBG_UNHANDLED_EXCEPTION("svx");
211         }
212     }
213 
214     m_aControllerList.clear();
215 }
216 
hasElements()217 sal_Bool SAL_CALL FormViewPageWindowAdapter::hasElements()
218 {
219     return getCount() != 0;
220 }
221 
getElementType()222 Type SAL_CALL  FormViewPageWindowAdapter::getElementType()
223 {
224     return cppu::UnoType<XFormController>::get();
225 }
226 
227 // XIndexAccess
getCount()228 sal_Int32 SAL_CALL FormViewPageWindowAdapter::getCount()
229 {
230     return m_aControllerList.size();
231 }
232 
getByIndex(sal_Int32 nIndex)233 Any SAL_CALL FormViewPageWindowAdapter::getByIndex(sal_Int32 nIndex)
234 {
235     if (nIndex < 0 ||
236         nIndex >= getCount())
237         throw IndexOutOfBoundsException();
238 
239     Any aElement;
240     aElement <<= m_aControllerList[nIndex];
241     return aElement;
242 }
243 
makeVisible(const Reference<XControl> & Control)244 void SAL_CALL FormViewPageWindowAdapter::makeVisible( const Reference< XControl >& Control )
245 {
246     SolarMutexGuard aSolarGuard;
247 
248     Reference< XWindow >  xWindow( Control, UNO_QUERY );
249     if ( xWindow.is() && m_pViewImpl->getView() && m_pWindow )
250     {
251         awt::Rectangle aRect = xWindow->getPosSize();
252         ::tools::Rectangle aNewRect( aRect.X, aRect.Y, aRect.X + aRect.Width, aRect.Y + aRect.Height );
253         aNewRect = m_pWindow->PixelToLogic( aNewRect );
254         m_pViewImpl->getView()->MakeVisible( aNewRect, *m_pWindow );
255     }
256 }
257 
getControllerSearchChildren(const Reference<XIndexAccess> & xIndex,const Reference<XTabControllerModel> & xModel)258 static Reference< XFormController >  getControllerSearchChildren( const Reference< XIndexAccess > & xIndex, const Reference< XTabControllerModel > & xModel)
259 {
260     if (xIndex.is() && xIndex->getCount())
261     {
262         Reference< XFormController >  xController;
263 
264         for (sal_Int32 n = xIndex->getCount(); n-- && !xController.is(); )
265         {
266             xIndex->getByIndex(n) >>= xController;
267             if (xModel.get() == xController->getModel().get())
268                 return xController;
269             else
270             {
271                 xController = getControllerSearchChildren(xController, xModel);
272                 if ( xController.is() )
273                     return xController;
274             }
275         }
276     }
277     return Reference< XFormController > ();
278 }
279 
280 // Search the according controller
getController(const Reference<XForm> & xForm) const281 Reference< XFormController >  FormViewPageWindowAdapter::getController( const Reference< XForm > & xForm ) const
282 {
283     Reference< XTabControllerModel >  xModel(xForm, UNO_QUERY);
284     for (const auto& rpController : m_aControllerList)
285     {
286         if (rpController->getModel().get() == xModel.get())
287             return rpController;
288 
289         // the current-round controller isn't the right one. perhaps one of its children ?
290         Reference< XFormController >  xChildSearch = getControllerSearchChildren(Reference< XIndexAccess > (rpController, UNO_QUERY), xModel);
291         if (xChildSearch.is())
292             return xChildSearch;
293     }
294     return Reference< XFormController > ();
295 }
296 
297 
setController(const Reference<XForm> & xForm,const Reference<XFormController> & _rxParentController)298 void FormViewPageWindowAdapter::setController(const Reference< XForm > & xForm, const Reference< XFormController >& _rxParentController )
299 {
300     DBG_ASSERT( xForm.is(), "FormViewPageWindowAdapter::setController: there should be a form!" );
301     Reference< XIndexAccess >  xFormCps(xForm, UNO_QUERY);
302     if (!xFormCps.is())
303         return;
304 
305     Reference< XTabControllerModel >  xTabOrder(xForm, UNO_QUERY);
306 
307     // create a form controller
308     Reference< XFormController > xController( FormController::create(m_xContext) );
309 
310     Reference< XInteractionHandler > xHandler;
311     if ( _rxParentController.is() )
312         xHandler = _rxParentController->getInteractionHandler();
313     else
314     {
315         // TODO: should we create a default handler? Not really necessary, since the
316         // FormController itself has a default fallback
317     }
318     if ( xHandler.is() )
319         xController->setInteractionHandler( xHandler );
320 
321     xController->setContext( this );
322 
323     xController->setModel( xTabOrder );
324     xController->setContainer( m_xControlContainer );
325     xController->activateTabOrder();
326     xController->addActivateListener( m_pViewImpl );
327 
328     if ( _rxParentController.is() )
329         _rxParentController->addChildController( xController );
330     else
331     {
332         m_aControllerList.push_back(xController);
333 
334         xController->setParent( *this );
335 
336         // attaching the events
337         Reference< XEventAttacherManager > xEventManager( xForm->getParent(), UNO_QUERY );
338         xEventManager->attach(m_aControllerList.size() - 1, Reference<XInterface>( xController, UNO_QUERY ), makeAny(xController) );
339     }
340 
341     // now go through the subforms
342     sal_uInt32 nLength = xFormCps->getCount();
343     Reference< XForm >  xSubForm;
344     for (sal_uInt32 i = 0; i < nLength; i++)
345     {
346         if ( xFormCps->getByIndex(i) >>= xSubForm )
347             setController( xSubForm, xController );
348     }
349 }
350 
351 
updateTabOrder(const Reference<XForm> & _rxForm)352 void FormViewPageWindowAdapter::updateTabOrder( const Reference< XForm >& _rxForm )
353 {
354     OSL_PRECOND( _rxForm.is(), "FormViewPageWindowAdapter::updateTabOrder: illegal argument!" );
355     if ( !_rxForm.is() )
356         return;
357 
358     try
359     {
360         Reference< XTabController > xTabCtrl( getController( _rxForm ) );
361         if ( xTabCtrl.is() )
362         {   // if there already is a TabController for this form, then delegate the "updateTabOrder" request
363             xTabCtrl->activateTabOrder();
364         }
365         else
366         {   // otherwise, create a TabController
367 
368             // if it's a sub form, then we must ensure there exist TabControllers
369             // for all its ancestors, too
370             Reference< XForm > xParentForm( _rxForm->getParent(), UNO_QUERY );
371             // there is a parent form -> look for the respective controller
372             Reference< XFormController > xParentController;
373             if ( xParentForm.is() )
374                 xParentController = getController( xParentForm );
375 
376             setController( _rxForm, xParentController );
377         }
378     }
379     catch (const Exception&)
380     {
381         DBG_UNHANDLED_EXCEPTION("svx");
382     }
383 }
384 
385 
FmXFormView(FmFormView * _pView)386 FmXFormView::FmXFormView(FmFormView* _pView )
387     :m_pMarkedGrid(nullptr)
388     ,m_pView(_pView)
389     ,m_nActivationEvent(nullptr)
390     ,m_nErrorMessageEvent( nullptr )
391     ,m_nAutoFocusEvent( nullptr )
392     ,m_nControlWizardEvent( nullptr )
393     ,m_bFirstActivation( true )
394     ,m_isTabOrderUpdateSuspended( false )
395 {
396 }
397 
398 
cancelEvents()399 void FmXFormView::cancelEvents()
400 {
401     if ( m_nActivationEvent )
402     {
403         Application::RemoveUserEvent( m_nActivationEvent );
404         m_nActivationEvent = nullptr;
405     }
406 
407     if ( m_nErrorMessageEvent )
408     {
409         Application::RemoveUserEvent( m_nErrorMessageEvent );
410         m_nErrorMessageEvent = nullptr;
411     }
412 
413     if ( m_nAutoFocusEvent )
414     {
415         Application::RemoveUserEvent( m_nAutoFocusEvent );
416         m_nAutoFocusEvent = nullptr;
417     }
418 
419     if ( m_nControlWizardEvent )
420     {
421         Application::RemoveUserEvent( m_nControlWizardEvent );
422         m_nControlWizardEvent = nullptr;
423     }
424 }
425 
426 
notifyViewDying()427 void FmXFormView::notifyViewDying( )
428 {
429     DBG_ASSERT( m_pView, "FmXFormView::notifyViewDying: my view already died!" );
430     m_pView = nullptr;
431     cancelEvents();
432 }
433 
434 
~FmXFormView()435 FmXFormView::~FmXFormView()
436 {
437     DBG_ASSERT( m_aPageWindowAdapters.empty(), "FmXFormView::~FmXFormView: Window list not empty!" );
438     for (const auto& rpAdapter : m_aPageWindowAdapters)
439     {
440         rpAdapter->dispose();
441     }
442 
443     cancelEvents();
444 }
445 
446 //      EventListener
447 
disposing(const EventObject & Source)448 void SAL_CALL FmXFormView::disposing(const EventObject& Source)
449 {
450     if ( m_xWindow.is() && Source.Source == m_xWindow )
451     {
452         m_xWindow->removeFocusListener(this);
453         if ( m_pView )
454         {
455             m_pView->SetMoveOutside( false, FmFormView::ImplAccess() );
456         }
457         m_xWindow = nullptr;
458     }
459 }
460 
461 // XFormControllerListener
462 
formActivated(const EventObject & rEvent)463 void SAL_CALL FmXFormView::formActivated(const EventObject& rEvent)
464 {
465     if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() )
466         m_pView->GetFormShell()->GetImpl()->formActivated( rEvent );
467 }
468 
469 
formDeactivated(const EventObject & rEvent)470 void SAL_CALL FmXFormView::formDeactivated(const EventObject& rEvent)
471 {
472     if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() )
473         m_pView->GetFormShell()->GetImpl()->formDeactivated( rEvent );
474 }
475 
476 // XContainerListener
477 
elementInserted(const ContainerEvent & evt)478 void SAL_CALL FmXFormView::elementInserted(const ContainerEvent& evt)
479 {
480     try
481     {
482         Reference< XControlContainer > xControlContainer( evt.Source, UNO_QUERY_THROW );
483         Reference< XControl > xControl( evt.Element, UNO_QUERY_THROW );
484         Reference< XFormComponent > xControlModel( xControl->getModel(), UNO_QUERY_THROW );
485         Reference< XForm > xForm( xControlModel->getParent(), UNO_QUERY_THROW );
486 
487         if ( m_isTabOrderUpdateSuspended )
488         {
489             // remember the container and the control, so we can update the tab order on resumeTabOrderUpdate
490             m_aNeedTabOrderUpdate[ xControlContainer ].insert( xForm );
491         }
492         else
493         {
494             rtl::Reference< FormViewPageWindowAdapter > pAdapter = findWindow( xControlContainer );
495             if ( pAdapter.is() )
496                 pAdapter->updateTabOrder( xForm );
497         }
498     }
499     catch (const Exception&)
500     {
501         DBG_UNHANDLED_EXCEPTION("svx");
502     }
503 }
504 
505 
elementReplaced(const ContainerEvent & evt)506 void SAL_CALL FmXFormView::elementReplaced(const ContainerEvent& evt)
507 {
508     elementInserted(evt);
509 }
510 
511 
elementRemoved(const ContainerEvent &)512 void SAL_CALL FmXFormView::elementRemoved(const ContainerEvent& /*evt*/)
513 {
514 }
515 
516 
findWindow(const Reference<XControlContainer> & _rxCC) const517 rtl::Reference< FormViewPageWindowAdapter > FmXFormView::findWindow( const Reference< XControlContainer >& _rxCC )  const
518 {
519     auto i = std::find_if(m_aPageWindowAdapters.begin(), m_aPageWindowAdapters.end(),
520         [&_rxCC](const rtl::Reference< FormViewPageWindowAdapter >& rpAdapter) { return _rxCC == rpAdapter->getControlContainer(); });
521     if (i != m_aPageWindowAdapters.end())
522         return *i;
523     return nullptr;
524 }
525 
526 
addWindow(const SdrPageWindow & rWindow)527 void FmXFormView::addWindow(const SdrPageWindow& rWindow)
528 {
529     FmFormPage* pFormPage = dynamic_cast<FmFormPage*>( rWindow.GetPageView().GetPage()  );
530     if ( !pFormPage )
531         return;
532 
533     const Reference< XControlContainer >& xCC = rWindow.GetControlContainer();
534     if  (   xCC.is()
535         &&  ( !findWindow( xCC ).is() )
536         )
537     {
538         rtl::Reference< FormViewPageWindowAdapter > pAdapter = new FormViewPageWindowAdapter( comphelper::getProcessComponentContext(), rWindow, this );
539         m_aPageWindowAdapters.push_back( pAdapter );
540 
541         // listen at the ControlContainer to notice changes
542         Reference< XContainer >  xContainer( xCC, UNO_QUERY );
543         if ( xContainer.is() )
544             xContainer->addContainerListener( this );
545     }
546 }
547 
548 
removeWindow(const Reference<XControlContainer> & _rxCC)549 void FmXFormView::removeWindow( const Reference< XControlContainer >& _rxCC )
550 {
551     // Is called if
552     // - the design mode is being switched to
553     // - a window is deleted while in the design mode
554     // - the control container for a window is removed while the active mode is on
555 
556     auto i = std::find_if(m_aPageWindowAdapters.begin(), m_aPageWindowAdapters.end(),
557         [&_rxCC](const rtl::Reference< FormViewPageWindowAdapter >& rpAdapter) { return _rxCC == rpAdapter->getControlContainer(); });
558     if (i != m_aPageWindowAdapters.end())
559     {
560         Reference< XContainer >  xContainer( _rxCC, UNO_QUERY );
561         if ( xContainer.is() )
562             xContainer->removeContainerListener( this );
563 
564         (*i)->dispose();
565         m_aPageWindowAdapters.erase( i );
566     }
567 }
568 
displayAsyncErrorMessage(const SQLErrorEvent & _rEvent)569 void FmXFormView::displayAsyncErrorMessage( const SQLErrorEvent& _rEvent )
570 {
571     DBG_ASSERT( nullptr == m_nErrorMessageEvent, "FmXFormView::displayAsyncErrorMessage: not too fast, please!" );
572         // This should not happen - usually, the PostUserEvent is faster than any possible user
573         // interaction which could trigger a new error. If it happens, we need a queue for the events.
574     m_aAsyncError = _rEvent;
575     m_nErrorMessageEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnDelayedErrorMessage ) );
576 }
577 
IMPL_LINK_NOARG(FmXFormView,OnDelayedErrorMessage,void *,void)578 IMPL_LINK_NOARG(FmXFormView, OnDelayedErrorMessage, void*, void)
579 {
580     m_nErrorMessageEvent = nullptr;
581     displayException(m_aAsyncError, GetParentWindow());
582 }
583 
onFirstViewActivation(const FmFormModel * _pDocModel)584 void FmXFormView::onFirstViewActivation( const FmFormModel* _pDocModel )
585 {
586     if ( _pDocModel && _pDocModel->GetAutoControlFocus() )
587         m_nAutoFocusEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnAutoFocus ) );
588 }
589 
suspendTabOrderUpdate()590 void FmXFormView::suspendTabOrderUpdate()
591 {
592     OSL_ENSURE( !m_isTabOrderUpdateSuspended, "FmXFormView::suspendTabOrderUpdate: nesting not allowed!" );
593     m_isTabOrderUpdateSuspended = true;
594 }
595 
resumeTabOrderUpdate()596 void FmXFormView::resumeTabOrderUpdate()
597 {
598     OSL_ENSURE( m_isTabOrderUpdateSuspended, "FmXFormView::resumeTabOrderUpdate: not suspended!" );
599     m_isTabOrderUpdateSuspended = false;
600 
601     // update the tab orders for all components which were collected since the suspendTabOrderUpdate call.
602     for (const auto& rContainer : m_aNeedTabOrderUpdate)
603     {
604         rtl::Reference< FormViewPageWindowAdapter > pAdapter = findWindow( rContainer.first );
605         if ( !pAdapter.is() )
606             continue;
607 
608         for (const auto& rForm : rContainer.second)
609         {
610             pAdapter->updateTabOrder( rForm );
611         }
612     }
613     m_aNeedTabOrderUpdate.clear();
614 }
615 
616 namespace
617 {
isActivableDatabaseForm(const Reference<XFormController> & xController)618     bool isActivableDatabaseForm(const Reference< XFormController > &xController)
619     {
620         // only database forms are to be activated
621         Reference< XRowSet >  xForm(xController->getModel(), UNO_QUERY);
622         if ( !xForm.is() || !getConnection( xForm ).is() )
623             return false;
624 
625         Reference< XPropertySet > xFormSet( xForm, UNO_QUERY );
626         if ( !xFormSet.is() )
627         {
628             SAL_WARN( "svx.form", "FmXFormView::OnActivate: a form which does not have properties?" );
629             return false;
630         }
631 
632         const OUString aSource = ::comphelper::getString( xFormSet->getPropertyValue( FM_PROP_COMMAND ) );
633 
634         return !aSource.isEmpty();
635     }
636 
637     class find_active_databaseform
638     {
639         const Reference< XFormController > xActiveController;
640 
641     public:
642 
find_active_databaseform(const Reference<XFormController> & _xActiveController)643         explicit find_active_databaseform( const Reference< XFormController >& _xActiveController )
644             : xActiveController(_xActiveController )
645         {}
646 
operator ()(const Reference<XFormController> & xController)647         Reference < XFormController > operator() (const Reference< XFormController > &xController)
648         {
649             if(xController == xActiveController && isActivableDatabaseForm(xController))
650                 return xController;
651 
652             if ( !xController.is() )
653             {
654                 SAL_WARN( "svx.form", "FmXFormView::OnActivate: a form controller which does not have children?" );
655                 return nullptr;
656             }
657 
658             for(sal_Int32 i = 0; i < xController->getCount(); ++i)
659             {
660                 const Any a(xController->getByIndex(i));
661                 Reference < XFormController > xI;
662                 if ((a >>= xI) && xI.is())
663                 {
664                     Reference < XFormController > xRes(operator()(xI));
665                     if (xRes.is())
666                         return xRes;
667                 }
668             }
669 
670             return nullptr;
671         }
672     };
673 }
674 
675 
IMPL_LINK_NOARG(FmXFormView,OnActivate,void *,void)676 IMPL_LINK_NOARG(FmXFormView, OnActivate, void*, void)
677 {
678     m_nActivationEvent = nullptr;
679 
680     if ( !m_pView )
681     {
682         OSL_FAIL( "FmXFormView::OnActivate: well... seems we have a timing problem (the view already died)!" );
683         return;
684     }
685 
686     // setting the controller to activate
687     if (!(m_pView->GetFormShell() && m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW))
688         return;
689 
690     FmXFormShell* const pShImpl =  m_pView->GetFormShell()->GetImpl();
691 
692     if(!pShImpl)
693         return;
694 
695     find_active_databaseform fad(pShImpl->getActiveController_Lock());
696 
697     vcl::Window* pWindow = m_pView->GetActualOutDev()->GetOwnerWindow();
698     rtl::Reference< FormViewPageWindowAdapter > pAdapter = m_aPageWindowAdapters.empty() ? nullptr : m_aPageWindowAdapters[0];
699     for (const auto& rpPageWindowAdapter : m_aPageWindowAdapters)
700     {
701         if ( pWindow == rpPageWindowAdapter->getWindow() )
702             pAdapter = rpPageWindowAdapter;
703     }
704 
705     if ( !pAdapter.is() )
706         return;
707 
708     Reference< XFormController > xControllerToActivate;
709     for (const Reference< XFormController > & xController : pAdapter->GetList())
710     {
711         if ( !xController.is() )
712             continue;
713 
714         {
715             Reference< XFormController > xActiveController(fad(xController));
716             if (xActiveController.is())
717             {
718                 xControllerToActivate = xActiveController;
719                 break;
720             }
721         }
722 
723         if(xControllerToActivate.is() || !isActivableDatabaseForm(xController))
724             continue;
725 
726         xControllerToActivate = xController;
727     }
728     pShImpl->setActiveController_Lock(xControllerToActivate);
729 }
730 
731 
Activate(bool bSync)732 void FmXFormView::Activate(bool bSync)
733 {
734     if (m_nActivationEvent)
735     {
736         Application::RemoveUserEvent(m_nActivationEvent);
737         m_nActivationEvent = nullptr;
738     }
739 
740     if (bSync)
741     {
742         LINK(this,FmXFormView,OnActivate).Call(nullptr);
743     }
744     else
745         m_nActivationEvent = Application::PostUserEvent(LINK(this,FmXFormView,OnActivate));
746 }
747 
748 
Deactivate(bool bDeactivateController)749 void FmXFormView::Deactivate(bool bDeactivateController)
750 {
751     if (m_nActivationEvent)
752     {
753         Application::RemoveUserEvent(m_nActivationEvent);
754         m_nActivationEvent = nullptr;
755     }
756 
757     FmXFormShell* pShImpl =  m_pView->GetFormShell() ? m_pView->GetFormShell()->GetImpl() : nullptr;
758     if (pShImpl && bDeactivateController)
759         pShImpl->setActiveController_Lock(nullptr);
760 }
761 
762 
GetFormShell() const763 FmFormShell* FmXFormView::GetFormShell() const
764 {
765     return m_pView ? m_pView->GetFormShell() : nullptr;
766 }
767 
AutoFocus()768 void FmXFormView::AutoFocus()
769 {
770     if (m_nAutoFocusEvent)
771         Application::RemoveUserEvent(m_nAutoFocusEvent);
772 
773     m_nAutoFocusEvent = Application::PostUserEvent(LINK(this, FmXFormView, OnAutoFocus));
774 }
775 
776 
isFocusable(const Reference<XControl> & i_rControl)777 bool FmXFormView::isFocusable( const Reference< XControl >& i_rControl )
778 {
779     if ( !i_rControl.is() )
780         return false;
781 
782     try
783     {
784         Reference< XPropertySet > xModelProps( i_rControl->getModel(), UNO_QUERY_THROW );
785 
786         // only enabled controls are allowed to participate
787         bool bEnabled = false;
788         OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_ENABLED ) >>= bEnabled );
789         if ( !bEnabled )
790             return false;
791 
792         // check the class id of the control model
793         sal_Int16 nClassId = FormComponentType::CONTROL;
794         OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
795 
796         // controls which are not focussable
797         if  (   ( FormComponentType::CONTROL != nClassId )
798             &&  ( FormComponentType::IMAGEBUTTON != nClassId )
799             &&  ( FormComponentType::GROUPBOX != nClassId )
800             &&  ( FormComponentType::FIXEDTEXT != nClassId )
801             &&  ( FormComponentType::HIDDENCONTROL != nClassId )
802             &&  ( FormComponentType::IMAGECONTROL != nClassId )
803             &&  ( FormComponentType::SCROLLBAR != nClassId )
804             &&  ( FormComponentType::SPINBUTTON!= nClassId )
805             )
806         {
807             return true;
808         }
809     }
810     catch (const Exception&)
811     {
812         DBG_UNHANDLED_EXCEPTION("svx");
813     }
814     return false;
815 }
816 
817 
lcl_firstFocussableControl(const Sequence<Reference<XControl>> & _rControls)818 static Reference< XControl > lcl_firstFocussableControl( const Sequence< Reference< XControl > >& _rControls )
819 {
820     Reference< XControl > xReturn;
821 
822     // loop through all the controls
823     for ( auto const & control : _rControls )
824     {
825         if ( !control.is() )
826             continue;
827 
828         if ( FmXFormView::isFocusable( control ) )
829         {
830             xReturn = control;
831             break;
832         }
833     }
834 
835     if ( !xReturn.is() && _rControls.hasElements() )
836         xReturn = _rControls[0];
837 
838     return xReturn;
839 }
840 
841 
842 namespace
843 {
844 
lcl_ensureControlsOfFormExist_nothrow(const SdrPage & _rPage,const SdrView & _rView,const vcl::Window & _rWindow,const Reference<XForm> & _rxForm)845     void lcl_ensureControlsOfFormExist_nothrow( const SdrPage& _rPage, const SdrView& _rView, const vcl::Window& _rWindow, const Reference< XForm >& _rxForm )
846     {
847         try
848         {
849             Reference< XInterface > xNormalizedForm( _rxForm, UNO_QUERY_THROW );
850 
851             SdrObjListIter aSdrObjectLoop( &_rPage, SdrIterMode::DeepNoGroups );
852             while ( aSdrObjectLoop.IsMore() )
853             {
854                 FmFormObj* pFormObject = FmFormObj::GetFormObject( aSdrObjectLoop.Next() );
855                 if ( !pFormObject )
856                     continue;
857 
858                 Reference< XChild > xModel( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW );
859                 Reference< XInterface > xModelParent( xModel->getParent(), UNO_QUERY );
860 
861                 if ( xNormalizedForm.get() != xModelParent.get() )
862                     continue;
863 
864                 pFormObject->GetUnoControl( _rView, *_rWindow.GetOutDev() );
865             }
866         }
867         catch (const Exception&)
868         {
869             DBG_UNHANDLED_EXCEPTION("svx");
870         }
871     }
872 }
873 
874 
getFormController(const Reference<XForm> & _rxForm,const OutputDevice & _rDevice) const875 Reference< XFormController > FmXFormView::getFormController( const Reference< XForm >& _rxForm, const OutputDevice& _rDevice ) const
876 {
877     Reference< XFormController > xController;
878 
879     for (const rtl::Reference< FormViewPageWindowAdapter >& pAdapter : m_aPageWindowAdapters)
880     {
881         if ( !pAdapter )
882         {
883             SAL_WARN( "svx.form", "FmXFormView::getFormController: invalid page window adapter!" );
884             continue;
885         }
886 
887         if ( pAdapter->getWindow() != _rDevice.GetOwnerWindow() )
888             // wrong device
889             continue;
890 
891         xController = pAdapter->getController( _rxForm );
892         if ( xController.is() )
893             break;
894     }
895     return xController;
896 }
897 
898 
IMPL_LINK_NOARG(FmXFormView,OnAutoFocus,void *,void)899 IMPL_LINK_NOARG(FmXFormView, OnAutoFocus, void*, void)
900 {
901     m_nAutoFocusEvent = nullptr;
902 
903     // go to the first form of our page, examine it's TabController, go to its first (in terms of the tab order)
904     // control, give it the focus
905 
906     SdrPageView *pPageView = m_pView ? m_pView->GetSdrPageView() : nullptr;
907     SdrPage *pSdrPage = pPageView ? pPageView->GetPage() : nullptr;
908     // get the forms collection of the page we belong to
909     FmFormPage* pPage = dynamic_cast<FmFormPage*>( pSdrPage  );
910     Reference< XIndexAccess > xForms( pPage ? Reference< XIndexAccess >( pPage->GetForms() ) : Reference< XIndexAccess >() );
911 
912     const rtl::Reference< FormViewPageWindowAdapter > pAdapter = m_aPageWindowAdapters.empty() ? nullptr : m_aPageWindowAdapters[0];
913     const vcl::Window* pWindow = pAdapter ? pAdapter->getWindow() : nullptr;
914 
915     ENSURE_OR_RETURN_VOID( xForms.is() && pWindow, "FmXFormView::OnAutoFocus: could not collect all essentials!" );
916 
917     try
918     {
919         // go for the tab controller of the first form
920         if ( !xForms->getCount() )
921             return;
922         Reference< XForm > xForm( xForms->getByIndex( 0 ), UNO_QUERY_THROW );
923         Reference< XTabController > xTabController( pAdapter->getController( xForm ), UNO_QUERY_THROW );
924 
925         // go for the first control of the controller
926         Sequence< Reference< XControl > > aControls( xTabController->getControls() );
927         if ( !aControls.hasElements() )
928         {
929             Reference< XElementAccess > xFormElementAccess( xForm, UNO_QUERY_THROW );
930             if (xFormElementAccess->hasElements() && pPage && m_pView)
931             {
932                 // there are control models in the form, but no controls, yet.
933                 // Well, since some time controls are created on demand only. In particular,
934                 // they're normally created when they're first painted.
935                 // Unfortunately, the FormController does not have any way to
936                 // trigger the creation itself, so we must hack this ...
937                 lcl_ensureControlsOfFormExist_nothrow( *pPage, *m_pView, *pWindow, xForm );
938                 aControls = xTabController->getControls();
939                 OSL_ENSURE( aControls.hasElements(), "FmXFormView::OnAutoFocus: no controls at all!" );
940             }
941         }
942 
943         // set the focus to this first control
944         Reference< XWindow > xControlWindow( lcl_firstFocussableControl( aControls ), UNO_QUERY );
945         if ( !xControlWindow.is() )
946             return;
947 
948         xControlWindow->setFocus();
949 
950         // ensure that the control is visible
951         // 80210 - 12/07/00 - FS
952         const OutputDevice* pOut = m_pView ? m_pView->GetActualOutDev() : nullptr;
953         const vcl::Window* pCurrentWindow = pOut ? pOut->GetOwnerWindow() : nullptr;
954         if ( pCurrentWindow )
955         {
956             awt::Rectangle aRect = xControlWindow->getPosSize();
957             ::tools::Rectangle aNonUnoRect( aRect.X, aRect.Y, aRect.X + aRect.Width, aRect.Y + aRect.Height );
958             m_pView->MakeVisible( pCurrentWindow->PixelToLogic( aNonUnoRect ), *const_cast< vcl::Window* >( pCurrentWindow ) );
959         }
960     }
961     catch (const Exception&)
962     {
963         DBG_UNHANDLED_EXCEPTION("svx");
964     }
965 }
966 
967 
onCreatedFormObject(FmFormObj const & _rFormObject)968 void FmXFormView::onCreatedFormObject( FmFormObj const & _rFormObject )
969 {
970     FmFormShell* pShell = m_pView ? m_pView->GetFormShell() : nullptr;
971     FmXFormShell* pShellImpl = pShell ? pShell->GetImpl() : nullptr;
972     OSL_ENSURE( pShellImpl, "FmXFormView::onCreatedFormObject: no form shell!" );
973     if ( !pShellImpl )
974         return;
975 
976     // it is valid that the form shell's forms collection is not initialized, yet
977     pShellImpl->UpdateForms_Lock(true);
978 
979     m_xLastCreatedControlModel.set( _rFormObject.GetUnoControlModel(), UNO_QUERY );
980     if ( !m_xLastCreatedControlModel.is() )
981         return;
982 
983     // some initial property defaults
984     FormControlFactory aControlFactory;
985     aControlFactory.initializeControlModel(pShellImpl->getDocumentType_Lock(), _rFormObject);
986 
987     if (!pShellImpl->GetWizardUsing_Lock())
988         return;
989 
990     // #i31958# don't call wizards in XForms mode
991     if (pShellImpl->isEnhancedForm_Lock())
992         return;
993 
994     // #i46898# no wizards if there is no Base installed - currently, all wizards are
995     // database related
996     if ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) )
997         return;
998 
999     if ( m_nControlWizardEvent )
1000         Application::RemoveUserEvent( m_nControlWizardEvent );
1001     m_nControlWizardEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnStartControlWizard ) );
1002 }
1003 
breakCreateFormObject()1004 void FmXFormView::breakCreateFormObject()
1005 {
1006     if (m_nControlWizardEvent != nullptr)
1007     {
1008         Application::RemoveUserEvent(m_nControlWizardEvent);
1009         m_nControlWizardEvent = nullptr;
1010     }
1011     m_xLastCreatedControlModel.clear();
1012 }
1013 
GetParentWindow() const1014 Reference<XWindow> FmXFormView::GetParentWindow() const
1015 {
1016     const OutputDevice* pOut = m_pView ? m_pView->GetActualOutDev() : nullptr;
1017     const vcl::Window* pCurrentWindow = pOut ? pOut->GetOwnerWindow() : nullptr;
1018     return VCLUnoHelper::GetInterface(const_cast<vcl::Window*>(pCurrentWindow));
1019 }
1020 
IMPL_LINK_NOARG(FmXFormView,OnStartControlWizard,void *,void)1021 IMPL_LINK_NOARG( FmXFormView, OnStartControlWizard, void*, void )
1022 {
1023     m_nControlWizardEvent = nullptr;
1024     OSL_PRECOND( m_xLastCreatedControlModel.is(), "FmXFormView::OnStartControlWizard: illegal call!" );
1025     if ( !m_xLastCreatedControlModel.is() )
1026         return;
1027 
1028     sal_Int16 nClassId = FormComponentType::CONTROL;
1029     try
1030     {
1031         OSL_VERIFY( m_xLastCreatedControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
1032     }
1033     catch (const Exception&)
1034     {
1035         DBG_UNHANDLED_EXCEPTION("svx");
1036     }
1037 
1038     const char* pWizardAsciiName = nullptr;
1039     switch ( nClassId )
1040     {
1041         case FormComponentType::GRIDCONTROL:
1042             pWizardAsciiName = "com.sun.star.sdb.GridControlAutoPilot";
1043             break;
1044         case FormComponentType::LISTBOX:
1045         case FormComponentType::COMBOBOX:
1046             pWizardAsciiName = "com.sun.star.sdb.ListComboBoxAutoPilot";
1047             break;
1048         case FormComponentType::GROUPBOX:
1049             pWizardAsciiName = "com.sun.star.sdb.GroupBoxAutoPilot";
1050             break;
1051     }
1052 
1053     if ( pWizardAsciiName )
1054     {
1055         // build the argument list
1056         ::comphelper::NamedValueCollection aWizardArgs;
1057         aWizardArgs.put("ObjectModel", m_xLastCreatedControlModel);
1058         aWizardArgs.put("ParentWindow", GetParentWindow());
1059 
1060         // create the wizard object
1061         Reference< XExecutableDialog > xWizard;
1062         try
1063         {
1064             Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
1065             xWizard.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext( OUString::createFromAscii(pWizardAsciiName), aWizardArgs.getWrappedPropertyValues(), xContext ), UNO_QUERY);
1066         }
1067         catch (const Exception&)
1068         {
1069             DBG_UNHANDLED_EXCEPTION("svx");
1070         }
1071 
1072         if ( !xWizard.is() )
1073         {
1074             ShowServiceNotAvailableError( nullptr, OUString::createFromAscii(pWizardAsciiName), true );
1075         }
1076         else
1077         {
1078             // execute the wizard
1079             try
1080             {
1081                 xWizard->execute();
1082             }
1083             catch (const Exception&)
1084             {
1085                 DBG_UNHANDLED_EXCEPTION("svx");
1086             }
1087         }
1088     }
1089 
1090     m_xLastCreatedControlModel.clear();
1091 }
1092 
1093 
1094 namespace
1095 {
lcl_insertIntoFormComponentHierarchy_throw(const FmFormView & _rView,const SdrUnoObj & _rSdrObj,const Reference<XDataSource> & _rxDataSource,const OUString & _rDataSourceName,const OUString & _rCommand,const sal_Int32 _nCommandType)1096     void lcl_insertIntoFormComponentHierarchy_throw( const FmFormView& _rView, const SdrUnoObj& _rSdrObj,
1097         const Reference< XDataSource >& _rxDataSource, const OUString& _rDataSourceName,
1098         const OUString& _rCommand, const sal_Int32 _nCommandType )
1099     {
1100         FmFormPage& rPage = static_cast< FmFormPage& >( *_rView.GetSdrPageView()->GetPage() );
1101 
1102         Reference< XFormComponent > xFormComponent( _rSdrObj.GetUnoControlModel(), UNO_QUERY_THROW );
1103         Reference< XForm > xTargetForm(
1104             rPage.GetImpl().findPlaceInFormComponentHierarchy( xFormComponent, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType ),
1105             UNO_SET_THROW );
1106 
1107         FmFormPageImpl::setUniqueName( xFormComponent, xTargetForm );
1108 
1109         Reference< XIndexContainer > xFormAsContainer( xTargetForm, UNO_QUERY_THROW );
1110         xFormAsContainer->insertByIndex( xFormAsContainer->getCount(), makeAny( xFormComponent ) );
1111     }
1112 }
1113 
1114 
implCreateFieldControl(const svx::ODataAccessDescriptor & _rColumnDescriptor)1115 SdrObjectUniquePtr FmXFormView::implCreateFieldControl( const svx::ODataAccessDescriptor& _rColumnDescriptor )
1116 {
1117     // not if we're in design mode
1118     if ( !m_pView->IsDesignMode() )
1119         return nullptr;
1120 
1121     OUString sCommand, sFieldName;
1122     sal_Int32 nCommandType = CommandType::COMMAND;
1123     SharedConnection xConnection;
1124 
1125     OUString sDataSource = _rColumnDescriptor.getDataSource();
1126     _rColumnDescriptor[ DataAccessDescriptorProperty::Command ]     >>= sCommand;
1127     _rColumnDescriptor[ DataAccessDescriptorProperty::ColumnName ]  >>= sFieldName;
1128     _rColumnDescriptor[ DataAccessDescriptorProperty::CommandType ] >>= nCommandType;
1129     {
1130         Reference< XConnection > xExternalConnection;
1131         _rColumnDescriptor[ DataAccessDescriptorProperty::Connection ]  >>= xExternalConnection;
1132         xConnection.reset( xExternalConnection, SharedConnection::NoTakeOwnership );
1133     }
1134 
1135     if  (   sCommand.isEmpty()
1136         ||  sFieldName.isEmpty()
1137         ||  (   sDataSource.isEmpty()
1138             &&  !xConnection.is()
1139             )
1140         )
1141     {
1142         OSL_FAIL( "FmXFormView::implCreateFieldControl: nonsense!" );
1143     }
1144 
1145     Reference< XDataSource > xDataSource;
1146     SQLErrorEvent aError;
1147     try
1148     {
1149         if ( xConnection.is() && !xDataSource.is() && sDataSource.isEmpty() )
1150         {
1151             Reference< XChild > xChild( xConnection, UNO_QUERY );
1152             if ( xChild.is() )
1153                 xDataSource.set(xChild->getParent(), css::uno::UNO_QUERY);
1154         }
1155 
1156         // obtain the data source
1157         if ( !xDataSource.is() )
1158             xDataSource = getDataSource( sDataSource, comphelper::getProcessComponentContext() );
1159 
1160         // and the connection, if necessary
1161         if ( !xConnection.is() )
1162             xConnection.reset( getConnection_withFeedback(
1163                 sDataSource,
1164                 OUString(),
1165                 OUString(),
1166                 comphelper::getProcessComponentContext(),
1167                 nullptr
1168             ) );
1169     }
1170     catch (const SQLException&)
1171     {
1172         aError.Reason = ::cppu::getCaughtException();
1173     }
1174     catch (const Exception& )
1175     {
1176         /* will be asserted below */
1177     }
1178     if (aError.Reason.hasValue())
1179     {
1180         displayAsyncErrorMessage( aError );
1181         return nullptr;
1182     }
1183 
1184     // need a data source and a connection here
1185     if (!xDataSource.is() || !xConnection.is())
1186     {
1187         OSL_FAIL("FmXFormView::implCreateFieldControl : could not retrieve the data source or the connection!");
1188         return nullptr;
1189     }
1190 
1191     Reference< XComponent > xKeepFieldsAlive;
1192     // go
1193     try
1194     {
1195         // determine the table/query field which we should create a control for
1196         Reference< XPropertySet >   xField;
1197 
1198         Reference< XNameAccess >    xFields = getFieldsByCommandDescriptor(
1199             xConnection, nCommandType, sCommand, xKeepFieldsAlive );
1200 
1201         if (xFields.is() && xFields->hasByName(sFieldName))
1202             xFields->getByName(sFieldName) >>= xField;
1203         if ( !xField.is() )
1204             return nullptr;
1205 
1206         Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( xConnection ), UNO_SET_THROW );
1207         Reference< XNumberFormats >  xNumberFormats( xSupplier->getNumberFormats(), UNO_SET_THROW );
1208 
1209         OUString sLabelPostfix;
1210 
1211 
1212         // only for text size
1213         OutputDevice* pOutDev = nullptr;
1214         if (m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
1215             pOutDev = const_cast<OutputDevice*>(m_pView->GetActualOutDev());
1216         else
1217         {// find OutDev
1218             if (SdrPageView* pPageView = m_pView->GetSdrPageView())
1219             {
1220                 // const SdrPageViewWinList& rWinList = pPageView->GetWinList();
1221                 // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows();
1222 
1223                 for( sal_uInt32 i = 0; i < pPageView->PageWindowCount(); i++ )
1224                 {
1225                     const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);
1226 
1227                     if( rPageWindow.GetPaintWindow().OutputToWindow())
1228                     {
1229                         pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice();
1230                         break;
1231                     }
1232                 }
1233             }
1234         }
1235 
1236         if ( !pOutDev )
1237             return nullptr;
1238 
1239         sal_Int32 nDataType = ::comphelper::getINT32(xField->getPropertyValue(FM_PROP_FIELDTYPE));
1240         if ((DataType::BINARY == nDataType) || (DataType::VARBINARY == nDataType))
1241             return nullptr;
1242 
1243 
1244         // determine the control type by examining the data type of the bound column
1245         SdrObjKind nOBJID = OBJ_NONE;
1246         bool bDateNTimeField = false;
1247 
1248         bool bIsCurrency = false;
1249         if (::comphelper::hasProperty(FM_PROP_ISCURRENCY, xField))
1250             bIsCurrency = ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISCURRENCY));
1251 
1252         if (bIsCurrency)
1253             nOBJID = OBJ_FM_CURRENCYFIELD;
1254         else
1255             switch (nDataType)
1256             {
1257                 case DataType::BLOB:
1258                 case DataType::LONGVARBINARY:
1259                     nOBJID = OBJ_FM_IMAGECONTROL;
1260                     break;
1261                 case DataType::LONGVARCHAR:
1262                 case DataType::CLOB:
1263                     nOBJID = OBJ_FM_EDIT;
1264                     break;
1265                 case DataType::BINARY:
1266                 case DataType::VARBINARY:
1267                     return nullptr;
1268                 case DataType::BIT:
1269                 case DataType::BOOLEAN:
1270                     nOBJID = OBJ_FM_CHECKBOX;
1271                     break;
1272                 case DataType::TINYINT:
1273                 case DataType::SMALLINT:
1274                 case DataType::INTEGER:
1275                     nOBJID = OBJ_FM_NUMERICFIELD;
1276                     break;
1277                 case DataType::REAL:
1278                 case DataType::DOUBLE:
1279                 case DataType::NUMERIC:
1280                 case DataType::DECIMAL:
1281                     nOBJID = OBJ_FM_FORMATTEDFIELD;
1282                     break;
1283                 case DataType::TIMESTAMP:
1284                     bDateNTimeField = true;
1285                     sLabelPostfix = SvxResId(RID_STR_POSTFIX_DATE);
1286                     [[fallthrough]];
1287                 case DataType::DATE:
1288                     nOBJID = OBJ_FM_DATEFIELD;
1289                     break;
1290                 case DataType::TIME:
1291                     nOBJID = OBJ_FM_TIMEFIELD;
1292                     break;
1293                 case DataType::CHAR:
1294                 case DataType::VARCHAR:
1295                 default:
1296                     nOBJID = OBJ_FM_EDIT;
1297                     break;
1298             }
1299         if (!nOBJID)
1300             return nullptr;
1301 
1302         std::unique_ptr<SdrUnoObj, SdrObjectFreeOp> pLabel;
1303         std::unique_ptr<SdrUnoObj, SdrObjectFreeOp> pControl;
1304         if  (   !createControlLabelPair( *pOutDev, 0, 0, xField, xNumberFormats, nOBJID, sLabelPostfix,
1305                     pLabel, pControl, xDataSource, sDataSource, sCommand, nCommandType )
1306             )
1307         {
1308             return nullptr;
1309         }
1310 
1311 
1312         // group objects
1313         bool bCheckbox = ( OBJ_FM_CHECKBOX == nOBJID );
1314         OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateFieldControl: why was there a label created for a check box?" );
1315         if ( bCheckbox )
1316             return SdrObjectUniquePtr(pControl.release());
1317 
1318         SdrObjGroup* pGroup  = new SdrObjGroup(getView()->getSdrModelFromSdrView());
1319         SdrObjList* pObjList = pGroup->GetSubList();
1320         pObjList->InsertObject( pLabel.release() );
1321         pObjList->InsertObject( pControl.release() );
1322 
1323         if ( bDateNTimeField )
1324         {   // so far we created a date field only, but we also need a time field
1325             if  (   createControlLabelPair( *pOutDev, 0, 1000, xField, xNumberFormats, OBJ_FM_TIMEFIELD,
1326                         SvxResId(RID_STR_POSTFIX_TIME), pLabel, pControl,
1327                         xDataSource, sDataSource, sCommand, nCommandType )
1328                 )
1329             {
1330                 pObjList->InsertObject( pLabel.release() );
1331                 pObjList->InsertObject( pControl.release() );
1332             }
1333         }
1334 
1335         return SdrObjectUniquePtr(pGroup); // and done
1336     }
1337     catch (const Exception&)
1338     {
1339         DBG_UNHANDLED_EXCEPTION("svx");
1340     }
1341 
1342 
1343     return nullptr;
1344 }
1345 
1346 
implCreateXFormsControl(const svx::OXFormsDescriptor & _rDesc)1347 SdrObjectUniquePtr FmXFormView::implCreateXFormsControl( const svx::OXFormsDescriptor &_rDesc )
1348 {
1349     // not if we're in design mode
1350     if ( !m_pView->IsDesignMode() )
1351         return nullptr;
1352 
1353     // go
1354     try
1355     {
1356         // determine the table/query field which we should create a control for
1357         Reference< XNumberFormats > xNumberFormats;
1358         OUString sLabelPostfix = _rDesc.szName;
1359 
1360 
1361         // only for text size
1362         OutputDevice* pOutDev = nullptr;
1363         if (m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
1364             pOutDev = const_cast<OutputDevice*>(m_pView->GetActualOutDev());
1365         else
1366         {// find OutDev
1367             if (SdrPageView* pPageView = m_pView->GetSdrPageView())
1368             {
1369                 // const SdrPageViewWinList& rWinList = pPageView->GetWinList();
1370                 // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows();
1371 
1372                 for( sal_uInt32 i = 0; i < pPageView->PageWindowCount(); i++ )
1373                 {
1374                     const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);
1375 
1376                     if( rPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType() == OUTDEV_WINDOW)
1377                     {
1378                         pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice();
1379                         break;
1380                     }
1381                 }
1382             }
1383         }
1384 
1385         if ( !pOutDev )
1386             return nullptr;
1387 
1388 
1389         // The service name decides which control should be created
1390         SdrObjKind nOBJID = OBJ_FM_EDIT;
1391         if(_rDesc.szServiceName == FM_SUN_COMPONENT_NUMERICFIELD)
1392             nOBJID = OBJ_FM_NUMERICFIELD;
1393         if(_rDesc.szServiceName == FM_SUN_COMPONENT_CHECKBOX)
1394             nOBJID = OBJ_FM_CHECKBOX;
1395         if(_rDesc.szServiceName == FM_COMPONENT_COMMANDBUTTON)
1396             nOBJID = OBJ_FM_BUTTON;
1397 
1398         Reference< css::form::submission::XSubmission > xSubmission(_rDesc.xPropSet, UNO_QUERY);
1399 
1400         // xform control or submission button?
1401         if ( !xSubmission.is() )
1402         {
1403             std::unique_ptr<SdrUnoObj, SdrObjectFreeOp> pLabel;
1404             std::unique_ptr<SdrUnoObj, SdrObjectFreeOp> pControl;
1405             if  (   !createControlLabelPair( *pOutDev, 0, 0, nullptr, xNumberFormats, nOBJID, sLabelPostfix,
1406                         pLabel, pControl, nullptr, "", "", -1 )
1407                 )
1408             {
1409                 return nullptr;
1410             }
1411 
1412 
1413             // Now build the connection between the control and the data item.
1414             Reference< XValueBinding > xValueBinding(_rDesc.xPropSet,UNO_QUERY);
1415             Reference< XBindableValue > xBindableValue(pControl->GetUnoControlModel(),UNO_QUERY);
1416 
1417             DBG_ASSERT( xBindableValue.is(), "FmXFormView::implCreateXFormsControl: control's not bindable!" );
1418             if ( xBindableValue.is() )
1419                 xBindableValue->setValueBinding(xValueBinding);
1420 
1421             bool bCheckbox = ( OBJ_FM_CHECKBOX == nOBJID );
1422             OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateXFormsControl: why was there a label created for a check box?" );
1423             if ( bCheckbox )
1424                 return SdrObjectUniquePtr(pControl.release());
1425 
1426 
1427             // group objects
1428             SdrObjGroup* pGroup  = new SdrObjGroup(getView()->getSdrModelFromSdrView());
1429             SdrObjList* pObjList = pGroup->GetSubList();
1430             pObjList->InsertObject(pLabel.release());
1431             pObjList->InsertObject(pControl.release());
1432 
1433             return SdrObjectUniquePtr(pGroup);
1434         }
1435         else {
1436 
1437             // create a button control
1438             const MapMode& eTargetMode( pOutDev->GetMapMode() );
1439             const MapMode eSourceMode(MapUnit::Map100thMM);
1440             const SdrObjKind nObjID = OBJ_FM_BUTTON;
1441             ::Size controlSize(4000, 500);
1442             FmFormObj *pControl = static_cast<FmFormObj*>(
1443                 SdrObjFactory::MakeNewObject(
1444                     getView()->getSdrModelFromSdrView(),
1445                     SdrInventor::FmForm,
1446                     nObjID));
1447             controlSize.setWidth( tools::Long(controlSize.Width() * eTargetMode.GetScaleX()) );
1448             controlSize.setHeight( tools::Long(controlSize.Height() * eTargetMode.GetScaleY()) );
1449             ::Point controlPos( OutputDevice::LogicToLogic( ::Point( controlSize.Width(), 0 ), eSourceMode, eTargetMode ) );
1450             ::tools::Rectangle controlRect( controlPos, OutputDevice::LogicToLogic( controlSize, eSourceMode, eTargetMode ) );
1451             pControl->SetLogicRect(controlRect);
1452 
1453             // set the button label
1454             Reference< XPropertySet > xControlSet(pControl->GetUnoControlModel(), UNO_QUERY);
1455             xControlSet->setPropertyValue(FM_PROP_LABEL, makeAny(_rDesc.szName));
1456 
1457             // connect the submission with the submission supplier (aka the button)
1458             xControlSet->setPropertyValue( FM_PROP_BUTTON_TYPE,
1459                                            makeAny( FormButtonType_SUBMIT ) );
1460             Reference< css::form::submission::XSubmissionSupplier > xSubmissionSupplier(pControl->GetUnoControlModel(), UNO_QUERY);
1461             xSubmissionSupplier->setSubmission(xSubmission);
1462 
1463             return SdrObjectUniquePtr(pControl);
1464         }
1465     }
1466     catch (const Exception&)
1467     {
1468         TOOLS_WARN_EXCEPTION("svx.form", "caught an exception while creating the control !");
1469     }
1470 
1471 
1472     return nullptr;
1473 }
1474 
createControlLabelPair(OutputDevice const & _rOutDev,sal_Int32 _nXOffsetMM,sal_Int32 _nYOffsetMM,const Reference<XPropertySet> & _rxField,const Reference<XNumberFormats> & _rxNumberFormats,SdrObjKind _nControlObjectID,std::u16string_view _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)1475 bool FmXFormView::createControlLabelPair( OutputDevice const & _rOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM,
1476         const Reference< XPropertySet >& _rxField, const Reference< XNumberFormats >& _rxNumberFormats,
1477         SdrObjKind _nControlObjectID, std::u16string_view _rFieldPostfix,
1478         std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpLabel,
1479         std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpControl,
1480         const Reference< XDataSource >& _rxDataSource, const OUString& _rDataSourceName,
1481         const OUString& _rCommand, const sal_Int32 _nCommandType )
1482 {
1483     if(!createControlLabelPair(
1484         _rOutDev,
1485         _nXOffsetMM,
1486         _nYOffsetMM,
1487         _rxField,
1488         _rxNumberFormats,
1489         _nControlObjectID,
1490         _rFieldPostfix,
1491         SdrInventor::FmForm,
1492         OBJ_FM_FIXEDTEXT,
1493 
1494         // tdf#118963 Hand over a SdrModel to SdrObject-creation. It uses the local m_pView
1495         // and already returning false when nullptr == getView() could be done, but m_pView
1496         // is already dereferenced here in many places (see below), so just use it for now.
1497         getView()->getSdrModelFromSdrView(),
1498 
1499         _rpLabel,
1500         _rpControl))
1501     {
1502         return false;
1503     }
1504 
1505     // insert the control model(s) into the form component hierarchy
1506     if ( _rpLabel )
1507         lcl_insertIntoFormComponentHierarchy_throw( *m_pView, *_rpLabel, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType );
1508     lcl_insertIntoFormComponentHierarchy_throw( *m_pView, *_rpControl, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType );
1509 
1510     // some context-dependent initializations
1511     FormControlFactory aControlFactory;
1512     if ( _rpLabel )
1513         aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpLabel );
1514     aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpControl );
1515 
1516     return true;
1517 }
1518 
1519 
createControlLabelPair(OutputDevice const & _rOutDev,sal_Int32 _nXOffsetMM,sal_Int32 _nYOffsetMM,const Reference<XPropertySet> & _rxField,const Reference<XNumberFormats> & _rxNumberFormats,SdrObjKind _nControlObjectID,std::u16string_view _rFieldPostfix,SdrInventor _nInventor,SdrObjKind _nLabelObjectID,SdrModel & _rModel,std::unique_ptr<SdrUnoObj,SdrObjectFreeOp> & _rpLabel,std::unique_ptr<SdrUnoObj,SdrObjectFreeOp> & _rpControl)1520 bool FmXFormView::createControlLabelPair( OutputDevice const & _rOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM,
1521     const Reference< XPropertySet >& _rxField,
1522     const Reference< XNumberFormats >& _rxNumberFormats, SdrObjKind _nControlObjectID,
1523     std::u16string_view _rFieldPostfix, SdrInventor _nInventor, SdrObjKind _nLabelObjectID,
1524     SdrModel& _rModel,
1525     std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpLabel, std::unique_ptr<SdrUnoObj, SdrObjectFreeOp>& _rpControl)
1526 {
1527     sal_Int32 nDataType = 0;
1528     OUString sFieldName;
1529     Any aFieldName;
1530     if ( _rxField.is() )
1531     {
1532         nDataType = ::comphelper::getINT32(_rxField->getPropertyValue(FM_PROP_FIELDTYPE));
1533         aFieldName = _rxField->getPropertyValue(FM_PROP_NAME);
1534         aFieldName >>= sFieldName;
1535     }
1536 
1537     // calculate the positions, respecting the settings of the target device
1538     ::Size aTextSize( _rOutDev.GetTextWidth(sFieldName + _rFieldPostfix), _rOutDev.GetTextHeight() );
1539 
1540     MapMode   eTargetMode( _rOutDev.GetMapMode() ),
1541               eSourceMode( MapUnit::Map100thMM );
1542 
1543     // text width is at least 4 centimeters
1544     // text height is always half a centimeter
1545     ::Size aDefTxtSize(4000, 500);
1546     ::Size aDefSize(4000, 500);
1547     ::Size aDefImageSize(4000, 4000);
1548 
1549     ::Size aRealSize = OutputDevice::LogicToLogic(aTextSize, eTargetMode, eSourceMode);
1550     aRealSize.setWidth( std::max(aRealSize.Width(), aDefTxtSize.Width()) );
1551     aRealSize.setHeight( aDefSize.Height() );
1552 
1553     // adjust to scaling of the target device (#53523#)
1554     aRealSize.setWidth( tools::Long(Fraction(aRealSize.Width(), 1) * eTargetMode.GetScaleX()) );
1555     aRealSize.setHeight( tools::Long(Fraction(aRealSize.Height(), 1) * eTargetMode.GetScaleY()) );
1556 
1557     // for boolean fields, we do not create a label, but just a checkbox
1558     bool bNeedLabel = ( _nControlObjectID != OBJ_FM_CHECKBOX );
1559 
1560     // the label
1561     ::std::unique_ptr< SdrUnoObj, SdrObjectFreeOp > pLabel;
1562     Reference< XPropertySet > xLabelModel;
1563 
1564     if ( bNeedLabel )
1565     {
1566         pLabel.reset( dynamic_cast< SdrUnoObj* >(
1567             SdrObjFactory::MakeNewObject(
1568                 _rModel,
1569                 _nInventor,
1570                 _nLabelObjectID)));
1571 
1572         OSL_ENSURE(pLabel, "FmXFormView::createControlLabelPair: could not create the label!");
1573 
1574         if (!pLabel)
1575             return false;
1576 
1577         xLabelModel.set( pLabel->GetUnoControlModel(), UNO_QUERY );
1578         if ( xLabelModel.is() )
1579         {
1580             OUString sLabel;
1581             if ( _rxField.is() && _rxField->getPropertySetInfo()->hasPropertyByName(FM_PROP_LABEL) )
1582                 _rxField->getPropertyValue(FM_PROP_LABEL) >>= sLabel;
1583             if ( sLabel.isEmpty() )
1584                 sLabel = sFieldName;
1585 
1586             xLabelModel->setPropertyValue( FM_PROP_LABEL, makeAny( sLabel + _rFieldPostfix ) );
1587             OUString sObjectLabel(SvxResId(RID_STR_OBJECT_LABEL).replaceAll("#object#", sFieldName));
1588             xLabelModel->setPropertyValue(FM_PROP_NAME, makeAny(sObjectLabel));
1589         }
1590 
1591         pLabel->SetLogicRect( ::tools::Rectangle(
1592             OutputDevice::LogicToLogic( ::Point( _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ),
1593             OutputDevice::LogicToLogic( aRealSize, eSourceMode, eTargetMode )
1594         ) );
1595     }
1596 
1597     // the control
1598     ::std::unique_ptr< SdrUnoObj, SdrObjectFreeOp > pControl( dynamic_cast< SdrUnoObj* >(
1599         SdrObjFactory::MakeNewObject(
1600             _rModel,
1601              _nInventor,
1602              _nControlObjectID)));
1603 
1604     OSL_ENSURE(pControl, "FmXFormView::createControlLabelPair: could not create the control!");
1605 
1606     if (!pControl)
1607         return false;
1608 
1609     Reference< XPropertySet > xControlSet( pControl->GetUnoControlModel(), UNO_QUERY );
1610     if ( !xControlSet.is() )
1611         return false;
1612 
1613     // size of the control
1614     ::Size aControlSize( aDefSize );
1615     switch ( nDataType )
1616     {
1617     case DataType::BIT:
1618     case DataType::BOOLEAN:
1619         aControlSize = aDefSize;
1620         break;
1621     case DataType::LONGVARCHAR:
1622     case DataType::CLOB:
1623     case DataType::LONGVARBINARY:
1624     case DataType::BLOB:
1625         aControlSize = aDefImageSize;
1626         break;
1627     }
1628 
1629     if ( OBJ_FM_IMAGECONTROL == _nControlObjectID )
1630         aControlSize = aDefImageSize;
1631 
1632     aControlSize.setWidth( tools::Long(Fraction(aControlSize.Width(), 1) * eTargetMode.GetScaleX()) );
1633     aControlSize.setHeight( tools::Long(Fraction(aControlSize.Height(), 1) * eTargetMode.GetScaleY()) );
1634 
1635     pControl->SetLogicRect( ::tools::Rectangle(
1636         OutputDevice::LogicToLogic( ::Point( aRealSize.Width() + _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ),
1637         OutputDevice::LogicToLogic( aControlSize, eSourceMode, eTargetMode )
1638     ) );
1639 
1640     // some initializations
1641     Reference< XPropertySetInfo > xControlPropInfo = xControlSet->getPropertySetInfo();
1642 
1643     if ( aFieldName.hasValue() )
1644     {
1645         xControlSet->setPropertyValue( FM_PROP_CONTROLSOURCE, aFieldName );
1646         xControlSet->setPropertyValue( FM_PROP_NAME, aFieldName );
1647         if ( !bNeedLabel )
1648         {
1649             // no dedicated label control => use the label property
1650             if ( xControlPropInfo->hasPropertyByName( FM_PROP_LABEL ) )
1651                 xControlSet->setPropertyValue( FM_PROP_LABEL, makeAny( sFieldName + _rFieldPostfix ) );
1652             else
1653                 OSL_FAIL( "FmXFormView::createControlLabelPair: can't set a label for the control!" );
1654         }
1655     }
1656 
1657     if ( (nDataType == DataType::LONGVARCHAR || nDataType == DataType::CLOB) && xControlPropInfo->hasPropertyByName( FM_PROP_MULTILINE ) )
1658     {
1659         xControlSet->setPropertyValue( FM_PROP_MULTILINE, makeAny( true ) );
1660     }
1661 
1662     // announce the label to the control
1663     if ( xControlPropInfo->hasPropertyByName( FM_PROP_CONTROLLABEL ) && xLabelModel.is() )
1664     {
1665         try
1666         {
1667             xControlSet->setPropertyValue( FM_PROP_CONTROLLABEL, makeAny( xLabelModel ) );
1668         }
1669         catch (const Exception&)
1670         {
1671             DBG_UNHANDLED_EXCEPTION("svx");
1672         }
1673     }
1674 
1675     if ( _rxField.is() )
1676     {
1677         FormControlFactory::initializeFieldDependentProperties( _rxField, xControlSet, _rxNumberFormats );
1678     }
1679 
1680     _rpLabel = std::move(pLabel);
1681     _rpControl = std::move(pControl);
1682     return true;
1683 }
1684 
1685 
ObjectRemoveListener(FmXFormView * pParent)1686 FmXFormView::ObjectRemoveListener::ObjectRemoveListener( FmXFormView* pParent )
1687     :m_pParent( pParent )
1688 {
1689 }
1690 
1691 
Notify(SfxBroadcaster &,const SfxHint & rHint)1692 void FmXFormView::ObjectRemoveListener::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
1693 {
1694     if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
1695         return;
1696     const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
1697     if (pSdrHint->GetKind() == SdrHintKind::ObjectRemoved)
1698         m_pParent->ObjectRemovedInAliveMode(pSdrHint->GetObject());
1699 }
1700 
1701 
ObjectRemovedInAliveMode(const SdrObject * pObject)1702 void FmXFormView::ObjectRemovedInAliveMode( const SdrObject* pObject )
1703 {
1704     // if the remote object in my MarkList, which I have memorized when switching to the
1705     // Alive mode, I have to take it out now, because I otherwise try to set the mark
1706     // again when switching back (interestingly, this fails only with grouped objects
1707     // (when accessing their ObjList GPF), not with individual ones)
1708 
1709     const size_t nCount = m_aMark.GetMarkCount();
1710     for (size_t i = 0; i < nCount; ++i)
1711     {
1712         SdrMark* pMark = m_aMark.GetMark(i);
1713         SdrObject* pCurrent = pMark->GetMarkedSdrObj();
1714         if (pObject == pCurrent)
1715         {
1716             m_aMark.DeleteMark(i);
1717             return;
1718         }
1719         // I do not need to descend into GroupObjects: if an object is deleted there,
1720         // then the pointer, which I have, to the GroupObject still remains valid ...
1721     }
1722 }
1723 
1724 
stopMarkListWatching()1725 void FmXFormView::stopMarkListWatching()
1726 {
1727     if ( m_pWatchStoredList )
1728     {
1729         m_pWatchStoredList->EndListeningAll();
1730         m_pWatchStoredList.reset();
1731     }
1732 }
1733 
1734 
startMarkListWatching()1735 void FmXFormView::startMarkListWatching()
1736 {
1737     if ( !m_pWatchStoredList )
1738     {
1739         FmFormModel* pModel = GetFormShell() ? GetFormShell()->GetFormModel() : nullptr;
1740         DBG_ASSERT( pModel != nullptr, "FmXFormView::startMarkListWatching: shell has no model!" );
1741         if (pModel)
1742         {
1743             m_pWatchStoredList.reset(new ObjectRemoveListener( this ));
1744             m_pWatchStoredList->StartListening( *static_cast< SfxBroadcaster* >( pModel ) );
1745         }
1746     }
1747     else
1748     {
1749         OSL_FAIL( "FmXFormView::startMarkListWatching: already listening!" );
1750     }
1751 }
1752 
saveMarkList()1753 void FmXFormView::saveMarkList()
1754 {
1755     if ( m_pView )
1756     {
1757         m_aMark = m_pView->GetMarkedObjectList();
1758         const size_t nCount = m_aMark.GetMarkCount( );
1759         for ( size_t i = 0; i < nCount; ++i )
1760         {
1761             SdrMark*   pMark = m_aMark.GetMark(i);
1762             SdrObject* pObj  = pMark->GetMarkedSdrObj();
1763 
1764             if ( m_pView->IsObjMarked( pObj ) )
1765             {
1766                 if ( pObj->IsGroupObject() )
1767                 {
1768                     SdrObjListIter aIter( pObj->GetSubList() );
1769                     bool bMixed = false;
1770                     while ( aIter.IsMore() && !bMixed )
1771                         bMixed = ( aIter.Next()->GetObjInventor() != SdrInventor::FmForm );
1772 
1773                     if ( !bMixed )
1774                     {
1775                         // all objects in the group are form objects
1776                         m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), true /* unmark! */ );
1777                     }
1778                 }
1779                 else
1780                 {
1781                     if ( pObj->GetObjInventor() == SdrInventor::FmForm )
1782                     {   // this is a form layer object
1783                         m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), true /* unmark! */ );
1784                     }
1785                 }
1786             }
1787         }
1788     }
1789     else
1790     {
1791         OSL_FAIL( "FmXFormView::saveMarkList: invalid view!" );
1792         m_aMark.Clear();
1793     }
1794 }
1795 
lcl_hasObject(SdrObjListIter & rIter,SdrObject const * pObj)1796 static bool lcl_hasObject( SdrObjListIter& rIter, SdrObject const * pObj )
1797 {
1798     bool bFound = false;
1799     while (rIter.IsMore() && !bFound)
1800         bFound = pObj == rIter.Next();
1801 
1802     rIter.Reset();
1803     return bFound;
1804 }
1805 
1806 
restoreMarkList(SdrMarkList & _rRestoredMarkList)1807 void FmXFormView::restoreMarkList( SdrMarkList& _rRestoredMarkList )
1808 {
1809     if ( !m_pView )
1810         return;
1811 
1812     _rRestoredMarkList.Clear();
1813 
1814     const SdrMarkList& rCurrentList = m_pView->GetMarkedObjectList();
1815     FmFormPage* pPage = GetFormShell() ? GetFormShell()->GetCurPage() : nullptr;
1816     if (!pPage)
1817         return;
1818 
1819     if (rCurrentList.GetMarkCount())
1820     {   // there is a current mark ... hmm. Is it a subset of the mark we remembered in saveMarkList?
1821         bool bMisMatch = false;
1822 
1823         // loop through all current marks
1824         const size_t nCurrentCount = rCurrentList.GetMarkCount();
1825         for ( size_t i=0; i<nCurrentCount && !bMisMatch; ++i )
1826         {
1827             const SdrObject* pCurrentMarked = rCurrentList.GetMark( i )->GetMarkedSdrObj();
1828 
1829             // loop through all saved marks, check for equality
1830             bool bFound = false;
1831             const size_t nSavedCount = m_aMark.GetMarkCount();
1832             for ( size_t j=0; j<nSavedCount && !bFound; ++j )
1833             {
1834                 if ( m_aMark.GetMark( j )->GetMarkedSdrObj() == pCurrentMarked )
1835                     bFound = true;
1836             }
1837 
1838             // did not find a current mark in the saved marks
1839             if ( !bFound )
1840                 bMisMatch = true;
1841         }
1842 
1843         if ( bMisMatch )
1844         {
1845             m_aMark.Clear();
1846             _rRestoredMarkList = rCurrentList;
1847             return;
1848         }
1849     }
1850     // it is important that the objects of the mark list are not accessed,
1851     // because they can be already destroyed
1852     SdrPageView* pCurPageView = m_pView->GetSdrPageView();
1853     SdrObjListIter aPageIter( pPage );
1854     bool bFound = true;
1855 
1856     // do all objects still exist
1857     const size_t nCount = m_aMark.GetMarkCount();
1858     for (size_t i = 0; i < nCount && bFound; ++i)
1859     {
1860         SdrMark*   pMark = m_aMark.GetMark(i);
1861         SdrObject* pObj  = pMark->GetMarkedSdrObj();
1862         if (pObj->IsGroupObject())
1863         {
1864             SdrObjListIter aIter(pObj->GetSubList());
1865             while (aIter.IsMore() && bFound)
1866                 bFound = lcl_hasObject(aPageIter, aIter.Next());
1867         }
1868         else
1869             bFound = lcl_hasObject(aPageIter, pObj);
1870 
1871         bFound = bFound && pCurPageView == pMark->GetPageView();
1872     }
1873 
1874     if (bFound)
1875     {
1876         // evaluate the LastObject
1877         if (nCount) // now mark the objects
1878         {
1879             for (size_t i = 0; i < nCount; ++i)
1880             {
1881                 SdrMark* pMark = m_aMark.GetMark(i);
1882                 SdrObject* pObj = pMark->GetMarkedSdrObj();
1883                 if ( pObj->GetObjInventor() == SdrInventor::FmForm )
1884                     if ( !m_pView->IsObjMarked( pObj ) )
1885                         m_pView->MarkObj( pObj, pMark->GetPageView() );
1886             }
1887 
1888             _rRestoredMarkList = m_aMark;
1889         }
1890     }
1891     m_aMark.Clear();
1892 }
1893 
focusGained(const FocusEvent &)1894 void SAL_CALL FmXFormView::focusGained( const FocusEvent& /*e*/ )
1895 {
1896     if ( m_xWindow.is() && m_pView )
1897     {
1898         m_pView->SetMoveOutside( true, FmFormView::ImplAccess() );
1899     }
1900 }
1901 
focusLost(const FocusEvent &)1902 void SAL_CALL FmXFormView::focusLost( const FocusEvent& /*e*/ )
1903 {
1904     // when switch the focus outside the office the mark didn't change
1905     // so we can not remove us as focus listener
1906     if ( m_xWindow.is() && m_pView )
1907     {
1908         m_pView->SetMoveOutside( false, FmFormView::ImplAccess() );
1909     }
1910 }
1911 
impl_getDocumentType() const1912 DocumentType FmXFormView::impl_getDocumentType() const
1913 {
1914     if ( GetFormShell() && GetFormShell()->GetImpl() )
1915         return GetFormShell()->GetImpl()->getDocumentType_Lock();
1916     return eUnknownDocumentType;
1917 }
1918 
1919 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1920