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