1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: stdtabcontroller.cxx,v $
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>
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
);
93 DBG_ASSERT( rControls
.getLength() <= rModels
.getLength(), "StdTabController:ImplCreateComponentSequence: inconsistence!" );
94 // there may be less controls than models, but never more controls than models
98 const Reference
< XControl
> * pControls
= rControls
.getConstArray();
99 sal_uInt32 nCtrls
= rControls
.getLength();
100 rComponents
.realloc( nCtrls
);
101 Reference
< XWindow
> * pComps
= rComponents
.getArray();
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
]);
118 pComps
[n
] = Reference
< XWindow
> (xCtrl
->getPeer(), UNO_QUERY
);
120 pComps
[n
] = Reference
< XWindow
> (xCtrl
, UNO_QUERY
);
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
);
138 DBG_TRACE( "ImplCreateComponentSequence: Control not found" );
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();
162 VCLXWindow
* pC
= VCLXWindow::GetImplementation( xCP
);
163 if ( pC
&& pC
->GetWindow() && ( pC
->GetWindow()->GetStyle() & WB_TABSTOP
) )
165 pC
->GetWindow()->GrabFocus();
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
));
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() );
196 Reference
< XTabControllerModel
> StdTabController::getModel( ) throw(RuntimeException
)
198 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
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
;
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() )
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
) )
264 sal_uInt32 nCtrls
= aCompSeq
.getLength();
265 Reference
< XWindow
> * pComponents
= aCompSeq
.getArray();
267 ComponentEntryList aCtrls
;
269 for ( n
= 0; n
< nCtrls
; n
++ )
271 XWindow
* pC
= (XWindow
*)pComponents
[n
].get();
272 ComponentEntry
* pE
= new ComponentEntry
;
274 awt::Rectangle aPosSize
= pC
->getPosSize();
275 pE
->aPos
.X() = aPosSize
.X
;
276 pE
->aPos
.Y() = aPosSize
.Y
;
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
);
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();
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
;
317 xVclContainerPeer
= xVclContainerPeer
.query( xC
->getPeer() );
318 if ( !xC
.is() || !xVclContainerPeer
.is() )
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
) )
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 );
399 ListenerIterator aIt( pUnoCtrlModel->maPropertiesListeners );
400 while( aIt.hasMoreElements() )
402 XEventListener* pL = aIt.next();
403 Reference< XControl > xC( pL, UNO_QUERY );
406 if( xC->getContext() == mxControlContainer )
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
);
430 return Reference
< XControl
> ();