/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

//____________________________________________________________________________________________________________
//	my own includes
//____________________________________________________________________________________________________________

#include "progressmonitor.hxx"

//____________________________________________________________________________________________________________
//	includes of other projects
//____________________________________________________________________________________________________________
#include <com/sun/star/awt/GradientStyle.hpp>
#include <com/sun/star/awt/RasterOperation.hpp>
#include <com/sun/star/awt/Gradient.hpp>
#include <com/sun/star/awt/XGraphics.hpp>
#include <com/sun/star/awt/PosSize.hpp>
#include <cppuhelper/typeprovider.hxx>
#include <tools/debug.hxx>
#include <tools/solar.h>

//____________________________________________________________________________________________________________
//	includes of my project
//____________________________________________________________________________________________________________
#include "progressbar.hxx"

//____________________________________________________________________________________________________________
//	namespace
//____________________________________________________________________________________________________________

using namespace	::cppu					;
using namespace	::osl					;
using namespace	::rtl					;
using namespace	::com::sun::star::uno	;
using namespace	::com::sun::star::lang	;
using namespace	::com::sun::star::awt	;

namespace unocontrols{

//____________________________________________________________________________________________________________
//	construct/destruct
//____________________________________________________________________________________________________________

ProgressMonitor::ProgressMonitor( const Reference< XMultiServiceFactory >& xFactory )
	: BaseContainerControl	( xFactory	)
{
	// Its not allowed to work with member in this method (refcounter !!!)
	// But with a HACK (++refcount) its "OK" :-(
	++m_refCount ;

	// Create instances for fixedtext, button and progress ...
	m_xTopic_Top	= Reference< XFixedText > 		( xFactory->createInstance ( OUString::createFromAscii( FIXEDTEXT_SERVICENAME	) ), UNO_QUERY ) ;
	m_xText_Top		= Reference< XFixedText > 		( xFactory->createInstance ( OUString::createFromAscii( FIXEDTEXT_SERVICENAME	) ), UNO_QUERY ) ;
	m_xTopic_Bottom	= Reference< XFixedText > 		( xFactory->createInstance ( OUString::createFromAscii( FIXEDTEXT_SERVICENAME	) ), UNO_QUERY ) ;
	m_xText_Bottom	= Reference< XFixedText > 		( xFactory->createInstance ( OUString::createFromAscii( FIXEDTEXT_SERVICENAME	) ), UNO_QUERY ) ;
	m_xButton		= Reference< XButton > 			( xFactory->createInstance ( OUString::createFromAscii( BUTTON_SERVICENAME		) ), UNO_QUERY ) ;
	m_xProgressBar	= Reference< XProgressBar >  	( xFactory->createInstance ( OUString::createFromAscii( SERVICENAME_PROGRESSBAR	) ), UNO_QUERY ) ;

	// ... cast controls to Reference< XControl >  (for "setModel"!) ...
	Reference< XControl > 	xRef_Topic_Top		( m_xTopic_Top	  , UNO_QUERY ) ;
	Reference< XControl > 	xRef_Text_Top		( m_xText_Top	  , UNO_QUERY ) ;
	Reference< XControl > 	xRef_Topic_Bottom	( m_xTopic_Bottom , UNO_QUERY ) ;
	Reference< XControl > 	xRef_Text_Bottom	( m_xText_Bottom  , UNO_QUERY ) ;
	Reference< XControl > 	xRef_Button			( m_xButton		  , UNO_QUERY ) ;
	Reference< XControl > 	xRef_ProgressBar	( m_xProgressBar  , UNO_QUERY ) ;

	// ... set models ...
	xRef_Topic_Top->setModel		( Reference< XControlModel >  ( xFactory->createInstance ( OUString::createFromAscii( FIXEDTEXT_MODELNAME	) ), UNO_QUERY ) ) ;
	xRef_Text_Top->setModel			( Reference< XControlModel >  ( xFactory->createInstance ( OUString::createFromAscii( FIXEDTEXT_MODELNAME	) ), UNO_QUERY ) ) ;
	xRef_Topic_Bottom->setModel		( Reference< XControlModel >  ( xFactory->createInstance ( OUString::createFromAscii( FIXEDTEXT_MODELNAME	) ), UNO_QUERY ) ) ;
	xRef_Text_Bottom->setModel		( Reference< XControlModel >  ( xFactory->createInstance ( OUString::createFromAscii( FIXEDTEXT_MODELNAME	) ), UNO_QUERY ) ) ;
	xRef_Button->setModel			( Reference< XControlModel >  ( xFactory->createInstance ( OUString::createFromAscii( BUTTON_MODELNAME		) ), UNO_QUERY ) ) ;
	// ProgressBar has no model !!!

	// ... and add controls to basecontainercontrol!
	addControl ( OUString::createFromAscii( CONTROLNAME_TEXT		) , xRef_Topic_Top   	) ;
	addControl ( OUString::createFromAscii( CONTROLNAME_TEXT		) , xRef_Text_Top	   	) ;
	addControl ( OUString::createFromAscii( CONTROLNAME_TEXT		) , xRef_Topic_Bottom	) ;
	addControl ( OUString::createFromAscii( CONTROLNAME_TEXT		) , xRef_Text_Bottom	) ;
	addControl ( OUString::createFromAscii( CONTROLNAME_BUTTON		) , xRef_Button			) ;
	addControl ( OUString::createFromAscii( CONTROLNAME_PROGRESSBAR	) , xRef_ProgressBar 	) ;

	// FixedText make it automaticly visible by himself ... but not the progressbar !!!
	// it must be set explicitly
	Reference< XWindow > xWindowRef_ProgressBar( m_xProgressBar, UNO_QUERY );
	xWindowRef_ProgressBar->setVisible( sal_True );

	// Reset to defaults !!!
	// (progressbar take automaticly its own defaults)
	m_xButton->setLabel			( OUString::createFromAscii( DEFAULT_BUTTONLABEL	) ) ;
	m_xTopic_Top->setText		( OUString::createFromAscii( DEFAULT_TOPIC			) ) ;
	m_xText_Top->setText		( OUString::createFromAscii( DEFAULT_TEXT			) ) ;
	m_xTopic_Bottom->setText	( OUString::createFromAscii( DEFAULT_TOPIC			) ) ;
	m_xText_Bottom->setText		( OUString::createFromAscii( DEFAULT_TEXT			) ) ;

	--m_refCount ;

	// Initialize info lists for fixedtext's
	m_pTextlist_Top		= new IMPL_Textlist ;
	m_pTextlist_Bottom	= new IMPL_Textlist ;
}

ProgressMonitor::~ProgressMonitor()
{
	impl_cleanMemory () ;
}

//____________________________________________________________________________________________________________
//	XInterface
//____________________________________________________________________________________________________________

Any SAL_CALL ProgressMonitor::queryInterface( const Type& rType ) throw( RuntimeException )
{
	// Attention:
	//	Don't use mutex or guard in this method!!! Is a method of XInterface.
	Any aReturn ;
	Reference< XInterface > xDel = BaseContainerControl::impl_getDelegator();
	if ( xDel.is() )
	{
		// If an delegator exist, forward question to his queryInterface.
		// Delegator will ask his own queryAggregation!
		aReturn = xDel->queryInterface( rType );
	}
	else
	{
		// If an delegator unknown, forward question to own queryAggregation.
		aReturn = queryAggregation( rType );
	}

	return aReturn ;
}

//____________________________________________________________________________________________________________
//	XInterface
//____________________________________________________________________________________________________________

void SAL_CALL ProgressMonitor::acquire() throw()
{
	// Attention:
	//	Don't use mutex or guard in this method!!! Is a method of XInterface.

	// Forward to baseclass
	BaseControl::acquire();
}

//____________________________________________________________________________________________________________
//	XInterface
//____________________________________________________________________________________________________________

void SAL_CALL ProgressMonitor::release() throw()
{
	// Attention:
	//	Don't use mutex or guard in this method!!! Is a method of XInterface.

	// Forward to baseclass
	BaseControl::release();
}

//____________________________________________________________________________________________________________
//	XTypeProvider
//____________________________________________________________________________________________________________

Sequence< Type > SAL_CALL ProgressMonitor::getTypes() throw( RuntimeException )
{
	// Optimize this method !
	// We initialize a static variable only one time. And we don't must use a mutex at every call!
	// For the first call; pTypeCollection is NULL - for the second call pTypeCollection is different from NULL!
	static OTypeCollection* pTypeCollection = NULL ;

	if ( pTypeCollection == NULL )
	{
		// Ready for multithreading; get global mutex for first call of this method only! see before
		MutexGuard aGuard( Mutex::getGlobalMutex() );

		// Control these pointer again ... it can be, that another instance will be faster then these!
		if ( pTypeCollection == NULL )
		{
			// Create a static typecollection ...
			static OTypeCollection aTypeCollection	(	::getCppuType(( const Reference< XLayoutConstrains	>*)NULL )	,
												  		::getCppuType(( const Reference< XButton			>*)NULL )	,
												  		::getCppuType(( const Reference< XProgressMonitor	>*)NULL )	,
														BaseContainerControl::getTypes()
													);
			// ... and set his address to static pointer!
			pTypeCollection = &aTypeCollection ;
		}
	}

	return pTypeCollection->getTypes();
}

//____________________________________________________________________________________________________________
//	XAggregation
//____________________________________________________________________________________________________________

Any SAL_CALL ProgressMonitor::queryAggregation( const Type& aType ) throw( RuntimeException )
{
	// Ask for my own supported interfaces ...
	// Attention: XTypeProvider and XInterface are supported by OComponentHelper!
	Any aReturn	( ::cppu::queryInterface(	aType					   					,
									   		static_cast< XLayoutConstrains*	> ( this )	,
									   		static_cast< XButton*			> ( this )	,
									   		static_cast< XProgressMonitor*	> ( this )
										)
				);

	// If searched interface not supported by this class ...
	if ( aReturn.hasValue() == sal_False )
	{
		// ... ask baseclasses.
		aReturn = BaseControl::queryAggregation( aType );
	}

	return aReturn ;
}

//____________________________________________________________________________________________________________
//	XProgressMonitor
//____________________________________________________________________________________________________________

void SAL_CALL ProgressMonitor::addText( const OUString& rTopic, const OUString& rText, sal_Bool bbeforeProgress ) throw( RuntimeException )
{
	// Safe impossible cases
	// Check valid call of this method.
	DBG_ASSERT ( impl_debug_checkParameter ( rTopic, rText, bbeforeProgress )	, "ProgressMonitor::addText()\nCall without valid parameters!\n") ;
	DBG_ASSERT ( !(impl_searchTopic ( rTopic, bbeforeProgress ) != NULL )		, "ProgresMonitor::addText()\nThe text already exist.\n"		) ;

	// Do nothing (in Release), if topic already exist.
	if ( impl_searchTopic ( rTopic, bbeforeProgress ) != NULL )
	{
		return ;
	}

	// Else ... take memory for new item ...
	IMPL_TextlistItem*	pTextItem = new IMPL_TextlistItem ;

	if ( pTextItem != NULL )
	{
		// Set values ...
		pTextItem->sTopic	= rTopic ;
		pTextItem->sText	= rText	;

		// Ready for multithreading
		MutexGuard aGuard ( m_aMutex ) ;

		// ... and insert it in right list.
		if ( bbeforeProgress == sal_True )
		{
			m_pTextlist_Top->Insert    ( pTextItem, LIST_APPEND ) ;
		}
		else
		{
			m_pTextlist_Bottom->Insert ( pTextItem, LIST_APPEND ) ;
		}
	}

	// ... update window
	impl_rebuildFixedText	() ;
	impl_recalcLayout		() ;
}

//____________________________________________________________________________________________________________
//	XProgressMonitor
//____________________________________________________________________________________________________________

void SAL_CALL ProgressMonitor::removeText ( const OUString& rTopic, sal_Bool bbeforeProgress ) throw( RuntimeException )
{
	// Safe impossible cases
	// Check valid call of this method.
	DBG_ASSERT ( impl_debug_checkParameter ( rTopic, bbeforeProgress ), "ProgressMonitor::removeText()\nCall without valid parameters!\n" ) ;

	// Search the topic ...
	IMPL_TextlistItem* pSearchItem = impl_searchTopic ( rTopic, bbeforeProgress ) ;

	if ( pSearchItem != NULL )
	{
		// Ready for multithreading
		MutexGuard aGuard ( m_aMutex ) ;

		// ... delete item from right list ...
		if ( bbeforeProgress == sal_True )
		{
			m_pTextlist_Top->Remove	   ( pSearchItem ) ;
		}
		else
		{
			m_pTextlist_Bottom->Remove ( pSearchItem ) ;
		}

		delete pSearchItem ;

		// ... and update window.
		impl_rebuildFixedText	() ;
		impl_recalcLayout		() ;
	}
}

//____________________________________________________________________________________________________________
//	XProgressMonitor
//____________________________________________________________________________________________________________

void SAL_CALL ProgressMonitor::updateText ( const OUString& rTopic, const OUString& rText, sal_Bool bbeforeProgress ) throw( RuntimeException )
{
	// Safe impossible cases
	// Check valid call of this method.
	DBG_ASSERT ( impl_debug_checkParameter ( rTopic, rText, bbeforeProgress ), "ProgressMonitor::updateText()\nCall without valid parameters!\n" ) ;

	// Search topic ...
	IMPL_TextlistItem* pSearchItem = impl_searchTopic ( rTopic, bbeforeProgress ) ;

	if ( pSearchItem != NULL )
	{
		// Ready for multithreading
		MutexGuard aGuard ( m_aMutex ) ;

		// ... update text ...
		pSearchItem->sText = rText ;

		// ... and update window.
		impl_rebuildFixedText	() ;
		impl_recalcLayout		() ;
	}
}

//____________________________________________________________________________________________________________
//	XProgressBar
//____________________________________________________________________________________________________________

void SAL_CALL ProgressMonitor::setForegroundColor ( sal_Int32 nColor ) throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard aGuard ( m_aMutex ) ;

	if ( m_xProgressBar.is () )
	{
		m_xProgressBar->setForegroundColor ( nColor ) ;
	}
}

//____________________________________________________________________________________________________________
//	XProgressBar
//____________________________________________________________________________________________________________

void SAL_CALL ProgressMonitor::setBackgroundColor ( sal_Int32 nColor ) throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard aGuard ( m_aMutex ) ;

	if ( m_xProgressBar.is () )
	{
		m_xProgressBar->setBackgroundColor ( nColor ) ;
	}
}

//____________________________________________________________________________________________________________
//	XProgressBar
//____________________________________________________________________________________________________________

void SAL_CALL ProgressMonitor::setValue ( sal_Int32 nValue ) throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard aGuard ( m_aMutex ) ;

	if ( m_xProgressBar.is () )
	{
		m_xProgressBar->setValue ( nValue ) ;
	}
}

//____________________________________________________________________________________________________________
//	XProgressBar
//____________________________________________________________________________________________________________

void SAL_CALL ProgressMonitor::setRange ( sal_Int32 nMin, sal_Int32 nMax ) throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard aGuard ( m_aMutex ) ;

	if ( m_xProgressBar.is () )
	{
		m_xProgressBar->setRange ( nMin, nMax ) ;
	}
}

