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 <comphelper/uno3.hxx>
25 #include <tools/solar.h>
26 #include <tools/debug.hxx>
28 #include "property.hrc"
32 //.........................................................................
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
;
47 bool isRadioButton( const Reference
< XPropertySet
>& _rxComponent
)
50 if ( hasProperty( PROPERTY_CLASSID
, _rxComponent
) )
52 sal_Int16 nClassId
= FormComponentType::CONTROL
;
53 _rxComponent
->getPropertyValue( PROPERTY_CLASSID
) >>= nClassId
;
54 if ( nClassId
== FormComponentType::RADIOBUTTON
)
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
>
81 sal_Bool
operator() (const OGroupCompAcc
& lhs
, const OGroupCompAcc
& rhs
) const
84 reinterpret_cast<sal_Int64
>(lhs
.m_xComponent
.get())
85 < reinterpret_cast<sal_Int64
>(rhs
.m_xComponent
.get());
89 //========================================================================
91 //========================================================================
93 //------------------------------------------------------------------
94 OGroupComp::OGroupComp()
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
)
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
>
136 sal_Bool
operator() (const OGroupComp
& lhs
, const OGroupComp
& rhs
) const
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();
145 bResult
= lhs
.m_nTabIndex
!= 0;
150 //========================================================================
152 //========================================================================
155 //------------------------------------------------------------------
156 OGroup::OGroup( const OUString
& rGroupName
)
157 :m_aGroupName( rGroupName
)
160 DBG_CTOR(OGroup
,NULL
);
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
);
175 //------------------------------------------------------------------
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());
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 ============================================================*/
217 OSL_FAIL( "OGroup::RemoveComponent: Component nicht in Gruppe" );
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
>
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
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 ////////////////////////////////////////////////////////////////
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() )
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(),
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
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
;
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
;
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
;
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
;
391 RemoveElement( xProps
);
394 Event
.Element
>>= xProps
;
396 InsertElement( xProps
);
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
)
433 Reference
<XControlModel
> xControl(xSet
, UNO_QUERY
);
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(),
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
)
492 Reference
<XControlModel
> xControl(xSet
, UNO_QUERY
);
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())
507 if (hasProperty( PROPERTY_GROUP_NAME
, xComponent
)) {
508 xComponent
->getPropertyValue( PROPERTY_GROUP_NAME
) >>= sGroupName
;
509 if (sGroupName
.isEmpty())
510 xComponent
->getPropertyValue( PROPERTY_NAME
) >>= sGroupName
;
513 xComponent
->getPropertyValue( PROPERTY_NAME
) >>= sGroupName
;
517 //.........................................................................
519 //.........................................................................
521 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */