1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "eformspropertyhandler.hxx"
21 #include "formstrings.hxx"
22 #include "formmetadata.hxx"
23 #include <propctrlr.h>
24 #include "eformshelper.hxx"
25 #include "handlerhelper.hxx"
27 #include <com/sun/star/lang/NullPointerException.hpp>
28 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
29 #include <com/sun/star/inspection/PropertyControlType.hpp>
30 #include <com/sun/star/inspection/XObjectInspectorUI.hpp>
31 #include <tools/debug.hxx>
32 #include <comphelper/diagnose_ex.hxx>
33 #include <sal/log.hxx>
40 using namespace ::com::sun::star
;
41 using namespace ::com::sun::star::uno
;
42 using namespace ::com::sun::star::lang
;
43 using namespace ::com::sun::star::beans
;
44 using namespace ::com::sun::star::xforms
;
45 using namespace ::com::sun::star::script
;
46 using namespace ::com::sun::star::ui::dialogs
;
47 using namespace ::com::sun::star::form::binding
;
48 using namespace ::com::sun::star::inspection
;
51 //= EFormsPropertyHandler
54 EFormsPropertyHandler::EFormsPropertyHandler( const Reference
< XComponentContext
>& _rxContext
)
55 :PropertyHandlerComponent( _rxContext
)
56 ,m_bSimulatingModelChange( false )
61 EFormsPropertyHandler::~EFormsPropertyHandler( )
66 OUString
EFormsPropertyHandler::getImplementationName( )
68 return "com.sun.star.comp.extensions.EFormsPropertyHandler";
72 Sequence
< OUString
> EFormsPropertyHandler::getSupportedServiceNames( )
74 return { "com.sun.star.form.inspection.XMLFormsPropertyHandler" };
78 OUString
EFormsPropertyHandler::getModelNamePropertyValue() const
80 OUString sModelName
= m_pHelper
->getCurrentFormModelName();
81 if ( sModelName
.isEmpty() )
82 sModelName
= m_sBindingLessModelName
;
87 Any SAL_CALL
EFormsPropertyHandler::getPropertyValue( const OUString
& _rPropertyName
)
89 ::osl::MutexGuard
aGuard( m_aMutex
);
90 PropertyId
nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName
) );
94 "EFormsPropertyHandler::getPropertyValue: we don't have any SupportedProperties!");
95 // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties
102 case PROPERTY_ID_LIST_BINDING
:
103 aReturn
<<= m_pHelper
->getCurrentListSourceBinding();
106 case PROPERTY_ID_XML_DATA_MODEL
:
107 aReturn
<<= getModelNamePropertyValue();
110 case PROPERTY_ID_BINDING_NAME
:
111 aReturn
<<= m_pHelper
->getCurrentBindingName();
114 case PROPERTY_ID_BIND_EXPRESSION
:
115 case PROPERTY_ID_XSD_CONSTRAINT
:
116 case PROPERTY_ID_XSD_CALCULATION
:
117 case PROPERTY_ID_XSD_REQUIRED
:
118 case PROPERTY_ID_XSD_RELEVANT
:
119 case PROPERTY_ID_XSD_READONLY
:
121 Reference
< XPropertySet
> xBindingProps( m_pHelper
->getCurrentBinding() );
122 if ( xBindingProps
.is() )
124 aReturn
= xBindingProps
->getPropertyValue( _rPropertyName
);
125 DBG_ASSERT( aReturn
.getValueType().equals( ::cppu::UnoType
<OUString
>::get() ),
126 "EFormsPropertyHandler::getPropertyValue: invalid BindingExpression value type!" );
129 aReturn
<<= OUString();
134 OSL_FAIL( "EFormsPropertyHandler::getPropertyValue: cannot handle this property!" );
138 catch( const Exception
& )
140 TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsPropertyHandler::getPropertyValue: caught exception!"
141 "(have been asked for the \"" <<_rPropertyName
<< "\" property.)");
147 void SAL_CALL
EFormsPropertyHandler::setPropertyValue( const OUString
& _rPropertyName
, const Any
& _rValue
)
149 ::osl::MutexGuard
aGuard( m_aMutex
);
150 PropertyId
nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName
) );
154 "EFormsPropertyHandler::setPropertyValue: we don't have any SupportedProperties!");
155 // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties
159 Any aOldValue
= getPropertyValue( _rPropertyName
);
163 case PROPERTY_ID_LIST_BINDING
:
165 Reference
< XListEntrySource
> xSource
;
166 OSL_VERIFY( _rValue
>>= xSource
);
167 m_pHelper
->setListSourceBinding( xSource
);
171 case PROPERTY_ID_XML_DATA_MODEL
:
173 OSL_VERIFY( _rValue
>>= m_sBindingLessModelName
);
175 // if the model changed, reset the binding to NULL
176 if ( m_pHelper
->getCurrentFormModelName() != m_sBindingLessModelName
)
178 OUString sOldBindingName
= m_pHelper
->getCurrentBindingName();
179 m_pHelper
->setBinding( nullptr );
180 firePropertyChange( PROPERTY_BINDING_NAME
, PROPERTY_ID_BINDING_NAME
,
181 Any( sOldBindingName
), Any( OUString() ) );
186 case PROPERTY_ID_BINDING_NAME
:
188 OUString sNewBindingName
;
189 OSL_VERIFY( _rValue
>>= sNewBindingName
);
191 bool bPreviouslyEmptyModel
= !m_pHelper
->getCurrentFormModel().is();
193 Reference
< XPropertySet
> xNewBinding
;
194 if ( !sNewBindingName
.isEmpty() )
195 // obtain the binding with this name, for the current model
196 xNewBinding
= m_pHelper
->getOrCreateBindingForModel( getModelNamePropertyValue(), sNewBindingName
);
198 m_pHelper
->setBinding( xNewBinding
);
200 if ( bPreviouslyEmptyModel
)
201 { // simulate a property change for the model property
202 // This is because we "simulate" the Model property by remembering the
203 // value ourself. Other instances might, however, not know this value,
204 // but prefer to retrieve it somewhere else - e.g. from the EFormsHelper
206 // The really correct solution would be if *all* property handlers
207 // obtain a "current property value" for *all* properties from a central
208 // instance. Then, handler A could ask it for the value of property
209 // X, and this request would be re-routed to handler B, which ultimately
210 // knows the current value.
211 // However, there's no such mechanism in place currently.
212 m_bSimulatingModelChange
= true;
213 firePropertyChange( PROPERTY_XML_DATA_MODEL
, PROPERTY_ID_XML_DATA_MODEL
,
214 Any( OUString() ), Any( getModelNamePropertyValue() ) );
215 m_bSimulatingModelChange
= false;
220 case PROPERTY_ID_BIND_EXPRESSION
:
222 Reference
< XPropertySet
> xBinding( m_pHelper
->getCurrentBinding() );
223 OSL_ENSURE( xBinding
.is(), "You should not reach this without an active binding!" );
225 xBinding
->setPropertyValue( PROPERTY_BIND_EXPRESSION
, _rValue
);
229 case PROPERTY_ID_XSD_REQUIRED
:
230 case PROPERTY_ID_XSD_RELEVANT
:
231 case PROPERTY_ID_XSD_READONLY
:
232 case PROPERTY_ID_XSD_CONSTRAINT
:
233 case PROPERTY_ID_XSD_CALCULATION
:
235 Reference
< XPropertySet
> xBindingProps( m_pHelper
->getCurrentBinding() );
236 DBG_ASSERT( xBindingProps
.is(), "EFormsPropertyHandler::setPropertyValue: how can I set a property if there's no binding?" );
237 if ( xBindingProps
.is() )
239 DBG_ASSERT( _rValue
.getValueType().equals( ::cppu::UnoType
<OUString
>::get() ),
240 "EFormsPropertyHandler::setPropertyValue: invalid value type!" );
241 xBindingProps
->setPropertyValue( _rPropertyName
, _rValue
);
247 OSL_FAIL( "EFormsPropertyHandler::setPropertyValue: cannot handle this property!" );
251 impl_setContextDocumentModified_nothrow();
253 Any
aNewValue( getPropertyValue( _rPropertyName
) );
254 firePropertyChange( _rPropertyName
, nPropId
, aOldValue
, aNewValue
);
256 catch( const Exception
& )
258 TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsPropertyHandler::setPropertyValue" );
263 void EFormsPropertyHandler::onNewComponent()
265 PropertyHandlerComponent::onNewComponent();
267 Reference
< frame::XModel
> xDocument( impl_getContextDocument_nothrow() );
268 DBG_ASSERT( xDocument
.is(), "EFormsPropertyHandler::onNewComponent: no document!" );
269 if ( EFormsHelper::isEForm( xDocument
) )
270 m_pHelper
.reset( new EFormsHelper( m_aMutex
, m_xComponent
, xDocument
) );
276 Sequence
< Property
> EFormsPropertyHandler::doDescribeSupportedProperties() const
278 std::vector
< Property
> aProperties
;
282 if ( m_pHelper
->canBindToAnyDataType() )
284 aProperties
.reserve(9);
285 addStringPropertyDescription( aProperties
, PROPERTY_XML_DATA_MODEL
);
286 addStringPropertyDescription( aProperties
, PROPERTY_BINDING_NAME
);
287 addStringPropertyDescription( aProperties
, PROPERTY_BIND_EXPRESSION
);
288 addStringPropertyDescription( aProperties
, PROPERTY_XSD_REQUIRED
);
289 addStringPropertyDescription( aProperties
, PROPERTY_XSD_RELEVANT
);
290 addStringPropertyDescription( aProperties
, PROPERTY_XSD_READONLY
);
291 addStringPropertyDescription( aProperties
, PROPERTY_XSD_CONSTRAINT
);
292 addStringPropertyDescription( aProperties
, PROPERTY_XSD_CALCULATION
);
294 if ( m_pHelper
->isListEntrySink() )
296 implAddPropertyDescription( aProperties
, PROPERTY_LIST_BINDING
,
297 cppu::UnoType
<XListEntrySource
>::get() );
301 if ( aProperties
.empty() )
302 return Sequence
< Property
>();
303 return comphelper::containerToSequence(aProperties
);
307 Any SAL_CALL
EFormsPropertyHandler::convertToPropertyValue( const OUString
& _rPropertyName
, const Any
& _rControlValue
)
309 ::osl::MutexGuard
aGuard( m_aMutex
);
314 "EFormsPropertyHandler::convertToPropertyValue: we have no SupportedProperties!");
318 PropertyId
nPropId( m_pInfoService
->getPropertyId( _rPropertyName
) );
320 OUString sControlValue
;
323 case PROPERTY_ID_LIST_BINDING
:
325 OSL_VERIFY( _rControlValue
>>= sControlValue
);
326 Reference
< XListEntrySource
> xListSource( m_pHelper
->getModelElementFromUIName( EFormsHelper::Binding
, sControlValue
), UNO_QUERY
);
327 OSL_ENSURE( xListSource
.is() || !m_pHelper
->getModelElementFromUIName( EFormsHelper::Binding
, sControlValue
).is(),
328 "EFormsPropertyHandler::convertToPropertyValue: there's a binding which is no ListEntrySource!" );
329 aReturn
<<= xListSource
;
334 aReturn
= PropertyHandlerComponent::convertToPropertyValue( _rPropertyName
, _rControlValue
);
342 Any SAL_CALL
EFormsPropertyHandler::convertToControlValue( const OUString
& _rPropertyName
, const Any
& _rPropertyValue
, const Type
& _rControlValueType
)
344 ::osl::MutexGuard
aGuard( m_aMutex
);
347 OSL_ENSURE(m_pHelper
,
348 "EFormsPropertyHandler::convertToControlValue: we have no SupportedProperties!");
352 PropertyId
nPropId( m_pInfoService
->getPropertyId( _rPropertyName
) );
354 OSL_ENSURE( _rControlValueType
.getTypeClass() == TypeClass_STRING
,
355 "EFormsPropertyHandler::convertToControlValue: all our controls should use strings for value exchange!" );
359 case PROPERTY_ID_LIST_BINDING
:
361 Reference
< XPropertySet
> xListSourceBinding( _rPropertyValue
, UNO_QUERY
);
362 if ( xListSourceBinding
.is() )
363 aReturn
<<= EFormsHelper::getModelElementUIName( EFormsHelper::Binding
, xListSourceBinding
);
368 aReturn
= PropertyHandlerComponent::convertToControlValue( _rPropertyName
, _rPropertyValue
, _rControlValueType
);
376 Sequence
< OUString
> SAL_CALL
EFormsPropertyHandler::getActuatingProperties( )
378 ::osl::MutexGuard
aGuard( m_aMutex
);
380 return Sequence
< OUString
>();
382 std::vector
< OUString
> aInterestedInActuations( 2 );
383 aInterestedInActuations
[ 0 ] = PROPERTY_XML_DATA_MODEL
;
384 aInterestedInActuations
[ 1 ] = PROPERTY_BINDING_NAME
;
385 return comphelper::containerToSequence(aInterestedInActuations
);
389 Sequence
< OUString
> SAL_CALL
EFormsPropertyHandler::getSupersededProperties( )
391 ::osl::MutexGuard
aGuard( m_aMutex
);
393 return Sequence
< OUString
>();
395 Sequence
<OUString
> aReturn
{ PROPERTY_INPUT_REQUIRED
};
399 LineDescriptor SAL_CALL
EFormsPropertyHandler::describePropertyLine( const OUString
& _rPropertyName
,
400 const Reference
< XPropertyControlFactory
>& _rxControlFactory
)
402 ::osl::MutexGuard
aGuard( m_aMutex
);
403 if ( !_rxControlFactory
.is() )
404 throw NullPointerException();
406 throw RuntimeException();
408 LineDescriptor aDescriptor
;
409 sal_Int16 nControlType
= PropertyControlType::TextField
;
410 std::vector
< OUString
> aListEntries
;
411 PropertyId
nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName
) );
414 case PROPERTY_ID_LIST_BINDING
:
415 nControlType
= PropertyControlType::ListBox
;
416 m_pHelper
->getAllElementUINames(EFormsHelper::Binding
, aListEntries
, true);
419 case PROPERTY_ID_XML_DATA_MODEL
:
420 nControlType
= PropertyControlType::ListBox
;
421 m_pHelper
->getFormModelNames( aListEntries
);
424 case PROPERTY_ID_BINDING_NAME
:
426 nControlType
= PropertyControlType::ComboBox
;
427 OUString
sCurrentModel( getModelNamePropertyValue() );
428 if ( !sCurrentModel
.isEmpty() )
429 m_pHelper
->getBindingNames( sCurrentModel
, aListEntries
);
433 case PROPERTY_ID_BIND_EXPRESSION
: aDescriptor
.PrimaryButtonId
= UID_PROP_DLG_BIND_EXPRESSION
; break;
434 case PROPERTY_ID_XSD_REQUIRED
: aDescriptor
.PrimaryButtonId
= UID_PROP_DLG_XSD_REQUIRED
; break;
435 case PROPERTY_ID_XSD_RELEVANT
: aDescriptor
.PrimaryButtonId
= UID_PROP_DLG_XSD_RELEVANT
; break;
436 case PROPERTY_ID_XSD_READONLY
: aDescriptor
.PrimaryButtonId
= UID_PROP_DLG_XSD_READONLY
; break;
437 case PROPERTY_ID_XSD_CONSTRAINT
: aDescriptor
.PrimaryButtonId
= UID_PROP_DLG_XSD_CONSTRAINT
; break;
438 case PROPERTY_ID_XSD_CALCULATION
: aDescriptor
.PrimaryButtonId
= UID_PROP_DLG_XSD_CALCULATION
; break;
441 OSL_FAIL( "EFormsPropertyHandler::describePropertyLine: cannot handle this property!" );
445 switch ( nControlType
)
447 case PropertyControlType::ListBox
:
448 aDescriptor
.Control
= PropertyHandlerHelper::createListBoxControl( _rxControlFactory
, std::move(aListEntries
), false, true );
450 case PropertyControlType::ComboBox
:
451 aDescriptor
.Control
= PropertyHandlerHelper::createComboBoxControl( _rxControlFactory
, std::move(aListEntries
), true );
454 aDescriptor
.Control
= _rxControlFactory
->createPropertyControl( nControlType
, false );
458 aDescriptor
.DisplayName
= m_pInfoService
->getPropertyTranslation( nPropId
);
459 aDescriptor
.Category
= "Data";
460 aDescriptor
.HelpURL
= HelpIdUrl::getHelpURL( m_pInfoService
->getPropertyHelpId( nPropId
) );
464 InteractiveSelectionResult SAL_CALL
EFormsPropertyHandler::onInteractivePropertySelection( const OUString
& _rPropertyName
, sal_Bool
/*_bPrimary*/, Any
& _rData
, const Reference
< XObjectInspectorUI
>& _rxInspectorUI
)
466 if ( !_rxInspectorUI
.is() )
467 throw NullPointerException();
469 ::osl::MutexGuard
aGuard( m_aMutex
);
470 OSL_ENSURE(m_pHelper
, "EFormsPropertyHandler::onInteractivePropertySelection: we do not "
471 "have any SupportedProperties!");
473 return InteractiveSelectionResult_Cancelled
;
475 PropertyId
nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName
) );
476 OSL_ENSURE( ( PROPERTY_ID_BINDING_NAME
== nPropId
)
477 || ( PROPERTY_ID_BIND_EXPRESSION
== nPropId
)
478 || ( PROPERTY_ID_XSD_REQUIRED
== nPropId
)
479 || ( PROPERTY_ID_XSD_RELEVANT
== nPropId
)
480 || ( PROPERTY_ID_XSD_READONLY
== nPropId
)
481 || ( PROPERTY_ID_XSD_CONSTRAINT
== nPropId
)
482 || ( PROPERTY_ID_XSD_CALCULATION
== nPropId
), "EFormsPropertyHandler::onInteractivePropertySelection: unexpected!" );
486 Reference
< XExecutableDialog
> xDialog
;
487 xDialog
.set( m_xContext
->getServiceManager()->createInstanceWithContext( "com.sun.star.xforms.ui.dialogs.AddCondition", m_xContext
), UNO_QUERY
);
488 Reference
< XPropertySet
> xDialogProps( xDialog
, UNO_QUERY_THROW
);
490 // the model for the dialog to work with
491 Reference
< xforms::XModel
> xModel( m_pHelper
->getCurrentFormModel() );
492 // the binding for the dialog to work with
493 Reference
< XPropertySet
> xBinding( m_pHelper
->getCurrentBinding() );
494 // the aspect of the binding which the dialog should modify
495 const OUString
& sFacetName( _rPropertyName
);
497 OSL_ENSURE( xModel
.is() && xBinding
.is() && !sFacetName
.isEmpty(),
498 "EFormsPropertyHandler::onInteractivePropertySelection: something is missing for the dialog initialization!" );
499 if ( !xModel
.is() || !xBinding
.is() || sFacetName
.isEmpty() )
500 return InteractiveSelectionResult_Cancelled
;
502 xDialogProps
->setPropertyValue("FormModel", Any( xModel
) );
503 xDialogProps
->setPropertyValue("Binding", Any( xBinding
) );
504 xDialogProps
->setPropertyValue("FacetName", Any( sFacetName
) );
506 if ( !xDialog
->execute() )
508 return InteractiveSelectionResult_Cancelled
;
510 _rData
= xDialogProps
->getPropertyValue("ConditionValue");
511 return InteractiveSelectionResult_ObtainedValue
;
513 catch( const Exception
& )
515 TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsPropertyHandler::onInteractivePropertySelection" );
518 // something went wrong here ...(but has been asserted already)
519 return InteractiveSelectionResult_Cancelled
;
523 void SAL_CALL
EFormsPropertyHandler::addPropertyChangeListener( const Reference
< XPropertyChangeListener
>& _rxListener
)
525 ::osl::MutexGuard
aGuard( m_aMutex
);
526 PropertyHandlerComponent::addPropertyChangeListener( _rxListener
);
528 m_pHelper
->registerBindingListener( _rxListener
);
532 void SAL_CALL
EFormsPropertyHandler::removePropertyChangeListener( const Reference
< XPropertyChangeListener
>& _rxListener
)
534 ::osl::MutexGuard
aGuard( m_aMutex
);
536 m_pHelper
->revokeBindingListener( _rxListener
);
537 PropertyHandlerComponent::removePropertyChangeListener( _rxListener
);
541 void SAL_CALL
EFormsPropertyHandler::actuatingPropertyChanged( const OUString
& _rActuatingPropertyName
, const Any
& _rNewValue
, const Any
& /*_rOldValue*/, const Reference
< XObjectInspectorUI
>& _rxInspectorUI
, sal_Bool
)
543 if ( !_rxInspectorUI
.is() )
544 throw NullPointerException();
546 ::osl::MutexGuard
aGuard( m_aMutex
);
547 PropertyId
nActuatingPropId( impl_getPropertyId_throwRuntime( _rActuatingPropertyName
) );
548 OSL_PRECOND(m_pHelper
, "EFormsPropertyHandler::actuatingPropertyChanged: inconsistency!");
549 // if we survived impl_getPropertyId_throwRuntime, we should have a helper, since no helper implies no properties
551 DBG_ASSERT( _rxInspectorUI
.is(), "EFormsPropertyHandler::actuatingPropertyChanged: invalid callback!" );
552 if ( !_rxInspectorUI
.is() )
555 switch ( nActuatingPropId
)
557 case PROPERTY_ID_XML_DATA_MODEL
:
559 if ( m_bSimulatingModelChange
)
561 OUString sDataModelName
;
562 OSL_VERIFY( _rNewValue
>>= sDataModelName
);
563 bool bBoundToSomeModel
= !sDataModelName
.isEmpty();
564 _rxInspectorUI
->rebuildPropertyUI( PROPERTY_BINDING_NAME
);
565 _rxInspectorUI
->enablePropertyUI( PROPERTY_BINDING_NAME
, bBoundToSomeModel
);
569 case PROPERTY_ID_BINDING_NAME
:
571 bool bHaveABinding
= !m_pHelper
->getCurrentBindingName().isEmpty();
572 _rxInspectorUI
->enablePropertyUI( PROPERTY_BIND_EXPRESSION
, bHaveABinding
);
573 _rxInspectorUI
->enablePropertyUI( PROPERTY_XSD_REQUIRED
, bHaveABinding
);
574 _rxInspectorUI
->enablePropertyUI( PROPERTY_XSD_RELEVANT
, bHaveABinding
);
575 _rxInspectorUI
->enablePropertyUI( PROPERTY_XSD_READONLY
, bHaveABinding
);
576 _rxInspectorUI
->enablePropertyUI( PROPERTY_XSD_CONSTRAINT
, bHaveABinding
);
577 _rxInspectorUI
->enablePropertyUI( PROPERTY_XSD_CALCULATION
, bHaveABinding
);
578 _rxInspectorUI
->enablePropertyUI( PROPERTY_XSD_DATA_TYPE
, bHaveABinding
);
583 OSL_FAIL( "EFormsPropertyHandler::actuatingPropertyChanged: cannot handle this property!" );
591 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
592 extensions_propctrlr_EFormsPropertyHandler_get_implementation(
593 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
595 return cppu::acquire(new pcr::EFormsPropertyHandler(context
));
598 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */