Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include "fmcontrolbordermanager.hxx"
31 : :
32 : : #include "fmprop.hrc"
33 : :
34 : : #include <com/sun/star/form/validation/XValidatableFormComponent.hpp>
35 : : #include <com/sun/star/awt/XTextComponent.hpp>
36 : : #include <com/sun/star/awt/XListBox.hpp>
37 : : #include <tools/debug.hxx>
38 : :
39 : : //........................................................................
40 : : namespace svxform
41 : : {
42 : : //........................................................................
43 : :
44 : : using namespace ::com::sun::star::uno;
45 : : using namespace ::com::sun::star::awt;
46 : : using namespace ::com::sun::star::form::validation;
47 : :
48 : : //====================================================================
49 : : //= helper
50 : : //====================================================================
51 : : //--------------------------------------------------------------------
52 : 0 : static void setUnderline( const Reference< XVclWindowPeer >& _rxPeer, const UnderlineDescriptor& _rUnderline )
53 : : {
54 : : OSL_ENSURE( _rxPeer.is(), "setUnderline: invalid peer!" );
55 : :
56 : : // the underline type is an aspect of the font
57 : 0 : FontDescriptor aFont;
58 [ # # ][ # # ]: 0 : OSL_VERIFY( _rxPeer->getProperty( FM_PROP_FONT ) >>= aFont );
[ # # ][ # # ]
59 : 0 : aFont.Underline = _rUnderline.nUnderlineType;
60 [ # # ][ # # ]: 0 : _rxPeer->setProperty( FM_PROP_FONT, makeAny( aFont ) );
[ # # ][ # # ]
61 : : // the underline color is a separate property
62 [ # # ][ # # ]: 0 : _rxPeer->setProperty( FM_PROP_TEXTLINECOLOR, makeAny( _rUnderline.nUnderlineColor ) );
[ # # ][ # # ]
63 : 0 : }
64 : :
65 : : //--------------------------------------------------------------------
66 : 0 : static void getUnderline( const Reference< XVclWindowPeer >& _rxPeer, UnderlineDescriptor& _rUnderline )
67 : : {
68 : : OSL_ENSURE( _rxPeer.is(), "getUnderline: invalid peer!" );
69 : :
70 : 0 : FontDescriptor aFont;
71 [ # # ][ # # ]: 0 : OSL_VERIFY( _rxPeer->getProperty( FM_PROP_FONT ) >>= aFont );
[ # # ][ # # ]
72 : 0 : _rUnderline.nUnderlineType = aFont.Underline;
73 : :
74 [ # # ][ # # ]: 0 : OSL_VERIFY( _rxPeer->getProperty( FM_PROP_TEXTLINECOLOR ) >>= _rUnderline.nUnderlineColor );
[ # # ]
75 : 0 : }
76 : :
77 : : //--------------------------------------------------------------------
78 : 0 : static void getBorder( const Reference< XVclWindowPeer >& _rxPeer, BorderDescriptor& _rBoder )
79 : : {
80 : : OSL_ENSURE( _rxPeer.is(), "getBorder: invalid peer!" );
81 : :
82 [ # # ]: 0 : OSL_VERIFY( _rxPeer->getProperty( FM_PROP_BORDER ) >>= _rBoder.nBorderType );
83 [ # # ]: 0 : OSL_VERIFY( _rxPeer->getProperty( FM_PROP_BORDERCOLOR ) >>= _rBoder.nBorderColor );
84 : 0 : }
85 : :
86 : : //--------------------------------------------------------------------
87 : 0 : static void setBorder( const Reference< XVclWindowPeer >& _rxPeer, const BorderDescriptor& _rBoder )
88 : : {
89 : : OSL_ENSURE( _rxPeer.is(), "setBorder: invalid peer!" );
90 : :
91 [ # # ][ # # ]: 0 : _rxPeer->setProperty( FM_PROP_BORDER, makeAny( _rBoder.nBorderType ) );
92 [ # # ][ # # ]: 0 : _rxPeer->setProperty( FM_PROP_BORDERCOLOR, makeAny( _rBoder.nBorderColor ) );
93 : 0 : }
94 : :
95 : : //====================================================================
96 : : //= ControlBorderManager
97 : : //====================================================================
98 : : //--------------------------------------------------------------------
99 : 20 : ControlBorderManager::ControlBorderManager()
100 : : :m_nFocusColor ( 0x000000FF )
101 : : ,m_nMouseHoveColor( 0x007098BE )
102 : : ,m_nInvalidColor ( 0x00FF0000 )
103 [ + - ][ + - ]: 20 : ,m_bDynamicBorderColors( false )
[ + - ][ + - ]
104 : : {
105 : 20 : }
106 : :
107 : : //--------------------------------------------------------------------
108 [ + - ][ + - ]: 17 : ControlBorderManager::~ControlBorderManager()
109 : : {
110 : 17 : }
111 : :
112 : : //--------------------------------------------------------------------
113 : 0 : bool ControlBorderManager::canColorBorder( const Reference< XVclWindowPeer >& _rxPeer )
114 : : {
115 : : OSL_PRECOND( _rxPeer.is(), "ControlBorderManager::canColorBorder: invalid peer!" );
116 : :
117 [ # # ]: 0 : PeerBag::const_iterator aPos = m_aColorableControls.find( _rxPeer );
118 [ # # ]: 0 : if ( aPos != m_aColorableControls.end() )
119 : 0 : return true;
120 : :
121 [ # # ]: 0 : aPos = m_aNonColorableControls.find( _rxPeer );
122 [ # # ]: 0 : if ( aPos != m_aNonColorableControls.end() )
123 : 0 : return false;
124 : :
125 : : // this peer is not yet known
126 : :
127 : : // no border coloring for controls which are not for text input
128 : : // #i37434# / 2004-11-19 / frank.schoenheit@sun.com
129 [ # # ]: 0 : Reference< XTextComponent > xText( _rxPeer, UNO_QUERY );
130 [ # # ]: 0 : Reference< XListBox > xListBox( _rxPeer, UNO_QUERY );
131 [ # # ][ # # ]: 0 : if ( xText.is() || xListBox.is() )
[ # # ]
132 : : {
133 : 0 : sal_Int16 nBorderStyle = VisualEffect::NONE;
134 [ # # ][ # # ]: 0 : OSL_VERIFY( _rxPeer->getProperty( FM_PROP_BORDER ) >>= nBorderStyle );
[ # # ]
135 [ # # ]: 0 : if ( nBorderStyle == VisualEffect::FLAT )
136 : : // if you change this to also accept LOOK3D, then this would also work, but look ugly
137 : : {
138 [ # # ]: 0 : m_aColorableControls.insert( _rxPeer );
139 : 0 : return true;
140 : : }
141 : : }
142 : :
143 [ # # ]: 0 : m_aNonColorableControls.insert( _rxPeer );
144 : 0 : return false;
145 : : }
146 : :
147 : : //--------------------------------------------------------------------
148 : 0 : ControlStatus ControlBorderManager::getControlStatus( const Reference< XControl >& _rxControl ) SAL_THROW(())
149 : : {
150 : 0 : ControlStatus nStatus = CONTROL_STATUS_NONE;
151 : :
152 [ # # ]: 0 : if ( _rxControl.get() == m_aFocusControl.xControl.get() )
153 : 0 : nStatus |= CONTROL_STATUS_FOCUSED;
154 : :
155 [ # # ]: 0 : if ( _rxControl.get() == m_aMouseHoverControl.xControl.get() )
156 : 0 : nStatus |= CONTROL_STATUS_MOUSE_HOVER;
157 : :
158 [ # # ][ # # ]: 0 : if ( m_aInvalidControls.find( ControlData( _rxControl ) ) != m_aInvalidControls.end() )
[ # # ][ # # ]
159 : 0 : nStatus |= CONTROL_STATUS_INVALID;
160 : :
161 : 0 : return nStatus;
162 : : }
163 : :
164 : : //--------------------------------------------------------------------
165 : 0 : sal_Int32 ControlBorderManager::getControlColorByStatus( ControlStatus _nStatus )
166 : : {
167 : : // "invalid" is ranked highest
168 [ # # ]: 0 : if ( _nStatus & CONTROL_STATUS_INVALID )
169 : 0 : return m_nInvalidColor;
170 : :
171 : : // then, "focused" is more important than ...
172 [ # # ]: 0 : if ( _nStatus & CONTROL_STATUS_FOCUSED )
173 : 0 : return m_nFocusColor;
174 : :
175 : : // ... "mouse over"
176 [ # # ]: 0 : if ( _nStatus & CONTROL_STATUS_MOUSE_HOVER )
177 : 0 : return m_nMouseHoveColor;
178 : :
179 : : OSL_FAIL( "ControlBorderManager::getControlColorByStatus: invalid status!" );
180 : 0 : return 0x00000000;
181 : : }
182 : :
183 : : //--------------------------------------------------------------------
184 : 0 : void ControlBorderManager::updateBorderStyle( const Reference< XControl >& _rxControl, const Reference< XVclWindowPeer >& _rxPeer, const BorderDescriptor& _rFallback ) SAL_THROW(())
185 : : {
186 : : OSL_PRECOND( _rxControl.is() && _rxPeer.is(), "ControlBorderManager::updateBorderStyle: invalid parameters!" );
187 : :
188 [ # # ]: 0 : ControlStatus nStatus = getControlStatus( _rxControl );
189 : 0 : BorderDescriptor aBorder;
190 : : aBorder.nBorderType = ( nStatus == CONTROL_STATUS_NONE )
191 : : ? _rFallback.nBorderType
192 [ # # ]: 0 : : VisualEffect::FLAT;
193 : : aBorder.nBorderColor = ( nStatus == CONTROL_STATUS_NONE )
194 : : ? _rFallback.nBorderColor
195 [ # # ]: 0 : : getControlColorByStatus( nStatus );
196 [ # # ]: 0 : setBorder( _rxPeer, aBorder );
197 : 0 : }
198 : :
199 : : //--------------------------------------------------------------------
200 : 0 : void ControlBorderManager::determineOriginalBorderStyle( const Reference< XControl >& _rxControl, BorderDescriptor& _rData ) const
201 : : {
202 : 0 : _rData = ControlData();
203 [ # # ]: 0 : if ( m_aFocusControl.xControl.get() == _rxControl.get() )
204 : : {
205 : 0 : _rData = m_aFocusControl;
206 : : }
207 [ # # ]: 0 : else if ( m_aMouseHoverControl.xControl.get() == _rxControl.get() )
208 : : {
209 : 0 : _rData = m_aMouseHoverControl;
210 : : }
211 : : else
212 : : {
213 [ # # ][ # # ]: 0 : ControlBag::const_iterator aPos = m_aInvalidControls.find( _rxControl );
[ # # ]
214 [ # # ]: 0 : if ( aPos != m_aInvalidControls.end() )
215 : : {
216 : 0 : _rData = *aPos;
217 : : }
218 : : else
219 : : {
220 [ # # ][ # # ]: 0 : Reference< XVclWindowPeer > xPeer( _rxControl->getPeer(), UNO_QUERY );
[ # # ]
221 [ # # ]: 0 : getBorder( xPeer, _rData );
222 : : }
223 : : }
224 : 0 : }
225 : :
226 : : //--------------------------------------------------------------------
227 : 0 : void ControlBorderManager::controlStatusGained( const Reference< XInterface >& _rxControl, ControlData& _rControlData ) SAL_THROW(())
228 : : {
229 [ # # ][ # # ]: 0 : if ( _rxControl == _rControlData.xControl )
230 : : // nothing to do - though suspicious
231 : : return;
232 : :
233 [ # # ]: 0 : Reference< XControl > xAsControl( _rxControl, UNO_QUERY );
234 : : DBG_ASSERT( xAsControl.is(), "ControlBorderManager::controlStatusGained: invalid control!" );
235 [ # # ]: 0 : if ( !xAsControl.is() )
236 : : return;
237 : :
238 : : try
239 : : {
240 [ # # ][ # # ]: 0 : Reference< XVclWindowPeer > xPeer( xAsControl->getPeer(), UNO_QUERY );
[ # # ]
241 [ # # ][ # # ]: 0 : if ( xPeer.is() && canColorBorder( xPeer ) )
[ # # ][ # # ]
242 : : {
243 : : // remember the control and it's current border color
244 : 0 : _rControlData.xControl.clear(); // so determineOriginalBorderStyle doesn't get confused
245 : :
246 [ # # ]: 0 : determineOriginalBorderStyle( xAsControl, _rControlData );
247 : :
248 [ # # ]: 0 : _rControlData.xControl = xAsControl;
249 : :
250 [ # # ]: 0 : updateBorderStyle( xAsControl, xPeer, _rControlData );
251 [ # # ]: 0 : }
252 : : }
253 [ # # ]: 0 : catch( const Exception& )
254 : : {
255 : : OSL_FAIL( "ControlBorderManager::controlStatusGained: caught an exception!" );
256 [ # # ]: 0 : }
257 : : }
258 : :
259 : : //--------------------------------------------------------------------
260 : 0 : void ControlBorderManager::controlStatusLost( const Reference< XInterface >& _rxControl, ControlData& _rControlData ) SAL_THROW(())
261 : : {
262 [ # # ]: 0 : if ( _rxControl != _rControlData.xControl )
263 : : // nothing to do
264 : 0 : return;
265 : :
266 : : OSL_PRECOND( _rControlData.xControl.is(), "ControlBorderManager::controlStatusLost: invalid control data - this will crash!" );
267 : : try
268 : : {
269 [ # # ][ # # ]: 0 : Reference< XVclWindowPeer > xPeer( _rControlData.xControl->getPeer(), UNO_QUERY );
[ # # ]
270 [ # # ][ # # ]: 0 : if ( xPeer.is() && canColorBorder( xPeer ) )
[ # # ][ # # ]
271 : : {
272 [ # # ]: 0 : ControlData aPreviousStatus( _rControlData );
273 [ # # ][ # # ]: 0 : _rControlData = ControlData();
[ # # ]
274 [ # # ][ # # ]: 0 : updateBorderStyle( aPreviousStatus.xControl, xPeer, aPreviousStatus );
275 [ # # ]: 0 : }
276 : : }
277 : 0 : catch( const Exception& )
278 : : {
279 : : OSL_FAIL( "ControlBorderManager::controlStatusLost: caught an exception!" );
280 : : }
281 : : }
282 : :
283 : : //--------------------------------------------------------------------
284 : 0 : void ControlBorderManager::enableDynamicBorderColor( )
285 : : {
286 : 0 : m_bDynamicBorderColors = true;
287 : 0 : }
288 : :
289 : : //--------------------------------------------------------------------
290 : 20 : void ControlBorderManager::disableDynamicBorderColor( )
291 : : {
292 : 20 : m_bDynamicBorderColors = false;
293 : 20 : restoreAll();
294 : 20 : }
295 : :
296 : : //--------------------------------------------------------------------
297 : 0 : void ControlBorderManager::setStatusColor( ControlStatus _nStatus, sal_Int32 _nColor )
298 : : {
299 [ # # # # ]: 0 : switch ( _nStatus )
300 : : {
301 : : case CONTROL_STATUS_FOCUSED:
302 : 0 : m_nFocusColor = _nColor;
303 : 0 : break;
304 : : case CONTROL_STATUS_MOUSE_HOVER:
305 : 0 : m_nMouseHoveColor = _nColor;
306 : 0 : break;
307 : : case CONTROL_STATUS_INVALID:
308 : 0 : m_nInvalidColor = _nColor;
309 : 0 : break;
310 : : default:
311 : : OSL_FAIL( "ControlBorderManager::setStatusColor: invalid status!" );
312 : : }
313 : 0 : }
314 : :
315 : : //--------------------------------------------------------------------
316 : 37 : void ControlBorderManager::restoreAll()
317 : : {
318 [ - + ]: 37 : if ( m_aFocusControl.xControl.is() )
319 [ # # ]: 0 : controlStatusLost( m_aFocusControl.xControl, m_aFocusControl );
320 [ - + ]: 37 : if ( m_aMouseHoverControl.xControl.is() )
321 [ # # ]: 0 : controlStatusLost( m_aMouseHoverControl.xControl, m_aMouseHoverControl );
322 : :
323 [ + - ]: 37 : ControlBag aInvalidControls;
324 [ + - ]: 37 : m_aInvalidControls.swap( aInvalidControls );
325 : :
326 [ - + ]: 74 : for ( ControlBag::const_iterator loop = aInvalidControls.begin();
327 : 37 : loop != aInvalidControls.end();
328 : : ++loop
329 : : )
330 : : {
331 [ # # ][ # # ]: 0 : Reference< XVclWindowPeer > xPeer( loop->xControl->getPeer(), UNO_QUERY );
[ # # ]
332 [ # # ]: 0 : if ( xPeer.is() )
333 : : {
334 [ # # ]: 0 : updateBorderStyle( loop->xControl, xPeer, *loop );
335 [ # # ][ # # ]: 0 : xPeer->setProperty( FM_PROP_HELPTEXT, makeAny( loop->sOriginalHelpText ) );
[ # # ][ # # ]
336 [ # # ]: 0 : setUnderline( xPeer, *loop );
337 : : }
338 : 37 : }
339 : 37 : }
340 : :
341 : : //--------------------------------------------------------------------
342 : 6 : void ControlBorderManager::focusGained( const Reference< XInterface >& _rxControl ) SAL_THROW(())
343 : : {
344 [ - + ]: 6 : if ( m_bDynamicBorderColors )
345 : 0 : controlStatusGained( _rxControl, m_aFocusControl );
346 : 6 : }
347 : :
348 : : //--------------------------------------------------------------------
349 : 6 : void ControlBorderManager::focusLost( const Reference< XInterface >& _rxControl ) SAL_THROW(())
350 : : {
351 [ - + ]: 6 : if ( m_bDynamicBorderColors )
352 : 0 : controlStatusLost( _rxControl, m_aFocusControl );
353 : 6 : }
354 : :
355 : : //--------------------------------------------------------------------
356 : 0 : void ControlBorderManager::mouseEntered( const Reference< XInterface >& _rxControl ) SAL_THROW(())
357 : : {
358 [ # # ]: 0 : if ( m_bDynamicBorderColors )
359 : 0 : controlStatusGained( _rxControl, m_aMouseHoverControl );
360 : 0 : }
361 : :
362 : : //--------------------------------------------------------------------
363 : 0 : void ControlBorderManager::mouseExited( const Reference< XInterface >& _rxControl ) SAL_THROW(())
364 : : {
365 [ # # ]: 0 : if ( m_bDynamicBorderColors )
366 : 0 : controlStatusLost( _rxControl, m_aMouseHoverControl );
367 : 0 : }
368 : :
369 : : //--------------------------------------------------------------------
370 : 17 : void ControlBorderManager::validityChanged( const Reference< XControl >& _rxControl, const Reference< XValidatableFormComponent >& _rxValidatable ) SAL_THROW(())
371 : : {
372 : : try
373 : : {
374 : : OSL_ENSURE( _rxControl.is(), "ControlBorderManager::validityChanged: invalid control!" );
375 : : OSL_ENSURE( _rxValidatable.is(), "ControlBorderManager::validityChanged: invalid validatable!" );
376 : :
377 [ + - ][ + - ]: 17 : Reference< XVclWindowPeer > xPeer( _rxControl.is() ? _rxControl->getPeer() : Reference< XWindowPeer >(), UNO_QUERY );
[ + - ][ + - ]
378 [ - + ][ - + ]: 17 : if ( !xPeer.is() || !_rxValidatable.is() )
[ + - ]
379 : : return;
380 : :
381 [ + - ]: 17 : ControlData aData( _rxControl );
382 : :
383 [ + - ][ + - ]: 17 : if ( _rxValidatable->isValid() )
[ + - ]
384 : : {
385 [ + - ]: 17 : ControlBag::iterator aPos = m_aInvalidControls.find( aData );
386 [ - + ]: 17 : if ( aPos != m_aInvalidControls.end() )
387 : : { // invalid before, valid now
388 [ # # ]: 0 : ControlData aOriginalLayout( *aPos );
389 [ # # ]: 0 : m_aInvalidControls.erase( aPos );
390 : :
391 : : // restore all the things we used to indicate invalidity
392 [ # # ]: 0 : if ( m_bDynamicBorderColors )
393 [ # # ]: 0 : updateBorderStyle( _rxControl, xPeer, aOriginalLayout );
394 [ # # ][ # # ]: 0 : xPeer->setProperty( FM_PROP_HELPTEXT, makeAny( aOriginalLayout.sOriginalHelpText ) );
[ # # ][ # # ]
395 [ # # ][ # # ]: 17 : setUnderline( xPeer, aOriginalLayout );
396 : : }
397 : : return;
398 : : }
399 : :
400 : : // we're here in the INVALID case
401 [ # # ][ # # ]: 0 : if ( m_aInvalidControls.find( _rxControl ) == m_aInvalidControls.end() )
[ # # ][ # # ]
402 : : { // valid before, invalid now
403 : :
404 : : // remember the current border
405 [ # # ]: 0 : determineOriginalBorderStyle( _rxControl, aData );
406 : : // and tool tip
407 [ # # ][ # # ]: 0 : xPeer->getProperty( FM_PROP_HELPTEXT ) >>= aData.sOriginalHelpText;
[ # # ]
408 : : // and font
409 [ # # ]: 0 : getUnderline( xPeer, aData );
410 : :
411 [ # # ]: 0 : m_aInvalidControls.insert( aData );
412 : :
413 : : // update the border to the new invalidity
414 [ # # ][ # # ]: 0 : if ( m_bDynamicBorderColors && canColorBorder( xPeer ) )
[ # # ][ # # ]
415 [ # # ]: 0 : updateBorderStyle( _rxControl, xPeer, aData );
416 : : else
417 : : {
418 : : // and also the new font
419 [ # # ]: 0 : setUnderline( xPeer, UnderlineDescriptor( com::sun::star::awt::FontUnderline::WAVE, m_nInvalidColor ) );
420 : : }
421 : : }
422 : :
423 : : // update the explanation for invalidity (this is always done, even if the validity did not change)
424 [ # # ][ # # ]: 0 : Reference< XValidator > xValidator = _rxValidatable->getValidator();
425 : : OSL_ENSURE( xValidator.is(), "ControlBorderManager::validityChanged: invalid, but no validator?" );
426 [ # # ][ # # ]: 0 : ::rtl::OUString sExplainInvalidity = xValidator.is() ? xValidator->explainInvalid( _rxValidatable->getCurrentValue() ) : ::rtl::OUString();
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
427 [ # # ][ # # ]: 17 : xPeer->setProperty( FM_PROP_HELPTEXT, makeAny( sExplainInvalidity ) );
[ # # ][ # # ]
[ + - ][ + - ]
[ - + ][ # # ]
428 : : }
429 : 0 : catch( const Exception& )
430 : : {
431 : : OSL_FAIL( "ControlBorderManager::validityChanged: caught an exception!" );
432 : : }
433 : : }
434 : :
435 : : //........................................................................
436 : : } // namespace svxform
437 : : //........................................................................
438 : :
439 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|