1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: GroupManager.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_forms.hxx"
33 #include "GroupManager.hxx"
34 #include <com/sun/star/beans/XFastPropertySet.hpp>
35 #include <com/sun/star/form/FormComponentType.hpp>
36 #include <comphelper/property.hxx>
37 #include <comphelper/uno3.hxx>
38 #include <tools/solar.h>
39 #include <tools/debug.hxx>
41 #include "property.hrc"
45 //.........................................................................
48 //.........................................................................
50 using namespace ::com::sun::star::uno
;
51 using namespace ::com::sun::star::sdbc
;
52 using namespace ::com::sun::star::beans
;
53 using namespace ::com::sun::star::container
;
54 using namespace ::com::sun::star::form
;
55 using namespace ::com::sun::star::awt
;
56 using namespace ::com::sun::star::lang
;
57 using namespace ::com::sun::star::form
;
61 bool isRadioButton( const Reference
< XPropertySet
>& _rxComponent
)
64 if ( hasProperty( PROPERTY_CLASSID
, _rxComponent
) )
66 sal_Int16 nClassId
= FormComponentType::CONTROL
;
67 _rxComponent
->getPropertyValue( PROPERTY_CLASSID
) >>= nClassId
;
68 if ( nClassId
== FormComponentType::RADIOBUTTON
)
75 //========================================================================
76 // class OGroupCompAcc
77 //========================================================================
78 //------------------------------------------------------------------
79 OGroupCompAcc::OGroupCompAcc(const Reference
<XPropertySet
>& rxElement
, const OGroupComp
& _rGroupComp
)
80 :m_xComponent( rxElement
)
81 ,m_aGroupComp( _rGroupComp
)
85 //------------------------------------------------------------------
86 sal_Bool
OGroupCompAcc::operator==( const OGroupCompAcc
& rCompAcc
) const
88 return (m_xComponent
== rCompAcc
.GetComponent());
91 //------------------------------------------------------------------
92 class OGroupCompAccLess
: public ::std::binary_function
<OGroupCompAcc
, OGroupCompAcc
, sal_Bool
>
95 sal_Bool
operator() (const OGroupCompAcc
& lhs
, const OGroupCompAcc
& rhs
) const
98 reinterpret_cast<sal_Int64
>(lhs
.m_xComponent
.get())
99 < reinterpret_cast<sal_Int64
>(rhs
.m_xComponent
.get());
103 //========================================================================
105 //========================================================================
107 //------------------------------------------------------------------
108 OGroupComp::OGroupComp()
114 //------------------------------------------------------------------
115 OGroupComp::OGroupComp(const OGroupComp
& _rSource
)
116 :m_aName( _rSource
.m_aName
)
117 ,m_xComponent( _rSource
.m_xComponent
)
118 ,m_xControlModel(_rSource
.m_xControlModel
)
119 ,m_nPos( _rSource
.m_nPos
)
120 ,m_nTabIndex( _rSource
.m_nTabIndex
)
124 //------------------------------------------------------------------
125 OGroupComp::OGroupComp(const Reference
<XPropertySet
>& rxSet
, sal_Int32 nInsertPos
)
126 :m_xComponent( rxSet
)
127 ,m_xControlModel(rxSet
,UNO_QUERY
)
128 ,m_nPos( nInsertPos
)
130 ,m_aName( OGroupManager::GetGroupName( rxSet
) )
132 if (m_xComponent
.is())
134 if (hasProperty( PROPERTY_TABINDEX
, m_xComponent
) )
135 // Indices kleiner 0 werden wie 0 behandelt
136 m_nTabIndex
= Max(getINT16(m_xComponent
->getPropertyValue( PROPERTY_TABINDEX
)) , sal_Int16(0));
140 //------------------------------------------------------------------
141 sal_Bool
OGroupComp::operator==( const OGroupComp
& rComp
) const
143 return m_nTabIndex
== rComp
.GetTabIndex() && m_nPos
== rComp
.GetPos();
146 //------------------------------------------------------------------
147 class OGroupCompLess
: public ::std::binary_function
<OGroupComp
, OGroupComp
, sal_Bool
>
150 sal_Bool
operator() (const OGroupComp
& lhs
, const OGroupComp
& rhs
) const
153 // TabIndex von 0 wird hinten einsortiert
154 if (lhs
.m_nTabIndex
== rhs
.GetTabIndex())
155 bResult
= lhs
.m_nPos
< rhs
.GetPos();
156 else if (lhs
.m_nTabIndex
&& rhs
.GetTabIndex())
157 bResult
= lhs
.m_nTabIndex
< rhs
.GetTabIndex();
159 bResult
= lhs
.m_nTabIndex
!= 0;
164 //========================================================================
166 //========================================================================
169 //------------------------------------------------------------------
170 OGroup::OGroup( const ::rtl::OUString
& rGroupName
)
171 :m_aGroupName( rGroupName
)
174 DBG_CTOR(OGroup
,NULL
);
178 //------------------------------------------------------------------
179 OGroup::OGroup( const OGroup
& _rSource
)
180 :m_aCompArray(_rSource
.m_aCompArray
)
181 ,m_aCompAccArray(_rSource
.m_aCompAccArray
)
182 ,m_aGroupName(_rSource
.m_aGroupName
)
183 ,m_nInsertPos(_rSource
.m_nInsertPos
)
185 DBG_CTOR(OGroup
,NULL
);
189 //------------------------------------------------------------------
192 DBG_DTOR(OGroup
,NULL
);
195 //------------------------------------------------------------------
196 void OGroup::InsertComponent( const Reference
<XPropertySet
>& xSet
)
198 OGroupComp
aNewGroupComp( xSet
, m_nInsertPos
);
199 sal_Int32 nPosInserted
= insert_sorted(m_aCompArray
, aNewGroupComp
, OGroupCompLess());
201 OGroupCompAcc
aNewGroupCompAcc( xSet
, m_aCompArray
[nPosInserted
] );
202 insert_sorted(m_aCompAccArray
, aNewGroupCompAcc
, OGroupCompAccLess());
206 //------------------------------------------------------------------
207 void OGroup::RemoveComponent( const Reference
<XPropertySet
>& rxElement
)
209 sal_Int32 nGroupCompAccPos
;
210 OGroupCompAcc
aSearchCompAcc( rxElement
, OGroupComp() );
211 if ( seek_entry(m_aCompAccArray
, aSearchCompAcc
, nGroupCompAccPos
, OGroupCompAccLess()) )
213 OGroupCompAcc
& aGroupCompAcc
= m_aCompAccArray
[nGroupCompAccPos
];
214 const OGroupComp
& aGroupComp
= aGroupCompAcc
.GetGroupComponent();
216 sal_Int32 nGroupCompPos
;
217 if ( seek_entry(m_aCompArray
, aGroupComp
, nGroupCompPos
, OGroupCompLess()) )
219 m_aCompAccArray
.erase( m_aCompAccArray
.begin() + nGroupCompAccPos
);
220 m_aCompArray
.erase( m_aCompArray
.begin() + nGroupCompPos
);
222 /*============================================================
223 Durch das Entfernen der GroupComp ist die Einfuegeposition
224 ungueltig geworden. Sie braucht hier aber nicht angepasst werden,
225 da sie fortlaufend vergeben wird und damit immer
226 aufsteigend eindeutig ist.
227 ============================================================*/
231 DBG_ERROR( "OGroup::RemoveComponent: Component nicht in Gruppe" );
236 DBG_ERROR( "OGroup::RemoveComponent: Component nicht in Gruppe" );
240 //------------------------------------------------------------------
241 sal_Bool
OGroup::operator==( const OGroup
& rGroup
) const
243 return m_aGroupName
.equals(rGroup
.GetGroupName());
246 //------------------------------------------------------------------
247 class OGroupLess
: public ::std::binary_function
<OGroup
, OGroup
, sal_Bool
>
250 sal_Bool
operator() (const OGroup
& lhs
, const OGroup
& rhs
) const
252 return lhs
.m_aGroupName
< rhs
.m_aGroupName
;
256 //------------------------------------------------------------------
257 Sequence
< Reference
<XControlModel
> > OGroup::GetControlModels() const
259 sal_Int32 nLen
= m_aCompArray
.size();
260 Sequence
<Reference
<XControlModel
> > aControlModelSeq( nLen
);
261 Reference
<XControlModel
>* pModels
= aControlModelSeq
.getArray();
263 ConstOGroupCompArrIterator aGroupComps
= m_aCompArray
.begin();
264 for (sal_Int32 i
= 0; i
< nLen
; ++i
, ++pModels
, ++aGroupComps
)
266 *pModels
= aGroupComps
->GetControlModel();
268 return aControlModelSeq
;
271 DBG_NAME(OGroupManager
);
272 //------------------------------------------------------------------
273 OGroupManager::OGroupManager(const Reference
< XContainer
>& _rxContainer
)
274 :m_pCompGroup( new OGroup( ::rtl::OUString::createFromAscii( "AllComponentGroup" ) ) )
275 ,m_xContainer(_rxContainer
)
277 DBG_CTOR(OGroupManager
,NULL
);
279 increment(m_refCount
);
281 _rxContainer
->addContainerListener(this);
283 decrement(m_refCount
);
286 //------------------------------------------------------------------
287 OGroupManager::~OGroupManager()
289 DBG_DTOR(OGroupManager
,NULL
);
290 // Alle Components und CompGroup loeschen
294 // XPropertyChangeListener
295 //------------------------------------------------------------------
296 void OGroupManager::disposing(const EventObject
& evt
) throw( RuntimeException
)
298 Reference
<XContainer
> xContainer(evt
.Source
, UNO_QUERY
);
299 if (xContainer
.get() == m_xContainer
.get())
301 DELETEZ(m_pCompGroup
);
303 ////////////////////////////////////////////////////////////////
306 m_xContainer
.clear();
309 // -----------------------------------------------------------------------------
310 void OGroupManager::removeFromGroupMap(const ::rtl::OUString
& _sGroupName
,const Reference
<XPropertySet
>& _xSet
)
312 // Component aus CompGroup entfernen
313 m_pCompGroup
->RemoveComponent( _xSet
);
315 OGroupArr::iterator aFind
= m_aGroupArr
.find(_sGroupName
);
317 if ( aFind
!= m_aGroupArr
.end() )
320 aFind
->second
.RemoveComponent( _xSet
);
322 // Wenn Anzahl der Gruppenelemente == 1 ist, Gruppe deaktivieren
323 sal_Int32 nCount
= aFind
->second
.Count();
324 if ( nCount
== 1 || nCount
== 0 )
326 OActiveGroups::iterator aActiveFind
= ::std::find(
327 m_aActiveGroupMap
.begin(),
328 m_aActiveGroupMap
.end(),
331 if ( aActiveFind
!= m_aActiveGroupMap
.end() )
333 // the group is active. Deactivate it if the remaining component
334 // is *no* radio button
335 if ( nCount
== 0 || !isRadioButton( aFind
->second
.GetObject( 0 ) ) )
336 m_aActiveGroupMap
.erase( aActiveFind
);
342 // Bei Component als PropertyChangeListener abmelden
343 _xSet
->removePropertyChangeListener( PROPERTY_NAME
, this );
344 if (hasProperty(PROPERTY_GROUP_NAME
, _xSet
))
345 _xSet
->removePropertyChangeListener( PROPERTY_GROUP_NAME
, this );
346 if (hasProperty(PROPERTY_TABINDEX
, _xSet
))
347 _xSet
->removePropertyChangeListener( PROPERTY_TABINDEX
, this );
349 //------------------------------------------------------------------
350 void SAL_CALL
OGroupManager::propertyChange(const PropertyChangeEvent
& evt
) throw ( ::com::sun::star::uno::RuntimeException
)
352 Reference
<XPropertySet
> xSet(evt
.Source
, UNO_QUERY
);
354 // Component aus Gruppe entfernen
355 ::rtl::OUString sGroupName
;
356 if (hasProperty( PROPERTY_GROUP_NAME
, xSet
))
357 xSet
->getPropertyValue( PROPERTY_GROUP_NAME
) >>= sGroupName
;
358 if (evt
.PropertyName
== PROPERTY_NAME
) {
359 if (sGroupName
.getLength() > 0)
360 return; // group hasn't changed; ignore this name change.
361 // no GroupName; use Name as GroupNme
362 evt
.OldValue
>>= sGroupName
;
364 else if (evt
.PropertyName
== PROPERTY_GROUP_NAME
) {
365 evt
.OldValue
>>= sGroupName
;
366 if (sGroupName
.getLength() == 0) {
367 // No prior GroupName; fallback to Nme
368 xSet
->getPropertyValue( PROPERTY_NAME
) >>= sGroupName
;
372 sGroupName
= GetGroupName( xSet
);
374 removeFromGroupMap(sGroupName
,xSet
);
376 // Component neu einordnen
377 InsertElement( xSet
);
380 // XContainerListener
381 //------------------------------------------------------------------
382 void SAL_CALL
OGroupManager::elementInserted(const ContainerEvent
& Event
) throw ( ::com::sun::star::uno::RuntimeException
)
384 Reference
< XPropertySet
> xProps
;
385 Event
.Element
>>= xProps
;
387 InsertElement( xProps
);
390 //------------------------------------------------------------------
391 void SAL_CALL
OGroupManager::elementRemoved(const ContainerEvent
& Event
) throw ( ::com::sun::star::uno::RuntimeException
)
393 Reference
<XPropertySet
> xProps
;
394 Event
.Element
>>= xProps
;
396 RemoveElement( xProps
);
399 //------------------------------------------------------------------
400 void SAL_CALL
OGroupManager::elementReplaced(const ContainerEvent
& Event
) throw ( ::com::sun::star::uno::RuntimeException
)
402 Reference
<XPropertySet
> xProps
;
403 Event
.ReplacedElement
>>= xProps
;
405 RemoveElement( xProps
);
408 Event
.Element
>>= xProps
;
410 InsertElement( xProps
);
414 //------------------------------------------------------------------
415 Sequence
<Reference
<XControlModel
> > OGroupManager::getControlModels()
417 return m_pCompGroup
->GetControlModels();
420 //------------------------------------------------------------------
421 sal_Int32
OGroupManager::getGroupCount()
423 return m_aActiveGroupMap
.size();
426 //------------------------------------------------------------------
427 void OGroupManager::getGroup(sal_Int32 nGroup
, Sequence
< Reference
<XControlModel
> >& _rGroup
, ::rtl::OUString
& _rName
)
429 OSL_ENSURE(nGroup
>= 0 && (size_t)nGroup
< m_aActiveGroupMap
.size(),"OGroupManager::getGroup: Invalid group index!");
430 OGroupArr::iterator aGroupPos
= m_aActiveGroupMap
[nGroup
];
431 _rName
= aGroupPos
->second
.GetGroupName();
432 _rGroup
= aGroupPos
->second
.GetControlModels();
435 //------------------------------------------------------------------
436 void OGroupManager::getGroupByName(const ::rtl::OUString
& _rName
, Sequence
< Reference
<XControlModel
> >& _rGroup
)
438 OGroupArr::iterator aFind
= m_aGroupArr
.find(_rName
);
439 if ( aFind
!= m_aGroupArr
.end() )
440 _rGroup
= aFind
->second
.GetControlModels();
443 //------------------------------------------------------------------
444 void OGroupManager::InsertElement( const Reference
<XPropertySet
>& xSet
)
447 Reference
<XControlModel
> xControl(xSet
, UNO_QUERY
);
451 // Component in CompGroup aufnehmen
452 m_pCompGroup
->InsertComponent( xSet
);
454 // Component in Gruppe aufnehmen
455 ::rtl::OUString
sGroupName( GetGroupName( xSet
) );
457 OGroupArr::iterator aFind
= m_aGroupArr
.find(sGroupName
);
459 if ( aFind
== m_aGroupArr
.end() )
461 aFind
= m_aGroupArr
.insert(OGroupArr::value_type(sGroupName
,OGroup(sGroupName
))).first
;
464 aFind
->second
.InsertComponent( xSet
);
466 // if we have at least 2 elements in the group, then this is an "active group"
467 bool bActivateGroup
= aFind
->second
.Count() == 2;
469 // Additionally, if the component is a radio button, then it's group becomes active,
470 // too. With this, we ensure that in a container with n radio buttons which all are
471 // in different groups the selection still works reliably (means that all radios can be
472 // clicked independently)
473 if ( aFind
->second
.Count() == 1 )
475 if ( isRadioButton( xSet
) )
476 bActivateGroup
= true;
479 if ( bActivateGroup
)
481 OActiveGroups::iterator aAlreadyExistent
= ::std::find(
482 m_aActiveGroupMap
.begin(),
483 m_aActiveGroupMap
.end(),
486 if ( aAlreadyExistent
== m_aActiveGroupMap
.end() )
487 m_aActiveGroupMap
.push_back( aFind
);
491 // Bei Component als PropertyChangeListener anmelden
492 xSet
->addPropertyChangeListener( PROPERTY_NAME
, this );
493 if (hasProperty(PROPERTY_GROUP_NAME
, xSet
))
494 xSet
->addPropertyChangeListener( PROPERTY_GROUP_NAME
, this );
496 // Tabindex muss nicht jeder unterstuetzen
497 if (hasProperty(PROPERTY_TABINDEX
, xSet
))
498 xSet
->addPropertyChangeListener( PROPERTY_TABINDEX
, this );
502 //------------------------------------------------------------------
503 void OGroupManager::RemoveElement( const Reference
<XPropertySet
>& xSet
)
506 Reference
<XControlModel
> xControl(xSet
, UNO_QUERY
);
510 // Component aus Gruppe entfernen
511 ::rtl::OUString
sGroupName( GetGroupName( xSet
) );
513 removeFromGroupMap(sGroupName
,xSet
);
516 ::rtl::OUString
OGroupManager::GetGroupName( ::com::sun::star::uno::Reference
< ::com::sun::star::beans::XPropertySet
> xComponent
)
518 if (!xComponent
.is())
519 return ::rtl::OUString();
520 ::rtl::OUString sGroupName
;
521 if (hasProperty( PROPERTY_GROUP_NAME
, xComponent
)) {
522 xComponent
->getPropertyValue( PROPERTY_GROUP_NAME
) >>= sGroupName
;
523 if (sGroupName
.getLength() == 0)
524 xComponent
->getPropertyValue( PROPERTY_NAME
) >>= sGroupName
;
527 xComponent
->getPropertyValue( PROPERTY_NAME
) >>= sGroupName
;
531 //.........................................................................
533 //.........................................................................