xref: /AOO41X/main/forms/source/component/GroupManager.cxx (revision 24acc54625a85f778a4f966495e8f4cd9d7b247c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_forms.hxx"
26 #include "GroupManager.hxx"
27 #include <com/sun/star/beans/XFastPropertySet.hpp>
28 #include <com/sun/star/form/FormComponentType.hpp>
29 #include <comphelper/property.hxx>
30 #include <comphelper/uno3.hxx>
31 #include <tools/solar.h>
32 #include <tools/debug.hxx>
33 
34 #include "property.hrc"
35 
36 #include <algorithm>
37 
38 //.........................................................................
39 namespace frm
40 {
41 //.........................................................................
42 
43 using namespace ::com::sun::star::uno;
44 using namespace ::com::sun::star::sdbc;
45 using namespace ::com::sun::star::beans;
46 using namespace ::com::sun::star::container;
47 using namespace ::com::sun::star::form;
48 using namespace ::com::sun::star::awt;
49 using namespace ::com::sun::star::lang;
50 using namespace ::com::sun::star::form;
51 
52 namespace
53 {
isRadioButton(const Reference<XPropertySet> & _rxComponent)54     bool isRadioButton( const Reference< XPropertySet >& _rxComponent )
55     {
56         bool bIs = false;
57         if ( hasProperty( PROPERTY_CLASSID, _rxComponent ) )
58         {
59             sal_Int16 nClassId = FormComponentType::CONTROL;
60             _rxComponent->getPropertyValue( PROPERTY_CLASSID ) >>= nClassId;
61             if ( nClassId == FormComponentType::RADIOBUTTON )
62                 bIs = true;
63         }
64         return bIs;
65     }
66 }
67 
68 //========================================================================
69 // class OGroupCompAcc
70 //========================================================================
71 //------------------------------------------------------------------
OGroupCompAcc(const Reference<XPropertySet> & rxElement,const OGroupComp & _rGroupComp)72 OGroupCompAcc::OGroupCompAcc(const Reference<XPropertySet>& rxElement, const OGroupComp& _rGroupComp )
73                :m_xComponent( rxElement )
74                ,m_aGroupComp( _rGroupComp )
75 {
76 }
77 
78 //------------------------------------------------------------------
operator ==(const OGroupCompAcc & rCompAcc) const79 sal_Bool OGroupCompAcc::operator==( const OGroupCompAcc& rCompAcc ) const
80 {
81     return (m_xComponent == rCompAcc.GetComponent());
82 }
83 
84 //------------------------------------------------------------------
85 class OGroupCompAccLess : public ::std::binary_function<OGroupCompAcc, OGroupCompAcc, sal_Bool>
86 {
87 public:
operator ()(const OGroupCompAcc & lhs,const OGroupCompAcc & rhs) const88     sal_Bool operator() (const OGroupCompAcc& lhs, const OGroupCompAcc& rhs) const
89     {
90         return
91             reinterpret_cast<sal_Int64>(lhs.m_xComponent.get())
92         <   reinterpret_cast<sal_Int64>(rhs.m_xComponent.get());
93     }
94 };
95 
96 //========================================================================
97 // class OGroupComp
98 //========================================================================
99 
100 //------------------------------------------------------------------
OGroupComp()101 OGroupComp::OGroupComp()
102     :m_nPos( -1 )
103     ,m_nTabIndex( 0 )
104 {
105 }
106 
107 //------------------------------------------------------------------
OGroupComp(const OGroupComp & _rSource)108 OGroupComp::OGroupComp(const OGroupComp& _rSource)
109     :m_aName( _rSource.m_aName )
110     ,m_xComponent( _rSource.m_xComponent )
111     ,m_xControlModel(_rSource.m_xControlModel)
112     ,m_nPos( _rSource.m_nPos )
113     ,m_nTabIndex( _rSource.m_nTabIndex )
114 {
115 }
116 
117 //------------------------------------------------------------------
OGroupComp(const Reference<XPropertySet> & rxSet,sal_Int32 nInsertPos)118 OGroupComp::OGroupComp(const Reference<XPropertySet>& rxSet, sal_Int32 nInsertPos )
119     :m_xComponent( rxSet )
120     ,m_xControlModel(rxSet,UNO_QUERY)
121     ,m_nPos( nInsertPos )
122     ,m_nTabIndex(0)
123 {
124     if (m_xComponent.is())
125     {
126         if (hasProperty( PROPERTY_TABINDEX, m_xComponent ) )
127             // Indices kleiner 0 werden wie 0 behandelt
128             m_nTabIndex = Max(getINT16(m_xComponent->getPropertyValue( PROPERTY_TABINDEX )) , sal_Int16(0));
129 
130         m_xComponent->getPropertyValue( PROPERTY_NAME ) >>= m_aName;
131     }
132 }
133 
134 //------------------------------------------------------------------
operator ==(const OGroupComp & rComp) const135 sal_Bool OGroupComp::operator==( const OGroupComp& rComp ) const
136 {
137     return m_nTabIndex == rComp.GetTabIndex() && m_nPos == rComp.GetPos();
138 }
139 
140 //------------------------------------------------------------------
141 class OGroupCompLess : public ::std::binary_function<OGroupComp, OGroupComp, sal_Bool>
142 {
143 public:
operator ()(const OGroupComp & lhs,const OGroupComp & rhs) const144     sal_Bool operator() (const OGroupComp& lhs, const OGroupComp& rhs) const
145     {
146         sal_Bool bResult;
147         // TabIndex von 0 wird hinten einsortiert
148         if (lhs.m_nTabIndex == rhs.GetTabIndex())
149             bResult = lhs.m_nPos < rhs.GetPos();
150         else if (lhs.m_nTabIndex && rhs.GetTabIndex())
151             bResult = lhs.m_nTabIndex < rhs.GetTabIndex();
152         else
153             bResult = lhs.m_nTabIndex != 0;
154         return bResult;
155     }
156 };
157 
158 //========================================================================
159 // class OGroup
160 //========================================================================
161 
DBG_NAME(OGroup)162 DBG_NAME(OGroup)
163 //------------------------------------------------------------------
164 OGroup::OGroup( const ::rtl::OUString& rGroupName )
165         :m_aGroupName( rGroupName )
166         ,m_nInsertPos(0)
167 {
168     DBG_CTOR(OGroup,NULL);
169 }
170 
171 #ifdef DBG_UTIL
172 //------------------------------------------------------------------
OGroup(const OGroup & _rSource)173 OGroup::OGroup( const OGroup& _rSource )
174 :m_aCompArray(_rSource.m_aCompArray)
175     ,m_aCompAccArray(_rSource.m_aCompAccArray)
176     ,m_aGroupName(_rSource.m_aGroupName)
177     ,m_nInsertPos(_rSource.m_nInsertPos)
178 {
179     DBG_CTOR(OGroup,NULL);
180 }
181 #endif
182 
183 //------------------------------------------------------------------
~OGroup()184 OGroup::~OGroup()
185 {
186     DBG_DTOR(OGroup,NULL);
187 }
188 
189 //------------------------------------------------------------------
InsertComponent(const Reference<XPropertySet> & xSet)190 void OGroup::InsertComponent( const Reference<XPropertySet>& xSet )
191 {
192     OGroupComp aNewGroupComp( xSet, m_nInsertPos );
193     sal_Int32 nPosInserted = insert_sorted(m_aCompArray, aNewGroupComp, OGroupCompLess());
194 
195     OGroupCompAcc aNewGroupCompAcc( xSet, m_aCompArray[nPosInserted] );
196     insert_sorted(m_aCompAccArray, aNewGroupCompAcc, OGroupCompAccLess());
197     m_nInsertPos++;
198 }
199 
200 //------------------------------------------------------------------
RemoveComponent(const Reference<XPropertySet> & rxElement)201 void OGroup::RemoveComponent( const Reference<XPropertySet>& rxElement )
202 {
203     sal_Int32 nGroupCompAccPos;
204     OGroupCompAcc aSearchCompAcc( rxElement, OGroupComp() );
205     if ( seek_entry(m_aCompAccArray, aSearchCompAcc, nGroupCompAccPos, OGroupCompAccLess()) )
206     {
207         OGroupCompAcc& aGroupCompAcc = m_aCompAccArray[nGroupCompAccPos];
208         const OGroupComp& aGroupComp = aGroupCompAcc.GetGroupComponent();
209 
210         sal_Int32 nGroupCompPos;
211         if ( seek_entry(m_aCompArray, aGroupComp, nGroupCompPos, OGroupCompLess()) )
212         {
213             m_aCompAccArray.erase( m_aCompAccArray.begin() + nGroupCompAccPos );
214             m_aCompArray.erase( m_aCompArray.begin() + nGroupCompPos );
215 
216             /*============================================================
217             Durch das Entfernen der GroupComp ist die Einfuegeposition
218             ungueltig geworden. Sie braucht hier aber nicht angepasst werden,
219             da sie fortlaufend vergeben wird und damit immer
220             aufsteigend eindeutig ist.
221             ============================================================*/
222         }
223         else
224         {
225             DBG_ERROR( "OGroup::RemoveComponent: Component nicht in Gruppe" );
226         }
227     }
228     else
229     {
230         DBG_ERROR( "OGroup::RemoveComponent: Component nicht in Gruppe" );
231     }
232 }
233 
234 //------------------------------------------------------------------
operator ==(const OGroup & rGroup) const235 sal_Bool OGroup::operator==( const OGroup& rGroup ) const
236 {
237     return m_aGroupName.equals(rGroup.GetGroupName());
238 }
239 
240 //------------------------------------------------------------------
241 class OGroupLess : public ::std::binary_function<OGroup, OGroup, sal_Bool>
242 {
243 public:
operator ()(const OGroup & lhs,const OGroup & rhs) const244     sal_Bool operator() (const OGroup& lhs, const OGroup& rhs) const
245     {
246         return lhs.m_aGroupName < rhs.m_aGroupName;
247     }
248 };
249 
250 //------------------------------------------------------------------
GetControlModels() const251 Sequence< Reference<XControlModel>  > OGroup::GetControlModels() const
252 {
253     sal_Int32 nLen = m_aCompArray.size();
254     Sequence<Reference<XControlModel> > aControlModelSeq( nLen );
255     Reference<XControlModel>* pModels = aControlModelSeq.getArray();
256 
257     ConstOGroupCompArrIterator aGroupComps = m_aCompArray.begin();
258     for (sal_Int32 i = 0; i < nLen; ++i, ++pModels, ++aGroupComps)
259     {
260         *pModels = aGroupComps->GetControlModel();
261     }
262     return aControlModelSeq;
263 }
264 
265 DBG_NAME(OGroupManager);
266 //------------------------------------------------------------------
OGroupManager(const Reference<XContainer> & _rxContainer)267 OGroupManager::OGroupManager(const Reference< XContainer >& _rxContainer)
268     :m_pCompGroup( new OGroup( ::rtl::OUString::createFromAscii( "AllComponentGroup" ) ) )
269     ,m_xContainer(_rxContainer)
270 {
271     DBG_CTOR(OGroupManager,NULL);
272 
273     increment(m_refCount);
274     {
275         _rxContainer->addContainerListener(this);
276     }
277     decrement(m_refCount);
278 }
279 
280 //------------------------------------------------------------------
~OGroupManager()281 OGroupManager::~OGroupManager()
282 {
283     DBG_DTOR(OGroupManager,NULL);
284     // Alle Components und CompGroup loeschen
285     delete m_pCompGroup;
286 }
287 
288 // XPropertyChangeListener
289 //------------------------------------------------------------------
disposing(const EventObject & evt)290 void OGroupManager::disposing(const EventObject& evt) throw( RuntimeException )
291 {
292     Reference<XContainer>  xContainer(evt.Source, UNO_QUERY);
293     if (xContainer.get() == m_xContainer.get())
294     {
295         DELETEZ(m_pCompGroup);
296 
297         ////////////////////////////////////////////////////////////////
298         // Gruppen loeschen
299         m_aGroupArr.clear();
300         m_xContainer.clear();
301     }
302 }
303 // -----------------------------------------------------------------------------
removeFromGroupMap(const::rtl::OUString & _sGroupName,const Reference<XPropertySet> & _xSet)304 void OGroupManager::removeFromGroupMap(const ::rtl::OUString& _sGroupName,const Reference<XPropertySet>& _xSet)
305 {
306     // Component aus CompGroup entfernen
307     m_pCompGroup->RemoveComponent( _xSet );
308 
309     OGroupArr::iterator aFind = m_aGroupArr.find(_sGroupName);
310 
311     if ( aFind != m_aGroupArr.end() )
312     {
313         // Gruppe vorhanden
314         aFind->second.RemoveComponent( _xSet );
315 
316         // Wenn Anzahl der Gruppenelemente == 1 ist, Gruppe deaktivieren
317         if ( aFind->second.Count() == 1 )
318         {
319             OActiveGroups::iterator aActiveFind = ::std::find(
320                 m_aActiveGroupMap.begin(),
321                 m_aActiveGroupMap.end(),
322                 aFind
323             );
324             if ( aActiveFind != m_aActiveGroupMap.end() )
325             {
326                 // the group is active. Deactivate it if the remaining component
327                 // is *no* radio button
328                 if ( !isRadioButton( aFind->second.GetObject( 0 ) ) )
329                     m_aActiveGroupMap.erase( aActiveFind );
330             }
331         }
332     }
333 
334 
335     // Bei Component als PropertyChangeListener abmelden
336     _xSet->removePropertyChangeListener( PROPERTY_NAME, this );
337     if (hasProperty(PROPERTY_TABINDEX, _xSet))
338         _xSet->removePropertyChangeListener( PROPERTY_TABINDEX, this );
339 }
340 //------------------------------------------------------------------
propertyChange(const PropertyChangeEvent & evt)341 void SAL_CALL OGroupManager::propertyChange(const PropertyChangeEvent& evt) throw ( ::com::sun::star::uno::RuntimeException)
342 {
343     Reference<XPropertySet>  xSet(evt.Source, UNO_QUERY);
344 
345     // Component aus Gruppe entfernen
346     ::rtl::OUString     sGroupName;
347     if (evt.PropertyName == PROPERTY_NAME)
348         evt.OldValue >>= sGroupName;
349     else
350         xSet->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
351 
352     removeFromGroupMap(sGroupName,xSet);
353 
354     // Component neu einordnen
355     InsertElement( xSet );
356 }
357 
358 // XContainerListener
359 //------------------------------------------------------------------
elementInserted(const ContainerEvent & Event)360 void SAL_CALL OGroupManager::elementInserted(const ContainerEvent& Event) throw ( ::com::sun::star::uno::RuntimeException)
361 {
362     Reference< XPropertySet > xProps;
363     Event.Element >>= xProps;
364     if ( xProps.is() )
365         InsertElement( xProps );
366 }
367 
368 //------------------------------------------------------------------
elementRemoved(const ContainerEvent & Event)369 void SAL_CALL OGroupManager::elementRemoved(const ContainerEvent& Event) throw ( ::com::sun::star::uno::RuntimeException)
370 {
371     Reference<XPropertySet> xProps;
372     Event.Element >>= xProps;
373     if ( xProps.is() )
374         RemoveElement( xProps );
375 }
376 
377 //------------------------------------------------------------------
elementReplaced(const ContainerEvent & Event)378 void SAL_CALL OGroupManager::elementReplaced(const ContainerEvent& Event) throw ( ::com::sun::star::uno::RuntimeException)
379 {
380     Reference<XPropertySet> xProps;
381     Event.ReplacedElement >>= xProps;
382     if ( xProps.is() )
383         RemoveElement( xProps );
384 
385     xProps.clear();
386     Event.Element >>= xProps;
387     if ( xProps.is() )
388         InsertElement( xProps );
389 }
390 
391 // Other functions
392 //------------------------------------------------------------------
getControlModels()393 Sequence<Reference<XControlModel> > OGroupManager::getControlModels()
394 {
395     return m_pCompGroup->GetControlModels();
396 }
397 
398 //------------------------------------------------------------------
getGroupCount()399 sal_Int32 OGroupManager::getGroupCount()
400 {
401     return m_aActiveGroupMap.size();
402 }
403 
404 //------------------------------------------------------------------
getGroup(sal_Int32 nGroup,Sequence<Reference<XControlModel>> & _rGroup,::rtl::OUString & _rName)405 void OGroupManager::getGroup(sal_Int32 nGroup, Sequence< Reference<XControlModel> >& _rGroup, ::rtl::OUString& _rName)
406 {
407     OSL_ENSURE(nGroup >= 0 && (size_t)nGroup < m_aActiveGroupMap.size(),"OGroupManager::getGroup: Invalid group index!");
408     OGroupArr::iterator aGroupPos   = m_aActiveGroupMap[nGroup];
409     _rName                          = aGroupPos->second.GetGroupName();
410     _rGroup                         = aGroupPos->second.GetControlModels();
411 }
412 
413 //------------------------------------------------------------------
getGroupByName(const::rtl::OUString & _rName,Sequence<Reference<XControlModel>> & _rGroup)414 void OGroupManager::getGroupByName(const ::rtl::OUString& _rName, Sequence< Reference<XControlModel>  >& _rGroup)
415 {
416     OGroupArr::iterator aFind = m_aGroupArr.find(_rName);
417     if ( aFind != m_aGroupArr.end() )
418         _rGroup = aFind->second.GetControlModels();
419 }
420 
421 //------------------------------------------------------------------
InsertElement(const Reference<XPropertySet> & xSet)422 void OGroupManager::InsertElement( const Reference<XPropertySet>& xSet )
423 {
424     // Nur ControlModels
425     Reference<XControlModel>  xControl(xSet, UNO_QUERY);
426     if (!xControl.is() )
427         return;
428 
429     // Component in CompGroup aufnehmen
430     m_pCompGroup->InsertComponent( xSet );
431 
432     // Component in Gruppe aufnehmen
433     ::rtl::OUString sGroupName;
434     xSet->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
435 
436     OGroupArr::iterator aFind = m_aGroupArr.find(sGroupName);
437 
438     if ( aFind == m_aGroupArr.end() )
439     {
440         aFind = m_aGroupArr.insert(OGroupArr::value_type(sGroupName,OGroup(sGroupName))).first;
441     }
442 
443     aFind->second.InsertComponent( xSet );
444 
445     // if we have at least 2 elements in the group, then this is an "active group"
446     bool bActivateGroup = aFind->second.Count() == 2;
447 
448     // Additionally, if the component is a radio button, then it's group becomes active,
449     // too. With this, we ensure that in a container with n radio buttons which all are
450     // in different groups the selection still works reliably (means that all radios can be
451     // clicked independently)
452     if ( aFind->second.Count() == 1 )
453     {
454         if ( isRadioButton( xSet ) )
455             bActivateGroup = true;
456     }
457 
458     if ( bActivateGroup )
459     {
460         OActiveGroups::iterator aAlreadyExistent = ::std::find(
461             m_aActiveGroupMap.begin(),
462             m_aActiveGroupMap.end(),
463             aFind
464         );
465         if ( aAlreadyExistent == m_aActiveGroupMap.end() )
466             m_aActiveGroupMap.push_back(  aFind );
467     }
468 
469 
470     // Bei Component als PropertyChangeListener anmelden
471     xSet->addPropertyChangeListener( PROPERTY_NAME, this );
472 
473     // Tabindex muss nicht jeder unterstuetzen
474     if (hasProperty(PROPERTY_TABINDEX, xSet))
475         xSet->addPropertyChangeListener( PROPERTY_TABINDEX, this );
476 
477 }
478 
479 //------------------------------------------------------------------
RemoveElement(const Reference<XPropertySet> & xSet)480 void OGroupManager::RemoveElement( const Reference<XPropertySet>& xSet )
481 {
482     // Nur ControlModels
483     Reference<XControlModel>  xControl(xSet, UNO_QUERY);
484     if (!xControl.is() )
485         return;
486 
487     // Component aus Gruppe entfernen
488     ::rtl::OUString     sGroupName;
489     xSet->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
490 
491     removeFromGroupMap(sGroupName,xSet);
492 }
493 
494 //.........................................................................
495 }   // namespace frm
496 //.........................................................................
497 
498