Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "RadioButton.hxx"
21 : #include "GroupManager.hxx"
22 : #include "property.hxx"
23 : #include "property.hrc"
24 : #include "services.hxx"
25 : #include <comphelper/basicio.hxx>
26 : #include <comphelper/processfactory.hxx>
27 : #include <com/sun/star/container/XIndexAccess.hpp>
28 : #include <com/sun/star/awt/XVclWindowPeer.hpp>
29 :
30 :
31 : namespace frm
32 : {
33 : using namespace ::com::sun::star::uno;
34 : using namespace ::com::sun::star::sdb;
35 : using namespace ::com::sun::star::sdbc;
36 : using namespace ::com::sun::star::sdbcx;
37 : using namespace ::com::sun::star::beans;
38 : using namespace ::com::sun::star::container;
39 : using namespace ::com::sun::star::form;
40 : using namespace ::com::sun::star::awt;
41 : using namespace ::com::sun::star::io;
42 : using namespace ::com::sun::star::lang;
43 : using namespace ::com::sun::star::util;
44 : using namespace ::com::sun::star::form::binding;
45 :
46 :
47 :
48 36 : InterfaceRef SAL_CALL ORadioButtonControl_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory)
49 : {
50 36 : return *(new ORadioButtonControl( comphelper::getComponentContext(_rxFactory) ));
51 : }
52 :
53 :
54 0 : StringSequence SAL_CALL ORadioButtonControl::getSupportedServiceNames() throw(RuntimeException, std::exception)
55 : {
56 0 : StringSequence aSupported = OBoundControl::getSupportedServiceNames();
57 0 : aSupported.realloc(aSupported.getLength() + 1);
58 :
59 0 : OUString* pArray = aSupported.getArray();
60 0 : pArray[aSupported.getLength()-1] = FRM_SUN_CONTROL_RADIOBUTTON;
61 0 : return aSupported;
62 : }
63 :
64 :
65 :
66 36 : ORadioButtonControl::ORadioButtonControl(const Reference<XComponentContext>& _rxFactory)
67 36 : :OBoundControl(_rxFactory, VCL_CONTROL_RADIOBUTTON)
68 : {
69 36 : }
70 :
71 :
72 42 : void SAL_CALL ORadioButtonControl::createPeer(const Reference<css::awt::XToolkit>& _rxToolkit, const Reference<css::awt::XWindowPeer>& _rxParent) throw (RuntimeException, std::exception)
73 : {
74 42 : OBoundControl::createPeer(_rxToolkit, _rxParent);
75 :
76 : // switch off the auto-toggle, we do this ourself ....
77 : // (formerly this switch-off was done in the toolkit - but the correct place is here ...)
78 : // Reference< XVclWindowPeer > xVclWindowPeer( getPeer(), UNO_QUERY );
79 : // if (xVclWindowPeer.is())
80 : // xVclWindowPeer->setProperty(OUString("AutoToggle"), ::cppu::bool2any(sal_False));
81 : // new order: do _not_ switch off the auto toggle because:
82 : // * today, it is not necessary anymore to handle the toggling ourself (everything works fine without it)
83 : // * without auto toggle, the AccessibleEvents as fired by the radio buttons are
84 : // a. newly checked button: "unchecked"->"checked"
85 : // b. previously checked button: "checked"->"unchecked"
86 : // This is deadly for AT-tools, which then get the "unchecked" event _immediately_ after the "checked" event,
87 : // and only read the latter. This makes radio buttons pretty unusable in form documents.
88 : // So we switched AutoToggle _on_, again, because then VCL can handle the notifications, and will send
89 : // them in the proper order.
90 42 : }
91 :
92 :
93 46 : InterfaceRef SAL_CALL ORadioButtonModel_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory)
94 : {
95 46 : return *(new ORadioButtonModel( comphelper::getComponentContext(_rxFactory) ));
96 : }
97 :
98 :
99 :
100 46 : ORadioButtonModel::ORadioButtonModel(const Reference<XComponentContext>& _rxFactory)
101 46 : :OReferenceValueComponent( _rxFactory, VCL_CONTROLMODEL_RADIOBUTTON, FRM_SUN_CONTROL_RADIOBUTTON,true )
102 : // use the old control name for compytibility reasons
103 : {
104 :
105 46 : m_nClassId = FormComponentType::RADIOBUTTON;
106 46 : m_aLabelServiceName = FRM_SUN_COMPONENT_GROUPBOX;
107 46 : initValueProperty( PROPERTY_STATE, PROPERTY_ID_STATE );
108 46 : startAggregatePropertyListening( PROPERTY_GROUP_NAME );
109 46 : }
110 :
111 :
112 2 : ORadioButtonModel::ORadioButtonModel( const ORadioButtonModel* _pOriginal, const Reference<XComponentContext>& _rxFactory )
113 2 : :OReferenceValueComponent( _pOriginal, _rxFactory )
114 : {
115 2 : }
116 :
117 :
118 84 : ORadioButtonModel::~ORadioButtonModel()
119 : {
120 84 : }
121 :
122 : // XCloneable
123 :
124 2 : IMPLEMENT_DEFAULT_CLONING( ORadioButtonModel )
125 :
126 : // XServiceInfo
127 :
128 56 : StringSequence SAL_CALL ORadioButtonModel::getSupportedServiceNames() throw(RuntimeException, std::exception)
129 : {
130 56 : StringSequence aSupported = OReferenceValueComponent::getSupportedServiceNames();
131 :
132 56 : sal_Int32 nOldLen = aSupported.getLength();
133 56 : aSupported.realloc( nOldLen + 8 );
134 56 : OUString* pStoreTo = aSupported.getArray() + nOldLen;
135 :
136 56 : *pStoreTo++ = BINDABLE_CONTROL_MODEL;
137 56 : *pStoreTo++ = DATA_AWARE_CONTROL_MODEL;
138 56 : *pStoreTo++ = VALIDATABLE_CONTROL_MODEL;
139 :
140 56 : *pStoreTo++ = BINDABLE_DATA_AWARE_CONTROL_MODEL;
141 56 : *pStoreTo++ = VALIDATABLE_BINDABLE_CONTROL_MODEL;
142 :
143 56 : *pStoreTo++ = FRM_SUN_COMPONENT_RADIOBUTTON;
144 56 : *pStoreTo++ = FRM_SUN_COMPONENT_DATABASE_RADIOBUTTON;
145 56 : *pStoreTo++ = BINDABLE_DATABASE_RADIO_BUTTON;
146 :
147 56 : return aSupported;
148 : }
149 :
150 :
151 64 : void ORadioButtonModel::SetSiblingPropsTo(const OUString& rPropName, const Any& rValue)
152 : {
153 : // my name
154 64 : OUString sMyGroup;
155 64 : if (hasProperty(PROPERTY_GROUP_NAME, this))
156 64 : this->getPropertyValue(PROPERTY_GROUP_NAME) >>= sMyGroup;
157 64 : if (sMyGroup.isEmpty())
158 38 : sMyGroup = m_aName;
159 :
160 : // Iterate over my siblings
161 128 : Reference<XIndexAccess> xIndexAccess(getParent(), UNO_QUERY);
162 64 : if (xIndexAccess.is())
163 : {
164 56 : Reference<XPropertySet> xMyProps;
165 56 : query_interface(static_cast<XWeak*>(this), xMyProps);
166 112 : OUString sCurrentGroup;
167 56 : sal_Int32 nNumSiblings = xIndexAccess->getCount();
168 172 : for (sal_Int32 i=0; i<nNumSiblings; ++i)
169 : {
170 116 : Reference<XPropertySet> xSiblingProperties(*(InterfaceRef*)xIndexAccess->getByIndex(i).getValue(), UNO_QUERY);
171 116 : if (!xSiblingProperties.is())
172 0 : continue;
173 116 : if (xMyProps == xSiblingProperties)
174 56 : continue; // do not set myself
175 :
176 : // Only if it's a RadioButton
177 60 : if (!hasProperty(PROPERTY_CLASSID, xSiblingProperties))
178 0 : continue;
179 60 : sal_Int16 nType = 0;
180 60 : xSiblingProperties->getPropertyValue(PROPERTY_CLASSID) >>= nType;
181 60 : if (nType != FormComponentType::RADIOBUTTON)
182 60 : continue;
183 :
184 : // The group association is attached to the name
185 0 : sCurrentGroup = OGroupManager::GetGroupName( xSiblingProperties );
186 0 : if (sCurrentGroup == sMyGroup)
187 0 : xSiblingProperties->setPropertyValue(rPropName, rValue);
188 56 : }
189 64 : }
190 64 : }
191 :
192 :
193 328 : void ORadioButtonModel::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) throw (Exception, std::exception)
194 : {
195 328 : OReferenceValueComponent::setFastPropertyValue_NoBroadcast( nHandle, rValue );
196 :
197 : // if the label control changed ...
198 328 : if (nHandle == PROPERTY_ID_CONTROLLABEL)
199 : { // ... forward this to our siblings
200 0 : SetSiblingPropsTo(PROPERTY_CONTROLLABEL, rValue);
201 : }
202 :
203 : // If the ControlSource property has changed ...
204 328 : if (nHandle == PROPERTY_ID_CONTROLSOURCE)
205 : { // ... I have to pass the new ControlSource to my siblings, which are in the same RadioButton group as I am
206 32 : SetSiblingPropsTo(PROPERTY_CONTROLSOURCE, rValue);
207 : }
208 :
209 : // The other way: if my name changes ...
210 328 : if (nHandle == PROPERTY_ID_NAME)
211 : {
212 76 : setControlSource();
213 : }
214 :
215 328 : if (nHandle == PROPERTY_ID_DEFAULT_STATE)
216 : {
217 : sal_Int16 nValue;
218 26 : rValue >>= nValue;
219 26 : if (1 == nValue)
220 : { // Reset the 'default checked' for all Radios of the same group.
221 : // Because (as the Highlander already knew): "There can be only one"
222 10 : Any aZero;
223 10 : nValue = 0;
224 10 : aZero <<= nValue;
225 10 : SetSiblingPropsTo(PROPERTY_DEFAULT_STATE, aZero);
226 : }
227 : }
228 328 : }
229 :
230 96 : void ORadioButtonModel::setControlSource()
231 : {
232 96 : Reference<XIndexAccess> xIndexAccess(getParent(), UNO_QUERY);
233 96 : if (xIndexAccess.is())
234 : {
235 112 : OUString sName, sGroupName;
236 :
237 56 : if (hasProperty(PROPERTY_GROUP_NAME, this))
238 56 : this->getPropertyValue(PROPERTY_GROUP_NAME) >>= sGroupName;
239 56 : this->getPropertyValue(PROPERTY_NAME) >>= sName;
240 :
241 112 : Reference<XPropertySet> xMyProps;
242 56 : query_interface(static_cast<XWeak*>(this), xMyProps);
243 180 : for (sal_Int32 i=0; i<xIndexAccess->getCount(); ++i)
244 : {
245 124 : Reference<XPropertySet> xSiblingProperties(*(InterfaceRef*)xIndexAccess->getByIndex(i).getValue(), UNO_QUERY);
246 124 : if (!xSiblingProperties.is())
247 0 : continue;
248 :
249 124 : if (xMyProps == xSiblingProperties)
250 : // Only if I didn't find myself
251 56 : continue;
252 :
253 68 : sal_Int16 nType = 0;
254 68 : xSiblingProperties->getPropertyValue(PROPERTY_CLASSID) >>= nType;
255 68 : if (nType != FormComponentType::RADIOBUTTON)
256 : // Only RadioButtons
257 56 : continue;
258 :
259 24 : OUString sSiblingName, sSiblingGroupName;
260 12 : if (hasProperty(PROPERTY_GROUP_NAME, xSiblingProperties))
261 12 : xSiblingProperties->getPropertyValue(PROPERTY_GROUP_NAME) >>= sSiblingGroupName;
262 12 : xSiblingProperties->getPropertyValue(PROPERTY_NAME) >>= sSiblingName;
263 :
264 48 : if ((sGroupName.isEmpty() && sSiblingGroupName.isEmpty() && // (no group name
265 36 : sName == sSiblingName) || // names match) or
266 12 : (!sGroupName.isEmpty() && !sSiblingGroupName.isEmpty() && // (have group name
267 0 : sGroupName == sSiblingGroupName)) // they match)
268 : {
269 0 : setPropertyValue(PROPERTY_CONTROLSOURCE, xSiblingProperties->getPropertyValue(PROPERTY_CONTROLSOURCE));
270 0 : break;
271 : }
272 68 : }
273 96 : }
274 96 : }
275 :
276 :
277 50 : void ORadioButtonModel::describeFixedProperties( Sequence< Property >& _rProps ) const
278 : {
279 50 : BEGIN_DESCRIBE_PROPERTIES( 1, OReferenceValueComponent )
280 50 : DECL_PROP1(TABINDEX, sal_Int16, BOUND);
281 : END_DESCRIBE_PROPERTIES();
282 50 : }
283 :
284 :
285 4 : OUString SAL_CALL ORadioButtonModel::getServiceName() throw(RuntimeException, std::exception)
286 : {
287 4 : return OUString(FRM_COMPONENT_RADIOBUTTON); // old (non-sun) name for compatibility !
288 : }
289 :
290 :
291 2 : void SAL_CALL ORadioButtonModel::write(const Reference<XObjectOutputStream>& _rxOutStream)
292 : throw(IOException, RuntimeException, std::exception)
293 : {
294 2 : OReferenceValueComponent::write(_rxOutStream);
295 :
296 : // Version
297 2 : _rxOutStream->writeShort(0x0003);
298 :
299 : // Properties
300 2 : _rxOutStream << getReferenceValue();
301 2 : _rxOutStream << (sal_Int16)getDefaultChecked();
302 2 : writeHelpTextCompatibly(_rxOutStream);
303 :
304 : // from version 0x0003 : common properties
305 2 : writeCommonProperties(_rxOutStream);
306 2 : }
307 :
308 :
309 2 : void SAL_CALL ORadioButtonModel::read(const Reference<XObjectInputStream>& _rxInStream) throw(IOException, RuntimeException, std::exception)
310 : {
311 2 : OReferenceValueComponent::read(_rxInStream);
312 2 : ::osl::MutexGuard aGuard(m_aMutex);
313 :
314 : // Version
315 2 : sal_uInt16 nVersion = _rxInStream->readShort();
316 :
317 4 : OUString sReferenceValue;
318 2 : sal_Int16 nDefaultChecked( 0 );
319 2 : switch (nVersion)
320 : {
321 : case 0x0001 :
322 0 : _rxInStream >> sReferenceValue;
323 0 : _rxInStream >> nDefaultChecked;
324 0 : break;
325 : case 0x0002 :
326 0 : _rxInStream >> sReferenceValue;
327 0 : _rxInStream >> nDefaultChecked;
328 0 : readHelpTextCompatibly(_rxInStream);
329 0 : break;
330 : case 0x0003 :
331 2 : _rxInStream >> sReferenceValue;
332 2 : _rxInStream >> nDefaultChecked;
333 2 : readHelpTextCompatibly(_rxInStream);
334 2 : readCommonProperties(_rxInStream);
335 2 : break;
336 : default :
337 : OSL_FAIL("ORadioButtonModel::read : unknown version !");
338 0 : defaultCommonProperties();
339 0 : break;
340 : }
341 :
342 2 : setReferenceValue( sReferenceValue );
343 2 : setDefaultChecked( (ToggleState)nDefaultChecked );
344 :
345 : // Display default values after read
346 2 : if ( !getControlSource().isEmpty() )
347 : // (not if we don't have a control source - the "State" property acts like it is persistent, then
348 4 : resetNoBroadcast();
349 2 : }
350 :
351 :
352 70 : void ORadioButtonModel::_propertyChanged(const PropertyChangeEvent& _rEvent) throw(RuntimeException)
353 : {
354 70 : if ( _rEvent.PropertyName.equals( PROPERTY_STATE ) )
355 : {
356 50 : if ( _rEvent.NewValue == (sal_Int16)1 )
357 : {
358 : // If my status has changed to 'checked', I have to reset all my siblings, which are in the same group as I am
359 22 : Any aZero;
360 22 : aZero <<= (sal_Int16)0;
361 22 : SetSiblingPropsTo( PROPERTY_STATE, aZero );
362 : }
363 : }
364 20 : else if ( _rEvent.PropertyName.equals( PROPERTY_GROUP_NAME ) )
365 : {
366 20 : setControlSource();
367 : // Can't call OReferenceValueComponent::_propertyChanged(), as it
368 : // doesn't know what to do with the GroupName property.
369 90 : return;
370 : }
371 :
372 50 : OReferenceValueComponent::_propertyChanged( _rEvent );
373 : }
374 :
375 :
376 0 : Any ORadioButtonModel::translateDbColumnToControlValue()
377 : {
378 : return makeAny( (sal_Int16)
379 0 : ( ( m_xColumn->getString() == getReferenceValue() ) ? TRISTATE_TRUE : TRISTATE_FALSE )
380 0 : );
381 : }
382 :
383 :
384 6 : Any ORadioButtonModel::translateExternalValueToControlValue( const Any& _rExternalValue ) const
385 : {
386 6 : Any aControlValue = OReferenceValueComponent::translateExternalValueToControlValue( _rExternalValue );
387 6 : sal_Int16 nState = TRISTATE_FALSE;
388 6 : if ( ( aControlValue >>= nState ) && ( nState == TRISTATE_INDET ) )
389 : // radio buttons do not have the DONTKNOW state
390 4 : aControlValue <<= (sal_Int16)TRISTATE_FALSE;
391 6 : return aControlValue;
392 : }
393 :
394 :
395 0 : bool ORadioButtonModel::commitControlValueToDbColumn( bool /*_bPostReset*/ )
396 : {
397 0 : Reference< XPropertySet > xField( getField() );
398 : OSL_PRECOND( xField.is(), "ORadioButtonModel::commitControlValueToDbColumn: not bound!" );
399 0 : if ( xField.is() )
400 : {
401 : try
402 : {
403 0 : sal_Int16 nValue = 0;
404 0 : m_xAggregateSet->getPropertyValue( PROPERTY_STATE ) >>= nValue;
405 0 : if ( nValue == 1 )
406 0 : xField->setPropertyValue( PROPERTY_VALUE, makeAny( getReferenceValue() ) );
407 : }
408 0 : catch(const Exception&)
409 : {
410 : OSL_FAIL("ORadioButtonModel::commitControlValueToDbColumn: could not commit !");
411 : }
412 : }
413 0 : return true;
414 : }
415 :
416 :
417 : }
418 :
419 :
420 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|