blob: a35b90f4e0ec4b2724c5c150d797ad6a7cd96cd8 [file] [log] [blame]
/**************************************************************
*
* 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 <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
#include <com/sun/star/style/VerticalAlignment.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/sdbc/XRowSet.hpp>
#include <com/sun/star/form/XLoadable.hpp>
#include <com/sun/star/awt/VisualEffect.hpp>
#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
#include <com/sun/star/util/XNumberFormats.hpp>
#include <com/sun/star/sdb/CommandType.hpp>
#include <com/sun/star/sdbc/DataType.hpp>
#include <com/sun/star/sdbc/ColumnValue.hpp>
#include <com/sun/star/form/FormComponentType.hpp>
#include <com/sun/star/form/FormButtonType.hpp>
#include <com/sun/star/form/XReset.hpp>
#include <com/sun/star/form/binding/XBindableValue.hpp>
#include <com/sun/star/form/binding/XValueBinding.hpp>
#include <com/sun/star/form/submission/XSubmissionSupplier.hpp>
#include <com/sun/star/awt/XTabControllerModel.hpp>
#include <com/sun/star/awt/XControlContainer.hpp>
#include <com/sun/star/awt/XTabController.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/awt/XControl.hpp>
#include <com/sun/star/lang/XUnoTunnel.hpp>
#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
#include <com/sun/star/sdbc/XPreparedStatement.hpp>
#include <com/sun/star/sdb/XQueriesSupplier.hpp>
#include <com/sun/star/container/XContainer.hpp>
/** === end UNO includes === **/
#include <comphelper/enumhelper.hxx>
#include <comphelper/extract.hxx>
#include <comphelper/namedvaluecollection.hxx>
#include <comphelper/numbers.hxx>
#include <comphelper/property.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <unotools/moduleoptions.hxx>
#include <tools/diagnose_ex.h>
#include <vcl/msgbox.hxx>
#include <vcl/stdtext.hxx>
#include <vos/mutex.hxx>
#include <rtl/logfile.hxx>
#include <algorithm>
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<Window*>(static_cast<const Window*>(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<OutputDevice*>(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<OutputDevice*>(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<FmFormObj*>(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 hierachy
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; i<nCurrentCount&& !bMisMatch; ++i )
{
const SdrObject* pCurrentMarked = rCurrentList.GetMark( i )->GetMarkedSdrObj();
// loop through all saved marks, check for equality
sal_Bool bFound = sal_False;
sal_uIntPtr nSavedCount = m_aMark.GetMarkCount();
for ( sal_uIntPtr j=0; j<nSavedCount && !bFound; ++j )
{
if ( m_aMark.GetMark( j )->GetMarkedSdrObj() == 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;
}