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