1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_forms.hxx" 26 #include "GroupManager.hxx" 27 #include <com/sun/star/beans/XFastPropertySet.hpp> 28 #include <com/sun/star/form/FormComponentType.hpp> 29 #include <comphelper/property.hxx> 30 #include <comphelper/uno3.hxx> 31 #include <tools/solar.h> 32 #include <tools/debug.hxx> 33 34 #include "property.hrc" 35 36 #include <algorithm> 37 38 //......................................................................... 39 namespace frm 40 { 41 //......................................................................... 42 43 using namespace ::com::sun::star::uno; 44 using namespace ::com::sun::star::sdbc; 45 using namespace ::com::sun::star::beans; 46 using namespace ::com::sun::star::container; 47 using namespace ::com::sun::star::form; 48 using namespace ::com::sun::star::awt; 49 using namespace ::com::sun::star::lang; 50 using namespace ::com::sun::star::form; 51 52 namespace 53 { 54 bool isRadioButton( const Reference< XPropertySet >& _rxComponent ) 55 { 56 bool bIs = false; 57 if ( hasProperty( PROPERTY_CLASSID, _rxComponent ) ) 58 { 59 sal_Int16 nClassId = FormComponentType::CONTROL; 60 _rxComponent->getPropertyValue( PROPERTY_CLASSID ) >>= nClassId; 61 if ( nClassId == FormComponentType::RADIOBUTTON ) 62 bIs = true; 63 } 64 return bIs; 65 } 66 } 67 68 //======================================================================== 69 // class OGroupCompAcc 70 //======================================================================== 71 //------------------------------------------------------------------ 72 OGroupCompAcc::OGroupCompAcc(const Reference<XPropertySet>& rxElement, const OGroupComp& _rGroupComp ) 73 :m_xComponent( rxElement ) 74 ,m_aGroupComp( _rGroupComp ) 75 { 76 } 77 78 //------------------------------------------------------------------ 79 sal_Bool OGroupCompAcc::operator==( const OGroupCompAcc& rCompAcc ) const 80 { 81 return (m_xComponent == rCompAcc.GetComponent()); 82 } 83 84 //------------------------------------------------------------------ 85 class OGroupCompAccLess : public ::std::binary_function<OGroupCompAcc, OGroupCompAcc, sal_Bool> 86 { 87 public: 88 sal_Bool operator() (const OGroupCompAcc& lhs, const OGroupCompAcc& rhs) const 89 { 90 return 91 reinterpret_cast<sal_Int64>(lhs.m_xComponent.get()) 92 < reinterpret_cast<sal_Int64>(rhs.m_xComponent.get()); 93 } 94 }; 95 96 //======================================================================== 97 // class OGroupComp 98 //======================================================================== 99 100 //------------------------------------------------------------------ 101 OGroupComp::OGroupComp() 102 :m_nPos( -1 ) 103 ,m_nTabIndex( 0 ) 104 { 105 } 106 107 //------------------------------------------------------------------ 108 OGroupComp::OGroupComp(const OGroupComp& _rSource) 109 :m_aName( _rSource.m_aName ) 110 ,m_xComponent( _rSource.m_xComponent ) 111 ,m_xControlModel(_rSource.m_xControlModel) 112 ,m_nPos( _rSource.m_nPos ) 113 ,m_nTabIndex( _rSource.m_nTabIndex ) 114 { 115 } 116 117 //------------------------------------------------------------------ 118 OGroupComp::OGroupComp(const Reference<XPropertySet>& rxSet, sal_Int32 nInsertPos ) 119 :m_xComponent( rxSet ) 120 ,m_xControlModel(rxSet,UNO_QUERY) 121 ,m_nPos( nInsertPos ) 122 ,m_nTabIndex(0) 123 { 124 if (m_xComponent.is()) 125 { 126 if (hasProperty( PROPERTY_TABINDEX, m_xComponent ) ) 127 // Indices kleiner 0 werden wie 0 behandelt 128 m_nTabIndex = Max(getINT16(m_xComponent->getPropertyValue( PROPERTY_TABINDEX )) , sal_Int16(0)); 129 130 m_xComponent->getPropertyValue( PROPERTY_NAME ) >>= m_aName; 131 } 132 } 133 134 //------------------------------------------------------------------ 135 sal_Bool OGroupComp::operator==( const OGroupComp& rComp ) const 136 { 137 return m_nTabIndex == rComp.GetTabIndex() && m_nPos == rComp.GetPos(); 138 } 139 140 //------------------------------------------------------------------ 141 class OGroupCompLess : public ::std::binary_function<OGroupComp, OGroupComp, sal_Bool> 142 { 143 public: 144 sal_Bool operator() (const OGroupComp& lhs, const OGroupComp& rhs) const 145 { 146 sal_Bool bResult; 147 // TabIndex von 0 wird hinten einsortiert 148 if (lhs.m_nTabIndex == rhs.GetTabIndex()) 149 bResult = lhs.m_nPos < rhs.GetPos(); 150 else if (lhs.m_nTabIndex && rhs.GetTabIndex()) 151 bResult = lhs.m_nTabIndex < rhs.GetTabIndex(); 152 else 153 bResult = lhs.m_nTabIndex != 0; 154 return bResult; 155 } 156 }; 157 158 //======================================================================== 159 // class OGroup 160 //======================================================================== 161 162 DBG_NAME(OGroup) 163 //------------------------------------------------------------------ 164 OGroup::OGroup( const ::rtl::OUString& rGroupName ) 165 :m_aGroupName( rGroupName ) 166 ,m_nInsertPos(0) 167 { 168 DBG_CTOR(OGroup,NULL); 169 } 170 171 #ifdef DBG_UTIL 172 //------------------------------------------------------------------ 173 OGroup::OGroup( const OGroup& _rSource ) 174 :m_aCompArray(_rSource.m_aCompArray) 175 ,m_aCompAccArray(_rSource.m_aCompAccArray) 176 ,m_aGroupName(_rSource.m_aGroupName) 177 ,m_nInsertPos(_rSource.m_nInsertPos) 178 { 179 DBG_CTOR(OGroup,NULL); 180 } 181 #endif 182 183 //------------------------------------------------------------------ 184 OGroup::~OGroup() 185 { 186 DBG_DTOR(OGroup,NULL); 187 } 188 189 //------------------------------------------------------------------ 190 void OGroup::InsertComponent( const Reference<XPropertySet>& xSet ) 191 { 192 OGroupComp aNewGroupComp( xSet, m_nInsertPos ); 193 sal_Int32 nPosInserted = insert_sorted(m_aCompArray, aNewGroupComp, OGroupCompLess()); 194 195 OGroupCompAcc aNewGroupCompAcc( xSet, m_aCompArray[nPosInserted] ); 196 insert_sorted(m_aCompAccArray, aNewGroupCompAcc, OGroupCompAccLess()); 197 m_nInsertPos++; 198 } 199 200 //------------------------------------------------------------------ 201 void OGroup::RemoveComponent( const Reference<XPropertySet>& rxElement ) 202 { 203 sal_Int32 nGroupCompAccPos; 204 OGroupCompAcc aSearchCompAcc( rxElement, OGroupComp() ); 205 if ( seek_entry(m_aCompAccArray, aSearchCompAcc, nGroupCompAccPos, OGroupCompAccLess()) ) 206 { 207 OGroupCompAcc& aGroupCompAcc = m_aCompAccArray[nGroupCompAccPos]; 208 const OGroupComp& aGroupComp = aGroupCompAcc.GetGroupComponent(); 209 210 sal_Int32 nGroupCompPos; 211 if ( seek_entry(m_aCompArray, aGroupComp, nGroupCompPos, OGroupCompLess()) ) 212 { 213 m_aCompAccArray.erase( m_aCompAccArray.begin() + nGroupCompAccPos ); 214 m_aCompArray.erase( m_aCompArray.begin() + nGroupCompPos ); 215 216 /*============================================================ 217 Durch das Entfernen der GroupComp ist die Einfuegeposition 218 ungueltig geworden. Sie braucht hier aber nicht angepasst werden, 219 da sie fortlaufend vergeben wird und damit immer 220 aufsteigend eindeutig ist. 221 ============================================================*/ 222 } 223 else 224 { 225 DBG_ERROR( "OGroup::RemoveComponent: Component nicht in Gruppe" ); 226 } 227 } 228 else 229 { 230 DBG_ERROR( "OGroup::RemoveComponent: Component nicht in Gruppe" ); 231 } 232 } 233 234 //------------------------------------------------------------------ 235 sal_Bool OGroup::operator==( const OGroup& rGroup ) const 236 { 237 return m_aGroupName.equals(rGroup.GetGroupName()); 238 } 239 240 //------------------------------------------------------------------ 241 class OGroupLess : public ::std::binary_function<OGroup, OGroup, sal_Bool> 242 { 243 public: 244 sal_Bool operator() (const OGroup& lhs, const OGroup& rhs) const 245 { 246 return lhs.m_aGroupName < rhs.m_aGroupName; 247 } 248 }; 249 250 //------------------------------------------------------------------ 251 Sequence< Reference<XControlModel> > OGroup::GetControlModels() const 252 { 253 sal_Int32 nLen = m_aCompArray.size(); 254 Sequence<Reference<XControlModel> > aControlModelSeq( nLen ); 255 Reference<XControlModel>* pModels = aControlModelSeq.getArray(); 256 257 ConstOGroupCompArrIterator aGroupComps = m_aCompArray.begin(); 258 for (sal_Int32 i = 0; i < nLen; ++i, ++pModels, ++aGroupComps) 259 { 260 *pModels = aGroupComps->GetControlModel(); 261 } 262 return aControlModelSeq; 263 } 264 265 DBG_NAME(OGroupManager); 266 //------------------------------------------------------------------ 267 OGroupManager::OGroupManager(const Reference< XContainer >& _rxContainer) 268 :m_pCompGroup( new OGroup( ::rtl::OUString::createFromAscii( "AllComponentGroup" ) ) ) 269 ,m_xContainer(_rxContainer) 270 { 271 DBG_CTOR(OGroupManager,NULL); 272 273 increment(m_refCount); 274 { 275 _rxContainer->addContainerListener(this); 276 } 277 decrement(m_refCount); 278 } 279 280 //------------------------------------------------------------------ 281 OGroupManager::~OGroupManager() 282 { 283 DBG_DTOR(OGroupManager,NULL); 284 // Alle Components und CompGroup loeschen 285 delete m_pCompGroup; 286 } 287 288 // XPropertyChangeListener 289 //------------------------------------------------------------------ 290 void OGroupManager::disposing(const EventObject& evt) throw( RuntimeException ) 291 { 292 Reference<XContainer> xContainer(evt.Source, UNO_QUERY); 293 if (xContainer.get() == m_xContainer.get()) 294 { 295 DELETEZ(m_pCompGroup); 296 297 //////////////////////////////////////////////////////////////// 298 // Gruppen loeschen 299 m_aGroupArr.clear(); 300 m_xContainer.clear(); 301 } 302 } 303 // ----------------------------------------------------------------------------- 304 void OGroupManager::removeFromGroupMap(const ::rtl::OUString& _sGroupName,const Reference<XPropertySet>& _xSet) 305 { 306 // Component aus CompGroup entfernen 307 m_pCompGroup->RemoveComponent( _xSet ); 308 309 OGroupArr::iterator aFind = m_aGroupArr.find(_sGroupName); 310 311 if ( aFind != m_aGroupArr.end() ) 312 { 313 // Gruppe vorhanden 314 aFind->second.RemoveComponent( _xSet ); 315 316 // Wenn Anzahl der Gruppenelemente == 1 ist, Gruppe deaktivieren 317 if ( aFind->second.Count() == 1 ) 318 { 319 OActiveGroups::iterator aActiveFind = ::std::find( 320 m_aActiveGroupMap.begin(), 321 m_aActiveGroupMap.end(), 322 aFind 323 ); 324 if ( aActiveFind != m_aActiveGroupMap.end() ) 325 { 326 // the group is active. Deactivate it if the remaining component 327 // is *no* radio button 328 if ( !isRadioButton( aFind->second.GetObject( 0 ) ) ) 329 m_aActiveGroupMap.erase( aActiveFind ); 330 } 331 } 332 } 333 334 335 // Bei Component als PropertyChangeListener abmelden 336 _xSet->removePropertyChangeListener( PROPERTY_NAME, this ); 337 if (hasProperty(PROPERTY_TABINDEX, _xSet)) 338 _xSet->removePropertyChangeListener( PROPERTY_TABINDEX, this ); 339 } 340 //------------------------------------------------------------------ 341 void SAL_CALL OGroupManager::propertyChange(const PropertyChangeEvent& evt) throw ( ::com::sun::star::uno::RuntimeException) 342 { 343 Reference<XPropertySet> xSet(evt.Source, UNO_QUERY); 344 345 // Component aus Gruppe entfernen 346 ::rtl::OUString sGroupName; 347 if (evt.PropertyName == PROPERTY_NAME) 348 evt.OldValue >>= sGroupName; 349 else 350 xSet->getPropertyValue( PROPERTY_NAME ) >>= sGroupName; 351 352 removeFromGroupMap(sGroupName,xSet); 353 354 // Component neu einordnen 355 InsertElement( xSet ); 356 } 357 358 // XContainerListener 359 //------------------------------------------------------------------ 360 void SAL_CALL OGroupManager::elementInserted(const ContainerEvent& Event) throw ( ::com::sun::star::uno::RuntimeException) 361 { 362 Reference< XPropertySet > xProps; 363 Event.Element >>= xProps; 364 if ( xProps.is() ) 365 InsertElement( xProps ); 366 } 367 368 //------------------------------------------------------------------ 369 void SAL_CALL OGroupManager::elementRemoved(const ContainerEvent& Event) throw ( ::com::sun::star::uno::RuntimeException) 370 { 371 Reference<XPropertySet> xProps; 372 Event.Element >>= xProps; 373 if ( xProps.is() ) 374 RemoveElement( xProps ); 375 } 376 377 //------------------------------------------------------------------ 378 void SAL_CALL OGroupManager::elementReplaced(const ContainerEvent& Event) throw ( ::com::sun::star::uno::RuntimeException) 379 { 380 Reference<XPropertySet> xProps; 381 Event.ReplacedElement >>= xProps; 382 if ( xProps.is() ) 383 RemoveElement( xProps ); 384 385 xProps.clear(); 386 Event.Element >>= xProps; 387 if ( xProps.is() ) 388 InsertElement( xProps ); 389 } 390 391 // Other functions 392 //------------------------------------------------------------------ 393 Sequence<Reference<XControlModel> > OGroupManager::getControlModels() 394 { 395 return m_pCompGroup->GetControlModels(); 396 } 397 398 //------------------------------------------------------------------ 399 sal_Int32 OGroupManager::getGroupCount() 400 { 401 return m_aActiveGroupMap.size(); 402 } 403 404 //------------------------------------------------------------------ 405 void OGroupManager::getGroup(sal_Int32 nGroup, Sequence< Reference<XControlModel> >& _rGroup, ::rtl::OUString& _rName) 406 { 407 OSL_ENSURE(nGroup >= 0 && (size_t)nGroup < m_aActiveGroupMap.size(),"OGroupManager::getGroup: Invalid group index!"); 408 OGroupArr::iterator aGroupPos = m_aActiveGroupMap[nGroup]; 409 _rName = aGroupPos->second.GetGroupName(); 410 _rGroup = aGroupPos->second.GetControlModels(); 411 } 412 413 //------------------------------------------------------------------ 414 void OGroupManager::getGroupByName(const ::rtl::OUString& _rName, Sequence< Reference<XControlModel> >& _rGroup) 415 { 416 OGroupArr::iterator aFind = m_aGroupArr.find(_rName); 417 if ( aFind != m_aGroupArr.end() ) 418 _rGroup = aFind->second.GetControlModels(); 419 } 420 421 //------------------------------------------------------------------ 422 void OGroupManager::InsertElement( const Reference<XPropertySet>& xSet ) 423 { 424 // Nur ControlModels 425 Reference<XControlModel> xControl(xSet, UNO_QUERY); 426 if (!xControl.is() ) 427 return; 428 429 // Component in CompGroup aufnehmen 430 m_pCompGroup->InsertComponent( xSet ); 431 432 // Component in Gruppe aufnehmen 433 ::rtl::OUString sGroupName; 434 xSet->getPropertyValue( PROPERTY_NAME ) >>= sGroupName; 435 436 OGroupArr::iterator aFind = m_aGroupArr.find(sGroupName); 437 438 if ( aFind == m_aGroupArr.end() ) 439 { 440 aFind = m_aGroupArr.insert(OGroupArr::value_type(sGroupName,OGroup(sGroupName))).first; 441 } 442 443 aFind->second.InsertComponent( xSet ); 444 445 // if we have at least 2 elements in the group, then this is an "active group" 446 bool bActivateGroup = aFind->second.Count() == 2; 447 448 // Additionally, if the component is a radio button, then it's group becomes active, 449 // too. With this, we ensure that in a container with n radio buttons which all are 450 // in different groups the selection still works reliably (means that all radios can be 451 // clicked independently) 452 if ( aFind->second.Count() == 1 ) 453 { 454 if ( isRadioButton( xSet ) ) 455 bActivateGroup = true; 456 } 457 458 if ( bActivateGroup ) 459 { 460 OActiveGroups::iterator aAlreadyExistent = ::std::find( 461 m_aActiveGroupMap.begin(), 462 m_aActiveGroupMap.end(), 463 aFind 464 ); 465 if ( aAlreadyExistent == m_aActiveGroupMap.end() ) 466 m_aActiveGroupMap.push_back( aFind ); 467 } 468 469 470 // Bei Component als PropertyChangeListener anmelden 471 xSet->addPropertyChangeListener( PROPERTY_NAME, this ); 472 473 // Tabindex muss nicht jeder unterstuetzen 474 if (hasProperty(PROPERTY_TABINDEX, xSet)) 475 xSet->addPropertyChangeListener( PROPERTY_TABINDEX, this ); 476 477 } 478 479 //------------------------------------------------------------------ 480 void OGroupManager::RemoveElement( const Reference<XPropertySet>& xSet ) 481 { 482 // Nur ControlModels 483 Reference<XControlModel> xControl(xSet, UNO_QUERY); 484 if (!xControl.is() ) 485 return; 486 487 // Component aus Gruppe entfernen 488 ::rtl::OUString sGroupName; 489 xSet->getPropertyValue( PROPERTY_NAME ) >>= sGroupName; 490 491 removeFromGroupMap(sGroupName,xSet); 492 } 493 494 //......................................................................... 495 } // namespace frm 496 //......................................................................... 497 498