xref: /AOO41X/main/toolkit/source/controls/stdtabcontroller.cxx (revision b0724fc6948542b2496e16ea247f985ee5987cfe)
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