1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_forms.hxx" 26 #include "RadioButton.hxx" 27 #include "property.hxx" 28 #ifndef _FRM_PROPERTY_HRC_ 29 #include "property.hrc" 30 #endif 31 #include "services.hxx" 32 #include <tools/debug.hxx> 33 #include <comphelper/extract.hxx> 34 #include <comphelper/basicio.hxx> 35 #include <com/sun/star/container/XIndexAccess.hpp> 36 #include <com/sun/star/awt/XVclWindowPeer.hpp> 37 38 //......................................................................... 39 namespace frm 40 { 41 using namespace ::com::sun::star::uno; 42 using namespace ::com::sun::star::sdb; 43 using namespace ::com::sun::star::sdbc; 44 using namespace ::com::sun::star::sdbcx; 45 using namespace ::com::sun::star::beans; 46 using namespace ::com::sun::star::container; 47 using namespace ::com::sun::star::form; 48 using namespace ::com::sun::star::awt; 49 using namespace ::com::sun::star::io; 50 using namespace ::com::sun::star::lang; 51 using namespace ::com::sun::star::util; 52 using namespace ::com::sun::star::form::binding; 53 54 //================================================================== 55 //------------------------------------------------------------------------------ 56 InterfaceRef SAL_CALL ORadioButtonControl_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) 57 { 58 return *(new ORadioButtonControl(_rxFactory)); 59 } 60 61 //------------------------------------------------------------------------------ 62 StringSequence SAL_CALL ORadioButtonControl::getSupportedServiceNames() 63 { 64 StringSequence aSupported = OBoundControl::getSupportedServiceNames(); 65 aSupported.realloc(aSupported.getLength() + 1); 66 67 ::rtl::OUString* pArray = aSupported.getArray(); 68 pArray[aSupported.getLength()-1] = FRM_SUN_CONTROL_RADIOBUTTON; 69 return aSupported; 70 } 71 72 73 //------------------------------------------------------------------ 74 ORadioButtonControl::ORadioButtonControl(const Reference<XMultiServiceFactory>& _rxFactory) 75 :OBoundControl(_rxFactory, VCL_CONTROL_RADIOBUTTON) 76 { 77 } 78 79 //------------------------------------------------------------------ 80 void SAL_CALL ORadioButtonControl::createPeer(const Reference<starawt::XToolkit>& _rxToolkit, const Reference<starawt::XWindowPeer>& _rxParent) 81 { 82 OBoundControl::createPeer(_rxToolkit, _rxParent); 83 84 // switch off the auto-toggle, we do this ourself .... 85 // (formerly this switch-off was done in the toolkit - but the correct place is here ...) 86 // Reference< XVclWindowPeer > xVclWindowPeer( getPeer(), UNO_QUERY ); 87 // if (xVclWindowPeer.is()) 88 // xVclWindowPeer->setProperty(::rtl::OUString::createFromAscii("AutoToggle"), ::cppu::bool2any(sal_False)); 89 // new order: do _not_ switch off the auto toggle because: 90 // * today, it is not necessary anymore to handle the toggling ourself (everything works fine without it) 91 // * without auto toggle, the AccessibleEvents as fired by the radio buttons are 92 // a. newly checked button: "unchecked"->"checked" 93 // b. previously checked button: "checked"->"unchecked" 94 // This is deadly for AT-tools, which then get the "unchecked" event _immediately_ after the "checked" event, 95 // and only read the latter. This makes radio buttons pretty unusable in form documents. 96 // So we switched AutoToggle _on_, again, because then VCL can handle the notifications, and will send 97 // them in the proper order. 98 } 99 100 //================================================================== 101 InterfaceRef SAL_CALL ORadioButtonModel_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) 102 { 103 return *(new ORadioButtonModel(_rxFactory)); 104 } 105 106 //------------------------------------------------------------------ 107 DBG_NAME( ORadioButtonModel ) 108 //------------------------------------------------------------------ 109 ORadioButtonModel::ORadioButtonModel(const Reference<XMultiServiceFactory>& _rxFactory) 110 :OReferenceValueComponent( _rxFactory, VCL_CONTROLMODEL_RADIOBUTTON, FRM_SUN_CONTROL_RADIOBUTTON,sal_True ) 111 // use the old control name for compytibility reasons 112 { 113 DBG_CTOR( ORadioButtonModel, NULL ); 114 115 m_nClassId = FormComponentType::RADIOBUTTON; 116 m_aLabelServiceName = FRM_SUN_COMPONENT_GROUPBOX; 117 initValueProperty( PROPERTY_STATE, PROPERTY_ID_STATE ); 118 } 119 120 //------------------------------------------------------------------ 121 ORadioButtonModel::ORadioButtonModel( const ORadioButtonModel* _pOriginal, const Reference<XMultiServiceFactory>& _rxFactory ) 122 :OReferenceValueComponent( _pOriginal, _rxFactory ) 123 { 124 DBG_CTOR( ORadioButtonModel, NULL ); 125 } 126 127 //------------------------------------------------------------------------------ 128 ORadioButtonModel::~ORadioButtonModel() 129 { 130 DBG_DTOR( ORadioButtonModel, NULL ); 131 } 132 133 // XCloneable 134 //------------------------------------------------------------------------------ 135 IMPLEMENT_DEFAULT_CLONING( ORadioButtonModel ) 136 137 // XServiceInfo 138 //------------------------------------------------------------------------------ 139 StringSequence SAL_CALL ORadioButtonModel::getSupportedServiceNames() 140 { 141 StringSequence aSupported = OReferenceValueComponent::getSupportedServiceNames(); 142 143 sal_Int32 nOldLen = aSupported.getLength(); 144 aSupported.realloc( nOldLen + 8 ); 145 ::rtl::OUString* pStoreTo = aSupported.getArray() + nOldLen; 146 147 *pStoreTo++ = BINDABLE_CONTROL_MODEL; 148 *pStoreTo++ = DATA_AWARE_CONTROL_MODEL; 149 *pStoreTo++ = VALIDATABLE_CONTROL_MODEL; 150 151 *pStoreTo++ = BINDABLE_DATA_AWARE_CONTROL_MODEL; 152 *pStoreTo++ = VALIDATABLE_BINDABLE_CONTROL_MODEL; 153 154 *pStoreTo++ = FRM_SUN_COMPONENT_RADIOBUTTON; 155 *pStoreTo++ = FRM_SUN_COMPONENT_DATABASE_RADIOBUTTON; 156 *pStoreTo++ = BINDABLE_DATABASE_RADIO_BUTTON; 157 158 return aSupported; 159 } 160 161 //------------------------------------------------------------------------------ 162 void ORadioButtonModel::SetSiblingPropsTo(const ::rtl::OUString& rPropName, const Any& rValue) 163 { 164 // mein Name 165 ::rtl::OUString sMyName(m_aName); 166 167 // meine Siblings durchiterieren 168 Reference<XIndexAccess> xIndexAccess(getParent(), UNO_QUERY); 169 if (xIndexAccess.is()) 170 { 171 Reference<XPropertySet> xMyProps; 172 query_interface(static_cast<XWeak*>(this), xMyProps); 173 ::rtl::OUString sCurrentName; 174 for (sal_Int32 i=0; i<xIndexAccess->getCount(); ++i) 175 { 176 Reference<XPropertySet> xSiblingProperties(*(InterfaceRef*)xIndexAccess->getByIndex(i).getValue(), UNO_QUERY); 177 if (!xSiblingProperties.is()) 178 continue; 179 if (xMyProps == xSiblingProperties) 180 continue; // mich selber nicht umsetzen 181 182 // nur wenn es ein Radio-Button ist 183 if (!hasProperty(PROPERTY_CLASSID, xSiblingProperties)) 184 continue; 185 sal_Int16 nType = 0; 186 xSiblingProperties->getPropertyValue(PROPERTY_CLASSID) >>= nType; 187 if (nType != FormComponentType::RADIOBUTTON) 188 continue; 189 190 // das 'zur selben Gruppe gehoeren' wird am Namen festgemacht 191 xSiblingProperties->getPropertyValue(PROPERTY_NAME) >>= sCurrentName; 192 if (sCurrentName == sMyName) 193 xSiblingProperties->setPropertyValue(rPropName, rValue); 194 } 195 } 196 } 197 198 //------------------------------------------------------------------------------ 199 void ORadioButtonModel::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) 200 { 201 OReferenceValueComponent::setFastPropertyValue_NoBroadcast( nHandle, rValue ); 202 203 // if the label control changed ... 204 if (nHandle == PROPERTY_ID_CONTROLLABEL) 205 { // ... forward this to our siblings 206 SetSiblingPropsTo(PROPERTY_CONTROLLABEL, rValue); 207 } 208 209 // wenn sich die ControlSource-Eigenschaft geaendert hat ... 210 if (nHandle == PROPERTY_ID_CONTROLSOURCE) 211 { // ... muss ich allen meinen Siblings, die in der selben RadioButton-Gruppe sind wie ich, auch die 212 // neue ControlSource mitgeben 213 SetSiblingPropsTo(PROPERTY_CONTROLSOURCE, rValue); 214 } 215 216 // die andere Richtung : wenn sich mein Name aendert ... 217 if (nHandle == PROPERTY_ID_NAME) 218 { 219 // ... muss ich testen, ob ich Siblings mit dem selben Namen habe, damit ich deren ControlSource uebernehmen kann 220 Reference<XIndexAccess> xIndexAccess(getParent(), UNO_QUERY); 221 if (xIndexAccess.is()) 222 { 223 ::rtl::OUString sName; 224 ::rtl::OUString sControlSource; 225 226 Reference<XPropertySet> xMyProps; 227 query_interface(static_cast<XWeak*>(this), xMyProps); 228 for (sal_Int32 i=0; i<xIndexAccess->getCount(); ++i) 229 { 230 Reference<XPropertySet> xSiblingProperties(*(InterfaceRef*)xIndexAccess->getByIndex(i).getValue(), UNO_QUERY); 231 if (!xSiblingProperties.is()) 232 continue; 233 234 if (xMyProps == xSiblingProperties) 235 // nur wenn ich nicht mich selber gefunden habe 236 continue; 237 238 sal_Int16 nType = 0; 239 xSiblingProperties->getPropertyValue(PROPERTY_CLASSID) >>= nType; 240 if (nType != FormComponentType::RADIOBUTTON) 241 // nur Radio-Buttons 242 continue; 243 244 xSiblingProperties->getPropertyValue(PROPERTY_NAME) >>= sName; 245 // Control, das zur gleichen Gruppe gehoert ? 246 if (rValue == sName) 247 { 248 setPropertyValue(PROPERTY_CONTROLSOURCE, xSiblingProperties->getPropertyValue(PROPERTY_CONTROLSOURCE)); 249 break; 250 } 251 } 252 } 253 } 254 255 if (nHandle == PROPERTY_ID_DEFAULT_STATE) 256 { 257 sal_Int16 nValue; 258 rValue >>= nValue; 259 if (1 == nValue) 260 { // bei allen Radios der selben Gruppe das 'default checked' ruecksetzen, denn wie schon der highlander wusste : 261 // es kann nur einen geben. 262 Any aZero; 263 nValue = 0; 264 aZero <<= nValue; 265 SetSiblingPropsTo(PROPERTY_DEFAULT_STATE, aZero); 266 } 267 } 268 } 269 270 //------------------------------------------------------------------------------ 271 void ORadioButtonModel::describeFixedProperties( Sequence< Property >& _rProps ) const 272 { 273 BEGIN_DESCRIBE_PROPERTIES( 1, OReferenceValueComponent ) 274 DECL_PROP1(TABINDEX, sal_Int16, BOUND); 275 END_DESCRIBE_PROPERTIES(); 276 } 277 278 //------------------------------------------------------------------------------ 279 ::rtl::OUString SAL_CALL ORadioButtonModel::getServiceName() 280 { 281 return FRM_COMPONENT_RADIOBUTTON; // old (non-sun) name for compatibility ! 282 } 283 284 //------------------------------------------------------------------------------ 285 void SAL_CALL ORadioButtonModel::write(const Reference<XObjectOutputStream>& _rxOutStream) 286 { 287 OReferenceValueComponent::write(_rxOutStream); 288 289 // Version 290 _rxOutStream->writeShort(0x0003); 291 292 // Properties 293 _rxOutStream << getReferenceValue(); 294 _rxOutStream << (sal_Int16)getDefaultChecked(); 295 writeHelpTextCompatibly(_rxOutStream); 296 297 // from version 0x0003 : common properties 298 writeCommonProperties(_rxOutStream); 299 } 300 301 //------------------------------------------------------------------------------ 302 void SAL_CALL ORadioButtonModel::read(const Reference<XObjectInputStream>& _rxInStream) 303 { 304 OReferenceValueComponent::read(_rxInStream); 305 ::osl::MutexGuard aGuard(m_aMutex); 306 307 // Version 308 sal_uInt16 nVersion = _rxInStream->readShort(); 309 310 ::rtl::OUString sReferenceValue; 311 sal_Int16 nDefaultChecked( 0 ); 312 switch (nVersion) 313 { 314 case 0x0001 : 315 _rxInStream >> sReferenceValue; 316 _rxInStream >> nDefaultChecked; 317 break; 318 case 0x0002 : 319 _rxInStream >> sReferenceValue; 320 _rxInStream >> nDefaultChecked; 321 readHelpTextCompatibly(_rxInStream); 322 break; 323 case 0x0003 : 324 _rxInStream >> sReferenceValue; 325 _rxInStream >> nDefaultChecked; 326 readHelpTextCompatibly(_rxInStream); 327 readCommonProperties(_rxInStream); 328 break; 329 default : 330 DBG_ERROR("ORadioButtonModel::read : unknown version !"); 331 defaultCommonProperties(); 332 break; 333 } 334 335 setReferenceValue( sReferenceValue ); 336 setDefaultChecked( (ToggleState)nDefaultChecked ); 337 338 // Nach dem Lesen die Defaultwerte anzeigen 339 if ( getControlSource().getLength() ) 340 // (not if we don't have a control source - the "State" property acts like it is persistent, then 341 resetNoBroadcast(); 342 } 343 344 //------------------------------------------------------------------------------ 345 void ORadioButtonModel::_propertyChanged(const PropertyChangeEvent& _rEvent) 346 { 347 if ( _rEvent.PropertyName.equals( PROPERTY_STATE ) ) 348 { 349 if ( _rEvent.NewValue == (sal_Int16)1 ) 350 { 351 // wenn sich mein Status auf 'checked' geaendert hat, muss ich alle meine Siblings, die in der selben Gruppe 352 // sind wie ich, entsprechend zuruecksetzen 353 Any aZero; 354 aZero <<= (sal_Int16)0; 355 SetSiblingPropsTo( PROPERTY_STATE, aZero ); 356 } 357 } 358 359 OReferenceValueComponent::_propertyChanged( _rEvent ); 360 } 361 362 //------------------------------------------------------------------------------ 363 Any ORadioButtonModel::translateDbColumnToControlValue() 364 { 365 return makeAny( (sal_Int16) 366 ( ( m_xColumn->getString() == getReferenceValue() ) ? STATE_CHECK : STATE_NOCHECK ) 367 ); 368 } 369 370 //------------------------------------------------------------------------------ 371 Any ORadioButtonModel::translateExternalValueToControlValue( const Any& _rExternalValue ) const 372 { 373 Any aControlValue = OReferenceValueComponent::translateExternalValueToControlValue( _rExternalValue ); 374 sal_Int16 nState = STATE_NOCHECK; 375 if ( ( aControlValue >>= nState ) && ( nState == STATE_DONTKNOW ) ) 376 // radio buttons do not have the DONTKNOW state 377 aControlValue <<= (sal_Int16)STATE_NOCHECK; 378 return aControlValue; 379 } 380 381 //----------------------------------------------------------------------------- 382 sal_Bool ORadioButtonModel::commitControlValueToDbColumn( bool /*_bPostReset*/ ) 383 { 384 Reference< XPropertySet > xField( getField() ); 385 OSL_PRECOND( xField.is(), "ORadioButtonModel::commitControlValueToDbColumn: not bound!" ); 386 if ( xField.is() ) 387 { 388 try 389 { 390 sal_Int16 nValue = 0; 391 m_xAggregateSet->getPropertyValue( PROPERTY_STATE ) >>= nValue; 392 if ( nValue == 1 ) 393 xField->setPropertyValue( PROPERTY_VALUE, makeAny( getReferenceValue() ) ); 394 } 395 catch(Exception&) 396 { 397 DBG_ERROR("ORadioButtonModel::commitControlValueToDbColumn: could not commit !"); 398 } 399 } 400 return sal_True; 401 } 402 403 //......................................................................... 404 } 405 //......................................................................... 406