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