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