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