1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/beans/XPropertySet.hpp>
21 #include <com/sun/star/uno/XComponentContext.hpp>
22 #include <com/sun/star/awt/XVclContainerPeer.hpp>
23 #include <com/sun/star/lang/IllegalArgumentException.hpp>
25 #include <controls/stdtabcontroller.hxx>
26 #include <toolkit/awt/vclxwindow.hxx>
27 #include <toolkit/helper/macros.hxx>
28 #include <cppuhelper/supportsservice.hxx>
29 #include <cppuhelper/queryinterface.hxx>
31 #include <sal/log.hxx>
32 #include <tools/debug.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/window.hxx>
35 #include <comphelper/sequence.hxx>
37 using namespace ::com::sun::star
;
38 using namespace ::com::sun::star::uno
;
39 using namespace ::com::sun::star::awt
;
40 using namespace ::com::sun::star::lang
;
41 using namespace ::com::sun::star::beans
;
45 StdTabController::StdTabController()
49 StdTabController::~StdTabController()
53 bool StdTabController::ImplCreateComponentSequence(
54 Sequence
< Reference
< XControl
> >& rControls
,
55 const Sequence
< Reference
< XControlModel
> >& rModels
,
56 Sequence
< Reference
< XWindow
> >& rComponents
,
57 Sequence
< Any
>* pTabStops
,
60 // Get only the requested controls
61 sal_Int32 nModels
= rModels
.getLength();
62 if (nModels
!= rControls
.getLength())
64 Sequence
< Reference
< XControl
> > aSeq( nModels
);
65 auto aSeqRange
= asNonConstRange(aSeq
);
66 Reference
< XControl
> xCurrentControl
;
68 sal_Int32 nRealControls
= 0;
69 for (const Reference
< XControlModel
>& rModel
: rModels
)
71 xCurrentControl
= FindControl(rControls
, rModel
);
72 if (xCurrentControl
.is())
73 aSeqRange
[nRealControls
++] = xCurrentControl
;
75 aSeq
.realloc(nRealControls
);
79 // there may be less controls than models, but never more controls than models
80 assert(rControls
.getLength() <= rModels
.getLength());
82 sal_Int32 nCtrls
= rControls
.getLength();
83 rComponents
.realloc( nCtrls
);
84 Reference
< XWindow
> * pComps
= rComponents
.getArray();
90 *pTabStops
= Sequence
< Any
>( nCtrls
);
91 pTabs
= pTabStops
->getArray();
95 for ( const Reference
< XControl
>& xCtrl
: std::as_const(rControls
) )
97 // Get the matching control for this model
100 SAL_WARN("toolkit", "Control not found" );
106 pComps
->set(xCtrl
->getPeer(), UNO_QUERY
);
108 pComps
->set(xCtrl
, UNO_QUERY
);
113 // opt: Constant String for TabStop name
114 static constexpr OUStringLiteral aTabStopName
= u
"Tabstop";
116 Reference
< XPropertySet
> xPSet( xCtrl
->getModel(), UNO_QUERY
);
117 Reference
< XPropertySetInfo
> xInfo
= xPSet
->getPropertySetInfo();
118 if( xInfo
->hasPropertyByName( aTabStopName
) )
119 *pTabs
++ = xPSet
->getPropertyValue( aTabStopName
);
129 void StdTabController::ImplActivateControl( bool bFirst
) const
131 // HACK due to bug #53688#, map controls onto an interface if remote controls may occur
132 Sequence
< Reference
< XControl
> > aCtrls
= const_cast<StdTabController
*>(this)->getControls();
133 const Reference
< XControl
> * pControls
= aCtrls
.getConstArray();
134 sal_uInt32 nCount
= aCtrls
.getLength();
136 for ( sal_uInt32 n
= bFirst
? 0 : nCount
; bFirst
? n
< nCount
: n
!= 0; )
138 sal_uInt32 nCtrl
= bFirst
? n
++ : --n
;
139 DBG_ASSERT( pControls
[nCtrl
].is(), "Control not in Container!" );
140 if ( pControls
[nCtrl
].is() )
142 Reference
< XWindowPeer
> xCP
= pControls
[nCtrl
]->getPeer();
145 VCLXWindow
* pC
= dynamic_cast<VCLXWindow
*>( xCP
.get() );
146 if ( pC
&& pC
->GetWindow() && ( pC
->GetWindow()->GetStyle() & WB_TABSTOP
) )
148 pC
->GetWindow()->GrabFocus();
157 Any
StdTabController::queryAggregation( const Type
& rType
)
159 Any aRet
= ::cppu::queryInterface( rType
,
160 static_cast< XTabController
* >(this),
161 static_cast< XServiceInfo
* >(this),
162 static_cast< XTypeProvider
* >(this) );
163 return (aRet
.hasValue() ? aRet
: OWeakAggObject::queryAggregation( rType
));
166 IMPL_IMPLEMENTATION_ID( StdTabController
)
169 css::uno::Sequence
< css::uno::Type
> StdTabController::getTypes()
171 static const css::uno::Sequence
< css::uno::Type
> aTypeList
{
172 cppu::UnoType
<css::lang::XTypeProvider
>::get(),
173 cppu::UnoType
<XTabController
>::get(),
174 cppu::UnoType
<XServiceInfo
>::get()
179 void StdTabController::setModel( const Reference
< XTabControllerModel
>& Model
)
181 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
186 Reference
< XTabControllerModel
> StdTabController::getModel( )
188 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
193 void StdTabController::setContainer( const Reference
< XControlContainer
>& Container
)
195 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
197 mxControlContainer
= Container
;
200 Reference
< XControlContainer
> StdTabController::getContainer( )
202 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
204 return mxControlContainer
;
207 Sequence
< Reference
< XControl
> > StdTabController::getControls( )
209 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
211 Sequence
< Reference
< XControl
> > aSeq
;
213 if ( mxControlContainer
.is() )
215 const Sequence
< Reference
< XControlModel
> > aModels
= mxModel
->getControlModels();
217 Sequence
< Reference
< XControl
> > xCtrls
= mxControlContainer
->getControls();
219 sal_Int32 nCtrls
= aModels
.getLength();
220 aSeq
= Sequence
< Reference
< XControl
> >( nCtrls
);
221 std::transform(aModels
.begin(), aModels
.end(), aSeq
.getArray(),
222 [&xCtrls
](const Reference
< XControlModel
>& xCtrlModel
) -> Reference
< XControl
> {
223 return FindControl( xCtrls
, xCtrlModel
); });
230 struct ComponentEntry
232 css::awt::XWindow
* pComponent
;
238 void StdTabController::autoTabOrder( )
240 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
242 DBG_ASSERT( mxControlContainer
.is(), "autoTabOrder: No ControlContainer!" );
243 if ( !mxControlContainer
.is() )
246 Sequence
< Reference
< XControlModel
> > aSeq
= mxModel
->getControlModels();
247 Sequence
< Reference
< XWindow
> > aCompSeq
;
249 // This may return a TabController, which returns desired list of controls faster
250 Sequence
< Reference
< XControl
> > aControls
= getControls();
252 // #58317# Some Models may be missing from the Container. Plus there is a
253 // autoTabOrder call later on.
254 if( !ImplCreateComponentSequence( aControls
, aSeq
, aCompSeq
, nullptr, false ) )
257 sal_uInt32 nCtrls
= aCompSeq
.getLength();
259 // insert sort algorithm
260 std::vector
< ComponentEntry
> aCtrls
;
261 aCtrls
.reserve(nCtrls
);
262 for ( const Reference
< XWindow
>& rComponent
: std::as_const(aCompSeq
) )
264 XWindow
* pC
= rComponent
.get();
265 ComponentEntry newEntry
;
266 newEntry
.pComponent
= pC
;
267 awt::Rectangle aPosSize
= pC
->getPosSize();
268 newEntry
.aPos
.setX( aPosSize
.X
);
269 newEntry
.aPos
.setY( aPosSize
.Y
);
271 decltype(aCtrls
)::size_type nPos
;
272 for ( nPos
= 0; nPos
< aCtrls
.size(); nPos
++ )
274 ComponentEntry
& rEntry
= aCtrls
[ nPos
];
275 if ( ( rEntry
.aPos
.Y() > newEntry
.aPos
.Y() ) ||
276 ( ( rEntry
.aPos
.Y() == newEntry
.aPos
.Y() ) && ( rEntry
.aPos
.X() > newEntry
.aPos
.X() ) ) )
279 if ( nPos
< aCtrls
.size() ) {
280 aCtrls
.insert( aCtrls
.begin() + nPos
, newEntry
);
282 aCtrls
.push_back( newEntry
);
286 Sequence
< Reference
< XControlModel
> > aNewSeq( nCtrls
);
287 std::transform(aCtrls
.begin(), aCtrls
.end(), aNewSeq
.getArray(),
288 [](const ComponentEntry
& rEntry
) -> Reference
< XControlModel
> {
289 Reference
< XControl
> xUC( rEntry
.pComponent
, UNO_QUERY
);
290 return xUC
->getModel();
293 mxModel
->setControlModels( aNewSeq
);
296 void StdTabController::activateTabOrder( )
298 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() );
300 // Activate tab order for the control container
302 Reference
< XControl
> xC( mxControlContainer
, UNO_QUERY
);
303 Reference
< XVclContainerPeer
> xVclContainerPeer
;
305 xVclContainerPeer
.set(xC
->getPeer(), css::uno::UNO_QUERY
);
306 if ( !xC
.is() || !xVclContainerPeer
.is() )
309 // This may return a TabController, which returns desired list of controls faster
310 // (the dreaded UNO aggregation, retrieve the thing that we are part of)
311 Reference
<XTabController
> xTabController( static_cast<XTabController
*>(this), UNO_QUERY
);
313 // Get a flattened list of controls sequences
314 Sequence
< Reference
< XControlModel
> > aModels
= mxModel
->getControlModels();
315 Sequence
< Reference
< XWindow
> > aCompSeq
;
316 Sequence
< Any
> aTabSeq
;
318 // DG: For the sake of optimization, retrieve Controls from getControls(),
319 // this may sound counterproductive, but leads to performance improvements
320 // in practical scenarios (Forms)
321 Sequence
< Reference
< XControl
> > aControls
= xTabController
->getControls();
323 // #58317# Some Models may be missing from the Container. Plus there is a
324 // autoTabOrder call later on.
325 if( !ImplCreateComponentSequence( aControls
, aModels
, aCompSeq
, &aTabSeq
, true ) )
328 xVclContainerPeer
->setTabOrder( aCompSeq
, aTabSeq
, mxModel
->getGroupControl() );
331 Sequence
< Reference
< XControlModel
> > aThisGroupModels
;
332 Sequence
< Reference
< XWindow
> > aControlComponents
;
334 sal_uInt32 nGroups
= mxModel
->getGroupCount();
335 for ( sal_uInt32 nG
= 0; nG
< nGroups
; nG
++ )
337 mxModel
->getGroup( nG
, aThisGroupModels
, aName
);
339 aControls
= xTabController
->getControls();
340 // ImplCreateComponentSequence has a really strange semantics regarding it's first parameter:
341 // upon method entry, it expects a super set of the controls which it returns
342 // this means we need to completely fill this sequence with all available controls before
343 // calling into ImplCreateComponentSequence
345 aControlComponents
.realloc( 0 );
347 ImplCreateComponentSequence( aControls
, aThisGroupModels
, aControlComponents
, nullptr, true );
348 xVclContainerPeer
->setGroup( aControlComponents
);
352 void StdTabController::activateFirst( )
354 SolarMutexGuard aSolarGuard
;
355 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() ); //TODO: necessary?
357 ImplActivateControl( true );
360 void StdTabController::activateLast( )
362 SolarMutexGuard aSolarGuard
;
363 ::osl::Guard
< ::osl::Mutex
> aGuard( GetMutex() ); //TODO: necessary?
365 ImplActivateControl( false );
368 OUString
StdTabController::getImplementationName()
370 return "stardiv.Toolkit.StdTabController";
373 sal_Bool
StdTabController::supportsService(OUString
const & ServiceName
)
375 return cppu::supportsService(this, ServiceName
);
378 css::uno::Sequence
<OUString
> StdTabController::getSupportedServiceNames()
380 return css::uno::Sequence
<OUString
>{
381 "com.sun.star.awt.TabController",
382 "stardiv.vcl.control.TabController"};
385 Reference
< XControl
> StdTabController::FindControl( Sequence
< Reference
< XControl
> >& rCtrls
,
386 const Reference
< XControlModel
> & rxCtrlModel
)
388 if (!rxCtrlModel
.is())
389 throw lang::IllegalArgumentException("No valid XControlModel",
390 uno::Reference
<uno::XInterface
>(), 0);
392 auto pCtrl
= std::find_if(std::cbegin(rCtrls
), std::cend(rCtrls
),
393 [&rxCtrlModel
](const Reference
< XControl
>& rCtrl
) {
394 Reference
< XControlModel
> xModel(rCtrl
.is() ? rCtrl
->getModel() : Reference
< XControlModel
> ());
395 return xModel
.get() == rxCtrlModel
.get();
397 if (pCtrl
!= std::cend(rCtrls
))
399 auto n
= static_cast<sal_Int32
>(std::distance(std::cbegin(rCtrls
), pCtrl
));
400 Reference
< XControl
> xCtrl( *pCtrl
);
401 ::comphelper::removeElementAt( rCtrls
, n
);
404 return Reference
< XControl
> ();
407 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
408 stardiv_Toolkit_StdTabController_get_implementation(
409 css::uno::XComponentContext
*,
410 css::uno::Sequence
<css::uno::Any
> const &)
412 return cppu::acquire(new StdTabController());
415 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */