bump product version to 5.0.4.1
[LibreOffice.git] / forms / source / component / GroupManager.cxx
blobb8eedbd82f66ec4615f7134504804e9be5915ba9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
29 #include <algorithm>
31 namespace frm
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;
41 namespace
43 bool isRadioButton( const Reference< XPropertySet >& _rxComponent )
45 bool bIs = false;
46 if ( hasProperty( PROPERTY_CLASSID, _rxComponent ) )
48 sal_Int16 nClassId = FormComponentType::CONTROL;
49 _rxComponent->getPropertyValue( PROPERTY_CLASSID ) >>= nClassId;
50 if ( nClassId == FormComponentType::RADIOBUTTON )
51 bIs = true;
53 return bIs;
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>
70 public:
71 bool operator() (const OGroupCompAcc& lhs, const OGroupCompAcc& rhs) const
73 return
74 reinterpret_cast<sal_Int64>(lhs.m_xComponent.get())
75 < reinterpret_cast<sal_Int64>(rhs.m_xComponent.get());
79 OGroupComp::OGroupComp()
80 :m_nPos( -1 )
81 ,m_nTabIndex( 0 )
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 )
99 , m_nTabIndex(0)
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>
116 public:
117 bool operator() (const OGroupComp& lhs, const OGroupComp& rhs) const
119 bool bResult;
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();
125 else
126 bResult = lhs.m_nTabIndex != 0;
127 return bResult;
131 OGroup::OGroup( const OUString& rGroupName )
132 :m_aGroupName( rGroupName )
133 ,m_nInsertPos(0)
137 OGroup::~OGroup()
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());
148 m_nInsertPos++;
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.
172 else
174 OSL_FAIL( "OGroup::RemoveComponent: Component not in Group" );
177 else
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
216 delete m_pCompGroup;
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);
227 // delete group
228 m_aGroupArr.clear();
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() )
242 // group exists
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(),
252 aFind
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
278 OUString sGroupName;
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;
294 else
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;
308 if ( xProps.is() )
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;
316 if ( xProps.is() )
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;
324 if ( xProps.is() )
325 RemoveElement( xProps );
327 xProps.clear();
328 Event.Element >>= xProps;
329 if ( xProps.is() )
330 InsertElement( xProps );
333 // Other functions
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);
363 if (!xControl.is() )
364 return;
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(),
399 aFind
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);
419 if (!xControl.is() )
420 return;
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())
431 return OUString();
432 OUString sGroupName;
433 if (hasProperty( PROPERTY_GROUP_NAME, xComponent )) {
434 xComponent->getPropertyValue( PROPERTY_GROUP_NAME ) >>= sGroupName;
435 if (sGroupName.isEmpty())
436 xComponent->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
438 else
439 xComponent->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
440 return sGroupName;
442 } // namespace frm
444 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */