/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: calendar.cxx,v $
 * $Revision: 1.14 $
 *
 * 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.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svtools.hxx"

#ifndef _APP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef _TABLE_HXX
#include <tools/table.hxx>
#endif
#ifndef _HELP_HXX
#include <vcl/help.hxx>
#endif
#ifndef _MENU_HXX
#include <vcl/menu.hxx>
#endif
#ifndef _DECOVIEW_HXX
#include <vcl/decoview.hxx>
#endif
#ifndef _FLOATWIN_HXX
#include <vcl/floatwin.hxx>
#endif
#ifndef _BUTTON_HXX
#include <vcl/button.hxx>
#endif
#ifndef _FIXED_HXX
#include <vcl/fixed.hxx>
#endif
#include <unotools/calendarwrapper.hxx>
#include <unotools/localedatawrapper.hxx>
#include <com/sun/star/i18n/Weekdays.hpp>
#include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
#include <com/sun/star/i18n/CalendarFieldIndex.hpp>

#define _SV_CALENDAR_CXX
#include <svtools/svtools.hrc>
#include <svtools/svtdata.hxx>
#include <calendar.hxx>

// =======================================================================

#define DAY_OFFX						4
#define DAY_OFFY						2
#define MONTH_BORDERX					4
#define MONTH_OFFY						3
#define WEEKNUMBER_OFFX 				4
#define WEEKDAY_OFFY					3
#define TITLE_OFFY						3
#define TITLE_BORDERY					2
#define SPIN_OFFX						4
#define SPIN_OFFY						TITLE_BORDERY

#define WEEKNUMBER_HEIGHT				85

#define CALENDAR_HITTEST_DAY			((USHORT)0x0001)
#define CALENDAR_HITTEST_WEEK			((USHORT)0x0002)
#define CALENDAR_HITTEST_MONTHTITLE 	((USHORT)0x0004)
#define CALENDAR_HITTEST_PREV			((USHORT)0x0008)
#define CALENDAR_HITTEST_NEXT			((USHORT)0x0010)
#define CALENDAR_HITTEST_OUTSIDE		((USHORT)0x1000)

#define MENU_YEAR_COUNT 				3

#define TABLE_DATE_SELECTED 			((void*)0x00000001)

using namespace ::com::sun::star;

// =======================================================================

struct ImplDateInfo
{
	XubString	maText;
	Color*		mpTextColor;
	Color*		mpFrameColor;
	USHORT		mnFlags;

				ImplDateInfo( const XubString& rText ) :
					maText( rText )
				{ mpTextColor = mpFrameColor = NULL; mnFlags = 0; }
				~ImplDateInfo() { delete mpTextColor; delete mpFrameColor; }
};

DECLARE_TABLE( ImplDateTable, ImplDateInfo* )

// =======================================================================

static void ImplCalendarSelectDate( Table* pTable, const Date& rDate, BOOL bSelect )
{
	if ( bSelect )
		pTable->Insert( rDate.GetDate(), TABLE_DATE_SELECTED );
	else
		pTable->Remove( rDate.GetDate() );
}

// -----------------------------------------------------------------------

static void ImplCalendarSelectDateRange( Table* pTable,
										 const Date& rStartDate,
										 const Date& rEndDate,
										 BOOL bSelect )
{
	Date aStartDate = rStartDate;
	Date aEndDate = rEndDate;
	if ( aStartDate > aEndDate )
	{
		Date aTempDate = aStartDate;
		aStartDate = aEndDate;
		aEndDate = aTempDate;
	}

	if ( bSelect )
	{
		while ( aStartDate <= aEndDate )
		{
			pTable->Insert( aStartDate.GetDate(), TABLE_DATE_SELECTED );
			aStartDate++;
		}
	}
	else
	{
		void* p = pTable->First();
		while ( p )
		{
			Date aDate( pTable->GetCurKey() );
			if ( aDate > aEndDate )
				break;

			if ( aDate >= aStartDate )
				pTable->Remove( aDate.GetDate() );
			else
				p = pTable->Next();
		}
	}
}

// -----------------------------------------------------------------------

static void ImplCalendarUnSelectDateRange( Table* pTable,
										   Table* pOldTable,
										   const Date& rStartDate,
										   const Date& rEndDate )
{
	Date aStartDate = rStartDate;
	Date aEndDate = rEndDate;
	if ( aStartDate > aEndDate )
	{
		Date aTempDate = aStartDate;
		aStartDate = aEndDate;
		aEndDate = aTempDate;
	}

	void* p = pTable->First();
	while ( p )
	{
		Date aDate( pTable->GetCurKey() );
		if ( aDate > aEndDate )
			break;

		if ( aDate >= aStartDate )
			pTable->Remove( aDate.GetDate() );
		else
			p = pTable->Next();
	}

	p = pOldTable->First();
	while ( p )
	{
		Date aDate( pOldTable->GetCurKey() );
		if ( aDate > aEndDate )
			break;
		if ( aDate >= aStartDate )
			pTable->Insert( aDate.GetDate(), TABLE_DATE_SELECTED );

		p = pOldTable->Next();
	}
}

// -----------------------------------------------------------------------

inline void ImplCalendarClearSelectDate( Table* pTable )
{
	pTable->Clear();
}

// =======================================================================

void Calendar::ImplInit( WinBits nWinStyle )
{
	mpDateTable 			= NULL;
	mpSelectTable			= new Table;
	mpOldSelectTable		= NULL;
	mpRestoreSelectTable	= NULL;
	mpStandardColor 		= NULL;
	mpSaturdayColor 		= NULL;
	mpSundayColor			= NULL;
	mnDayCount				= 0;
	mnWinStyle				= nWinStyle;
	mnFirstYear 			= 0;
	mnLastYear				= 0;
	mnRequestYear			= 0;
	mbCalc					= TRUE;
	mbFormat				= TRUE;
	mbDrag					= FALSE;
	mbSelection 			= FALSE;
	mbMultiSelection		= FALSE;
	mbWeekSel				= FALSE;
	mbUnSel 				= FALSE;
	mbMenuDown				= FALSE;
	mbSpinDown				= FALSE;
	mbPrevIn				= FALSE;
	mbNextIn				= FALSE;
	mbDirect				= FALSE;
	mbInSelChange			= FALSE;
	mbTravelSelect			= FALSE;
	mbScrollDateRange		= FALSE;
	mbSelLeft				= FALSE;
	mbAllSel				= FALSE;
	mbDropPos				= FALSE;

    ::rtl::OUString aGregorian( RTL_CONSTASCII_USTRINGPARAM( "gregorian"));
    maCalendarWrapper.loadCalendar( aGregorian,
            Application::GetAppLocaleDataWrapper().getLocale());
    if (maCalendarWrapper.getUniqueID() != aGregorian)
    {
#ifdef DBG_UTIL
        ByteString aMsg( "Calendar::ImplInit: No ``gregorian'' calendar available for locale ``");
        lang::Locale aLoc( Application::GetAppLocaleDataWrapper().getLocale());
        aMsg += ByteString( String( aLoc.Language), RTL_TEXTENCODING_UTF8);
        aMsg += '-';
        aMsg += ByteString( String( aLoc.Country), RTL_TEXTENCODING_UTF8);
        aMsg += "'' and other calendars aren't supported. Using en-US fallback.";
        DBG_ERRORFILE( aMsg.GetBuffer());
#endif
        /* If we ever wanted to support other calendars than Gregorian a lot of
         * rewrite would be necessary to internally replace use of class Date
         * with proper class CalendarWrapper methods, get rid of fixed 12
         * months, fixed 7 days, ... */
        maCalendarWrapper.loadCalendar( aGregorian, lang::Locale(
                    ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "en")),
                    ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "US")),
                    ::rtl::OUString()));
    }

	SetFirstDate( maCurDate );
	ImplCalendarSelectDate( mpSelectTable, maCurDate, TRUE );

	// Sonstige Strings erzeugen
	maDayText = XubString( SvtResId( STR_SVT_CALENDAR_DAY ) );
	maWeekText = XubString( SvtResId( STR_SVT_CALENDAR_WEEK ) );

	// Tagestexte anlegen
	for ( USHORT i = 0; i < 31; i++ )
		mpDayText[i] = new UniString( UniString::CreateFromInt32( i+1 ) );

	maDragScrollTimer.SetTimeoutHdl( STATIC_LINK( this, Calendar, ScrollHdl ) );
	maDragScrollTimer.SetTimeout( GetSettings().GetMouseSettings().GetScrollRepeat() );
	mnDragScrollHitTest = 0;

	ImplInitSettings();
}

// -----------------------------------------------------------------------

void Calendar::ImplInitSettings()
{
	const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
	maSelColor = rStyleSettings.GetHighlightTextColor();
	SetPointFont( rStyleSettings.GetToolFont() );
	SetTextColor( rStyleSettings.GetFieldTextColor() );
	SetBackground( Wallpaper( rStyleSettings.GetFieldColor() ) );
}

// -----------------------------------------------------------------------

Calendar::Calendar( Window* pParent, WinBits nWinStyle ) :
	Control( pParent, nWinStyle & (WB_TABSTOP | WB_GROUP | WB_BORDER | WB_3DLOOK | WB_RANGESELECT | WB_MULTISELECT) ),
	maCalendarWrapper( Application::GetAppLocaleDataWrapper().getServiceFactory() ),
	maOldFormatFirstDate( 0, 0, 1900 ),
	maOldFormatLastDate( 0, 0, 1900 ),
	maFirstDate( 0, 0, 1900 ),
	maOldFirstDate( 0, 0, 1900 ),
	maOldCurDate( 0, 0, 1900 ),
	maAnchorDate( maCurDate ),
	maDropDate( 0, 0, 1900 )
{
	ImplInit( nWinStyle );
}

// -----------------------------------------------------------------------

Calendar::Calendar( Window* pParent, const ResId& rResId ) :
	Control( pParent, rResId ),
	maCalendarWrapper( Application::GetAppLocaleDataWrapper().getServiceFactory() ),
	maOldFormatFirstDate( 0, 0, 1900 ),
	maOldFormatLastDate( 0, 0, 1900 ),
	maFirstDate( 0, 0, 1900 ),
	maOldFirstDate( 0, 0, 1900 ),
	maOldCurDate( 0, 0, 1900 ),
	maAnchorDate( maCurDate ),
	maDropDate( 0, 0, 1900 )
{
	ImplInit( rResId.GetWinBits() );
}

// -----------------------------------------------------------------------

Calendar::~Calendar()
{
	delete mpStandardColor;
	delete mpSaturdayColor;
	delete mpSundayColor;

	if ( mpDateTable )
	{
		ImplDateInfo* pDateInfo = mpDateTable->First();
		while ( pDateInfo )
		{
			delete pDateInfo;
			pDateInfo = mpDateTable->Next();
		}

		delete mpDateTable;
	}

	delete mpSelectTable;
	if ( mpOldSelectTable )
		delete mpOldSelectTable;
	if ( mpRestoreSelectTable )
		delete mpRestoreSelectTable;

	for ( USHORT i = 0; i < 31; i++ )
		delete mpDayText[i];
}

// -----------------------------------------------------------------------

void Calendar::SetMinimumNumberOfDaysInWeek( sal_Int16 nDays )
{
    ImplUpdate( TRUE );
    maCalendarWrapper.setMinimumNumberOfDaysForFirstWeek( nDays);
}

// -----------------------------------------------------------------------

void Calendar::SetWeekStart( sal_Int16 nDay )
{
    ImplUpdate( TRUE );
    switch (nDay)
    {
        case i18n::Weekdays::SUNDAY :
        case i18n::Weekdays::MONDAY :
        case i18n::Weekdays::TUESDAY :
        case i18n::Weekdays::WEDNESDAY :
        case i18n::Weekdays::THURSDAY :
        case i18n::Weekdays::FRIDAY :
        case i18n::Weekdays::SATURDAY :
            ;   // nothing
        default:
            DBG_ERRORFILE("Calendar::SetWeekStart: unknown value for setFirstDayOfWeek() of a Gregorian calendar");
            nDay = i18n::Weekdays::SUNDAY;
    }
    maCalendarWrapper.setFirstDayOfWeek( nDay);
}

// -----------------------------------------------------------------------

DayOfWeek Calendar::ImplGetWeekStart() const
{
    // Map i18n::Weekdays to Date DayOfWeek
    DayOfWeek eDay;
    sal_Int16 nDay = maCalendarWrapper.getFirstDayOfWeek();
    switch (nDay)
    {
        case i18n::Weekdays::SUNDAY :
            eDay = SUNDAY;
            break;
        case i18n::Weekdays::MONDAY :
            eDay = MONDAY;
            break;
        case i18n::Weekdays::TUESDAY :
            eDay = TUESDAY;
            break;
        case i18n::Weekdays::WEDNESDAY :
            eDay = WEDNESDAY;
            break;
        case i18n::Weekdays::THURSDAY :
            eDay = THURSDAY;
            break;
        case i18n::Weekdays::FRIDAY :
            eDay = FRIDAY;
            break;
        case i18n::Weekdays::SATURDAY :
            eDay = SATURDAY;
            break;
        default:
            DBG_ERRORFILE("Calendar::ImplGetWeekStart: broken i18n Gregorian calendar (getFirstDayOfWeek())");
            eDay = SUNDAY;
    }
    return eDay;
}

// -----------------------------------------------------------------------

void Calendar::ImplGetWeekFont( Font& rFont ) const
{
	// Wochennummer geben wir in WEEKNUMBER_HEIGHT%-Fonthoehe aus
	Size aFontSize = rFont.GetSize();
	aFontSize.Height() *= WEEKNUMBER_HEIGHT;
	aFontSize.Height() /= 100;
	rFont.SetSize( aFontSize );
	rFont.SetWeight( WEIGHT_NORMAL );
}

// -----------------------------------------------------------------------

void Calendar::ImplFormat()
{
	if ( !mbFormat )
		return;

	if ( mbCalc )
	{
		Size aOutSize = GetOutputSizePixel();

		if ( (aOutSize.Width() <= 1) || (aOutSize.Height() <= 1) )
			return;

		XubString a99Text( XubString( RTL_CONSTASCII_USTRINGPARAM( "99" ) ) );

		Font aOldFont = GetFont();

		// Wochenanzeige beruecksichtigen
		if ( mnWinStyle & WB_WEEKNUMBER )
		{
			Font aTempFont = aOldFont;
			ImplGetWeekFont( aTempFont );
			SetFont( aTempFont );
			mnWeekWidth = GetTextWidth( a99Text )+WEEKNUMBER_OFFX;
			SetFont( aOldFont );
		}
		else
			mnWeekWidth = 0;

		if ( mnWinStyle & WB_BOLDTEXT )
		{
			Font aFont = aOldFont;
			if ( aFont.GetWeight() < WEIGHT_BOLD )
				aFont.SetWeight( WEIGHT_BOLD );
			else
				aFont.SetWeight( WEIGHT_NORMAL );
			SetFont( aFont );
		}

		long n99TextWidth = GetTextWidth( a99Text );
		long nTextHeight = GetTextHeight();

		// Breiten und X-Positionen berechnen
		mnDayWidth		= n99TextWidth+DAY_OFFX;
		mnMonthWidth	= mnDayWidth*7;
		mnMonthWidth   += mnWeekWidth;
		mnMonthWidth   += MONTH_BORDERX*2;
		mnMonthPerLine	= aOutSize.Width() / mnMonthWidth;
		if ( !mnMonthPerLine )
			mnMonthPerLine = 1;
		long nOver		= ((aOutSize.Width()-(mnMonthPerLine*mnMonthWidth)) / mnMonthPerLine);
		mnMonthWidth   += nOver;
		mnDaysOffX		= MONTH_BORDERX;
		mnDaysOffX	   += nOver/2;
		mnDaysOffX	   += mnWeekWidth;

		// Hoehen und Y-Positionen berechnen
		mnDayHeight 	= nTextHeight + DAY_OFFY;
		mnWeekDayOffY	= nTextHeight + TITLE_OFFY + (TITLE_BORDERY*2);
		mnDaysOffY		= mnWeekDayOffY + nTextHeight + WEEKDAY_OFFY;
		mnMonthHeight	= (mnDayHeight*6) + mnDaysOffY;
		mnMonthHeight  += MONTH_OFFY;
		mnLines 		= aOutSize.Height() / mnMonthHeight;
		if ( !mnLines )
			mnLines = 1;
		mnMonthHeight  += (aOutSize.Height()-(mnLines*mnMonthHeight)) / mnLines;

		// Spinfelder berechnen
		long nSpinSize		= nTextHeight+TITLE_BORDERY-SPIN_OFFY;
		maPrevRect.Left()	= SPIN_OFFX;
		maPrevRect.Top()	= SPIN_OFFY;
		maPrevRect.Right()	= maPrevRect.Left()+nSpinSize;
		maPrevRect.Bottom() = maPrevRect.Top()+nSpinSize;
		maNextRect.Left()	= aOutSize.Width()-SPIN_OFFX-nSpinSize-1;
		maNextRect.Top()	= SPIN_OFFY;
		maNextRect.Right()	= maNextRect.Left()+nSpinSize;
		maNextRect.Bottom() = maNextRect.Top()+nSpinSize;

		if ( mnWinStyle & WB_BOLDTEXT )
			SetFont( aOldFont );

		// Calculate DayOfWeekText (gets displayed in a narrow font)
		maDayOfWeekText.Erase();
		long nStartOffX = 0;
		sal_Int16 nDay = maCalendarWrapper.getFirstDayOfWeek();
		for ( sal_Int16 nDayOfWeek = 0; nDayOfWeek < 7; nDayOfWeek++ )
		{
            // Use first character of full name, since the abbreviated name may
            // be roman digits or similar in some locales. Proper
            // implementation would need narrow one letter month names defined
            // in locale data.
            String aDayOfWeek( maCalendarWrapper.getDisplayName(
                        i18n::CalendarDisplayIndex::DAY, nDay, 1).GetChar(0));
			long nOffX = (mnDayWidth-GetTextWidth( aDayOfWeek ))/2;
			if ( mnWinStyle & WB_BOLDTEXT )
				nOffX++;
			if ( !nDayOfWeek )
				nStartOffX = nOffX;
			else
				nOffX -= nStartOffX;
			nOffX += nDayOfWeek * mnDayWidth;
			mnDayOfWeekAry[nDayOfWeek] = nOffX;
			maDayOfWeekText += aDayOfWeek;
			nDay++;
			nDay %= 7;
		}

		mbCalc = FALSE;
	}

	// Anzahl Tage berechnen

    DayOfWeek eStartDay = ImplGetWeekStart();

	USHORT nWeekDay;
	Date aTempDate = GetFirstMonth();
	maFirstDate = aTempDate;
	nWeekDay = (USHORT)aTempDate.GetDayOfWeek();
	nWeekDay = (nWeekDay+(7-(USHORT)eStartDay)) % 7;
	maFirstDate -= (ULONG)nWeekDay;
	mnDayCount = nWeekDay;
	USHORT nDaysInMonth;
	USHORT nMonthCount = (USHORT)(mnMonthPerLine*mnLines);
	for ( USHORT i = 0; i < nMonthCount; i++ )
	{
		nDaysInMonth = aTempDate.GetDaysInMonth();
		mnDayCount += nDaysInMonth;
		aTempDate += nDaysInMonth;
	}
	Date aTempDate2 = aTempDate;
	aTempDate2--;
	nDaysInMonth = aTempDate2.GetDaysInMonth();
	aTempDate2 -= nDaysInMonth-1;
	nWeekDay = (USHORT)aTempDate2.GetDayOfWeek();
	nWeekDay = (nWeekDay+(7-(USHORT)eStartDay)) % 7;
	mnDayCount += 42-nDaysInMonth-nWeekDay;

	// Farben festlegen
	maOtherColor = Color( COL_LIGHTGRAY );
	if ( maOtherColor.IsRGBEqual( GetBackground().GetColor() ) )
		maOtherColor.SetColor( COL_GRAY );

	Date aLastDate = GetLastDate();
	if ( (maOldFormatLastDate != aLastDate) ||
		 (maOldFormatFirstDate != maFirstDate) )
	{
		maOldFormatFirstDate = maFirstDate;
		maOldFormatLastDate  = aLastDate;
		DateRangeChanged();
	}

	// DateInfo besorgen
	USHORT nNewFirstYear = maFirstDate.GetYear();
	USHORT nNewLastYear = GetLastDate().GetYear();
	if ( mnFirstYear )
	{
		if ( nNewFirstYear < mnFirstYear )
		{
			for ( mnRequestYear = nNewFirstYear; mnRequestYear < mnFirstYear; mnRequestYear++ )
				RequestDateInfo();
			mnFirstYear = nNewFirstYear;
		}
		if ( nNewLastYear > mnLastYear )
		{
			for ( mnRequestYear = mnLastYear; mnRequestYear < nNewLastYear; mnRequestYear++ )
				RequestDateInfo();
			mnLastYear = nNewLastYear;
		}
	}
	else
	{
		for ( mnRequestYear = nNewFirstYear; mnRequestYear < nNewLastYear; mnRequestYear++ )
			RequestDateInfo();
		mnFirstYear = nNewFirstYear;
		mnLastYear = nNewLastYear;
	}
	mnRequestYear = 0;

	mbFormat = FALSE;
}

// -----------------------------------------------------------------------

USHORT Calendar::ImplHitTest( const Point& rPos, Date& rDate ) const
{
	if ( mbFormat )
		return 0;

	if ( maPrevRect.IsInside( rPos ) )
		return CALENDAR_HITTEST_PREV;
	else if ( maNextRect.IsInside( rPos ) )
		return CALENDAR_HITTEST_NEXT;

	long		nX;
	long		nY;
	long		nOffX;
	long		nYMonth;
	USHORT		nDay;
	DayOfWeek	eStartDay = ImplGetWeekStart();

	rDate = GetFirstMonth();
	nY = 0;
	for ( long i = 0; i < mnLines; i++ )
	{
		if ( rPos.Y() < nY )
			return 0;

		nX = 0;
		nYMonth = nY+mnMonthHeight;
		for ( long j = 0; j < mnMonthPerLine; j++ )
		{
			if ( (rPos.X() < nX) && (rPos.Y() < nYMonth) )
				return 0;

			USHORT nDaysInMonth = rDate.GetDaysInMonth();

			// Entsprechender Monat gefunden
			if ( (rPos.X() > nX) && (rPos.Y() < nYMonth) &&
				 (rPos.X() < nX+mnMonthWidth) )
			{
				if ( rPos.Y() < (nY+(TITLE_BORDERY*2)+mnDayHeight))
					return CALENDAR_HITTEST_MONTHTITLE;
				else
				{
					long nDayX = nX+mnDaysOffX;
					long nDayY = nY+mnDaysOffY;
					if ( rPos.Y() < nDayY )
						return 0;
					USHORT nDayIndex = (USHORT)rDate.GetDayOfWeek();
					nDayIndex = (nDayIndex+(7-(USHORT)eStartDay)) % 7;
					if ( (i == 0) && (j == 0) )
					{
						Date aTempDate = rDate;
						aTempDate -= nDayIndex;
						for ( nDay = 0; nDay < nDayIndex; nDay++ )
						{
							nOffX = nDayX + (nDay*mnDayWidth);
							if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) &&
								 (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) )
							{
								rDate = aTempDate;
								rDate += nDay;
								return CALENDAR_HITTEST_DAY;
							}
						}
					}
					for ( nDay = 1; nDay <= nDaysInMonth; nDay++ )
					{
						if ( rPos.Y() < nDayY )
						{
							rDate += nDayIndex;
							return 0;
						}
						nOffX = nDayX + (nDayIndex*mnDayWidth);
						if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) &&
							 (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) )
						{
							rDate += nDay-1;
							return CALENDAR_HITTEST_DAY;
						}
						if ( nDayIndex == 6 )
						{
							nDayIndex = 0;
							nDayY += mnDayHeight;
						}
						else
							nDayIndex++;
					}
					if ( (i == mnLines-1) && (j == mnMonthPerLine-1) )
					{
						USHORT nWeekDay = (USHORT)rDate.GetDayOfWeek();
						nWeekDay = (nWeekDay+(7-(USHORT)eStartDay)) % 7;
						USHORT nDayCount = 42-nDaysInMonth-nWeekDay;
						Date aTempDate = rDate;
						aTempDate += nDaysInMonth;
						for ( nDay = 1; nDay <= nDayCount; nDay++ )
						{
							if ( rPos.Y() < nDayY )
							{
								rDate += nDayIndex;
								return 0;
							}
							nOffX = nDayX + (nDayIndex*mnDayWidth);
							if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) &&
								 (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) )
							{
								rDate = aTempDate;
								rDate += nDay-1;
								return CALENDAR_HITTEST_DAY;
							}
							if ( nDayIndex == 6 )
							{
								nDayIndex = 0;
								nDayY += mnDayHeight;
							}
							else
								nDayIndex++;
						}
					}
				}
			}

			rDate += nDaysInMonth;
			nX += mnMonthWidth;
		}

		nY += mnMonthHeight;
	}

	return 0;
}

