tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / forms / source / component / GroupManager.cxx
blob895dde067d544136ba88a60a04b7d3e624b8d771
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "GroupManager.hxx"
21 #include <com/sun/star/form/FormComponentType.hpp>
22 #include <comphelper/property.hxx>
23 #include <comphelper/types.hxx>
24 #include <o3tl/safeint.hxx>
25 #include <osl/diagnose.h>
27 #include <frm_strings.hxx>
29 #include <algorithm>
30 #include <utility>
32 namespace frm
34 using namespace ::com::sun::star::uno;
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 using namespace ::comphelper;
42 namespace
44 bool isRadioButton( const Reference< XPropertySet >& _rxComponent )
46 bool bIs = false;
47 if ( hasProperty( PROPERTY_CLASSID, _rxComponent ) )
49 sal_Int16 nClassId = FormComponentType::CONTROL;
50 _rxComponent->getPropertyValue( PROPERTY_CLASSID ) >>= nClassId;
51 if ( nClassId == FormComponentType::RADIOBUTTON )
52 bIs = true;
54 return bIs;
58 OGroupCompAcc::OGroupCompAcc(const Reference<XPropertySet>& rxElement, OGroupComp _aGroupComp )
59 :m_xComponent( rxElement )
60 ,m_aGroupComp(std::move( _aGroupComp ))
64 bool OGroupCompAcc::operator==( const OGroupCompAcc& rCompAcc ) const
66 return m_xComponent == rCompAcc.m_xComponent;
69 class OGroupCompAccLess
71 public:
72 bool operator() (const OGroupCompAcc& lhs, const OGroupCompAcc& rhs) const
74 return
75 reinterpret_cast<sal_Int64>(lhs.m_xComponent.get())
76 < reinterpret_cast<sal_Int64>(rhs.m_xComponent.get());
80 OGroupComp::OGroupComp()
81 :m_nPos( -1 )
82 ,m_nTabIndex( 0 )
86 OGroupComp::OGroupComp(const Reference<XPropertySet>& rxSet, sal_Int32 nInsertPos )
87 : m_xComponent( rxSet )
88 , m_xControlModel(rxSet,UNO_QUERY)
89 , m_nPos( nInsertPos )
90 , m_nTabIndex(0)
92 if (m_xComponent.is())
94 if (hasProperty( PROPERTY_TABINDEX, m_xComponent ) )
95 // Indices smaller than 0 are treated like 0
96 m_nTabIndex = std::max(getINT16(m_xComponent->getPropertyValue( PROPERTY_TABINDEX )) , sal_Int16(0));
100 bool OGroupComp::operator==( const OGroupComp& rComp ) const
102 return m_nTabIndex == rComp.GetTabIndex() && m_nPos == rComp.GetPos();
105 class OGroupCompLess
107 public:
108 bool operator() (const OGroupComp& lhs, const OGroupComp& rhs) const
110 bool bResult;
111 // TabIndex of 0 will be added at the end
112 if (lhs.m_nTabIndex == rhs.GetTabIndex())
113 bResult = lhs.m_nPos < rhs.GetPos();
114 else if (lhs.m_nTabIndex && rhs.GetTabIndex())
115 bResult = lhs.m_nTabIndex < rhs.GetTabIndex();
116 else
117 bResult = lhs.m_nTabIndex != 0;
118 return bResult;
122 OGroup::OGroup( OUString sGroupName )
123 :m_aGroupName(std::move( sGroupName ))
124 ,m_nInsertPos(0)
128 void OGroup::InsertComponent( const Reference<XPropertySet>& xSet )
130 OGroupComp aNewGroupComp( xSet, m_nInsertPos );
131 sal_Int32 nPosInserted = insert_sorted(m_aCompArray, aNewGroupComp, OGroupCompLess());
133 OGroupCompAcc aNewGroupCompAcc( xSet, m_aCompArray[nPosInserted] );
134 insert_sorted(m_aCompAccArray, aNewGroupCompAcc, OGroupCompAccLess());
135 m_nInsertPos++;
138 void OGroup::RemoveComponent( const Reference<XPropertySet>& rxElement )
140 sal_Int32 nGroupCompAccPos;
141 OGroupCompAcc aSearchCompAcc( rxElement, OGroupComp() );
142 if ( seek_entry(m_aCompAccArray, aSearchCompAcc, nGroupCompAccPos, OGroupCompAccLess()) )
144 OGroupCompAcc& aGroupCompAcc = m_aCompAccArray[nGroupCompAccPos];
145 const OGroupComp& aGroupComp = aGroupCompAcc.GetGroupComponent();
147 sal_Int32 nGroupCompPos;
148 if ( seek_entry(m_aCompArray, aGroupComp, nGroupCompPos, OGroupCompLess()) )
150 m_aCompAccArray.erase( m_aCompAccArray.begin() + nGroupCompAccPos );
151 m_aCompArray.erase( m_aCompArray.begin() + nGroupCompPos );
154 * By removing the GroupComp the insertion position has become invalid.
155 * We do not to change it here, however, because it's passed on continuously
156 * and ascending distinctively.
159 else
161 OSL_FAIL( "OGroup::RemoveComponent: Component not in Group" );
164 else
166 OSL_FAIL( "OGroup::RemoveComponent: Component not in Group" );
170 Sequence< Reference<XControlModel> > OGroup::GetControlModels() const
172 Sequence<Reference<XControlModel> > aControlModelSeq( m_aCompArray.size() );
173 Reference<XControlModel>* pModels = aControlModelSeq.getArray();
175 for (auto const& rGroupComp : m_aCompArray)
177 *pModels++ = rGroupComp.GetControlModel();
179 return aControlModelSeq;
182 OGroupManager::OGroupManager(const Reference< XContainer >& _rxContainer)
183 :m_pCompGroup( new OGroup( u"AllComponentGroup"_ustr ) )
184 ,m_xContainer(_rxContainer)
186 osl_atomic_increment(&m_refCount);
188 _rxContainer->addContainerListener(this);
190 osl_atomic_decrement(&m_refCount);
193 OGroupManager::~OGroupManager()
197 // XPropertyChangeListener
198 void OGroupManager::disposing(const EventObject& evt)
200 Reference<XContainer> xContainer(evt.Source, UNO_QUERY);
201 if (xContainer.get() == m_xContainer.get())
203 m_pCompGroup.reset();
205 // delete group
206 m_aGroupArr.clear();
207 m_xContainer.clear();
211 void OGroupManager::removeFromGroupMap(const OUString& _sGroupName,const Reference<XPropertySet>& _xSet)
213 // remove Component from CompGroup
214 m_pCompGroup->RemoveComponent( _xSet );
216 OGroupArr::iterator aFind = m_aGroupArr.find(_sGroupName);
218 if ( aFind != m_aGroupArr.end() )
220 // group exists
221 aFind->second.RemoveComponent( _xSet );
223 // If the count of Group elements == 1 -> deactivate Group
224 sal_Int32 nCount = aFind->second.Count();
225 if ( nCount == 1 || nCount == 0 )
227 OActiveGroups::iterator aActiveFind = ::std::find(
228 m_aActiveGroupMap.begin(),
229 m_aActiveGroupMap.end(),
230 aFind
232 if ( aActiveFind != m_aActiveGroupMap.end() )
234 // the group is active. Deactivate it if the remaining component
235 // is *no* radio button
236 if ( nCount == 0 || !isRadioButton( aFind->second.GetObject( 0 ) ) )
237 m_aActiveGroupMap.erase( aActiveFind );
243 // Deregister as PropertyChangeListener at Component
244 _xSet->removePropertyChangeListener( PROPERTY_NAME, this );
245 if (hasProperty(PROPERTY_GROUP_NAME, _xSet))
246 _xSet->removePropertyChangeListener( PROPERTY_GROUP_NAME, this );
247 if (hasProperty(PROPERTY_TABINDEX, _xSet))
248 _xSet->removePropertyChangeListener( PROPERTY_TABINDEX, this );
251 void SAL_CALL OGroupManager::propertyChange(const PropertyChangeEvent& evt)
253 Reference<XPropertySet> xSet(evt.Source, UNO_QUERY);
255 // remove Component from group
256 OUString sGroupName;
257 if (hasProperty( PROPERTY_GROUP_NAME, xSet ))
258 xSet->getPropertyValue( PROPERTY_GROUP_NAME ) >>= sGroupName;
259 if (evt.PropertyName == PROPERTY_NAME) {
260 if (!sGroupName.isEmpty())
261 return; // group hasn't changed; ignore this name change.
262 // no GroupName; use Name as GroupName
263 evt.OldValue >>= sGroupName;
265 else if (evt.PropertyName == PROPERTY_GROUP_NAME) {
266 evt.OldValue >>= sGroupName;
267 if (sGroupName.isEmpty()) {
268 // No prior GroupName; fallback to Name
269 xSet->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
272 else
273 sGroupName = GetGroupName( xSet );
275 removeFromGroupMap(sGroupName,xSet);
277 // Re-insert Component
278 InsertElement( xSet );
281 // XContainerListener
282 void SAL_CALL OGroupManager::elementInserted(const ContainerEvent& Event)
284 Reference< XPropertySet > xProps;
285 Event.Element >>= xProps;
286 if ( xProps.is() )
287 InsertElement( xProps );
290 void SAL_CALL OGroupManager::elementRemoved(const ContainerEvent& Event)
292 Reference<XPropertySet> xProps;
293 Event.Element >>= xProps;
294 if ( xProps.is() )
295 RemoveElement( xProps );
298 void SAL_CALL OGroupManager::elementReplaced(const ContainerEvent& Event)
300 Reference<XPropertySet> xProps;
301 Event.ReplacedElement >>= xProps;
302 if ( xProps.is() )
303 RemoveElement( xProps );
305 xProps.clear();
306 Event.Element >>= xProps;
307 if ( xProps.is() )
308 InsertElement( xProps );
311 // Other functions
312 Sequence<Reference<XControlModel> > OGroupManager::getControlModels() const
314 return m_pCompGroup->GetControlModels();
317 sal_Int32 OGroupManager::getGroupCount() const
319 return m_aActiveGroupMap.size();
322 void OGroupManager::getGroup(sal_Int32 nGroup, Sequence< Reference<XControlModel> >& _rGroup, OUString& _rName)
324 OSL_ENSURE(nGroup >= 0 && o3tl::make_unsigned(nGroup) < m_aActiveGroupMap.size(),"OGroupManager::getGroup: Invalid group index!");
325 OGroupArr::iterator aGroupPos = m_aActiveGroupMap[nGroup];
326 _rName = aGroupPos->second.GetGroupName();
327 _rGroup = aGroupPos->second.GetControlModels();
330 void OGroupManager::getGroupByName(const OUString& _rName, Sequence< Reference<XControlModel> >& _rGroup)
332 OGroupArr::iterator aFind = m_aGroupArr.find(_rName);
333 if ( aFind != m_aGroupArr.end() )
334 _rGroup = aFind->second.GetControlModels();
337 void OGroupManager::InsertElement( const Reference<XPropertySet>& xSet )
339 // Only ControlModels
340 Reference<XControlModel> xControl(xSet, UNO_QUERY);
341 if (!xControl.is() )
342 return;
344 // Add Component to CompGroup
345 m_pCompGroup->InsertComponent( xSet );
347 // Add Component to Group
348 OUString sGroupName( GetGroupName( xSet ) );
350 OGroupArr::iterator aFind = m_aGroupArr.find(sGroupName);
352 if ( aFind == m_aGroupArr.end() )
354 aFind = m_aGroupArr.emplace(sGroupName,OGroup(sGroupName)).first;
357 aFind->second.InsertComponent( xSet );
359 // if we have at least 2 elements in the group, then this is an "active group"
360 bool bActivateGroup = aFind->second.Count() == 2;
362 // Additionally, if the component is a radio button, then it's group becomes active,
363 // too. With this, we ensure that in a container with n radio buttons which all are
364 // in different groups the selection still works reliably (means that all radios can be
365 // clicked independently)
366 if ( aFind->second.Count() == 1 )
368 if ( isRadioButton( xSet ) )
369 bActivateGroup = true;
372 if ( bActivateGroup )
374 OActiveGroups::iterator aAlreadyExistent = ::std::find(
375 m_aActiveGroupMap.begin(),
376 m_aActiveGroupMap.end(),
377 aFind
379 if ( aAlreadyExistent == m_aActiveGroupMap.end() )
380 m_aActiveGroupMap.push_back( aFind );
383 // Register as PropertyChangeListener at Component
384 xSet->addPropertyChangeListener( PROPERTY_NAME, this );
385 if (hasProperty(PROPERTY_GROUP_NAME, xSet))
386 xSet->addPropertyChangeListener( PROPERTY_GROUP_NAME, this );
388 // Not everyone needs to support Tabindex
389 if (hasProperty(PROPERTY_TABINDEX, xSet))
390 xSet->addPropertyChangeListener( PROPERTY_TABINDEX, this );
393 void OGroupManager::RemoveElement( const Reference<XPropertySet>& xSet )
395 // Only ControlModels
396 Reference<XControlModel> xControl(xSet, UNO_QUERY);
397 if (!xControl.is() )
398 return;
400 // Remove Component from Group
401 OUString sGroupName( GetGroupName( xSet ) );
403 removeFromGroupMap(sGroupName,xSet);
406 OUString OGroupManager::GetGroupName( const css::uno::Reference< css::beans::XPropertySet>& xComponent )
408 if (!xComponent.is())
409 return OUString();
410 OUString sGroupName;
411 if (hasProperty( PROPERTY_GROUP_NAME, xComponent )) {
412 xComponent->getPropertyValue( PROPERTY_GROUP_NAME ) >>= sGroupName;
413 if (sGroupName.isEmpty())
414 xComponent->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
416 else
417 xComponent->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
418 return sGroupName;
420 } // namespace frm
422 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */