merge the formfield patch from ooo-build
[ooovba.git] / toolkit / source / controls / stdtabcontroller.cxx
blobc1ef864a74f30a1e2a6f876557f4c0bd72fd88c5
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: stdtabcontroller.cxx,v $
10 * $Revision: 1.12 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_toolkit.hxx"
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/awt/XVclContainerPeer.hpp>
36 #include <toolkit/controls/stdtabcontroller.hxx>
37 #include <toolkit/controls/stdtabcontrollermodel.hxx>
38 #include <toolkit/awt/vclxwindow.hxx>
39 #include <toolkit/helper/macros.hxx>
40 #include <cppuhelper/typeprovider.hxx>
41 #include <rtl/memory.h>
42 #include <rtl/uuid.h>
44 #include <tools/debug.hxx>
45 #include <vcl/window.hxx>
46 #include <comphelper/sequence.hxx>
48 using namespace ::com::sun::star;
49 using namespace ::com::sun::star::uno;
50 using namespace ::com::sun::star::awt;
51 using namespace ::com::sun::star::lang;
52 using namespace ::com::sun::star::beans;
54 // ----------------------------------------------------
55 // class StdTabController
56 // ----------------------------------------------------
57 StdTabController::StdTabController()
61 StdTabController::~StdTabController()
65 sal_Bool StdTabController::ImplCreateComponentSequence(
66 Sequence< Reference< XControl > >& rControls,
67 const Sequence< Reference< XControlModel > >& rModels,
68 Sequence< Reference< XWindow > >& rComponents,
69 Sequence< Any>* pTabStops,
70 sal_Bool bPeerComponent ) const
72 sal_Bool bOK = sal_True;
74 // nur die wirklich geforderten Controls
75 sal_Int32 nModels = rModels.getLength();
76 if (nModels != rControls.getLength())
78 Sequence< Reference< XControl > > aSeq( nModels );
79 const Reference< XControlModel >* pModels = rModels.getConstArray();
80 Reference< XControl > xCurrentControl;
82 sal_Int32 nRealControls = 0;
83 for (sal_Int32 n = 0; n < nModels; ++n, ++pModels)
85 xCurrentControl = FindControl(rControls, *pModels);
86 if (xCurrentControl.is())
87 aSeq.getArray()[nRealControls++] = xCurrentControl;
89 aSeq.realloc(nRealControls);
90 rControls = aSeq;
92 #ifdef DBG_UTIL
93 DBG_ASSERT( rControls.getLength() <= rModels.getLength(), "StdTabController:ImplCreateComponentSequence: inconsistence!" );
94 // there may be less controls than models, but never more controls than models
95 #endif
98 const Reference< XControl > * pControls = rControls.getConstArray();
99 sal_uInt32 nCtrls = rControls.getLength();
100 rComponents.realloc( nCtrls );
101 Reference< XWindow > * pComps = rComponents.getArray();
102 Any* pTabs = NULL;
105 if ( pTabStops )
107 *pTabStops = Sequence< Any>( nCtrls );
108 pTabs = pTabStops->getArray();
111 for ( sal_uInt32 n = 0; bOK && ( n < nCtrls ); n++ )
113 // Zum Model passendes Control suchen
114 Reference< XControl > xCtrl(pControls[n]);
115 if ( xCtrl.is() )
117 if (bPeerComponent)
118 pComps[n] = Reference< XWindow > (xCtrl->getPeer(), UNO_QUERY);
119 else
120 pComps[n] = Reference< XWindow > (xCtrl, UNO_QUERY);
122 // TabStop-Property
123 if ( pTabs )
125 // opt: String fuer TabStop als Konstante
126 static const ::rtl::OUString aTabStopName( ::rtl::OUString::createFromAscii( "Tabstop" ) );
128 Reference< XPropertySet > xPSet( xCtrl->getModel(), UNO_QUERY );
129 Reference< XPropertySetInfo > xInfo = xPSet->getPropertySetInfo();
130 if( xInfo->hasPropertyByName( aTabStopName ) )
131 *pTabs++ = xPSet->getPropertyValue( aTabStopName );
132 else
133 ++pTabs;
136 else
138 DBG_TRACE( "ImplCreateComponentSequence: Control not found" );
139 bOK = sal_False;
142 return bOK;
145 void StdTabController::ImplActivateControl( sal_Bool bFirst ) const
147 // HACK wegen #53688#, muss auf ein Interface abgebildet werden, wenn Controls Remote liegen koennen.
148 Reference< XTabController > xTabController(const_cast< ::cppu::OWeakObject* >(static_cast< const ::cppu::OWeakObject* >(this)), UNO_QUERY);
149 Sequence< Reference< XControl > > aCtrls = xTabController->getControls();
150 const Reference< XControl > * pControls = aCtrls.getConstArray();
151 sal_uInt32 nCount = aCtrls.getLength();
153 for ( sal_uInt32 n = bFirst ? 0 : nCount; bFirst ? ( n < nCount ) : n; )
155 sal_uInt32 nCtrl = bFirst ? n++ : --n;
156 DBG_ASSERT( pControls[nCtrl].is(), "Control nicht im Container!" );
157 if ( pControls[nCtrl].is() )
159 Reference< XWindowPeer > xCP = pControls[nCtrl]->getPeer();
160 if ( xCP.is() )
162 VCLXWindow* pC = VCLXWindow::GetImplementation( xCP );
163 if ( pC && pC->GetWindow() && ( pC->GetWindow()->GetStyle() & WB_TABSTOP ) )
165 pC->GetWindow()->GrabFocus();
166 break;
173 // XInterface
174 Any StdTabController::queryAggregation( const Type & rType ) throw(RuntimeException)
176 Any aRet = ::cppu::queryInterface( rType,
177 SAL_STATIC_CAST( XTabController*, this ),
178 SAL_STATIC_CAST( XServiceInfo*, this ),
179 SAL_STATIC_CAST( XTypeProvider*, this ) );
180 return (aRet.hasValue() ? aRet : OWeakAggObject::queryAggregation( rType ));
183 // XTypeProvider
184 IMPL_XTYPEPROVIDER_START( StdTabController )
185 getCppuType( ( Reference< XTabController>* ) NULL ),
186 getCppuType( ( Reference< XServiceInfo>* ) NULL )
187 IMPL_XTYPEPROVIDER_END
189 void StdTabController::setModel( const Reference< XTabControllerModel >& Model ) throw(RuntimeException)
191 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
193 mxModel = Model;
196 Reference< XTabControllerModel > StdTabController::getModel( ) throw(RuntimeException)
198 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
200 return mxModel;
203 void StdTabController::setContainer( const Reference< XControlContainer >& Container ) throw(RuntimeException)
205 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
207 mxControlContainer = Container;
210 Reference< XControlContainer > StdTabController::getContainer( ) throw(RuntimeException)
212 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
214 return mxControlContainer;
217 Sequence< Reference< XControl > > StdTabController::getControls( ) throw(RuntimeException)
219 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
221 Sequence< Reference< XControl > > aSeq;
223 if ( mxControlContainer.is() )
225 Sequence< Reference< XControlModel > > aModels = mxModel->getControlModels();
226 const Reference< XControlModel > * pModels = aModels.getConstArray();
228 Sequence< Reference< XControl > > xCtrls = mxControlContainer->getControls();
230 sal_uInt32 nCtrls = aModels.getLength();
231 aSeq = Sequence< Reference< XControl > >( nCtrls );
232 for ( sal_uInt32 n = 0; n < nCtrls; n++ )
234 Reference< XControlModel > xCtrlModel = pModels[n];
235 // Zum Model passendes Control suchen
236 Reference< XControl > xCtrl = FindControl( xCtrls, xCtrlModel );
237 aSeq.getArray()[n] = xCtrl;
240 return aSeq;
243 void StdTabController::autoTabOrder( ) throw(RuntimeException)
245 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
247 DBG_ASSERT( mxControlContainer.is(), "autoTabOrder: No ControlContainer!" );
248 if ( !mxControlContainer.is() )
249 return;
251 Sequence< Reference< XControlModel > > aSeq = mxModel->getControlModels();
252 Sequence< Reference< XWindow > > aCompSeq;
254 // vieleicht erhalte ich hier einen TabController,
255 // der schneller die Liste meiner Controls ermittelt
256 Reference< XTabController > xTabController(static_cast< ::cppu::OWeakObject* >(this), UNO_QUERY);
257 Sequence< Reference< XControl > > aControls = xTabController->getControls();
259 // #58317# Es sind ggf. noch nicht alle Controls fuer die Models im Container,
260 // dann kommt spaeter nochmal ein autoTabOrder...
261 if( !ImplCreateComponentSequence( aControls, aSeq, aCompSeq, NULL, sal_False ) )
262 return;
264 sal_uInt32 nCtrls = aCompSeq.getLength();
265 Reference< XWindow > * pComponents = aCompSeq.getArray();
267 ComponentEntryList aCtrls;
268 sal_uInt32 n;
269 for ( n = 0; n < nCtrls; n++ )
271 XWindow* pC = (XWindow*)pComponents[n].get();
272 ComponentEntry* pE = new ComponentEntry;
273 pE->pComponent = pC;
274 awt::Rectangle aPosSize = pC->getPosSize();
275 pE->aPos.X() = aPosSize.X;
276 pE->aPos.Y() = aPosSize.Y;
278 sal_uInt16 nPos;
279 for ( nPos = 0; nPos < aCtrls.Count(); nPos++ )
281 ComponentEntry* pEntry = aCtrls.GetObject( nPos );
282 if ( pEntry->aPos.Y() >= pE->aPos.Y() )
284 while ( pEntry && ( pEntry->aPos.Y() == pE->aPos.Y() )
285 && ( pEntry->aPos.X() < pE->aPos.X() ) )
287 pEntry = aCtrls.GetObject( ++nPos );
289 break;
292 aCtrls.Insert( pE, nPos );
295 Sequence< Reference< XControlModel > > aNewSeq( nCtrls );
296 for ( n = 0; n < nCtrls; n++ )
298 ComponentEntry* pE = aCtrls.GetObject( n );
299 Reference< XControl > xUC( pE->pComponent, UNO_QUERY );
300 aNewSeq.getArray()[n] = xUC->getModel();
301 delete pE;
303 aCtrls.Clear();
305 mxModel->setControlModels( aNewSeq );
308 void StdTabController::activateTabOrder( ) throw(RuntimeException)
310 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
312 // Am Container die Tab-Reihenfolge aktivieren...
314 Reference< XControl > xC( mxControlContainer, UNO_QUERY );
315 Reference< XVclContainerPeer > xVclContainerPeer;
316 if ( xC.is() )
317 xVclContainerPeer = xVclContainerPeer.query( xC->getPeer() );
318 if ( !xC.is() || !xVclContainerPeer.is() )
319 return;
321 // vieleicht erhalte ich hier einen TabController,
322 // der schneller die Liste meiner Controls ermittelt
323 Reference< XTabController > xTabController(static_cast< ::cppu::OWeakObject* >(this), UNO_QUERY);
325 // Flache Liste besorgen...
326 Sequence< Reference< XControlModel > > aModels = mxModel->getControlModels();
327 Sequence< Reference< XWindow > > aCompSeq;
328 Sequence< Any> aTabSeq;
330 // DG: Aus Optimierungsgruenden werden die Controls mittels getControls() geholt,
331 // dieses hoert sich zwar wiedersinning an, fuehrt aber im konkreten Fall (Forms) zu sichtbaren
332 // Geschwindigkeitsvorteilen
333 Sequence< Reference< XControl > > aControls = xTabController->getControls();
335 // #58317# Es sind ggf. noch nicht alle Controls fuer die Models im Container,
336 // dann kommt spaeter nochmal ein activateTabOrder...
337 if( !ImplCreateComponentSequence( aControls, aModels, aCompSeq, &aTabSeq, sal_True ) )
338 return;
340 xVclContainerPeer->setTabOrder( aCompSeq, aTabSeq, mxModel->getGroupControl() );
342 ::rtl::OUString aName;
343 Sequence< Reference< XControlModel > > aThisGroupModels;
344 Sequence< Reference< XWindow > > aControlComponents;
346 sal_uInt32 nGroups = mxModel->getGroupCount();
347 for ( sal_uInt32 nG = 0; nG < nGroups; nG++ )
349 mxModel->getGroup( nG, aThisGroupModels, aName );
351 aControls = xTabController->getControls();
352 // ImplCreateComponentSequence has a really strange semantics regarding it's first parameter:
353 // upon method entry, it expects a super set of the controls which it returns
354 // this means we need to completely fill this sequence with all available controls before
355 // calling into ImplCreateComponentSequence
357 aControlComponents.realloc( 0 );
359 ImplCreateComponentSequence( aControls, aThisGroupModels, aControlComponents, NULL, sal_True );
360 xVclContainerPeer->setGroup( aControlComponents );
364 void StdTabController::activateFirst( ) throw(RuntimeException)
366 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
368 ImplActivateControl( sal_True );
371 void StdTabController::activateLast( ) throw(RuntimeException)
373 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
375 ImplActivateControl( sal_False );
379 Reference< XControl > StdTabController::FindControl( Sequence< Reference< XControl > >& rCtrls,
380 const Reference< XControlModel > & rxCtrlModel )
384 // MT: Funktioniert nicht mehr, weil ich nicht mehr bei mir angemeldet bin,
385 // weil DG das abfaengt.
387 // #54677# Beim Laden eines HTML-Dokuments wird nach jedem Control ein
388 // activateTabOrder gerufen und jede Menge Zeit in dieser Methode verbraten.
389 // Die Anzahl dieser Schleifendurchlaufe steigt quadratisch, also versuchen
390 // das Control direkt vom Model zu erhalten.
391 // => Wenn genau ein Control als PropertyChangeListener angemeldet ist,
392 // dann muss das auch das richtige sein.
394 UnoControlModel* pUnoCtrlModel = UnoControlModel::GetImplementation( rxCtrlModel );
397 if ( pUnoCtrlModel )
399 ListenerIterator aIt( pUnoCtrlModel->maPropertiesListeners );
400 while( aIt.hasMoreElements() )
402 XEventListener* pL = aIt.next();
403 Reference< XControl > xC( pL, UNO_QUERY );
404 if ( xC.is() )
406 if( xC->getContext() == mxControlContainer )
408 xCtrl = xC;
409 break;
414 if ( !xCtrl.is() && rxCtrlModel.is())
416 DBG_ASSERT( rxCtrlModel.is(), "ImplFindControl - welches ?!" );
418 const Reference< XControl > * pCtrls = rCtrls.getConstArray();
419 sal_Int32 nCtrls = rCtrls.getLength();
420 for ( sal_Int32 n = 0; n < nCtrls; n++ )
422 Reference< XControlModel > xModel(pCtrls[n].is() ? pCtrls[n]->getModel() : Reference< XControlModel > ());
423 if ( (XControlModel*)xModel.get() == (XControlModel*)rxCtrlModel.get() )
425 Reference< XControl > xCtrl( pCtrls[n] );
426 ::comphelper::removeElementAt( rCtrls, n );
427 return xCtrl;
430 return Reference< XControl > ();