//____________________________________________________________________________________________________________
//	XProgressBar
//____________________________________________________________________________________________________________

sal_Int32 SAL_CALL ProgressMonitor::getValue () throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard aGuard ( m_aMutex ) ;

	if (m_xProgressBar.is())
	{
		return m_xProgressBar->getValue () ;
	}

	return 0 ;
}

//____________________________________________________________________________________________________________
//	XButton
//____________________________________________________________________________________________________________

void SAL_CALL ProgressMonitor::addActionListener ( const Reference< XActionListener > & rListener ) throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard aGuard ( m_aMutex ) ;

	if ( m_xButton.is () )
	{
		m_xButton->addActionListener ( rListener ) ;
	}
}

//____________________________________________________________________________________________________________
//	XButton
//____________________________________________________________________________________________________________

void SAL_CALL ProgressMonitor::removeActionListener ( const Reference< XActionListener > & rListener ) throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard aGuard ( m_aMutex ) ;

	if ( m_xButton.is () )
	{
		m_xButton->removeActionListener ( rListener ) ;
	}
}

//____________________________________________________________________________________________________________
//	XButton
//____________________________________________________________________________________________________________

void SAL_CALL ProgressMonitor::setLabel ( const OUString& rLabel ) throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard aGuard ( m_aMutex ) ;

	if ( m_xButton.is () )
	{
		m_xButton->setLabel ( rLabel ) ;
	}
}

