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 //	my own includes
25 //____________________________________________________________________________________________________________
26 
27 #include "progressbar.hxx"
28 
29 //____________________________________________________________________________________________________________
30 //	includes of other projects
31 //____________________________________________________________________________________________________________
32 #include <com/sun/star/awt/GradientStyle.hpp>
33 #include <com/sun/star/awt/RasterOperation.hpp>
34 #include <com/sun/star/awt/Gradient.hpp>
35 #include <com/sun/star/awt/XGraphics.hpp>
36 #include <tools/debug.hxx>
37 #include <cppuhelper/typeprovider.hxx>
38 
39 #include <math.h>
40 #include <limits.h>
41 
42 //____________________________________________________________________________________________________________
43 //	includes of my project
44 //____________________________________________________________________________________________________________
45 
46 //____________________________________________________________________________________________________________
47 //	namespace
48 //____________________________________________________________________________________________________________
49 
50 using namespace	::cppu					;
51 using namespace	::osl					;
52 using namespace	::rtl					;
53 using namespace	::com::sun::star::uno	;
54 using namespace	::com::sun::star::lang	;
55 using namespace	::com::sun::star::awt	;
56 
57 namespace unocontrols{
58 
59 //____________________________________________________________________________________________________________
60 //	construct/destruct
61 //____________________________________________________________________________________________________________
62 
63 ProgressBar::ProgressBar( const Reference< XMultiServiceFactory >& xFactory )
64 	: BaseControl		 	(	 xFactory					)
65 	, m_bHorizontal			(	 DEFAULT_HORIZONTAL			)
66 	, m_aBlockSize			(	 DEFAULT_BLOCKDIMENSION		)
67 	, m_nForegroundColor	(	 DEFAULT_FOREGROUNDCOLOR	)
68 	, m_nBackgroundColor	(	 DEFAULT_BACKGROUNDCOLOR	)
69 	, m_nMinRange		 	(	 DEFAULT_MINRANGE			)
70 	, m_nMaxRange		 	(	 DEFAULT_MAXRANGE			)
71 	, m_nBlockValue		 	(	 DEFAULT_BLOCKVALUE			)
72 	, m_nValue		 	 	(	 DEFAULT_VALUE				)
73 {
74 }
75 
76 ProgressBar::~ProgressBar()
77 {
78 }
79 
80 //____________________________________________________________________________________________________________
81 //	XInterface
82 //____________________________________________________________________________________________________________
83 
84 Any SAL_CALL ProgressBar::queryInterface( const Type& rType ) throw( RuntimeException )
85 {
86 	// Attention:
87 	//	Don't use mutex or guard in this method!!! Is a method of XInterface.
88 	Any aReturn ;
89 	Reference< XInterface > xDel = BaseControl::impl_getDelegator();
90 	if ( xDel.is() )
91 	{
92 		// If an delegator exist, forward question to his queryInterface.
93 		// Delegator will ask his own queryAggregation!
94 		aReturn = xDel->queryInterface( rType );
95 	}
96 	else
97 	{
98 		// If an delegator unknown, forward question to own queryAggregation.
99 		aReturn = queryAggregation( rType );
100 	}
101 
102 	return aReturn ;
103 }
104 
105 //____________________________________________________________________________________________________________
106 //	XInterface
107 //____________________________________________________________________________________________________________
108 
109 void SAL_CALL ProgressBar::acquire() throw()
110 {
111 	// Attention:
112 	//	Don't use mutex or guard in this method!!! Is a method of XInterface.
113 
114 	// Forward to baseclass
115 	BaseControl::acquire();
116 }
117 
118 //____________________________________________________________________________________________________________
119 //	XInterface
120 //____________________________________________________________________________________________________________
121 
122 void SAL_CALL ProgressBar::release() throw()
123 {
124 	// Attention:
125 	//	Don't use mutex or guard in this method!!! Is a method of XInterface.
126 
127 	// Forward to baseclass
128 	BaseControl::release();
129 }
130 
131 //____________________________________________________________________________________________________________
132 //	XTypeProvider
133 //____________________________________________________________________________________________________________
134 
135 Sequence< Type > SAL_CALL ProgressBar::getTypes() throw( RuntimeException )
136 {
137 	// Optimize this method !
138 	// We initialize a static variable only one time. And we don't must use a mutex at every call!
139 	// For the first call; pTypeCollection is NULL - for the second call pTypeCollection is different from NULL!
140 	static OTypeCollection* pTypeCollection = NULL ;
141 
142 	if ( pTypeCollection == NULL )
143 	{
144 		// Ready for multithreading; get global mutex for first call of this method only! see before
145 		MutexGuard aGuard( Mutex::getGlobalMutex() );
146 
147 		// Control these pointer again ... it can be, that another instance will be faster then these!
148 		if ( pTypeCollection == NULL )
149 		{
150 			// Create a static typecollection ...
151 			static OTypeCollection aTypeCollection	(	::getCppuType(( const Reference< XControlModel	>*)NULL )	,
152 												  		::getCppuType(( const Reference< XProgressBar	>*)NULL )	,
153 														BaseControl::getTypes()
154 													);
155 			// ... and set his address to static pointer!
156 			pTypeCollection = &aTypeCollection ;
157 		}
158 	}
159 
160 	return pTypeCollection->getTypes();
161 }
162 
163 //____________________________________________________________________________________________________________
164 //	XAggregation
165 //____________________________________________________________________________________________________________
166 
167 Any SAL_CALL ProgressBar::queryAggregation( const Type& aType ) throw( RuntimeException )
168 {
169 	// Ask for my own supported interfaces ...
170 	// Attention: XTypeProvider and XInterface are supported by OComponentHelper!
171 	Any aReturn	( ::cppu::queryInterface(	aType					   				,
172 									   		static_cast< XControlModel*	> ( this )	,
173 									   		static_cast< XProgressBar*	> ( this )
174 										)
175 				);
176 
177 	// If searched interface not supported by this class ...
178 	if ( aReturn.hasValue() == sal_False )
179 	{
180 		// ... ask baseclasses.
181 		aReturn = BaseControl::queryAggregation( aType );
182 	}
183 
184 	return aReturn ;
185 }
186 
187 //____________________________________________________________________________________________________________
188 //	XProgressBar
189 //____________________________________________________________________________________________________________
190 
191 void SAL_CALL ProgressBar::setForegroundColor( sal_Int32 nColor ) throw( RuntimeException )
192 {
193 	// Ready for multithreading
194 	MutexGuard	aGuard (m_aMutex) ;
195 
196 	// Safe color for later use.
197 	m_nForegroundColor = nColor ;
198 
199 	// Repaint control
200 	impl_paint ( 0, 0, impl_getGraphicsPeer() ) ;
201 }
202 
203 //____________________________________________________________________________________________________________
204 //	XProgressBar
205 //____________________________________________________________________________________________________________
206 
207 void SAL_CALL ProgressBar::setBackgroundColor ( sal_Int32 nColor ) throw( RuntimeException )
208 {
209 	// Ready for multithreading
210 	MutexGuard	aGuard (m_aMutex) ;
211 
212 	// Safe color for later use.
213 	m_nBackgroundColor = nColor ;
214 
215 	// Repaint control
216 	impl_paint ( 0, 0, impl_getGraphicsPeer() ) ;
217 }
218 
219 //____________________________________________________________________________________________________________
220 //	XProgressBar
221 //____________________________________________________________________________________________________________
222 
223 void SAL_CALL ProgressBar::setValue ( sal_Int32 nValue ) throw( RuntimeException )
224 {
225 	// This method is defined for follow things:
226 	//		1) Values >= _nMinRange
227 	//		2) Values <= _nMaxRange
228 
229 	// Ready for multithreading
230 	MutexGuard aGuard (m_aMutex) ;
231 
232 	// save impossible cases
233 	// This method is only defined for valid values
234 	DBG_ASSERT ( (( nValue >= m_nMinRange ) && ( nValue <= m_nMaxRange )), "ProgressBar::setValue()\nNot valid value.\n" ) ;
235 
236 	// If new value not valid ... do nothing in release version!
237 	if (
238 		( nValue >= m_nMinRange ) &&
239 		( nValue <= m_nMaxRange )
240 	   )
241 	{
242 		// New value is ok => save this
243 		m_nValue = nValue ;
244 
245 		// Repaint to display changes
246 		impl_paint ( 0, 0, impl_getGraphicsPeer() ) ;
247 	}
248 }
249 
250 //____________________________________________________________________________________________________________
251 //	XProgressBar
252 //____________________________________________________________________________________________________________
253 
254 void SAL_CALL ProgressBar::setRange ( sal_Int32 nMin, sal_Int32 nMax ) throw( RuntimeException )
255 {
256 	// This method is defined for follow things:
257 	//		1) All values of sal_Int32
258 	//		2) Min < Max
259 	//		3) Min > Max
260 
261 	// save impossible cases
262 	// This method is only defined for valid values
263 	// If you ignore this, the release version wil produce an error "division by zero" in "ProgressBar::setValue()"!
264 	DBG_ASSERT ( ( nMin != nMax ) , "ProgressBar::setRange()\nValues for MIN and MAX are the same. This is not allowed!\n" ) ;
265 
266 	// Ready for multithreading
267 	MutexGuard	aGuard (m_aMutex) ;
268 
269 	// control the values for min and max
270 	if ( nMin < nMax )
271 	{
272 		// Take correct Min and Max
273 		m_nMinRange = nMin	;
274 		m_nMaxRange = nMax	;
275 	}
276 	else
277 	{
278 		// Change Min and Max automaticly
279 		m_nMinRange = nMax	;
280 		m_nMaxRange = nMin	;
281 	}
282 
283     // assure that m_nValue is within the range
284 	if (!(m_nMinRange < m_nValue  &&  m_nValue < m_nMaxRange))
285 		m_nValue = m_nMinRange;
286 
287     impl_recalcRange () ;
288 
289 	// Do not repaint the control at this place!!!
290 	// An old "m_nValue" is set and can not be correct for this new range.
291 	// Next call of "ProgressBar::setValue()" do this.
292 }
293 
294 //____________________________________________________________________________________________________________
295 //	XProgressBar
296 //____________________________________________________________________________________________________________
297 
298 sal_Int32 SAL_CALL ProgressBar::getValue () throw( RuntimeException )
299 {
300 	// Ready for multithreading
301 	MutexGuard aGuard (m_aMutex) ;
302 
303 	return ( m_nValue ) ;
304 }
305 
306 //____________________________________________________________________________________________________________
307 //	XWindow
308 //____________________________________________________________________________________________________________
309 
310 void SAL_CALL ProgressBar::setPosSize ( sal_Int32 nX, sal_Int32 nY, sal_Int32 nWidth, sal_Int32 nHeight, sal_Int16 nFlags ) throw( RuntimeException )
311 {
312 	// Take old size BEFORE you set the new values at baseclass!
313 	// You will control changes. At the other way, the values are the same!
314 	Rectangle aBasePosSize = getPosSize () ;
315 	BaseControl::setPosSize (nX, nY, nWidth, nHeight, nFlags) ;
316 
317 	// Do only, if size has changed.
318 	if (
319 		( nWidth  != aBasePosSize.Width		) ||
320 		( nHeight != aBasePosSize.Height	)
321 	   )
322 	{
323 		impl_recalcRange	(							) ;
324 		impl_paint 			( 0, 0, impl_getGraphicsPeer ()	) ;
325 	}
326 }
327 
328 //____________________________________________________________________________________________________________
329 //	XControl
330 //____________________________________________________________________________________________________________
331 
332 sal_Bool SAL_CALL ProgressBar::setModel( const Reference< XControlModel >& /*xModel*/ ) throw( RuntimeException )
333 {
334 	// A model is not possible for this control.
335 	return sal_False ;
336 }
337 
338 //____________________________________________________________________________________________________________
339 //	XControl
340 //____________________________________________________________________________________________________________
341 
342 Reference< XControlModel > SAL_CALL ProgressBar::getModel() throw( RuntimeException )
343 {
344 	// A model is not possible for this control.
345 	return Reference< XControlModel >();
346 }
347 
348 //____________________________________________________________________________________________________________
349 //	impl but public method to register service
350 //____________________________________________________________________________________________________________
351 
352 const Sequence< OUString > ProgressBar::impl_getStaticSupportedServiceNames()
353 {
354 	MutexGuard aGuard( Mutex::getGlobalMutex() );
355     Sequence< OUString > seqServiceNames( 1 );
356     seqServiceNames.getArray() [0] = OUString::createFromAscii( SERVICENAME_PROGRESSBAR );
357     return seqServiceNames ;
358 }
359 
360 //____________________________________________________________________________________________________________
361 //	impl but public method to register service
362 //____________________________________________________________________________________________________________
363 
364 const OUString ProgressBar::impl_getStaticImplementationName()
365 {
366 	return OUString::createFromAscii( IMPLEMENTATIONNAME_PROGRESSBAR );
367 }
368 
369 //____________________________________________________________________________________________________________
370 //	protected method
371 //____________________________________________________________________________________________________________
372 
373 void ProgressBar::impl_paint ( sal_Int32 nX, sal_Int32 nY, const Reference< XGraphics > & rGraphics )
374 {
375 	// save impossible cases
376 	DBG_ASSERT ( rGraphics.is(), "ProgressBar::paint()\nCalled with invalid Reference< XGraphics > ." ) ;
377 
378 	// This paint method ist not buffered !!
379 	// Every request paint the completely control. ( but only, if peer exist )
380  	if ( rGraphics.is () )
381 	{
382 		MutexGuard	aGuard (m_aMutex) ;
383 
384 		// Clear background
385 		// (same color for line and fill)
386 		rGraphics->setFillColor ( m_nBackgroundColor						) ;
387 		rGraphics->setLineColor ( m_nBackgroundColor						) ;
388 		rGraphics->drawRect		( nX, nY, impl_getWidth(), impl_getHeight()	) ;
389 
390 		// same color for line and fill for blocks
391 		rGraphics->setFillColor ( m_nForegroundColor ) ;
392 		rGraphics->setLineColor ( m_nForegroundColor ) ;
393 
394         sal_Int32   nBlockStart     =   0                                                                           ;   // = left site of new block
395         sal_Int32   nBlockCount     =   m_nBlockValue!=0.00 ? (sal_Int32)((m_nValue-m_nMinRange)/m_nBlockValue) : 0 ;   // = number of next block
396 
397 		// Draw horizontal progressbar
398 		// decision in "recalcRange()"
399 		if (m_bHorizontal)
400 		{
401 			// Step to left side of window
402 			nBlockStart	= nX ;
403 
404 			for ( sal_Int16 i=1; i<=nBlockCount; ++i )
405 			{
406 				// step free field
407 				nBlockStart	+=	FREESPACE	;
408 				// paint block
409 				rGraphics->drawRect (nBlockStart, nY+FREESPACE, m_aBlockSize.Width, m_aBlockSize.Height) ;
410 				// step next free field
411 				nBlockStart	+=	m_aBlockSize.Width ;
412 			}
413 		}
414 		// draw vertikal progressbar
415 		// decision in "recalcRange()"
416 		else
417 		{
418 			// step to bottom side of window
419 			nBlockStart	 =	nY+impl_getHeight() ;
420 			nBlockStart	-=	m_aBlockSize.Height ;
421 
422 			for ( sal_Int16 i=1; i<=nBlockCount; ++i )
423 			{
424 				// step free field
425 				nBlockStart	-=	FREESPACE	;
426 				// paint block
427 				rGraphics->drawRect (nX+FREESPACE, nBlockStart, m_aBlockSize.Width, m_aBlockSize.Height) ;
428 				// step next free field
429 				nBlockStart	-=	m_aBlockSize.Height;
430 			}
431 		}
432 
433 		// Paint shadow border around the progressbar
434 		rGraphics->setLineColor ( LINECOLOR_SHADOW  						) ;
435 		rGraphics->drawLine		( nX, nY, impl_getWidth(), nY 				) ;
436 		rGraphics->drawLine		( nX, nY, nX		  	 , impl_getHeight() ) ;
437 
438 		rGraphics->setLineColor ( LINECOLOR_BRIGHT  															) ;
439 		rGraphics->drawLine		( impl_getWidth()-1, impl_getHeight()-1, impl_getWidth()-1, nY 					) ;
440 		rGraphics->drawLine		( impl_getWidth()-1, impl_getHeight()-1, nX		   		  , impl_getHeight()-1	) ;
441 	}
442 }
443 
444 //____________________________________________________________________________________________________________
445 //	protected method
446 //____________________________________________________________________________________________________________
447 
448 void ProgressBar::impl_recalcRange ()
449 {
450 	MutexGuard	aGuard (m_aMutex) ;
451 
452     sal_Int32 nWindowWidth  = impl_getWidth()  ;
453     sal_Int32 nWindowHeight = impl_getHeight() ;
454     double    fBlockHeight                     ;
455     double    fBlockWidth                      ;
456     double    fMaxBlocks                       ;
457 
458     if( nWindowWidth > nWindowHeight )
459 	{
460         m_bHorizontal = sal_True                            ;
461         fBlockHeight  = (nWindowHeight-(2*FREESPACE))       ;
462         fBlockWidth   = fBlockHeight                        ;
463         fMaxBlocks    = nWindowWidth/(fBlockWidth+FREESPACE);
464     }
465     else
466     {
467         m_bHorizontal = sal_False                             ;
468         fBlockWidth   = (nWindowWidth-(2*FREESPACE))          ;
469         fBlockHeight  = fBlockWidth                           ;
470         fMaxBlocks    = nWindowHeight/(fBlockHeight+FREESPACE);
471     }
472 
473     double fRange       = m_nMaxRange-m_nMinRange    ;
474     double fBlockValue  = fRange/fMaxBlocks          ;
475 
476     m_nBlockValue       = fBlockValue            ;
477     m_aBlockSize.Height = (sal_Int32)fBlockHeight;
478     m_aBlockSize.Width  = (sal_Int32)fBlockWidth ;
479 /*
480 		// Calculate count of blocks for actual size
481 		// (prevent error "division by zero")
482 		if ( nHeight == 0 )
483 		{
484 			nHeight = 1 ;
485 		}
486 
487 		nMaxBlock	 =	nWidth / nHeight	;
488 		nMaxBlock	*=	2					;
489 
490 		// prevent error "division by zero"
491 		if ( nMaxBlock == 0 )
492 		{
493 			nMaxBlock = 1 ;
494 		}
495 
496 		// Calculate new value and new size for ONE block.
497 
498 		// Do not a calculation like this: "m_nBlockValue=(m_nMaxRange-m_nMinRange)/nMaxBlock"	!
499 		// If difference between m_nMaxRange and m_nMinRange to large, it give an overflow and a
500 		// following error "division by zero" in method "paint() ... nBlockCount=nDifference/m_nBlockValue ..."
501 
502 		// Overflow ? => example: _I32_MAX - _I32_MIN = -1 and not _UI32_MAX !!!
503 
504 		m_nBlockValue		=	( m_nMaxRange / nMaxBlock ) - ( m_nMinRange / nMaxBlock ) ;
505 		m_aBlockSize.Height	=	( nHeight - ( FREESPACE * 2 )							) ;
506 		m_aBlockSize.Width	=	( ( nWidth / nMaxBlock ) - FREESPACE					) ;
507 	}
508 	else
509 	{
510 		// Don't forget to save this state! Used in "ProgressBar::paint()"
511 		m_bHorizontal = sal_False ;
512 
513         double fBlockWidth  = (nHeight-(2*FREESPACE))       ;
514         double fBlockHeight = fBlockWidth                   ;
515         double fRange       = m_nMaxRange-m_nMinRange       ;
516         double fBlockValue  = fRange/(fBlockWidth+FREESPACE);
517 
518         m_nBlockValue       = fBlockValue            ;
519         m_aBlockSize.Height = (sal_Int32)fBlockHeight;
520         m_aBlockSize.Width  = (sal_Int32)fBlockWidth ;
521 
522 		// Calculate count of blocks for actual size
523 		// (prevent error "division by zero")
524 		if ( nWidth == 0 )
525 		{
526 			nWidth = 1 ;
527 		}
528 
529 		nMaxBlock	 =	nHeight / nWidth	;
530 		nMaxBlock	*=	2					;
531 
532 		// prevent error "division by zero"
533 		if ( nMaxBlock == 0 )
534 		{
535 			nMaxBlock = 1 ;
536 		}
537 
538 		// Calculate new value and new size for ONE block.
539 
540 		// Do not a calculation like this: "m_nBlockValue=(m_nMaxRange-m_nMinRange)/nMaxBlock"	!
541 		// If difference between m_nMaxRange and m_nMinRange to large, it give an overflow and a
542 		// following error "division by zero" in method "paint() ... nBlockCount=nDifference/m_nBlockValue ..."
543 
544 		// Overflow ? => example: _I32_MAX - _I32_MIN = -1 and not _UI32_MAX !!!
545 
546 		m_nBlockValue		=	( m_nMaxRange / nMaxBlock ) - ( m_nMinRange / nMaxBlock ) ;
547 		m_aBlockSize.Height	=	( ( nHeight / nMaxBlock ) - FREESPACE					) ;
548 		m_aBlockSize.Width	=	( nWidth - ( FREESPACE * 2 )							) ;
549 
550 	}
551 */
552 }
553 
554 }	// namespace unocontrols
555