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