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 // ----------------------------------------------------
StdTabController()50 StdTabController::StdTabController()
51 {
52 }
53
~StdTabController()54 StdTabController::~StdTabController()
55 {
56 }
57
ImplCreateComponentSequence(Sequence<Reference<XControl>> & rControls,const Sequence<Reference<XControlModel>> & rModels,Sequence<Reference<XWindow>> & rComponents,Sequence<Any> * pTabStops,sal_Bool bPeerComponent) const58 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
ImplActivateControl(sal_Bool bFirst) const138 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
queryAggregation(const Type & rType)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
getModel()189 Reference< XTabControllerModel > StdTabController::getModel( ) throw(RuntimeException)
190 {
191 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
192
193 return mxModel;
194 }
195
setContainer(const Reference<XControlContainer> & Container)196 void StdTabController::setContainer( const Reference< XControlContainer >& Container ) throw(RuntimeException)
197 {
198 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
199
200 mxControlContainer = Container;
201 }
202
getContainer()203 Reference< XControlContainer > StdTabController::getContainer( ) throw(RuntimeException)
204 {
205 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
206
207 return mxControlContainer;
208 }
209
getControls()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
autoTabOrder()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
activateTabOrder()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
activateFirst()357 void StdTabController::activateFirst( ) throw(RuntimeException)
358 {
359 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
360
361 ImplActivateControl( sal_True );
362 }
363
activateLast()364 void StdTabController::activateLast( ) throw(RuntimeException)
365 {
366 ::osl::Guard< ::osl::Mutex > aGuard( GetMutex() );
367
368 ImplActivateControl( sal_False );
369 }
370
371
FindControl(Sequence<Reference<XControl>> & rCtrls,const Reference<XControlModel> & rxCtrlModel)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