LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / forms / source / component / GroupManager.cxx
blobdeec1bcd572cbeccfbb32743816654aa457cc2e2
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>
31 namespace frm
33 using namespace ::com::sun::star::uno;
34 using namespace ::com::sun::star::beans;
35 using namespace ::com::sun::star::container;
36 using namespace ::com::sun::star::form;
37 using namespace ::com::sun::star::awt;
38 using namespace ::com::sun::star::lang;
39 using namespace ::comphelper;
41 namespace
43 bool isRadioButton( const Reference< XPropertySet >& _rxComponent )
45 bool bIs = false;
46 if ( hasProperty( PROPERTY_CLASSID, _rxComponent ) )
48 sal_Int16 nClassId = FormComponentType::CONTROL;
49 _rxComponent->getPropertyValue( PROPERTY_CLASSID ) >>= nClassId;
50 if ( nClassId == FormComponentType::RADIOBUTTON )
51 bIs = true;
53 return bIs;
57 OGroupCompAcc::OGroupCompAcc(const Reference<XPropertySet>& rxElement, const OGroupComp& _rGroupComp )
58 :m_xComponent( rxElement )
59 ,m_aGroupComp( _rGroupComp )
63 bool OGroupCompAcc::operator==( const OGroupCompAcc& rCompAcc ) const
65 return m_xComponent == rCompAcc.m_xComponent;
68 class OGroupCompAccLess
70 public:
71 bool operator() (const OGroupCompAcc& lhs, const OGroupCompAcc& rhs) const
73 return
74 reinterpret_cast<sal_Int64>(lhs.m_xComponent.get())
75 < reinterpret_cast<sal_Int64>(rhs.m_xComponent.get());
79 OGroupComp::OGroupComp()
80 :m_nPos( -1 )
81 ,m_nTabIndex( 0 )
85 OGroupComp::OGroupComp(const Reference<XPropertySet>& rxSet, sal_Int32 nInsertPos )
86 : m_xComponent( rxSet )
87 , m_xControlModel(rxSet,UNO_QUERY)
88 , m_nPos( nInsertPos )
89 , m_nTabIndex(0)
91 if (m_xComponent.is())
93 if (hasProperty( PROPERTY_TABINDEX, m_xComponent ) )
94 // Indices smaller than 0 are treated like 0
95 m_nTabIndex = std::max(getINT16(m_xComponent->getPropertyValue( PROPERTY_TABINDEX )) , sal_Int16(0));
99 bool OGroupComp::operator==( const OGroupComp& rComp ) const
101 return m_nTabIndex == rComp.GetTabIndex() && m_nPos == rComp.GetPos();
104 class OGroupCompLess
106 public:
107 bool operator() (const OGroupComp& lhs, const OGroupComp& rhs) const
109 bool bResult;
110 // TabIndex of 0 will be added at the end
111 if (lhs.m_nTabIndex == rhs.GetTabIndex())
112 bResult = lhs.m_nPos < rhs.GetPos();
113 else if (lhs.m_nTabIndex && rhs.GetTabIndex())
114 bResult = lhs.m_nTabIndex < rhs.GetTabIndex();
115 else
116 bResult = lhs.m_nTabIndex != 0;
117 return bResult;
121 OGroup::OGroup( const OUString& rGroupName )
122 :m_aGroupName( rGroupName )
123 ,m_nInsertPos(0)
127 void OGroup::InsertComponent( const Reference<XPropertySet>& xSet )
129 OGroupComp aNewGroupComp( xSet, m_nInsertPos );
130 sal_Int32 nPosInserted = insert_sorted(m_aCompArray, aNewGroupComp, OGroupCompLess());
132 OGroupCompAcc aNewGroupCompAcc( xSet, m_aCompArray[nPosInserted] );
133 insert_sorted(m_aCompAccArray, aNewGroupCompAcc, OGroupCompAccLess());
134 m_nInsertPos++;
137 void OGroup::RemoveComponent( const Reference<XPropertySet>& rxElement )
139 sal_Int32 nGroupCompAccPos;
140 OGroupCompAcc aSearchCompAcc( rxElement, OGroupComp() );
141 if ( seek_entry(m_aCompAccArray, aSearchCompAcc, nGroupCompAccPos, OGroupCompAccLess()) )
143 OGroupCompAcc& aGroupCompAcc = m_aCompAccArray[nGroupCompAccPos];
144 const OGroupComp& aGroupComp = aGroupCompAcc.GetGroupComponent();
146 sal_Int32 nGroupCompPos;
147 if ( seek_entry(m_aCompArray, aGroupComp, nGroupCompPos, OGroupCompLess()) )
149 m_aCompAccArray.erase( m_aCompAccArray.begin() + nGroupCompAccPos );
150 m_aCompArray.erase( m_aCompArray.begin() + nGroupCompPos );
153 * By removing the GroupComp the insertion position has become invalid.
154 * We do not to change it here, however, because it's passed on continuously
155 * and ascending distinctively.
158 else
160 OSL_FAIL( "OGroup::RemoveComponent: Component not in Group" );
163 else
165 OSL_FAIL( "OGroup::RemoveComponent: Component not in Group" );
169 Sequence< Reference<XControlModel> > OGroup::GetControlModels() const
171 Sequence<Reference<XControlModel> > aControlModelSeq( m_aCompArray.size() );
172 Reference<XControlModel>* pModels = aControlModelSeq.getArray();
174 for (auto const& rGroupComp : m_aCompArray)
176 *pModels++ = rGroupComp.GetControlModel();
178 return aControlModelSeq;
181 OGroupManager::OGroupManager(const Reference< XContainer >& _rxContainer)
182 :m_pCompGroup( new OGroup( "AllComponentGroup" ) )
183 ,m_xContainer(_rxContainer)
185 osl_atomic_increment(&m_refCount);
187 _rxContainer->addContainerListener(this);
189 osl_atomic_decrement(&m_refCount);
192 OGroupManager::~OGroupManager()
196 // XPropertyChangeListener
197 void OGroupManager::disposing(const EventObject& evt)
199 Reference<XContainer> xContainer(evt.Source, UNO_QUERY);
200 if (xContainer.get() == m_xContainer.get())
202 m_pCompGroup.reset();
204 // delete group
205 m_aGroupArr.clear();
206 m_xContainer.clear();
210 void OGroupManager::removeFromGroupMap(const OUString& _sGroupName,const Reference<XPropertySet>& _xSet)
212 // remove Component from CompGroup
213 m_pCompGroup->RemoveComponent( _xSet );
215 OGroupArr::iterator aFind = m_aGroupArr.find(_sGroupName);
217 if ( aFind != m_aGroupArr.end() )
219 // group exists
220 aFind->second.RemoveComponent( _xSet );
222 // If the count of Group elements == 1 -> deactivate Group
223 sal_Int32 nCount = aFind->second.Count();
224 if ( nCount == 1 || nCount == 0 )
226 OActiveGroups::iterator aActiveFind = ::std::find(
227 m_aActiveGroupMap.begin(),
228 m_aActiveGroupMap.end(),
229 aFind
231 if ( aActiveFind != m_aActiveGroupMap.end() )
233 // the group is active. Deactivate it if the remaining component
234 // is *no* radio button
235 if ( nCount == 0 || !isRadioButton( aFind->second.GetObject( 0 ) ) )
236 m_aActiveGroupMap.erase( aActiveFind );
242 // Deregister as PropertyChangeListener at Component
243 _xSet->removePropertyChangeListener( PROPERTY_NAME, this );
244 if (hasProperty(PROPERTY_GROUP_NAME, _xSet))
245 _xSet->removePropertyChangeListener( PROPERTY_GROUP_NAME, this );
246 if (hasProperty(PROPERTY_TABINDEX, _xSet))
247 _xSet->removePropertyChangeListener( PROPERTY_TABINDEX, this );
250 void SAL_CALL OGroupManager::propertyChange(const PropertyChangeEvent& evt)
252 Reference<XPropertySet> xSet(evt.Source, UNO_QUERY);
254 // remove Component from group
255 OUString sGroupName;
256 if (hasProperty( PROPERTY_GROUP_NAME, xSet ))
257 xSet->getPropertyValue( PROPERTY_GROUP_NAME ) >>= sGroupName;
258 if (evt.PropertyName == PROPERTY_NAME) {
259 if (!sGroupName.isEmpty())
260 return; // group hasn't changed; ignore this name change.
261 // no GroupName; use Name as GroupName
262 evt.OldValue >>= sGroupName;
264 else if (evt.PropertyName == PROPERTY_GROUP_NAME) {
265 evt.OldValue >>= sGroupName;
266 if (sGroupName.isEmpty()) {
267 // No prior GroupName; fallback to Name
268 xSet->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
271 else
272 sGroupName = GetGroupName( xSet );
274 removeFromGroupMap(sGroupName,xSet);
276 // Re-insert Component
277 InsertElement( xSet );
280 // XContainerListener
281 void SAL_CALL OGroupManager::elementInserted(const ContainerEvent& Event)
283 Reference< XPropertySet > xProps;
284 Event.Element >>= xProps;
285 if ( xProps.is() )
286 InsertElement( xProps );
289 void SAL_CALL OGroupManager::elementRemoved(const ContainerEvent& Event)
291 Reference<XPropertySet> xProps;
292 Event.Element >>= xProps;
293 if ( xProps.is() )
294 RemoveElement( xProps );
297 void SAL_CALL OGroupManager::elementReplaced(const ContainerEvent& Event)
299 Reference<XPropertySet> xProps;
300 Event.ReplacedElement >>= xProps;
301 if ( xProps.is() )
302 RemoveElement( xProps );
304 xProps.clear();
305 Event.Element >>= xProps;
306 if ( xProps.is() )
307 InsertElement( xProps );
310 // Other functions
311 Sequence<Reference<XControlModel> > OGroupManager::getControlModels() const
313 return m_pCompGroup->GetControlModels();
316 sal_Int32 OGroupManager::getGroupCount() const
318 return m_aActiveGroupMap.size();
321 void OGroupManager::getGroup(sal_Int32 nGroup, Sequence< Reference<XControlModel> >& _rGroup, OUString& _rName)
323 OSL_ENSURE(nGroup >= 0 && o3tl::make_unsigned(nGroup) < m_aActiveGroupMap.size(),"OGroupManager::getGroup: Invalid group index!");
324 OGroupArr::iterator aGroupPos = m_aActiveGroupMap[nGroup];
325 _rName = aGroupPos->second.GetGroupName();
326 _rGroup = aGroupPos->second.GetControlModels();
329 void OGroupManager::getGroupByName(const OUString& _rName, Sequence< Reference<XControlModel> >& _rGroup)
331 OGroupArr::iterator aFind = m_aGroupArr.find(_rName);
332 if ( aFind != m_aGroupArr.end() )
333 _rGroup = aFind->second.GetControlModels();
336 void OGroupManager::InsertElement( const Reference<XPropertySet>& xSet )
338 // Only ControlModels
339 Reference<XControlModel> xControl(xSet, UNO_QUERY);
340 if (!xControl.is() )
341 return;
343 // Add Component to CompGroup
344 m_pCompGroup->InsertComponent( xSet );
346 // Add Component to Group
347 OUString sGroupName( GetGroupName( xSet ) );
349 OGroupArr::iterator aFind = m_aGroupArr.find(sGroupName);
351 if ( aFind == m_aGroupArr.end() )
353 aFind = m_aGroupArr.emplace(sGroupName,OGroup(sGroupName)).first;
356 aFind->second.InsertComponent( xSet );
358 // if we have at least 2 elements in the group, then this is an "active group"
359 bool bActivateGroup = aFind->second.Count() == 2;
361 // Additionally, if the component is a radio button, then it's group becomes active,
362 // too. With this, we ensure that in a container with n radio buttons which all are
363 // in different groups the selection still works reliably (means that all radios can be
364 // clicked independently)
365 if ( aFind->second.Count() == 1 )
367 if ( isRadioButton( xSet ) )
368 bActivateGroup = true;
371 if ( bActivateGroup )
373 OActiveGroups::iterator aAlreadyExistent = ::std::find(
374 m_aActiveGroupMap.begin(),
375 m_aActiveGroupMap.end(),
376 aFind
378 if ( aAlreadyExistent == m_aActiveGroupMap.end() )
379 m_aActiveGroupMap.push_back( aFind );
382 // Register as PropertyChangeListener at Component
383 xSet->addPropertyChangeListener( PROPERTY_NAME, this );
384 if (hasProperty(PROPERTY_GROUP_NAME, xSet))
385 xSet->addPropertyChangeListener( PROPERTY_GROUP_NAME, this );
387 // Not everyone needs to support Tabindex
388 if (hasProperty(PROPERTY_TABINDEX, xSet))
389 xSet->addPropertyChangeListener( PROPERTY_TABINDEX, this );
392 void OGroupManager::RemoveElement( const Reference<XPropertySet>& xSet )
394 // Only ControlModels
395 Reference<XControlModel> xControl(xSet, UNO_QUERY);
396 if (!xControl.is() )
397 return;
399 // Remove Component from Group
400 OUString sGroupName( GetGroupName( xSet ) );
402 removeFromGroupMap(sGroupName,xSet);
405 OUString OGroupManager::GetGroupName( const css::uno::Reference< css::beans::XPropertySet>& xComponent )
407 if (!xComponent.is())
408 return OUString();
409 OUString sGroupName;
410 if (hasProperty( PROPERTY_GROUP_NAME, xComponent )) {
411 xComponent->getPropertyValue( PROPERTY_GROUP_NAME ) >>= sGroupName;
412 if (sGroupName.isEmpty())
413 xComponent->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
415 else
416 xComponent->getPropertyValue( PROPERTY_NAME ) >>= sGroupName;
417 return sGroupName;
419 } // namespace frm
421 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */