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