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 16 : bool isRadioButton( const Reference< XPropertySet >& _rxComponent )
49 : {
50 16 : bool bIs = false;
51 16 : if ( hasProperty( PROPERTY_CLASSID, _rxComponent ) )
52 : {
53 16 : sal_Int16 nClassId = FormComponentType::CONTROL;
54 16 : _rxComponent->getPropertyValue( PROPERTY_CLASSID ) >>= nClassId;
55 16 : if ( nClassId == FormComponentType::RADIOBUTTON )
56 0 : bIs = true;
57 : }
58 16 : return bIs;
59 : }
60 : }
61 :
62 : //========================================================================
63 : // class OGroupCompAcc
64 : //========================================================================
65 : //------------------------------------------------------------------
66 72 : OGroupCompAcc::OGroupCompAcc(const Reference<XPropertySet>& rxElement, const OGroupComp& _rGroupComp )
67 : :m_xComponent( rxElement )
68 72 : ,m_aGroupComp( _rGroupComp )
69 : {
70 72 : }
71 :
72 : //------------------------------------------------------------------
73 12 : sal_Bool OGroupCompAcc::operator==( const OGroupCompAcc& rCompAcc ) const
74 : {
75 12 : return (m_xComponent == rCompAcc.GetComponent());
76 : }
77 :
78 : //------------------------------------------------------------------
79 : class OGroupCompAccLess : public ::std::binary_function<OGroupCompAcc, OGroupCompAcc, sal_Bool>
80 : {
81 : public:
82 80 : sal_Bool operator() (const OGroupCompAcc& lhs, const OGroupCompAcc& rhs) const
83 : {
84 : return
85 80 : reinterpret_cast<sal_Int64>(lhs.m_xComponent.get())
86 80 : < reinterpret_cast<sal_Int64>(rhs.m_xComponent.get());
87 : }
88 : };
89 :
90 : //========================================================================
91 : // class OGroupComp
92 : //========================================================================
93 :
94 : //------------------------------------------------------------------
95 12 : OGroupComp::OGroupComp()
96 : :m_nPos( -1 )
97 12 : ,m_nTabIndex( 0 )
98 : {
99 12 : }
100 :
101 : //------------------------------------------------------------------
102 288 : 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 288 : ,m_nTabIndex( _rSource.m_nTabIndex )
108 : {
109 288 : }
110 :
111 : //------------------------------------------------------------------
112 60 : 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 60 : , m_nTabIndex(0)
118 : {
119 60 : if (m_xComponent.is())
120 : {
121 60 : if (hasProperty( PROPERTY_TABINDEX, m_xComponent ) )
122 : // Indices kleiner 0 werden wie 0 behandelt
123 56 : m_nTabIndex = Max(getINT16(m_xComponent->getPropertyValue( PROPERTY_TABINDEX )) , sal_Int16(0));
124 : }
125 60 : }
126 :
127 : //------------------------------------------------------------------
128 12 : sal_Bool OGroupComp::operator==( const OGroupComp& rComp ) const
129 : {
130 12 : 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 70 : sal_Bool operator() (const OGroupComp& lhs, const OGroupComp& rhs) const
138 : {
139 : sal_Bool bResult;
140 : // TabIndex von 0 wird hinten einsortiert
141 70 : if (lhs.m_nTabIndex == rhs.GetTabIndex())
142 70 : 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 70 : return bResult;
148 : }
149 : };
150 :
151 : //========================================================================
152 : // class OGroup
153 : //========================================================================
154 :
155 : DBG_NAME(OGroup)
156 : //------------------------------------------------------------------
157 26 : OGroup::OGroup( const ::rtl::OUString& rGroupName )
158 : :m_aGroupName( rGroupName )
159 26 : ,m_nInsertPos(0)
160 : {
161 : DBG_CTOR(OGroup,NULL);
162 26 : }
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 55 : OGroup::~OGroup()
178 : {
179 : DBG_DTOR(OGroup,NULL);
180 55 : }
181 :
182 : //------------------------------------------------------------------
183 60 : void OGroup::InsertComponent( const Reference<XPropertySet>& xSet )
184 : {
185 60 : OGroupComp aNewGroupComp( xSet, m_nInsertPos );
186 60 : sal_Int32 nPosInserted = insert_sorted(m_aCompArray, aNewGroupComp, OGroupCompLess());
187 :
188 60 : OGroupCompAcc aNewGroupCompAcc( xSet, m_aCompArray[nPosInserted] );
189 60 : insert_sorted(m_aCompAccArray, aNewGroupCompAcc, OGroupCompAccLess());
190 60 : m_nInsertPos++;
191 60 : }
192 :
193 : //------------------------------------------------------------------
194 12 : void OGroup::RemoveComponent( const Reference<XPropertySet>& rxElement )
195 : {
196 : sal_Int32 nGroupCompAccPos;
197 12 : OGroupCompAcc aSearchCompAcc( rxElement, OGroupComp() );
198 12 : if ( seek_entry(m_aCompAccArray, aSearchCompAcc, nGroupCompAccPos, OGroupCompAccLess()) )
199 : {
200 12 : OGroupCompAcc& aGroupCompAcc = m_aCompAccArray[nGroupCompAccPos];
201 12 : const OGroupComp& aGroupComp = aGroupCompAcc.GetGroupComponent();
202 :
203 : sal_Int32 nGroupCompPos;
204 12 : if ( seek_entry(m_aCompArray, aGroupComp, nGroupCompPos, OGroupCompLess()) )
205 : {
206 12 : m_aCompAccArray.erase( m_aCompAccArray.begin() + nGroupCompAccPos );
207 12 : 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 12 : }
225 12 : }
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 46 : Sequence< Reference<XControlModel> > OGroup::GetControlModels() const
245 : {
246 46 : sal_Int32 nLen = m_aCompArray.size();
247 46 : Sequence<Reference<XControlModel> > aControlModelSeq( nLen );
248 46 : Reference<XControlModel>* pModels = aControlModelSeq.getArray();
249 :
250 46 : ConstOGroupCompArrIterator aGroupComps = m_aCompArray.begin();
251 116 : for (sal_Int32 i = 0; i < nLen; ++i, ++pModels, ++aGroupComps)
252 : {
253 70 : *pModels = aGroupComps->GetControlModel();
254 : }
255 46 : return aControlModelSeq;
256 : }
257 :
258 : DBG_NAME(OGroupManager);
259 : //------------------------------------------------------------------
260 11 : OGroupManager::OGroupManager(const Reference< XContainer >& _rxContainer)
261 11 : :m_pCompGroup( new OGroup( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AllComponentGroup") ) ) )
262 22 : ,m_xContainer(_rxContainer)
263 : {
264 : DBG_CTOR(OGroupManager,NULL);
265 :
266 11 : increment(m_refCount);
267 : {
268 11 : _rxContainer->addContainerListener(this);
269 : }
270 11 : decrement(m_refCount);
271 11 : }
272 :
273 : //------------------------------------------------------------------
274 15 : OGroupManager::~OGroupManager()
275 : {
276 : DBG_DTOR(OGroupManager,NULL);
277 : // Alle Components und CompGroup loeschen
278 5 : delete m_pCompGroup;
279 10 : }
280 :
281 : // XPropertyChangeListener
282 : //------------------------------------------------------------------
283 53 : void OGroupManager::disposing(const EventObject& evt) throw( RuntimeException )
284 : {
285 53 : Reference<XContainer> xContainer(evt.Source, UNO_QUERY);
286 53 : if (xContainer.get() == m_xContainer.get())
287 : {
288 7 : DELETEZ(m_pCompGroup);
289 :
290 : ////////////////////////////////////////////////////////////////
291 : // Gruppen loeschen
292 7 : m_aGroupArr.clear();
293 7 : m_xContainer.clear();
294 53 : }
295 53 : }
296 : // -----------------------------------------------------------------------------
297 6 : void OGroupManager::removeFromGroupMap(const ::rtl::OUString& _sGroupName,const Reference<XPropertySet>& _xSet)
298 : {
299 : // Component aus CompGroup entfernen
300 6 : m_pCompGroup->RemoveComponent( _xSet );
301 :
302 6 : OGroupArr::iterator aFind = m_aGroupArr.find(_sGroupName);
303 :
304 6 : if ( aFind != m_aGroupArr.end() )
305 : {
306 : // Gruppe vorhanden
307 6 : aFind->second.RemoveComponent( _xSet );
308 :
309 : // Wenn Anzahl der Gruppenelemente == 1 ist, Gruppe deaktivieren
310 6 : sal_Int32 nCount = aFind->second.Count();
311 6 : if ( nCount == 1 || nCount == 0 )
312 : {
313 : OActiveGroups::iterator aActiveFind = ::std::find(
314 : m_aActiveGroupMap.begin(),
315 : m_aActiveGroupMap.end(),
316 : aFind
317 4 : );
318 4 : if ( aActiveFind != m_aActiveGroupMap.end() )
319 : {
320 : // the group is active. Deactivate it if the remaining component
321 : // is *no* radio button
322 1 : if ( nCount == 0 || !isRadioButton( aFind->second.GetObject( 0 ) ) )
323 1 : m_aActiveGroupMap.erase( aActiveFind );
324 : }
325 : }
326 : }
327 :
328 :
329 : // Bei Component als PropertyChangeListener abmelden
330 6 : _xSet->removePropertyChangeListener( PROPERTY_NAME, this );
331 6 : if (hasProperty(PROPERTY_GROUP_NAME, _xSet))
332 0 : _xSet->removePropertyChangeListener( PROPERTY_GROUP_NAME, this );
333 6 : if (hasProperty(PROPERTY_TABINDEX, _xSet))
334 6 : _xSet->removePropertyChangeListener( PROPERTY_TABINDEX, this );
335 6 : }
336 : //------------------------------------------------------------------
337 2 : void SAL_CALL OGroupManager::propertyChange(const PropertyChangeEvent& evt) throw ( ::com::sun::star::uno::RuntimeException)
338 : {
339 2 : Reference<XPropertySet> xSet(evt.Source, UNO_QUERY);
340 :
341 : // Component aus Gruppe entfernen
342 2 : ::rtl::OUString sGroupName;
343 2 : if (hasProperty( PROPERTY_GROUP_NAME, xSet ))
344 0 : xSet->getPropertyValue( PROPERTY_GROUP_NAME ) >>= sGroupName;
345 2 : if (evt.PropertyName == PROPERTY_NAME) {
346 2 : if (!sGroupName.isEmpty())
347 2 : return; // group hasn't changed; ignore this name change.
348 : // no GroupName; use Name as GroupNme
349 2 : 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 2 : removeFromGroupMap(sGroupName,xSet);
362 :
363 : // Component neu einordnen
364 2 : InsertElement( xSet );
365 : }
366 :
367 : // XContainerListener
368 : //------------------------------------------------------------------
369 28 : void SAL_CALL OGroupManager::elementInserted(const ContainerEvent& Event) throw ( ::com::sun::star::uno::RuntimeException)
370 : {
371 28 : Reference< XPropertySet > xProps;
372 28 : Event.Element >>= xProps;
373 28 : if ( xProps.is() )
374 28 : InsertElement( xProps );
375 28 : }
376 :
377 : //------------------------------------------------------------------
378 4 : void SAL_CALL OGroupManager::elementRemoved(const ContainerEvent& Event) throw ( ::com::sun::star::uno::RuntimeException)
379 : {
380 4 : Reference<XPropertySet> xProps;
381 4 : Event.Element >>= xProps;
382 4 : if ( xProps.is() )
383 4 : RemoveElement( xProps );
384 4 : }
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 43 : Sequence<Reference<XControlModel> > OGroupManager::getControlModels()
403 : {
404 43 : return m_pCompGroup->GetControlModels();
405 : }
406 :
407 : //------------------------------------------------------------------
408 28 : sal_Int32 OGroupManager::getGroupCount()
409 : {
410 28 : return m_aActiveGroupMap.size();
411 : }
412 :
413 : //------------------------------------------------------------------
414 3 : 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 3 : OGroupArr::iterator aGroupPos = m_aActiveGroupMap[nGroup];
418 3 : _rName = aGroupPos->second.GetGroupName();
419 3 : _rGroup = aGroupPos->second.GetControlModels();
420 3 : }
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 30 : void OGroupManager::InsertElement( const Reference<XPropertySet>& xSet )
432 : {
433 : // Nur ControlModels
434 30 : Reference<XControlModel> xControl(xSet, UNO_QUERY);
435 30 : if (!xControl.is() )
436 30 : return;
437 :
438 : // Component in CompGroup aufnehmen
439 30 : m_pCompGroup->InsertComponent( xSet );
440 :
441 : // Component in Gruppe aufnehmen
442 30 : ::rtl::OUString sGroupName( GetGroupName( xSet ) );
443 :
444 30 : OGroupArr::iterator aFind = m_aGroupArr.find(sGroupName);
445 :
446 30 : if ( aFind == m_aGroupArr.end() )
447 : {
448 15 : aFind = m_aGroupArr.insert(OGroupArr::value_type(sGroupName,OGroup(sGroupName))).first;
449 : }
450 :
451 30 : aFind->second.InsertComponent( xSet );
452 :
453 : // if we have at least 2 elements in the group, then this is an "active group"
454 30 : 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 30 : if ( aFind->second.Count() == 1 )
461 : {
462 15 : if ( isRadioButton( xSet ) )
463 0 : bActivateGroup = true;
464 : }
465 :
466 30 : if ( bActivateGroup )
467 : {
468 : OActiveGroups::iterator aAlreadyExistent = ::std::find(
469 : m_aActiveGroupMap.begin(),
470 : m_aActiveGroupMap.end(),
471 : aFind
472 5 : );
473 5 : if ( aAlreadyExistent == m_aActiveGroupMap.end() )
474 5 : m_aActiveGroupMap.push_back( aFind );
475 : }
476 :
477 :
478 : // Bei Component als PropertyChangeListener anmelden
479 30 : xSet->addPropertyChangeListener( PROPERTY_NAME, this );
480 30 : if (hasProperty(PROPERTY_GROUP_NAME, xSet))
481 8 : xSet->addPropertyChangeListener( PROPERTY_GROUP_NAME, this );
482 :
483 : // Tabindex muss nicht jeder unterstuetzen
484 30 : if (hasProperty(PROPERTY_TABINDEX, xSet))
485 28 : xSet->addPropertyChangeListener( PROPERTY_TABINDEX, this );
486 :
487 : }
488 :
489 : //------------------------------------------------------------------
490 4 : void OGroupManager::RemoveElement( const Reference<XPropertySet>& xSet )
491 : {
492 : // Nur ControlModels
493 4 : Reference<XControlModel> xControl(xSet, UNO_QUERY);
494 4 : if (!xControl.is() )
495 4 : return;
496 :
497 : // Component aus Gruppe entfernen
498 4 : ::rtl::OUString sGroupName( GetGroupName( xSet ) );
499 :
500 4 : removeFromGroupMap(sGroupName,xSet);
501 : }
502 :
503 94 : ::rtl::OUString OGroupManager::GetGroupName( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet> xComponent )
504 : {
505 94 : if (!xComponent.is())
506 0 : return ::rtl::OUString();
507 94 : ::rtl::OUString sGroupName;
508 94 : if (hasProperty( PROPERTY_GROUP_NAME, xComponent )) {
509 24 : xComponent->getPropertyValue( PROPERTY_GROUP_NAME ) >>= sGroupName;
510 24 : if (sGroupName.isEmpty())
511 24 : xComponent->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
512 : }
513 : else
514 70 : xComponent->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
515 94 : return sGroupName;
516 : }
517 :
518 : //.........................................................................
519 : } // namespace frm
520 : //.........................................................................
521 :
522 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|