//____________________________________________________________________________________________________________
//	XButton
//____________________________________________________________________________________________________________

void SAL_CALL ProgressMonitor::setActionCommand ( const OUString& rCommand ) throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard aGuard ( m_aMutex ) ;

	if ( m_xButton.is () )
	{
		m_xButton->setActionCommand ( rCommand ) ;
	}
}

//____________________________________________________________________________________________________________
//	XLayoutConstrains
//____________________________________________________________________________________________________________

Size SAL_CALL ProgressMonitor::getMinimumSize () throw( RuntimeException )
{
	return Size (DEFAULT_WIDTH, DEFAULT_HEIGHT) ;
}

//____________________________________________________________________________________________________________
//	XLayoutConstrains
//____________________________________________________________________________________________________________

Size SAL_CALL ProgressMonitor::getPreferredSize () throw( RuntimeException )
{
	// Ready for multithreading
	ClearableMutexGuard aGuard ( m_aMutex ) ;

	// get information about required place of child controls
	Reference< XLayoutConstrains > 	xTopicLayout_Top		( m_xTopic_Top		, UNO_QUERY ) ;
	Reference< XLayoutConstrains > 	xTopicLayout_Bottom		( m_xTopic_Bottom	, UNO_QUERY ) ;
	Reference< XLayoutConstrains > 	xButtonLayout			( m_xButton			, UNO_QUERY ) ;
	Reference< XWindow > 			xProgressBarWindow		( m_xProgressBar	, UNO_QUERY ) ;

	Size		aTopicSize_Top		=	xTopicLayout_Top->getPreferredSize			();
	Size		aTopicSize_Bottom	=	xTopicLayout_Bottom->getPreferredSize		();
	Size		aButtonSize			=	xButtonLayout->getPreferredSize		 		();
	Rectangle	aTempRectangle		=	xProgressBarWindow->getPosSize				();
	Size		aProgressBarSize	=	Size( aTempRectangle.Width, aTempRectangle.Height );

	aGuard.clear () ;

	// calc preferred size of progressmonitor
	sal_Int32	nWidth	=	0 ;
	sal_Int32	nHeight	=	0 ;

	nWidth	 =	3 * FREEBORDER			;
	nWidth	+=	aProgressBarSize.Width	;

	nHeight	 =	6 * FREEBORDER			;
	nHeight	+=	aTopicSize_Top.Height	;
	nHeight	+=	aProgressBarSize.Height	;
	nHeight	+=	aTopicSize_Bottom.Height;
	nHeight	+=	2						;	// 1 for black line, 1 for white line = 3D-Line!
	nHeight	+=	aButtonSize.Height		;

	// norm to minimum
	if ( nWidth<DEFAULT_WIDTH )
	{
		nWidth = DEFAULT_WIDTH ;
	}
	if ( nHeight<DEFAULT_HEIGHT )
	{
		nHeight = DEFAULT_HEIGHT ;
	}

	// return to caller
	return Size ( nWidth, nHeight ) ;
}

//____________________________________________________________________________________________________________
//	XLayoutConstrains
//____________________________________________________________________________________________________________

Size SAL_CALL ProgressMonitor::calcAdjustedSize ( const Size& /*rNewSize*/ ) throw( RuntimeException )
{
	return getPreferredSize () ;
}

//____________________________________________________________________________________________________________
//	XControl
//____________________________________________________________________________________________________________

void SAL_CALL ProgressMonitor::createPeer ( const Reference< XToolkit > & rToolkit, const Reference< XWindowPeer > & rParent	) throw( RuntimeException )
{
	if (!getPeer().is())
	{
		BaseContainerControl::createPeer ( rToolkit, rParent ) ;

		// If user forget to call "setPosSize()", we have still a correct size.
		// And a "MinimumSize" IS A "MinimumSize"!
		// We change not the position of control at this point.
		Size aDefaultSize = getMinimumSize () ;
		setPosSize ( 0, 0, aDefaultSize.Width, aDefaultSize.Height, PosSize::SIZE ) ;
	}
}

//____________________________________________________________________________________________________________
//	XControl
//____________________________________________________________________________________________________________

sal_Bool SAL_CALL ProgressMonitor::setModel ( const Reference< XControlModel > & /*rModel*/ ) throw( RuntimeException )
{
	// We have no model.
	return sal_False ;
}

//____________________________________________________________________________________________________________
//	XControl
//____________________________________________________________________________________________________________

Reference< XControlModel > SAL_CALL ProgressMonitor::getModel () throw( RuntimeException )
{
	// We have no model.
	// return (XControlModel*)this ;
	return Reference< XControlModel >  () ;
}

//____________________________________________________________________________________________________________
//	XComponent
//____________________________________________________________________________________________________________

void SAL_CALL ProgressMonitor::dispose () throw( RuntimeException )
{
	// Ready for multithreading
	MutexGuard aGuard ( m_aMutex ) ;

	// "removeControl()" control the state of a reference
	Reference< XControl >  xRef_Topic_Top		( m_xTopic_Top		, UNO_QUERY ) ;
	Reference< XControl >  xRef_Text_Top		( m_xText_Top		, UNO_QUERY ) ;
	Reference< XControl >  xRef_Topic_Bottom	( m_xTopic_Bottom	, UNO_QUERY ) ;
	Reference< XControl >  xRef_Text_Bottom		( m_xText_Bottom	, UNO_QUERY ) ;
	Reference< XControl >  xRef_Button			( m_xButton			, UNO_QUERY ) ;
	Reference< XControl >  xRef_ProgressBar		( m_xProgressBar	, UNO_QUERY ) ;

	removeControl ( xRef_Topic_Top	  	) ;
	removeControl ( xRef_Text_Top	  	) ;
	removeControl ( xRef_Topic_Bottom 	) ;
	removeControl ( xRef_Text_Bottom	) ;
	removeControl ( xRef_Button 		) ;
	removeControl ( xRef_ProgressBar	) ;

	// do'nt use "...->clear ()" or "... = XFixedText ()"
	// when other hold a reference at this object !!!
	xRef_Topic_Top->dispose 	() ;
	xRef_Text_Top->dispose 		() ;
	xRef_Topic_Bottom->dispose 	() ;
	xRef_Text_Bottom->dispose 	() ;
	xRef_Button->dispose		() ;
	xRef_ProgressBar->dispose	() ;

	BaseContainerControl::dispose () ;
}

//____________________________________________________________________________________________________________
//	XWindow
//____________________________________________________________________________________________________________

void SAL_CALL ProgressMonitor::setPosSize ( sal_Int32 nX, sal_Int32 nY, sal_Int32 nWidth, sal_Int32 nHeight, sal_Int16 nFlags ) throw( RuntimeException )
{
	Rectangle	aBasePosSize = getPosSize () ;
	BaseContainerControl::setPosSize (nX, nY, nWidth, nHeight, nFlags) ;

	// if position or size changed
	if (
		( nWidth  != aBasePosSize.Width	) ||
		( nHeight != aBasePosSize.Height)
	   )
	{
		// calc new layout for controls
		impl_recalcLayout () ;
		// clear background (!)
		// [Childs was repainted in "recalcLayout" by setPosSize() automaticly!]
		getPeer()->invalidate(2);
		// and repaint the control
		impl_paint ( 0, 0, impl_getGraphicsPeer() ) ;
	}
}

//____________________________________________________________________________________________________________
//	impl but public method to register service
//____________________________________________________________________________________________________________

const Sequence< OUString > ProgressMonitor::impl_getStaticSupportedServiceNames()
{
	MutexGuard aGuard( Mutex::getGlobalMutex() );
    Sequence< OUString > seqServiceNames( 1 );
    seqServiceNames.getArray() [0] = OUString::createFromAscii( SERVICENAME_PROGRESSMONITOR );
    return seqServiceNames ;
}

//____________________________________________________________________________________________________________
//	impl but public method to register service
//____________________________________________________________________________________________________________

const OUString ProgressMonitor::impl_getStaticImplementationName()
{
	return OUString::createFromAscii( IMPLEMENTATIONNAME_PROGRESSMONITOR );
}

//____________________________________________________________________________________________________________
//	protected method
//____________________________________________________________________________________________________________

void ProgressMonitor::impl_paint ( sal_Int32 nX, sal_Int32 nY, const Reference< XGraphics > & rGraphics )
{
	if (rGraphics.is())
	{
		// Ready for multithreading
		MutexGuard aGuard ( m_aMutex ) ;

		// paint shadowed border around the progressmonitor
		rGraphics->setLineColor ( LINECOLOR_SHADOW																) ;
		rGraphics->drawLine		( impl_getWidth()-1, impl_getHeight()-1, impl_getWidth()-1, nY 					) ;
		rGraphics->drawLine		( impl_getWidth()-1, impl_getHeight()-1, nX		   		  , impl_getHeight()-1	) ;

		rGraphics->setLineColor ( LINECOLOR_BRIGHT							) ;
		rGraphics->drawLine		( nX, nY, impl_getWidth(), nY 				) ;
		rGraphics->drawLine		( nX, nY, nX		  	 , impl_getHeight()	) ;

		// Paint 3D-line
		rGraphics->setLineColor ( LINECOLOR_SHADOW	) ;
		rGraphics->drawLine		( m_a3DLine.X, m_a3DLine.Y, m_a3DLine.X+m_a3DLine.Width, m_a3DLine.Y ) ;

		rGraphics->setLineColor ( LINECOLOR_BRIGHT	) ;
		rGraphics->drawLine		( m_a3DLine.X, m_a3DLine.Y+1, m_a3DLine.X+m_a3DLine.Width, m_a3DLine.Y+1 ) ;
	}
}

//____________________________________________________________________________________________________________
//	private method
//____________________________________________________________________________________________________________

void ProgressMonitor::impl_recalcLayout ()
{
	sal_Int32	nX_Button				;
	sal_Int32	nY_Button				;
	sal_Int32	nWidth_Button			;
	sal_Int32	nHeight_Button			;

	sal_Int32	nX_ProgressBar			;
	sal_Int32	nY_ProgressBar			;
	sal_Int32	nWidth_ProgressBar		;
	sal_Int32	nHeight_ProgressBar		;

	sal_Int32	nX_3DLine				;
	sal_Int32	nY_3DLine				;
	sal_Int32	nWidth_3DLine			;
	sal_Int32	nHeight_3DLine			;

	sal_Int32	nX_Text_Top				;
	sal_Int32	nY_Text_Top				;
	sal_Int32	nWidth_Text_Top			;
	sal_Int32	nHeight_Text_Top		;

	sal_Int32	nX_Topic_Top	 		;
	sal_Int32	nY_Topic_Top	 		;
	sal_Int32	nWidth_Topic_Top 		;
	sal_Int32	nHeight_Topic_Top		;

	sal_Int32	nX_Text_Bottom			;
	sal_Int32	nY_Text_Bottom			;
	sal_Int32	nWidth_Text_Bottom		;
	sal_Int32	nHeight_Text_Bottom		;

	sal_Int32	nX_Topic_Bottom	 		;
	sal_Int32	nY_Topic_Bottom	 		;
	sal_Int32	nWidth_Topic_Bottom 	;
	sal_Int32	nHeight_Topic_Bottom	;

	// Ready for multithreading
	MutexGuard aGuard ( m_aMutex ) ;

	// get information about required place of child controls
	Reference< XLayoutConstrains > 	xTopicLayout_Top	( m_xTopic_Top		, UNO_QUERY ) ;
	Reference< XLayoutConstrains > 	xTextLayout_Top		( m_xText_Top		, UNO_QUERY ) ;
	Reference< XLayoutConstrains > 	xTopicLayout_Bottom	( m_xTopic_Bottom	, UNO_QUERY ) ;
	Reference< XLayoutConstrains > 	xTextLayout_Bottom	( m_xText_Bottom	, UNO_QUERY ) ;
	Reference< XLayoutConstrains > 	xButtonLayout		( m_xButton			, UNO_QUERY ) ;

	Size	aTopicSize_Top		=	xTopicLayout_Top->getPreferredSize		() ;
	Size	aTextSize_Top		=	xTextLayout_Top->getPreferredSize		() ;
	Size	aTopicSize_Bottom	=	xTopicLayout_Bottom->getPreferredSize	() ;
	Size	aTextSize_Bottom	=	xTextLayout_Bottom->getPreferredSize	() ;
	Size	aButtonSize			=	xButtonLayout->getPreferredSize		 	() ;

	// calc position and size of child controls
	// Button has preferred size!
	nWidth_Button			=	aButtonSize.Width												;
	nHeight_Button			=	aButtonSize.Height												;

	// Left column before progressbar has preferred size and fixed position.
	// But "Width" is oriented on left column below progressbar to!!! "max(...)"
	nX_Topic_Top			=	FREEBORDER														;
	nY_Topic_Top			=	FREEBORDER														;
	nWidth_Topic_Top		=	Max ( aTopicSize_Top.Width, aTopicSize_Bottom.Width )			;
	nHeight_Topic_Top		=	aTopicSize_Top.Height											;

	// Right column before progressbar has relativ position to left column ...
	// ... and a size as rest of dialog size!
	nX_Text_Top				=	nX_Topic_Top+nWidth_Topic_Top+FREEBORDER						;
	nY_Text_Top				=	nY_Topic_Top													;
	nWidth_Text_Top			=	Max ( aTextSize_Top.Width, aTextSize_Bottom.Width )				;
	// Fix size of this column to minimum!
	sal_Int32 nSummaryWidth = nWidth_Text_Top+nWidth_Topic_Top+(3*FREEBORDER) ;
	if ( nSummaryWidth < DEFAULT_WIDTH )
		nWidth_Text_Top		=	DEFAULT_WIDTH-nWidth_Topic_Top-(3*FREEBORDER);
	// Fix size of column to maximum!
	if ( nSummaryWidth > impl_getWidth() )
		nWidth_Text_Top		=	impl_getWidth()-nWidth_Topic_Top-(3*FREEBORDER)					;
	nHeight_Text_Top		=	nHeight_Topic_Top												;

	// Position of progressbar is relativ to columns before.
	// Progressbar.Width  = Dialog.Width !!!
	// Progressbar.Height = Button.Height
	nX_ProgressBar			=	nX_Topic_Top													;
	nY_ProgressBar			=	nY_Topic_Top+nHeight_Topic_Top+FREEBORDER						;
	nWidth_ProgressBar		=	FREEBORDER+nWidth_Topic_Top+nWidth_Text_Top						;
	nHeight_ProgressBar		=	nHeight_Button													;

	// Oriented by left column before progressbar.
	nX_Topic_Bottom			=	nX_Topic_Top													;
	nY_Topic_Bottom			=	nY_ProgressBar+nHeight_ProgressBar+FREEBORDER					;
	nWidth_Topic_Bottom		=	nWidth_Topic_Top												;
	nHeight_Topic_Bottom	=	aTopicSize_Bottom.Height										;

	// Oriented by right column before progressbar.
	nX_Text_Bottom			=	nX_Topic_Bottom+nWidth_Topic_Bottom+FREEBORDER					;
	nY_Text_Bottom			=	nY_Topic_Bottom													;
	nWidth_Text_Bottom		=	nWidth_Text_Top													;
	nHeight_Text_Bottom		=	nHeight_Topic_Bottom											;

	// Oriented by progressbar.
	nX_3DLine				=	nX_Topic_Top													;
	nY_3DLine				=	nY_Topic_Bottom+nHeight_Topic_Bottom+(FREEBORDER/2)				;
	nWidth_3DLine			=	nWidth_ProgressBar												;
	nHeight_3DLine			=	1																;	// Height for ONE line ! (But we paint two lines!)

	// Oriented by progressbar.
	nX_Button				=	nX_ProgressBar+nWidth_ProgressBar-nWidth_Button					;
	nY_Button				=	nY_Topic_Bottom+nHeight_Topic_Bottom+FREEBORDER					;

	// Calc offsets to center controls
	sal_Int32	nDx	;
	sal_Int32	nDy	;

	nDx	=	( (2*FREEBORDER)+nWidth_ProgressBar																) ;
	nDy	=	( (6*FREEBORDER)+nHeight_Topic_Top+nHeight_ProgressBar+nHeight_Topic_Bottom+2+nHeight_Button	) ;

	// At this point use original dialog size to center controls!
	nDx	=	(impl_getWidth ()/2)-(nDx/2)	;
	nDy	=	(impl_getHeight()/2)-(nDy/2)	;

	if ( nDx<0 )
	{
		nDx=0 ;
	}
	if ( nDy<0 )
	{
		nDy=0 ;
	}

	// Set new position and size on all controls
	Reference< XWindow >  xRef_Topic_Top		( m_xTopic_Top		, UNO_QUERY ) ;
	Reference< XWindow >  xRef_Text_Top			( m_xText_Top 		, UNO_QUERY ) ;
	Reference< XWindow >  xRef_Topic_Bottom		( m_xTopic_Bottom	, UNO_QUERY ) ;
	Reference< XWindow >  xRef_Text_Bottom		( m_xText_Bottom 	, UNO_QUERY ) ;
	Reference< XWindow >  xRef_Button			( m_xButton			, UNO_QUERY ) ;
	Reference< XWindow >  xRef_ProgressBar		( m_xProgressBar	, UNO_QUERY ) ;

	xRef_Topic_Top->setPosSize		( nDx+nX_Topic_Top		, nDy+nY_Topic_Top		, nWidth_Topic_Top		, nHeight_Topic_Top	  	, 15 ) ;
	xRef_Text_Top->setPosSize		( nDx+nX_Text_Top		, nDy+nY_Text_Top		, nWidth_Text_Top		, nHeight_Text_Top		, 15 ) ;
	xRef_Topic_Bottom->setPosSize	( nDx+nX_Topic_Bottom	, nDy+nY_Topic_Bottom	, nWidth_Topic_Bottom	, nHeight_Topic_Bottom	, 15 ) ;
	xRef_Text_Bottom->setPosSize	( nDx+nX_Text_Bottom	, nDy+nY_Text_Bottom	, nWidth_Text_Bottom	, nHeight_Text_Bottom	, 15 ) ;
	xRef_Button->setPosSize			( nDx+nX_Button	 		, nDy+nY_Button	 		, nWidth_Button	 		, nHeight_Button	 	, 15 ) ;
	xRef_ProgressBar->setPosSize	( nDx+nX_ProgressBar	, nDy+nY_ProgressBar	, nWidth_ProgressBar	, nHeight_ProgressBar	, 15 ) ;

	m_a3DLine.X			= nDx+nX_Topic_Top											;
	m_a3DLine.Y			= nDy+nY_Topic_Bottom+nHeight_Topic_Bottom+(FREEBORDER/2)	;
	m_a3DLine.Width		= nWidth_ProgressBar										;
	m_a3DLine.Height	= nHeight_ProgressBar										;

	// All childcontrols make an implicit repaint in setPosSize()!
	// Make it also for this 3D-line ...
	Reference< XGraphics >  xGraphics = impl_getGraphicsPeer () ;

	xGraphics->setLineColor ( LINECOLOR_SHADOW	) ;
	xGraphics->drawLine		( m_a3DLine.X, m_a3DLine.Y, m_a3DLine.X+m_a3DLine.Width, m_a3DLine.Y ) ;

	xGraphics->setLineColor ( LINECOLOR_BRIGHT	) ;
	xGraphics->drawLine		( m_a3DLine.X, m_a3DLine.Y+1, m_a3DLine.X+m_a3DLine.Width, m_a3DLine.Y+1 ) ;
}

//____________________________________________________________________________________________________________
//	private method
//____________________________________________________________________________________________________________

void ProgressMonitor::impl_rebuildFixedText ()
{
	// Ready for multithreading
	MutexGuard aGuard ( m_aMutex ) ;

	// Rebuild fixedtext before progress

	// Rebuild left site of text
	if (m_xTopic_Top.is())
	{
		OUString		aCollectString	;

		// Collect all topics from list and format text.
		// "\n" MUST BE at the end of line!!! => Else ... topic and his text are not in the same line!!!
		for ( sal_uInt32 n=0; n<m_pTextlist_Top->Count(); ++n )
		{
			IMPL_TextlistItem* pSearchItem = m_pTextlist_Top->GetObject (n) ;
			aCollectString	+=	pSearchItem->sTopic ;
			aCollectString	+=	OUString::createFromAscii("\n")			    ;
		}
		aCollectString	+=	OUString::createFromAscii("\0")	;	// It's better :-)

		m_xTopic_Top->setText ( aCollectString ) ;
	}

	// Rebuild right site of text
	if (m_xText_Top.is())
	{
		OUString		aCollectString	;

		// Collect all topics from list and format text.
		// "\n" MUST BE at the end of line!!! => Else ... topic and his text are not in the same line!!!
		for ( sal_uInt32 n=0; n<m_pTextlist_Top->Count(); ++n )
		{
			IMPL_TextlistItem* pSearchItem = m_pTextlist_Top->GetObject (n) ;
			aCollectString	+=	pSearchItem->sText ;
			aCollectString	+=	OUString::createFromAscii("\n")			   ;
		}
		aCollectString	+=	OUString::createFromAscii("\0")	;	// It's better :-)

		m_xText_Top->setText ( aCollectString ) ;
	}

	// Rebuild fixedtext below progress

	// Rebuild left site of text
	if (m_xTopic_Bottom.is())
	{
		OUString		aCollectString	;

		// Collect all topics from list and format text.
		// "\n" MUST BE at the end of line!!! => Else ... topic and his text are not in the same line!!!
		for ( sal_uInt32 n=0; n<m_pTextlist_Bottom->Count(); ++n )
		{
			IMPL_TextlistItem* pSearchItem = m_pTextlist_Bottom->GetObject (n) ;
			aCollectString	+=	pSearchItem->sTopic ;
			aCollectString	+=	OUString::createFromAscii("\n")			    ;
		}
		aCollectString	+=	OUString::createFromAscii("\0")	;	// It's better :-)

		m_xTopic_Bottom->setText ( aCollectString ) ;
	}

	// Rebuild right site of text
	if (m_xText_Bottom.is())
	{
		OUString		aCollectString	;

		// Collect all topics from list and format text.
		// "\n" MUST BE at the end of line!!! => Else ... topic and his text are not in the same line!!!
		for ( sal_uInt32 n=0; n<m_pTextlist_Bottom->Count(); ++n )
		{
			IMPL_TextlistItem* pSearchItem = m_pTextlist_Bottom->GetObject (n) ;
			aCollectString	+=	pSearchItem->sText ;
			aCollectString	+=	OUString::createFromAscii("\n")			   ;
		}
		aCollectString	+=	OUString::createFromAscii("\0")	;	// It's better :-)

		m_xText_Bottom->setText ( aCollectString ) ;
	}
}

//____________________________________________________________________________________________________________
//	private method
//____________________________________________________________________________________________________________

void ProgressMonitor::impl_cleanMemory ()
{
	// Ready for multithreading
	MutexGuard aGuard ( m_aMutex ) ;

	// Delete all of lists.

	sal_uInt32 nPosition ;

	for ( nPosition = 0; nPosition < m_pTextlist_Top->Count () ; ++nPosition )
	{
		IMPL_TextlistItem* pSearchItem = m_pTextlist_Top->GetObject ( nPosition ) ;
		delete pSearchItem ;
	}
	m_pTextlist_Top->Clear () ;
	delete m_pTextlist_Top ;

	for ( nPosition = 0; nPosition < m_pTextlist_Bottom->Count () ; ++nPosition )
	{
		IMPL_TextlistItem* pSearchItem = m_pTextlist_Bottom->GetObject ( nPosition ) ;
		delete pSearchItem ;
	}
	m_pTextlist_Bottom->Clear () ;
	delete m_pTextlist_Bottom ;
}

//____________________________________________________________________________________________________________
//	private method
//____________________________________________________________________________________________________________

IMPL_TextlistItem* ProgressMonitor::impl_searchTopic ( const OUString& rTopic, sal_Bool bbeforeProgress	)
{
	// Get right textlist for following operations.
	IMPL_Textlist* pTextList ;

	// Ready for multithreading
	ClearableMutexGuard aGuard ( m_aMutex ) ;

	if ( bbeforeProgress == sal_True )
	{
		pTextList = m_pTextlist_Top    ;
	}
	else
	{
		pTextList = m_pTextlist_Bottom ;
	}

	// Switch off guard.
	aGuard.clear () ;

	// Search the topic in textlist.
	sal_uInt32	nPosition	=	0					;
	sal_uInt32	nCount		=	pTextList->Count ()	;

	for ( nPosition = 0; nPosition < nCount ; ++nPosition )
	{
		IMPL_TextlistItem* pSearchItem = pTextList->GetObject ( nPosition ) ;

		if ( pSearchItem->sTopic == rTopic )
		{
			// We have found this topic ... return a valid pointer.
			return pSearchItem ;
		}
	}

	// We have'nt found this topic ... return a nonvalid pointer.
	return NULL ;
}

//____________________________________________________________________________________________________________
//	debug methods
//____________________________________________________________________________________________________________

#ifdef DBG_UTIL

// addText, updateText
sal_Bool ProgressMonitor::impl_debug_checkParameter ( const OUString& rTopic, const OUString& rText, sal_Bool /*bbeforeProgress*/ )
{
	// Check "rTopic"
	if ( &rTopic		==	NULL	) return sal_False ;	// NULL-pointer for reference ???!!!
	if ( rTopic.getLength ()	<	1		) return sal_False ;	// ""

	// Check "rText"
	if ( &rText			==	NULL	) return sal_False ;	// NULL-pointer for reference ???!!!
	if ( rText.getLength ()	<	1		) return sal_False ;	// ""

	// "bbeforeProgress" is valid in everyway!

	// Parameter OK ... return sal_True.
	return sal_True ;
}

// removeText
sal_Bool ProgressMonitor::impl_debug_checkParameter ( const OUString& rTopic, sal_Bool /*bbeforeProgress*/ )
{
	// Check "rTopic"
	if ( &rTopic		==	NULL	) return sal_False ;	// NULL-pointer for reference ???!!!
	if ( rTopic.getLength ()	<	1		) return sal_False ;	// ""

	// "bbeforeProgress" is valid in everyway!

	// Parameter OK ... return sal_True.
	return sal_True ;
}

#endif	// #ifdef DBG_UTIL

}	// namespace unocontrols