/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_svx.hxx" #include "fmdocumentclassification.hxx" #include "fmobj.hxx" #include "fmpgeimp.hxx" #include "fmprop.hrc" #include "svx/fmresids.hrc" #include "fmservs.hxx" #include "fmshimp.hxx" #include "svx/fmtools.hxx" #include "fmundo.hxx" #include "fmvwimp.hxx" #include "formcontrolfactory.hxx" #include "svx/sdrpaintwindow.hxx" #include "svx/svditer.hxx" #include "svx/dataaccessdescriptor.hxx" #include "svx/dialmgr.hxx" #include "svx/fmglob.hxx" #include "svx/fmmodel.hxx" #include "svx/fmpage.hxx" #include "svx/fmshell.hxx" #include "svx/fmview.hxx" #include "svx/sdrpagewindow.hxx" #include "svx/svdogrp.hxx" #include "svx/svdpagv.hxx" #include "svx/xmlexchg.hxx" /** === begin UNO includes === **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** === end UNO includes === **/ #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::comphelper; using namespace ::svx; using namespace ::svxform; using namespace ::com::sun::star; /** === begin UNO using === **/ using ::com::sun::star::uno::Exception; using ::com::sun::star::uno::RuntimeException; using ::com::sun::star::uno::XInterface; using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::UNO_QUERY; using ::com::sun::star::uno::UNO_QUERY_THROW; using ::com::sun::star::uno::UNO_SET_THROW; using ::com::sun::star::uno::Type; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::Any; using ::com::sun::star::uno::makeAny; using ::com::sun::star::style::VerticalAlignment_MIDDLE; using ::com::sun::star::form::FormButtonType_SUBMIT; using ::com::sun::star::form::binding::XValueBinding; using ::com::sun::star::form::binding::XBindableValue; using ::com::sun::star::lang::XComponent; using ::com::sun::star::container::XIndexAccess; using ::com::sun::star::form::XForm; using ::com::sun::star::form::runtime::XFormController; using ::com::sun::star::script::XEventAttacherManager; using ::com::sun::star::awt::XTabControllerModel; using ::com::sun::star::container::XChild; using ::com::sun::star::container::XEnumeration; using ::com::sun::star::task::XInteractionHandler; using ::com::sun::star::lang::XInitialization; using ::com::sun::star::awt::XTabController; using ::com::sun::star::lang::XUnoTunnel; using ::com::sun::star::awt::XControlContainer; using ::com::sun::star::awt::XControl; using ::com::sun::star::form::XFormComponent; using ::com::sun::star::form::XForm; using ::com::sun::star::lang::IndexOutOfBoundsException; using ::com::sun::star::lang::WrappedTargetException; using ::com::sun::star::container::XContainer; using ::com::sun::star::container::ContainerEvent; using ::com::sun::star::lang::EventObject; using ::com::sun::star::beans::NamedValue; using ::com::sun::star::sdb::SQLErrorEvent; using ::com::sun::star::sdbc::XRowSet; using ::com::sun::star::beans::XPropertySet; using ::com::sun::star::container::XElementAccess; using ::com::sun::star::awt::XWindow; using ::com::sun::star::awt::FocusEvent; using ::com::sun::star::ui::dialogs::XExecutableDialog; using ::com::sun::star::sdbc::XDataSource; using ::com::sun::star::container::XIndexContainer; using ::com::sun::star::sdbc::XConnection; using ::com::sun::star::container::XNameAccess; using ::com::sun::star::sdb::SQLContext; using ::com::sun::star::sdbc::SQLWarning; using ::com::sun::star::sdbc::SQLException; using ::com::sun::star::util::XNumberFormatsSupplier; using ::com::sun::star::util::XNumberFormats; using ::com::sun::star::beans::XPropertySetInfo; /** === end UNO using === **/ namespace FormComponentType = ::com::sun::star::form::FormComponentType; namespace CommandType = ::com::sun::star::sdb::CommandType; namespace DataType = ::com::sun::star::sdbc::DataType; //------------------------------------------------------------------------------ class FmXFormView::ObjectRemoveListener : public SfxListener { FmXFormView* m_pParent; public: ObjectRemoveListener( FmXFormView* pParent ); virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); }; //======================================================================== DBG_NAME(FormViewPageWindowAdapter) //------------------------------------------------------------------------ FormViewPageWindowAdapter::FormViewPageWindowAdapter( const ::comphelper::ComponentContext& _rContext, const SdrPageWindow& _rWindow, FmXFormView* _pViewImpl ) : m_xControlContainer( _rWindow.GetControlContainer() ), m_aContext( _rContext ), m_pViewImpl( _pViewImpl ), m_pWindow( dynamic_cast< Window* >( &_rWindow.GetPaintWindow().GetOutputDevice() ) ) { DBG_CTOR(FormViewPageWindowAdapter,NULL); // create an XFormController for every form FmFormPage* pFormPage = dynamic_cast< FmFormPage* >( _rWindow.GetPageView().GetPage() ); DBG_ASSERT( pFormPage, "FormViewPageWindowAdapter::FormViewPageWindowAdapter: no FmFormPage found!" ); if ( pFormPage ) { try { Reference< XIndexAccess > xForms( pFormPage->GetForms(), UNO_QUERY_THROW ); sal_uInt32 nLength = xForms->getCount(); for (sal_uInt32 i = 0; i < nLength; i++) { Reference< XForm > xForm( xForms->getByIndex(i), UNO_QUERY ); if ( xForm.is() ) setController( xForm, NULL ); } } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } } } // ----------------------------------------------------------------------------- FormViewPageWindowAdapter::~FormViewPageWindowAdapter() { DBG_DTOR(FormViewPageWindowAdapter,NULL); } //------------------------------------------------------------------ void FormViewPageWindowAdapter::dispose() { for ( ::std::vector< Reference< XFormController > >::const_iterator i = m_aControllerList.begin(); i != m_aControllerList.end(); ++i ) { try { Reference< XFormController > xController( *i, UNO_QUERY_THROW ); // detaching the events Reference< XChild > xControllerModel( xController->getModel(), UNO_QUERY ); if ( xControllerModel.is() ) { Reference< XEventAttacherManager > xEventManager( xControllerModel->getParent(), UNO_QUERY_THROW ); Reference< XInterface > xControllerNormalized( xController, UNO_QUERY_THROW ); xEventManager->detach( i - m_aControllerList.begin(), xControllerNormalized ); } // dispose the formcontroller Reference< XComponent > xComp( xController, UNO_QUERY_THROW ); xComp->dispose(); } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } } m_aControllerList.clear(); } //------------------------------------------------------------------------------ sal_Bool SAL_CALL FormViewPageWindowAdapter::hasElements(void) throw( RuntimeException ) { return getCount() != 0; } //------------------------------------------------------------------------------ Type SAL_CALL FormViewPageWindowAdapter::getElementType(void) throw( RuntimeException ) { return ::getCppuType((const Reference< XFormController>*)0); } // XEnumerationAccess //------------------------------------------------------------------------------ Reference< XEnumeration > SAL_CALL FormViewPageWindowAdapter::createEnumeration(void) throw( RuntimeException ) { return new ::comphelper::OEnumerationByIndex(this); } // XIndexAccess //------------------------------------------------------------------------------ sal_Int32 SAL_CALL FormViewPageWindowAdapter::getCount(void) throw( RuntimeException ) { return m_aControllerList.size(); } //------------------------------------------------------------------------------ Any SAL_CALL FormViewPageWindowAdapter::getByIndex(sal_Int32 nIndex) throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException ) { if (nIndex < 0 || nIndex >= getCount()) throw IndexOutOfBoundsException(); Any aElement; aElement <<= m_aControllerList[nIndex]; return aElement; } //------------------------------------------------------------------------ void SAL_CALL FormViewPageWindowAdapter::makeVisible( const Reference< XControl >& _Control ) throw (RuntimeException) { ::vos::OGuard aSolarGuard(Application::GetSolarMutex()); Reference< XWindow > xWindow( _Control, UNO_QUERY ); if ( xWindow.is() && m_pViewImpl->getView() && m_pWindow ) { awt::Rectangle aRect = xWindow->getPosSize(); ::Rectangle aNewRect( aRect.X, aRect.Y, aRect.X + aRect.Width, aRect.Y + aRect.Height ); aNewRect = m_pWindow->PixelToLogic( aNewRect ); m_pViewImpl->getView()->MakeVisible( aNewRect, *m_pWindow ); } } //------------------------------------------------------------------------ Reference< XFormController > getControllerSearchChilds( const Reference< XIndexAccess > & xIndex, const Reference< XTabControllerModel > & xModel) { if (xIndex.is() && xIndex->getCount()) { Reference< XFormController > xController; for (sal_Int32 n = xIndex->getCount(); n-- && !xController.is(); ) { xIndex->getByIndex(n) >>= xController; if ((XTabControllerModel*)xModel.get() == (XTabControllerModel*)xController->getModel().get()) return xController; else { xController = getControllerSearchChilds(Reference< XIndexAccess > (xController, UNO_QUERY), xModel); if ( xController.is() ) return xController; } } } return Reference< XFormController > (); } // Search the according controller //------------------------------------------------------------------------ Reference< XFormController > FormViewPageWindowAdapter::getController( const Reference< XForm > & xForm ) const { Reference< XTabControllerModel > xModel(xForm, UNO_QUERY); for (::std::vector< Reference< XFormController > >::const_iterator i = m_aControllerList.begin(); i != m_aControllerList.end(); i++) { if ((XTabControllerModel*)(*i)->getModel().get() == (XTabControllerModel*)xModel.get()) return *i; // the current-round controller isn't the right one. perhaps one of it's children ? Reference< XFormController > xChildSearch = getControllerSearchChilds(Reference< XIndexAccess > (*i, UNO_QUERY), xModel); if (xChildSearch.is()) return xChildSearch; } return Reference< XFormController > (); } //------------------------------------------------------------------------ void FormViewPageWindowAdapter::setController(const Reference< XForm > & xForm, const Reference< XFormController >& _rxParentController ) { DBG_ASSERT( xForm.is(), "FormViewPageWindowAdapter::setController: there should be a form!" ); Reference< XIndexAccess > xFormCps(xForm, UNO_QUERY); if (!xFormCps.is()) return; Reference< XTabControllerModel > xTabOrder(xForm, UNO_QUERY); // create a form controller Reference< XFormController > xController( m_aContext.createComponent( FM_FORM_CONTROLLER ), UNO_QUERY ); if ( !xController.is() ) { ShowServiceNotAvailableError( m_pWindow, FM_FORM_CONTROLLER, sal_True ); return; } Reference< XInteractionHandler > xHandler; if ( _rxParentController.is() ) xHandler = _rxParentController->getInteractionHandler(); else { // TODO: should we create a default handler? Not really necessary, since the // FormController itself has a default fallback } if ( xHandler.is() ) xController->setInteractionHandler( xHandler ); xController->setContext( this ); xController->setModel( xTabOrder ); xController->setContainer( m_xControlContainer ); xController->activateTabOrder(); xController->addActivateListener( m_pViewImpl ); if ( _rxParentController.is() ) _rxParentController->addChildController( xController ); else { m_aControllerList.push_back(xController); xController->setParent( *this ); // attaching the events Reference< XEventAttacherManager > xEventManager( xForm->getParent(), UNO_QUERY ); Reference< XInterface > xIfc(xController, UNO_QUERY); xEventManager->attach(m_aControllerList.size() - 1, xIfc, makeAny(xController) ); } // jetzt die Subforms durchgehen sal_uInt32 nLength = xFormCps->getCount(); Reference< XForm > xSubForm; for (sal_uInt32 i = 0; i < nLength; i++) { if ( xFormCps->getByIndex(i) >>= xSubForm ) setController( xSubForm, xController ); } } //------------------------------------------------------------------------ void FormViewPageWindowAdapter::updateTabOrder( const Reference< XForm >& _rxForm ) { OSL_PRECOND( _rxForm.is(), "FormViewPageWindowAdapter::updateTabOrder: illegal argument!" ); if ( !_rxForm.is() ) return; try { Reference< XTabController > xTabCtrl( getController( _rxForm ).get() ); if ( xTabCtrl.is() ) { // if there already is a TabController for this form, then delegate the "updateTabOrder" request xTabCtrl->activateTabOrder(); } else { // otherwise, create a TabController // if it's a sub form, then we must ensure there exist TabControllers // for all its ancestors, too Reference< XForm > xParentForm( _rxForm->getParent(), UNO_QUERY ); // there is a parent form -> look for the respective controller Reference< XFormController > xParentController; if ( xParentForm.is() ) xParentController.set( getController( xParentForm ), UNO_QUERY ); setController( _rxForm, xParentController ); } } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } } //------------------------------------------------------------------------ FmXFormView::FmXFormView(const ::comphelper::ComponentContext& _rContext, FmFormView* _pView ) :m_aContext( _rContext ) ,m_pMarkedGrid(NULL) ,m_pView(_pView) ,m_nActivationEvent(0) ,m_nErrorMessageEvent( 0 ) ,m_nAutoFocusEvent( 0 ) ,m_nControlWizardEvent( 0 ) ,m_pWatchStoredList( NULL ) ,m_bFirstActivation( true ) ,m_isTabOrderUpdateSuspended( false ) { } //------------------------------------------------------------------------ void FmXFormView::cancelEvents() { if ( m_nActivationEvent ) { Application::RemoveUserEvent( m_nActivationEvent ); m_nActivationEvent = 0; } if ( m_nErrorMessageEvent ) { Application::RemoveUserEvent( m_nErrorMessageEvent ); m_nErrorMessageEvent = 0; } if ( m_nAutoFocusEvent ) { Application::RemoveUserEvent( m_nAutoFocusEvent ); m_nAutoFocusEvent = 0; } if ( m_nControlWizardEvent ) { Application::RemoveUserEvent( m_nControlWizardEvent ); m_nControlWizardEvent = 0; } } //------------------------------------------------------------------------ void FmXFormView::notifyViewDying( ) { DBG_ASSERT( m_pView, "FmXFormView::notifyViewDying: my view already died!" ); m_pView = NULL; cancelEvents(); } //------------------------------------------------------------------------ FmXFormView::~FmXFormView() { DBG_ASSERT( m_aPageWindowAdapters.empty(), "FmXFormView::~FmXFormView: Window list not empty!" ); if ( !m_aPageWindowAdapters.empty() ) { for ( PageWindowAdapterList::const_iterator loop = m_aPageWindowAdapters.begin(); loop != m_aPageWindowAdapters.end(); ++loop ) { (*loop)->dispose(); } } cancelEvents(); delete m_pWatchStoredList; m_pWatchStoredList = NULL; } // EventListener //------------------------------------------------------------------------------ void SAL_CALL FmXFormView::disposing(const EventObject& Source) throw( RuntimeException ) { if ( m_xWindow.is() && Source.Source == m_xWindow ) removeGridWindowListening(); } // XFormControllerListener //------------------------------------------------------------------------------ void SAL_CALL FmXFormView::formActivated(const EventObject& rEvent) throw( RuntimeException ) { if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() ) m_pView->GetFormShell()->GetImpl()->formActivated( rEvent ); } //------------------------------------------------------------------------------ void SAL_CALL FmXFormView::formDeactivated(const EventObject& rEvent) throw( RuntimeException ) { if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() ) m_pView->GetFormShell()->GetImpl()->formDeactivated( rEvent ); } // XContainerListener //------------------------------------------------------------------------------ void SAL_CALL FmXFormView::elementInserted(const ContainerEvent& evt) throw( RuntimeException ) { try { Reference< XControlContainer > xControlContainer( evt.Source, UNO_QUERY_THROW ); Reference< XControl > xControl( evt.Element, UNO_QUERY_THROW ); Reference< XFormComponent > xControlModel( xControl->getModel(), UNO_QUERY_THROW ); Reference< XForm > xForm( xControlModel->getParent(), UNO_QUERY_THROW ); if ( m_isTabOrderUpdateSuspended ) { // remember the container and the control, so we can update the tab order on resumeTabOrderUpdate m_aNeedTabOrderUpdate[ xControlContainer ].insert( xForm ); } else { PFormViewPageWindowAdapter pAdapter = findWindow( xControlContainer ); if ( pAdapter.is() ) pAdapter->updateTabOrder( xForm ); } } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } } //------------------------------------------------------------------------------ void SAL_CALL FmXFormView::elementReplaced(const ContainerEvent& evt) throw( RuntimeException ) { elementInserted(evt); } //------------------------------------------------------------------------------ void SAL_CALL FmXFormView::elementRemoved(const ContainerEvent& /*evt*/) throw( RuntimeException ) { } //------------------------------------------------------------------------------ PFormViewPageWindowAdapter FmXFormView::findWindow( const Reference< XControlContainer >& _rxCC ) const { for ( PageWindowAdapterList::const_iterator i = m_aPageWindowAdapters.begin(); i != m_aPageWindowAdapters.end(); ++i ) { if ( _rxCC == (*i)->getControlContainer() ) return *i; } return NULL; } //------------------------------------------------------------------------------ void FmXFormView::addWindow(const SdrPageWindow& rWindow) { FmFormPage* pFormPage = PTR_CAST( FmFormPage, rWindow.GetPageView().GetPage() ); if ( !pFormPage ) return; Reference< XControlContainer > xCC = rWindow.GetControlContainer(); if ( xCC.is() && ( !findWindow( xCC ).is() ) ) { PFormViewPageWindowAdapter pAdapter = new FormViewPageWindowAdapter( m_aContext, rWindow, this ); m_aPageWindowAdapters.push_back( pAdapter ); // Am ControlContainer horchen um Aenderungen mitzbekommen Reference< XContainer > xContainer( xCC, UNO_QUERY ); if ( xContainer.is() ) xContainer->addContainerListener( this ); } } //------------------------------------------------------------------------------ void FmXFormView::removeWindow( const Reference< XControlContainer >& _rxCC ) { // Wird gerufen, wenn // - in den Design-Modus geschaltet wird // - ein Window geloescht wird, waehrend man im Design-Modus ist // - der Control-Container fuer ein Window entfernt wird, waehrend // der aktive Modus eingeschaltet ist. for ( PageWindowAdapterList::iterator i = m_aPageWindowAdapters.begin(); i != m_aPageWindowAdapters.end(); ++i ) { if ( _rxCC != (*i)->getControlContainer() ) continue; Reference< XContainer > xContainer( _rxCC, UNO_QUERY ); if ( xContainer.is() ) xContainer->removeContainerListener( this ); (*i)->dispose(); m_aPageWindowAdapters.erase( i ); break; } } //------------------------------------------------------------------------------ void FmXFormView::displayAsyncErrorMessage( const SQLErrorEvent& _rEvent ) { DBG_ASSERT( 0 == m_nErrorMessageEvent, "FmXFormView::displayAsyncErrorMessage: not too fast, please!" ); // This should not happen - usually, the PostUserEvent is faster than any possible user // interaction which could trigger a new error. If it happens, we need a queue for the events. m_aAsyncError = _rEvent; m_nErrorMessageEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnDelayedErrorMessage ) ); } //------------------------------------------------------------------------------ IMPL_LINK(FmXFormView, OnDelayedErrorMessage, void*, /*EMPTYTAG*/) { m_nErrorMessageEvent = 0; displayException( m_aAsyncError ); return 0L; } //------------------------------------------------------------------------------ void FmXFormView::onFirstViewActivation( const FmFormModel* _pDocModel ) { if ( _pDocModel && _pDocModel->GetAutoControlFocus() ) m_nAutoFocusEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnAutoFocus ) ); } //------------------------------------------------------------------------------ void FmXFormView::suspendTabOrderUpdate() { OSL_ENSURE( !m_isTabOrderUpdateSuspended, "FmXFormView::suspendTabOrderUpdate: nesting not allowed!" ); m_isTabOrderUpdateSuspended = true; } //------------------------------------------------------------------------------ void FmXFormView::resumeTabOrderUpdate() { OSL_ENSURE( m_isTabOrderUpdateSuspended, "FmXFormView::resumeTabOrderUpdate: not suspended!" ); m_isTabOrderUpdateSuspended = false; // update the tab orders for all components which were collected since the suspendTabOrderUpdate call. for ( MapControlContainerToSetOfForms::const_iterator container = m_aNeedTabOrderUpdate.begin(); container != m_aNeedTabOrderUpdate.end(); ++container ) { PFormViewPageWindowAdapter pAdapter = findWindow( container->first ); if ( !pAdapter.is() ) continue; for ( SetOfForms::const_iterator form = container->second.begin(); form != container->second.end(); ++form ) { pAdapter->updateTabOrder( *form ); } } m_aNeedTabOrderUpdate.clear(); } //------------------------------------------------------------------------------ IMPL_LINK(FmXFormView, OnActivate, void*, /*EMPTYTAG*/) { m_nActivationEvent = 0; if ( !m_pView ) { DBG_ERROR( "FmXFormView::OnActivate: well .... seems we have a timing problem (the view already died)!" ); return 0; } // setting the controller to activate if (m_pView->GetFormShell() && m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW) { Window* pWindow = const_cast(static_cast(m_pView->GetActualOutDev())); PFormViewPageWindowAdapter pAdapter = m_aPageWindowAdapters.empty() ? NULL : m_aPageWindowAdapters[0]; for ( PageWindowAdapterList::const_iterator i = m_aPageWindowAdapters.begin(); i != m_aPageWindowAdapters.end(); ++i ) { if ( pWindow == (*i)->getWindow() ) pAdapter =*i; } if ( pAdapter.get() ) { for ( ::std::vector< Reference< XFormController > >::const_iterator i = pAdapter->GetList().begin(); i != pAdapter->GetList().end(); ++i ) { const Reference< XFormController > & xController = *i; if ( !xController.is() ) continue; // only database forms are to be activated Reference< XRowSet > xForm(xController->getModel(), UNO_QUERY); if ( !xForm.is() || !OStaticDataAccessTools().getRowSetConnection( xForm ).is() ) continue; Reference< XPropertySet > xFormSet( xForm, UNO_QUERY ); ENSURE_OR_CONTINUE( xFormSet.is(), "FmXFormView::OnActivate: a form which does not have properties?" ); const ::rtl::OUString aSource = ::comphelper::getString( xFormSet->getPropertyValue( FM_PROP_COMMAND ) ); if ( aSource.getLength() ) { FmXFormShell* pShImpl = m_pView->GetFormShell()->GetImpl(); if ( pShImpl ) pShImpl->setActiveController( xController ); break; } } } } return 0; } //------------------------------------------------------------------------------ void FmXFormView::Activate(sal_Bool bSync) { if (m_nActivationEvent) { Application::RemoveUserEvent(m_nActivationEvent); m_nActivationEvent = 0; } if (bSync) { LINK(this,FmXFormView,OnActivate).Call(NULL); } else m_nActivationEvent = Application::PostUserEvent(LINK(this,FmXFormView,OnActivate)); } //------------------------------------------------------------------------------ void FmXFormView::Deactivate(sal_Bool bDeactivateController) { if (m_nActivationEvent) { Application::RemoveUserEvent(m_nActivationEvent); m_nActivationEvent = 0; } FmXFormShell* pShImpl = m_pView->GetFormShell() ? m_pView->GetFormShell()->GetImpl() : NULL; if (pShImpl && bDeactivateController) pShImpl->setActiveController( NULL ); } //------------------------------------------------------------------------------ FmFormShell* FmXFormView::GetFormShell() const { return m_pView ? m_pView->GetFormShell() : NULL; } // ----------------------------------------------------------------------------- void FmXFormView::AutoFocus( sal_Bool _bSync ) { if (m_nAutoFocusEvent) Application::RemoveUserEvent(m_nAutoFocusEvent); if ( _bSync ) OnAutoFocus( NULL ); else m_nAutoFocusEvent = Application::PostUserEvent(LINK(this, FmXFormView, OnAutoFocus)); } // ----------------------------------------------------------------------------- bool FmXFormView::isFocusable( const Reference< XControl >& i_rControl ) { if ( !i_rControl.is() ) return false; try { Reference< XPropertySet > xModelProps( i_rControl->getModel(), UNO_QUERY_THROW ); // only enabled controls are allowed to participate sal_Bool bEnabled = sal_False; OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_ENABLED ) >>= bEnabled ); if ( !bEnabled ) return false; // check the class id of the control model sal_Int16 nClassId = FormComponentType::CONTROL; OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId ); // controls which are not focussable if ( ( FormComponentType::CONTROL != nClassId ) && ( FormComponentType::IMAGEBUTTON != nClassId ) && ( FormComponentType::GROUPBOX != nClassId ) && ( FormComponentType::FIXEDTEXT != nClassId ) && ( FormComponentType::HIDDENCONTROL != nClassId ) && ( FormComponentType::IMAGECONTROL != nClassId ) && ( FormComponentType::SCROLLBAR != nClassId ) && ( FormComponentType::SPINBUTTON!= nClassId ) ) { return true; } } catch( const Exception& e ) { DBG_UNHANDLED_EXCEPTION(); } return false; } // ----------------------------------------------------------------------------- static Reference< XControl > lcl_firstFocussableControl( const Sequence< Reference< XControl > >& _rControls ) { Reference< XControl > xReturn; // loop through all the controls const Reference< XControl >* pControls = _rControls.getConstArray(); const Reference< XControl >* pControlsEnd = _rControls.getConstArray() + _rControls.getLength(); for ( ; pControls != pControlsEnd; ++pControls ) { if ( !pControls->is() ) continue; if ( FmXFormView::isFocusable( *pControls ) ) { xReturn = *pControls; break; } } if ( !xReturn.is() && _rControls.getLength() ) xReturn = _rControls[0]; return xReturn; } // ----------------------------------------------------------------------------- namespace { // ......................................................................... void lcl_ensureControlsOfFormExist_nothrow( const SdrPage& _rPage, const SdrView& _rView, const Window& _rWindow, const Reference< XForm >& _rxForm ) { try { Reference< XInterface > xNormalizedForm( _rxForm, UNO_QUERY_THROW ); SdrObjListIter aSdrObjectLoop( _rPage, IM_DEEPNOGROUPS ); while ( aSdrObjectLoop.IsMore() ) { FmFormObj* pFormObject = FmFormObj::GetFormObject( aSdrObjectLoop.Next() ); if ( !pFormObject ) continue; Reference< XChild > xModel( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW ); Reference< XInterface > xModelParent( xModel->getParent(), UNO_QUERY_THROW ); if ( xNormalizedForm.get() != xModelParent.get() ) continue; pFormObject->GetUnoControl( _rView, _rWindow ); } } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } } } // ----------------------------------------------------------------------------- Reference< XFormController > FmXFormView::getFormController( const Reference< XForm >& _rxForm, const OutputDevice& _rDevice ) const { Reference< XFormController > xController; for ( PageWindowAdapterList::const_iterator pos = m_aPageWindowAdapters.begin(); pos != m_aPageWindowAdapters.end(); ++pos ) { const PFormViewPageWindowAdapter pAdapter( *pos ); ENSURE_OR_CONTINUE( pAdapter.get(), "FmXFormView::getFormController: invalid page window adapter!" ); if ( pAdapter->getWindow() != &_rDevice ) // wrong device continue; xController = pAdapter->getController( _rxForm ); if ( xController.is() ) break; } return xController; } // ----------------------------------------------------------------------------- IMPL_LINK(FmXFormView, OnAutoFocus, void*, /*EMPTYTAG*/) { m_nAutoFocusEvent = 0; // go to the first form of our page, examine it's TabController, go to it's first (in terms of the tab order) // control, give it the focus do { // get the forms collection of the page we belong to FmFormPage* pPage = m_pView ? PTR_CAST( FmFormPage, m_pView->GetSdrPageView()->GetPage() ) : NULL; Reference< XIndexAccess > xForms( pPage ? Reference< XIndexAccess >( pPage->GetForms(), UNO_QUERY ) : Reference< XIndexAccess >() ); const PFormViewPageWindowAdapter pAdapter = m_aPageWindowAdapters.empty() ? NULL : m_aPageWindowAdapters[0]; const Window* pWindow = pAdapter.get() ? pAdapter->getWindow() : NULL; ENSURE_OR_RETURN( xForms.is() && pWindow, "FmXFormView::OnAutoFocus: could not collect all essentials!", 0L ); try { // go for the tab controller of the first form if ( !xForms->getCount() ) break; Reference< XForm > xForm( xForms->getByIndex( 0 ), UNO_QUERY_THROW ); Reference< XTabController > xTabController( pAdapter->getController( xForm ), UNO_QUERY_THROW ); // go for the first control of the controller Sequence< Reference< XControl > > aControls( xTabController->getControls() ); if ( aControls.getLength() == 0 ) { Reference< XElementAccess > xFormElementAccess( xForm, UNO_QUERY_THROW ); if ( xFormElementAccess->hasElements() ) { // there are control models in the form, but no controls, yet. // Well, since some time controls are created on demand only. In particular, // they're normally created when they're first painted. // Unfortunately, the FormController does not have any way to // trigger the creation itself, so we must hack this ... lcl_ensureControlsOfFormExist_nothrow( *pPage, *m_pView, *pWindow, xForm ); aControls = xTabController->getControls(); OSL_ENSURE( aControls.getLength(), "FmXFormView::OnAutoFocus: no controls at all!" ); } } // set the focus to this first control Reference< XWindow > xControlWindow( lcl_firstFocussableControl( aControls ), UNO_QUERY ); if ( !xControlWindow.is() ) break; xControlWindow->setFocus(); // ensure that the control is visible // 80210 - 12/07/00 - FS const Window* pCurrentWindow = dynamic_cast< const Window* >( m_pView->GetActualOutDev() ); if ( pCurrentWindow ) { awt::Rectangle aRect = xControlWindow->getPosSize(); ::Rectangle aNonUnoRect( aRect.X, aRect.Y, aRect.X + aRect.Width, aRect.Y + aRect.Height ); m_pView->MakeVisible( pCurrentWindow->PixelToLogic( aNonUnoRect ), *const_cast< Window* >( pCurrentWindow ) ); } } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } } // do while ( false ); return 1L; } // ----------------------------------------------------------------------------- void FmXFormView::onCreatedFormObject( FmFormObj& _rFormObject ) { FmFormShell* pShell = m_pView ? m_pView->GetFormShell() : NULL; FmXFormShell* pShellImpl = pShell ? pShell->GetImpl() : NULL; OSL_ENSURE( pShellImpl, "FmXFormView::onCreatedFormObject: no form shell!" ); if ( !pShellImpl ) return; // it is valid that the form shell's forms collection is not initialized, yet pShellImpl->UpdateForms( sal_True ); m_xLastCreatedControlModel.set( _rFormObject.GetUnoControlModel(), UNO_QUERY ); if ( !m_xLastCreatedControlModel.is() ) return; // some initial property defaults FormControlFactory aControlFactory( m_aContext ); aControlFactory.initializeControlModel( pShellImpl->getDocumentType(), _rFormObject ); if ( !pShellImpl->GetWizardUsing() ) return; // #i31958# don't call wizards in XForms mode if ( pShellImpl->isEnhancedForm() ) return; // #i46898# no wizards if there is no Base installed - currently, all wizards are // database related if ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::E_SDATABASE ) ) return; if ( m_nControlWizardEvent ) Application::RemoveUserEvent( m_nControlWizardEvent ); m_nControlWizardEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnStartControlWizard ) ); } // ----------------------------------------------------------------------------- IMPL_LINK( FmXFormView, OnStartControlWizard, void*, /**/ ) { m_nControlWizardEvent = 0; OSL_PRECOND( m_xLastCreatedControlModel.is(), "FmXFormView::OnStartControlWizard: illegal call!" ); if ( !m_xLastCreatedControlModel.is() ) return 0L; sal_Int16 nClassId = FormComponentType::CONTROL; try { OSL_VERIFY( m_xLastCreatedControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId ); } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } const sal_Char* pWizardAsciiName = NULL; switch ( nClassId ) { case FormComponentType::GRIDCONTROL: pWizardAsciiName = "com.sun.star.sdb.GridControlAutoPilot"; break; case FormComponentType::LISTBOX: case FormComponentType::COMBOBOX: pWizardAsciiName = "com.sun.star.sdb.ListComboBoxAutoPilot"; break; case FormComponentType::GROUPBOX: pWizardAsciiName = "com.sun.star.sdb.GroupBoxAutoPilot"; break; } if ( pWizardAsciiName ) { // build the argument list ::comphelper::NamedValueCollection aWizardArgs; aWizardArgs.put( "ObjectModel", m_xLastCreatedControlModel ); // create the wizard object Reference< XExecutableDialog > xWizard; try { m_aContext.createComponentWithArguments( pWizardAsciiName, aWizardArgs.getWrappedPropertyValues(), xWizard ); } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } if ( !xWizard.is() ) { ShowServiceNotAvailableError( NULL, String::CreateFromAscii( pWizardAsciiName ), sal_True ); } else { // execute the wizard try { xWizard->execute(); } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } } } m_xLastCreatedControlModel.clear(); return 1L; } // ----------------------------------------------------------------------------- namespace { void lcl_insertIntoFormComponentHierarchy_throw( const FmFormView& _rView, const SdrUnoObj& _rSdrObj, const Reference< XDataSource >& _rxDataSource = NULL, const ::rtl::OUString& _rDataSourceName = ::rtl::OUString(), const ::rtl::OUString& _rCommand = ::rtl::OUString(), const sal_Int32 _nCommandType = -1 ) { FmFormPage& rPage = static_cast< FmFormPage& >( *_rView.GetSdrPageView()->GetPage() ); Reference< XFormComponent > xFormComponent( _rSdrObj.GetUnoControlModel(), UNO_QUERY_THROW ); Reference< XForm > xTargetForm( rPage.GetImpl().findPlaceInFormComponentHierarchy( xFormComponent, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType ), UNO_SET_THROW ); rPage.GetImpl().setUniqueName( xFormComponent, xTargetForm ); Reference< XIndexContainer > xFormAsContainer( xTargetForm, UNO_QUERY_THROW ); xFormAsContainer->insertByIndex( xFormAsContainer->getCount(), makeAny( xFormComponent ) ); } } // ----------------------------------------------------------------------------- SdrObject* FmXFormView::implCreateFieldControl( const ::svx::ODataAccessDescriptor& _rColumnDescriptor ) { // not if we're in design mode if ( !m_pView->IsDesignMode() ) return NULL; ::rtl::OUString sCommand, sFieldName; sal_Int32 nCommandType = CommandType::COMMAND; SharedConnection xConnection; ::rtl::OUString sDataSource = _rColumnDescriptor.getDataSource(); _rColumnDescriptor[ daCommand ] >>= sCommand; _rColumnDescriptor[ daColumnName ] >>= sFieldName; _rColumnDescriptor[ daCommandType ] >>= nCommandType; { Reference< XConnection > xExternalConnection; _rColumnDescriptor[ daConnection ] >>= xExternalConnection; xConnection.reset( xExternalConnection, SharedConnection::NoTakeOwnership ); } if ( !sCommand.getLength() || !sFieldName.getLength() || ( !sDataSource.getLength() && !xConnection.is() ) ) { DBG_ERROR( "FmXFormView::implCreateFieldControl: nonsense!" ); } Reference< XDataSource > xDataSource; SQLErrorEvent aError; try { if ( xConnection.is() && !xDataSource.is() && !sDataSource.getLength() ) { Reference< XChild > xChild( xConnection, UNO_QUERY ); if ( xChild.is() ) xDataSource = xDataSource.query( xChild->getParent() ); } // obtain the data source if ( !xDataSource.is() ) xDataSource = OStaticDataAccessTools().getDataSource( sDataSource, m_aContext.getLegacyServiceFactory() ); // and the connection, if necessary if ( !xConnection.is() ) xConnection.reset( OStaticDataAccessTools().getConnection_withFeedback( sDataSource, ::rtl::OUString(), ::rtl::OUString(), m_aContext.getLegacyServiceFactory() ) ); } catch ( const SQLException& ) { aError.Reason = ::cppu::getCaughtException(); } catch( const Exception& ) { /* will be asserted below */ } if (aError.Reason.hasValue()) { displayAsyncErrorMessage( aError ); return NULL; } // need a data source and a connection here if (!xDataSource.is() || !xConnection.is()) { DBG_ERROR("FmXFormView::implCreateFieldControl : could not retrieve the data source or the connection!"); return NULL; } OStaticDataAccessTools aDBATools; Reference< XComponent > xKeepFieldsAlive; // go try { // determine the table/query field which we should create a control for Reference< XPropertySet > xField; Reference< XNameAccess > xFields = aDBATools.getFieldsByCommandDescriptor( xConnection, nCommandType, sCommand, xKeepFieldsAlive ); if (xFields.is() && xFields->hasByName(sFieldName)) xFields->getByName(sFieldName) >>= xField; if ( !xField.is() ) return NULL; Reference< XNumberFormatsSupplier > xSupplier( aDBATools.getNumberFormats( xConnection, sal_False ), UNO_SET_THROW ); Reference< XNumberFormats > xNumberFormats( xSupplier->getNumberFormats(), UNO_SET_THROW ); ::rtl::OUString sLabelPostfix; //////////////////////////////////////////////////////////////// // nur fuer Textgroesse OutputDevice* pOutDev = NULL; if (m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW) pOutDev = const_cast(m_pView->GetActualOutDev()); else {// OutDev suchen SdrPageView* pPageView = m_pView->GetSdrPageView(); if( pPageView && !pOutDev ) { // const SdrPageViewWinList& rWinList = pPageView->GetWinList(); // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows(); for( sal_uInt32 i = 0L; i < pPageView->PageWindowCount(); i++ ) { const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i); if( rPageWindow.GetPaintWindow().OutputToWindow()) { pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice(); break; } } } } if ( !pOutDev ) return NULL; sal_Int32 nDataType = ::comphelper::getINT32(xField->getPropertyValue(FM_PROP_FIELDTYPE)); if ((DataType::BINARY == nDataType) || (DataType::VARBINARY == nDataType)) return NULL; ////////////////////////////////////////////////////////////////////// // determine the control type by examining the data type of the bound column sal_uInt16 nOBJID = 0; sal_Bool bDateNTimeField = sal_False; sal_Bool bIsCurrency = sal_False; if (::comphelper::hasProperty(FM_PROP_ISCURRENCY, xField)) bIsCurrency = ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISCURRENCY)); if (bIsCurrency) nOBJID = OBJ_FM_CURRENCYFIELD; else switch (nDataType) { case DataType::BLOB: case DataType::LONGVARBINARY: nOBJID = OBJ_FM_IMAGECONTROL; break; case DataType::LONGVARCHAR: case DataType::CLOB: nOBJID = OBJ_FM_EDIT; break; case DataType::BINARY: case DataType::VARBINARY: return NULL; case DataType::BIT: case DataType::BOOLEAN: nOBJID = OBJ_FM_CHECKBOX; break; case DataType::TINYINT: case DataType::SMALLINT: case DataType::INTEGER: nOBJID = OBJ_FM_NUMERICFIELD; break; case DataType::REAL: case DataType::DOUBLE: case DataType::NUMERIC: case DataType::DECIMAL: nOBJID = OBJ_FM_FORMATTEDFIELD; break; case DataType::TIMESTAMP: bDateNTimeField = sal_True; sLabelPostfix = String( SVX_RES( RID_STR_POSTFIX_DATE ) ); // DON'T break ! case DataType::DATE: nOBJID = OBJ_FM_DATEFIELD; break; case DataType::TIME: nOBJID = OBJ_FM_TIMEFIELD; break; case DataType::CHAR: case DataType::VARCHAR: default: nOBJID = OBJ_FM_EDIT; break; } if (!nOBJID) return NULL; SdrUnoObj* pLabel( NULL ); SdrUnoObj* pControl( NULL ); if ( !createControlLabelPair( *pOutDev, 0, 0, xField, xNumberFormats, nOBJID, sLabelPostfix, pLabel, pControl, xDataSource, sDataSource, sCommand, nCommandType ) ) { return NULL; } ////////////////////////////////////////////////////////////////////// // group objects bool bCheckbox = ( OBJ_FM_CHECKBOX == nOBJID ); OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateFieldControl: why was there a label created for a check box?" ); if ( bCheckbox ) return pControl; SdrObjGroup* pGroup = new SdrObjGroup(); SdrObjList* pObjList = pGroup->GetSubList(); pObjList->InsertObject( pLabel ); pObjList->InsertObject( pControl ); if ( bDateNTimeField ) { // so far we created a date field only, but we also need a time field pLabel = pControl = NULL; if ( createControlLabelPair( *pOutDev, 0, 1000, xField, xNumberFormats, OBJ_FM_TIMEFIELD, String( SVX_RES( RID_STR_POSTFIX_TIME ) ), pLabel, pControl, xDataSource, sDataSource, sCommand, nCommandType ) ) { pObjList->InsertObject( pLabel ); pObjList->InsertObject( pControl ); } } return pGroup; // und fertig } catch(const Exception&) { DBG_UNHANDLED_EXCEPTION(); } return NULL; } // ----------------------------------------------------------------------------- SdrObject* FmXFormView::implCreateXFormsControl( const ::svx::OXFormsDescriptor &_rDesc ) { // not if we're in design mode if ( !m_pView->IsDesignMode() ) return NULL; Reference< XComponent > xKeepFieldsAlive; // go try { // determine the table/query field which we should create a control for Reference< XNumberFormats > xNumberFormats; ::rtl::OUString sLabelPostfix = _rDesc.szName; //////////////////////////////////////////////////////////////// // nur fuer Textgroesse OutputDevice* pOutDev = NULL; if (m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW) pOutDev = const_cast(m_pView->GetActualOutDev()); else {// OutDev suchen SdrPageView* pPageView = m_pView->GetSdrPageView(); if( pPageView && !pOutDev ) { // const SdrPageViewWinList& rWinList = pPageView->GetWinList(); // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows(); for( sal_uInt32 i = 0L; i < pPageView->PageWindowCount(); i++ ) { const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i); if( rPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType() == OUTDEV_WINDOW) { pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice(); break; } } } } if ( !pOutDev ) return NULL; ////////////////////////////////////////////////////////////////////// // The service name decides which control should be created sal_uInt16 nOBJID = OBJ_FM_EDIT; if(::rtl::OUString(_rDesc.szServiceName).equals((::rtl::OUString)FM_SUN_COMPONENT_NUMERICFIELD)) nOBJID = OBJ_FM_NUMERICFIELD; if(::rtl::OUString(_rDesc.szServiceName).equals((::rtl::OUString)FM_SUN_COMPONENT_CHECKBOX)) nOBJID = OBJ_FM_CHECKBOX; if(::rtl::OUString(_rDesc.szServiceName).equals((::rtl::OUString)FM_COMPONENT_COMMANDBUTTON)) nOBJID = OBJ_FM_BUTTON; typedef ::com::sun::star::form::submission::XSubmission XSubmission_t; Reference< XSubmission_t > xSubmission(_rDesc.xPropSet, UNO_QUERY); // xform control or submission button? if ( !xSubmission.is() ) { SdrUnoObj* pLabel( NULL ); SdrUnoObj* pControl( NULL ); if ( !createControlLabelPair( *pOutDev, 0, 0, NULL, xNumberFormats, nOBJID, sLabelPostfix, pLabel, pControl ) ) { return NULL; } ////////////////////////////////////////////////////////////////////// // Now build the connection between the control and the data item. Reference< XValueBinding > xValueBinding(_rDesc.xPropSet,UNO_QUERY); Reference< XBindableValue > xBindableValue(pControl->GetUnoControlModel(),UNO_QUERY); DBG_ASSERT( xBindableValue.is(), "FmXFormView::implCreateXFormsControl: control's not bindable!" ); if ( xBindableValue.is() ) xBindableValue->setValueBinding(xValueBinding); bool bCheckbox = ( OBJ_FM_CHECKBOX == nOBJID ); OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateXFormsControl: why was there a label created for a check box?" ); if ( bCheckbox ) return pControl; ////////////////////////////////////////////////////////////////////// // group objects SdrObjGroup* pGroup = new SdrObjGroup(); SdrObjList* pObjList = pGroup->GetSubList(); pObjList->InsertObject(pLabel); pObjList->InsertObject(pControl); return pGroup; } else { // create a button control const MapMode eTargetMode( pOutDev->GetMapMode() ); const MapMode eSourceMode(MAP_100TH_MM); const sal_uInt16 nObjID = OBJ_FM_BUTTON; ::Size controlSize(4000, 500); FmFormObj *pControl = static_cast(SdrObjFactory::MakeNewObject( FmFormInventor, nObjID, NULL, NULL )); controlSize.Width() = Fraction(controlSize.Width(), 1) * eTargetMode.GetScaleX(); controlSize.Height() = Fraction(controlSize.Height(), 1) * eTargetMode.GetScaleY(); ::Point controlPos( pOutDev->LogicToLogic( ::Point( controlSize.Width(), 0 ), eSourceMode, eTargetMode ) ); ::Rectangle controlRect( controlPos, pOutDev->LogicToLogic( controlSize, eSourceMode, eTargetMode ) ); pControl->SetLogicRect(controlRect); // set the button label Reference< XPropertySet > xControlSet(pControl->GetUnoControlModel(), UNO_QUERY); xControlSet->setPropertyValue(FM_PROP_LABEL, makeAny(::rtl::OUString(_rDesc.szName))); // connect the submission with the submission supplier (aka the button) xControlSet->setPropertyValue( FM_PROP_BUTTON_TYPE, makeAny( FormButtonType_SUBMIT ) ); typedef ::com::sun::star::form::submission::XSubmissionSupplier XSubmissionSupplier_t; Reference< XSubmissionSupplier_t > xSubmissionSupplier(pControl->GetUnoControlModel(), UNO_QUERY); xSubmissionSupplier->setSubmission(xSubmission); return pControl; } } catch(const Exception&) { DBG_ERROR("FmXFormView::implCreateXFormsControl: caught an exception while creating the control !"); } return NULL; } //------------------------------------------------------------------------ bool FmXFormView::createControlLabelPair( OutputDevice& _rOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM, const Reference< XPropertySet >& _rxField, const Reference< XNumberFormats >& _rxNumberFormats, sal_uInt16 _nControlObjectID, const ::rtl::OUString& _rFieldPostfix, SdrUnoObj*& _rpLabel, SdrUnoObj*& _rpControl, const Reference< XDataSource >& _rxDataSource, const ::rtl::OUString& _rDataSourceName, const ::rtl::OUString& _rCommand, const sal_Int32 _nCommandType ) { if ( !createControlLabelPair( m_aContext, _rOutDev, _nXOffsetMM, _nYOffsetMM, _rxField, _rxNumberFormats, _nControlObjectID, _rFieldPostfix, FmFormInventor, OBJ_FM_FIXEDTEXT, NULL, NULL, NULL, _rpLabel, _rpControl ) ) return false; // insert the control model(s) into the form component hierarchy if ( _rpLabel ) lcl_insertIntoFormComponentHierarchy_throw( *m_pView, *_rpLabel, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType ); lcl_insertIntoFormComponentHierarchy_throw( *m_pView, *_rpControl, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType ); // some context-dependent initializations FormControlFactory aControlFactory( m_aContext ); if ( _rpLabel ) aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpLabel ); aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpControl ); return true; } //------------------------------------------------------------------------ bool FmXFormView::createControlLabelPair( const ::comphelper::ComponentContext& _rContext, OutputDevice& _rOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM, const Reference< XPropertySet >& _rxField, const Reference< XNumberFormats >& _rxNumberFormats, sal_uInt16 _nControlObjectID, const ::rtl::OUString& _rFieldPostfix, sal_uInt32 _nInventor, sal_uInt16 _nLabelObjectID, SdrPage* _pLabelPage, SdrPage* _pControlPage, SdrModel* _pModel, SdrUnoObj*& _rpLabel, SdrUnoObj*& _rpControl) { sal_Int32 nDataType = 0; ::rtl::OUString sFieldName; Any aFieldName; if ( _rxField.is() ) { nDataType = ::comphelper::getINT32(_rxField->getPropertyValue(FM_PROP_FIELDTYPE)); aFieldName = Any(_rxField->getPropertyValue(FM_PROP_NAME)); aFieldName >>= sFieldName; } // calculate the positions, respecting the settings of the target device ::Size aTextSize( _rOutDev.GetTextWidth(sFieldName + _rFieldPostfix), _rOutDev.GetTextHeight() ); MapMode eTargetMode( _rOutDev.GetMapMode() ), eSourceMode( MAP_100TH_MM ); // Textbreite ist mindestens 4cm // Texthoehe immer halber cm ::Size aDefTxtSize(4000, 500); ::Size aDefSize(4000, 500); ::Size aDefImageSize(4000, 4000); ::Size aRealSize = _rOutDev.LogicToLogic(aTextSize, eTargetMode, eSourceMode); aRealSize.Width() = std::max(aRealSize.Width(), aDefTxtSize.Width()); aRealSize.Height()= aDefSize.Height(); // adjust to scaling of the target device (#53523#) aRealSize.Width() = long(Fraction(aRealSize.Width(), 1) * eTargetMode.GetScaleX()); aRealSize.Height() = long(Fraction(aRealSize.Height(), 1) * eTargetMode.GetScaleY()); // for boolean fields, we do not create a label, but just a checkbox bool bNeedLabel = ( _nControlObjectID != OBJ_FM_CHECKBOX ); // the label ::std::auto_ptr< SdrUnoObj > pLabel; Reference< XPropertySet > xLabelModel; if ( bNeedLabel ) { pLabel.reset( dynamic_cast< SdrUnoObj* >( SdrObjFactory::MakeNewObject( _nInventor, _nLabelObjectID, _pLabelPage, _pModel ) ) ); OSL_ENSURE( pLabel.get(), "FmXFormView::createControlLabelPair: could not create the label!" ); if ( !pLabel.get() ) return false; xLabelModel.set( pLabel->GetUnoControlModel(), UNO_QUERY ); if ( xLabelModel.is() ) { ::rtl::OUString sLabel; if ( _rxField.is() && _rxField->getPropertySetInfo()->hasPropertyByName(FM_PROP_LABEL) ) _rxField->getPropertyValue(FM_PROP_LABEL) >>= sLabel; if ( !sLabel.getLength() ) sLabel = sFieldName; xLabelModel->setPropertyValue( FM_PROP_LABEL, makeAny( sLabel + _rFieldPostfix ) ); String sObjectLabel( SVX_RES( RID_STR_OBJECT_LABEL ) ); sObjectLabel.SearchAndReplaceAllAscii( "#object#", sFieldName ); xLabelModel->setPropertyValue( FM_PROP_NAME, makeAny( ::rtl::OUString( sObjectLabel ) ) ); } pLabel->SetLogicRect( ::Rectangle( _rOutDev.LogicToLogic( ::Point( _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ), _rOutDev.LogicToLogic( aRealSize, eSourceMode, eTargetMode ) ) ); } // the control ::std::auto_ptr< SdrUnoObj > pControl( dynamic_cast< SdrUnoObj* >( SdrObjFactory::MakeNewObject( _nInventor, _nControlObjectID, _pControlPage, _pModel ) ) ); OSL_ENSURE( pControl.get(), "FmXFormView::createControlLabelPair: could not create the control!" ); if ( !pControl.get() ) return false; Reference< XPropertySet > xControlSet( pControl->GetUnoControlModel(), UNO_QUERY ); if ( !xControlSet.is() ) return false; // size of the control ::Size aControlSize( aDefSize ); switch ( nDataType ) { case DataType::BIT: case DataType::BOOLEAN: aControlSize = aDefSize; break; case DataType::LONGVARCHAR: case DataType::CLOB: case DataType::LONGVARBINARY: case DataType::BLOB: aControlSize = aDefImageSize; break; } if ( OBJ_FM_IMAGECONTROL == _nControlObjectID ) aControlSize = aDefImageSize; aControlSize.Width() = long(Fraction(aControlSize.Width(), 1) * eTargetMode.GetScaleX()); aControlSize.Height() = long(Fraction(aControlSize.Height(), 1) * eTargetMode.GetScaleY()); pControl->SetLogicRect( ::Rectangle( _rOutDev.LogicToLogic( ::Point( aRealSize.Width() + _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ), _rOutDev.LogicToLogic( aControlSize, eSourceMode, eTargetMode ) ) ); // some initializations Reference< XPropertySetInfo > xControlPropInfo = xControlSet->getPropertySetInfo(); if ( aFieldName.hasValue() ) { xControlSet->setPropertyValue( FM_PROP_CONTROLSOURCE, aFieldName ); xControlSet->setPropertyValue( FM_PROP_NAME, aFieldName ); if ( !bNeedLabel ) { // no dedicated label control => use the label property if ( xControlPropInfo->hasPropertyByName( FM_PROP_LABEL ) ) xControlSet->setPropertyValue( FM_PROP_LABEL, makeAny( sFieldName + _rFieldPostfix ) ); else OSL_ENSURE( false, "FmXFormView::createControlLabelPair: can't set a label for the control!" ); } } if ( (nDataType == DataType::LONGVARCHAR || nDataType == DataType::CLOB) && xControlPropInfo->hasPropertyByName( FM_PROP_MULTILINE ) ) { xControlSet->setPropertyValue( FM_PROP_MULTILINE, makeAny( sal_Bool( sal_True ) ) ); } // announce the label to the control if ( xControlPropInfo->hasPropertyByName( FM_PROP_CONTROLLABEL ) && xLabelModel.is() ) { try { xControlSet->setPropertyValue( FM_PROP_CONTROLLABEL, makeAny( xLabelModel ) ); } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } } if ( _rxField.is() ) { FormControlFactory aControlFactory( _rContext ); aControlFactory.initializeFieldDependentProperties( _rxField, xControlSet, _rxNumberFormats ); } _rpLabel = pLabel.release(); _rpControl = pControl.release(); return true; } //------------------------------------------------------------------------------ FmXFormView::ObjectRemoveListener::ObjectRemoveListener( FmXFormView* pParent ) :m_pParent( pParent ) { } //------------------------------------------------------------------------------ void FmXFormView::ObjectRemoveListener::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) { if (rHint.ISA(SdrHint) && (((SdrHint&)rHint).GetKind() == HINT_OBJREMOVED)) m_pParent->ObjectRemovedInAliveMode(((SdrHint&)rHint).GetObject()); } //------------------------------------------------------------------------------ void FmXFormView::ObjectRemovedInAliveMode( const SdrObject* pObject ) { // wenn das entfernte Objekt in meiner MarkList, die ich mir beim Umschalten in den Alive-Mode gemerkt habe, steht, // muss ich es jetzt da rausnehmen, da ich sonst beim Zurueckschalten versuche, die Markierung wieder zu setzen // (interesanterweise geht das nur bei gruppierten Objekten schief (beim Zugriff auf deren ObjList GPF), nicht bei einzelnen) sal_uIntPtr nCount = m_aMark.GetMarkCount(); for (sal_uIntPtr i = 0; i < nCount; ++i) { SdrMark* pMark = m_aMark.GetMark(i); SdrObject* pCurrent = pMark->GetMarkedSdrObj(); if (pObject == pCurrent) { m_aMark.DeleteMark(i); return; } // ich brauche nicht in GroupObjects absteigen : wenn dort unten ein Objekt geloescht wird, dann bleibt der // Zeiger auf das GroupObject, den ich habe, trotzdem weiter gueltig bleibt ... } } //------------------------------------------------------------------------------ void FmXFormView::stopMarkListWatching() { if ( m_pWatchStoredList ) { m_pWatchStoredList->EndListeningAll(); delete m_pWatchStoredList; m_pWatchStoredList = NULL; } } //------------------------------------------------------------------------------ void FmXFormView::startMarkListWatching() { if ( !m_pWatchStoredList ) { m_pWatchStoredList = new ObjectRemoveListener( this ); FmFormModel* pModel = GetFormShell() ? GetFormShell()->GetFormModel() : NULL; DBG_ASSERT( pModel != NULL, "FmXFormView::startMarkListWatching: shell has no model!" ); m_pWatchStoredList->StartListening( *static_cast< SfxBroadcaster* >( pModel ) ); } else { DBG_ERROR( "FmXFormView::startMarkListWatching: already listening!" ); } } //------------------------------------------------------------------------------ void FmXFormView::saveMarkList( sal_Bool _bSmartUnmark ) { if ( m_pView ) { m_aMark = m_pView->GetMarkedObjectList(); if ( _bSmartUnmark ) { sal_uIntPtr nCount = m_aMark.GetMarkCount( ); for ( sal_uIntPtr i = 0; i < nCount; ++i ) { SdrMark* pMark = m_aMark.GetMark(i); SdrObject* pObj = pMark->GetMarkedSdrObj(); if ( m_pView->IsObjMarked( pObj ) ) { if ( pObj->IsGroupObject() ) { SdrObjListIter aIter( *pObj->GetSubList() ); sal_Bool bMixed = sal_False; while ( aIter.IsMore() && !bMixed ) bMixed = ( aIter.Next()->GetObjInventor() != FmFormInventor ); if ( !bMixed ) { // all objects in the group are form objects m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), sal_True /* unmark! */ ); } } else { if ( pObj->GetObjInventor() == FmFormInventor ) { // this is a form layer object m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), sal_True /* unmark! */ ); } } } } } } else { DBG_ERROR( "FmXFormView::saveMarkList: invalid view!" ); m_aMark = SdrMarkList(); } } //-------------------------------------------------------------------------- static sal_Bool lcl_hasObject( SdrObjListIter& rIter, SdrObject* pObj ) { sal_Bool bFound = sal_False; while (rIter.IsMore() && !bFound) bFound = pObj == rIter.Next(); rIter.Reset(); return bFound; } //------------------------------------------------------------------------------ void FmXFormView::restoreMarkList( SdrMarkList& _rRestoredMarkList ) { if ( !m_pView ) return; _rRestoredMarkList.Clear(); const SdrMarkList& rCurrentList = m_pView->GetMarkedObjectList(); FmFormPage* pPage = GetFormShell() ? GetFormShell()->GetCurPage() : NULL; if (pPage) { if (rCurrentList.GetMarkCount()) { // there is a current mark ... hmm. Is it a subset of the mark we remembered in saveMarkList? sal_Bool bMisMatch = sal_False; // loop through all current marks sal_uIntPtr nCurrentCount = rCurrentList.GetMarkCount(); for ( sal_uIntPtr i=0; iGetMarkedSdrObj(); // loop through all saved marks, check for equality sal_Bool bFound = sal_False; sal_uIntPtr nSavedCount = m_aMark.GetMarkCount(); for ( sal_uIntPtr j=0; jGetMarkedSdrObj() == pCurrentMarked ) bFound = sal_True; } // did not find a current mark in the saved marks if ( !bFound ) bMisMatch = sal_True; } if ( bMisMatch ) { m_aMark.Clear(); _rRestoredMarkList = rCurrentList; return; } } // wichtig ist das auf die Objecte der markliste nicht zugegriffen wird // da diese bereits zerstoert sein koennen SdrPageView* pCurPageView = m_pView->GetSdrPageView(); SdrObjListIter aPageIter( *pPage ); sal_Bool bFound = sal_True; // gibt es noch alle Objecte sal_uIntPtr nCount = m_aMark.GetMarkCount(); for (sal_uIntPtr i = 0; i < nCount && bFound; i++) { SdrMark* pMark = m_aMark.GetMark(i); SdrObject* pObj = pMark->GetMarkedSdrObj(); if (pObj->IsGroupObject()) { SdrObjListIter aIter(*pObj->GetSubList()); while (aIter.IsMore() && bFound) bFound = lcl_hasObject(aPageIter, aIter.Next()); } else bFound = lcl_hasObject(aPageIter, pObj); bFound = bFound && pCurPageView == pMark->GetPageView(); } if (bFound) { // Das LastObject auswerten if (nCount) // Objecte jetzt Markieren { for (sal_uIntPtr i = 0; i < nCount; i++) { SdrMark* pMark = m_aMark.GetMark(i); SdrObject* pObj = pMark->GetMarkedSdrObj(); if ( pObj->GetObjInventor() == FmFormInventor ) if ( !m_pView->IsObjMarked( pObj ) ) m_pView->MarkObj( pObj, pMark->GetPageView() ); } _rRestoredMarkList = m_aMark; } } m_aMark.Clear(); } } // ----------------------------------------------------------------------------- void SAL_CALL FmXFormView::focusGained( const FocusEvent& /*e*/ ) throw (RuntimeException) { if ( m_xWindow.is() && m_pView ) { m_pView->SetMoveOutside( sal_True, FmFormView::ImplAccess() ); } } // ----------------------------------------------------------------------------- void SAL_CALL FmXFormView::focusLost( const FocusEvent& /*e*/ ) throw (RuntimeException) { // when switch the focus outside the office the mark didn't change // so we can not remove us as focus listener if ( m_xWindow.is() && m_pView ) { m_pView->SetMoveOutside( sal_False, FmFormView::ImplAccess() ); } } // ----------------------------------------------------------------------------- void FmXFormView::removeGridWindowListening() { if ( m_xWindow.is() ) { m_xWindow->removeFocusListener(this); if ( m_pView ) { m_pView->SetMoveOutside( sal_False, FmFormView::ImplAccess() ); } m_xWindow = NULL; } } // ----------------------------------------------------------------------------- DocumentType FmXFormView::impl_getDocumentType() const { if ( GetFormShell() && GetFormShell()->GetImpl() ) return GetFormShell()->GetImpl()->getDocumentType(); return eUnknownDocumentType; }