// -----------------------------------------------------------------------

static void ImplDrawSpinArrow( OutputDevice* pDev, const Rectangle& rRect,
							   BOOL bPrev )
{
	long	i;
	long	n;
	long	nLines;
	long	nHeight = rRect.GetHeight();
	long	nWidth = rRect.GetWidth();
	if ( nWidth < nHeight )
		n = nWidth;
	else
		n = nHeight;
	if ( !(n & 0x01) )
		n--;
	nLines = n/2;

	Rectangle aRect( Point( rRect.Left()+(nWidth/2)-(nLines/2),
							rRect.Top()+(nHeight/2) ),
					 Size( 1, 1 ) );
	if ( !bPrev )
	{
		aRect.Left()  += nLines;
		aRect.Right() += nLines;
	}

	pDev->DrawRect( aRect );
	for ( i = 0; i < nLines; i++ )
	{
		if ( bPrev )
		{
			aRect.Left()++;
			aRect.Right()++;
		}
		else
		{
			aRect.Left()--;
			aRect.Right()--;
		}
		aRect.Top()--;
		aRect.Bottom()++;
		pDev->DrawRect( aRect );
	}
}

// -----------------------------------------------------------------------

void Calendar::ImplDrawSpin( BOOL bDrawPrev, BOOL bDrawNext )
{
	if ( !bDrawPrev && !bDrawNext )
		return;

	SetLineColor();
	SetFillColor( GetSettings().GetStyleSettings().GetButtonTextColor() );
	if ( bDrawPrev )
	{
		Rectangle aOutRect = maPrevRect;
		aOutRect.Left()   += 3;
		aOutRect.Top()	  += 3;
		aOutRect.Right()  -= 3;
		aOutRect.Bottom() -= 3;
		ImplDrawSpinArrow( this, aOutRect, TRUE );
	}
	if ( bDrawNext )
	{
		Rectangle aOutRect = maNextRect;
		aOutRect.Left()   += 3;
		aOutRect.Top()	  += 3;
		aOutRect.Right()  -= 3;
		aOutRect.Bottom() -= 3;
		ImplDrawSpinArrow( this, aOutRect, FALSE );
	}
}

// -----------------------------------------------------------------------

void Calendar::ImplDrawDate( long nX, long nY,
							 USHORT nDay, USHORT nMonth, USHORT nYear,
							 DayOfWeek eDayOfWeek,
							 BOOL bBack, BOOL bOther, ULONG nToday )
{
	ImplDateInfo*	pDateInfo;
	Color*			pTextColor = NULL;
	const String&	rDay = *(mpDayText[nDay-1]);
	Rectangle		aDateRect( nX, nY, nX+mnDayWidth-1, nY+mnDayHeight-1 );

	BOOL bSel = FALSE;
	BOOL bFocus = FALSE;
	// Aktueller Tag
	if ( (nDay	 == maCurDate.GetDay()) &&
		 (nMonth == maCurDate.GetMonth()) &&
		 (nYear  == maCurDate.GetYear()) )
		bFocus = TRUE;
	if ( mpSelectTable )
	{
		if ( mpSelectTable->IsKeyValid( Date( nDay, nMonth, nYear ).GetDate() ) )
			bSel = TRUE;
	}

	// Dateinfo ermitteln
	if ( mpDateTable )
	{
		pDateInfo = mpDateTable->Get( Date( nDay, nMonth, nYear ).GetDate() );
		if ( !pDateInfo )
			pDateInfo = mpDateTable->Get( Date( nDay, nMonth, 0 ).GetDate() );
	}
	else
		pDateInfo = NULL;

	// Textfarbe ermitteln
	if ( bSel )
		pTextColor = &maSelColor;
	else if ( bOther )
		pTextColor = &maOtherColor;
	else
	{
		if ( pDateInfo && pDateInfo->mpTextColor )
			pTextColor = pDateInfo->mpTextColor;
		else
		{
			if ( eDayOfWeek == SATURDAY )
				pTextColor = mpSaturdayColor;
			else if ( eDayOfWeek == SUNDAY )
				pTextColor = mpSundayColor;
			if ( !pTextColor )
				pTextColor = mpStandardColor;
		}
	}

	if ( bFocus )
		HideFocus();

	// Font ermitteln
	Font aOldFont = GetFont();
	BOOL bBoldFont = FALSE;
	if ( (mnWinStyle & WB_BOLDTEXT) &&
		 pDateInfo && (pDateInfo->mnFlags & DIB_BOLD) )
	{
		bBoldFont = TRUE;
		Font aFont = aOldFont;
		if ( aFont.GetWeight() < WEIGHT_BOLD )
			aFont.SetWeight( WEIGHT_BOLD );
		else
			aFont.SetWeight( WEIGHT_NORMAL );
		SetFont( aFont );
	}

	// Hintergrund ausgeben
	const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
	if ( bSel || bBack )
	{
		if ( bSel )
		{
			SetLineColor();
			SetFillColor( rStyleSettings.GetHighlightColor() );
			DrawRect( aDateRect );
		}
		else
			Erase( aDateRect );
	}

	// Text ausgeben
	long nTextX = nX+(mnDayWidth-GetTextWidth( rDay ))-(DAY_OFFX/2);
	long nTextY = nY+(mnDayHeight-GetTextHeight())/2;
	if ( pTextColor )
	{
		Color aOldColor = GetTextColor();
		SetTextColor( *pTextColor );
		DrawText( Point( nTextX, nTextY ), rDay );
		SetTextColor( aOldColor );
	}
	else
		DrawText( Point( nTextX, nTextY ), rDay );

	// Heute
	Date aTodayDate( maCurDate );
	if ( nToday )
		aTodayDate.SetDate( nToday );
	else
		aTodayDate = Date();
	if ( (nDay	 == aTodayDate.GetDay()) &&
		 (nMonth == aTodayDate.GetMonth()) &&
		 (nYear  == aTodayDate.GetYear()) )
	{
		SetLineColor( rStyleSettings.GetWindowTextColor() );
		SetFillColor();
		DrawRect( aDateRect );
	}

	// Evt. DateInfo ausgeben
	if ( (mnWinStyle & WB_FRAMEINFO) && pDateInfo && pDateInfo->mpFrameColor )
	{
		SetLineColor( *(pDateInfo->mpFrameColor) );
		SetFillColor();
		Rectangle aFrameRect( aDateRect );
		aFrameRect.Left()++;
		aFrameRect.Top()++;
		long nFrameWidth = aFrameRect.GetWidth();
		long nFrameHeight = aFrameRect.GetHeight();
		long nFrameOff;
		if ( nFrameWidth < nFrameHeight )
		{
			nFrameOff = nFrameHeight-nFrameWidth;
			aFrameRect.Top() += nFrameOff/2;
			nFrameOff %= 2;
			aFrameRect.Bottom() -= nFrameOff;
		}
		else if ( nFrameWidth > nFrameHeight )
		{
			nFrameOff = nFrameWidth-nFrameHeight;
			aFrameRect.Left() += nFrameOff/2;
			nFrameOff %= 2;
			aFrameRect.Right() -= nFrameOff;
		}
		DrawEllipse( aFrameRect );
	}

	// Evt. noch FocusRect
	if ( bFocus && HasFocus() )
		ShowFocus( aDateRect );

	if( mbDropPos && maDropDate == Date( nDay, nMonth, nYear ) )
		ImplInvertDropPos();

	if ( bBoldFont )
		SetFont( aOldFont );
}

// -----------------------------------------------------------------------

void Calendar::ImplDraw( BOOL bPaint )
{
	ImplFormat();

	const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
	Size		aOutSize = GetOutputSizePixel();
	long		i;
	long		j;
	long		nX;
	long		nY;
	long		nDeltaX;
	long		nDeltaY;
	long		nDayX;
	long		nDayY;
	ULONG		nToday = Date().GetDate();
	USHORT		nDay;
	USHORT		nMonth;
	USHORT		nYear;
	Date		aDate = GetFirstMonth();
	DayOfWeek	eStartDay = ImplGetWeekStart();

	HideFocus();

	nY = 0;
	for ( i = 0; i < mnLines; i++ )
	{
		// Titleleiste ausgeben
		SetLineColor();
		SetFillColor( rStyleSettings.GetFaceColor() );
		Rectangle aTitleRect( 0, nY, aOutSize.Width()-1, nY+mnDayHeight-DAY_OFFY+TITLE_BORDERY*2 );
		if ( !bPaint )
		{
			Rectangle aTempRect( 1, aTitleRect.Top()+TITLE_BORDERY,
								 aOutSize.Width()-2,
								 aTitleRect.Bottom()-TITLE_BORDERY );
			if ( !i )
			{
				aTempRect.Left()  = maPrevRect.Right()+1;
				aTempRect.Right() = maNextRect.Left()-1;
			}
			DrawRect( aTempRect );
		}
		else
		{
			DrawRect( aTitleRect );
			Point aTopLeft1( aTitleRect.Left(), aTitleRect.Top() );
			Point aTopLeft2( aTitleRect.Left(), aTitleRect.Top()+1 );
			Point aBottomRight1( aTitleRect.Right(), aTitleRect.Bottom() );
			Point aBottomRight2( aTitleRect.Right(), aTitleRect.Bottom()-1 );
			SetLineColor( rStyleSettings.GetDarkShadowColor() );
			DrawLine( aTopLeft1, Point( aBottomRight1.X(), aTopLeft1.Y() ) );
			SetLineColor( rStyleSettings.GetLightColor() );
			DrawLine( aTopLeft2, Point( aBottomRight2.X(), aTopLeft2.Y() ) );
			DrawLine( aTopLeft2, Point( aTopLeft2.X(), aBottomRight2.Y() ) );
			SetLineColor( rStyleSettings.GetShadowColor() );
			DrawLine( Point( aTopLeft2.X(), aBottomRight2.Y() ), aBottomRight2 );
			DrawLine( Point( aBottomRight2.X(), aTopLeft2.Y() ), aBottomRight2 );
			SetLineColor( rStyleSettings.GetDarkShadowColor() );
			DrawLine( Point( aTopLeft1.X(), aBottomRight1.Y() ), aBottomRight1 );
		}
		Point aSepPos1( 0, aTitleRect.Top()+TITLE_BORDERY );
		Point aSepPos2( 0, aTitleRect.Bottom()-TITLE_BORDERY );
		for ( j = 0; j < mnMonthPerLine-1; j++ )
		{
			aSepPos1.X() += mnMonthWidth-1;
			aSepPos2.X() = aSepPos1.X();
			SetLineColor( rStyleSettings.GetShadowColor() );
			DrawLine( aSepPos1, aSepPos2 );
			aSepPos1.X()++;
			aSepPos2.X() = aSepPos1.X();
			SetLineColor( rStyleSettings.GetLightColor() );
			DrawLine( aSepPos1, aSepPos2 );
		}

		nX = 0;
		for ( j = 0; j < mnMonthPerLine; j++ )
		{
			nMonth	= aDate.GetMonth();
			nYear	= aDate.GetYear();

			// Monat in der Titleleiste ausgeben
			nDeltaX = nX;
			nDeltaY = nY+TITLE_BORDERY;
            String aMonthText( maCalendarWrapper.getDisplayName(
                        i18n::CalendarDisplayIndex::MONTH, nMonth-1, 1));
			aMonthText += ' ';
			aMonthText += String::CreateFromInt64( nYear );
			long nMonthTextWidth = GetTextWidth( aMonthText );
			long nMonthOffX1 = 0;
			long nMonthOffX2 = 0;
			if ( i == 0 )
			{
				if ( j == 0 )
					nMonthOffX1 = maPrevRect.Right()+1;
				if ( j == mnMonthPerLine-1 )
					nMonthOffX2 = aOutSize.Width()-maNextRect.Left()+1;
			}
			long nMaxMonthWidth = mnMonthWidth-nMonthOffX1-nMonthOffX2-4;
			if ( nMonthTextWidth > nMaxMonthWidth )
			{
				// Abbreviated month name.
                aMonthText  = maCalendarWrapper.getDisplayName(
                        i18n::CalendarDisplayIndex::MONTH, nMonth-1, 0);
				aMonthText += ' ';
				aMonthText += String::CreateFromInt64( nYear );
				nMonthTextWidth = GetTextWidth( aMonthText );
			}
			long nTempOff = (mnMonthWidth-nMonthTextWidth+1)/2;
			if ( nTempOff < nMonthOffX1 )
				nDeltaX += nMonthOffX1+1;
			else
			{
				if ( nTempOff+nMonthTextWidth > mnMonthWidth-nMonthOffX2 )
					nDeltaX += mnMonthWidth-nMonthOffX2-nMonthTextWidth;
				else
					nDeltaX += nTempOff;
			}
			SetTextColor( rStyleSettings.GetButtonTextColor() );
			DrawText( Point( nDeltaX, nDeltaY ), aMonthText );
			SetTextColor( rStyleSettings.GetWindowTextColor() );

			// Weekleiste ausgeben
			if ( bPaint )
			{
				nDayX = nX+mnDaysOffX;
				nDayY = nY+mnWeekDayOffY;
				nDeltaY = nDayY + mnDayHeight;
				SetLineColor( rStyleSettings.GetWindowTextColor() );
				Point aStartPos( nDayX, nDeltaY );
				if ( mnWinStyle & WB_WEEKNUMBER )
					aStartPos.X() -= WEEKNUMBER_OFFX-2;
				DrawLine( aStartPos, Point( nDayX+(7*mnDayWidth), nDeltaY ) );
				DrawTextArray( Point( nDayX+mnDayOfWeekAry[0], nDayY ), maDayOfWeekText, &(mnDayOfWeekAry[1]) );
			}

			// Week-Numbers ausgeben
			if ( mnWinStyle & WB_WEEKNUMBER )
			{
				nDayX = nX+mnDaysOffX;
				nDayY = nY+mnWeekDayOffY;
				nDeltaY = nDayY + mnDayHeight;
				long nMonthHeight = mnDayHeight*6;
				if ( bPaint )
					DrawLine( Point( nDayX-WEEKNUMBER_OFFX+2, nDeltaY ), Point( nDayX-WEEKNUMBER_OFFX+2, nDeltaY+nMonthHeight ) );
				else
					Erase( Rectangle( nDayX-mnWeekWidth-WEEKNUMBER_OFFX, nDeltaY, nDayX-WEEKNUMBER_OFFX-1, nDeltaY+nMonthHeight ) );

				Font aOldFont = GetFont();
				Font aTempFont = aOldFont;
				ImplGetWeekFont( aTempFont );
				SetFont( aTempFont );
				nDayX -= mnWeekWidth;
				nDayY = nY+mnDaysOffY;
                maCalendarWrapper.setGregorianDateTime( aDate);
				for ( USHORT nWeekCount = 0; nWeekCount < 6; nWeekCount++ )
				{
                    sal_Int16 nWeek = maCalendarWrapper.getValue( i18n::CalendarFieldIndex::WEEK_OF_YEAR);
					String	aWeekText( String::CreateFromInt32( nWeek));
					long	nOffX = (mnWeekWidth-WEEKNUMBER_OFFX)-GetTextWidth( aWeekText );
					long	nOffY = (mnDayHeight-GetTextHeight())/2;
					DrawText( Point( nDayX+nOffX, nDayY+nOffY ), aWeekText );
					nDayY += mnDayHeight;
                    maCalendarWrapper.addValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, 7);
				}
				SetFont( aOldFont );
			}

			// Tage ausgeben
			USHORT nDaysInMonth = aDate.GetDaysInMonth();
			nDayX = nX+mnDaysOffX;
			nDayY = nY+mnDaysOffY;
			if ( !bPaint )
			{
				Rectangle aClearRect( nDayX, nDayY,
									  nDayX+(7*mnDayWidth)-1, nDayY+(6*mnDayHeight)-1 );
				Erase( aClearRect );
			}
			USHORT nDayIndex = (USHORT)aDate.GetDayOfWeek();
			nDayIndex = (nDayIndex+(7-(USHORT)eStartDay)) % 7;
			if ( (i == 0) && (j == 0) )
			{
				Date aTempDate = aDate;
				aTempDate -= nDayIndex;
				for ( nDay = 0; nDay < nDayIndex; nDay++ )
				{
					nDeltaX = nDayX + (nDay*mnDayWidth);
					ImplDrawDate( nDeltaX, nDayY, nDay+aTempDate.GetDay(),
								  aTempDate.GetMonth(), aTempDate.GetYear(),
								  (DayOfWeek)((nDay+(USHORT)eStartDay)%7), FALSE, TRUE, nToday );
				}
			}
			for ( nDay = 1; nDay <= nDaysInMonth; nDay++ )
			{
				nDeltaX = nDayX + (nDayIndex*mnDayWidth);
				ImplDrawDate( nDeltaX, nDayY, nDay, nMonth, nYear,
							  (DayOfWeek)((nDayIndex+(USHORT)eStartDay)%7),
							  FALSE, FALSE, nToday );
				if ( nDayIndex == 6 )
				{
					nDayIndex = 0;
					nDayY += mnDayHeight;
				}
				else
					nDayIndex++;
			}
			if ( (i == mnLines-1) && (j == mnMonthPerLine-1) )
			{
				USHORT nWeekDay = (USHORT)aDate.GetDayOfWeek();
				nWeekDay = (nWeekDay+(7-(USHORT)eStartDay)) % 7;
				USHORT nDayCount = 42-nDaysInMonth-nWeekDay;
				Date aTempDate = aDate;
				aTempDate += nDaysInMonth;
				for ( nDay = 1; nDay <= nDayCount; nDay++ )
				{
					nDeltaX = nDayX + (nDayIndex*mnDayWidth);
					ImplDrawDate( nDeltaX, nDayY, nDay,
								  aTempDate.GetMonth(), aTempDate.GetYear(),
								  (DayOfWeek)((nDayIndex+(USHORT)eStartDay)%7),
								  FALSE, TRUE, nToday );
					if ( nDayIndex == 6 )
					{
						nDayIndex = 0;
						nDayY += mnDayHeight;
					}
					else
						nDayIndex++;
				}
			}

			aDate += nDaysInMonth;
			nX += mnMonthWidth;
		}

		nY += mnMonthHeight;
	}

	// Spin-Buttons zeichnen
	if ( bPaint )
		ImplDrawSpin();
}

// -----------------------------------------------------------------------

void Calendar::ImplUpdateDate( const Date& rDate )
{
	if ( IsReallyVisible() && IsUpdateMode() )
	{
		Rectangle aDateRect( GetDateRect( rDate ) );
		if ( !aDateRect.IsEmpty() )
		{
			BOOL bOther = (rDate < GetFirstMonth()) || (rDate > GetLastMonth());
			ImplDrawDate( aDateRect.Left(), aDateRect.Top(),
						  rDate.GetDay(), rDate.GetMonth(), rDate.GetYear(),
						  rDate.GetDayOfWeek(), TRUE, bOther );
		}
	}
}

// -----------------------------------------------------------------------

void Calendar::ImplUpdateSelection( Table* pOld )
{
	Table*	pNew = mpSelectTable;
	void*	p;
	ULONG	nKey;

	p = pOld->First();
	while ( p )
	{
		nKey = pOld->GetCurKey();
		if ( !pNew->Get( nKey ) )
		{
			Date aTempDate( nKey );
			ImplUpdateDate( aTempDate );
		}

		p = pOld->Next();
	}

	p = pNew->First();
	while ( p )
	{
		nKey = pNew->GetCurKey();
		if ( !pOld->Get( nKey ) )
		{
			Date aTempDate( nKey );
			ImplUpdateDate( aTempDate );
		}

		p = pNew->Next();
	}
}

// -----------------------------------------------------------------------

void Calendar::ImplMouseSelect( const Date& rDate, USHORT nHitTest,
								BOOL bMove, BOOL bExpand, BOOL bExtended )
{
	Table*	pOldSel = new Table( *mpSelectTable );
	Date	aOldDate = maCurDate;
	Date	aTempDate = rDate;

	if ( !(nHitTest & CALENDAR_HITTEST_DAY) )
		aTempDate--;

	if ( mbMultiSelection )
	{
		maCurDate = aTempDate;
		mbSelLeft = aTempDate < maAnchorDate;

		if ( bMove )
		{
			if ( mbSelLeft )
			{
				ImplCalendarUnSelectDateRange( mpSelectTable, mpRestoreSelectTable, Date( 1, 1, 0 ), aTempDate );
				ImplCalendarUnSelectDateRange( mpSelectTable, mpRestoreSelectTable, maAnchorDate, Date( 31, 12, 9999 ) );
			}
			else
			{
				ImplCalendarUnSelectDateRange( mpSelectTable, mpRestoreSelectTable, Date( 1, 1, 0 ), maAnchorDate );
				ImplCalendarUnSelectDateRange( mpSelectTable, mpRestoreSelectTable, aTempDate, Date( 31, 12, 9999 ) );
			}
			ImplCalendarSelectDateRange( mpSelectTable, aTempDate, maAnchorDate, !mbUnSel );
		}
		else
		{
			if ( bExpand )
			{
				if ( !bExtended )
				{
					if ( mbSelLeft )
					{
						ImplCalendarSelectDateRange( mpSelectTable, Date( 1, 1, 0 ), aTempDate, FALSE );
						ImplCalendarSelectDateRange( mpSelectTable, maAnchorDate, Date( 31, 12, 9999 ), FALSE );
					}
					else
					{
						ImplCalendarSelectDateRange( mpSelectTable, Date( 1, 1, 0 ), maAnchorDate, FALSE );
						ImplCalendarSelectDateRange( mpSelectTable, aTempDate, Date( 31, 12, 9999 ), FALSE );
					}
				}
				ImplCalendarSelectDateRange( mpSelectTable, aTempDate, maAnchorDate, TRUE );
			}
			else if ( bExtended && !(mnWinStyle & WB_RANGESELECT) )
			{
				maAnchorDate = aTempDate;
				if ( IsDateSelected( aTempDate ) )
				{
					mbUnSel = TRUE;
					ImplCalendarSelectDate( mpSelectTable, aTempDate, FALSE );
				}
				else
				{
					ImplCalendarSelectDate( mpSelectTable, aTempDate, TRUE );
				}
			}
			else
			{
				maAnchorDate = aTempDate;
				ImplCalendarClearSelectDate( mpSelectTable );
				ImplCalendarSelectDate( mpSelectTable, aTempDate, TRUE );
			}

			mpRestoreSelectTable = new Table( *mpSelectTable );
		}
	}
	else
	{
		if ( aTempDate < maCurDate )
			mbSelLeft = TRUE;
		else
			mbSelLeft = FALSE;
		if ( !(nHitTest & CALENDAR_HITTEST_DAY) )
			aTempDate = maOldCurDate;
		if ( !bMove )
			maAnchorDate = aTempDate;
		if ( aTempDate != maCurDate )
		{
			maCurDate = aTempDate;
			ImplCalendarSelectDate( mpSelectTable, aOldDate, FALSE );
			ImplCalendarSelectDate( mpSelectTable, maCurDate, TRUE );
		}
	}

	BOOL bNewSel = *pOldSel != *mpSelectTable;
	if ( (maCurDate != aOldDate) || bNewSel )
	{
		if ( bNewSel )
		{
			mbInSelChange = TRUE;
			SelectionChanging();
			mbInSelChange = FALSE;
		}
		HideFocus();
		if ( bNewSel )
			ImplUpdateSelection( pOldSel );
		if ( !bNewSel || !pOldSel->Get( aOldDate.GetDate() ) )
			ImplUpdateDate( aOldDate );
		// Damit Focus-Rechteck auch wieder neu ausgegeben wird
		if ( HasFocus() || !bNewSel || !mpSelectTable->Get( maCurDate.GetDate() ) )
			ImplUpdateDate( maCurDate );
	}
	delete pOldSel;
}

// -----------------------------------------------------------------------

void Calendar::ImplUpdate( BOOL bCalcNew )
{
	if ( IsReallyVisible() && IsUpdateMode() )
	{
		if ( bCalcNew && !mbCalc )
			Invalidate();
		else if ( !mbFormat && !mbCalc )
		{
			if ( mbDirect )
			{
				mbFormat = TRUE;
				ImplDraw( FALSE );
				return;
			}
			else
				Invalidate();
		}
	}

	if ( bCalcNew )
		mbCalc = TRUE;
	mbFormat = TRUE;
}

// -----------------------------------------------------------------------

void Calendar::ImplInvertDropPos()
{
	Rectangle aRect = GetDateRect( maDropDate );//this is one Pixel to width and one to heigh
	aRect.Bottom() = aRect.Top()+mnDayHeight-1;
	aRect.Right() = aRect.Left()+mnDayWidth-1;
	Invert( aRect );
}

// -----------------------------------------------------------------------

void Calendar::ImplScroll( BOOL bPrev )
{
	Date aNewFirstMonth = GetFirstMonth();
	if ( bPrev )
	{
		aNewFirstMonth--;
		aNewFirstMonth -= aNewFirstMonth.GetDaysInMonth()-1;
	}
	else
		aNewFirstMonth += aNewFirstMonth.GetDaysInMonth();
	mbDirect = TRUE;
	SetFirstDate( aNewFirstMonth );
	mbDirect = FALSE;
}

// -----------------------------------------------------------------------

void Calendar::ImplShowMenu( const Point& rPos, const Date& rDate )
{
	EndSelection();

	Date		aOldFirstDate = GetFirstMonth();
	PopupMenu	aPopupMenu;
	PopupMenu*	pYearPopupMenus[MENU_YEAR_COUNT];
	USHORT		nMonthOff;
	USHORT		nCurItemId;
	USHORT		nYear = rDate.GetYear()-1;
	USHORT		i;
	USHORT		j;
	USHORT		nYearIdCount = 1000;

	nMonthOff = (rDate.GetYear()-aOldFirstDate.GetYear())*12;
	if ( aOldFirstDate.GetMonth() < rDate.GetMonth() )
		nMonthOff += rDate.GetMonth()-aOldFirstDate.GetMonth();
	else
		nMonthOff -= aOldFirstDate.GetMonth()-rDate.GetMonth();

	// Menu aufbauen (Jahre mit verschiedenen Monaten aufnehmen)
	for ( i = 0; i < MENU_YEAR_COUNT; i++ )
	{
		pYearPopupMenus[i] = new PopupMenu;
		for ( j = 1; j <= 12; j++ )
            pYearPopupMenus[i]->InsertItem( nYearIdCount+j,
                    maCalendarWrapper.getDisplayName(
                        i18n::CalendarDisplayIndex::MONTH, j-1, 1));
		aPopupMenu.InsertItem( 10+i, UniString::CreateFromInt32( nYear+i ) );
		aPopupMenu.SetPopupMenu( 10+i, pYearPopupMenus[i] );
		nYearIdCount += 1000;
	}

	mbMenuDown = TRUE;
	nCurItemId = aPopupMenu.Execute( this, rPos );
	mbMenuDown = FALSE;

	// Menu zerstoeren
	aPopupMenu.SetPopupMenu( 2, NULL );
	for ( i = 0; i < MENU_YEAR_COUNT; i++ )
	{
		aPopupMenu.SetPopupMenu( 10+i, NULL );
		delete pYearPopupMenus[i];
	}

	if ( nCurItemId )
	{
		USHORT nTempMonthOff = nMonthOff % 12;
		USHORT nTempYearOff = nMonthOff / 12;
		USHORT nNewMonth = nCurItemId % 1000;
		USHORT nNewYear = nYear+((nCurItemId-1000)/1000);
		if ( nTempMonthOff < nNewMonth )
			nNewMonth = nNewMonth - nTempMonthOff;
		else
		{
			nNewYear--;
			nNewMonth = 12-(nTempMonthOff-nNewMonth);
		}
		nNewYear = nNewYear - nTempYearOff;
		SetFirstDate( Date( 1, nNewMonth, nNewYear ) );
	}
}

// -----------------------------------------------------------------------

void Calendar::ImplTracking( const Point& rPos, BOOL bRepeat )
{
	Date	aTempDate = maCurDate;
	USHORT	nHitTest = ImplHitTest( rPos, aTempDate );

	if ( mbSpinDown )
	{
		mbPrevIn = (nHitTest & CALENDAR_HITTEST_PREV) != 0;
		mbNextIn = (nHitTest & CALENDAR_HITTEST_NEXT) != 0;

		if ( bRepeat && (mbPrevIn || mbNextIn) )
		{
			mbScrollDateRange = TRUE;
			ImplScroll( mbPrevIn );
			mbScrollDateRange = FALSE;
		}
	}
	else
		ImplMouseSelect( aTempDate, nHitTest, TRUE, FALSE, FALSE );
}

// -----------------------------------------------------------------------

void Calendar::ImplEndTracking( BOOL bCancel )
{
	BOOL bSelection = mbSelection;
	BOOL bSpinDown = mbSpinDown;

	mbDrag				= FALSE;
	mbSelection 		= FALSE;
	mbMultiSelection	= FALSE;
	mbUnSel 			= FALSE;
	mbSpinDown			= FALSE;
	mbPrevIn			= FALSE;
	mbNextIn			= FALSE;

	if ( bCancel )
	{
		if ( maOldFirstDate != maFirstDate )
			SetFirstDate( maOldFirstDate );

		if ( !bSpinDown )
		{
			Table*	pOldSel = new Table( *mpSelectTable );
			Date	aOldDate = maCurDate;
			maCurDate		= maOldCurDate;
			*mpSelectTable	= *mpOldSelectTable;
			HideFocus();
			ImplUpdateSelection( pOldSel );
			if ( !pOldSel->Get( aOldDate.GetDate() ) )
				ImplUpdateDate( aOldDate );
			// Damit Focus-Rechteck auch wieder neu ausgegeben wird
			if ( HasFocus() || !mpSelectTable->Get( maCurDate.GetDate() ) )
				ImplUpdateDate( maCurDate );
			delete pOldSel;
		}
	}

	if ( !bSpinDown )
	{
		if ( !bCancel )
		{
			// Feststellen, ob wir sichtbaren Bereich scrollen sollen
			ULONG nSelCount = mpSelectTable->Count();
			if ( nSelCount )
			{
				Date aFirstSelDate( mpSelectTable->GetObjectKey( 0 ) );
				Date aLastSelDate( mpSelectTable->GetObjectKey( nSelCount-1 ) );
				if ( aLastSelDate < GetFirstMonth() )
					ImplScroll( TRUE );
				else if ( GetLastMonth() < aFirstSelDate )
					ImplScroll( FALSE );
			}
		}

		if ( mbAllSel ||
			 (!bCancel && ((maCurDate != maOldCurDate) || (*mpOldSelectTable != *mpSelectTable))) )
			Select();

		if ( !bSelection && (mnWinStyle & WB_TABSTOP) && !bCancel )
			GrabFocus();

		delete mpOldSelectTable;
		mpOldSelectTable = NULL;
		delete mpRestoreSelectTable;
		mpRestoreSelectTable = NULL;
	}
}

// -----------------------------------------------------------------------

IMPL_STATIC_LINK( Calendar, ScrollHdl, Timer*, EMPTYARG )
{
	BOOL bPrevIn = (pThis->mnDragScrollHitTest & CALENDAR_HITTEST_PREV) != 0;
	BOOL bNextIn = (pThis->mnDragScrollHitTest & CALENDAR_HITTEST_NEXT) != 0;
	if( bNextIn || bPrevIn )
	{
		pThis->mbScrollDateRange = TRUE;
		pThis->ImplScroll( bPrevIn );
		pThis->mbScrollDateRange = FALSE;
	}
	return 0;
}

// -----------------------------------------------------------------------

void Calendar::MouseButtonDown( const MouseEvent& rMEvt )
{
	if ( rMEvt.IsLeft() && !mbMenuDown )
	{
		Date	aTempDate = maCurDate;
		USHORT	nHitTest = ImplHitTest( rMEvt.GetPosPixel(), aTempDate );
		if ( nHitTest )
		{
			if ( nHitTest & CALENDAR_HITTEST_MONTHTITLE )
				ImplShowMenu( rMEvt.GetPosPixel(), aTempDate );
			else
			{
				maOldFirstDate = maFirstDate;

				mbPrevIn = (nHitTest & CALENDAR_HITTEST_PREV) != 0;
				mbNextIn = (nHitTest & CALENDAR_HITTEST_NEXT) != 0;
				if ( mbPrevIn || mbNextIn )
				{
					mbSpinDown = TRUE;
					mbScrollDateRange = TRUE;
					ImplScroll( mbPrevIn );
					mbScrollDateRange = FALSE;
					// Hier muss BUTTONREPEAT stehen, also nicht wieder
					// auf SCROLLREPEAT aendern, sondern mit TH abklaeren,
					// warum es evtl. anders sein sollte (71775)
					StartTracking( STARTTRACK_BUTTONREPEAT );
				}
				else
				{
					if ( (rMEvt.GetClicks() == 2) && (nHitTest & CALENDAR_HITTEST_DAY) )
						DoubleClick();
					else
					{
						if ( mpOldSelectTable )
							delete mpOldSelectTable;
						maOldCurDate = maCurDate;
						mpOldSelectTable = new Table( *mpSelectTable );

						if ( !mbSelection )
						{
							mbDrag = TRUE;
							StartTracking();
						}

						mbMultiSelection = (mnWinStyle & (WB_MULTISELECT | WB_RANGESELECT)) != 0;
						if ( (nHitTest & CALENDAR_HITTEST_DAY) && mbMultiSelection )
							mbWeekSel = TRUE;
						else
							mbWeekSel = FALSE;
						ImplMouseSelect( aTempDate, nHitTest, FALSE, rMEvt.IsShift(), rMEvt.IsMod1() );
					}
				}
			}
		}

		return;
	}

	Control::MouseButtonDown( rMEvt );
}

// -----------------------------------------------------------------------

void Calendar::MouseButtonUp( const MouseEvent& rMEvt )
{
	if ( rMEvt.IsLeft() && mbSelection )
		ImplEndTracking( FALSE );
	else
		Control::MouseButtonUp( rMEvt );
}

// -----------------------------------------------------------------------

void Calendar::MouseMove( const MouseEvent& rMEvt )
{
	if ( mbSelection && rMEvt.GetButtons() )
		ImplTracking( rMEvt.GetPosPixel(), FALSE );
	else
		Control::MouseMove( rMEvt );
}

// -----------------------------------------------------------------------

void Calendar::Tracking( const TrackingEvent& rTEvt )
{
	Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel();

	if ( rTEvt.IsTrackingEnded() )
		ImplEndTracking( rTEvt.IsTrackingCanceled() );
	else
		ImplTracking( aMousePos, rTEvt.IsTrackingRepeat() );
}

// -----------------------------------------------------------------------

void Calendar::KeyInput( const KeyEvent& rKEvt )
{
	Date	aNewDate = maCurDate;
	BOOL	bMultiSel = (mnWinStyle & (WB_RANGESELECT | WB_MULTISELECT)) != 0;
	BOOL	bExpand = rKEvt.GetKeyCode().IsShift();
	BOOL	bExtended = rKEvt.GetKeyCode().IsMod1();

	switch ( rKEvt.GetKeyCode().GetCode() )
	{
		case KEY_HOME:
			aNewDate.SetDay( 1 );
			break;

		case KEY_END:
			aNewDate.SetDay( aNewDate.GetDaysInMonth() );
			break;

		case KEY_LEFT:
			aNewDate--;
			break;

		case KEY_RIGHT:
			aNewDate++;
			break;

		case KEY_UP:
			aNewDate -= 7;
			break;

		case KEY_DOWN:
			aNewDate += 7;
			break;

		case KEY_PAGEUP:
			{
			Date aTempDate = aNewDate;
			aTempDate -= aNewDate.GetDay()+1;
			aNewDate -= aTempDate.GetDaysInMonth();
			}
			break;

		case KEY_PAGEDOWN:
			aNewDate += aNewDate.GetDaysInMonth();
			break;

		case KEY_SPACE:
			if ( bMultiSel && !(mnWinStyle & WB_RANGESELECT) )
			{
				if ( !bExpand )
				{
					BOOL bDateSel = IsDateSelected( maCurDate );
					SelectDate( maCurDate, !bDateSel );
					mbSelLeft = FALSE;
					SelectionChanging();
					mbTravelSelect = TRUE;
					Select();
					mbTravelSelect = FALSE;
				}
			}
			else
				Control::KeyInput( rKEvt );
			break;

		default:
			Control::KeyInput( rKEvt );
			break;
	}

	if ( aNewDate != maCurDate )
	{
		if ( bMultiSel && bExpand )
		{
			Table* pOldSel = new Table( *mpSelectTable );
			Date aOldAnchorDate = maAnchorDate;
			mbSelLeft = aNewDate < maAnchorDate;
			if ( !bExtended )
			{
				if ( mbSelLeft )
				{
					ImplCalendarSelectDateRange( mpSelectTable, Date( 1, 1, 0 ), aNewDate, FALSE );
					ImplCalendarSelectDateRange( mpSelectTable, maAnchorDate, Date( 31, 12, 9999 ), FALSE );
				}
				else
				{
					ImplCalendarSelectDateRange( mpSelectTable, Date( 1, 1, 0 ), maAnchorDate, FALSE );
					ImplCalendarSelectDateRange( mpSelectTable, aNewDate, Date( 31, 12, 9999 ), FALSE );
				}
			}
			ImplCalendarSelectDateRange( mpSelectTable, aNewDate, maAnchorDate, TRUE );
			mbDirect = TRUE;
			SetCurDate( aNewDate );
			mbDirect = FALSE;
			maAnchorDate = aOldAnchorDate;
			mbInSelChange = TRUE;
			SelectionChanging();
			mbInSelChange = FALSE;
			ImplUpdateSelection( pOldSel );
            delete pOldSel;
		}
		else
		{
			if ( mnWinStyle & WB_RANGESELECT )
			{
				SetNoSelection();
				SelectDate( aNewDate, TRUE );
			}
			mbDirect = TRUE;
			SetCurDate( aNewDate );
			mbDirect = FALSE;
		}
		mbTravelSelect = TRUE;
		Select();
		mbTravelSelect = FALSE;
	}
}

// -----------------------------------------------------------------------

void Calendar::Paint( const Rectangle& )
{
	ImplDraw( TRUE );
}

// -----------------------------------------------------------------------

void Calendar::GetFocus()
{
	ImplUpdateDate( maCurDate );
	Control::GetFocus();
}

// -----------------------------------------------------------------------

void Calendar::LoseFocus()
{
	HideFocus();
	Control::LoseFocus();
}

// -----------------------------------------------------------------------

void Calendar::Resize()
{
	ImplUpdate( TRUE );
	Control::Resize();
}

// -----------------------------------------------------------------------

void Calendar::RequestHelp( const HelpEvent& rHEvt )
{
	if ( rHEvt.GetMode() & (HELPMODE_QUICK | HELPMODE_BALLOON) )
	{
		Date aDate = maCurDate;
		if ( GetDate( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ), aDate ) )
		{
			Rectangle aDateRect = GetDateRect( aDate );
			Point aPt = OutputToScreenPixel( aDateRect.TopLeft() );
			aDateRect.Left()   = aPt.X();
			aDateRect.Top()    = aPt.Y();
			aPt = OutputToScreenPixel( aDateRect.BottomRight() );
			aDateRect.Right()  = aPt.X();
			aDateRect.Bottom() = aPt.Y();

			if ( (rHEvt.GetMode() & HELPMODE_BALLOON) || (mnWinStyle & WB_QUICKHELPSHOWSDATEINFO) )
			{
				ImplDateInfo* pInfo;
				if ( mpDateTable )
				{
					pInfo = mpDateTable->Get( aDate.GetDate() );
					if ( !pInfo )
						pInfo = mpDateTable->Get( Date( aDate.GetDay(), aDate.GetMonth(), 0 ).GetDate() );
				}
				else
					pInfo = NULL;
				if ( pInfo )
				{
					XubString aStr = pInfo->maText;
					if ( aStr.Len() )
					{
						Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), aDateRect, aStr );
						return;
					}
				}
			}

			if ( rHEvt.GetMode() & HELPMODE_QUICK )
			{
                maCalendarWrapper.setGregorianDateTime( aDate);
                USHORT      nWeek = (USHORT) maCalendarWrapper.getValue( i18n::CalendarFieldIndex::WEEK_OF_YEAR);
				USHORT		nMonth = aDate.GetMonth();
				XubString	aStr( maDayText );
				aStr.AppendAscii( ": " );
				aStr.Append( XubString::CreateFromInt32( aDate.GetDayOfYear() ) );
				aStr.AppendAscii( " / " );
				aStr.Append( maWeekText );
				aStr.AppendAscii( ": " );
				aStr.Append( XubString::CreateFromInt32( nWeek ) );
				// Evt. noch Jahr hinzufuegen, wenn es nicht das gleiche ist
				if ( (nMonth == 12) && (nWeek == 1) )
				{
					aStr.AppendAscii( ",  " );
					aStr.Append( XubString::CreateFromInt32( aDate.GetYear()+1 ) );
				}
				else if ( (nMonth == 1) && (nWeek > 50) )
				{
					aStr.AppendAscii( ", " );
					aStr.Append( XubString::CreateFromInt32( aDate.GetYear()-1 ) );
				}
				Help::ShowQuickHelp( this, aDateRect, aStr );
				return;
			}
		}
	}

	Control::RequestHelp( rHEvt );
}

// -----------------------------------------------------------------------

void Calendar::Command( const CommandEvent& rCEvt )
{
	if ( rCEvt.GetCommand() == COMMAND_CONTEXTMENU )
	{
		if ( !mbSelection && rCEvt.IsMouseEvent() )
		{
			Date	aTempDate = maCurDate;
			USHORT	nHitTest = ImplHitTest( rCEvt.GetMousePosPixel(), aTempDate );
			if ( nHitTest & CALENDAR_HITTEST_MONTHTITLE )
			{
				ImplShowMenu( rCEvt.GetMousePosPixel(), aTempDate );
				return;
			}
		}
	}
	else if ( rCEvt.GetCommand() == COMMAND_WHEEL )
	{
		const CommandWheelData* pData = rCEvt.GetWheelData();
		if ( pData->GetMode() == COMMAND_WHEEL_SCROLL )
		{
			long nNotchDelta = pData->GetNotchDelta();
			if ( nNotchDelta < 0 )
			{
				while ( nNotchDelta < 0 )
				{
					ImplScroll( TRUE );
					nNotchDelta++;
				}
			}
			else
			{
				while ( nNotchDelta > 0 )
				{
					ImplScroll( FALSE );
					nNotchDelta--;
				}
			}

			return;
		}
	}

	Control::Command( rCEvt );
}

// -----------------------------------------------------------------------

void Calendar::StateChanged( StateChangedType nType )
{
	Control::StateChanged( nType );

	if ( nType == STATE_CHANGE_INITSHOW )
		ImplFormat();
}

// -----------------------------------------------------------------------

void Calendar::DataChanged( const DataChangedEvent& rDCEvt )
{
	Control::DataChanged( rDCEvt );

	if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
		 (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
		 ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
		  (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
	{
		ImplInitSettings();
		Invalidate();
	}
}

// -----------------------------------------------------------------------

void Calendar::SelectionChanging()
{
	maSelectionChangingHdl.Call( this );
}

// -----------------------------------------------------------------------

void Calendar::DateRangeChanged()
{
	maDateRangeChangedHdl.Call( this );
}

// -----------------------------------------------------------------------

void Calendar::RequestDateInfo()
{
	maRequestDateInfoHdl.Call( this );
}

// -----------------------------------------------------------------------

void Calendar::DoubleClick()
{
	maDoubleClickHdl.Call( this );
}

// -----------------------------------------------------------------------

void Calendar::Select()
{
	maSelectHdl.Call( this );
}

// -----------------------------------------------------------------------

void Calendar::SelectDate( const Date& rDate, BOOL bSelect )
{
	if ( !rDate.IsValid() )
		return;

	Table* pOldSel;

	if ( !mbInSelChange )
		pOldSel = new Table( *mpSelectTable );
	else
		pOldSel = NULL;

	ImplCalendarSelectDate( mpSelectTable, rDate, bSelect );

	if ( pOldSel )
	{
		ImplUpdateSelection( pOldSel );
		delete pOldSel;
	}
}

// -----------------------------------------------------------------------

void Calendar::SelectDateRange( const Date& rStartDate, const Date& rEndDate,
								BOOL bSelect )
{
	if ( !rStartDate.IsValid() || !rEndDate.IsValid() )
		return;

	Table* pOldSel;

	if ( !mbInSelChange )
		pOldSel = new Table( *mpSelectTable );
	else
		pOldSel = NULL;

	ImplCalendarSelectDateRange( mpSelectTable, rStartDate, rEndDate, bSelect );

	if ( pOldSel )
	{
		ImplUpdateSelection( pOldSel );
		delete pOldSel;
	}
}

// -----------------------------------------------------------------------

void Calendar::SetNoSelection()
{
	Table* pOldSel;

	if ( !mbInSelChange )
		pOldSel = new Table( *mpSelectTable );
	else
		pOldSel = NULL;

	ImplCalendarClearSelectDate( mpSelectTable );

	if ( pOldSel )
	{
		ImplUpdateSelection( pOldSel );
		delete pOldSel;
	}
}

// -----------------------------------------------------------------------

BOOL Calendar::IsDateSelected( const Date& rDate ) const
{
	return mpSelectTable->IsKeyValid( rDate.GetDate() );
}

// -----------------------------------------------------------------------

ULONG Calendar::GetSelectDateCount() const
{
	return mpSelectTable->Count();
}

// -----------------------------------------------------------------------

Date Calendar::GetSelectDate( ULONG nIndex ) const
{
	if ( nIndex < mpSelectTable->Count() )
		return Date( mpSelectTable->GetObjectKey( nIndex ) );
	else
	{
		Date aDate( 0, 0, 0 );
		return aDate;
	}
}

// -----------------------------------------------------------------------

void Calendar::SetCurDate( const Date& rNewDate )
{
	if ( !rNewDate.IsValid() )
		return;

	if ( maCurDate != rNewDate )
	{
		BOOL bUpdate	= IsVisible() && IsUpdateMode();
		Date aOldDate	= maCurDate;
		maCurDate		= rNewDate;
		maAnchorDate	= maCurDate;

		if ( !(mnWinStyle & (WB_RANGESELECT | WB_MULTISELECT)) )
		{
			ImplCalendarSelectDate( mpSelectTable, aOldDate, FALSE );
			ImplCalendarSelectDate( mpSelectTable, maCurDate, TRUE );
		}
		else if ( !HasFocus() )
			bUpdate = FALSE;

		// Aktuelles Datum noch in den sichtbaren Bereich verschieben
		if ( mbFormat || (maCurDate < GetFirstMonth()) )
			SetFirstDate( maCurDate );
		else if ( maCurDate > GetLastMonth() )
		{
			Date aTempDate = GetLastMonth();
			long nDateOff = maCurDate-aTempDate;
			if ( nDateOff < 365 )
			{
				Date aFirstDate = GetFirstMonth();
				aFirstDate += aFirstDate.GetDaysInMonth();
				aTempDate++;
				while ( nDateOff > aTempDate.GetDaysInMonth() )
				{
					aFirstDate += aFirstDate.GetDaysInMonth();
					long nDaysInMonth = aTempDate.GetDaysInMonth();
					aTempDate += nDaysInMonth;
					nDateOff -= nDaysInMonth;
				}
				SetFirstDate( aFirstDate );
			}
			else
				SetFirstDate( maCurDate );
		}
		else
		{
			if ( bUpdate )
			{
				HideFocus();
				ImplUpdateDate( aOldDate );
				ImplUpdateDate( maCurDate );
			}
		}
	}
}

// -----------------------------------------------------------------------

void Calendar::SetFirstDate( const Date& rNewFirstDate )
{
	if ( maFirstDate != rNewFirstDate )
	{
		maFirstDate = Date( 1, rNewFirstDate.GetMonth(), rNewFirstDate.GetYear() );
		mbDropPos = FALSE;
		ImplUpdate();
	}
}

// -----------------------------------------------------------------------

Date Calendar::GetFirstMonth() const
{
	if ( maFirstDate.GetDay() > 1 )
	{
		if ( maFirstDate.GetMonth() == 12 )
			return Date( 1, 1, maFirstDate.GetYear()+1 );
		else
			return Date( 1, maFirstDate.GetMonth()+1, maFirstDate.GetYear() );
	}
	else
		return maFirstDate;
}

// -----------------------------------------------------------------------

Date Calendar::GetLastMonth() const
{
	Date aDate = GetFirstMonth();
	USHORT nMonthCount = GetMonthCount();
	for ( USHORT i = 0; i < nMonthCount; i++ )
		aDate += aDate.GetDaysInMonth();
	aDate--;
	return aDate;
}

// -----------------------------------------------------------------------

USHORT Calendar::GetMonthCount() const
{
	if ( mbFormat )
		return 1;
	else
		return (USHORT)(mnMonthPerLine*mnLines);
}

// -----------------------------------------------------------------------

BOOL Calendar::GetDropDate( Date& rDate ) const
{
	if( mbDropPos )
	{
		rDate = maDropDate;
		return TRUE;
	}
	return FALSE;
}

// -----------------------------------------------------------------------

BOOL Calendar::GetDate( const Point& rPos, Date& rDate ) const
{
	Date	aDate = maCurDate;
	USHORT	nHitTest = ImplHitTest( rPos, aDate );
	if ( nHitTest & CALENDAR_HITTEST_DAY )
	{
		rDate = aDate;
		return TRUE;
	}
	else
		return FALSE;
}

// -----------------------------------------------------------------------

Rectangle Calendar::GetDateRect( const Date& rDate ) const
{
	Rectangle aRect;

	if ( mbFormat || (rDate < maFirstDate) || (rDate > (maFirstDate+mnDayCount)) )
		return aRect;

	long	nX;
	long	nY;
	ULONG	nDaysOff;
	USHORT	nDayIndex;
	Date	aDate = GetFirstMonth();

	if ( rDate < aDate )
	{
		aRect = GetDateRect( aDate );
		nDaysOff = aDate-rDate;
		nX = (long)(nDaysOff*mnDayWidth);
		aRect.Left() -= nX;
		aRect.Right() -= nX;
		return aRect;
	}
	else
	{
		Date aLastDate = GetLastMonth();
		if ( rDate > aLastDate )
		{
			USHORT nWeekDay = (USHORT)aLastDate.GetDayOfWeek();
			nWeekDay = (nWeekDay+(7-(USHORT)ImplGetWeekStart())) % 7;
			aLastDate -= nWeekDay;
			aRect = GetDateRect( aLastDate );
			nDaysOff = rDate-aLastDate;
			nDayIndex = 0;
			for ( USHORT i = 0; i <= nDaysOff; i++ )
			{
				if ( aLastDate == rDate )
				{
					aRect.Left() += nDayIndex*mnDayWidth;
					aRect.Right() = aRect.Left()+mnDayWidth;
					return aRect;
				}
				if ( nDayIndex == 6 )
				{
					nDayIndex = 0;
					aRect.Top() += mnDayHeight;
					aRect.Bottom() += mnDayHeight;
				}
				else
					nDayIndex++;
				aLastDate++;
			}
		}
	}

	nY = 0;
	for ( long i = 0; i < mnLines; i++ )
	{
		nX = 0;
		for ( long j = 0; j < mnMonthPerLine; j++ )
		{
			USHORT nDaysInMonth = aDate.GetDaysInMonth();

			// Monat gerufen
			if ( (aDate.GetMonth() == rDate.GetMonth()) &&
				 (aDate.GetYear() == rDate.GetYear()) )
			{
				long nDayX = nX+mnDaysOffX;
				long nDayY = nY+mnDaysOffY;
				nDayIndex = (USHORT)aDate.GetDayOfWeek();
				nDayIndex = (nDayIndex+(7-(USHORT)ImplGetWeekStart())) % 7;
				for ( USHORT nDay = 1; nDay <= nDaysInMonth; nDay++ )
				{
					if ( nDay == rDate.GetDay() )
					{
						aRect.Left()	= nDayX + (nDayIndex*mnDayWidth);
						aRect.Top() 	= nDayY;
						aRect.Right()	= aRect.Left()+mnDayWidth;
						aRect.Bottom()	= aRect.Top()+mnDayHeight;
						break;
					}
					if ( nDayIndex == 6 )
					{
						nDayIndex = 0;
						nDayY += mnDayHeight;
					}
					else
						nDayIndex++;
				}
			}

			aDate += nDaysInMonth;
			nX += mnMonthWidth;
		}

		nY += mnMonthHeight;
	}

	return aRect;
}

// -----------------------------------------------------------------------

void Calendar::SetStandardColor( const Color& rColor )
{
	if ( mpStandardColor )
		*mpStandardColor = rColor;
	else
		mpStandardColor = new Color( rColor );
	ImplUpdate();
}

// -----------------------------------------------------------------------

void Calendar::SetSaturdayColor( const Color& rColor )
{
	if ( mpSaturdayColor )
		*mpSaturdayColor = rColor;
	else
		mpSaturdayColor = new Color( rColor );
	ImplUpdate();
}

// -----------------------------------------------------------------------

void Calendar::SetSundayColor( const Color& rColor )
{
	if ( mpSundayColor )
		*mpSundayColor = rColor;
	else
		mpSundayColor = new Color( rColor );
	ImplUpdate();
}

// -----------------------------------------------------------------------

void Calendar::AddDateInfo( const Date& rDate, const String& rText,
							const Color* pTextColor, const Color* pFrameColor,
							USHORT nFlags )
{
	if ( !mpDateTable )
		mpDateTable = new ImplDateTable( 256, 256 );

	BOOL			bChanged = FALSE;
	ULONG			nKey = rDate.GetDate();
	ImplDateInfo*	pDateInfo = mpDateTable->Get( nKey );
	if ( pDateInfo )
		pDateInfo->maText = rText;
	else
	{
		pDateInfo = new ImplDateInfo( rText );
		mpDateTable->Insert( nKey, pDateInfo );
	}
	if ( pTextColor )
	{
		if ( pDateInfo->mpTextColor )
		{
			if ( *(pDateInfo->mpTextColor) != *pTextColor )
			{
				*(pDateInfo->mpTextColor) = *pTextColor;
				bChanged = TRUE;
			}
		}
		else
		{
			pDateInfo->mpTextColor = new Color( *pTextColor );
			bChanged = TRUE;
		}
	}
	else
	{
		if ( pDateInfo->mpTextColor )
		{
			delete pDateInfo->mpTextColor;
			pDateInfo->mpTextColor = NULL;
			bChanged = TRUE;
		}
	}
	if ( pFrameColor )
	{
		if ( pDateInfo->mpFrameColor )
		{
			if ( *(pDateInfo->mpFrameColor) != *pFrameColor )
			{
				*(pDateInfo->mpFrameColor) = *pFrameColor;
				bChanged = TRUE;
			}
		}
		else
		{
			pDateInfo->mpFrameColor = new Color( *pFrameColor );
			bChanged = TRUE;
		}
	}
	else
	{
		if ( pDateInfo->mpFrameColor )
		{
			delete pDateInfo->mpFrameColor;
			pDateInfo->mpFrameColor = NULL;
			bChanged = TRUE;
		}
	}
	if ( pDateInfo->mnFlags != nFlags )
	{
		pDateInfo->mnFlags = nFlags;
		bChanged = TRUE;
	}

	if ( bChanged )
		ImplUpdateDate( rDate );
}

// -----------------------------------------------------------------------

void Calendar::RemoveDateInfo( const Date& rDate )
{
	if ( mpDateTable )
	{
		ImplDateInfo* pDateInfo = mpDateTable->Remove( rDate.GetDate() );
		if ( pDateInfo )
		{
			delete pDateInfo;
			ImplUpdateDate( rDate );
		}
	}
}

// -----------------------------------------------------------------------

void Calendar::ClearDateInfo()
{
	if ( mpDateTable )
	{
		ImplDateInfo* pDateInfo = mpDateTable->First();
		while ( pDateInfo )
		{
			ULONG nKey = mpDateTable->GetCurKey();
			mpDateTable->Remove( nKey );
			Date aDate( nKey );
			ImplUpdateDate( aDate );
			delete pDateInfo;
			pDateInfo = mpDateTable->First();
		}
		delete mpDateTable;
		mpDateTable = NULL;
	}
}

// -----------------------------------------------------------------------

XubString Calendar::GetDateInfoText( const Date& rDate )
{
	XubString aRet;
	if ( mpDateTable )
	{
		ULONG			nKey = rDate.GetDate();
		ImplDateInfo*	pDateInfo = mpDateTable->Get( nKey );
		if ( pDateInfo )
			aRet = pDateInfo->maText;
	}
	return aRet;
}

// -----------------------------------------------------------------------

BOOL Calendar::ShowDropPos( const Point& rPos, Date& rDate )
{
	Date	aTempDate = maCurDate;
	mnDragScrollHitTest = ImplHitTest( rPos, aTempDate );

	if ( mnDragScrollHitTest )
	{
		if ( mnDragScrollHitTest & (CALENDAR_HITTEST_PREV | CALENDAR_HITTEST_NEXT) )
		{
			if ( !maDragScrollTimer.IsActive() )
				maDragScrollTimer.Start();
		}
		else
		{
			maDragScrollTimer.Stop();
			if ( mnDragScrollHitTest & CALENDAR_HITTEST_DAY )
			{
				if ( !mbDropPos || (aTempDate != maDropDate) )
				{
					if( mbDropPos )
						ImplInvertDropPos();
					maDropDate = aTempDate;
					mbDropPos = TRUE;
					ImplInvertDropPos();
				}

				rDate = maDropDate;
				return TRUE;
			}
		}
	}
	else
		maDragScrollTimer.Stop();

	HideDropPos();
	return FALSE;
}

// -----------------------------------------------------------------------

void Calendar::HideDropPos()
{
	if ( mbDropPos )
	{
		ImplInvertDropPos();
		mbDropPos = FALSE;
	}
}

// -----------------------------------------------------------------------

void Calendar::StartSelection()
{
	if ( mpOldSelectTable )
		delete mpOldSelectTable;
	maOldCurDate = maCurDate;
	mpOldSelectTable = new Table( *mpSelectTable );

	mbSelection = TRUE;
}

// -----------------------------------------------------------------------

void Calendar::EndSelection()
{
	if ( mbDrag || mbSpinDown || mbSelection )
	{
		if ( !mbSelection )
			ReleaseMouse();

		mbDrag				= FALSE;
		mbSelection 		= FALSE;
		mbMultiSelection	= FALSE;
		mbSpinDown			= FALSE;
		mbPrevIn			= FALSE;
		mbNextIn			= FALSE;
	}
}

// -----------------------------------------------------------------------

Size Calendar::CalcWindowSizePixel( long nCalcMonthPerLine,
									long nCalcLines ) const
{
	XubString	a99Text( XubString( RTL_CONSTASCII_USTRINGPARAM( "99" ) ) );
	Font		aOldFont = GetFont();

	// Wochenanzeige beruecksichtigen
	long nWeekWidth;
	if ( mnWinStyle & WB_WEEKNUMBER )
	{
		Font aTempFont = aOldFont;
		ImplGetWeekFont( aTempFont );
		((Calendar*)this)->SetFont( aTempFont );
		nWeekWidth = GetTextWidth( a99Text )+WEEKNUMBER_OFFX;
		((Calendar*)this)->SetFont( aOldFont );
	}
	else
		nWeekWidth = 0;

	if ( mnWinStyle & WB_BOLDTEXT )
	{
		Font aFont = aOldFont;
		if ( aFont.GetWeight() < WEIGHT_BOLD )
			aFont.SetWeight( WEIGHT_BOLD );
		else
			aFont.SetWeight( WEIGHT_NORMAL );
		((Calendar*)this)->SetFont( aFont );
	}

	Size	aSize;
	long	n99TextWidth = GetTextWidth( a99Text );
	long	nTextHeight = GetTextHeight();

	if ( mnWinStyle & WB_BOLDTEXT )
		((Calendar*)this)->SetFont( aOldFont );

	aSize.Width()  += ((n99TextWidth+DAY_OFFX)*7) + nWeekWidth;
	aSize.Width()  += MONTH_BORDERX*2;
	aSize.Width()  *= nCalcMonthPerLine;

	aSize.Height()	= nTextHeight + TITLE_OFFY + (TITLE_BORDERY*2);
	aSize.Height() += nTextHeight + WEEKDAY_OFFY;
	aSize.Height() += ((nTextHeight+DAY_OFFY)*6);
	aSize.Height() += MONTH_OFFY;
	aSize.Height() *= nCalcLines;

	return aSize;
}

// =======================================================================

#define CALFIELD_EXTRA_BUTTON_WIDTH 		14
#define CALFIELD_EXTRA_BUTTON_HEIGHT		8
#define CALFIELD_SEP_X						6
#define CALFIELD_BORDERLINE_X				5
#define CALFIELD_BORDER_YTOP				4
#define CALFIELD_BORDER_Y					5

// =======================================================================

class ImplCFieldFloatWin : public FloatingWindow
{
private:
	Calendar*		mpCalendar;
	PushButton* 	mpTodayBtn;
	PushButton* 	mpNoneBtn;
	FixedLine*		mpFixedLine;

public:
					ImplCFieldFloatWin( Window* pParent );
					~ImplCFieldFloatWin();

	void			SetCalendar( Calendar* pCalendar )
						{ mpCalendar = pCalendar; }

	PushButton* 	EnableTodayBtn( BOOL bEnable );
	PushButton* 	EnableNoneBtn( BOOL bEnable );
	void			ArrangeButtons();

	long			Notify( NotifyEvent& rNEvt );
};

// -----------------------------------------------------------------------

ImplCFieldFloatWin::ImplCFieldFloatWin( Window* pParent ) :
	FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW | WB_NOSHADOW  )
{
	mpCalendar	= NULL;
	mpTodayBtn	= NULL;
	mpNoneBtn	= NULL;
	mpFixedLine = NULL;
}

// -----------------------------------------------------------------------

ImplCFieldFloatWin::~ImplCFieldFloatWin()
{
	delete mpTodayBtn;
	delete mpNoneBtn;
	delete mpFixedLine;
}

// -----------------------------------------------------------------------

PushButton* ImplCFieldFloatWin::EnableTodayBtn( BOOL bEnable )
{
	if ( bEnable )
	{
		if ( !mpTodayBtn )
		{
			mpTodayBtn = new PushButton( this, WB_NOPOINTERFOCUS );
			XubString aTodayText( SvtResId( STR_SVT_CALENDAR_TODAY ) );
			mpTodayBtn->SetText( aTodayText );
			Size aSize;
			aSize.Width()	= mpTodayBtn->GetCtrlTextWidth( mpTodayBtn->GetText() );
			aSize.Height()	= mpTodayBtn->GetTextHeight();
			aSize.Width()  += CALFIELD_EXTRA_BUTTON_WIDTH;
			aSize.Height() += CALFIELD_EXTRA_BUTTON_HEIGHT;
			mpTodayBtn->SetSizePixel( aSize );
			mpTodayBtn->Show();
		}
	}
	else
	{
		if ( mpTodayBtn )
		{
			delete mpTodayBtn;
			mpTodayBtn = NULL;
		}
	}

	return mpTodayBtn;
}

// -----------------------------------------------------------------------

PushButton* ImplCFieldFloatWin::EnableNoneBtn( BOOL bEnable )
{
	if ( bEnable )
	{
		if ( !mpNoneBtn )
		{
			mpNoneBtn = new PushButton( this, WB_NOPOINTERFOCUS );
			XubString aNoneText( SvtResId( STR_SVT_CALENDAR_NONE ) );
			mpNoneBtn->SetText( aNoneText );
			Size aSize;
			aSize.Width()	= mpNoneBtn->GetCtrlTextWidth( mpNoneBtn->GetText() );
			aSize.Height()	= mpNoneBtn->GetTextHeight();
			aSize.Width()  += CALFIELD_EXTRA_BUTTON_WIDTH;
			aSize.Height() += CALFIELD_EXTRA_BUTTON_HEIGHT;
			mpNoneBtn->SetSizePixel( aSize );
			mpNoneBtn->Show();
		}
	}
	else
	{
		if ( mpNoneBtn )
		{
			delete mpNoneBtn;
			mpNoneBtn = NULL;
		}
	}

	return mpNoneBtn;
}

// -----------------------------------------------------------------------

void ImplCFieldFloatWin::ArrangeButtons()
{
	long nBtnHeight = 0;
	long nBtnWidth	= 0;
	Size aOutSize	= GetOutputSizePixel();
	if ( mpTodayBtn && mpNoneBtn )
	{
		Size aTodayBtnSize = mpTodayBtn->GetSizePixel();
		Size aNoneBtnSize  = mpNoneBtn->GetSizePixel();
		if ( aTodayBtnSize.Width() < aNoneBtnSize.Width() )
			aTodayBtnSize.Width() = aNoneBtnSize.Width();
		else
			aNoneBtnSize.Width() = aTodayBtnSize.Width();
		if ( aTodayBtnSize.Height() < aNoneBtnSize.Height() )
			aTodayBtnSize.Height() = aNoneBtnSize.Height();
		else
			aNoneBtnSize.Height() = aTodayBtnSize.Height();

		nBtnWidth  = aTodayBtnSize.Width() + aNoneBtnSize.Width() + CALFIELD_SEP_X;
		nBtnHeight = aTodayBtnSize.Height();
		long nX = (aOutSize.Width()-nBtnWidth)/2;
		long nY = aOutSize.Height()+CALFIELD_BORDER_Y+CALFIELD_BORDER_YTOP;
		mpTodayBtn->SetPosSizePixel( Point( nX, nY ), aTodayBtnSize );
		nX += aTodayBtnSize.Width() + CALFIELD_SEP_X;
		mpNoneBtn->SetPosSizePixel( Point( nX, nY ), aNoneBtnSize );
	}
	else if ( mpTodayBtn )
	{
		Size aTodayBtnSize = mpTodayBtn->GetSizePixel();
		nBtnWidth  = aTodayBtnSize.Width();
		nBtnHeight = aTodayBtnSize.Height();
		mpTodayBtn->SetPosPixel( Point( (aOutSize.Width()-nBtnWidth)/2, aOutSize.Height()+CALFIELD_BORDER_Y+CALFIELD_BORDER_YTOP ) );
	}
	else if ( mpNoneBtn )
	{
		Size aNoneBtnSize  = mpNoneBtn->GetSizePixel();
		nBtnWidth  = aNoneBtnSize.Width();
		nBtnHeight = aNoneBtnSize.Height();
		mpNoneBtn->SetPosPixel( Point( (aOutSize.Width()-nBtnWidth)/2, aOutSize.Height()+CALFIELD_BORDER_Y+CALFIELD_BORDER_YTOP ) );
	}

	if ( nBtnHeight )
	{
		if ( !mpFixedLine )
		{
			mpFixedLine = new FixedLine( this );
			mpFixedLine->Show();
		}
		long nLineWidth = aOutSize.Width()-(CALFIELD_BORDERLINE_X*2);
		mpFixedLine->SetPosSizePixel( (aOutSize.Width()-nLineWidth)/2, aOutSize.Height()+((CALFIELD_BORDER_YTOP-2)/2),
									  nLineWidth, 2, WINDOW_POSSIZE_POSSIZE );
		aOutSize.Height() += nBtnHeight + (CALFIELD_BORDER_Y*2) + CALFIELD_BORDER_YTOP;
		SetOutputSizePixel( aOutSize );
	}
	else
	{
		if ( mpFixedLine )
		{
			delete mpFixedLine;
			mpFixedLine = NULL;
		}
	}
}

// -----------------------------------------------------------------------

long ImplCFieldFloatWin::Notify( NotifyEvent& rNEvt )
{
	if ( rNEvt.GetType() == EVENT_KEYINPUT )
	{
		const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
		if ( pKEvt->GetKeyCode().GetCode() == KEY_RETURN )
			mpCalendar->Select();
	}

	return FloatingWindow::Notify( rNEvt );
}

// =======================================================================

CalendarField::CalendarField( Window* pParent, WinBits nWinStyle ) :
	DateField( pParent, nWinStyle ),
	maDefaultDate( 0, 0, 0 )
{
	mpFloatWin		= NULL;
	mpCalendar		= NULL;
	mnCalendarStyle = 0;
	mbToday 		= FALSE;
	mbNone			= FALSE;
}

// -----------------------------------------------------------------------

CalendarField::CalendarField( Window* pParent, const ResId& rResId ) :
	DateField( pParent, rResId ),
	maDefaultDate( 0, 0, 0 )
{
	mpFloatWin		= NULL;
	mpCalendar		= NULL;
	mnCalendarStyle = 0;
	mbToday 		= FALSE;
	mbNone			= FALSE;
}

// -----------------------------------------------------------------------

CalendarField::~CalendarField()
{
	if ( mpFloatWin )
	{
		delete mpCalendar;
		delete mpFloatWin;
	}
}

// -----------------------------------------------------------------------

IMPL_LINK( CalendarField, ImplSelectHdl, Calendar*, pCalendar )
{
	if ( !pCalendar->IsTravelSelect() )
	{
		mpFloatWin->EndPopupMode();
		EndDropDown();
		GrabFocus();
		Date aNewDate = mpCalendar->GetSelectDate( 0 );
		if ( IsEmptyDate() || ( aNewDate != GetDate() ) )
		{
			SetDate( aNewDate );
			SetModifyFlag();
			Modify();
		}
		Select();
	}
	return 0;
}

// -----------------------------------------------------------------------

IMPL_LINK( CalendarField, ImplClickHdl, PushButton*, pBtn )
{
	mpFloatWin->EndPopupMode();
	EndDropDown();
	GrabFocus();

	if ( pBtn == mpTodayBtn )
	{
		Date aToday;
		if ( (aToday != GetDate()) || IsEmptyDate() )
		{
			SetDate( aToday );
			SetModifyFlag();
			Modify();
		}
	}
	else if ( pBtn == mpNoneBtn )
	{
		if ( !IsEmptyDate() )
		{
			SetEmptyDate();
			SetModifyFlag();
			Modify();
		}
	}
	Select();

	return 0;
}

// -----------------------------------------------------------------------

IMPL_LINK( CalendarField, ImplPopupModeEndHdl, FloatingWindow*, EMPTYARG )
{
	EndDropDown();
	GrabFocus();
	mpCalendar->EndSelection();
	return 0;
}

// -----------------------------------------------------------------------

void CalendarField::Select()
{
	maSelectHdl.Call( this );
}

// -----------------------------------------------------------------------

BOOL CalendarField::ShowDropDown( BOOL bShow )
{
	if ( bShow )
	{
		Calendar* pCalendar = GetCalendar();

		Date aDate = GetDate();
		if ( IsEmptyDate() || !aDate.IsValid() )
		{
			if ( maDefaultDate.IsValid() )
				aDate = maDefaultDate;
			else
				aDate = Date();
		}
		if ( pCalendar->GetStyle() & (WB_RANGESELECT | WB_MULTISELECT) )
		{
			pCalendar->SetNoSelection();
			pCalendar->SelectDate( aDate );
		}
		pCalendar->SetCurDate( aDate );
		Point		aPos( GetParent()->OutputToScreenPixel( GetPosPixel() ) );
		Rectangle	aRect( aPos, GetSizePixel() );
		aRect.Bottom() -= 1;
		mpCalendar->SetOutputSizePixel( mpCalendar->CalcWindowSizePixel() );
		mpFloatWin->SetOutputSizePixel( mpCalendar->GetSizePixel() );
		mpFloatWin->SetCalendar( mpCalendar );
		mpTodayBtn = mpFloatWin->EnableTodayBtn( mbToday );
		mpNoneBtn = mpFloatWin->EnableNoneBtn( mbNone );
		if ( mpTodayBtn )
			mpTodayBtn->SetClickHdl( LINK( this, CalendarField, ImplClickHdl ) );
		if ( mpNoneBtn )
			mpNoneBtn->SetClickHdl( LINK( this, CalendarField, ImplClickHdl ) );
		mpFloatWin->ArrangeButtons();
		mpCalendar->EnableCallEverySelect();
		mpCalendar->StartSelection();
		mpCalendar->GrabFocus();
		mpCalendar->Show();
		mpFloatWin->StartPopupMode( aRect, FLOATWIN_POPUPMODE_NOFOCUSCLOSE|FLOATWIN_POPUPMODE_DOWN );
	}
	else
	{
		mpFloatWin->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL );
		mpCalendar->EndSelection();
		EndDropDown();
	}
	return TRUE;
}

// -----------------------------------------------------------------------

Calendar* CalendarField::CreateCalendar( Window* pParent )
{
	return new Calendar( pParent, mnCalendarStyle | WB_TABSTOP );
}

// -----------------------------------------------------------------------

Calendar* CalendarField::GetCalendar()
{
	if ( !mpFloatWin )
	{
		mpFloatWin = new ImplCFieldFloatWin( this );
		mpFloatWin->SetPopupModeEndHdl( LINK( this, CalendarField, ImplPopupModeEndHdl ) );
		mpCalendar = CreateCalendar( mpFloatWin );
		mpCalendar->SetPosPixel( Point() );
		mpCalendar->SetSelectHdl( LINK( this, CalendarField, ImplSelectHdl ) );
	}

	return mpCalendar;
}

// -----------------------------------------------------------------------

void CalendarField::StateChanged( StateChangedType nStateChange )
{
	DateField::StateChanged( nStateChange );

	if ( ( nStateChange == STATE_CHANGE_STYLE ) && GetSubEdit() )
	{
        WinBits nAllAlignmentBits = ( WB_LEFT | WB_CENTER | WB_RIGHT | WB_TOP | WB_VCENTER | WB_BOTTOM );
        WinBits nMyAlignment = GetStyle() & nAllAlignmentBits;
        GetSubEdit()->SetStyle( ( GetSubEdit()->GetStyle() & ~nAllAlignmentBits ) | nMyAlignment );
	}
}

