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