bump product version to 5.0.4.1
[LibreOffice.git] / svx / source / form / fmvwimp.cxx
blob5fae555d94d0358f47dad3be1393404f702db2ea
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "fmdocumentclassification.hxx"
22 #include "fmobj.hxx"
23 #include "fmpgeimp.hxx"
24 #include "fmprop.hrc"
25 #include "svx/fmresids.hrc"
26 #include "fmservs.hxx"
27 #include "fmshimp.hxx"
28 #include "svx/fmtools.hxx"
29 #include "fmundo.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/fmglob.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"
46 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
47 #include <com/sun/star/style/VerticalAlignment.hpp>
48 #include <com/sun/star/lang/XInitialization.hpp>
49 #include <com/sun/star/sdbc/XRowSet.hpp>
50 #include <com/sun/star/form/XLoadable.hpp>
51 #include <com/sun/star/awt/VisualEffect.hpp>
52 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
53 #include <com/sun/star/util/XNumberFormats.hpp>
54 #include <com/sun/star/sdb/CommandType.hpp>
55 #include <com/sun/star/sdbc/DataType.hpp>
56 #include <com/sun/star/sdbc/ColumnValue.hpp>
57 #include <com/sun/star/form/FormComponentType.hpp>
58 #include <com/sun/star/form/FormButtonType.hpp>
59 #include <com/sun/star/form/XReset.hpp>
60 #include <com/sun/star/form/binding/XBindableValue.hpp>
61 #include <com/sun/star/form/binding/XValueBinding.hpp>
62 #include <com/sun/star/form/runtime/FormController.hpp>
63 #include <com/sun/star/form/submission/XSubmissionSupplier.hpp>
64 #include <com/sun/star/awt/XTabControllerModel.hpp>
65 #include <com/sun/star/awt/XControlContainer.hpp>
66 #include <com/sun/star/awt/XTabController.hpp>
67 #include <com/sun/star/container/XIndexAccess.hpp>
68 #include <com/sun/star/awt/XControl.hpp>
69 #include <com/sun/star/lang/XUnoTunnel.hpp>
70 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
71 #include <com/sun/star/sdbc/XPreparedStatement.hpp>
72 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
73 #include <com/sun/star/container/XContainer.hpp>
75 #include <comphelper/enumhelper.hxx>
76 #include <comphelper/extract.hxx>
77 #include <comphelper/namedvaluecollection.hxx>
78 #include <comphelper/numbers.hxx>
79 #include <comphelper/property.hxx>
80 #include <comphelper/processfactory.hxx>
81 #include <cppuhelper/exc_hlp.hxx>
82 #include <unotools/moduleoptions.hxx>
83 #include <tools/diagnose_ex.h>
84 #include <vcl/msgbox.hxx>
85 #include <vcl/stdtext.hxx>
86 #include <osl/mutex.hxx>
87 #include <connectivity/dbtools.hxx>
89 #include <algorithm>
91 using namespace ::comphelper;
92 using namespace ::svx;
93 using namespace ::svxform;
94 using namespace ::dbtools;
96 using namespace ::com::sun::star;
97 using ::com::sun::star::uno::Exception;
98 using ::com::sun::star::uno::RuntimeException;
99 using ::com::sun::star::uno::XInterface;
100 using ::com::sun::star::uno::Sequence;
101 using ::com::sun::star::uno::UNO_QUERY;
102 using ::com::sun::star::uno::UNO_QUERY_THROW;
103 using ::com::sun::star::uno::UNO_SET_THROW;
104 using ::com::sun::star::uno::Type;
105 using ::com::sun::star::uno::Reference;
106 using ::com::sun::star::uno::Any;
107 using ::com::sun::star::uno::makeAny;
108 using ::com::sun::star::uno::XComponentContext;
109 using ::com::sun::star::style::VerticalAlignment_MIDDLE;
110 using ::com::sun::star::form::FormButtonType_SUBMIT;
111 using ::com::sun::star::form::binding::XValueBinding;
112 using ::com::sun::star::form::binding::XBindableValue;
113 using ::com::sun::star::lang::XComponent;
114 using ::com::sun::star::container::XIndexAccess;
115 using ::com::sun::star::form::runtime::FormController;
116 using ::com::sun::star::form::runtime::XFormController;
117 using ::com::sun::star::script::XEventAttacherManager;
118 using ::com::sun::star::awt::XTabControllerModel;
119 using ::com::sun::star::container::XChild;
120 using ::com::sun::star::container::XEnumeration;
121 using ::com::sun::star::task::XInteractionHandler;
122 using ::com::sun::star::lang::XInitialization;
123 using ::com::sun::star::awt::XTabController;
124 using ::com::sun::star::lang::XUnoTunnel;
125 using ::com::sun::star::awt::XControlContainer;
126 using ::com::sun::star::awt::XControl;
127 using ::com::sun::star::form::XFormComponent;
128 using ::com::sun::star::form::XForm;
129 using ::com::sun::star::lang::IndexOutOfBoundsException;
130 using ::com::sun::star::lang::WrappedTargetException;
131 using ::com::sun::star::container::XContainer;
132 using ::com::sun::star::container::ContainerEvent;
133 using ::com::sun::star::lang::EventObject;
134 using ::com::sun::star::beans::NamedValue;
135 using ::com::sun::star::sdb::SQLErrorEvent;
136 using ::com::sun::star::sdbc::XRowSet;
137 using ::com::sun::star::beans::XPropertySet;
138 using ::com::sun::star::container::XElementAccess;
139 using ::com::sun::star::awt::XWindow;
140 using ::com::sun::star::awt::FocusEvent;
141 using ::com::sun::star::ui::dialogs::XExecutableDialog;
142 using ::com::sun::star::sdbc::XDataSource;
143 using ::com::sun::star::container::XIndexContainer;
144 using ::com::sun::star::sdbc::XConnection;
145 using ::com::sun::star::container::XNameAccess;
146 using ::com::sun::star::sdb::SQLContext;
147 using ::com::sun::star::sdbc::SQLWarning;
148 using ::com::sun::star::sdbc::SQLException;
149 using ::com::sun::star::util::XNumberFormatsSupplier;
150 using ::com::sun::star::util::XNumberFormats;
151 using ::com::sun::star::beans::XPropertySetInfo;
153 namespace FormComponentType = ::com::sun::star::form::FormComponentType;
154 namespace CommandType = ::com::sun::star::sdb::CommandType;
155 namespace DataType = ::com::sun::star::sdbc::DataType;
158 class FmXFormView::ObjectRemoveListener : public SfxListener
160 FmXFormView* m_pParent;
161 public:
162 ObjectRemoveListener( FmXFormView* pParent );
163 virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) SAL_OVERRIDE;
168 FormViewPageWindowAdapter::FormViewPageWindowAdapter( const css::uno::Reference<css::uno::XComponentContext>& _rContext, const SdrPageWindow& _rWindow, FmXFormView* _pViewImpl )
169 : m_xControlContainer( _rWindow.GetControlContainer() ),
170 m_xContext( _rContext ),
171 m_pViewImpl( _pViewImpl ),
172 m_pWindow( dynamic_cast< vcl::Window* >( &_rWindow.GetPaintWindow().GetOutputDevice() ) )
175 // create an XFormController for every form
176 FmFormPage* pFormPage = dynamic_cast< FmFormPage* >( _rWindow.GetPageView().GetPage() );
177 DBG_ASSERT( pFormPage, "FormViewPageWindowAdapter::FormViewPageWindowAdapter: no FmFormPage found!" );
178 if ( pFormPage )
182 Reference< XIndexAccess > xForms( pFormPage->GetForms(), UNO_QUERY_THROW );
183 sal_uInt32 nLength = xForms->getCount();
184 for (sal_uInt32 i = 0; i < nLength; i++)
186 Reference< XForm > xForm( xForms->getByIndex(i), UNO_QUERY );
187 if ( xForm.is() )
188 setController( xForm, NULL );
191 catch (const Exception&)
193 DBG_UNHANDLED_EXCEPTION();
198 FormViewPageWindowAdapter::~FormViewPageWindowAdapter()
202 void FormViewPageWindowAdapter::dispose()
204 for ( ::std::vector< Reference< XFormController > >::const_iterator i = m_aControllerList.begin();
205 i != m_aControllerList.end();
211 Reference< XFormController > xController( *i, UNO_QUERY_THROW );
213 // detaching the events
214 Reference< XChild > xControllerModel( xController->getModel(), UNO_QUERY );
215 if ( xControllerModel.is() )
217 Reference< XEventAttacherManager > xEventManager( xControllerModel->getParent(), UNO_QUERY_THROW );
218 Reference< XInterface > xControllerNormalized( xController, UNO_QUERY_THROW );
219 xEventManager->detach( i - m_aControllerList.begin(), xControllerNormalized );
222 // dispose the formcontroller
223 xController->dispose();
225 catch (const Exception&)
227 DBG_UNHANDLED_EXCEPTION();
231 m_aControllerList.clear();
234 sal_Bool SAL_CALL FormViewPageWindowAdapter::hasElements() throw( RuntimeException, std::exception )
236 return getCount() != 0;
239 Type SAL_CALL FormViewPageWindowAdapter::getElementType() throw( RuntimeException, std::exception )
241 return cppu::UnoType<XFormController>::get();
244 // XIndexAccess
245 sal_Int32 SAL_CALL FormViewPageWindowAdapter::getCount() throw( RuntimeException, std::exception )
247 return m_aControllerList.size();
250 Any SAL_CALL FormViewPageWindowAdapter::getByIndex(sal_Int32 nIndex) throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException, std::exception )
252 if (nIndex < 0 ||
253 nIndex >= getCount())
254 throw IndexOutOfBoundsException();
256 Any aElement;
257 aElement <<= m_aControllerList[nIndex];
258 return aElement;
261 void SAL_CALL FormViewPageWindowAdapter::makeVisible( const Reference< XControl >& _Control ) throw (RuntimeException, std::exception)
263 SolarMutexGuard aSolarGuard;
265 Reference< XWindow > xWindow( _Control, UNO_QUERY );
266 if ( xWindow.is() && m_pViewImpl->getView() && m_pWindow )
268 awt::Rectangle aRect = xWindow->getPosSize();
269 ::Rectangle aNewRect( aRect.X, aRect.Y, aRect.X + aRect.Width, aRect.Y + aRect.Height );
270 aNewRect = m_pWindow->PixelToLogic( aNewRect );
271 m_pViewImpl->getView()->MakeVisible( aNewRect, *m_pWindow );
275 Reference< XFormController > getControllerSearchChildren( const Reference< XIndexAccess > & xIndex, const Reference< XTabControllerModel > & xModel)
277 if (xIndex.is() && xIndex->getCount())
279 Reference< XFormController > xController;
281 for (sal_Int32 n = xIndex->getCount(); n-- && !xController.is(); )
283 xIndex->getByIndex(n) >>= xController;
284 if ((XTabControllerModel*)xModel.get() == (XTabControllerModel*)xController->getModel().get())
285 return xController;
286 else
288 xController = getControllerSearchChildren(xController, xModel);
289 if ( xController.is() )
290 return xController;
294 return Reference< XFormController > ();
297 // Search the according controller
298 Reference< XFormController > FormViewPageWindowAdapter::getController( const Reference< XForm > & xForm ) const
300 Reference< XTabControllerModel > xModel(xForm, UNO_QUERY);
301 for (::std::vector< Reference< XFormController > >::const_iterator i = m_aControllerList.begin();
302 i != m_aControllerList.end(); ++i)
304 if ((XTabControllerModel*)(*i)->getModel().get() == (XTabControllerModel*)xModel.get())
305 return *i;
307 // the current-round controller isn't the right one. perhaps one of its children ?
308 Reference< XFormController > xChildSearch = getControllerSearchChildren(Reference< XIndexAccess > (*i, UNO_QUERY), xModel);
309 if (xChildSearch.is())
310 return xChildSearch;
312 return Reference< XFormController > ();
316 void FormViewPageWindowAdapter::setController(const Reference< XForm > & xForm, const Reference< XFormController >& _rxParentController )
318 DBG_ASSERT( xForm.is(), "FormViewPageWindowAdapter::setController: there should be a form!" );
319 Reference< XIndexAccess > xFormCps(xForm, UNO_QUERY);
320 if (!xFormCps.is())
321 return;
323 Reference< XTabControllerModel > xTabOrder(xForm, UNO_QUERY);
325 // create a form controller
326 Reference< XFormController > xController( FormController::create(m_xContext) );
328 Reference< XInteractionHandler > xHandler;
329 if ( _rxParentController.is() )
330 xHandler = _rxParentController->getInteractionHandler();
331 else
333 // TODO: should we create a default handler? Not really necessary, since the
334 // FormController itself has a default fallback
336 if ( xHandler.is() )
337 xController->setInteractionHandler( xHandler );
339 xController->setContext( this );
341 xController->setModel( xTabOrder );
342 xController->setContainer( m_xControlContainer );
343 xController->activateTabOrder();
344 xController->addActivateListener( m_pViewImpl );
346 if ( _rxParentController.is() )
347 _rxParentController->addChildController( xController );
348 else
350 m_aControllerList.push_back(xController);
352 xController->setParent( *this );
354 // attaching the events
355 Reference< XEventAttacherManager > xEventManager( xForm->getParent(), UNO_QUERY );
356 xEventManager->attach(m_aControllerList.size() - 1, Reference<XInterface>( xController, UNO_QUERY ), makeAny(xController) );
359 // jetzt die Subforms durchgehen
360 sal_uInt32 nLength = xFormCps->getCount();
361 Reference< XForm > xSubForm;
362 for (sal_uInt32 i = 0; i < nLength; i++)
364 if ( xFormCps->getByIndex(i) >>= xSubForm )
365 setController( xSubForm, xController );
370 void FormViewPageWindowAdapter::updateTabOrder( const Reference< XForm >& _rxForm )
372 OSL_PRECOND( _rxForm.is(), "FormViewPageWindowAdapter::updateTabOrder: illegal argument!" );
373 if ( !_rxForm.is() )
374 return;
378 Reference< XTabController > xTabCtrl( getController( _rxForm ).get() );
379 if ( xTabCtrl.is() )
380 { // if there already is a TabController for this form, then delegate the "updateTabOrder" request
381 xTabCtrl->activateTabOrder();
383 else
384 { // otherwise, create a TabController
386 // if it's a sub form, then we must ensure there exist TabControllers
387 // for all its ancestors, too
388 Reference< XForm > xParentForm( _rxForm->getParent(), UNO_QUERY );
389 // there is a parent form -> look for the respective controller
390 Reference< XFormController > xParentController;
391 if ( xParentForm.is() )
392 xParentController.set( getController( xParentForm ), UNO_QUERY );
394 setController( _rxForm, xParentController );
397 catch (const Exception&)
399 DBG_UNHANDLED_EXCEPTION();
404 FmXFormView::FmXFormView(FmFormView* _pView )
405 :m_pMarkedGrid(NULL)
406 ,m_pView(_pView)
407 ,m_nActivationEvent(0)
408 ,m_nErrorMessageEvent( 0 )
409 ,m_nAutoFocusEvent( 0 )
410 ,m_nControlWizardEvent( 0 )
411 ,m_pWatchStoredList( NULL )
412 ,m_bFirstActivation( true )
413 ,m_isTabOrderUpdateSuspended( false )
418 void FmXFormView::cancelEvents()
420 if ( m_nActivationEvent )
422 Application::RemoveUserEvent( m_nActivationEvent );
423 m_nActivationEvent = 0;
426 if ( m_nErrorMessageEvent )
428 Application::RemoveUserEvent( m_nErrorMessageEvent );
429 m_nErrorMessageEvent = 0;
432 if ( m_nAutoFocusEvent )
434 Application::RemoveUserEvent( m_nAutoFocusEvent );
435 m_nAutoFocusEvent = 0;
438 if ( m_nControlWizardEvent )
440 Application::RemoveUserEvent( m_nControlWizardEvent );
441 m_nControlWizardEvent = 0;
446 void FmXFormView::notifyViewDying( )
448 DBG_ASSERT( m_pView, "FmXFormView::notifyViewDying: my view already died!" );
449 m_pView = NULL;
450 cancelEvents();
454 FmXFormView::~FmXFormView()
456 DBG_ASSERT( m_aPageWindowAdapters.empty(), "FmXFormView::~FmXFormView: Window list not empty!" );
457 if ( !m_aPageWindowAdapters.empty() )
459 for ( PageWindowAdapterList::const_iterator loop = m_aPageWindowAdapters.begin();
460 loop != m_aPageWindowAdapters.end();
461 ++loop
464 (*loop)->dispose();
468 cancelEvents();
470 delete m_pWatchStoredList;
471 m_pWatchStoredList = NULL;
474 // EventListener
476 void SAL_CALL FmXFormView::disposing(const EventObject& Source) throw( RuntimeException, std::exception )
478 if ( m_xWindow.is() && Source.Source == m_xWindow )
479 removeGridWindowListening();
482 // XFormControllerListener
484 void SAL_CALL FmXFormView::formActivated(const EventObject& rEvent) throw( RuntimeException, std::exception )
486 if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() )
487 m_pView->GetFormShell()->GetImpl()->formActivated( rEvent );
491 void SAL_CALL FmXFormView::formDeactivated(const EventObject& rEvent) throw( RuntimeException, std::exception )
493 if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() )
494 m_pView->GetFormShell()->GetImpl()->formDeactivated( rEvent );
497 // XContainerListener
499 void SAL_CALL FmXFormView::elementInserted(const ContainerEvent& evt) throw( RuntimeException, std::exception )
503 Reference< XControlContainer > xControlContainer( evt.Source, UNO_QUERY_THROW );
504 Reference< XControl > xControl( evt.Element, UNO_QUERY_THROW );
505 Reference< XFormComponent > xControlModel( xControl->getModel(), UNO_QUERY_THROW );
506 Reference< XForm > xForm( xControlModel->getParent(), UNO_QUERY_THROW );
508 if ( m_isTabOrderUpdateSuspended )
510 // remember the container and the control, so we can update the tab order on resumeTabOrderUpdate
511 m_aNeedTabOrderUpdate[ xControlContainer ].insert( xForm );
513 else
515 PFormViewPageWindowAdapter pAdapter = findWindow( xControlContainer );
516 if ( pAdapter.is() )
517 pAdapter->updateTabOrder( xForm );
520 catch (const Exception&)
522 DBG_UNHANDLED_EXCEPTION();
527 void SAL_CALL FmXFormView::elementReplaced(const ContainerEvent& evt) throw( RuntimeException, std::exception )
529 elementInserted(evt);
533 void SAL_CALL FmXFormView::elementRemoved(const ContainerEvent& /*evt*/) throw( RuntimeException, std::exception )
538 PFormViewPageWindowAdapter FmXFormView::findWindow( const Reference< XControlContainer >& _rxCC ) const
540 for ( PageWindowAdapterList::const_iterator i = m_aPageWindowAdapters.begin();
541 i != m_aPageWindowAdapters.end();
545 if ( _rxCC == (*i)->getControlContainer() )
546 return *i;
548 return NULL;
552 void FmXFormView::addWindow(const SdrPageWindow& rWindow)
554 FmFormPage* pFormPage = PTR_CAST( FmFormPage, rWindow.GetPageView().GetPage() );
555 if ( !pFormPage )
556 return;
558 Reference< XControlContainer > xCC = rWindow.GetControlContainer();
559 if ( xCC.is()
560 && ( !findWindow( xCC ).is() )
563 PFormViewPageWindowAdapter pAdapter = new FormViewPageWindowAdapter( comphelper::getProcessComponentContext(), rWindow, this );
564 m_aPageWindowAdapters.push_back( pAdapter );
566 // Am ControlContainer horchen um Aenderungen mitzbekommen
567 Reference< XContainer > xContainer( xCC, UNO_QUERY );
568 if ( xContainer.is() )
569 xContainer->addContainerListener( this );
574 void FmXFormView::removeWindow( const Reference< XControlContainer >& _rxCC )
576 // Wird gerufen, wenn
577 // - in den Design-Modus geschaltet wird
578 // - ein Window geloescht wird, waehrend man im Design-Modus ist
579 // - der Control-Container fuer ein Window entfernt wird, waehrend
580 // der aktive Modus eingeschaltet ist.
582 for ( PageWindowAdapterList::iterator i = m_aPageWindowAdapters.begin();
583 i != m_aPageWindowAdapters.end();
587 if ( _rxCC != (*i)->getControlContainer() )
588 continue;
590 Reference< XContainer > xContainer( _rxCC, UNO_QUERY );
591 if ( xContainer.is() )
592 xContainer->removeContainerListener( this );
594 (*i)->dispose();
595 m_aPageWindowAdapters.erase( i );
596 break;
601 void FmXFormView::displayAsyncErrorMessage( const SQLErrorEvent& _rEvent )
603 DBG_ASSERT( 0 == m_nErrorMessageEvent, "FmXFormView::displayAsyncErrorMessage: not too fast, please!" );
604 // This should not happen - usually, the PostUserEvent is faster than any possible user
605 // interaction which could trigger a new error. If it happens, we need a queue for the events.
606 m_aAsyncError = _rEvent;
607 m_nErrorMessageEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnDelayedErrorMessage ) );
611 IMPL_LINK_NOARG(FmXFormView, OnDelayedErrorMessage)
613 m_nErrorMessageEvent = 0;
614 displayException( m_aAsyncError );
615 return 0L;
619 void FmXFormView::onFirstViewActivation( const FmFormModel* _pDocModel )
621 if ( _pDocModel && _pDocModel->GetAutoControlFocus() )
622 m_nAutoFocusEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnAutoFocus ) );
626 void FmXFormView::suspendTabOrderUpdate()
628 OSL_ENSURE( !m_isTabOrderUpdateSuspended, "FmXFormView::suspendTabOrderUpdate: nesting not allowed!" );
629 m_isTabOrderUpdateSuspended = true;
633 void FmXFormView::resumeTabOrderUpdate()
635 OSL_ENSURE( m_isTabOrderUpdateSuspended, "FmXFormView::resumeTabOrderUpdate: not suspended!" );
636 m_isTabOrderUpdateSuspended = false;
638 // update the tab orders for all components which were collected since the suspendTabOrderUpdate call.
639 for ( MapControlContainerToSetOfForms::const_iterator container = m_aNeedTabOrderUpdate.begin();
640 container != m_aNeedTabOrderUpdate.end();
641 ++container
644 PFormViewPageWindowAdapter pAdapter = findWindow( container->first );
645 if ( !pAdapter.is() )
646 continue;
648 for ( SetOfForms::const_iterator form = container->second.begin();
649 form != container->second.end();
650 ++form
653 pAdapter->updateTabOrder( *form );
656 m_aNeedTabOrderUpdate.clear();
659 namespace
661 bool isActivableDatabaseForm(const Reference< XFormController > &xController)
663 // only database forms are to be activated
664 Reference< XRowSet > xForm(xController->getModel(), UNO_QUERY);
665 if ( !xForm.is() || !getConnection( xForm ).is() )
666 return false;
668 Reference< XPropertySet > xFormSet( xForm, UNO_QUERY );
669 if ( !xFormSet.is() )
671 SAL_WARN( "svx.form", "FmXFormView::OnActivate: a form which does not have properties?" );
672 return false;
675 const OUString aSource = ::comphelper::getString( xFormSet->getPropertyValue( FM_PROP_COMMAND ) );
677 return !aSource.isEmpty();
680 class find_active_databaseform
682 const Reference< XFormController > xActiveController;
684 public:
686 find_active_databaseform( const Reference< XFormController > _xActiveController )
687 : xActiveController(_xActiveController )
690 Reference < XFormController > operator() (const Reference< XFormController > &xController)
692 if(xController == xActiveController && isActivableDatabaseForm(xController))
693 return xController;
695 Reference< XIndexAccess > xSubControllers( xController, UNO_QUERY );
696 if ( !xSubControllers.is() )
698 SAL_WARN( "svx.form", "FmXFormView::OnActivate: a form controller which does not have children?" );
699 return nullptr;
702 for(sal_Int32 i = 0; i < xSubControllers->getCount(); ++i)
704 const Any a(xSubControllers->getByIndex(i));
705 Reference < XFormController > xI;
706 if ((a >>= xI) && xI.is())
708 Reference < XFormController > xRes(operator()(xI));
709 if (xRes.is())
710 return xRes;
714 return nullptr;
720 IMPL_LINK_NOARG(FmXFormView, OnActivate)
722 m_nActivationEvent = 0;
724 if ( !m_pView )
726 OSL_FAIL( "FmXFormView::OnActivate: well .... seems we have a timing problem (the view already died)!" );
727 return 0;
730 // setting the controller to activate
731 if (m_pView->GetFormShell() && m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
733 FmXFormShell* const pShImpl = m_pView->GetFormShell()->GetImpl();
735 if(!pShImpl)
736 return 0;
738 find_active_databaseform fad(pShImpl->getActiveController());
740 vcl::Window* pWindow = const_cast<vcl::Window*>(static_cast<const vcl::Window*>(m_pView->GetActualOutDev()));
741 PFormViewPageWindowAdapter pAdapter = m_aPageWindowAdapters.empty() ? NULL : m_aPageWindowAdapters[0];
742 for ( PageWindowAdapterList::const_iterator i = m_aPageWindowAdapters.begin();
743 i != m_aPageWindowAdapters.end();
747 if ( pWindow == (*i)->getWindow() )
748 pAdapter =*i;
751 if ( pAdapter.get() )
753 Reference< XFormController > xControllerToActivate;
754 for ( ::std::vector< Reference< XFormController > >::const_iterator i = pAdapter->GetList().begin();
755 i != pAdapter->GetList().end();
759 const Reference< XFormController > & xController = *i;
760 if ( !xController.is() )
761 continue;
764 Reference< XFormController > xActiveController(fad(xController));
765 if (xActiveController.is())
767 xControllerToActivate = xActiveController;
768 break;
772 if(xControllerToActivate.is() || !isActivableDatabaseForm(xController))
773 continue;
775 xControllerToActivate = xController;
777 pShImpl->setActiveController( xControllerToActivate );
780 return 0;
784 void FmXFormView::Activate(bool bSync)
786 if (m_nActivationEvent)
788 Application::RemoveUserEvent(m_nActivationEvent);
789 m_nActivationEvent = 0;
792 if (bSync)
794 LINK(this,FmXFormView,OnActivate).Call(NULL);
796 else
797 m_nActivationEvent = Application::PostUserEvent(LINK(this,FmXFormView,OnActivate));
801 void FmXFormView::Deactivate(bool bDeactivateController)
803 if (m_nActivationEvent)
805 Application::RemoveUserEvent(m_nActivationEvent);
806 m_nActivationEvent = 0;
809 FmXFormShell* pShImpl = m_pView->GetFormShell() ? m_pView->GetFormShell()->GetImpl() : NULL;
810 if (pShImpl && bDeactivateController)
811 pShImpl->setActiveController( NULL );
815 FmFormShell* FmXFormView::GetFormShell() const
817 return m_pView ? m_pView->GetFormShell() : NULL;
820 void FmXFormView::AutoFocus( bool _bSync )
822 if (m_nAutoFocusEvent)
823 Application::RemoveUserEvent(m_nAutoFocusEvent);
825 if ( _bSync )
826 OnAutoFocus( NULL );
827 else
828 m_nAutoFocusEvent = Application::PostUserEvent(LINK(this, FmXFormView, OnAutoFocus));
832 bool FmXFormView::isFocusable( const Reference< XControl >& i_rControl )
834 if ( !i_rControl.is() )
835 return false;
839 Reference< XPropertySet > xModelProps( i_rControl->getModel(), UNO_QUERY_THROW );
841 // only enabled controls are allowed to participate
842 bool bEnabled = false;
843 OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_ENABLED ) >>= bEnabled );
844 if ( !bEnabled )
845 return false;
847 // check the class id of the control model
848 sal_Int16 nClassId = FormComponentType::CONTROL;
849 OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
851 // controls which are not focussable
852 if ( ( FormComponentType::CONTROL != nClassId )
853 && ( FormComponentType::IMAGEBUTTON != nClassId )
854 && ( FormComponentType::GROUPBOX != nClassId )
855 && ( FormComponentType::FIXEDTEXT != nClassId )
856 && ( FormComponentType::HIDDENCONTROL != nClassId )
857 && ( FormComponentType::IMAGECONTROL != nClassId )
858 && ( FormComponentType::SCROLLBAR != nClassId )
859 && ( FormComponentType::SPINBUTTON!= nClassId )
862 return true;
865 catch (const Exception&)
867 DBG_UNHANDLED_EXCEPTION();
869 return false;
873 static Reference< XControl > lcl_firstFocussableControl( const Sequence< Reference< XControl > >& _rControls )
875 Reference< XControl > xReturn;
877 // loop through all the controls
878 const Reference< XControl >* pControls = _rControls.getConstArray();
879 const Reference< XControl >* pControlsEnd = _rControls.getConstArray() + _rControls.getLength();
880 for ( ; pControls != pControlsEnd; ++pControls )
882 if ( !pControls->is() )
883 continue;
885 if ( FmXFormView::isFocusable( *pControls ) )
887 xReturn = *pControls;
888 break;
892 if ( !xReturn.is() && _rControls.getLength() )
893 xReturn = _rControls[0];
895 return xReturn;
899 namespace
902 void lcl_ensureControlsOfFormExist_nothrow( const SdrPage& _rPage, const SdrView& _rView, const vcl::Window& _rWindow, const Reference< XForm >& _rxForm )
906 Reference< XInterface > xNormalizedForm( _rxForm, UNO_QUERY_THROW );
908 SdrObjListIter aSdrObjectLoop( _rPage, IM_DEEPNOGROUPS );
909 while ( aSdrObjectLoop.IsMore() )
911 FmFormObj* pFormObject = FmFormObj::GetFormObject( aSdrObjectLoop.Next() );
912 if ( !pFormObject )
913 continue;
915 Reference< XChild > xModel( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW );
916 Reference< XInterface > xModelParent( xModel->getParent(), UNO_QUERY_THROW );
918 if ( xNormalizedForm.get() != xModelParent.get() )
919 continue;
921 pFormObject->GetUnoControl( _rView, _rWindow );
924 catch (const Exception&)
926 DBG_UNHANDLED_EXCEPTION();
932 Reference< XFormController > FmXFormView::getFormController( const Reference< XForm >& _rxForm, const OutputDevice& _rDevice ) const
934 Reference< XFormController > xController;
936 for ( PageWindowAdapterList::const_iterator pos = m_aPageWindowAdapters.begin();
937 pos != m_aPageWindowAdapters.end();
938 ++pos
941 const PFormViewPageWindowAdapter pAdapter( *pos );
942 if ( !pAdapter.get() )
944 SAL_WARN( "svx.form", "FmXFormView::getFormController: invalid page window adapter!" );
945 continue;
948 if ( pAdapter->getWindow() != &_rDevice )
949 // wrong device
950 continue;
952 xController = pAdapter->getController( _rxForm );
953 if ( xController.is() )
954 break;
956 return xController;
960 IMPL_LINK_NOARG(FmXFormView, OnAutoFocus)
962 m_nAutoFocusEvent = 0;
964 // go to the first form of our page, examine it's TabController, go to it's first (in terms of the tab order)
965 // control, give it the focus
970 SdrPageView *pPageView = m_pView ? m_pView->GetSdrPageView() : NULL;
971 SdrPage *pSdrPage = pPageView ? pPageView->GetPage() : NULL;
972 // get the forms collection of the page we belong to
973 FmFormPage* pPage = PTR_CAST( FmFormPage, pSdrPage );
974 Reference< XIndexAccess > xForms( pPage ? Reference< XIndexAccess >( pPage->GetForms(), UNO_QUERY ) : Reference< XIndexAccess >() );
976 const PFormViewPageWindowAdapter pAdapter = m_aPageWindowAdapters.empty() ? NULL : m_aPageWindowAdapters[0];
977 const vcl::Window* pWindow = pAdapter.get() ? pAdapter->getWindow() : NULL;
979 ENSURE_OR_RETURN( xForms.is() && pWindow, "FmXFormView::OnAutoFocus: could not collect all essentials!", 0L );
983 // go for the tab controller of the first form
984 if ( !xForms->getCount() )
985 break;
986 Reference< XForm > xForm( xForms->getByIndex( 0 ), UNO_QUERY_THROW );
987 Reference< XTabController > xTabController( pAdapter->getController( xForm ), UNO_QUERY_THROW );
989 // go for the first control of the controller
990 Sequence< Reference< XControl > > aControls( xTabController->getControls() );
991 if ( aControls.getLength() == 0 )
993 Reference< XElementAccess > xFormElementAccess( xForm, UNO_QUERY_THROW );
994 if (xFormElementAccess->hasElements() && pPage && m_pView)
996 // there are control models in the form, but no controls, yet.
997 // Well, since some time controls are created on demand only. In particular,
998 // they're normally created when they're first painted.
999 // Unfortunately, the FormController does not have any way to
1000 // trigger the creation itself, so we must hack this ...
1001 lcl_ensureControlsOfFormExist_nothrow( *pPage, *m_pView, *pWindow, xForm );
1002 aControls = xTabController->getControls();
1003 OSL_ENSURE( aControls.getLength(), "FmXFormView::OnAutoFocus: no controls at all!" );
1007 // set the focus to this first control
1008 Reference< XWindow > xControlWindow( lcl_firstFocussableControl( aControls ), UNO_QUERY );
1009 if ( !xControlWindow.is() )
1010 break;
1012 xControlWindow->setFocus();
1014 // ensure that the control is visible
1015 // 80210 - 12/07/00 - FS
1016 const vcl::Window* pCurrentWindow = m_pView ? dynamic_cast<const vcl::Window*>(m_pView->GetActualOutDev()) : NULL;
1017 if ( pCurrentWindow )
1019 awt::Rectangle aRect = xControlWindow->getPosSize();
1020 ::Rectangle aNonUnoRect( aRect.X, aRect.Y, aRect.X + aRect.Width, aRect.Y + aRect.Height );
1021 m_pView->MakeVisible( pCurrentWindow->PixelToLogic( aNonUnoRect ), *const_cast< vcl::Window* >( pCurrentWindow ) );
1024 catch (const Exception&)
1026 DBG_UNHANDLED_EXCEPTION();
1029 } // do
1030 while ( false );
1032 return 1L;
1036 void FmXFormView::onCreatedFormObject( FmFormObj& _rFormObject )
1038 FmFormShell* pShell = m_pView ? m_pView->GetFormShell() : NULL;
1039 FmXFormShell* pShellImpl = pShell ? pShell->GetImpl() : NULL;
1040 OSL_ENSURE( pShellImpl, "FmXFormView::onCreatedFormObject: no form shell!" );
1041 if ( !pShellImpl )
1042 return;
1044 // it is valid that the form shell's forms collection is not initialized, yet
1045 pShellImpl->UpdateForms( true );
1047 m_xLastCreatedControlModel.set( _rFormObject.GetUnoControlModel(), UNO_QUERY );
1048 if ( !m_xLastCreatedControlModel.is() )
1049 return;
1051 // some initial property defaults
1052 FormControlFactory aControlFactory;
1053 aControlFactory.initializeControlModel( pShellImpl->getDocumentType(), _rFormObject );
1055 if ( !pShellImpl->GetWizardUsing() )
1056 return;
1058 // #i31958# don't call wizards in XForms mode
1059 if ( pShellImpl->isEnhancedForm() )
1060 return;
1062 // #i46898# no wizards if there is no Base installed - currently, all wizards are
1063 // database related
1064 if ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) )
1065 return;
1067 if ( m_nControlWizardEvent )
1068 Application::RemoveUserEvent( m_nControlWizardEvent );
1069 m_nControlWizardEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnStartControlWizard ) );
1072 void FmXFormView::breakCreateFormObject()
1074 if (m_nControlWizardEvent != 0)
1076 Application::RemoveUserEvent(m_nControlWizardEvent);
1077 m_nControlWizardEvent = 0;
1079 m_xLastCreatedControlModel.clear();
1082 IMPL_LINK_NOARG( FmXFormView, OnStartControlWizard )
1084 m_nControlWizardEvent = 0;
1085 OSL_PRECOND( m_xLastCreatedControlModel.is(), "FmXFormView::OnStartControlWizard: illegal call!" );
1086 if ( !m_xLastCreatedControlModel.is() )
1087 return 0L;
1089 sal_Int16 nClassId = FormComponentType::CONTROL;
1092 OSL_VERIFY( m_xLastCreatedControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
1094 catch (const Exception&)
1096 DBG_UNHANDLED_EXCEPTION();
1099 const sal_Char* pWizardAsciiName = NULL;
1100 switch ( nClassId )
1102 case FormComponentType::GRIDCONTROL:
1103 pWizardAsciiName = "com.sun.star.sdb.GridControlAutoPilot";
1104 break;
1105 case FormComponentType::LISTBOX:
1106 case FormComponentType::COMBOBOX:
1107 pWizardAsciiName = "com.sun.star.sdb.ListComboBoxAutoPilot";
1108 break;
1109 case FormComponentType::GROUPBOX:
1110 pWizardAsciiName = "com.sun.star.sdb.GroupBoxAutoPilot";
1111 break;
1114 if ( pWizardAsciiName )
1116 // build the argument list
1117 ::comphelper::NamedValueCollection aWizardArgs;
1118 aWizardArgs.put( "ObjectModel", m_xLastCreatedControlModel );
1120 // create the wizard object
1121 Reference< XExecutableDialog > xWizard;
1124 Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
1125 xWizard.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext( OUString::createFromAscii(pWizardAsciiName), aWizardArgs.getWrappedPropertyValues(), xContext ), UNO_QUERY);;
1127 catch (const Exception&)
1129 DBG_UNHANDLED_EXCEPTION();
1132 if ( !xWizard.is() )
1134 ShowServiceNotAvailableError( NULL, OUString::createFromAscii(pWizardAsciiName), true );
1136 else
1138 // execute the wizard
1141 xWizard->execute();
1143 catch (const Exception&)
1145 DBG_UNHANDLED_EXCEPTION();
1150 m_xLastCreatedControlModel.clear();
1151 return 1L;
1155 namespace
1157 void lcl_insertIntoFormComponentHierarchy_throw( const FmFormView& _rView, const SdrUnoObj& _rSdrObj,
1158 const Reference< XDataSource >& _rxDataSource = NULL, const OUString& _rDataSourceName = OUString(),
1159 const OUString& _rCommand = OUString(), const sal_Int32 _nCommandType = -1 )
1161 FmFormPage& rPage = static_cast< FmFormPage& >( *_rView.GetSdrPageView()->GetPage() );
1163 Reference< XFormComponent > xFormComponent( _rSdrObj.GetUnoControlModel(), UNO_QUERY_THROW );
1164 Reference< XForm > xTargetForm(
1165 rPage.GetImpl().findPlaceInFormComponentHierarchy( xFormComponent, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType ),
1166 UNO_SET_THROW );
1168 FmFormPageImpl::setUniqueName( xFormComponent, xTargetForm );
1170 Reference< XIndexContainer > xFormAsContainer( xTargetForm, UNO_QUERY_THROW );
1171 xFormAsContainer->insertByIndex( xFormAsContainer->getCount(), makeAny( xFormComponent ) );
1176 SdrObject* FmXFormView::implCreateFieldControl( const svx::ODataAccessDescriptor& _rColumnDescriptor )
1178 // not if we're in design mode
1179 if ( !m_pView->IsDesignMode() )
1180 return NULL;
1182 OUString sCommand, sFieldName;
1183 sal_Int32 nCommandType = CommandType::COMMAND;
1184 SharedConnection xConnection;
1186 OUString sDataSource = _rColumnDescriptor.getDataSource();
1187 _rColumnDescriptor[ daCommand ] >>= sCommand;
1188 _rColumnDescriptor[ daColumnName ] >>= sFieldName;
1189 _rColumnDescriptor[ daCommandType ] >>= nCommandType;
1191 Reference< XConnection > xExternalConnection;
1192 _rColumnDescriptor[ daConnection ] >>= xExternalConnection;
1193 xConnection.reset( xExternalConnection, SharedConnection::NoTakeOwnership );
1196 if ( sCommand.isEmpty()
1197 || sFieldName.isEmpty()
1198 || ( sDataSource.isEmpty()
1199 && !xConnection.is()
1203 OSL_FAIL( "FmXFormView::implCreateFieldControl: nonsense!" );
1206 Reference< XDataSource > xDataSource;
1207 SQLErrorEvent aError;
1210 if ( xConnection.is() && !xDataSource.is() && sDataSource.isEmpty() )
1212 Reference< XChild > xChild( xConnection, UNO_QUERY );
1213 if ( xChild.is() )
1214 xDataSource.set(xChild->getParent(), css::uno::UNO_QUERY);
1217 // obtain the data source
1218 if ( !xDataSource.is() )
1219 xDataSource = getDataSource( sDataSource, comphelper::getProcessComponentContext() );
1221 // and the connection, if necessary
1222 if ( !xConnection.is() )
1223 xConnection.reset( getConnection_withFeedback(
1224 sDataSource,
1225 OUString(),
1226 OUString(),
1227 comphelper::getProcessComponentContext()
1228 ) );
1230 catch (const SQLException&)
1232 aError.Reason = ::cppu::getCaughtException();
1234 catch (const Exception& )
1236 /* will be asserted below */
1238 if (aError.Reason.hasValue())
1240 displayAsyncErrorMessage( aError );
1241 return NULL;
1244 // need a data source and a connection here
1245 if (!xDataSource.is() || !xConnection.is())
1247 OSL_FAIL("FmXFormView::implCreateFieldControl : could not retrieve the data source or the connection!");
1248 return NULL;
1251 Reference< XComponent > xKeepFieldsAlive;
1252 // go
1255 // determine the table/query field which we should create a control for
1256 Reference< XPropertySet > xField;
1258 Reference< XNameAccess > xFields = getFieldsByCommandDescriptor(
1259 xConnection, nCommandType, sCommand, xKeepFieldsAlive );
1261 if (xFields.is() && xFields->hasByName(sFieldName))
1262 xFields->getByName(sFieldName) >>= xField;
1263 if ( !xField.is() )
1264 return NULL;
1266 Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( xConnection, false ), UNO_SET_THROW );
1267 Reference< XNumberFormats > xNumberFormats( xSupplier->getNumberFormats(), UNO_SET_THROW );
1269 OUString sLabelPostfix;
1272 // nur fuer Textgroesse
1273 OutputDevice* pOutDev = NULL;
1274 if (m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
1275 pOutDev = const_cast<OutputDevice*>(m_pView->GetActualOutDev());
1276 else
1277 {// OutDev suchen
1278 SdrPageView* pPageView = m_pView->GetSdrPageView();
1279 if( pPageView && !pOutDev )
1281 // const SdrPageViewWinList& rWinList = pPageView->GetWinList();
1282 // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows();
1284 for( sal_uInt32 i = 0L; i < pPageView->PageWindowCount(); i++ )
1286 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);
1288 if( rPageWindow.GetPaintWindow().OutputToWindow())
1290 pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice();
1291 break;
1297 if ( !pOutDev )
1298 return NULL;
1300 sal_Int32 nDataType = ::comphelper::getINT32(xField->getPropertyValue(FM_PROP_FIELDTYPE));
1301 if ((DataType::BINARY == nDataType) || (DataType::VARBINARY == nDataType))
1302 return NULL;
1305 // determine the control type by examining the data type of the bound column
1306 sal_uInt16 nOBJID = 0;
1307 bool bDateNTimeField = false;
1309 bool bIsCurrency = false;
1310 if (::comphelper::hasProperty(FM_PROP_ISCURRENCY, xField))
1311 bIsCurrency = ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISCURRENCY));
1313 if (bIsCurrency)
1314 nOBJID = OBJ_FM_CURRENCYFIELD;
1315 else
1316 switch (nDataType)
1318 case DataType::BLOB:
1319 case DataType::LONGVARBINARY:
1320 nOBJID = OBJ_FM_IMAGECONTROL;
1321 break;
1322 case DataType::LONGVARCHAR:
1323 case DataType::CLOB:
1324 nOBJID = OBJ_FM_EDIT;
1325 break;
1326 case DataType::BINARY:
1327 case DataType::VARBINARY:
1328 return NULL;
1329 case DataType::BIT:
1330 case DataType::BOOLEAN:
1331 nOBJID = OBJ_FM_CHECKBOX;
1332 break;
1333 case DataType::TINYINT:
1334 case DataType::SMALLINT:
1335 case DataType::INTEGER:
1336 nOBJID = OBJ_FM_NUMERICFIELD;
1337 break;
1338 case DataType::REAL:
1339 case DataType::DOUBLE:
1340 case DataType::NUMERIC:
1341 case DataType::DECIMAL:
1342 nOBJID = OBJ_FM_FORMATTEDFIELD;
1343 break;
1344 case DataType::TIMESTAMP:
1345 bDateNTimeField = true;
1346 sLabelPostfix = SVX_RESSTR(RID_STR_POSTFIX_DATE);
1347 // DON'T break !
1348 case DataType::DATE:
1349 nOBJID = OBJ_FM_DATEFIELD;
1350 break;
1351 case DataType::TIME:
1352 nOBJID = OBJ_FM_TIMEFIELD;
1353 break;
1354 case DataType::CHAR:
1355 case DataType::VARCHAR:
1356 default:
1357 nOBJID = OBJ_FM_EDIT;
1358 break;
1360 if (!nOBJID)
1361 return NULL;
1363 SdrUnoObj* pLabel( NULL );
1364 SdrUnoObj* pControl( NULL );
1365 if ( !createControlLabelPair( *pOutDev, 0, 0, xField, xNumberFormats, nOBJID, sLabelPostfix,
1366 pLabel, pControl, xDataSource, sDataSource, sCommand, nCommandType )
1369 return NULL;
1373 // group objects
1374 bool bCheckbox = ( OBJ_FM_CHECKBOX == nOBJID );
1375 OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateFieldControl: why was there a label created for a check box?" );
1376 if ( bCheckbox )
1377 return pControl;
1379 SdrObjGroup* pGroup = new SdrObjGroup();
1380 SdrObjList* pObjList = pGroup->GetSubList();
1381 pObjList->InsertObject( pLabel );
1382 pObjList->InsertObject( pControl );
1384 if ( bDateNTimeField )
1385 { // so far we created a date field only, but we also need a time field
1386 pLabel = pControl = NULL;
1387 if ( createControlLabelPair( *pOutDev, 0, 1000, xField, xNumberFormats, OBJ_FM_TIMEFIELD,
1388 SVX_RESSTR(RID_STR_POSTFIX_TIME), pLabel, pControl,
1389 xDataSource, sDataSource, sCommand, nCommandType )
1392 pObjList->InsertObject( pLabel );
1393 pObjList->InsertObject( pControl );
1397 return pGroup; // und fertig
1399 catch (const Exception&)
1401 DBG_UNHANDLED_EXCEPTION();
1405 return NULL;
1409 SdrObject* FmXFormView::implCreateXFormsControl( const svx::OXFormsDescriptor &_rDesc )
1411 // not if we're in design mode
1412 if ( !m_pView->IsDesignMode() )
1413 return NULL;
1415 Reference< XComponent > xKeepFieldsAlive;
1417 // go
1420 // determine the table/query field which we should create a control for
1421 Reference< XNumberFormats > xNumberFormats;
1422 OUString sLabelPostfix = _rDesc.szName;
1425 // nur fuer Textgroesse
1426 OutputDevice* pOutDev = NULL;
1427 if (m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
1428 pOutDev = const_cast<OutputDevice*>(m_pView->GetActualOutDev());
1429 else
1430 {// OutDev suchen
1431 SdrPageView* pPageView = m_pView->GetSdrPageView();
1432 if( pPageView && !pOutDev )
1434 // const SdrPageViewWinList& rWinList = pPageView->GetWinList();
1435 // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows();
1437 for( sal_uInt32 i = 0L; i < pPageView->PageWindowCount(); i++ )
1439 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);
1441 if( rPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType() == OUTDEV_WINDOW)
1443 pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice();
1444 break;
1450 if ( !pOutDev )
1451 return NULL;
1454 // The service name decides which control should be created
1455 sal_uInt16 nOBJID = OBJ_FM_EDIT;
1456 if(OUString(_rDesc.szServiceName) == FM_SUN_COMPONENT_NUMERICFIELD)
1457 nOBJID = OBJ_FM_NUMERICFIELD;
1458 if(OUString(_rDesc.szServiceName) == FM_SUN_COMPONENT_CHECKBOX)
1459 nOBJID = OBJ_FM_CHECKBOX;
1460 if(OUString(_rDesc.szServiceName) == FM_COMPONENT_COMMANDBUTTON)
1461 nOBJID = OBJ_FM_BUTTON;
1463 typedef ::com::sun::star::form::submission::XSubmission XSubmission_t;
1464 Reference< XSubmission_t > xSubmission(_rDesc.xPropSet, UNO_QUERY);
1466 // xform control or submission button?
1467 if ( !xSubmission.is() )
1469 SdrUnoObj* pLabel( NULL );
1470 SdrUnoObj* pControl( NULL );
1471 if ( !createControlLabelPair( *pOutDev, 0, 0, NULL, xNumberFormats, nOBJID, sLabelPostfix,
1472 pLabel, pControl )
1475 return NULL;
1479 // Now build the connection between the control and the data item.
1480 Reference< XValueBinding > xValueBinding(_rDesc.xPropSet,UNO_QUERY);
1481 Reference< XBindableValue > xBindableValue(pControl->GetUnoControlModel(),UNO_QUERY);
1483 DBG_ASSERT( xBindableValue.is(), "FmXFormView::implCreateXFormsControl: control's not bindable!" );
1484 if ( xBindableValue.is() )
1485 xBindableValue->setValueBinding(xValueBinding);
1487 bool bCheckbox = ( OBJ_FM_CHECKBOX == nOBJID );
1488 OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateXFormsControl: why was there a label created for a check box?" );
1489 if ( bCheckbox )
1490 return pControl;
1493 // group objects
1494 SdrObjGroup* pGroup = new SdrObjGroup();
1495 SdrObjList* pObjList = pGroup->GetSubList();
1496 pObjList->InsertObject(pLabel);
1497 pObjList->InsertObject(pControl);
1499 return pGroup;
1501 else {
1503 // create a button control
1504 const MapMode eTargetMode( pOutDev->GetMapMode() );
1505 const MapMode eSourceMode(MAP_100TH_MM);
1506 const sal_uInt16 nObjID = OBJ_FM_BUTTON;
1507 ::Size controlSize(4000, 500);
1508 FmFormObj *pControl = static_cast<FmFormObj*>(SdrObjFactory::MakeNewObject( FmFormInventor, nObjID, NULL, NULL ));
1509 controlSize.Width() = Fraction(controlSize.Width(), 1) * eTargetMode.GetScaleX();
1510 controlSize.Height() = Fraction(controlSize.Height(), 1) * eTargetMode.GetScaleY();
1511 ::Point controlPos( OutputDevice::LogicToLogic( ::Point( controlSize.Width(), 0 ), eSourceMode, eTargetMode ) );
1512 ::Rectangle controlRect( controlPos, OutputDevice::LogicToLogic( controlSize, eSourceMode, eTargetMode ) );
1513 pControl->SetLogicRect(controlRect);
1515 // set the button label
1516 Reference< XPropertySet > xControlSet(pControl->GetUnoControlModel(), UNO_QUERY);
1517 xControlSet->setPropertyValue(FM_PROP_LABEL, makeAny(OUString(_rDesc.szName)));
1519 // connect the submission with the submission supplier (aka the button)
1520 xControlSet->setPropertyValue( FM_PROP_BUTTON_TYPE,
1521 makeAny( FormButtonType_SUBMIT ) );
1522 typedef ::com::sun::star::form::submission::XSubmissionSupplier XSubmissionSupplier_t;
1523 Reference< XSubmissionSupplier_t > xSubmissionSupplier(pControl->GetUnoControlModel(), UNO_QUERY);
1524 xSubmissionSupplier->setSubmission(xSubmission);
1526 return pControl;
1529 catch (const Exception&)
1531 OSL_FAIL("FmXFormView::implCreateXFormsControl: caught an exception while creating the control !");
1535 return NULL;
1539 bool FmXFormView::createControlLabelPair( OutputDevice& _rOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM,
1540 const Reference< XPropertySet >& _rxField, const Reference< XNumberFormats >& _rxNumberFormats,
1541 sal_uInt16 _nControlObjectID, const OUString& _rFieldPostfix,
1542 SdrUnoObj*& _rpLabel, SdrUnoObj*& _rpControl,
1543 const Reference< XDataSource >& _rxDataSource, const OUString& _rDataSourceName,
1544 const OUString& _rCommand, const sal_Int32 _nCommandType )
1546 if ( !createControlLabelPair( _rOutDev, _nXOffsetMM, _nYOffsetMM,
1547 _rxField, _rxNumberFormats, _nControlObjectID, _rFieldPostfix, FmFormInventor, OBJ_FM_FIXEDTEXT,
1548 NULL, NULL, NULL, _rpLabel, _rpControl )
1550 return false;
1552 // insert the control model(s) into the form component hierarchy
1553 if ( _rpLabel )
1554 lcl_insertIntoFormComponentHierarchy_throw( *m_pView, *_rpLabel, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType );
1555 lcl_insertIntoFormComponentHierarchy_throw( *m_pView, *_rpControl, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType );
1557 // some context-dependent initializations
1558 FormControlFactory aControlFactory;
1559 if ( _rpLabel )
1560 aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpLabel );
1561 aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpControl );
1563 return true;
1567 bool FmXFormView::createControlLabelPair( OutputDevice& _rOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM,
1568 const Reference< XPropertySet >& _rxField,
1569 const Reference< XNumberFormats >& _rxNumberFormats, sal_uInt16 _nControlObjectID,
1570 const OUString& _rFieldPostfix, sal_uInt32 _nInventor, sal_uInt16 _nLabelObjectID,
1571 SdrPage* _pLabelPage, SdrPage* _pControlPage, SdrModel* _pModel, SdrUnoObj*& _rpLabel, SdrUnoObj*& _rpControl)
1573 sal_Int32 nDataType = 0;
1574 OUString sFieldName;
1575 Any aFieldName;
1576 if ( _rxField.is() )
1578 nDataType = ::comphelper::getINT32(_rxField->getPropertyValue(FM_PROP_FIELDTYPE));
1579 aFieldName = Any(_rxField->getPropertyValue(FM_PROP_NAME));
1580 aFieldName >>= sFieldName;
1583 // calculate the positions, respecting the settings of the target device
1584 ::Size aTextSize( _rOutDev.GetTextWidth(sFieldName + _rFieldPostfix), _rOutDev.GetTextHeight() );
1586 MapMode eTargetMode( _rOutDev.GetMapMode() ),
1587 eSourceMode( MAP_100TH_MM );
1589 // Textbreite ist mindestens 4cm
1590 // Texthoehe immer halber cm
1591 ::Size aDefTxtSize(4000, 500);
1592 ::Size aDefSize(4000, 500);
1593 ::Size aDefImageSize(4000, 4000);
1595 ::Size aRealSize = OutputDevice::LogicToLogic(aTextSize, eTargetMode, eSourceMode);
1596 aRealSize.Width() = std::max(aRealSize.Width(), aDefTxtSize.Width());
1597 aRealSize.Height()= aDefSize.Height();
1599 // adjust to scaling of the target device (#53523#)
1600 aRealSize.Width() = long(Fraction(aRealSize.Width(), 1) * eTargetMode.GetScaleX());
1601 aRealSize.Height() = long(Fraction(aRealSize.Height(), 1) * eTargetMode.GetScaleY());
1603 // for boolean fields, we do not create a label, but just a checkbox
1604 bool bNeedLabel = ( _nControlObjectID != OBJ_FM_CHECKBOX );
1606 // the label
1607 ::std::unique_ptr< SdrUnoObj > pLabel;
1608 Reference< XPropertySet > xLabelModel;
1609 if ( bNeedLabel )
1611 pLabel.reset( dynamic_cast< SdrUnoObj* >(
1612 SdrObjFactory::MakeNewObject( _nInventor, _nLabelObjectID, _pLabelPage, _pModel ) ) );
1613 OSL_ENSURE( pLabel.get(), "FmXFormView::createControlLabelPair: could not create the label!" );
1614 if ( !pLabel.get() )
1615 return false;
1617 xLabelModel.set( pLabel->GetUnoControlModel(), UNO_QUERY );
1618 if ( xLabelModel.is() )
1620 OUString sLabel;
1621 if ( _rxField.is() && _rxField->getPropertySetInfo()->hasPropertyByName(FM_PROP_LABEL) )
1622 _rxField->getPropertyValue(FM_PROP_LABEL) >>= sLabel;
1623 if ( sLabel.isEmpty() )
1624 sLabel = sFieldName;
1626 xLabelModel->setPropertyValue( FM_PROP_LABEL, makeAny( sLabel + _rFieldPostfix ) );
1627 OUString sObjectLabel(SVX_RESSTR(RID_STR_OBJECT_LABEL).replaceAll("#object#", sFieldName));
1628 xLabelModel->setPropertyValue(FM_PROP_NAME, makeAny(sObjectLabel));
1631 pLabel->SetLogicRect( ::Rectangle(
1632 OutputDevice::LogicToLogic( ::Point( _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ),
1633 OutputDevice::LogicToLogic( aRealSize, eSourceMode, eTargetMode )
1634 ) );
1637 // the control
1638 ::std::unique_ptr< SdrUnoObj > pControl( dynamic_cast< SdrUnoObj* >(
1639 SdrObjFactory::MakeNewObject( _nInventor, _nControlObjectID, _pControlPage, _pModel ) ) );
1640 OSL_ENSURE( pControl.get(), "FmXFormView::createControlLabelPair: could not create the control!" );
1641 if ( !pControl.get() )
1642 return false;
1644 Reference< XPropertySet > xControlSet( pControl->GetUnoControlModel(), UNO_QUERY );
1645 if ( !xControlSet.is() )
1646 return false;
1648 // size of the control
1649 ::Size aControlSize( aDefSize );
1650 switch ( nDataType )
1652 case DataType::BIT:
1653 case DataType::BOOLEAN:
1654 aControlSize = aDefSize;
1655 break;
1656 case DataType::LONGVARCHAR:
1657 case DataType::CLOB:
1658 case DataType::LONGVARBINARY:
1659 case DataType::BLOB:
1660 aControlSize = aDefImageSize;
1661 break;
1664 if ( OBJ_FM_IMAGECONTROL == _nControlObjectID )
1665 aControlSize = aDefImageSize;
1667 aControlSize.Width() = long(Fraction(aControlSize.Width(), 1) * eTargetMode.GetScaleX());
1668 aControlSize.Height() = long(Fraction(aControlSize.Height(), 1) * eTargetMode.GetScaleY());
1670 pControl->SetLogicRect( ::Rectangle(
1671 OutputDevice::LogicToLogic( ::Point( aRealSize.Width() + _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ),
1672 OutputDevice::LogicToLogic( aControlSize, eSourceMode, eTargetMode )
1673 ) );
1675 // some initializations
1676 Reference< XPropertySetInfo > xControlPropInfo = xControlSet->getPropertySetInfo();
1678 if ( aFieldName.hasValue() )
1680 xControlSet->setPropertyValue( FM_PROP_CONTROLSOURCE, aFieldName );
1681 xControlSet->setPropertyValue( FM_PROP_NAME, aFieldName );
1682 if ( !bNeedLabel )
1684 // no dedicated label control => use the label property
1685 if ( xControlPropInfo->hasPropertyByName( FM_PROP_LABEL ) )
1686 xControlSet->setPropertyValue( FM_PROP_LABEL, makeAny( sFieldName + _rFieldPostfix ) );
1687 else
1688 OSL_FAIL( "FmXFormView::createControlLabelPair: can't set a label for the control!" );
1692 if ( (nDataType == DataType::LONGVARCHAR || nDataType == DataType::CLOB) && xControlPropInfo->hasPropertyByName( FM_PROP_MULTILINE ) )
1694 xControlSet->setPropertyValue( FM_PROP_MULTILINE, makeAny( true ) );
1697 // announce the label to the control
1698 if ( xControlPropInfo->hasPropertyByName( FM_PROP_CONTROLLABEL ) && xLabelModel.is() )
1702 xControlSet->setPropertyValue( FM_PROP_CONTROLLABEL, makeAny( xLabelModel ) );
1704 catch (const Exception&)
1706 DBG_UNHANDLED_EXCEPTION();
1710 if ( _rxField.is() )
1712 FormControlFactory::initializeFieldDependentProperties( _rxField, xControlSet, _rxNumberFormats );
1715 _rpLabel = pLabel.release();
1716 _rpControl = pControl.release();
1717 return true;
1721 FmXFormView::ObjectRemoveListener::ObjectRemoveListener( FmXFormView* pParent )
1722 :m_pParent( pParent )
1727 void FmXFormView::ObjectRemoveListener::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
1729 const SdrHint* pSdrHint = dynamic_cast<const SdrHint*>(&rHint);
1730 if (pSdrHint && pSdrHint->GetKind() == HINT_OBJREMOVED)
1731 m_pParent->ObjectRemovedInAliveMode(pSdrHint->GetObject());
1735 void FmXFormView::ObjectRemovedInAliveMode( const SdrObject* pObject )
1737 // wenn das entfernte Objekt in meiner MarkList, die ich mir beim Umschalten in den Alive-Mode gemerkt habe, steht,
1738 // muss ich es jetzt da rausnehmen, da ich sonst beim Zurueckschalten versuche, die Markierung wieder zu setzen
1739 // (interesanterweise geht das nur bei gruppierten Objekten schief (beim Zugriff auf deren ObjList GPF), nicht bei einzelnen)
1741 const size_t nCount = m_aMark.GetMarkCount();
1742 for (size_t i = 0; i < nCount; ++i)
1744 SdrMark* pMark = m_aMark.GetMark(i);
1745 SdrObject* pCurrent = pMark->GetMarkedSdrObj();
1746 if (pObject == pCurrent)
1748 m_aMark.DeleteMark(i);
1749 return;
1751 // ich brauche nicht in GroupObjects absteigen : wenn dort unten ein Objekt geloescht wird, dann bleibt der
1752 // Zeiger auf das GroupObject, den ich habe, trotzdem weiter gueltig bleibt ...
1757 void FmXFormView::stopMarkListWatching()
1759 if ( m_pWatchStoredList )
1761 m_pWatchStoredList->EndListeningAll();
1762 delete m_pWatchStoredList;
1763 m_pWatchStoredList = NULL;
1768 void FmXFormView::startMarkListWatching()
1770 if ( !m_pWatchStoredList )
1772 FmFormModel* pModel = GetFormShell() ? GetFormShell()->GetFormModel() : NULL;
1773 DBG_ASSERT( pModel != NULL, "FmXFormView::startMarkListWatching: shell has no model!" );
1774 if (pModel)
1776 m_pWatchStoredList = new ObjectRemoveListener( this );
1777 m_pWatchStoredList->StartListening( *static_cast< SfxBroadcaster* >( pModel ) );
1780 else
1782 OSL_FAIL( "FmXFormView::startMarkListWatching: already listening!" );
1787 void FmXFormView::saveMarkList( bool _bSmartUnmark )
1789 if ( m_pView )
1791 m_aMark = m_pView->GetMarkedObjectList();
1792 if ( _bSmartUnmark )
1794 const size_t nCount = m_aMark.GetMarkCount( );
1795 for ( size_t i = 0; i < nCount; ++i )
1797 SdrMark* pMark = m_aMark.GetMark(i);
1798 SdrObject* pObj = pMark->GetMarkedSdrObj();
1800 if ( m_pView->IsObjMarked( pObj ) )
1802 if ( pObj->IsGroupObject() )
1804 SdrObjListIter aIter( *pObj->GetSubList() );
1805 bool bMixed = false;
1806 while ( aIter.IsMore() && !bMixed )
1807 bMixed = ( aIter.Next()->GetObjInventor() != FmFormInventor );
1809 if ( !bMixed )
1811 // all objects in the group are form objects
1812 m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), true /* unmark! */ );
1815 else
1817 if ( pObj->GetObjInventor() == FmFormInventor )
1818 { // this is a form layer object
1819 m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), true /* unmark! */ );
1826 else
1828 OSL_FAIL( "FmXFormView::saveMarkList: invalid view!" );
1829 m_aMark = SdrMarkList();
1834 static bool lcl_hasObject( SdrObjListIter& rIter, SdrObject* pObj )
1836 bool bFound = false;
1837 while (rIter.IsMore() && !bFound)
1838 bFound = pObj == rIter.Next();
1840 rIter.Reset();
1841 return bFound;
1845 void FmXFormView::restoreMarkList( SdrMarkList& _rRestoredMarkList )
1847 if ( !m_pView )
1848 return;
1850 _rRestoredMarkList.Clear();
1852 const SdrMarkList& rCurrentList = m_pView->GetMarkedObjectList();
1853 FmFormPage* pPage = GetFormShell() ? GetFormShell()->GetCurPage() : NULL;
1854 if (pPage)
1856 if (rCurrentList.GetMarkCount())
1857 { // there is a current mark ... hmm. Is it a subset of the mark we remembered in saveMarkList?
1858 bool bMisMatch = false;
1860 // loop through all current marks
1861 const size_t nCurrentCount = rCurrentList.GetMarkCount();
1862 for ( size_t i=0; i<nCurrentCount && !bMisMatch; ++i )
1864 const SdrObject* pCurrentMarked = rCurrentList.GetMark( i )->GetMarkedSdrObj();
1866 // loop through all saved marks, check for equality
1867 bool bFound = false;
1868 const size_t nSavedCount = m_aMark.GetMarkCount();
1869 for ( size_t j=0; j<nSavedCount && !bFound; ++j )
1871 if ( m_aMark.GetMark( j )->GetMarkedSdrObj() == pCurrentMarked )
1872 bFound = true;
1875 // did not find a current mark in the saved marks
1876 if ( !bFound )
1877 bMisMatch = true;
1880 if ( bMisMatch )
1882 m_aMark.Clear();
1883 _rRestoredMarkList = rCurrentList;
1884 return;
1887 // wichtig ist das auf die Objecte der markliste nicht zugegriffen wird
1888 // da diese bereits zerstoert sein koennen
1889 SdrPageView* pCurPageView = m_pView->GetSdrPageView();
1890 SdrObjListIter aPageIter( *pPage );
1891 bool bFound = true;
1893 // gibt es noch alle Objecte
1894 const size_t nCount = m_aMark.GetMarkCount();
1895 for (size_t i = 0; i < nCount && bFound; ++i)
1897 SdrMark* pMark = m_aMark.GetMark(i);
1898 SdrObject* pObj = pMark->GetMarkedSdrObj();
1899 if (pObj->IsGroupObject())
1901 SdrObjListIter aIter(*pObj->GetSubList());
1902 while (aIter.IsMore() && bFound)
1903 bFound = lcl_hasObject(aPageIter, aIter.Next());
1905 else
1906 bFound = lcl_hasObject(aPageIter, pObj);
1908 bFound = bFound && pCurPageView == pMark->GetPageView();
1911 if (bFound)
1913 // Das LastObject auswerten
1914 if (nCount) // Objecte jetzt Markieren
1916 for (size_t i = 0; i < nCount; ++i)
1918 SdrMark* pMark = m_aMark.GetMark(i);
1919 SdrObject* pObj = pMark->GetMarkedSdrObj();
1920 if ( pObj->GetObjInventor() == FmFormInventor )
1921 if ( !m_pView->IsObjMarked( pObj ) )
1922 m_pView->MarkObj( pObj, pMark->GetPageView() );
1925 _rRestoredMarkList = m_aMark;
1928 m_aMark.Clear();
1932 void SAL_CALL FmXFormView::focusGained( const FocusEvent& /*e*/ ) throw (RuntimeException, std::exception)
1934 if ( m_xWindow.is() && m_pView )
1936 m_pView->SetMoveOutside( true, FmFormView::ImplAccess() );
1940 void SAL_CALL FmXFormView::focusLost( const FocusEvent& /*e*/ ) throw (RuntimeException, std::exception)
1942 // when switch the focus outside the office the mark didn't change
1943 // so we can not remove us as focus listener
1944 if ( m_xWindow.is() && m_pView )
1946 m_pView->SetMoveOutside( false, FmFormView::ImplAccess() );
1950 void FmXFormView::removeGridWindowListening()
1952 if ( m_xWindow.is() )
1954 m_xWindow->removeFocusListener(this);
1955 if ( m_pView )
1957 m_pView->SetMoveOutside( false, FmFormView::ImplAccess() );
1959 m_xWindow = NULL;
1964 DocumentType FmXFormView::impl_getDocumentType() const
1966 if ( GetFormShell() && GetFormShell()->GetImpl() )
1967 return GetFormShell()->GetImpl()->getDocumentType();
1968 return eUnknownDocumentType;
1971 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */