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 .
21 #include "fmcontrolbordermanager.hxx"
25 #include <com/sun/star/form/validation/XValidatableFormComponent.hpp>
26 #include <com/sun/star/awt/XTextComponent.hpp>
27 #include <com/sun/star/awt/XListBox.hpp>
28 #include <tools/debug.hxx>
35 using namespace ::com::sun::star::uno
;
36 using namespace ::com::sun::star::awt
;
37 using namespace ::com::sun::star::form::validation
;
43 static void setUnderline( const Reference
< XVclWindowPeer
>& _rxPeer
, const UnderlineDescriptor
& _rUnderline
)
45 OSL_ENSURE( _rxPeer
.is(), "setUnderline: invalid peer!" );
47 // the underline type is an aspect of the font
49 OSL_VERIFY( _rxPeer
->getProperty( FM_PROP_FONT
) >>= aFont
);
50 aFont
.Underline
= _rUnderline
.nUnderlineType
;
51 _rxPeer
->setProperty( FM_PROP_FONT
, makeAny( aFont
) );
52 // the underline color is a separate property
53 _rxPeer
->setProperty( FM_PROP_TEXTLINECOLOR
, makeAny( _rUnderline
.nUnderlineColor
) );
57 static void getUnderline( const Reference
< XVclWindowPeer
>& _rxPeer
, UnderlineDescriptor
& _rUnderline
)
59 OSL_ENSURE( _rxPeer
.is(), "getUnderline: invalid peer!" );
62 OSL_VERIFY( _rxPeer
->getProperty( FM_PROP_FONT
) >>= aFont
);
63 _rUnderline
.nUnderlineType
= aFont
.Underline
;
65 OSL_VERIFY( _rxPeer
->getProperty( FM_PROP_TEXTLINECOLOR
) >>= _rUnderline
.nUnderlineColor
);
69 static void getBorder( const Reference
< XVclWindowPeer
>& _rxPeer
, BorderDescriptor
& _rBoder
)
71 OSL_ENSURE( _rxPeer
.is(), "getBorder: invalid peer!" );
73 OSL_VERIFY( _rxPeer
->getProperty( FM_PROP_BORDER
) >>= _rBoder
.nBorderType
);
74 OSL_VERIFY( _rxPeer
->getProperty( FM_PROP_BORDERCOLOR
) >>= _rBoder
.nBorderColor
);
78 static void setBorder( const Reference
< XVclWindowPeer
>& _rxPeer
, const BorderDescriptor
& _rBoder
)
80 OSL_ENSURE( _rxPeer
.is(), "setBorder: invalid peer!" );
82 _rxPeer
->setProperty( FM_PROP_BORDER
, makeAny( _rBoder
.nBorderType
) );
83 _rxPeer
->setProperty( FM_PROP_BORDERCOLOR
, makeAny( _rBoder
.nBorderColor
) );
87 //= ControlBorderManager
90 ControlBorderManager::ControlBorderManager()
91 :m_nFocusColor ( 0x000000FF )
92 ,m_nMouseHoveColor( 0x007098BE )
93 ,m_nInvalidColor ( 0x00FF0000 )
94 ,m_bDynamicBorderColors( false )
99 ControlBorderManager::~ControlBorderManager()
104 bool ControlBorderManager::canColorBorder( const Reference
< XVclWindowPeer
>& _rxPeer
)
106 OSL_PRECOND( _rxPeer
.is(), "ControlBorderManager::canColorBorder: invalid peer!" );
108 PeerBag::const_iterator aPos
= m_aColorableControls
.find( _rxPeer
);
109 if ( aPos
!= m_aColorableControls
.end() )
112 aPos
= m_aNonColorableControls
.find( _rxPeer
);
113 if ( aPos
!= m_aNonColorableControls
.end() )
116 // this peer is not yet known
118 // no border coloring for controls which are not for text input
119 // #i37434# / 2004-11-19 / frank.schoenheit@sun.com
120 Reference
< XTextComponent
> xText( _rxPeer
, UNO_QUERY
);
121 Reference
< XListBox
> xListBox( _rxPeer
, UNO_QUERY
);
122 if ( xText
.is() || xListBox
.is() )
124 sal_Int16 nBorderStyle
= VisualEffect::NONE
;
125 OSL_VERIFY( _rxPeer
->getProperty( FM_PROP_BORDER
) >>= nBorderStyle
);
126 if ( nBorderStyle
== VisualEffect::FLAT
)
127 // if you change this to also accept LOOK3D, then this would also work, but look ugly
129 m_aColorableControls
.insert( _rxPeer
);
134 m_aNonColorableControls
.insert( _rxPeer
);
139 ControlStatus
ControlBorderManager::getControlStatus( const Reference
< XControl
>& _rxControl
) SAL_THROW(())
141 ControlStatus nStatus
= CONTROL_STATUS_NONE
;
143 if ( _rxControl
.get() == m_aFocusControl
.xControl
.get() )
144 nStatus
|= CONTROL_STATUS_FOCUSED
;
146 if ( _rxControl
.get() == m_aMouseHoverControl
.xControl
.get() )
147 nStatus
|= CONTROL_STATUS_MOUSE_HOVER
;
149 if ( m_aInvalidControls
.find( ControlData( _rxControl
) ) != m_aInvalidControls
.end() )
150 nStatus
|= CONTROL_STATUS_INVALID
;
156 sal_Int32
ControlBorderManager::getControlColorByStatus( ControlStatus _nStatus
)
158 // "invalid" is ranked highest
159 if ( _nStatus
& CONTROL_STATUS_INVALID
)
160 return m_nInvalidColor
;
162 // then, "focused" is more important than ...
163 if ( _nStatus
& CONTROL_STATUS_FOCUSED
)
164 return m_nFocusColor
;
167 if ( _nStatus
& CONTROL_STATUS_MOUSE_HOVER
)
168 return m_nMouseHoveColor
;
170 OSL_FAIL( "ControlBorderManager::getControlColorByStatus: invalid status!" );
175 void ControlBorderManager::updateBorderStyle( const Reference
< XControl
>& _rxControl
, const Reference
< XVclWindowPeer
>& _rxPeer
, const BorderDescriptor
& _rFallback
) SAL_THROW(())
177 OSL_PRECOND( _rxControl
.is() && _rxPeer
.is(), "ControlBorderManager::updateBorderStyle: invalid parameters!" );
179 ControlStatus nStatus
= getControlStatus( _rxControl
);
180 BorderDescriptor aBorder
;
181 aBorder
.nBorderType
= ( nStatus
== CONTROL_STATUS_NONE
)
182 ? _rFallback
.nBorderType
183 : VisualEffect::FLAT
;
184 aBorder
.nBorderColor
= ( nStatus
== CONTROL_STATUS_NONE
)
185 ? _rFallback
.nBorderColor
186 : getControlColorByStatus( nStatus
);
187 setBorder( _rxPeer
, aBorder
);
191 void ControlBorderManager::determineOriginalBorderStyle( const Reference
< XControl
>& _rxControl
, BorderDescriptor
& _rData
) const
193 _rData
= ControlData();
194 if ( m_aFocusControl
.xControl
.get() == _rxControl
.get() )
196 _rData
= m_aFocusControl
;
198 else if ( m_aMouseHoverControl
.xControl
.get() == _rxControl
.get() )
200 _rData
= m_aMouseHoverControl
;
204 ControlBag::const_iterator aPos
= m_aInvalidControls
.find( _rxControl
);
205 if ( aPos
!= m_aInvalidControls
.end() )
211 Reference
< XVclWindowPeer
> xPeer( _rxControl
->getPeer(), UNO_QUERY
);
212 getBorder( xPeer
, _rData
);
218 void ControlBorderManager::controlStatusGained( const Reference
< XInterface
>& _rxControl
, ControlData
& _rControlData
) SAL_THROW(())
220 if ( _rxControl
== _rControlData
.xControl
)
221 // nothing to do - though suspicious
224 Reference
< XControl
> xAsControl( _rxControl
, UNO_QUERY
);
225 DBG_ASSERT( xAsControl
.is(), "ControlBorderManager::controlStatusGained: invalid control!" );
226 if ( !xAsControl
.is() )
231 Reference
< XVclWindowPeer
> xPeer( xAsControl
->getPeer(), UNO_QUERY
);
232 if ( xPeer
.is() && canColorBorder( xPeer
) )
234 // remember the control and its current border color
235 _rControlData
.xControl
.clear(); // so determineOriginalBorderStyle doesn't get confused
237 determineOriginalBorderStyle( xAsControl
, _rControlData
);
239 _rControlData
.xControl
= xAsControl
;
241 updateBorderStyle( xAsControl
, xPeer
, _rControlData
);
244 catch( const Exception
& )
246 OSL_FAIL( "ControlBorderManager::controlStatusGained: caught an exception!" );
251 void ControlBorderManager::controlStatusLost( const Reference
< XInterface
>& _rxControl
, ControlData
& _rControlData
) SAL_THROW(())
253 if ( _rxControl
!= _rControlData
.xControl
)
257 OSL_PRECOND( _rControlData
.xControl
.is(), "ControlBorderManager::controlStatusLost: invalid control data - this will crash!" );
260 Reference
< XVclWindowPeer
> xPeer( _rControlData
.xControl
->getPeer(), UNO_QUERY
);
261 if ( xPeer
.is() && canColorBorder( xPeer
) )
263 ControlData
aPreviousStatus( _rControlData
);
264 _rControlData
= ControlData();
265 updateBorderStyle( aPreviousStatus
.xControl
, xPeer
, aPreviousStatus
);
268 catch( const Exception
& )
270 OSL_FAIL( "ControlBorderManager::controlStatusLost: caught an exception!" );
275 void ControlBorderManager::enableDynamicBorderColor( )
277 m_bDynamicBorderColors
= true;
281 void ControlBorderManager::disableDynamicBorderColor( )
283 m_bDynamicBorderColors
= false;
288 void ControlBorderManager::setStatusColor( ControlStatus _nStatus
, sal_Int32 _nColor
)
292 case CONTROL_STATUS_FOCUSED
:
293 m_nFocusColor
= _nColor
;
295 case CONTROL_STATUS_MOUSE_HOVER
:
296 m_nMouseHoveColor
= _nColor
;
298 case CONTROL_STATUS_INVALID
:
299 m_nInvalidColor
= _nColor
;
302 OSL_FAIL( "ControlBorderManager::setStatusColor: invalid status!" );
307 void ControlBorderManager::restoreAll()
309 if ( m_aFocusControl
.xControl
.is() )
310 controlStatusLost( m_aFocusControl
.xControl
, m_aFocusControl
);
311 if ( m_aMouseHoverControl
.xControl
.is() )
312 controlStatusLost( m_aMouseHoverControl
.xControl
, m_aMouseHoverControl
);
314 ControlBag aInvalidControls
;
315 m_aInvalidControls
.swap( aInvalidControls
);
317 for ( ControlBag::const_iterator loop
= aInvalidControls
.begin();
318 loop
!= aInvalidControls
.end();
322 Reference
< XVclWindowPeer
> xPeer( loop
->xControl
->getPeer(), UNO_QUERY
);
325 updateBorderStyle( loop
->xControl
, xPeer
, *loop
);
326 xPeer
->setProperty( FM_PROP_HELPTEXT
, makeAny( loop
->sOriginalHelpText
) );
327 setUnderline( xPeer
, *loop
);
333 void ControlBorderManager::focusGained( const Reference
< XInterface
>& _rxControl
) SAL_THROW(())
335 if ( m_bDynamicBorderColors
)
336 controlStatusGained( _rxControl
, m_aFocusControl
);
340 void ControlBorderManager::focusLost( const Reference
< XInterface
>& _rxControl
) SAL_THROW(())
342 if ( m_bDynamicBorderColors
)
343 controlStatusLost( _rxControl
, m_aFocusControl
);
347 void ControlBorderManager::mouseEntered( const Reference
< XInterface
>& _rxControl
) SAL_THROW(())
349 if ( m_bDynamicBorderColors
)
350 controlStatusGained( _rxControl
, m_aMouseHoverControl
);
354 void ControlBorderManager::mouseExited( const Reference
< XInterface
>& _rxControl
) SAL_THROW(())
356 if ( m_bDynamicBorderColors
)
357 controlStatusLost( _rxControl
, m_aMouseHoverControl
);
361 void ControlBorderManager::validityChanged( const Reference
< XControl
>& _rxControl
, const Reference
< XValidatableFormComponent
>& _rxValidatable
) SAL_THROW(())
365 OSL_ENSURE( _rxControl
.is(), "ControlBorderManager::validityChanged: invalid control!" );
366 OSL_ENSURE( _rxValidatable
.is(), "ControlBorderManager::validityChanged: invalid validatable!" );
368 Reference
< XVclWindowPeer
> xPeer( _rxControl
.is() ? _rxControl
->getPeer() : Reference
< XWindowPeer
>(), UNO_QUERY
);
369 if ( !xPeer
.is() || !_rxValidatable
.is() )
372 ControlData
aData( _rxControl
);
374 if ( _rxValidatable
->isValid() )
376 ControlBag::iterator aPos
= m_aInvalidControls
.find( aData
);
377 if ( aPos
!= m_aInvalidControls
.end() )
378 { // invalid before, valid now
379 ControlData
aOriginalLayout( *aPos
);
380 m_aInvalidControls
.erase( aPos
);
382 // restore all the things we used to indicate invalidity
383 if ( m_bDynamicBorderColors
)
384 updateBorderStyle( _rxControl
, xPeer
, aOriginalLayout
);
385 xPeer
->setProperty( FM_PROP_HELPTEXT
, makeAny( aOriginalLayout
.sOriginalHelpText
) );
386 setUnderline( xPeer
, aOriginalLayout
);
391 // we're here in the INVALID case
392 if ( m_aInvalidControls
.find( _rxControl
) == m_aInvalidControls
.end() )
393 { // valid before, invalid now
395 // remember the current border
396 determineOriginalBorderStyle( _rxControl
, aData
);
398 xPeer
->getProperty( FM_PROP_HELPTEXT
) >>= aData
.sOriginalHelpText
;
400 getUnderline( xPeer
, aData
);
402 m_aInvalidControls
.insert( aData
);
404 // update the border to the new invalidity
405 if ( m_bDynamicBorderColors
&& canColorBorder( xPeer
) )
406 updateBorderStyle( _rxControl
, xPeer
, aData
);
409 // and also the new font
410 setUnderline( xPeer
, UnderlineDescriptor( com::sun::star::awt::FontUnderline::WAVE
, m_nInvalidColor
) );
414 // update the explanation for invalidity (this is always done, even if the validity did not change)
415 Reference
< XValidator
> xValidator
= _rxValidatable
->getValidator();
416 OSL_ENSURE( xValidator
.is(), "ControlBorderManager::validityChanged: invalid, but no validator?" );
417 OUString sExplainInvalidity
= xValidator
.is() ? xValidator
->explainInvalid( _rxValidatable
->getCurrentValue() ) : OUString();
418 xPeer
->setProperty( FM_PROP_HELPTEXT
, makeAny( sExplainInvalidity
) );
420 catch( const Exception
& )
422 OSL_FAIL( "ControlBorderManager::validityChanged: caught an exception!" );
427 } // namespace svxform
430 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */