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 "GroupManager.hxx"
21 #include <com/sun/star/beans/XFastPropertySet.hpp>
22 #include <com/sun/star/form/FormComponentType.hpp>
23 #include <comphelper/property.hxx>
24 #include <osl/diagnose.h>
25 #include <tools/solar.h>
27 #include "property.hrc"
33 using namespace ::com::sun::star::uno
;
34 using namespace ::com::sun::star::sdbc
;
35 using namespace ::com::sun::star::beans
;
36 using namespace ::com::sun::star::container
;
37 using namespace ::com::sun::star::form
;
38 using namespace ::com::sun::star::awt
;
39 using namespace ::com::sun::star::lang
;
43 bool isRadioButton( const Reference
< XPropertySet
>& _rxComponent
)
46 if ( hasProperty( PROPERTY_CLASSID
, _rxComponent
) )
48 sal_Int16 nClassId
= FormComponentType::CONTROL
;
49 _rxComponent
->getPropertyValue( PROPERTY_CLASSID
) >>= nClassId
;
50 if ( nClassId
== FormComponentType::RADIOBUTTON
)
57 OGroupCompAcc::OGroupCompAcc(const Reference
<XPropertySet
>& rxElement
, const OGroupComp
& _rGroupComp
)
58 :m_xComponent( rxElement
)
59 ,m_aGroupComp( _rGroupComp
)
63 bool OGroupCompAcc::operator==( const OGroupCompAcc
& rCompAcc
) const
65 return (m_xComponent
== rCompAcc
.GetComponent());
68 class OGroupCompAccLess
: public ::std::binary_function
<OGroupCompAcc
, OGroupCompAcc
, sal_Bool
>
71 bool operator() (const OGroupCompAcc
& lhs
, const OGroupCompAcc
& rhs
) const
74 reinterpret_cast<sal_Int64
>(lhs
.m_xComponent
.get())
75 < reinterpret_cast<sal_Int64
>(rhs
.m_xComponent
.get());
79 OGroupComp::OGroupComp()
85 OGroupComp::OGroupComp(const OGroupComp
& _rSource
)
86 :m_aName( _rSource
.m_aName
)
87 ,m_xComponent( _rSource
.m_xComponent
)
88 ,m_xControlModel(_rSource
.m_xControlModel
)
89 ,m_nPos( _rSource
.m_nPos
)
90 ,m_nTabIndex( _rSource
.m_nTabIndex
)
94 OGroupComp::OGroupComp(const Reference
<XPropertySet
>& rxSet
, sal_Int32 nInsertPos
)
95 : m_aName( OGroupManager::GetGroupName( rxSet
) )
96 , m_xComponent( rxSet
)
97 , m_xControlModel(rxSet
,UNO_QUERY
)
98 , m_nPos( nInsertPos
)
101 if (m_xComponent
.is())
103 if (hasProperty( PROPERTY_TABINDEX
, m_xComponent
) )
104 // Indices smaller than 0 are treated like 0
105 m_nTabIndex
= std::max(getINT16(m_xComponent
->getPropertyValue( PROPERTY_TABINDEX
)) , sal_Int16(0));
109 bool OGroupComp::operator==( const OGroupComp
& rComp
) const
111 return m_nTabIndex
== rComp
.GetTabIndex() && m_nPos
== rComp
.GetPos();
114 class OGroupCompLess
: public ::std::binary_function
<OGroupComp
, OGroupComp
, sal_Bool
>
117 bool operator() (const OGroupComp
& lhs
, const OGroupComp
& rhs
) const
120 // TabIndex of 0 will be added at the end
121 if (lhs
.m_nTabIndex
== rhs
.GetTabIndex())
122 bResult
= lhs
.m_nPos
< rhs
.GetPos();
123 else if (lhs
.m_nTabIndex
&& rhs
.GetTabIndex())
124 bResult
= lhs
.m_nTabIndex
< rhs
.GetTabIndex();
126 bResult
= lhs
.m_nTabIndex
!= 0;
131 OGroup::OGroup( const OUString
& rGroupName
)
132 :m_aGroupName( rGroupName
)
141 void OGroup::InsertComponent( const Reference
<XPropertySet
>& xSet
)
143 OGroupComp
aNewGroupComp( xSet
, m_nInsertPos
);
144 sal_Int32 nPosInserted
= insert_sorted(m_aCompArray
, aNewGroupComp
, OGroupCompLess());
146 OGroupCompAcc
aNewGroupCompAcc( xSet
, m_aCompArray
[nPosInserted
] );
147 insert_sorted(m_aCompAccArray
, aNewGroupCompAcc
, OGroupCompAccLess());
151 void OGroup::RemoveComponent( const Reference
<XPropertySet
>& rxElement
)
153 sal_Int32 nGroupCompAccPos
;
154 OGroupCompAcc
aSearchCompAcc( rxElement
, OGroupComp() );
155 if ( seek_entry(m_aCompAccArray
, aSearchCompAcc
, nGroupCompAccPos
, OGroupCompAccLess()) )
157 OGroupCompAcc
& aGroupCompAcc
= m_aCompAccArray
[nGroupCompAccPos
];
158 const OGroupComp
& aGroupComp
= aGroupCompAcc
.GetGroupComponent();
160 sal_Int32 nGroupCompPos
;
161 if ( seek_entry(m_aCompArray
, aGroupComp
, nGroupCompPos
, OGroupCompLess()) )
163 m_aCompAccArray
.erase( m_aCompAccArray
.begin() + nGroupCompAccPos
);
164 m_aCompArray
.erase( m_aCompArray
.begin() + nGroupCompPos
);
167 * By removing the GroupComp the insertion position has become invalid.
168 * We do not to change it here, however, because its passed on continuously
169 * and ascending distinctively.
174 OSL_FAIL( "OGroup::RemoveComponent: Component not in Group" );
179 OSL_FAIL( "OGroup::RemoveComponent: Component not in Group" );
183 bool OGroup::operator==( const OGroup
& rGroup
) const
185 return m_aGroupName
.equals(rGroup
.GetGroupName());
188 Sequence
< Reference
<XControlModel
> > OGroup::GetControlModels() const
190 sal_Int32 nLen
= m_aCompArray
.size();
191 Sequence
<Reference
<XControlModel
> > aControlModelSeq( nLen
);
192 Reference
<XControlModel
>* pModels
= aControlModelSeq
.getArray();
194 OGroupCompArr::const_iterator aGroupComps
= m_aCompArray
.begin();
195 for (sal_Int32 i
= 0; i
< nLen
; ++i
, ++pModels
, ++aGroupComps
)
197 *pModels
= aGroupComps
->GetControlModel();
199 return aControlModelSeq
;
202 OGroupManager::OGroupManager(const Reference
< XContainer
>& _rxContainer
)
203 :m_pCompGroup( new OGroup( OUString("AllComponentGroup") ) )
204 ,m_xContainer(_rxContainer
)
206 osl_atomic_increment(&m_refCount
);
208 _rxContainer
->addContainerListener(this);
210 osl_atomic_decrement(&m_refCount
);
213 OGroupManager::~OGroupManager()
215 // delete all Components and CompGroup
219 // XPropertyChangeListener
220 void OGroupManager::disposing(const EventObject
& evt
) throw( RuntimeException
, std::exception
)
222 Reference
<XContainer
> xContainer(evt
.Source
, UNO_QUERY
);
223 if (xContainer
.get() == m_xContainer
.get())
225 DELETEZ(m_pCompGroup
);
229 m_xContainer
.clear();
233 void OGroupManager::removeFromGroupMap(const OUString
& _sGroupName
,const Reference
<XPropertySet
>& _xSet
)
235 // remove Component from CompGroup
236 m_pCompGroup
->RemoveComponent( _xSet
);
238 OGroupArr::iterator aFind
= m_aGroupArr
.find(_sGroupName
);
240 if ( aFind
!= m_aGroupArr
.end() )
243 aFind
->second
.RemoveComponent( _xSet
);
245 // If the count of Group elements == 1 -> deactivate Group
246 sal_Int32 nCount
= aFind
->second
.Count();
247 if ( nCount
== 1 || nCount
== 0 )
249 OActiveGroups::iterator aActiveFind
= ::std::find(
250 m_aActiveGroupMap
.begin(),
251 m_aActiveGroupMap
.end(),
254 if ( aActiveFind
!= m_aActiveGroupMap
.end() )
256 // the group is active. Deactivate it if the remaining component
257 // is *no* radio button
258 if ( nCount
== 0 || !isRadioButton( aFind
->second
.GetObject( 0 ) ) )
259 m_aActiveGroupMap
.erase( aActiveFind
);
265 // Deregister as PropertyChangeListener at Component
266 _xSet
->removePropertyChangeListener( PROPERTY_NAME
, this );
267 if (hasProperty(PROPERTY_GROUP_NAME
, _xSet
))
268 _xSet
->removePropertyChangeListener( PROPERTY_GROUP_NAME
, this );
269 if (hasProperty(PROPERTY_TABINDEX
, _xSet
))
270 _xSet
->removePropertyChangeListener( PROPERTY_TABINDEX
, this );
273 void SAL_CALL
OGroupManager::propertyChange(const PropertyChangeEvent
& evt
) throw ( ::com::sun::star::uno::RuntimeException
, std::exception
)
275 Reference
<XPropertySet
> xSet(evt
.Source
, UNO_QUERY
);
277 // remove Component from group
279 if (hasProperty( PROPERTY_GROUP_NAME
, xSet
))
280 xSet
->getPropertyValue( PROPERTY_GROUP_NAME
) >>= sGroupName
;
281 if (evt
.PropertyName
== PROPERTY_NAME
) {
282 if (!sGroupName
.isEmpty())
283 return; // group hasn't changed; ignore this name change.
284 // no GroupName; use Name as GroupNme
285 evt
.OldValue
>>= sGroupName
;
287 else if (evt
.PropertyName
== PROPERTY_GROUP_NAME
) {
288 evt
.OldValue
>>= sGroupName
;
289 if (sGroupName
.isEmpty()) {
290 // No prior GroupName; fallback to Nme
291 xSet
->getPropertyValue( PROPERTY_NAME
) >>= sGroupName
;
295 sGroupName
= GetGroupName( xSet
);
297 removeFromGroupMap(sGroupName
,xSet
);
299 // Re-insert Component
300 InsertElement( xSet
);
303 // XContainerListener
304 void SAL_CALL
OGroupManager::elementInserted(const ContainerEvent
& Event
) throw ( ::com::sun::star::uno::RuntimeException
, std::exception
)
306 Reference
< XPropertySet
> xProps
;
307 Event
.Element
>>= xProps
;
309 InsertElement( xProps
);
312 void SAL_CALL
OGroupManager::elementRemoved(const ContainerEvent
& Event
) throw ( ::com::sun::star::uno::RuntimeException
, std::exception
)
314 Reference
<XPropertySet
> xProps
;
315 Event
.Element
>>= xProps
;
317 RemoveElement( xProps
);
320 void SAL_CALL
OGroupManager::elementReplaced(const ContainerEvent
& Event
) throw ( ::com::sun::star::uno::RuntimeException
, std::exception
)
322 Reference
<XPropertySet
> xProps
;
323 Event
.ReplacedElement
>>= xProps
;
325 RemoveElement( xProps
);
328 Event
.Element
>>= xProps
;
330 InsertElement( xProps
);
334 Sequence
<Reference
<XControlModel
> > OGroupManager::getControlModels()
336 return m_pCompGroup
->GetControlModels();
339 sal_Int32
OGroupManager::getGroupCount()
341 return m_aActiveGroupMap
.size();
344 void OGroupManager::getGroup(sal_Int32 nGroup
, Sequence
< Reference
<XControlModel
> >& _rGroup
, OUString
& _rName
)
346 OSL_ENSURE(nGroup
>= 0 && (size_t)nGroup
< m_aActiveGroupMap
.size(),"OGroupManager::getGroup: Invalid group index!");
347 OGroupArr::iterator aGroupPos
= m_aActiveGroupMap
[nGroup
];
348 _rName
= aGroupPos
->second
.GetGroupName();
349 _rGroup
= aGroupPos
->second
.GetControlModels();
352 void OGroupManager::getGroupByName(const OUString
& _rName
, Sequence
< Reference
<XControlModel
> >& _rGroup
)
354 OGroupArr::iterator aFind
= m_aGroupArr
.find(_rName
);
355 if ( aFind
!= m_aGroupArr
.end() )
356 _rGroup
= aFind
->second
.GetControlModels();
359 void OGroupManager::InsertElement( const Reference
<XPropertySet
>& xSet
)
361 // Only ControlModels
362 Reference
<XControlModel
> xControl(xSet
, UNO_QUERY
);
366 // Add Component to CompGroup
367 m_pCompGroup
->InsertComponent( xSet
);
369 // Add Component to Group
370 OUString
sGroupName( GetGroupName( xSet
) );
372 OGroupArr::iterator aFind
= m_aGroupArr
.find(sGroupName
);
374 if ( aFind
== m_aGroupArr
.end() )
376 aFind
= m_aGroupArr
.insert(OGroupArr::value_type(sGroupName
,OGroup(sGroupName
))).first
;
379 aFind
->second
.InsertComponent( xSet
);
381 // if we have at least 2 elements in the group, then this is an "active group"
382 bool bActivateGroup
= aFind
->second
.Count() == 2;
384 // Additionally, if the component is a radio button, then it's group becomes active,
385 // too. With this, we ensure that in a container with n radio buttons which all are
386 // in different groups the selection still works reliably (means that all radios can be
387 // clicked independently)
388 if ( aFind
->second
.Count() == 1 )
390 if ( isRadioButton( xSet
) )
391 bActivateGroup
= true;
394 if ( bActivateGroup
)
396 OActiveGroups::iterator aAlreadyExistent
= ::std::find(
397 m_aActiveGroupMap
.begin(),
398 m_aActiveGroupMap
.end(),
401 if ( aAlreadyExistent
== m_aActiveGroupMap
.end() )
402 m_aActiveGroupMap
.push_back( aFind
);
405 // Register as PropertyChangeListener at Component
406 xSet
->addPropertyChangeListener( PROPERTY_NAME
, this );
407 if (hasProperty(PROPERTY_GROUP_NAME
, xSet
))
408 xSet
->addPropertyChangeListener( PROPERTY_GROUP_NAME
, this );
410 // Not everyone needs to support Tabindex
411 if (hasProperty(PROPERTY_TABINDEX
, xSet
))
412 xSet
->addPropertyChangeListener( PROPERTY_TABINDEX
, this );
415 void OGroupManager::RemoveElement( const Reference
<XPropertySet
>& xSet
)
417 // Only ControlModels
418 Reference
<XControlModel
> xControl(xSet
, UNO_QUERY
);
422 // Remove Component from Group
423 OUString
sGroupName( GetGroupName( xSet
) );
425 removeFromGroupMap(sGroupName
,xSet
);
428 OUString
OGroupManager::GetGroupName( ::com::sun::star::uno::Reference
< ::com::sun::star::beans::XPropertySet
> xComponent
)
430 if (!xComponent
.is())
433 if (hasProperty( PROPERTY_GROUP_NAME
, xComponent
)) {
434 xComponent
->getPropertyValue( PROPERTY_GROUP_NAME
) >>= sGroupName
;
435 if (sGroupName
.isEmpty())
436 xComponent
->getPropertyValue( PROPERTY_NAME
) >>= sGroupName
;
439 xComponent
->getPropertyValue( PROPERTY_NAME
) >>= sGroupName
;
444 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */