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_toolkit.hxx" 30 #include <com/sun/star/beans/XPropertySet.hpp> 31 #include <com/sun/star/awt/XVclContainerPeer.hpp> 32 33 #include <toolkit/controls/stdtabcontroller.hxx> 34 #include <toolkit/controls/stdtabcontrollermodel.hxx> 35 #include <toolkit/awt/vclxwindow.hxx> 36 #include <toolkit/helper/macros.hxx> 37 #include <cppuhelper/typeprovider.hxx> 38 #include <rtl/memory.h> 39 #include <rtl/uuid.h> 40 41 #include <tools/debug.hxx> 42 #include <vcl/window.hxx> 43 #include <comphelper/sequence.hxx> 44 45 using namespace ::com::sun::star; 46 using namespace ::com::sun::star::uno; 47 using namespace ::com::sun::star::awt; 48 using namespace ::com::sun::star::lang; 49 using namespace ::com::sun::star::beans; 50 51 // ---------------------------------------------------- 52 // class StdTabController 53 // ---------------------------------------------------- 54 StdTabController::StdTabController() 55 { 56 } 57 58 StdTabController::~StdTabController() 59 { 60 } 61 62 sal_Bool StdTabController::ImplCreateComponentSequence( 63 Sequence< Reference< XControl > >& rControls, 64 const Sequence< Reference< XControlModel > >& rModels, 65 Sequence< Reference< XWindow > >& rComponents, 66 Sequence< Any>* pTabStops, 67 sal_Bool bPeerComponent ) const 68 { 69 sal_Bool bOK = sal_True; 70 71 // nur die wirklich geforderten Controls 72 sal_Int32 nModels = rModels.getLength(); 73 if (nModels != rControls.getLength()) 74 { 75 Sequence< Reference< XControl > > aSeq( nModels ); 76 const Reference< XControlModel >* pModels = rModels.getConstArray(); 77 Reference< XControl > xCurrentControl; 78 79 sal_Int32 nRealControls = 0; 80 for (sal_Int32 n = 0; n < nModels; ++n, ++pModels) 81 { 82 xCurrentControl = FindControl(rControls, *pModels); 83 if (xCurrentControl.is()) 84 aSeq.getArray()[nRealControls++] = xCurrentControl; 85 } 86 aSeq.realloc(nRealControls); 87 rControls = aSeq; 88 } 89 #ifdef DBG_UTIL 90 DBG_ASSERT( rControls.getLength() <= rModels.getLength(), "StdTabController:ImplCreateComponentSequence: inconsistence!" ); 91 // there may be less controls than models, but never more controls than models 92 #endif 93 94 95 const Reference< XControl > * pControls = rControls.getConstArray(); 96 sal_uInt32 nCtrls = rControls.getLength(); 97 rComponents.realloc( nCtrls ); 98 Reference< XWindow > * pComps = rComponents.getArray(); 99 Any* pTabs = NULL; 100 101 102 if ( pTabStops ) 103 { 104 *pTabStops = Sequence< Any>( nCtrls ); 105 pTabs = pTabStops->getArray(); 106 } 107 108 for ( sal_uInt32 n = 0; bOK && ( n < nCtrls ); n++ ) 109 { 110 // Zum Model passendes Control suchen 111 Reference< XControl > xCtrl(pControls[n]); 112 if ( xCtrl.is() ) 113 { 114 if (bPeerComponent) 115 pComps[n] = Reference< XWindow > (xCtrl->getPeer(), UNO_QUERY); 116 else 117 pComps[n] = Reference< XWindow > (xCtrl, UNO_QUERY); 118 119 // TabStop-Property 120 if ( pTabs ) 121 { 122 // opt: String fuer TabStop als Konstante 123 static const ::rtl::OUString aTabStopName( ::rtl::OUString::createFromAscii( "Tabstop" ) ); 124 125 Reference< XPropertySet > xPSet( xCtrl->getModel(), UNO_QUERY ); 126 Reference< XPropertySetInfo > xInfo = xPSet->getPropertySetInfo(); 127 if( xInfo->hasPropertyByName( aTabStopName ) ) 128 *pTabs++ = xPSet->getPropertyValue( aTabStopName ); 129 else 130 ++pTabs; 131 } 132 } 133 else 134 { 135 DBG_TRACE( "ImplCreateComponentSequence: Control not found" ); 136 bOK = sal_False; 137 } 138 } 139 return bOK; 140 } 141 142 void StdTabController::ImplActivateControl( sal_Bool bFirst ) const 143 { 144 // HACK wegen #53688#, muss auf ein Interface abgebildet werden, wenn Controls Remote liegen koennen. 145 Reference< XTabController > xTabController(const_cast< ::cppu::OWeakObject* >(static_cast< const ::cppu::OWeakObject* >(this)), UNO_QUERY); 146 Sequence< Reference< XControl > > aCtrls = xTabController->getControls(); 147 const Reference< XControl > * pControls = aCtrls.getConstArray(); 148 sal_uInt32 nCount = aCtrls.getLength(); 149 150 for ( sal_uInt32 n = bFirst ? 0 : nCount; bFirst ? ( n < nCount ) : n; ) 151 { 152 sal_uInt32 nCtrl = bFirst ? n++ : --n; 153 DBG_ASSERT( pControls[nCtrl].is(), "Control nicht im Container!" ); 154 if ( pControls[nCtrl].is() ) 155 { 156 Reference< XWindowPeer > xCP = pControls[nCtrl]->getPeer(); 157 if ( xCP.is() ) 158 { 159 VCLXWindow* pC = VCLXWindow::GetImplementation( xCP ); 160 if ( pC && pC->GetWindow() && ( pC->GetWindow()->GetStyle() & WB_TABSTOP ) ) 161 { 162 pC->GetWindow()->GrabFocus(); 163 break; 164 } 165 } 166 } 167 } 168 } 169 170 // XInterface 171 Any StdTabController::queryAggregation( const Type & rType ) throw(RuntimeException) 172 { 173 Any aRet = ::cppu::queryInterface( rType, 174 SAL_STATIC_CAST( XTabController*, this ), 175 SAL_STATIC_CAST( XServiceInfo*, this ), 176 SAL_STATIC_CAST( XTypeProvider*, this ) ); 177 return (aRet.hasValue() ? aRet : OWeakAggObject::queryAggregation( rType )); 178 } 179 180 // XTypeProvider 181 IMPL_XTYPEPROVIDER_START( StdTabController ) 182 getCppuType( ( Reference< XTabController>* ) NULL ), 183 getCppuType( ( Reference< XServiceInfo>* ) NULL ) 184 IMPL_XTYPEPROVIDER_END 185 186 void StdTabController::setModel( const Reference< XTabControllerModel >& Model ) throw(RuntimeException) 187 { 188 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); 189 190 mxModel = Model; 191 } 192 193 Reference< XTabControllerModel > StdTabController::getModel( ) throw(RuntimeException) 194 { 195 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); 196 197 return mxModel; 198 } 199 200 void StdTabController::setContainer( const Reference< XControlContainer >& Container ) throw(RuntimeException) 201 { 202 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); 203 204 mxControlContainer = Container; 205 } 206 207 Reference< XControlContainer > StdTabController::getContainer( ) throw(RuntimeException) 208 { 209 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); 210 211 return mxControlContainer; 212 } 213 214 Sequence< Reference< XControl > > StdTabController::getControls( ) throw(RuntimeException) 215 { 216 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); 217 218 Sequence< Reference< XControl > > aSeq; 219 220 if ( mxControlContainer.is() ) 221 { 222 Sequence< Reference< XControlModel > > aModels = mxModel->getControlModels(); 223 const Reference< XControlModel > * pModels = aModels.getConstArray(); 224 225 Sequence< Reference< XControl > > xCtrls = mxControlContainer->getControls(); 226 227 sal_uInt32 nCtrls = aModels.getLength(); 228 aSeq = Sequence< Reference< XControl > >( nCtrls ); 229 for ( sal_uInt32 n = 0; n < nCtrls; n++ ) 230 { 231 Reference< XControlModel > xCtrlModel = pModels[n]; 232 // Zum Model passendes Control suchen 233 Reference< XControl > xCtrl = FindControl( xCtrls, xCtrlModel ); 234 aSeq.getArray()[n] = xCtrl; 235 } 236 } 237 return aSeq; 238 } 239 240 void StdTabController::autoTabOrder( ) throw(RuntimeException) 241 { 242 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); 243 244 DBG_ASSERT( mxControlContainer.is(), "autoTabOrder: No ControlContainer!" ); 245 if ( !mxControlContainer.is() ) 246 return; 247 248 Sequence< Reference< XControlModel > > aSeq = mxModel->getControlModels(); 249 Sequence< Reference< XWindow > > aCompSeq; 250 251 // vieleicht erhalte ich hier einen TabController, 252 // der schneller die Liste meiner Controls ermittelt 253 Reference< XTabController > xTabController(static_cast< ::cppu::OWeakObject* >(this), UNO_QUERY); 254 Sequence< Reference< XControl > > aControls = xTabController->getControls(); 255 256 // #58317# Es sind ggf. noch nicht alle Controls fuer die Models im Container, 257 // dann kommt spaeter nochmal ein autoTabOrder... 258 if( !ImplCreateComponentSequence( aControls, aSeq, aCompSeq, NULL, sal_False ) ) 259 return; 260 261 sal_uInt32 nCtrls = aCompSeq.getLength(); 262 Reference< XWindow > * pComponents = aCompSeq.getArray(); 263 264 ComponentEntryList aCtrls; 265 sal_uInt32 n; 266 for ( n = 0; n < nCtrls; n++ ) 267 { 268 XWindow* pC = (XWindow*)pComponents[n].get(); 269 ComponentEntry* pE = new ComponentEntry; 270 pE->pComponent = pC; 271 awt::Rectangle aPosSize = pC->getPosSize(); 272 pE->aPos.X() = aPosSize.X; 273 pE->aPos.Y() = aPosSize.Y; 274 275 sal_uInt16 nPos; 276 for ( nPos = 0; nPos < aCtrls.Count(); nPos++ ) 277 { 278 ComponentEntry* pEntry = aCtrls.GetObject( nPos ); 279 if ( pEntry->aPos.Y() >= pE->aPos.Y() ) 280 { 281 while ( pEntry && ( pEntry->aPos.Y() == pE->aPos.Y() ) 282 && ( pEntry->aPos.X() < pE->aPos.X() ) ) 283 { 284 pEntry = aCtrls.GetObject( ++nPos ); 285 } 286 break; 287 } 288 } 289 aCtrls.Insert( pE, nPos ); 290 } 291 292 Sequence< Reference< XControlModel > > aNewSeq( nCtrls ); 293 for ( n = 0; n < nCtrls; n++ ) 294 { 295 ComponentEntry* pE = aCtrls.GetObject( n ); 296 Reference< XControl > xUC( pE->pComponent, UNO_QUERY ); 297 aNewSeq.getArray()[n] = xUC->getModel(); 298 delete pE; 299 } 300 aCtrls.Clear(); 301 302 mxModel->setControlModels( aNewSeq ); 303 } 304 305 void StdTabController::activateTabOrder( ) throw(RuntimeException) 306 { 307 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); 308 309 // Am Container die Tab-Reihenfolge aktivieren... 310 311 Reference< XControl > xC( mxControlContainer, UNO_QUERY ); 312 Reference< XVclContainerPeer > xVclContainerPeer; 313 if ( xC.is() ) 314 xVclContainerPeer = xVclContainerPeer.query( xC->getPeer() ); 315 if ( !xC.is() || !xVclContainerPeer.is() ) 316 return; 317 318 // vieleicht erhalte ich hier einen TabController, 319 // der schneller die Liste meiner Controls ermittelt 320 Reference< XTabController > xTabController(static_cast< ::cppu::OWeakObject* >(this), UNO_QUERY); 321 322 // Flache Liste besorgen... 323 Sequence< Reference< XControlModel > > aModels = mxModel->getControlModels(); 324 Sequence< Reference< XWindow > > aCompSeq; 325 Sequence< Any> aTabSeq; 326 327 // DG: Aus Optimierungsgruenden werden die Controls mittels getControls() geholt, 328 // dieses hoert sich zwar wiedersinning an, fuehrt aber im konkreten Fall (Forms) zu sichtbaren 329 // Geschwindigkeitsvorteilen 330 Sequence< Reference< XControl > > aControls = xTabController->getControls(); 331 332 // #58317# Es sind ggf. noch nicht alle Controls fuer die Models im Container, 333 // dann kommt spaeter nochmal ein activateTabOrder... 334 if( !ImplCreateComponentSequence( aControls, aModels, aCompSeq, &aTabSeq, sal_True ) ) 335 return; 336 337 xVclContainerPeer->setTabOrder( aCompSeq, aTabSeq, mxModel->getGroupControl() ); 338 339 ::rtl::OUString aName; 340 Sequence< Reference< XControlModel > > aThisGroupModels; 341 Sequence< Reference< XWindow > > aControlComponents; 342 343 sal_uInt32 nGroups = mxModel->getGroupCount(); 344 for ( sal_uInt32 nG = 0; nG < nGroups; nG++ ) 345 { 346 mxModel->getGroup( nG, aThisGroupModels, aName ); 347 348 aControls = xTabController->getControls(); 349 // ImplCreateComponentSequence has a really strange semantics regarding it's first parameter: 350 // upon method entry, it expects a super set of the controls which it returns 351 // this means we need to completely fill this sequence with all available controls before 352 // calling into ImplCreateComponentSequence 353 354 aControlComponents.realloc( 0 ); 355 356 ImplCreateComponentSequence( aControls, aThisGroupModels, aControlComponents, NULL, sal_True ); 357 xVclContainerPeer->setGroup( aControlComponents ); 358 } 359 } 360 361 void StdTabController::activateFirst( ) throw(RuntimeException) 362 { 363 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); 364 365 ImplActivateControl( sal_True ); 366 } 367 368 void StdTabController::activateLast( ) throw(RuntimeException) 369 { 370 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() ); 371 372 ImplActivateControl( sal_False ); 373 } 374 375 376 Reference< XControl > StdTabController::FindControl( Sequence< Reference< XControl > >& rCtrls, 377 const Reference< XControlModel > & rxCtrlModel ) 378 { 379 380 /* 381 // MT: Funktioniert nicht mehr, weil ich nicht mehr bei mir angemeldet bin, 382 // weil DG das abfaengt. 383 384 // #54677# Beim Laden eines HTML-Dokuments wird nach jedem Control ein 385 // activateTabOrder gerufen und jede Menge Zeit in dieser Methode verbraten. 386 // Die Anzahl dieser Schleifendurchlaufe steigt quadratisch, also versuchen 387 // das Control direkt vom Model zu erhalten. 388 // => Wenn genau ein Control als PropertyChangeListener angemeldet ist, 389 // dann muss das auch das richtige sein. 390 391 UnoControlModel* pUnoCtrlModel = UnoControlModel::GetImplementation( rxCtrlModel ); 392 393 394 if ( pUnoCtrlModel ) 395 { 396 ListenerIterator aIt( pUnoCtrlModel->maPropertiesListeners ); 397 while( aIt.hasMoreElements() ) 398 { 399 XEventListener* pL = aIt.next(); 400 Reference< XControl > xC( pL, UNO_QUERY ); 401 if ( xC.is() ) 402 { 403 if( xC->getContext() == mxControlContainer ) 404 { 405 xCtrl = xC; 406 break; 407 } 408 } 409 } 410 } 411 if ( !xCtrl.is() && rxCtrlModel.is()) 412 */ 413 DBG_ASSERT( rxCtrlModel.is(), "ImplFindControl - welches ?!" ); 414 415 const Reference< XControl > * pCtrls = rCtrls.getConstArray(); 416 sal_Int32 nCtrls = rCtrls.getLength(); 417 for ( sal_Int32 n = 0; n < nCtrls; n++ ) 418 { 419 Reference< XControlModel > xModel(pCtrls[n].is() ? pCtrls[n]->getModel() : Reference< XControlModel > ()); 420 if ( (XControlModel*)xModel.get() == (XControlModel*)rxCtrlModel.get() ) 421 { 422 Reference< XControl > xCtrl( pCtrls[n] ); 423 ::comphelper::removeElementAt( rCtrls, n ); 424 return xCtrl; 425 } 426 } 427 return Reference< XControl > (); 428 } 429