bump product version to 4.1.6.2
[LibreOffice.git] / forms / source / component / GroupManager.cxx
blob926c0cf34e7995767722674a4f02d100fe1bd1da
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 <comphelper/uno3.hxx>
25 #include <tools/solar.h>
26 #include <tools/debug.hxx>
28 #include "property.hrc"
30 #include <algorithm>
32 //.........................................................................
33 namespace frm
35 //.........................................................................
37 using namespace ::com::sun::star::uno;
38 using namespace ::com::sun::star::sdbc;
39 using namespace ::com::sun::star::beans;
40 using namespace ::com::sun::star::container;
41 using namespace ::com::sun::star::form;
42 using namespace ::com::sun::star::awt;
43 using namespace ::com::sun::star::lang;
45 namespace
47 bool isRadioButton( const Reference< XPropertySet >& _rxComponent )
49 bool bIs = false;
50 if ( hasProperty( PROPERTY_CLASSID, _rxComponent ) )
52 sal_Int16 nClassId = FormComponentType::CONTROL;
53 _rxComponent->getPropertyValue( PROPERTY_CLASSID ) >>= nClassId;
54 if ( nClassId == FormComponentType::RADIOBUTTON )
55 bIs = true;
57 return bIs;
61 //========================================================================
62 // class OGroupCompAcc
63 //========================================================================
64 //------------------------------------------------------------------
65 OGroupCompAcc::OGroupCompAcc(const Reference<XPropertySet>& rxElement, const OGroupComp& _rGroupComp )
66 :m_xComponent( rxElement )
67 ,m_aGroupComp( _rGroupComp )
71 //------------------------------------------------------------------
72 sal_Bool OGroupCompAcc::operator==( const OGroupCompAcc& rCompAcc ) const
74 return (m_xComponent == rCompAcc.GetComponent());
77 //------------------------------------------------------------------
78 class OGroupCompAccLess : public ::std::binary_function<OGroupCompAcc, OGroupCompAcc, sal_Bool>
80 public:
81 sal_Bool operator() (const OGroupCompAcc& lhs, const OGroupCompAcc& rhs) const
83 return
84 reinterpret_cast<sal_Int64>(lhs.m_xComponent.get())
85 < reinterpret_cast<sal_Int64>(rhs.m_xComponent.get());
89 //========================================================================
90 // class OGroupComp
91 //========================================================================
93 //------------------------------------------------------------------
94 OGroupComp::OGroupComp()
95 :m_nPos( -1 )
96 ,m_nTabIndex( 0 )
100 //------------------------------------------------------------------
101 OGroupComp::OGroupComp(const OGroupComp& _rSource)
102 :m_aName( _rSource.m_aName )
103 ,m_xComponent( _rSource.m_xComponent )
104 ,m_xControlModel(_rSource.m_xControlModel)
105 ,m_nPos( _rSource.m_nPos )
106 ,m_nTabIndex( _rSource.m_nTabIndex )
110 //------------------------------------------------------------------
111 OGroupComp::OGroupComp(const Reference<XPropertySet>& rxSet, sal_Int32 nInsertPos )
112 : m_aName( OGroupManager::GetGroupName( rxSet ) )
113 , m_xComponent( rxSet )
114 , m_xControlModel(rxSet,UNO_QUERY)
115 , m_nPos( nInsertPos )
116 , m_nTabIndex(0)
118 if (m_xComponent.is())
120 if (hasProperty( PROPERTY_TABINDEX, m_xComponent ) )
121 // Indices kleiner 0 werden wie 0 behandelt
122 m_nTabIndex = std::max(getINT16(m_xComponent->getPropertyValue( PROPERTY_TABINDEX )) , sal_Int16(0));
126 //------------------------------------------------------------------
127 sal_Bool OGroupComp::operator==( const OGroupComp& rComp ) const
129 return m_nTabIndex == rComp.GetTabIndex() && m_nPos == rComp.GetPos();
132 //------------------------------------------------------------------
133 class OGroupCompLess : public ::std::binary_function<OGroupComp, OGroupComp, sal_Bool>
135 public:
136 sal_Bool operator() (const OGroupComp& lhs, const OGroupComp& rhs) const
138 sal_Bool bResult;
139 // TabIndex von 0 wird hinten einsortiert
140 if (lhs.m_nTabIndex == rhs.GetTabIndex())
141 bResult = lhs.m_nPos < rhs.GetPos();
142 else if (lhs.m_nTabIndex && rhs.GetTabIndex())
143 bResult = lhs.m_nTabIndex < rhs.GetTabIndex();
144 else
145 bResult = lhs.m_nTabIndex != 0;
146 return bResult;
150 //========================================================================
151 // class OGroup
152 //========================================================================
154 DBG_NAME(OGroup)
155 //------------------------------------------------------------------
156 OGroup::OGroup( const OUString& rGroupName )
157 :m_aGroupName( rGroupName )
158 ,m_nInsertPos(0)
160 DBG_CTOR(OGroup,NULL);
163 #ifdef DBG_UTIL
164 //------------------------------------------------------------------
165 OGroup::OGroup( const OGroup& _rSource )
166 :m_aCompArray(_rSource.m_aCompArray)
167 ,m_aCompAccArray(_rSource.m_aCompAccArray)
168 ,m_aGroupName(_rSource.m_aGroupName)
169 ,m_nInsertPos(_rSource.m_nInsertPos)
171 DBG_CTOR(OGroup,NULL);
173 #endif
175 //------------------------------------------------------------------
176 OGroup::~OGroup()
178 DBG_DTOR(OGroup,NULL);
181 //------------------------------------------------------------------
182 void OGroup::InsertComponent( const Reference<XPropertySet>& xSet )
184 OGroupComp aNewGroupComp( xSet, m_nInsertPos );
185 sal_Int32 nPosInserted = insert_sorted(m_aCompArray, aNewGroupComp, OGroupCompLess());
187 OGroupCompAcc aNewGroupCompAcc( xSet, m_aCompArray[nPosInserted] );
188 insert_sorted(m_aCompAccArray, aNewGroupCompAcc, OGroupCompAccLess());
189 m_nInsertPos++;
192 //------------------------------------------------------------------
193 void OGroup::RemoveComponent( const Reference<XPropertySet>& rxElement )
195 sal_Int32 nGroupCompAccPos;
196 OGroupCompAcc aSearchCompAcc( rxElement, OGroupComp() );
197 if ( seek_entry(m_aCompAccArray, aSearchCompAcc, nGroupCompAccPos, OGroupCompAccLess()) )
199 OGroupCompAcc& aGroupCompAcc = m_aCompAccArray[nGroupCompAccPos];
200 const OGroupComp& aGroupComp = aGroupCompAcc.GetGroupComponent();
202 sal_Int32 nGroupCompPos;
203 if ( seek_entry(m_aCompArray, aGroupComp, nGroupCompPos, OGroupCompLess()) )
205 m_aCompAccArray.erase( m_aCompAccArray.begin() + nGroupCompAccPos );
206 m_aCompArray.erase( m_aCompArray.begin() + nGroupCompPos );
208 /*============================================================
209 Durch das Entfernen der GroupComp ist die Einfuegeposition
210 ungueltig geworden. Sie braucht hier aber nicht angepasst werden,
211 da sie fortlaufend vergeben wird und damit immer
212 aufsteigend eindeutig ist.
213 ============================================================*/
215 else
217 OSL_FAIL( "OGroup::RemoveComponent: Component nicht in Gruppe" );
220 else
222 OSL_FAIL( "OGroup::RemoveComponent: Component nicht in Gruppe" );
226 //------------------------------------------------------------------
227 sal_Bool OGroup::operator==( const OGroup& rGroup ) const
229 return m_aGroupName.equals(rGroup.GetGroupName());
232 //------------------------------------------------------------------
233 class OGroupLess : public ::std::binary_function<OGroup, OGroup, sal_Bool>
235 public:
236 sal_Bool operator() (const OGroup& lhs, const OGroup& rhs) const
238 return lhs.m_aGroupName < rhs.m_aGroupName;
242 //------------------------------------------------------------------
243 Sequence< Reference<XControlModel> > OGroup::GetControlModels() const
245 sal_Int32 nLen = m_aCompArray.size();
246 Sequence<Reference<XControlModel> > aControlModelSeq( nLen );
247 Reference<XControlModel>* pModels = aControlModelSeq.getArray();
249 ConstOGroupCompArrIterator aGroupComps = m_aCompArray.begin();
250 for (sal_Int32 i = 0; i < nLen; ++i, ++pModels, ++aGroupComps)
252 *pModels = aGroupComps->GetControlModel();
254 return aControlModelSeq;
257 DBG_NAME(OGroupManager);
258 //------------------------------------------------------------------
259 OGroupManager::OGroupManager(const Reference< XContainer >& _rxContainer)
260 :m_pCompGroup( new OGroup( OUString("AllComponentGroup") ) )
261 ,m_xContainer(_rxContainer)
263 DBG_CTOR(OGroupManager,NULL);
265 increment(m_refCount);
267 _rxContainer->addContainerListener(this);
269 decrement(m_refCount);
272 //------------------------------------------------------------------
273 OGroupManager::~OGroupManager()
275 DBG_DTOR(OGroupManager,NULL);
276 // Alle Components und CompGroup loeschen
277 delete m_pCompGroup;
280 // XPropertyChangeListener
281 //------------------------------------------------------------------
282 void OGroupManager::disposing(const EventObject& evt) throw( RuntimeException )
284 Reference<XContainer> xContainer(evt.Source, UNO_QUERY);
285 if (xContainer.get() == m_xContainer.get())
287 DELETEZ(m_pCompGroup);
289 ////////////////////////////////////////////////////////////////
290 // Gruppen loeschen
291 m_aGroupArr.clear();
292 m_xContainer.clear();
295 // -----------------------------------------------------------------------------
296 void OGroupManager::removeFromGroupMap(const OUString& _sGroupName,const Reference<XPropertySet>& _xSet)
298 // Component aus CompGroup entfernen
299 m_pCompGroup->RemoveComponent( _xSet );
301 OGroupArr::iterator aFind = m_aGroupArr.find(_sGroupName);
303 if ( aFind != m_aGroupArr.end() )
305 // Gruppe vorhanden
306 aFind->second.RemoveComponent( _xSet );
308 // Wenn Anzahl der Gruppenelemente == 1 ist, Gruppe deaktivieren
309 sal_Int32 nCount = aFind->second.Count();
310 if ( nCount == 1 || nCount == 0 )
312 OActiveGroups::iterator aActiveFind = ::std::find(
313 m_aActiveGroupMap.begin(),
314 m_aActiveGroupMap.end(),
315 aFind
317 if ( aActiveFind != m_aActiveGroupMap.end() )
319 // the group is active. Deactivate it if the remaining component
320 // is *no* radio button
321 if ( nCount == 0 || !isRadioButton( aFind->second.GetObject( 0 ) ) )
322 m_aActiveGroupMap.erase( aActiveFind );
328 // Bei Component als PropertyChangeListener abmelden
329 _xSet->removePropertyChangeListener( PROPERTY_NAME, this );
330 if (hasProperty(PROPERTY_GROUP_NAME, _xSet))
331 _xSet->removePropertyChangeListener( PROPERTY_GROUP_NAME, this );
332 if (hasProperty(PROPERTY_TABINDEX, _xSet))
333 _xSet->removePropertyChangeListener( PROPERTY_TABINDEX, this );
335 //------------------------------------------------------------------
336 void SAL_CALL OGroupManager::propertyChange(const PropertyChangeEvent& evt) throw ( ::com::sun::star::uno::RuntimeException)
338 Reference<XPropertySet> xSet(evt.Source, UNO_QUERY);
340 // Component aus Gruppe entfernen
341 OUString sGroupName;
342 if (hasProperty( PROPERTY_GROUP_NAME, xSet ))
343 xSet->getPropertyValue( PROPERTY_GROUP_NAME ) >>= sGroupName;
344 if (evt.PropertyName == PROPERTY_NAME) {
345 if (!sGroupName.isEmpty())
346 return; // group hasn't changed; ignore this name change.
347 // no GroupName; use Name as GroupNme
348 evt.OldValue >>= sGroupName;
350 else if (evt.PropertyName == PROPERTY_GROUP_NAME) {
351 evt.OldValue >>= sGroupName;
352 if (sGroupName.isEmpty()) {
353 // No prior GroupName; fallback to Nme
354 xSet->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
357 else
358 sGroupName = GetGroupName( xSet );
360 removeFromGroupMap(sGroupName,xSet);
362 // Component neu einordnen
363 InsertElement( xSet );
366 // XContainerListener
367 //------------------------------------------------------------------
368 void SAL_CALL OGroupManager::elementInserted(const ContainerEvent& Event) throw ( ::com::sun::star::uno::RuntimeException)
370 Reference< XPropertySet > xProps;
371 Event.Element >>= xProps;
372 if ( xProps.is() )
373 InsertElement( xProps );
376 //------------------------------------------------------------------
377 void SAL_CALL OGroupManager::elementRemoved(const ContainerEvent& Event) throw ( ::com::sun::star::uno::RuntimeException)
379 Reference<XPropertySet> xProps;
380 Event.Element >>= xProps;
381 if ( xProps.is() )
382 RemoveElement( xProps );
385 //------------------------------------------------------------------
386 void SAL_CALL OGroupManager::elementReplaced(const ContainerEvent& Event) throw ( ::com::sun::star::uno::RuntimeException)
388 Reference<XPropertySet> xProps;
389 Event.ReplacedElement >>= xProps;
390 if ( xProps.is() )
391 RemoveElement( xProps );
393 xProps.clear();
394 Event.Element >>= xProps;
395 if ( xProps.is() )
396 InsertElement( xProps );
399 // Other functions
400 //------------------------------------------------------------------
401 Sequence<Reference<XControlModel> > OGroupManager::getControlModels()
403 return m_pCompGroup->GetControlModels();
406 //------------------------------------------------------------------
407 sal_Int32 OGroupManager::getGroupCount()
409 return m_aActiveGroupMap.size();
412 //------------------------------------------------------------------
413 void OGroupManager::getGroup(sal_Int32 nGroup, Sequence< Reference<XControlModel> >& _rGroup, OUString& _rName)
415 OSL_ENSURE(nGroup >= 0 && (size_t)nGroup < m_aActiveGroupMap.size(),"OGroupManager::getGroup: Invalid group index!");
416 OGroupArr::iterator aGroupPos = m_aActiveGroupMap[nGroup];
417 _rName = aGroupPos->second.GetGroupName();
418 _rGroup = aGroupPos->second.GetControlModels();
421 //------------------------------------------------------------------
422 void OGroupManager::getGroupByName(const OUString& _rName, Sequence< Reference<XControlModel> >& _rGroup)
424 OGroupArr::iterator aFind = m_aGroupArr.find(_rName);
425 if ( aFind != m_aGroupArr.end() )
426 _rGroup = aFind->second.GetControlModels();
429 //------------------------------------------------------------------
430 void OGroupManager::InsertElement( const Reference<XPropertySet>& xSet )
432 // Nur ControlModels
433 Reference<XControlModel> xControl(xSet, UNO_QUERY);
434 if (!xControl.is() )
435 return;
437 // Component in CompGroup aufnehmen
438 m_pCompGroup->InsertComponent( xSet );
440 // Component in Gruppe aufnehmen
441 OUString sGroupName( GetGroupName( xSet ) );
443 OGroupArr::iterator aFind = m_aGroupArr.find(sGroupName);
445 if ( aFind == m_aGroupArr.end() )
447 aFind = m_aGroupArr.insert(OGroupArr::value_type(sGroupName,OGroup(sGroupName))).first;
450 aFind->second.InsertComponent( xSet );
452 // if we have at least 2 elements in the group, then this is an "active group"
453 bool bActivateGroup = aFind->second.Count() == 2;
455 // Additionally, if the component is a radio button, then it's group becomes active,
456 // too. With this, we ensure that in a container with n radio buttons which all are
457 // in different groups the selection still works reliably (means that all radios can be
458 // clicked independently)
459 if ( aFind->second.Count() == 1 )
461 if ( isRadioButton( xSet ) )
462 bActivateGroup = true;
465 if ( bActivateGroup )
467 OActiveGroups::iterator aAlreadyExistent = ::std::find(
468 m_aActiveGroupMap.begin(),
469 m_aActiveGroupMap.end(),
470 aFind
472 if ( aAlreadyExistent == m_aActiveGroupMap.end() )
473 m_aActiveGroupMap.push_back( aFind );
477 // Bei Component als PropertyChangeListener anmelden
478 xSet->addPropertyChangeListener( PROPERTY_NAME, this );
479 if (hasProperty(PROPERTY_GROUP_NAME, xSet))
480 xSet->addPropertyChangeListener( PROPERTY_GROUP_NAME, this );
482 // Tabindex muss nicht jeder unterstuetzen
483 if (hasProperty(PROPERTY_TABINDEX, xSet))
484 xSet->addPropertyChangeListener( PROPERTY_TABINDEX, this );
488 //------------------------------------------------------------------
489 void OGroupManager::RemoveElement( const Reference<XPropertySet>& xSet )
491 // Nur ControlModels
492 Reference<XControlModel> xControl(xSet, UNO_QUERY);
493 if (!xControl.is() )
494 return;
496 // Component aus Gruppe entfernen
497 OUString sGroupName( GetGroupName( xSet ) );
499 removeFromGroupMap(sGroupName,xSet);
502 OUString OGroupManager::GetGroupName( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet> xComponent )
504 if (!xComponent.is())
505 return OUString();
506 OUString sGroupName;
507 if (hasProperty( PROPERTY_GROUP_NAME, xComponent )) {
508 xComponent->getPropertyValue( PROPERTY_GROUP_NAME ) >>= sGroupName;
509 if (sGroupName.isEmpty())
510 xComponent->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
512 else
513 xComponent->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
514 return sGroupName;
517 //.........................................................................
518 } // namespace frm
519 //.........................................................................
521 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */