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 <osl/diagnose.h>
25 : #include <tools/solar.h>
26 :
27 : #include "property.hrc"
28 :
29 : #include <algorithm>
30 :
31 : namespace frm
32 : {
33 : using namespace ::com::sun::star::uno;
34 : using namespace ::com::sun::star::sdbc;
35 : using namespace ::com::sun::star::beans;
36 : using namespace ::com::sun::star::container;
37 : using namespace ::com::sun::star::form;
38 : using namespace ::com::sun::star::awt;
39 : using namespace ::com::sun::star::lang;
40 :
41 : namespace
42 : {
43 707 : bool isRadioButton( const Reference< XPropertySet >& _rxComponent )
44 : {
45 707 : bool bIs = false;
46 707 : if ( hasProperty( PROPERTY_CLASSID, _rxComponent ) )
47 : {
48 707 : sal_Int16 nClassId = FormComponentType::CONTROL;
49 707 : _rxComponent->getPropertyValue( PROPERTY_CLASSID ) >>= nClassId;
50 707 : if ( nClassId == FormComponentType::RADIOBUTTON )
51 41 : bIs = true;
52 : }
53 707 : return bIs;
54 : }
55 : }
56 :
57 2712 : OGroupCompAcc::OGroupCompAcc(const Reference<XPropertySet>& rxElement, const OGroupComp& _rGroupComp )
58 : :m_xComponent( rxElement )
59 2712 : ,m_aGroupComp( _rGroupComp )
60 : {
61 2712 : }
62 :
63 1274 : bool OGroupCompAcc::operator==( const OGroupCompAcc& rCompAcc ) const
64 : {
65 1274 : return (m_xComponent == rCompAcc.GetComponent());
66 : }
67 :
68 : class OGroupCompAccLess : public ::std::binary_function<OGroupCompAcc, OGroupCompAcc, sal_Bool>
69 : {
70 : public:
71 2309 : bool operator() (const OGroupCompAcc& lhs, const OGroupCompAcc& rhs) const
72 : {
73 : return
74 2309 : reinterpret_cast<sal_Int64>(lhs.m_xComponent.get())
75 2309 : < reinterpret_cast<sal_Int64>(rhs.m_xComponent.get());
76 : }
77 : };
78 :
79 1274 : OGroupComp::OGroupComp()
80 : :m_nPos( -1 )
81 1274 : ,m_nTabIndex( 0 )
82 : {
83 1274 : }
84 :
85 7110 : OGroupComp::OGroupComp(const OGroupComp& _rSource)
86 : :m_aName( _rSource.m_aName )
87 : ,m_xComponent( _rSource.m_xComponent )
88 : ,m_xControlModel(_rSource.m_xControlModel)
89 : ,m_nPos( _rSource.m_nPos )
90 7110 : ,m_nTabIndex( _rSource.m_nTabIndex )
91 : {
92 7110 : }
93 :
94 1438 : OGroupComp::OGroupComp(const Reference<XPropertySet>& rxSet, sal_Int32 nInsertPos )
95 : : m_aName( OGroupManager::GetGroupName( rxSet ) )
96 : , m_xComponent( rxSet )
97 : , m_xControlModel(rxSet,UNO_QUERY)
98 : , m_nPos( nInsertPos )
99 1438 : , m_nTabIndex(0)
100 : {
101 1438 : if (m_xComponent.is())
102 : {
103 1438 : if (hasProperty( PROPERTY_TABINDEX, m_xComponent ) )
104 : // Indices smaller than 0 are treated like 0
105 1284 : m_nTabIndex = std::max(getINT16(m_xComponent->getPropertyValue( PROPERTY_TABINDEX )) , sal_Int16(0));
106 : }
107 1438 : }
108 :
109 1274 : bool OGroupComp::operator==( const OGroupComp& rComp ) const
110 : {
111 1274 : return m_nTabIndex == rComp.GetTabIndex() && m_nPos == rComp.GetPos();
112 : }
113 :
114 : class OGroupCompLess : public ::std::binary_function<OGroupComp, OGroupComp, sal_Bool>
115 : {
116 : public:
117 2298 : bool operator() (const OGroupComp& lhs, const OGroupComp& rhs) const
118 : {
119 : bool bResult;
120 : // TabIndex of 0 will be added at the end
121 2298 : if (lhs.m_nTabIndex == rhs.GetTabIndex())
122 1776 : bResult = lhs.m_nPos < rhs.GetPos();
123 522 : else if (lhs.m_nTabIndex && rhs.GetTabIndex())
124 2 : bResult = lhs.m_nTabIndex < rhs.GetTabIndex();
125 : else
126 520 : bResult = lhs.m_nTabIndex != 0;
127 2298 : return bResult;
128 : }
129 : };
130 :
131 697 : OGroup::OGroup( const OUString& rGroupName )
132 : :m_aGroupName( rGroupName )
133 697 : ,m_nInsertPos(0)
134 : {
135 697 : }
136 :
137 1905 : OGroup::~OGroup()
138 : {
139 1905 : }
140 :
141 1438 : void OGroup::InsertComponent( const Reference<XPropertySet>& xSet )
142 : {
143 1438 : OGroupComp aNewGroupComp( xSet, m_nInsertPos );
144 1438 : sal_Int32 nPosInserted = insert_sorted(m_aCompArray, aNewGroupComp, OGroupCompLess());
145 :
146 2876 : OGroupCompAcc aNewGroupCompAcc( xSet, m_aCompArray[nPosInserted] );
147 1438 : insert_sorted(m_aCompAccArray, aNewGroupCompAcc, OGroupCompAccLess());
148 2876 : m_nInsertPos++;
149 1438 : }
150 :
151 1274 : void OGroup::RemoveComponent( const Reference<XPropertySet>& rxElement )
152 : {
153 : sal_Int32 nGroupCompAccPos;
154 1274 : OGroupCompAcc aSearchCompAcc( rxElement, OGroupComp() );
155 1274 : if ( seek_entry(m_aCompAccArray, aSearchCompAcc, nGroupCompAccPos, OGroupCompAccLess()) )
156 : {
157 1274 : OGroupCompAcc& aGroupCompAcc = m_aCompAccArray[nGroupCompAccPos];
158 1274 : const OGroupComp& aGroupComp = aGroupCompAcc.GetGroupComponent();
159 :
160 : sal_Int32 nGroupCompPos;
161 1274 : if ( seek_entry(m_aCompArray, aGroupComp, nGroupCompPos, OGroupCompLess()) )
162 : {
163 1274 : m_aCompAccArray.erase( m_aCompAccArray.begin() + nGroupCompAccPos );
164 1274 : m_aCompArray.erase( m_aCompArray.begin() + nGroupCompPos );
165 :
166 : /*
167 : * By removing the GroupComp the insertion position has become invalid.
168 : * We do not to change it here, however, because its passed on continuously
169 : * and ascending distinctively.
170 : */
171 : }
172 : else
173 : {
174 : OSL_FAIL( "OGroup::RemoveComponent: Component not in Group" );
175 : }
176 : }
177 : else
178 : {
179 : OSL_FAIL( "OGroup::RemoveComponent: Component not in Group" );
180 1274 : }
181 1274 : }
182 :
183 0 : bool OGroup::operator==( const OGroup& rGroup ) const
184 : {
185 0 : return m_aGroupName.equals(rGroup.GetGroupName());
186 : }
187 :
188 282 : Sequence< Reference<XControlModel> > OGroup::GetControlModels() const
189 : {
190 282 : sal_Int32 nLen = m_aCompArray.size();
191 282 : Sequence<Reference<XControlModel> > aControlModelSeq( nLen );
192 282 : Reference<XControlModel>* pModels = aControlModelSeq.getArray();
193 :
194 282 : OGroupCompArr::const_iterator aGroupComps = m_aCompArray.begin();
195 741 : for (sal_Int32 i = 0; i < nLen; ++i, ++pModels, ++aGroupComps)
196 : {
197 459 : *pModels = aGroupComps->GetControlModel();
198 : }
199 282 : return aControlModelSeq;
200 : }
201 :
202 184 : OGroupManager::OGroupManager(const Reference< XContainer >& _rxContainer)
203 184 : :m_pCompGroup( new OGroup( OUString("AllComponentGroup") ) )
204 368 : ,m_xContainer(_rxContainer)
205 : {
206 184 : osl_atomic_increment(&m_refCount);
207 : {
208 184 : _rxContainer->addContainerListener(this);
209 : }
210 184 : osl_atomic_decrement(&m_refCount);
211 184 : }
212 :
213 546 : OGroupManager::~OGroupManager()
214 : {
215 : // delete all Components and CompGroup
216 182 : delete m_pCompGroup;
217 364 : }
218 :
219 : // XPropertyChangeListener
220 354 : void OGroupManager::disposing(const EventObject& evt) throw( RuntimeException, std::exception )
221 : {
222 354 : Reference<XContainer> xContainer(evt.Source, UNO_QUERY);
223 354 : if (xContainer.get() == m_xContainer.get())
224 : {
225 183 : DELETEZ(m_pCompGroup);
226 :
227 : // delete group
228 183 : m_aGroupArr.clear();
229 183 : m_xContainer.clear();
230 354 : }
231 354 : }
232 :
233 637 : void OGroupManager::removeFromGroupMap(const OUString& _sGroupName,const Reference<XPropertySet>& _xSet)
234 : {
235 : // remove Component from CompGroup
236 637 : m_pCompGroup->RemoveComponent( _xSet );
237 :
238 637 : OGroupArr::iterator aFind = m_aGroupArr.find(_sGroupName);
239 :
240 637 : if ( aFind != m_aGroupArr.end() )
241 : {
242 : // group exists
243 637 : aFind->second.RemoveComponent( _xSet );
244 :
245 : // If the count of Group elements == 1 -> deactivate Group
246 637 : sal_Int32 nCount = aFind->second.Count();
247 637 : if ( nCount == 1 || nCount == 0 )
248 : {
249 : OActiveGroups::iterator aActiveFind = ::std::find(
250 : m_aActiveGroupMap.begin(),
251 : m_aActiveGroupMap.end(),
252 : aFind
253 631 : );
254 631 : if ( aActiveFind != m_aActiveGroupMap.end() )
255 : {
256 : // the group is active. Deactivate it if the remaining component
257 : // is *no* radio button
258 36 : if ( nCount == 0 || !isRadioButton( aFind->second.GetObject( 0 ) ) )
259 36 : m_aActiveGroupMap.erase( aActiveFind );
260 : }
261 : }
262 : }
263 :
264 :
265 : // Deregister as PropertyChangeListener at Component
266 637 : _xSet->removePropertyChangeListener( PROPERTY_NAME, this );
267 637 : if (hasProperty(PROPERTY_GROUP_NAME, _xSet))
268 34 : _xSet->removePropertyChangeListener( PROPERTY_GROUP_NAME, this );
269 637 : if (hasProperty(PROPERTY_TABINDEX, _xSet))
270 564 : _xSet->removePropertyChangeListener( PROPERTY_TABINDEX, this );
271 637 : }
272 :
273 392 : void SAL_CALL OGroupManager::propertyChange(const PropertyChangeEvent& evt) throw ( ::com::sun::star::uno::RuntimeException, std::exception)
274 : {
275 392 : Reference<XPropertySet> xSet(evt.Source, UNO_QUERY);
276 :
277 : // remove Component from group
278 774 : OUString sGroupName;
279 392 : if (hasProperty( PROPERTY_GROUP_NAME, xSet ))
280 36 : xSet->getPropertyValue( PROPERTY_GROUP_NAME ) >>= sGroupName;
281 392 : if (evt.PropertyName == PROPERTY_NAME) {
282 211 : if (!sGroupName.isEmpty())
283 402 : return; // group hasn't changed; ignore this name change.
284 : // no GroupName; use Name as GroupNme
285 201 : evt.OldValue >>= sGroupName;
286 : }
287 181 : else if (evt.PropertyName == PROPERTY_GROUP_NAME) {
288 10 : evt.OldValue >>= sGroupName;
289 10 : if (sGroupName.isEmpty()) {
290 : // No prior GroupName; fallback to Nme
291 3 : xSet->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
292 : }
293 : }
294 : else
295 171 : sGroupName = GetGroupName( xSet );
296 :
297 382 : removeFromGroupMap(sGroupName,xSet);
298 :
299 : // Re-insert Component
300 764 : InsertElement( xSet );
301 : }
302 :
303 : // XContainerListener
304 341 : void SAL_CALL OGroupManager::elementInserted(const ContainerEvent& Event) throw ( ::com::sun::star::uno::RuntimeException, std::exception)
305 : {
306 341 : Reference< XPropertySet > xProps;
307 341 : Event.Element >>= xProps;
308 341 : if ( xProps.is() )
309 341 : InsertElement( xProps );
310 341 : }
311 :
312 255 : void SAL_CALL OGroupManager::elementRemoved(const ContainerEvent& Event) throw ( ::com::sun::star::uno::RuntimeException, std::exception)
313 : {
314 255 : Reference<XPropertySet> xProps;
315 255 : Event.Element >>= xProps;
316 255 : if ( xProps.is() )
317 255 : RemoveElement( xProps );
318 255 : }
319 :
320 0 : void SAL_CALL OGroupManager::elementReplaced(const ContainerEvent& Event) throw ( ::com::sun::star::uno::RuntimeException, std::exception)
321 : {
322 0 : Reference<XPropertySet> xProps;
323 0 : Event.ReplacedElement >>= xProps;
324 0 : if ( xProps.is() )
325 0 : RemoveElement( xProps );
326 :
327 0 : xProps.clear();
328 0 : Event.Element >>= xProps;
329 0 : if ( xProps.is() )
330 0 : InsertElement( xProps );
331 0 : }
332 :
333 : // Other functions
334 269 : Sequence<Reference<XControlModel> > OGroupManager::getControlModels()
335 : {
336 269 : return m_pCompGroup->GetControlModels();
337 : }
338 :
339 149 : sal_Int32 OGroupManager::getGroupCount()
340 : {
341 149 : return m_aActiveGroupMap.size();
342 : }
343 :
344 13 : void OGroupManager::getGroup(sal_Int32 nGroup, Sequence< Reference<XControlModel> >& _rGroup, OUString& _rName)
345 : {
346 : OSL_ENSURE(nGroup >= 0 && (size_t)nGroup < m_aActiveGroupMap.size(),"OGroupManager::getGroup: Invalid group index!");
347 13 : OGroupArr::iterator aGroupPos = m_aActiveGroupMap[nGroup];
348 13 : _rName = aGroupPos->second.GetGroupName();
349 13 : _rGroup = aGroupPos->second.GetControlModels();
350 13 : }
351 :
352 0 : void OGroupManager::getGroupByName(const OUString& _rName, Sequence< Reference<XControlModel> >& _rGroup)
353 : {
354 0 : OGroupArr::iterator aFind = m_aGroupArr.find(_rName);
355 0 : if ( aFind != m_aGroupArr.end() )
356 0 : _rGroup = aFind->second.GetControlModels();
357 0 : }
358 :
359 723 : void OGroupManager::InsertElement( const Reference<XPropertySet>& xSet )
360 : {
361 : // Only ControlModels
362 723 : Reference<XControlModel> xControl(xSet, UNO_QUERY);
363 723 : if (!xControl.is() )
364 727 : return;
365 :
366 : // Add Component to CompGroup
367 719 : m_pCompGroup->InsertComponent( xSet );
368 :
369 : // Add Component to Group
370 1438 : OUString sGroupName( GetGroupName( xSet ) );
371 :
372 719 : OGroupArr::iterator aFind = m_aGroupArr.find(sGroupName);
373 :
374 719 : if ( aFind == m_aGroupArr.end() )
375 : {
376 513 : aFind = m_aGroupArr.insert(OGroupArr::value_type(sGroupName,OGroup(sGroupName))).first;
377 : }
378 :
379 719 : aFind->second.InsertComponent( xSet );
380 :
381 : // if we have at least 2 elements in the group, then this is an "active group"
382 719 : bool bActivateGroup = aFind->second.Count() == 2;
383 :
384 : // Additionally, if the component is a radio button, then it's group becomes active,
385 : // too. With this, we ensure that in a container with n radio buttons which all are
386 : // in different groups the selection still works reliably (means that all radios can be
387 : // clicked independently)
388 719 : if ( aFind->second.Count() == 1 )
389 : {
390 705 : if ( isRadioButton( xSet ) )
391 41 : bActivateGroup = true;
392 : }
393 :
394 719 : if ( bActivateGroup )
395 : {
396 : OActiveGroups::iterator aAlreadyExistent = ::std::find(
397 : m_aActiveGroupMap.begin(),
398 : m_aActiveGroupMap.end(),
399 : aFind
400 45 : );
401 45 : if ( aAlreadyExistent == m_aActiveGroupMap.end() )
402 45 : m_aActiveGroupMap.push_back( aFind );
403 : }
404 :
405 : // Register as PropertyChangeListener at Component
406 719 : xSet->addPropertyChangeListener( PROPERTY_NAME, this );
407 719 : if (hasProperty(PROPERTY_GROUP_NAME, xSet))
408 45 : xSet->addPropertyChangeListener( PROPERTY_GROUP_NAME, this );
409 :
410 : // Not everyone needs to support Tabindex
411 719 : if (hasProperty(PROPERTY_TABINDEX, xSet))
412 1361 : xSet->addPropertyChangeListener( PROPERTY_TABINDEX, this );
413 : }
414 :
415 255 : void OGroupManager::RemoveElement( const Reference<XPropertySet>& xSet )
416 : {
417 : // Only ControlModels
418 255 : Reference<XControlModel> xControl(xSet, UNO_QUERY);
419 255 : if (!xControl.is() )
420 255 : return;
421 :
422 : // Remove Component from Group
423 510 : OUString sGroupName( GetGroupName( xSet ) );
424 :
425 510 : removeFromGroupMap(sGroupName,xSet);
426 : }
427 :
428 2583 : OUString OGroupManager::GetGroupName( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet> xComponent )
429 : {
430 2583 : if (!xComponent.is())
431 0 : return OUString();
432 2583 : OUString sGroupName;
433 2583 : if (hasProperty( PROPERTY_GROUP_NAME, xComponent )) {
434 155 : xComponent->getPropertyValue( PROPERTY_GROUP_NAME ) >>= sGroupName;
435 155 : if (sGroupName.isEmpty())
436 82 : xComponent->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
437 : }
438 : else
439 2428 : xComponent->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
440 2583 : return sGroupName;
441 : }
442 : } // namespace frm
443 :
444 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|