1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svtools.hxx"
30 
31 #include <vcl/svapp.hxx>
32 #include <tools/table.hxx>
33 #include <vcl/help.hxx>
34 #include <vcl/menu.hxx>
35 #include <vcl/decoview.hxx>
36 #include <vcl/floatwin.hxx>
37 #include <vcl/button.hxx>
38 #include <vcl/fixed.hxx>
39 #include <unotools/calendarwrapper.hxx>
40 #include <unotools/localedatawrapper.hxx>
41 #include <com/sun/star/i18n/Weekdays.hpp>
42 #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
43 #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
44 
45 #define _SV_CALENDAR_CXX
46 #include <svtools/svtools.hrc>
47 #include <svtools/svtdata.hxx>
48 #include <svtools/calendar.hxx>
49 
50 // =======================================================================
51 
52 #define DAY_OFFX						4
53 #define DAY_OFFY						2
54 #define MONTH_BORDERX					4
55 #define MONTH_OFFY						3
56 #define WEEKNUMBER_OFFX 				4
57 #define WEEKDAY_OFFY					3
58 #define TITLE_OFFY						3
59 #define TITLE_BORDERY					2
60 #define SPIN_OFFX						4
61 #define SPIN_OFFY						TITLE_BORDERY
62 
63 #define WEEKNUMBER_HEIGHT				85
64 
65 #define CALENDAR_HITTEST_DAY			((sal_uInt16)0x0001)
66 #define CALENDAR_HITTEST_WEEK			((sal_uInt16)0x0002)
67 #define CALENDAR_HITTEST_MONTHTITLE 	((sal_uInt16)0x0004)
68 #define CALENDAR_HITTEST_PREV			((sal_uInt16)0x0008)
69 #define CALENDAR_HITTEST_NEXT			((sal_uInt16)0x0010)
70 #define CALENDAR_HITTEST_OUTSIDE		((sal_uInt16)0x1000)
71 
72 #define MENU_YEAR_COUNT 				3
73 
74 #define TABLE_DATE_SELECTED 			((void*)0x00000001)
75 
76 using namespace ::com::sun::star;
77 
78 // =======================================================================
79 
80 struct ImplDateInfo
81 {
82 	XubString	maText;
83 	Color*		mpTextColor;
84 	Color*		mpFrameColor;
85 	sal_uInt16		mnFlags;
86 
87 				ImplDateInfo( const XubString& rText ) :
88 					maText( rText )
89 				{ mpTextColor = mpFrameColor = NULL; mnFlags = 0; }
90 				~ImplDateInfo() { delete mpTextColor; delete mpFrameColor; }
91 };
92 
93 DECLARE_TABLE( ImplDateTable, ImplDateInfo* )
94 
95 // =======================================================================
96 
97 static void ImplCalendarSelectDate( Table* pTable, const Date& rDate, sal_Bool bSelect )
98 {
99 	if ( bSelect )
100 		pTable->Insert( rDate.GetDate(), TABLE_DATE_SELECTED );
101 	else
102 		pTable->Remove( rDate.GetDate() );
103 }
104 
105 // -----------------------------------------------------------------------
106 
107 static void ImplCalendarSelectDateRange( Table* pTable,
108 										 const Date& rStartDate,
109 										 const Date& rEndDate,
110 										 sal_Bool bSelect )
111 {
112 	Date aStartDate = rStartDate;
113 	Date aEndDate = rEndDate;
114 	if ( aStartDate > aEndDate )
115 	{
116 		Date aTempDate = aStartDate;
117 		aStartDate = aEndDate;
118 		aEndDate = aTempDate;
119 	}
120 
121 	if ( bSelect )
122 	{
123 		while ( aStartDate <= aEndDate )
124 		{
125 			pTable->Insert( aStartDate.GetDate(), TABLE_DATE_SELECTED );
126 			aStartDate++;
127 		}
128 	}
129 	else
130 	{
131 		void* p = pTable->First();
132 		while ( p )
133 		{
134 			Date aDate( pTable->GetCurKey() );
135 			if ( aDate > aEndDate )
136 				break;
137 
138 			if ( aDate >= aStartDate )
139 				pTable->Remove( aDate.GetDate() );
140 			else
141 				p = pTable->Next();
142 		}
143 	}
144 }
145 
146 // -----------------------------------------------------------------------
147 
148 static void ImplCalendarUnSelectDateRange( Table* pTable,
149 										   Table* pOldTable,
150 										   const Date& rStartDate,
151 										   const Date& rEndDate )
152 {
153 	Date aStartDate = rStartDate;
154 	Date aEndDate = rEndDate;
155 	if ( aStartDate > aEndDate )
156 	{
157 		Date aTempDate = aStartDate;
158 		aStartDate = aEndDate;
159 		aEndDate = aTempDate;
160 	}
161 
162 	void* p = pTable->First();
163 	while ( p )
164 	{
165 		Date aDate( pTable->GetCurKey() );
166 		if ( aDate > aEndDate )
167 			break;
168 
169 		if ( aDate >= aStartDate )
170 			pTable->Remove( aDate.GetDate() );
171 		else
172 			p = pTable->Next();
173 	}
174 
175 	p = pOldTable->First();
176 	while ( p )
177 	{
178 		Date aDate( pOldTable->GetCurKey() );
179 		if ( aDate > aEndDate )
180 			break;
181 		if ( aDate >= aStartDate )
182 			pTable->Insert( aDate.GetDate(), TABLE_DATE_SELECTED );
183 
184 		p = pOldTable->Next();
185 	}
186 }
187 
188 // -----------------------------------------------------------------------
189 
190 inline void ImplCalendarClearSelectDate( Table* pTable )
191 {
192 	pTable->Clear();
193 }
194 
195 // =======================================================================
196 
197 void Calendar::ImplInit( WinBits nWinStyle )
198 {
199 	mpDateTable 			= NULL;
200 	mpSelectTable			= new Table;
201 	mpOldSelectTable		= NULL;
202 	mpRestoreSelectTable	= NULL;
203 	mpStandardColor 		= NULL;
204 	mpSaturdayColor 		= NULL;
205 	mpSundayColor			= NULL;
206 	mnDayCount				= 0;
207 	mnWinStyle				= nWinStyle;
208 	mnFirstYear 			= 0;
209 	mnLastYear				= 0;
210 	mnRequestYear			= 0;
211 	mbCalc					= sal_True;
212 	mbFormat				= sal_True;
213 	mbDrag					= sal_False;
214 	mbSelection 			= sal_False;
215 	mbMultiSelection		= sal_False;
216 	mbWeekSel				= sal_False;
217 	mbUnSel 				= sal_False;
218 	mbMenuDown				= sal_False;
219 	mbSpinDown				= sal_False;
220 	mbPrevIn				= sal_False;
221 	mbNextIn				= sal_False;
222 	mbDirect				= sal_False;
223 	mbInSelChange			= sal_False;
224 	mbTravelSelect			= sal_False;
225 	mbScrollDateRange		= sal_False;
226 	mbSelLeft				= sal_False;
227 	mbAllSel				= sal_False;
228 	mbDropPos				= sal_False;
229 
230     ::rtl::OUString aGregorian( RTL_CONSTASCII_USTRINGPARAM( "gregorian"));
231     maCalendarWrapper.loadCalendar( aGregorian,
232             Application::GetAppLocaleDataWrapper().getLocale());
233     if (maCalendarWrapper.getUniqueID() != aGregorian)
234     {
235 #ifdef DBG_UTIL
236         ByteString aMsg( "Calendar::ImplInit: No ``gregorian'' calendar available for locale ``");
237         lang::Locale aLoc( Application::GetAppLocaleDataWrapper().getLocale());
238         aMsg += ByteString( String( aLoc.Language), RTL_TEXTENCODING_UTF8);
239         aMsg += '-';
240         aMsg += ByteString( String( aLoc.Country), RTL_TEXTENCODING_UTF8);
241         aMsg += "'' and other calendars aren't supported. Using en-US fallback.";
242         DBG_ERRORFILE( aMsg.GetBuffer());
243 #endif
244         /* If we ever wanted to support other calendars than Gregorian a lot of
245          * rewrite would be necessary to internally replace use of class Date
246          * with proper class CalendarWrapper methods, get rid of fixed 12
247          * months, fixed 7 days, ... */
248         maCalendarWrapper.loadCalendar( aGregorian, lang::Locale(
249                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "en")),
250                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "US")),
251                     ::rtl::OUString()));
252     }
253 
254 	SetFirstDate( maCurDate );
255 	ImplCalendarSelectDate( mpSelectTable, maCurDate, sal_True );
256 
257 	// Sonstige Strings erzeugen
258 	maDayText = XubString( SvtResId( STR_SVT_CALENDAR_DAY ) );
259 	maWeekText = XubString( SvtResId( STR_SVT_CALENDAR_WEEK ) );
260 
261 	// Tagestexte anlegen
262 	for ( sal_uInt16 i = 0; i < 31; i++ )
263 		mpDayText[i] = new UniString( UniString::CreateFromInt32( i+1 ) );
264 
265 	maDragScrollTimer.SetTimeoutHdl( STATIC_LINK( this, Calendar, ScrollHdl ) );
266 	maDragScrollTimer.SetTimeout( GetSettings().GetMouseSettings().GetScrollRepeat() );
267 	mnDragScrollHitTest = 0;
268 
269 	ImplInitSettings();
270 }
271 
272 // -----------------------------------------------------------------------
273 
274 void Calendar::ImplInitSettings()
275 {
276 	const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
277 	maSelColor = rStyleSettings.GetHighlightTextColor();
278 	SetPointFont( rStyleSettings.GetToolFont() );
279 	SetTextColor( rStyleSettings.GetFieldTextColor() );
280 	SetBackground( Wallpaper( rStyleSettings.GetFieldColor() ) );
281 }
282 
283 // -----------------------------------------------------------------------
284 
285 Calendar::Calendar( Window* pParent, WinBits nWinStyle ) :
286 	Control( pParent, nWinStyle & (WB_TABSTOP | WB_GROUP | WB_BORDER | WB_3DLOOK | WB_RANGESELECT | WB_MULTISELECT) ),
287 	maCalendarWrapper( Application::GetAppLocaleDataWrapper().getServiceFactory() ),
288 	maOldFormatFirstDate( 0, 0, 1900 ),
289 	maOldFormatLastDate( 0, 0, 1900 ),
290 	maFirstDate( 0, 0, 1900 ),
291 	maOldFirstDate( 0, 0, 1900 ),
292 	maOldCurDate( 0, 0, 1900 ),
293 	maAnchorDate( maCurDate ),
294 	maDropDate( 0, 0, 1900 )
295 {
296 	ImplInit( nWinStyle );
297 }
298 
299 // -----------------------------------------------------------------------
300 
301 Calendar::Calendar( Window* pParent, const ResId& rResId ) :
302 	Control( pParent, rResId ),
303 	maCalendarWrapper( Application::GetAppLocaleDataWrapper().getServiceFactory() ),
304 	maOldFormatFirstDate( 0, 0, 1900 ),
305 	maOldFormatLastDate( 0, 0, 1900 ),
306 	maFirstDate( 0, 0, 1900 ),
307 	maOldFirstDate( 0, 0, 1900 ),
308 	maOldCurDate( 0, 0, 1900 ),
309 	maAnchorDate( maCurDate ),
310 	maDropDate( 0, 0, 1900 )
311 {
312 	ImplInit( rResId.GetWinBits() );
313 }
314 
315 // -----------------------------------------------------------------------
316 
317 Calendar::~Calendar()
318 {
319 	delete mpStandardColor;
320 	delete mpSaturdayColor;
321 	delete mpSundayColor;
322 
323 	if ( mpDateTable )
324 	{
325 		ImplDateInfo* pDateInfo = mpDateTable->First();
326 		while ( pDateInfo )
327 		{
328 			delete pDateInfo;
329 			pDateInfo = mpDateTable->Next();
330 		}
331 
332 		delete mpDateTable;
333 	}
334 
335 	delete mpSelectTable;
336 	if ( mpOldSelectTable )
337 		delete mpOldSelectTable;
338 	if ( mpRestoreSelectTable )
339 		delete mpRestoreSelectTable;
340 
341 	for ( sal_uInt16 i = 0; i < 31; i++ )
342 		delete mpDayText[i];
343 }
344 
345 // -----------------------------------------------------------------------
346 
347 void Calendar::SetMinimumNumberOfDaysInWeek( sal_Int16 nDays )
348 {
349     ImplUpdate( sal_True );
350     maCalendarWrapper.setMinimumNumberOfDaysForFirstWeek( nDays);
351 }
352 
353 // -----------------------------------------------------------------------
354 
355 void Calendar::SetWeekStart( sal_Int16 nDay )
356 {
357     ImplUpdate( sal_True );
358     switch (nDay)
359     {
360         case i18n::Weekdays::SUNDAY :
361         case i18n::Weekdays::MONDAY :
362         case i18n::Weekdays::TUESDAY :
363         case i18n::Weekdays::WEDNESDAY :
364         case i18n::Weekdays::THURSDAY :
365         case i18n::Weekdays::FRIDAY :
366         case i18n::Weekdays::SATURDAY :
367             ;   // nothing
368         default:
369             DBG_ERRORFILE("Calendar::SetWeekStart: unknown value for setFirstDayOfWeek() of a Gregorian calendar");
370             nDay = i18n::Weekdays::SUNDAY;
371     }
372     maCalendarWrapper.setFirstDayOfWeek( nDay);
373 }
374 
375 // -----------------------------------------------------------------------
376 
377 DayOfWeek Calendar::ImplGetWeekStart() const
378 {
379     // Map i18n::Weekdays to Date DayOfWeek
380     DayOfWeek eDay;
381     sal_Int16 nDay = maCalendarWrapper.getFirstDayOfWeek();
382     switch (nDay)
383     {
384         case i18n::Weekdays::SUNDAY :
385             eDay = SUNDAY;
386             break;
387         case i18n::Weekdays::MONDAY :
388             eDay = MONDAY;
389             break;
390         case i18n::Weekdays::TUESDAY :
391             eDay = TUESDAY;
392             break;
393         case i18n::Weekdays::WEDNESDAY :
394             eDay = WEDNESDAY;
395             break;
396         case i18n::Weekdays::THURSDAY :
397             eDay = THURSDAY;
398             break;
399         case i18n::Weekdays::FRIDAY :
400             eDay = FRIDAY;
401             break;
402         case i18n::Weekdays::SATURDAY :
403             eDay = SATURDAY;
404             break;
405         default:
406             DBG_ERRORFILE("Calendar::ImplGetWeekStart: broken i18n Gregorian calendar (getFirstDayOfWeek())");
407             eDay = SUNDAY;
408     }
409     return eDay;
410 }
411 
412 // -----------------------------------------------------------------------
413 
414 void Calendar::ImplGetWeekFont( Font& rFont ) const
415 {
416 	// Wochennummer geben wir in WEEKNUMBER_HEIGHT%-Fonthoehe aus
417 	Size aFontSize = rFont.GetSize();
418 	aFontSize.Height() *= WEEKNUMBER_HEIGHT;
419 	aFontSize.Height() /= 100;
420 	rFont.SetSize( aFontSize );
421 	rFont.SetWeight( WEIGHT_NORMAL );
422 }
423 
424 // -----------------------------------------------------------------------
425 
426 void Calendar::ImplFormat()
427 {
428 	if ( !mbFormat )
429 		return;
430 
431 	if ( mbCalc )
432 	{
433 		Size aOutSize = GetOutputSizePixel();
434 
435 		if ( (aOutSize.Width() <= 1) || (aOutSize.Height() <= 1) )
436 			return;
437 
438 		XubString a99Text( XubString( RTL_CONSTASCII_USTRINGPARAM( "99" ) ) );
439 
440 		Font aOldFont = GetFont();
441 
442 		// Wochenanzeige beruecksichtigen
443 		if ( mnWinStyle & WB_WEEKNUMBER )
444 		{
445 			Font aTempFont = aOldFont;
446 			ImplGetWeekFont( aTempFont );
447 			SetFont( aTempFont );
448 			mnWeekWidth = GetTextWidth( a99Text )+WEEKNUMBER_OFFX;
449 			SetFont( aOldFont );
450 		}
451 		else
452 			mnWeekWidth = 0;
453 
454 		if ( mnWinStyle & WB_BOLDTEXT )
455 		{
456 			Font aFont = aOldFont;
457 			if ( aFont.GetWeight() < WEIGHT_BOLD )
458 				aFont.SetWeight( WEIGHT_BOLD );
459 			else
460 				aFont.SetWeight( WEIGHT_NORMAL );
461 			SetFont( aFont );
462 		}
463 
464 		long n99TextWidth = GetTextWidth( a99Text );
465 		long nTextHeight = GetTextHeight();
466 
467 		// Breiten und X-Positionen berechnen
468 		mnDayWidth		= n99TextWidth+DAY_OFFX;
469 		mnMonthWidth	= mnDayWidth*7;
470 		mnMonthWidth   += mnWeekWidth;
471 		mnMonthWidth   += MONTH_BORDERX*2;
472 		mnMonthPerLine	= aOutSize.Width() / mnMonthWidth;
473 		if ( !mnMonthPerLine )
474 			mnMonthPerLine = 1;
475 		long nOver		= ((aOutSize.Width()-(mnMonthPerLine*mnMonthWidth)) / mnMonthPerLine);
476 		mnMonthWidth   += nOver;
477 		mnDaysOffX		= MONTH_BORDERX;
478 		mnDaysOffX	   += nOver/2;
479 		mnDaysOffX	   += mnWeekWidth;
480 
481 		// Hoehen und Y-Positionen berechnen
482 		mnDayHeight 	= nTextHeight + DAY_OFFY;
483 		mnWeekDayOffY	= nTextHeight + TITLE_OFFY + (TITLE_BORDERY*2);
484 		mnDaysOffY		= mnWeekDayOffY + nTextHeight + WEEKDAY_OFFY;
485 		mnMonthHeight	= (mnDayHeight*6) + mnDaysOffY;
486 		mnMonthHeight  += MONTH_OFFY;
487 		mnLines 		= aOutSize.Height() / mnMonthHeight;
488 		if ( !mnLines )
489 			mnLines = 1;
490 		mnMonthHeight  += (aOutSize.Height()-(mnLines*mnMonthHeight)) / mnLines;
491 
492 		// Spinfelder berechnen
493 		long nSpinSize		= nTextHeight+TITLE_BORDERY-SPIN_OFFY;
494 		maPrevRect.Left()	= SPIN_OFFX;
495 		maPrevRect.Top()	= SPIN_OFFY;
496 		maPrevRect.Right()	= maPrevRect.Left()+nSpinSize;
497 		maPrevRect.Bottom() = maPrevRect.Top()+nSpinSize;
498 		maNextRect.Left()	= aOutSize.Width()-SPIN_OFFX-nSpinSize-1;
499 		maNextRect.Top()	= SPIN_OFFY;
500 		maNextRect.Right()	= maNextRect.Left()+nSpinSize;
501 		maNextRect.Bottom() = maNextRect.Top()+nSpinSize;
502 
503 		if ( mnWinStyle & WB_BOLDTEXT )
504 			SetFont( aOldFont );
505 
506 		// Calculate DayOfWeekText (gets displayed in a narrow font)
507 		maDayOfWeekText.Erase();
508 		long nStartOffX = 0;
509 		sal_Int16 nDay = maCalendarWrapper.getFirstDayOfWeek();
510 		for ( sal_Int16 nDayOfWeek = 0; nDayOfWeek < 7; nDayOfWeek++ )
511 		{
512             // Use first character of full name, since the abbreviated name may
513             // be roman digits or similar in some locales. Proper
514             // implementation would need narrow one letter month names defined
515             // in locale data.
516             String aDayOfWeek( maCalendarWrapper.getDisplayName(
517                         i18n::CalendarDisplayIndex::DAY, nDay, 1).GetChar(0));
518 			long nOffX = (mnDayWidth-GetTextWidth( aDayOfWeek ))/2;
519 			if ( mnWinStyle & WB_BOLDTEXT )
520 				nOffX++;
521 			if ( !nDayOfWeek )
522 				nStartOffX = nOffX;
523 			else
524 				nOffX -= nStartOffX;
525 			nOffX += nDayOfWeek * mnDayWidth;
526 			mnDayOfWeekAry[nDayOfWeek] = nOffX;
527 			maDayOfWeekText += aDayOfWeek;
528 			nDay++;
529 			nDay %= 7;
530 		}
531 
532 		mbCalc = sal_False;
533 	}
534 
535 	// Anzahl Tage berechnen
536 
537     DayOfWeek eStartDay = ImplGetWeekStart();
538 
539 	sal_uInt16 nWeekDay;
540 	Date aTempDate = GetFirstMonth();
541 	maFirstDate = aTempDate;
542 	nWeekDay = (sal_uInt16)aTempDate.GetDayOfWeek();
543 	nWeekDay = (nWeekDay+(7-(sal_uInt16)eStartDay)) % 7;
544 	maFirstDate -= (sal_uLong)nWeekDay;
545 	mnDayCount = nWeekDay;
546 	sal_uInt16 nDaysInMonth;
547 	sal_uInt16 nMonthCount = (sal_uInt16)(mnMonthPerLine*mnLines);
548 	for ( sal_uInt16 i = 0; i < nMonthCount; i++ )
549 	{
550 		nDaysInMonth = aTempDate.GetDaysInMonth();
551 		mnDayCount += nDaysInMonth;
552 		aTempDate += nDaysInMonth;
553 	}
554 	Date aTempDate2 = aTempDate;
555 	aTempDate2--;
556 	nDaysInMonth = aTempDate2.GetDaysInMonth();
557 	aTempDate2 -= nDaysInMonth-1;
558 	nWeekDay = (sal_uInt16)aTempDate2.GetDayOfWeek();
559 	nWeekDay = (nWeekDay+(7-(sal_uInt16)eStartDay)) % 7;
560 	mnDayCount += 42-nDaysInMonth-nWeekDay;
561 
562 	// Farben festlegen
563 	maOtherColor = Color( COL_LIGHTGRAY );
564 	if ( maOtherColor.IsRGBEqual( GetBackground().GetColor() ) )
565 		maOtherColor.SetColor( COL_GRAY );
566 
567 	Date aLastDate = GetLastDate();
568 	if ( (maOldFormatLastDate != aLastDate) ||
569 		 (maOldFormatFirstDate != maFirstDate) )
570 	{
571 		maOldFormatFirstDate = maFirstDate;
572 		maOldFormatLastDate  = aLastDate;
573 		DateRangeChanged();
574 	}
575 
576 	// DateInfo besorgen
577 	sal_uInt16 nNewFirstYear = maFirstDate.GetYear();
578 	sal_uInt16 nNewLastYear = GetLastDate().GetYear();
579 	if ( mnFirstYear )
580 	{
581 		if ( nNewFirstYear < mnFirstYear )
582 		{
583 			for ( mnRequestYear = nNewFirstYear; mnRequestYear < mnFirstYear; mnRequestYear++ )
584 				RequestDateInfo();
585 			mnFirstYear = nNewFirstYear;
586 		}
587 		if ( nNewLastYear > mnLastYear )
588 		{
589 			for ( mnRequestYear = mnLastYear; mnRequestYear < nNewLastYear; mnRequestYear++ )
590 				RequestDateInfo();
591 			mnLastYear = nNewLastYear;
592 		}
593 	}
594 	else
595 	{
596 		for ( mnRequestYear = nNewFirstYear; mnRequestYear < nNewLastYear; mnRequestYear++ )
597 			RequestDateInfo();
598 		mnFirstYear = nNewFirstYear;
599 		mnLastYear = nNewLastYear;
600 	}
601 	mnRequestYear = 0;
602 
603 	mbFormat = sal_False;
604 }
605 
606 // -----------------------------------------------------------------------
607 
608 sal_uInt16 Calendar::ImplHitTest( const Point& rPos, Date& rDate ) const
609 {
610 	if ( mbFormat )
611 		return 0;
612 
613 	if ( maPrevRect.IsInside( rPos ) )
614 		return CALENDAR_HITTEST_PREV;
615 	else if ( maNextRect.IsInside( rPos ) )
616 		return CALENDAR_HITTEST_NEXT;
617 
618 	long		nX;
619 	long		nY;
620 	long		nOffX;
621 	long		nYMonth;
622 	sal_uInt16		nDay;
623 	DayOfWeek	eStartDay = ImplGetWeekStart();
624 
625 	rDate = GetFirstMonth();
626 	nY = 0;
627 	for ( long i = 0; i < mnLines; i++ )
628 	{
629 		if ( rPos.Y() < nY )
630 			return 0;
631 
632 		nX = 0;
633 		nYMonth = nY+mnMonthHeight;
634 		for ( long j = 0; j < mnMonthPerLine; j++ )
635 		{
636 			if ( (rPos.X() < nX) && (rPos.Y() < nYMonth) )
637 				return 0;
638 
639 			sal_uInt16 nDaysInMonth = rDate.GetDaysInMonth();
640 
641 			// Entsprechender Monat gefunden
642 			if ( (rPos.X() > nX) && (rPos.Y() < nYMonth) &&
643 				 (rPos.X() < nX+mnMonthWidth) )
644 			{
645 				if ( rPos.Y() < (nY+(TITLE_BORDERY*2)+mnDayHeight))
646 					return CALENDAR_HITTEST_MONTHTITLE;
647 				else
648 				{
649 					long nDayX = nX+mnDaysOffX;
650 					long nDayY = nY+mnDaysOffY;
651 					if ( rPos.Y() < nDayY )
652 						return 0;
653 					sal_uInt16 nDayIndex = (sal_uInt16)rDate.GetDayOfWeek();
654 					nDayIndex = (nDayIndex+(7-(sal_uInt16)eStartDay)) % 7;
655 					if ( (i == 0) && (j == 0) )
656 					{
657 						Date aTempDate = rDate;
658 						aTempDate -= nDayIndex;
659 						for ( nDay = 0; nDay < nDayIndex; nDay++ )
660 						{
661 							nOffX = nDayX + (nDay*mnDayWidth);
662 							if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) &&
663 								 (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) )
664 							{
665 								rDate = aTempDate;
666 								rDate += nDay;
667 								return CALENDAR_HITTEST_DAY;
668 							}
669 						}
670 					}
671 					for ( nDay = 1; nDay <= nDaysInMonth; nDay++ )
672 					{
673 						if ( rPos.Y() < nDayY )
674 						{
675 							rDate += nDayIndex;
676 							return 0;
677 						}
678 						nOffX = nDayX + (nDayIndex*mnDayWidth);
679 						if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) &&
680 							 (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) )
681 						{
682 							rDate += nDay-1;
683 							return CALENDAR_HITTEST_DAY;
684 						}
685 						if ( nDayIndex == 6 )
686 						{
687 							nDayIndex = 0;
688 							nDayY += mnDayHeight;
689 						}
690 						else
691 							nDayIndex++;
692 					}
693 					if ( (i == mnLines-1) && (j == mnMonthPerLine-1) )
694 					{
695 						sal_uInt16 nWeekDay = (sal_uInt16)rDate.GetDayOfWeek();
696 						nWeekDay = (nWeekDay+(7-(sal_uInt16)eStartDay)) % 7;
697 						sal_uInt16 nDayCount = 42-nDaysInMonth-nWeekDay;
698 						Date aTempDate = rDate;
699 						aTempDate += nDaysInMonth;
700 						for ( nDay = 1; nDay <= nDayCount; nDay++ )
701 						{
702 							if ( rPos.Y() < nDayY )
703 							{
704 								rDate += nDayIndex;
705 								return 0;
706 							}
707 							nOffX = nDayX + (nDayIndex*mnDayWidth);
708 							if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) &&
709 								 (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) )
710 							{
711 								rDate = aTempDate;
712 								rDate += nDay-1;
713 								return CALENDAR_HITTEST_DAY;
714 							}
715 							if ( nDayIndex == 6 )
716 							{
717 								nDayIndex = 0;
718 								nDayY += mnDayHeight;
719 							}
720 							else
721 								nDayIndex++;
722 						}
723 					}
724 				}
725 			}
726 
727 			rDate += nDaysInMonth;
728 			nX += mnMonthWidth;
729 		}
730 
731 		nY += mnMonthHeight;
732 	}
733 
734 	return 0;
735 }
736 
737 // -----------------------------------------------------------------------
738 
739 static void ImplDrawSpinArrow( OutputDevice* pDev, const Rectangle& rRect,
740 							   sal_Bool bPrev )
741 {
742 	long	i;
743 	long	n;
744 	long	nLines;
745 	long	nHeight = rRect.GetHeight();
746 	long	nWidth = rRect.GetWidth();
747 	if ( nWidth < nHeight )
748 		n = nWidth;
749 	else
750 		n = nHeight;
751 	if ( !(n & 0x01) )
752 		n--;
753 	nLines = n/2;
754 
755 	Rectangle aRect( Point( rRect.Left()+(nWidth/2)-(nLines/2),
756 							rRect.Top()+(nHeight/2) ),
757 					 Size( 1, 1 ) );
758 	if ( !bPrev )
759 	{
760 		aRect.Left()  += nLines;
761 		aRect.Right() += nLines;
762 	}
763 
764 	pDev->DrawRect( aRect );
765 	for ( i = 0; i < nLines; i++ )
766 	{
767 		if ( bPrev )
768 		{
769 			aRect.Left()++;
770 			aRect.Right()++;
771 		}
772 		else
773 		{
774 			aRect.Left()--;
775 			aRect.Right()--;
776 		}
777 		aRect.Top()--;
778 		aRect.Bottom()++;
779 		pDev->DrawRect( aRect );
780 	}
781 }
782 
783 // -----------------------------------------------------------------------
784 
785 void Calendar::ImplDrawSpin( sal_Bool bDrawPrev, sal_Bool bDrawNext )
786 {
787 	if ( !bDrawPrev && !bDrawNext )
788 		return;
789 
790 	SetLineColor();
791 	SetFillColor( GetSettings().GetStyleSettings().GetButtonTextColor() );
792 	if ( bDrawPrev )
793 	{
794 		Rectangle aOutRect = maPrevRect;
795 		aOutRect.Left()   += 3;
796 		aOutRect.Top()	  += 3;
797 		aOutRect.Right()  -= 3;
798 		aOutRect.Bottom() -= 3;
799 		ImplDrawSpinArrow( this, aOutRect, sal_True );
800 	}
801 	if ( bDrawNext )
802 	{
803 		Rectangle aOutRect = maNextRect;
804 		aOutRect.Left()   += 3;
805 		aOutRect.Top()	  += 3;
806 		aOutRect.Right()  -= 3;
807 		aOutRect.Bottom() -= 3;
808 		ImplDrawSpinArrow( this, aOutRect, sal_False );
809 	}
810 }
811 
812 // -----------------------------------------------------------------------
813 
814 void Calendar::ImplDrawDate( long nX, long nY,
815 							 sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear,
816 							 DayOfWeek eDayOfWeek,
817 							 sal_Bool bBack, sal_Bool bOther, sal_uLong nToday )
818 {
819 	ImplDateInfo*	pDateInfo;
820 	Color*			pTextColor = NULL;
821 	const String&	rDay = *(mpDayText[nDay-1]);
822 	Rectangle		aDateRect( nX, nY, nX+mnDayWidth-1, nY+mnDayHeight-1 );
823 
824 	sal_Bool bSel = sal_False;
825 	sal_Bool bFocus = sal_False;
826 	// Aktueller Tag
827 	if ( (nDay	 == maCurDate.GetDay()) &&
828 		 (nMonth == maCurDate.GetMonth()) &&
829 		 (nYear  == maCurDate.GetYear()) )
830 		bFocus = sal_True;
831 	if ( mpSelectTable )
832 	{
833 		if ( mpSelectTable->IsKeyValid( Date( nDay, nMonth, nYear ).GetDate() ) )
834 			bSel = sal_True;
835 	}
836 
837 	// Dateinfo ermitteln
838 	if ( mpDateTable )
839 	{
840 		pDateInfo = mpDateTable->Get( Date( nDay, nMonth, nYear ).GetDate() );
841 		if ( !pDateInfo )
842 			pDateInfo = mpDateTable->Get( Date( nDay, nMonth, 0 ).GetDate() );
843 	}
844 	else
845 		pDateInfo = NULL;
846 
847 	// Textfarbe ermitteln
848 	if ( bSel )
849 		pTextColor = &maSelColor;
850 	else if ( bOther )
851 		pTextColor = &maOtherColor;
852 	else
853 	{
854 		if ( pDateInfo && pDateInfo->mpTextColor )
855 			pTextColor = pDateInfo->mpTextColor;
856 		else
857 		{
858 			if ( eDayOfWeek == SATURDAY )
859 				pTextColor = mpSaturdayColor;
860 			else if ( eDayOfWeek == SUNDAY )
861 				pTextColor = mpSundayColor;
862 			if ( !pTextColor )
863 				pTextColor = mpStandardColor;
864 		}
865 	}
866 
867 	if ( bFocus )
868 		HideFocus();
869 
870 	// Font ermitteln
871 	Font aOldFont = GetFont();
872 	sal_Bool bBoldFont = sal_False;
873 	if ( (mnWinStyle & WB_BOLDTEXT) &&
874 		 pDateInfo && (pDateInfo->mnFlags & DIB_BOLD) )
875 	{
876 		bBoldFont = sal_True;
877 		Font aFont = aOldFont;
878 		if ( aFont.GetWeight() < WEIGHT_BOLD )
879 			aFont.SetWeight( WEIGHT_BOLD );
880 		else
881 			aFont.SetWeight( WEIGHT_NORMAL );
882 		SetFont( aFont );
883 	}
884 
885 	// Hintergrund ausgeben
886 	const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
887 	if ( bSel || bBack )
888 	{
889 		if ( bSel )
890 		{
891 			SetLineColor();
892 			SetFillColor( rStyleSettings.GetHighlightColor() );
893 			DrawRect( aDateRect );
894 		}
895 		else
896 			Erase( aDateRect );
897 	}
898 
899 	// Text ausgeben
900 	long nTextX = nX+(mnDayWidth-GetTextWidth( rDay ))-(DAY_OFFX/2);
901 	long nTextY = nY+(mnDayHeight-GetTextHeight())/2;
902 	if ( pTextColor )
903 	{
904 		Color aOldColor = GetTextColor();
905 		SetTextColor( *pTextColor );
906 		DrawText( Point( nTextX, nTextY ), rDay );
907 		SetTextColor( aOldColor );
908 	}
909 	else
910 		DrawText( Point( nTextX, nTextY ), rDay );
911 
912 	// Heute
913 	Date aTodayDate( maCurDate );
914 	if ( nToday )
915 		aTodayDate.SetDate( nToday );
916 	else
917 		aTodayDate = Date();
918 	if ( (nDay	 == aTodayDate.GetDay()) &&
919 		 (nMonth == aTodayDate.GetMonth()) &&
920 		 (nYear  == aTodayDate.GetYear()) )
921 	{
922 		SetLineColor( rStyleSettings.GetWindowTextColor() );
923 		SetFillColor();
924 		DrawRect( aDateRect );
925 	}
926 
927 	// Evt. DateInfo ausgeben
928 	if ( (mnWinStyle & WB_FRAMEINFO) && pDateInfo && pDateInfo->mpFrameColor )
929 	{
930 		SetLineColor( *(pDateInfo->mpFrameColor) );
931 		SetFillColor();
932 		Rectangle aFrameRect( aDateRect );
933 		aFrameRect.Left()++;
934 		aFrameRect.Top()++;
935 		long nFrameWidth = aFrameRect.GetWidth();
936 		long nFrameHeight = aFrameRect.GetHeight();
937 		long nFrameOff;
938 		if ( nFrameWidth < nFrameHeight )
939 		{
940 			nFrameOff = nFrameHeight-nFrameWidth;
941 			aFrameRect.Top() += nFrameOff/2;
942 			nFrameOff %= 2;
943 			aFrameRect.Bottom() -= nFrameOff;
944 		}
945 		else if ( nFrameWidth > nFrameHeight )
946 		{
947 			nFrameOff = nFrameWidth-nFrameHeight;
948 			aFrameRect.Left() += nFrameOff/2;
949 			nFrameOff %= 2;
950 			aFrameRect.Right() -= nFrameOff;
951 		}
952 		DrawEllipse( aFrameRect );
953 	}
954 
955 	// Evt. noch FocusRect
956 	if ( bFocus && HasFocus() )
957 		ShowFocus( aDateRect );
958 
959 	if( mbDropPos && maDropDate == Date( nDay, nMonth, nYear ) )
960 		ImplInvertDropPos();
961 
962 	if ( bBoldFont )
963 		SetFont( aOldFont );
964 }
965 
966 // -----------------------------------------------------------------------
967 
968 void Calendar::ImplDraw( sal_Bool bPaint )
969 {
970 	ImplFormat();
971 
972 	const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
973 	Size		aOutSize = GetOutputSizePixel();
974 	long		i;
975 	long		j;
976 	long		nX;
977 	long		nY;
978 	long		nDeltaX;
979 	long		nDeltaY;
980 	long		nDayX;
981 	long		nDayY;
982 	sal_uLong		nToday = Date().GetDate();
983 	sal_uInt16		nDay;
984 	sal_uInt16		nMonth;
985 	sal_uInt16		nYear;
986 	Date		aDate = GetFirstMonth();
987 	DayOfWeek	eStartDay = ImplGetWeekStart();
988 
989 	HideFocus();
990 
991 	nY = 0;
992 	for ( i = 0; i < mnLines; i++ )
993 	{
994 		// Titleleiste ausgeben
995 		SetLineColor();
996 		SetFillColor( rStyleSettings.GetFaceColor() );
997 		Rectangle aTitleRect( 0, nY, aOutSize.Width()-1, nY+mnDayHeight-DAY_OFFY+TITLE_BORDERY*2 );
998 		if ( !bPaint )
999 		{
1000 			Rectangle aTempRect( 1, aTitleRect.Top()+TITLE_BORDERY,
1001 								 aOutSize.Width()-2,
1002 								 aTitleRect.Bottom()-TITLE_BORDERY );
1003 			if ( !i )
1004 			{
1005 				aTempRect.Left()  = maPrevRect.Right()+1;
1006 				aTempRect.Right() = maNextRect.Left()-1;
1007 			}
1008 			DrawRect( aTempRect );
1009 		}
1010 		else
1011 		{
1012 			DrawRect( aTitleRect );
1013 			Point aTopLeft1( aTitleRect.Left(), aTitleRect.Top() );
1014 			Point aTopLeft2( aTitleRect.Left(), aTitleRect.Top()+1 );
1015 			Point aBottomRight1( aTitleRect.Right(), aTitleRect.Bottom() );
1016 			Point aBottomRight2( aTitleRect.Right(), aTitleRect.Bottom()-1 );
1017 			SetLineColor( rStyleSettings.GetDarkShadowColor() );
1018 			DrawLine( aTopLeft1, Point( aBottomRight1.X(), aTopLeft1.Y() ) );
1019 			SetLineColor( rStyleSettings.GetLightColor() );
1020 			DrawLine( aTopLeft2, Point( aBottomRight2.X(), aTopLeft2.Y() ) );
1021 			DrawLine( aTopLeft2, Point( aTopLeft2.X(), aBottomRight2.Y() ) );
1022 			SetLineColor( rStyleSettings.GetShadowColor() );
1023 			DrawLine( Point( aTopLeft2.X(), aBottomRight2.Y() ), aBottomRight2 );
1024 			DrawLine( Point( aBottomRight2.X(), aTopLeft2.Y() ), aBottomRight2 );
1025 			SetLineColor( rStyleSettings.GetDarkShadowColor() );
1026 			DrawLine( Point( aTopLeft1.X(), aBottomRight1.Y() ), aBottomRight1 );
1027 		}
1028 		Point aSepPos1( 0, aTitleRect.Top()+TITLE_BORDERY );
1029 		Point aSepPos2( 0, aTitleRect.Bottom()-TITLE_BORDERY );
1030 		for ( j = 0; j < mnMonthPerLine-1; j++ )
1031 		{
1032 			aSepPos1.X() += mnMonthWidth-1;
1033 			aSepPos2.X() = aSepPos1.X();
1034 			SetLineColor( rStyleSettings.GetShadowColor() );
1035 			DrawLine( aSepPos1, aSepPos2 );
1036 			aSepPos1.X()++;
1037 			aSepPos2.X() = aSepPos1.X();
1038 			SetLineColor( rStyleSettings.GetLightColor() );
1039 			DrawLine( aSepPos1, aSepPos2 );
1040 		}
1041 
1042 		nX = 0;
1043 		for ( j = 0; j < mnMonthPerLine; j++ )
1044 		{
1045 			nMonth	= aDate.GetMonth();
1046 			nYear	= aDate.GetYear();
1047 
1048 			// Monat in der Titleleiste ausgeben
1049 			nDeltaX = nX;
1050 			nDeltaY = nY+TITLE_BORDERY;
1051             String aMonthText( maCalendarWrapper.getDisplayName(
1052                         i18n::CalendarDisplayIndex::MONTH, nMonth-1, 1));
1053 			aMonthText += ' ';
1054 			aMonthText += String::CreateFromInt64( nYear );
1055 			long nMonthTextWidth = GetTextWidth( aMonthText );
1056 			long nMonthOffX1 = 0;
1057 			long nMonthOffX2 = 0;
1058 			if ( i == 0 )
1059 			{
1060 				if ( j == 0 )
1061 					nMonthOffX1 = maPrevRect.Right()+1;
1062 				if ( j == mnMonthPerLine-1 )
1063 					nMonthOffX2 = aOutSize.Width()-maNextRect.Left()+1;
1064 			}
1065 			long nMaxMonthWidth = mnMonthWidth-nMonthOffX1-nMonthOffX2-4;
1066 			if ( nMonthTextWidth > nMaxMonthWidth )
1067 			{
1068 				// Abbreviated month name.
1069                 aMonthText  = maCalendarWrapper.getDisplayName(
1070                         i18n::CalendarDisplayIndex::MONTH, nMonth-1, 0);
1071 				aMonthText += ' ';
1072 				aMonthText += String::CreateFromInt64( nYear );
1073 				nMonthTextWidth = GetTextWidth( aMonthText );
1074 			}
1075 			long nTempOff = (mnMonthWidth-nMonthTextWidth+1)/2;
1076 			if ( nTempOff < nMonthOffX1 )
1077 				nDeltaX += nMonthOffX1+1;
1078 			else
1079 			{
1080 				if ( nTempOff+nMonthTextWidth > mnMonthWidth-nMonthOffX2 )
1081 					nDeltaX += mnMonthWidth-nMonthOffX2-nMonthTextWidth;
1082 				else
1083 					nDeltaX += nTempOff;
1084 			}
1085 			SetTextColor( rStyleSettings.GetButtonTextColor() );
1086 			DrawText( Point( nDeltaX, nDeltaY ), aMonthText );
1087 			SetTextColor( rStyleSettings.GetWindowTextColor() );
1088 
1089 			// Weekleiste ausgeben
1090 			if ( bPaint )
1091 			{
1092 				nDayX = nX+mnDaysOffX;
1093 				nDayY = nY+mnWeekDayOffY;
1094 				nDeltaY = nDayY + mnDayHeight;
1095 				SetLineColor( rStyleSettings.GetWindowTextColor() );
1096 				Point aStartPos( nDayX, nDeltaY );
1097 				if ( mnWinStyle & WB_WEEKNUMBER )
1098 					aStartPos.X() -= WEEKNUMBER_OFFX-2;
1099 				DrawLine( aStartPos, Point( nDayX+(7*mnDayWidth), nDeltaY ) );
1100 				DrawTextArray( Point( nDayX+mnDayOfWeekAry[0], nDayY ), maDayOfWeekText, &(mnDayOfWeekAry[1]) );
1101 			}
1102 
1103 			// Week-Numbers ausgeben
1104 			if ( mnWinStyle & WB_WEEKNUMBER )
1105 			{
1106 				nDayX = nX+mnDaysOffX;
1107 				nDayY = nY+mnWeekDayOffY;
1108 				nDeltaY = nDayY + mnDayHeight;
1109 				long nMonthHeight = mnDayHeight*6;
1110 				if ( bPaint )
1111 					DrawLine( Point( nDayX-WEEKNUMBER_OFFX+2, nDeltaY ), Point( nDayX-WEEKNUMBER_OFFX+2, nDeltaY+nMonthHeight ) );
1112 				else
1113 					Erase( Rectangle( nDayX-mnWeekWidth-WEEKNUMBER_OFFX, nDeltaY, nDayX-WEEKNUMBER_OFFX-1, nDeltaY+nMonthHeight ) );
1114 
1115 				Font aOldFont = GetFont();
1116 				Font aTempFont = aOldFont;
1117 				ImplGetWeekFont( aTempFont );
1118 				SetFont( aTempFont );
1119 				nDayX -= mnWeekWidth;
1120 				nDayY = nY+mnDaysOffY;
1121                 maCalendarWrapper.setGregorianDateTime( aDate);
1122 				for ( sal_uInt16 nWeekCount = 0; nWeekCount < 6; nWeekCount++ )
1123 				{
1124                     sal_Int16 nWeek = maCalendarWrapper.getValue( i18n::CalendarFieldIndex::WEEK_OF_YEAR);
1125 					String	aWeekText( String::CreateFromInt32( nWeek));
1126 					long	nOffX = (mnWeekWidth-WEEKNUMBER_OFFX)-GetTextWidth( aWeekText );
1127 					long	nOffY = (mnDayHeight-GetTextHeight())/2;
1128 					DrawText( Point( nDayX+nOffX, nDayY+nOffY ), aWeekText );
1129 					nDayY += mnDayHeight;
1130                     maCalendarWrapper.addValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, 7);
1131 				}
1132 				SetFont( aOldFont );
1133 			}
1134 
1135 			// Tage ausgeben
1136 			sal_uInt16 nDaysInMonth = aDate.GetDaysInMonth();
1137 			nDayX = nX+mnDaysOffX;
1138 			nDayY = nY+mnDaysOffY;
1139 			if ( !bPaint )
1140 			{
1141 				Rectangle aClearRect( nDayX, nDayY,
1142 									  nDayX+(7*mnDayWidth)-1, nDayY+(6*mnDayHeight)-1 );
1143 				Erase( aClearRect );
1144 			}
1145 			sal_uInt16 nDayIndex = (sal_uInt16)aDate.GetDayOfWeek();
1146 			nDayIndex = (nDayIndex+(7-(sal_uInt16)eStartDay)) % 7;
1147 			if ( (i == 0) && (j == 0) )
1148 			{
1149 				Date aTempDate = aDate;
1150 				aTempDate -= nDayIndex;
1151 				for ( nDay = 0; nDay < nDayIndex; nDay++ )
1152 				{
1153 					nDeltaX = nDayX + (nDay*mnDayWidth);
1154 					ImplDrawDate( nDeltaX, nDayY, nDay+aTempDate.GetDay(),
1155 								  aTempDate.GetMonth(), aTempDate.GetYear(),
1156 								  (DayOfWeek)((nDay+(sal_uInt16)eStartDay)%7), sal_False, sal_True, nToday );
1157 				}
1158 			}
1159 			for ( nDay = 1; nDay <= nDaysInMonth; nDay++ )
1160 			{
1161 				nDeltaX = nDayX + (nDayIndex*mnDayWidth);
1162 				ImplDrawDate( nDeltaX, nDayY, nDay, nMonth, nYear,
1163 							  (DayOfWeek)((nDayIndex+(sal_uInt16)eStartDay)%7),
1164 							  sal_False, sal_False, nToday );
1165 				if ( nDayIndex == 6 )
1166 				{
1167 					nDayIndex = 0;
1168 					nDayY += mnDayHeight;
1169 				}
1170 				else
1171 					nDayIndex++;
1172 			}
1173 			if ( (i == mnLines-1) && (j == mnMonthPerLine-1) )
1174 			{
1175 				sal_uInt16 nWeekDay = (sal_uInt16)aDate.GetDayOfWeek();
1176 				nWeekDay = (nWeekDay+(7-(sal_uInt16)eStartDay)) % 7;
1177 				sal_uInt16 nDayCount = 42-nDaysInMonth-nWeekDay;
1178 				Date aTempDate = aDate;
1179 				aTempDate += nDaysInMonth;
1180 				for ( nDay = 1; nDay <= nDayCount; nDay++ )
1181 				{
1182 					nDeltaX = nDayX + (nDayIndex*mnDayWidth);
1183 					ImplDrawDate( nDeltaX, nDayY, nDay,
1184 								  aTempDate.GetMonth(), aTempDate.GetYear(),
1185 								  (DayOfWeek)((nDayIndex+(sal_uInt16)eStartDay)%7),
1186 								  sal_False, sal_True, nToday );
1187 					if ( nDayIndex == 6 )
1188 					{
1189 						nDayIndex = 0;
1190 						nDayY += mnDayHeight;
1191 					}
1192 					else
1193 						nDayIndex++;
1194 				}
1195 			}
1196 
1197 			aDate += nDaysInMonth;
1198 			nX += mnMonthWidth;
1199 		}
1200 
1201 		nY += mnMonthHeight;
1202 	}
1203 
1204 	// Spin-Buttons zeichnen
1205 	if ( bPaint )
1206 		ImplDrawSpin();
1207 }
1208 
1209 // -----------------------------------------------------------------------
1210 
1211 void Calendar::ImplUpdateDate( const Date& rDate )
1212 {
1213 	if ( IsReallyVisible() && IsUpdateMode() )
1214 	{
1215 		Rectangle aDateRect( GetDateRect( rDate ) );
1216 		if ( !aDateRect.IsEmpty() )
1217 		{
1218 			sal_Bool bOther = (rDate < GetFirstMonth()) || (rDate > GetLastMonth());
1219 			ImplDrawDate( aDateRect.Left(), aDateRect.Top(),
1220 						  rDate.GetDay(), rDate.GetMonth(), rDate.GetYear(),
1221 						  rDate.GetDayOfWeek(), sal_True, bOther );
1222 		}
1223 	}
1224 }
1225 
1226 // -----------------------------------------------------------------------
1227 
1228 void Calendar::ImplUpdateSelection( Table* pOld )
1229 {
1230 	Table*	pNew = mpSelectTable;
1231 	void*	p;
1232 	sal_uLong	nKey;
1233 
1234 	p = pOld->First();
1235 	while ( p )
1236 	{
1237 		nKey = pOld->GetCurKey();
1238 		if ( !pNew->Get( nKey ) )
1239 		{
1240 			Date aTempDate( nKey );
1241 			ImplUpdateDate( aTempDate );
1242 		}
1243 
1244 		p = pOld->Next();
1245 	}
1246 
1247 	p = pNew->First();
1248 	while ( p )
1249 	{
1250 		nKey = pNew->GetCurKey();
1251 		if ( !pOld->Get( nKey ) )
1252 		{
1253 			Date aTempDate( nKey );
1254 			ImplUpdateDate( aTempDate );
1255 		}
1256 
1257 		p = pNew->Next();
1258 	}
1259 }
1260 
1261 // -----------------------------------------------------------------------
1262 
1263 void Calendar::ImplMouseSelect( const Date& rDate, sal_uInt16 nHitTest,
1264 								sal_Bool bMove, sal_Bool bExpand, sal_Bool bExtended )
1265 {
1266 	Table*	pOldSel = new Table( *mpSelectTable );
1267 	Date	aOldDate = maCurDate;
1268 	Date	aTempDate = rDate;
1269 
1270 	if ( !(nHitTest & CALENDAR_HITTEST_DAY) )
1271 		aTempDate--;
1272 
1273 	if ( mbMultiSelection )
1274 	{
1275 		maCurDate = aTempDate;
1276 		mbSelLeft = aTempDate < maAnchorDate;
1277 
1278 		if ( bMove )
1279 		{
1280 			if ( mbSelLeft )
1281 			{
1282 				ImplCalendarUnSelectDateRange( mpSelectTable, mpRestoreSelectTable, Date( 1, 1, 0 ), aTempDate );
1283 				ImplCalendarUnSelectDateRange( mpSelectTable, mpRestoreSelectTable, maAnchorDate, Date( 31, 12, 9999 ) );
1284 			}
1285 			else
1286 			{
1287 				ImplCalendarUnSelectDateRange( mpSelectTable, mpRestoreSelectTable, Date( 1, 1, 0 ), maAnchorDate );
1288 				ImplCalendarUnSelectDateRange( mpSelectTable, mpRestoreSelectTable, aTempDate, Date( 31, 12, 9999 ) );
1289 			}
1290 			ImplCalendarSelectDateRange( mpSelectTable, aTempDate, maAnchorDate, !mbUnSel );
1291 		}
1292 		else
1293 		{
1294 			if ( bExpand )
1295 			{
1296 				if ( !bExtended )
1297 				{
1298 					if ( mbSelLeft )
1299 					{
1300 						ImplCalendarSelectDateRange( mpSelectTable, Date( 1, 1, 0 ), aTempDate, sal_False );
1301 						ImplCalendarSelectDateRange( mpSelectTable, maAnchorDate, Date( 31, 12, 9999 ), sal_False );
1302 					}
1303 					else
1304 					{
1305 						ImplCalendarSelectDateRange( mpSelectTable, Date( 1, 1, 0 ), maAnchorDate, sal_False );
1306 						ImplCalendarSelectDateRange( mpSelectTable, aTempDate, Date( 31, 12, 9999 ), sal_False );
1307 					}
1308 				}
1309 				ImplCalendarSelectDateRange( mpSelectTable, aTempDate, maAnchorDate, sal_True );
1310 			}
1311 			else if ( bExtended && !(mnWinStyle & WB_RANGESELECT) )
1312 			{
1313 				maAnchorDate = aTempDate;
1314 				if ( IsDateSelected( aTempDate ) )
1315 				{
1316 					mbUnSel = sal_True;
1317 					ImplCalendarSelectDate( mpSelectTable, aTempDate, sal_False );
1318 				}
1319 				else
1320 				{
1321 					ImplCalendarSelectDate( mpSelectTable, aTempDate, sal_True );
1322 				}
1323 			}
1324 			else
1325 			{
1326 				maAnchorDate = aTempDate;
1327 				ImplCalendarClearSelectDate( mpSelectTable );
1328 				ImplCalendarSelectDate( mpSelectTable, aTempDate, sal_True );
1329 			}
1330 
1331 			mpRestoreSelectTable = new Table( *mpSelectTable );
1332 		}
1333 	}
1334 	else
1335 	{
1336 		if ( aTempDate < maCurDate )
1337 			mbSelLeft = sal_True;
1338 		else
1339 			mbSelLeft = sal_False;
1340 		if ( !(nHitTest & CALENDAR_HITTEST_DAY) )
1341 			aTempDate = maOldCurDate;
1342 		if ( !bMove )
1343 			maAnchorDate = aTempDate;
1344 		if ( aTempDate != maCurDate )
1345 		{
1346 			maCurDate = aTempDate;
1347 			ImplCalendarSelectDate( mpSelectTable, aOldDate, sal_False );
1348 			ImplCalendarSelectDate( mpSelectTable, maCurDate, sal_True );
1349 		}
1350 	}
1351 
1352 	sal_Bool bNewSel = *pOldSel != *mpSelectTable;
1353 	if ( (maCurDate != aOldDate) || bNewSel )
1354 	{
1355 		if ( bNewSel )
1356 		{
1357 			mbInSelChange = sal_True;
1358 			SelectionChanging();
1359 			mbInSelChange = sal_False;
1360 		}
1361 		HideFocus();
1362 		if ( bNewSel )
1363 			ImplUpdateSelection( pOldSel );
1364 		if ( !bNewSel || !pOldSel->Get( aOldDate.GetDate() ) )
1365 			ImplUpdateDate( aOldDate );
1366 		// Damit Focus-Rechteck auch wieder neu ausgegeben wird
1367 		if ( HasFocus() || !bNewSel || !mpSelectTable->Get( maCurDate.GetDate() ) )
1368 			ImplUpdateDate( maCurDate );
1369 	}
1370 	delete pOldSel;
1371 }
1372 
1373 // -----------------------------------------------------------------------
1374 
1375 void Calendar::ImplUpdate( sal_Bool bCalcNew )
1376 {
1377 	if ( IsReallyVisible() && IsUpdateMode() )
1378 	{
1379 		if ( bCalcNew && !mbCalc )
1380 			Invalidate();
1381 		else if ( !mbFormat && !mbCalc )
1382 		{
1383 			if ( mbDirect )
1384 			{
1385 				mbFormat = sal_True;
1386 				ImplDraw( sal_False );
1387 				return;
1388 			}
1389 			else
1390 				Invalidate();
1391 		}
1392 	}
1393 
1394 	if ( bCalcNew )
1395 		mbCalc = sal_True;
1396 	mbFormat = sal_True;
1397 }
1398 
1399 // -----------------------------------------------------------------------
1400 
1401 void Calendar::ImplInvertDropPos()
1402 {
1403 	Rectangle aRect = GetDateRect( maDropDate );//this is one Pixel to width and one to heigh
1404 	aRect.Bottom() = aRect.Top()+mnDayHeight-1;
1405 	aRect.Right() = aRect.Left()+mnDayWidth-1;
1406 	Invert( aRect );
1407 }
1408 
1409 // -----------------------------------------------------------------------
1410 
1411 void Calendar::ImplScroll( sal_Bool bPrev )
1412 {
1413 	Date aNewFirstMonth = GetFirstMonth();
1414 	if ( bPrev )
1415 	{
1416 		aNewFirstMonth--;
1417 		aNewFirstMonth -= aNewFirstMonth.GetDaysInMonth()-1;
1418 	}
1419 	else
1420 		aNewFirstMonth += aNewFirstMonth.GetDaysInMonth();
1421 	mbDirect = sal_True;
1422 	SetFirstDate( aNewFirstMonth );
1423 	mbDirect = sal_False;
1424 }
1425 
1426 // -----------------------------------------------------------------------
1427 
1428 void Calendar::ImplShowMenu( const Point& rPos, const Date& rDate )
1429 {
1430 	EndSelection();
1431 
1432 	Date		aOldFirstDate = GetFirstMonth();
1433 	PopupMenu	aPopupMenu;
1434 	PopupMenu*	pYearPopupMenus[MENU_YEAR_COUNT];
1435 	sal_uInt16		nMonthOff;
1436 	sal_uInt16		nCurItemId;
1437 	sal_uInt16		nYear = rDate.GetYear()-1;
1438 	sal_uInt16		i;
1439 	sal_uInt16		j;
1440 	sal_uInt16		nYearIdCount = 1000;
1441 
1442 	nMonthOff = (rDate.GetYear()-aOldFirstDate.GetYear())*12;
1443 	if ( aOldFirstDate.GetMonth() < rDate.GetMonth() )
1444 		nMonthOff += rDate.GetMonth()-aOldFirstDate.GetMonth();
1445 	else
1446 		nMonthOff -= aOldFirstDate.GetMonth()-rDate.GetMonth();
1447 
1448 	// Menu aufbauen (Jahre mit verschiedenen Monaten aufnehmen)
1449 	for ( i = 0; i < MENU_YEAR_COUNT; i++ )
1450 	{
1451 		pYearPopupMenus[i] = new PopupMenu;
1452 		for ( j = 1; j <= 12; j++ )
1453             pYearPopupMenus[i]->InsertItem( nYearIdCount+j,
1454                     maCalendarWrapper.getDisplayName(
1455                         i18n::CalendarDisplayIndex::MONTH, j-1, 1));
1456 		aPopupMenu.InsertItem( 10+i, UniString::CreateFromInt32( nYear+i ) );
1457 		aPopupMenu.SetPopupMenu( 10+i, pYearPopupMenus[i] );
1458 		nYearIdCount += 1000;
1459 	}
1460 
1461 	mbMenuDown = sal_True;
1462 	nCurItemId = aPopupMenu.Execute( this, rPos );
1463 	mbMenuDown = sal_False;
1464 
1465 	// Menu zerstoeren
1466 	aPopupMenu.SetPopupMenu( 2, NULL );
1467 	for ( i = 0; i < MENU_YEAR_COUNT; i++ )
1468 	{
1469 		aPopupMenu.SetPopupMenu( 10+i, NULL );
1470 		delete pYearPopupMenus[i];
1471 	}
1472 
1473 	if ( nCurItemId )
1474 	{
1475 		sal_uInt16 nTempMonthOff = nMonthOff % 12;
1476 		sal_uInt16 nTempYearOff = nMonthOff / 12;
1477 		sal_uInt16 nNewMonth = nCurItemId % 1000;
1478 		sal_uInt16 nNewYear = nYear+((nCurItemId-1000)/1000);
1479 		if ( nTempMonthOff < nNewMonth )
1480 			nNewMonth = nNewMonth - nTempMonthOff;
1481 		else
1482 		{
1483 			nNewYear--;
1484 			nNewMonth = 12-(nTempMonthOff-nNewMonth);
1485 		}
1486 		nNewYear = nNewYear - nTempYearOff;
1487 		SetFirstDate( Date( 1, nNewMonth, nNewYear ) );
1488 	}
1489 }
1490 
1491 // -----------------------------------------------------------------------
1492 
1493 void Calendar::ImplTracking( const Point& rPos, sal_Bool bRepeat )
1494 {
1495 	Date	aTempDate = maCurDate;
1496 	sal_uInt16	nHitTest = ImplHitTest( rPos, aTempDate );
1497 
1498 	if ( mbSpinDown )
1499 	{
1500 		mbPrevIn = (nHitTest & CALENDAR_HITTEST_PREV) != 0;
1501 		mbNextIn = (nHitTest & CALENDAR_HITTEST_NEXT) != 0;
1502 
1503 		if ( bRepeat && (mbPrevIn || mbNextIn) )
1504 		{
1505 			mbScrollDateRange = sal_True;
1506 			ImplScroll( mbPrevIn );
1507 			mbScrollDateRange = sal_False;
1508 		}
1509 	}
1510 	else
1511 		ImplMouseSelect( aTempDate, nHitTest, sal_True, sal_False, sal_False );
1512 }
1513 
1514 // -----------------------------------------------------------------------
1515 
1516 void Calendar::ImplEndTracking( sal_Bool bCancel )
1517 {
1518 	sal_Bool bSelection = mbSelection;
1519 	sal_Bool bSpinDown = mbSpinDown;
1520 
1521 	mbDrag				= sal_False;
1522 	mbSelection 		= sal_False;
1523 	mbMultiSelection	= sal_False;
1524 	mbUnSel 			= sal_False;
1525 	mbSpinDown			= sal_False;
1526 	mbPrevIn			= sal_False;
1527 	mbNextIn			= sal_False;
1528 
1529 	if ( bCancel )
1530 	{
1531 		if ( maOldFirstDate != maFirstDate )
1532 			SetFirstDate( maOldFirstDate );
1533 
1534 		if ( !bSpinDown )
1535 		{
1536 			Table*	pOldSel = new Table( *mpSelectTable );
1537 			Date	aOldDate = maCurDate;
1538 			maCurDate		= maOldCurDate;
1539 			*mpSelectTable	= *mpOldSelectTable;
1540 			HideFocus();
1541 			ImplUpdateSelection( pOldSel );
1542 			if ( !pOldSel->Get( aOldDate.GetDate() ) )
1543 				ImplUpdateDate( aOldDate );
1544 			// Damit Focus-Rechteck auch wieder neu ausgegeben wird
1545 			if ( HasFocus() || !mpSelectTable->Get( maCurDate.GetDate() ) )
1546 				ImplUpdateDate( maCurDate );
1547 			delete pOldSel;
1548 		}
1549 	}
1550 
1551 	if ( !bSpinDown )
1552 	{
1553 		if ( !bCancel )
1554 		{
1555 			// Feststellen, ob wir sichtbaren Bereich scrollen sollen
1556 			sal_uLong nSelCount = mpSelectTable->Count();
1557 			if ( nSelCount )
1558 			{
1559 				Date aFirstSelDate( mpSelectTable->GetObjectKey( 0 ) );
1560 				Date aLastSelDate( mpSelectTable->GetObjectKey( nSelCount-1 ) );
1561 				if ( aLastSelDate < GetFirstMonth() )
1562 					ImplScroll( sal_True );
1563 				else if ( GetLastMonth() < aFirstSelDate )
1564 					ImplScroll( sal_False );
1565 			}
1566 		}
1567 
1568 		if ( mbAllSel ||
1569 			 (!bCancel && ((maCurDate != maOldCurDate) || (*mpOldSelectTable != *mpSelectTable))) )
1570 			Select();
1571 
1572 		if ( !bSelection && (mnWinStyle & WB_TABSTOP) && !bCancel )
1573 			GrabFocus();
1574 
1575 		delete mpOldSelectTable;
1576 		mpOldSelectTable = NULL;
1577 		delete mpRestoreSelectTable;
1578 		mpRestoreSelectTable = NULL;
1579 	}
1580 }
1581 
1582 // -----------------------------------------------------------------------
1583 
1584 IMPL_STATIC_LINK( Calendar, ScrollHdl, Timer*, EMPTYARG )
1585 {
1586 	sal_Bool bPrevIn = (pThis->mnDragScrollHitTest & CALENDAR_HITTEST_PREV) != 0;
1587 	sal_Bool bNextIn = (pThis->mnDragScrollHitTest & CALENDAR_HITTEST_NEXT) != 0;
1588 	if( bNextIn || bPrevIn )
1589 	{
1590 		pThis->mbScrollDateRange = sal_True;
1591 		pThis->ImplScroll( bPrevIn );
1592 		pThis->mbScrollDateRange = sal_False;
1593 	}
1594 	return 0;
1595 }
1596 
1597 // -----------------------------------------------------------------------
1598 
1599 void Calendar::MouseButtonDown( const MouseEvent& rMEvt )
1600 {
1601 	if ( rMEvt.IsLeft() && !mbMenuDown )
1602 	{
1603 		Date	aTempDate = maCurDate;
1604 		sal_uInt16	nHitTest = ImplHitTest( rMEvt.GetPosPixel(), aTempDate );
1605 		if ( nHitTest )
1606 		{
1607 			if ( nHitTest & CALENDAR_HITTEST_MONTHTITLE )
1608 				ImplShowMenu( rMEvt.GetPosPixel(), aTempDate );
1609 			else
1610 			{
1611 				maOldFirstDate = maFirstDate;
1612 
1613 				mbPrevIn = (nHitTest & CALENDAR_HITTEST_PREV) != 0;
1614 				mbNextIn = (nHitTest & CALENDAR_HITTEST_NEXT) != 0;
1615 				if ( mbPrevIn || mbNextIn )
1616 				{
1617 					mbSpinDown = sal_True;
1618 					mbScrollDateRange = sal_True;
1619 					ImplScroll( mbPrevIn );
1620 					mbScrollDateRange = sal_False;
1621 					// Hier muss BUTTONREPEAT stehen, also nicht wieder
1622 					// auf SCROLLREPEAT aendern, sondern mit TH abklaeren,
1623 					// warum es evtl. anders sein sollte (71775)
1624 					StartTracking( STARTTRACK_BUTTONREPEAT );
1625 				}
1626 				else
1627 				{
1628 					if ( (rMEvt.GetClicks() == 2) && (nHitTest & CALENDAR_HITTEST_DAY) )
1629 						DoubleClick();
1630 					else
1631 					{
1632 						if ( mpOldSelectTable )
1633 							delete mpOldSelectTable;
1634 						maOldCurDate = maCurDate;
1635 						mpOldSelectTable = new Table( *mpSelectTable );
1636 
1637 						if ( !mbSelection )
1638 						{
1639 							mbDrag = sal_True;
1640 							StartTracking();
1641 						}
1642 
1643 						mbMultiSelection = (mnWinStyle & (WB_MULTISELECT | WB_RANGESELECT)) != 0;
1644 						if ( (nHitTest & CALENDAR_HITTEST_DAY) && mbMultiSelection )
1645 							mbWeekSel = sal_True;
1646 						else
1647 							mbWeekSel = sal_False;
1648 						ImplMouseSelect( aTempDate, nHitTest, sal_False, rMEvt.IsShift(), rMEvt.IsMod1() );
1649 					}
1650 				}
1651 			}
1652 		}
1653 
1654 		return;
1655 	}
1656 
1657 	Control::MouseButtonDown( rMEvt );
1658 }
1659 
1660 // -----------------------------------------------------------------------
1661 
1662 void Calendar::MouseButtonUp( const MouseEvent& rMEvt )
1663 {
1664 	if ( rMEvt.IsLeft() && mbSelection )
1665 		ImplEndTracking( sal_False );
1666 	else
1667 		Control::MouseButtonUp( rMEvt );
1668 }
1669 
1670 // -----------------------------------------------------------------------
1671 
1672 void Calendar::MouseMove( const MouseEvent& rMEvt )
1673 {
1674 	if ( mbSelection && rMEvt.GetButtons() )
1675 		ImplTracking( rMEvt.GetPosPixel(), sal_False );
1676 	else
1677 		Control::MouseMove( rMEvt );
1678 }
1679 
1680 // -----------------------------------------------------------------------
1681 
1682 void Calendar::Tracking( const TrackingEvent& rTEvt )
1683 {
1684 	Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel();
1685 
1686 	if ( rTEvt.IsTrackingEnded() )
1687 		ImplEndTracking( rTEvt.IsTrackingCanceled() );
1688 	else
1689 		ImplTracking( aMousePos, rTEvt.IsTrackingRepeat() );
1690 }
1691 
1692 // -----------------------------------------------------------------------
1693 
1694 void Calendar::KeyInput( const KeyEvent& rKEvt )
1695 {
1696 	Date	aNewDate = maCurDate;
1697 	sal_Bool	bMultiSel = (mnWinStyle & (WB_RANGESELECT | WB_MULTISELECT)) != 0;
1698 	sal_Bool	bExpand = rKEvt.GetKeyCode().IsShift();
1699 	sal_Bool	bExtended = rKEvt.GetKeyCode().IsMod1();
1700 
1701 	switch ( rKEvt.GetKeyCode().GetCode() )
1702 	{
1703 		case KEY_HOME:
1704 			aNewDate.SetDay( 1 );
1705 			break;
1706 
1707 		case KEY_END:
1708 			aNewDate.SetDay( aNewDate.GetDaysInMonth() );
1709 			break;
1710 
1711 		case KEY_LEFT:
1712 			aNewDate--;
1713 			break;
1714 
1715 		case KEY_RIGHT:
1716 			aNewDate++;
1717 			break;
1718 
1719 		case KEY_UP:
1720 			aNewDate -= 7;
1721 			break;
1722 
1723 		case KEY_DOWN:
1724 			aNewDate += 7;
1725 			break;
1726 
1727 		case KEY_PAGEUP:
1728 			{
1729 			Date aTempDate = aNewDate;
1730 			aTempDate -= aNewDate.GetDay()+1;
1731 			aNewDate -= aTempDate.GetDaysInMonth();
1732 			}
1733 			break;
1734 
1735 		case KEY_PAGEDOWN:
1736 			aNewDate += aNewDate.GetDaysInMonth();
1737 			break;
1738 
1739 		case KEY_SPACE:
1740 			if ( bMultiSel && !(mnWinStyle & WB_RANGESELECT) )
1741 			{
1742 				if ( !bExpand )
1743 				{
1744 					sal_Bool bDateSel = IsDateSelected( maCurDate );
1745 					SelectDate( maCurDate, !bDateSel );
1746 					mbSelLeft = sal_False;
1747 					SelectionChanging();
1748 					mbTravelSelect = sal_True;
1749 					Select();
1750 					mbTravelSelect = sal_False;
1751 				}
1752 			}
1753 			else
1754 				Control::KeyInput( rKEvt );
1755 			break;
1756 
1757 		default:
1758 			Control::KeyInput( rKEvt );
1759 			break;
1760 	}
1761 
1762 	if ( aNewDate != maCurDate )
1763 	{
1764 		if ( bMultiSel && bExpand )
1765 		{
1766 			Table* pOldSel = new Table( *mpSelectTable );
1767 			Date aOldAnchorDate = maAnchorDate;
1768 			mbSelLeft = aNewDate < maAnchorDate;
1769 			if ( !bExtended )
1770 			{
1771 				if ( mbSelLeft )
1772 				{
1773 					ImplCalendarSelectDateRange( mpSelectTable, Date( 1, 1, 0 ), aNewDate, sal_False );
1774 					ImplCalendarSelectDateRange( mpSelectTable, maAnchorDate, Date( 31, 12, 9999 ), sal_False );
1775 				}
1776 				else
1777 				{
1778 					ImplCalendarSelectDateRange( mpSelectTable, Date( 1, 1, 0 ), maAnchorDate, sal_False );
1779 					ImplCalendarSelectDateRange( mpSelectTable, aNewDate, Date( 31, 12, 9999 ), sal_False );
1780 				}
1781 			}
1782 			ImplCalendarSelectDateRange( mpSelectTable, aNewDate, maAnchorDate, sal_True );
1783 			mbDirect = sal_True;
1784 			SetCurDate( aNewDate );
1785 			mbDirect = sal_False;
1786 			maAnchorDate = aOldAnchorDate;
1787 			mbInSelChange = sal_True;
1788 			SelectionChanging();
1789 			mbInSelChange = sal_False;
1790 			ImplUpdateSelection( pOldSel );
1791             delete pOldSel;
1792 		}
1793 		else
1794 		{
1795 			if ( mnWinStyle & WB_RANGESELECT )
1796 			{
1797 				SetNoSelection();
1798 				SelectDate( aNewDate, sal_True );
1799 			}
1800 			mbDirect = sal_True;
1801 			SetCurDate( aNewDate );
1802 			mbDirect = sal_False;
1803 		}
1804 		mbTravelSelect = sal_True;
1805 		Select();
1806 		mbTravelSelect = sal_False;
1807 	}
1808 }
1809 
1810 // -----------------------------------------------------------------------
1811 
1812 void Calendar::Paint( const Rectangle& )
1813 {
1814 	ImplDraw( sal_True );
1815 }
1816 
1817 // -----------------------------------------------------------------------
1818 
1819 void Calendar::GetFocus()
1820 {
1821 	ImplUpdateDate( maCurDate );
1822 	Control::GetFocus();
1823 }
1824 
1825 // -----------------------------------------------------------------------
1826 
1827 void Calendar::LoseFocus()
1828 {
1829 	HideFocus();
1830 	Control::LoseFocus();
1831 }
1832 
1833 // -----------------------------------------------------------------------
1834 
1835 void Calendar::Resize()
1836 {
1837 	ImplUpdate( sal_True );
1838 	Control::Resize();
1839 }
1840 
1841 // -----------------------------------------------------------------------
1842 
1843 void Calendar::RequestHelp( const HelpEvent& rHEvt )
1844 {
1845 	if ( rHEvt.GetMode() & (HELPMODE_QUICK | HELPMODE_BALLOON) )
1846 	{
1847 		Date aDate = maCurDate;
1848 		if ( GetDate( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ), aDate ) )
1849 		{
1850 			Rectangle aDateRect = GetDateRect( aDate );
1851 			Point aPt = OutputToScreenPixel( aDateRect.TopLeft() );
1852 			aDateRect.Left()   = aPt.X();
1853 			aDateRect.Top()    = aPt.Y();
1854 			aPt = OutputToScreenPixel( aDateRect.BottomRight() );
1855 			aDateRect.Right()  = aPt.X();
1856 			aDateRect.Bottom() = aPt.Y();
1857 
1858 			if ( (rHEvt.GetMode() & HELPMODE_BALLOON) || (mnWinStyle & WB_QUICKHELPSHOWSDATEINFO) )
1859 			{
1860 				ImplDateInfo* pInfo;
1861 				if ( mpDateTable )
1862 				{
1863 					pInfo = mpDateTable->Get( aDate.GetDate() );
1864 					if ( !pInfo )
1865 						pInfo = mpDateTable->Get( Date( aDate.GetDay(), aDate.GetMonth(), 0 ).GetDate() );
1866 				}
1867 				else
1868 					pInfo = NULL;
1869 				if ( pInfo )
1870 				{
1871 					XubString aStr = pInfo->maText;
1872 					if ( aStr.Len() )
1873 					{
1874 						Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), aDateRect, aStr );
1875 						return;
1876 					}
1877 				}
1878 			}
1879 
1880 			if ( rHEvt.GetMode() & HELPMODE_QUICK )
1881 			{
1882                 maCalendarWrapper.setGregorianDateTime( aDate);
1883                 sal_uInt16      nWeek = (sal_uInt16) maCalendarWrapper.getValue( i18n::CalendarFieldIndex::WEEK_OF_YEAR);
1884 				sal_uInt16		nMonth = aDate.GetMonth();
1885 				XubString	aStr( maDayText );
1886 				aStr.AppendAscii( ": " );
1887 				aStr.Append( XubString::CreateFromInt32( aDate.GetDayOfYear() ) );
1888 				aStr.AppendAscii( " / " );
1889 				aStr.Append( maWeekText );
1890 				aStr.AppendAscii( ": " );
1891 				aStr.Append( XubString::CreateFromInt32( nWeek ) );
1892 				// Evt. noch Jahr hinzufuegen, wenn es nicht das gleiche ist
1893 				if ( (nMonth == 12) && (nWeek == 1) )
1894 				{
1895 					aStr.AppendAscii( ",  " );
1896 					aStr.Append( XubString::CreateFromInt32( aDate.GetYear()+1 ) );
1897 				}
1898 				else if ( (nMonth == 1) && (nWeek > 50) )
1899 				{
1900 					aStr.AppendAscii( ", " );
1901 					aStr.Append( XubString::CreateFromInt32( aDate.GetYear()-1 ) );
1902 				}
1903 				Help::ShowQuickHelp( this, aDateRect, aStr );
1904 				return;
1905 			}
1906 		}
1907 	}
1908 
1909 	Control::RequestHelp( rHEvt );
1910 }
1911 
1912 // -----------------------------------------------------------------------
1913 
1914 void Calendar::Command( const CommandEvent& rCEvt )
1915 {
1916 	if ( rCEvt.GetCommand() == COMMAND_CONTEXTMENU )
1917 	{
1918 		if ( !mbSelection && rCEvt.IsMouseEvent() )
1919 		{
1920 			Date	aTempDate = maCurDate;
1921 			sal_uInt16	nHitTest = ImplHitTest( rCEvt.GetMousePosPixel(), aTempDate );
1922 			if ( nHitTest & CALENDAR_HITTEST_MONTHTITLE )
1923 			{
1924 				ImplShowMenu( rCEvt.GetMousePosPixel(), aTempDate );
1925 				return;
1926 			}
1927 		}
1928 	}
1929 	else if ( rCEvt.GetCommand() == COMMAND_WHEEL )
1930 	{
1931 		const CommandWheelData* pData = rCEvt.GetWheelData();
1932 		if ( pData->GetMode() == COMMAND_WHEEL_SCROLL )
1933 		{
1934 			long nNotchDelta = pData->GetNotchDelta();
1935 			if ( nNotchDelta < 0 )
1936 			{
1937 				while ( nNotchDelta < 0 )
1938 				{
1939 					ImplScroll( sal_True );
1940 					nNotchDelta++;
1941 				}
1942 			}
1943 			else
1944 			{
1945 				while ( nNotchDelta > 0 )
1946 				{
1947 					ImplScroll( sal_False );
1948 					nNotchDelta--;
1949 				}
1950 			}
1951 
1952 			return;
1953 		}
1954 	}
1955 
1956 	Control::Command( rCEvt );
1957 }
1958 
1959 // -----------------------------------------------------------------------
1960 
1961 void Calendar::StateChanged( StateChangedType nType )
1962 {
1963 	Control::StateChanged( nType );
1964 
1965 	if ( nType == STATE_CHANGE_INITSHOW )
1966 		ImplFormat();
1967 }
1968 
1969 // -----------------------------------------------------------------------
1970 
1971 void Calendar::DataChanged( const DataChangedEvent& rDCEvt )
1972 {
1973 	Control::DataChanged( rDCEvt );
1974 
1975 	if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
1976 		 (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
1977 		 ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
1978 		  (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
1979 	{
1980 		ImplInitSettings();
1981 		Invalidate();
1982 	}
1983 }
1984 
1985 // -----------------------------------------------------------------------
1986 
1987 void Calendar::SelectionChanging()
1988 {
1989 	maSelectionChangingHdl.Call( this );
1990 }
1991 
1992 // -----------------------------------------------------------------------
1993 
1994 void Calendar::DateRangeChanged()
1995 {
1996 	maDateRangeChangedHdl.Call( this );
1997 }
1998 
1999 // -----------------------------------------------------------------------
2000 
2001 void Calendar::RequestDateInfo()
2002 {
2003 	maRequestDateInfoHdl.Call( this );
2004 }
2005 
2006 // -----------------------------------------------------------------------
2007 
2008 void Calendar::DoubleClick()
2009 {
2010 	maDoubleClickHdl.Call( this );
2011 }
2012 
2013 // -----------------------------------------------------------------------
2014 
2015 void Calendar::Select()
2016 {
2017 	maSelectHdl.Call( this );
2018 }
2019 
2020 // -----------------------------------------------------------------------
2021 
2022 void Calendar::SelectDate( const Date& rDate, sal_Bool bSelect )
2023 {
2024 	if ( !rDate.IsValid() )
2025 		return;
2026 
2027 	Table* pOldSel;
2028 
2029 	if ( !mbInSelChange )
2030 		pOldSel = new Table( *mpSelectTable );
2031 	else
2032 		pOldSel = NULL;
2033 
2034 	ImplCalendarSelectDate( mpSelectTable, rDate, bSelect );
2035 
2036 	if ( pOldSel )
2037 	{
2038 		ImplUpdateSelection( pOldSel );
2039 		delete pOldSel;
2040 	}
2041 }
2042 
2043 // -----------------------------------------------------------------------
2044 
2045 void Calendar::SelectDateRange( const Date& rStartDate, const Date& rEndDate,
2046 								sal_Bool bSelect )
2047 {
2048 	if ( !rStartDate.IsValid() || !rEndDate.IsValid() )
2049 		return;
2050 
2051 	Table* pOldSel;
2052 
2053 	if ( !mbInSelChange )
2054 		pOldSel = new Table( *mpSelectTable );
2055 	else
2056 		pOldSel = NULL;
2057 
2058 	ImplCalendarSelectDateRange( mpSelectTable, rStartDate, rEndDate, bSelect );
2059 
2060 	if ( pOldSel )
2061 	{
2062 		ImplUpdateSelection( pOldSel );
2063 		delete pOldSel;
2064 	}
2065 }
2066 
2067 // -----------------------------------------------------------------------
2068 
2069 void Calendar::SetNoSelection()
2070 {
2071 	Table* pOldSel;
2072 
2073 	if ( !mbInSelChange )
2074 		pOldSel = new Table( *mpSelectTable );
2075 	else
2076 		pOldSel = NULL;
2077 
2078 	ImplCalendarClearSelectDate( mpSelectTable );
2079 
2080 	if ( pOldSel )
2081 	{
2082 		ImplUpdateSelection( pOldSel );
2083 		delete pOldSel;
2084 	}
2085 }
2086 
2087 // -----------------------------------------------------------------------
2088 
2089 sal_Bool Calendar::IsDateSelected( const Date& rDate ) const
2090 {
2091 	return mpSelectTable->IsKeyValid( rDate.GetDate() );
2092 }
2093 
2094 // -----------------------------------------------------------------------
2095 
2096 sal_uLong Calendar::GetSelectDateCount() const
2097 {
2098 	return mpSelectTable->Count();
2099 }
2100 
2101 // -----------------------------------------------------------------------
2102 
2103 Date Calendar::GetSelectDate( sal_uLong nIndex ) const
2104 {
2105 	if ( nIndex < mpSelectTable->Count() )
2106 		return Date( mpSelectTable->GetObjectKey( nIndex ) );
2107 	else
2108 	{
2109 		Date aDate( 0, 0, 0 );
2110 		return aDate;
2111 	}
2112 }
2113 
2114 // -----------------------------------------------------------------------
2115 
2116 void Calendar::SetCurDate( const Date& rNewDate )
2117 {
2118 	if ( !rNewDate.IsValid() )
2119 		return;
2120 
2121 	if ( maCurDate != rNewDate )
2122 	{
2123 		sal_Bool bUpdate	= IsVisible() && IsUpdateMode();
2124 		Date aOldDate	= maCurDate;
2125 		maCurDate		= rNewDate;
2126 		maAnchorDate	= maCurDate;
2127 
2128 		if ( !(mnWinStyle & (WB_RANGESELECT | WB_MULTISELECT)) )
2129 		{
2130 			ImplCalendarSelectDate( mpSelectTable, aOldDate, sal_False );
2131 			ImplCalendarSelectDate( mpSelectTable, maCurDate, sal_True );
2132 		}
2133 		else if ( !HasFocus() )
2134 			bUpdate = sal_False;
2135 
2136 		// Aktuelles Datum noch in den sichtbaren Bereich verschieben
2137 		if ( mbFormat || (maCurDate < GetFirstMonth()) )
2138 			SetFirstDate( maCurDate );
2139 		else if ( maCurDate > GetLastMonth() )
2140 		{
2141 			Date aTempDate = GetLastMonth();
2142 			long nDateOff = maCurDate-aTempDate;
2143 			if ( nDateOff < 365 )
2144 			{
2145 				Date aFirstDate = GetFirstMonth();
2146 				aFirstDate += aFirstDate.GetDaysInMonth();
2147 				aTempDate++;
2148 				while ( nDateOff > aTempDate.GetDaysInMonth() )
2149 				{
2150 					aFirstDate += aFirstDate.GetDaysInMonth();
2151 					long nDaysInMonth = aTempDate.GetDaysInMonth();
2152 					aTempDate += nDaysInMonth;
2153 					nDateOff -= nDaysInMonth;
2154 				}
2155 				SetFirstDate( aFirstDate );
2156 			}
2157 			else
2158 				SetFirstDate( maCurDate );
2159 		}
2160 		else
2161 		{
2162 			if ( bUpdate )
2163 			{
2164 				HideFocus();
2165 				ImplUpdateDate( aOldDate );
2166 				ImplUpdateDate( maCurDate );
2167 			}
2168 		}
2169 	}
2170 }
2171 
2172 // -----------------------------------------------------------------------
2173 
2174 void Calendar::SetFirstDate( const Date& rNewFirstDate )
2175 {
2176 	if ( maFirstDate != rNewFirstDate )
2177 	{
2178 		maFirstDate = Date( 1, rNewFirstDate.GetMonth(), rNewFirstDate.GetYear() );
2179 		mbDropPos = sal_False;
2180 		ImplUpdate();
2181 	}
2182 }
2183 
2184 // -----------------------------------------------------------------------
2185 
2186 Date Calendar::GetFirstMonth() const
2187 {
2188 	if ( maFirstDate.GetDay() > 1 )
2189 	{
2190 		if ( maFirstDate.GetMonth() == 12 )
2191 			return Date( 1, 1, maFirstDate.GetYear()+1 );
2192 		else
2193 			return Date( 1, maFirstDate.GetMonth()+1, maFirstDate.GetYear() );
2194 	}
2195 	else
2196 		return maFirstDate;
2197 }
2198 
2199 // -----------------------------------------------------------------------
2200 
2201 Date Calendar::GetLastMonth() const
2202 {
2203 	Date aDate = GetFirstMonth();
2204 	sal_uInt16 nMonthCount = GetMonthCount();
2205 	for ( sal_uInt16 i = 0; i < nMonthCount; i++ )
2206 		aDate += aDate.GetDaysInMonth();
2207 	aDate--;
2208 	return aDate;
2209 }
2210 
2211 // -----------------------------------------------------------------------
2212 
2213 sal_uInt16 Calendar::GetMonthCount() const
2214 {
2215 	if ( mbFormat )
2216 		return 1;
2217 	else
2218 		return (sal_uInt16)(mnMonthPerLine*mnLines);
2219 }
2220 
2221 // -----------------------------------------------------------------------
2222 
2223 sal_Bool Calendar::GetDropDate( Date& rDate ) const
2224 {
2225 	if( mbDropPos )
2226 	{
2227 		rDate = maDropDate;
2228 		return sal_True;
2229 	}
2230 	return sal_False;
2231 }
2232 
2233 // -----------------------------------------------------------------------
2234 
2235 sal_Bool Calendar::GetDate( const Point& rPos, Date& rDate ) const
2236 {
2237 	Date	aDate = maCurDate;
2238 	sal_uInt16	nHitTest = ImplHitTest( rPos, aDate );
2239 	if ( nHitTest & CALENDAR_HITTEST_DAY )
2240 	{
2241 		rDate = aDate;
2242 		return sal_True;
2243 	}
2244 	else
2245 		return sal_False;
2246 }
2247 
2248 // -----------------------------------------------------------------------
2249 
2250 Rectangle Calendar::GetDateRect( const Date& rDate ) const
2251 {
2252 	Rectangle aRect;
2253 
2254 	if ( mbFormat || (rDate < maFirstDate) || (rDate > (maFirstDate+mnDayCount)) )
2255 		return aRect;
2256 
2257 	long	nX;
2258 	long	nY;
2259 	sal_uLong	nDaysOff;
2260 	sal_uInt16	nDayIndex;
2261 	Date	aDate = GetFirstMonth();
2262 
2263 	if ( rDate < aDate )
2264 	{
2265 		aRect = GetDateRect( aDate );
2266 		nDaysOff = aDate-rDate;
2267 		nX = (long)(nDaysOff*mnDayWidth);
2268 		aRect.Left() -= nX;
2269 		aRect.Right() -= nX;
2270 		return aRect;
2271 	}
2272 	else
2273 	{
2274 		Date aLastDate = GetLastMonth();
2275 		if ( rDate > aLastDate )
2276 		{
2277 			sal_uInt16 nWeekDay = (sal_uInt16)aLastDate.GetDayOfWeek();
2278 			nWeekDay = (nWeekDay+(7-(sal_uInt16)ImplGetWeekStart())) % 7;
2279 			aLastDate -= nWeekDay;
2280 			aRect = GetDateRect( aLastDate );
2281 			nDaysOff = rDate-aLastDate;
2282 			nDayIndex = 0;
2283 			for ( sal_uInt16 i = 0; i <= nDaysOff; i++ )
2284 			{
2285 				if ( aLastDate == rDate )
2286 				{
2287 					aRect.Left() += nDayIndex*mnDayWidth;
2288 					aRect.Right() = aRect.Left()+mnDayWidth;
2289 					return aRect;
2290 				}
2291 				if ( nDayIndex == 6 )
2292 				{
2293 					nDayIndex = 0;
2294 					aRect.Top() += mnDayHeight;
2295 					aRect.Bottom() += mnDayHeight;
2296 				}
2297 				else
2298 					nDayIndex++;
2299 				aLastDate++;
2300 			}
2301 		}
2302 	}
2303 
2304 	nY = 0;
2305 	for ( long i = 0; i < mnLines; i++ )
2306 	{
2307 		nX = 0;
2308 		for ( long j = 0; j < mnMonthPerLine; j++ )
2309 		{
2310 			sal_uInt16 nDaysInMonth = aDate.GetDaysInMonth();
2311 
2312 			// Monat gerufen
2313 			if ( (aDate.GetMonth() == rDate.GetMonth()) &&
2314 				 (aDate.GetYear() == rDate.GetYear()) )
2315 			{
2316 				long nDayX = nX+mnDaysOffX;
2317 				long nDayY = nY+mnDaysOffY;
2318 				nDayIndex = (sal_uInt16)aDate.GetDayOfWeek();
2319 				nDayIndex = (nDayIndex+(7-(sal_uInt16)ImplGetWeekStart())) % 7;
2320 				for ( sal_uInt16 nDay = 1; nDay <= nDaysInMonth; nDay++ )
2321 				{
2322 					if ( nDay == rDate.GetDay() )
2323 					{
2324 						aRect.Left()	= nDayX + (nDayIndex*mnDayWidth);
2325 						aRect.Top() 	= nDayY;
2326 						aRect.Right()	= aRect.Left()+mnDayWidth;
2327 						aRect.Bottom()	= aRect.Top()+mnDayHeight;
2328 						break;
2329 					}
2330 					if ( nDayIndex == 6 )
2331 					{
2332 						nDayIndex = 0;
2333 						nDayY += mnDayHeight;
2334 					}
2335 					else
2336 						nDayIndex++;
2337 				}
2338 			}
2339 
2340 			aDate += nDaysInMonth;
2341 			nX += mnMonthWidth;
2342 		}
2343 
2344 		nY += mnMonthHeight;
2345 	}
2346 
2347 	return aRect;
2348 }
2349 
2350 // -----------------------------------------------------------------------
2351 
2352 void Calendar::SetStandardColor( const Color& rColor )
2353 {
2354 	if ( mpStandardColor )
2355 		*mpStandardColor = rColor;
2356 	else
2357 		mpStandardColor = new Color( rColor );
2358 	ImplUpdate();
2359 }
2360 
2361 // -----------------------------------------------------------------------
2362 
2363 void Calendar::SetSaturdayColor( const Color& rColor )
2364 {
2365 	if ( mpSaturdayColor )
2366 		*mpSaturdayColor = rColor;
2367 	else
2368 		mpSaturdayColor = new Color( rColor );
2369 	ImplUpdate();
2370 }
2371 
2372 // -----------------------------------------------------------------------
2373 
2374 void Calendar::SetSundayColor( const Color& rColor )
2375 {
2376 	if ( mpSundayColor )
2377 		*mpSundayColor = rColor;
2378 	else
2379 		mpSundayColor = new Color( rColor );
2380 	ImplUpdate();
2381 }
2382 
2383 // -----------------------------------------------------------------------
2384 
2385 void Calendar::AddDateInfo( const Date& rDate, const String& rText,
2386 							const Color* pTextColor, const Color* pFrameColor,
2387 							sal_uInt16 nFlags )
2388 {
2389 	if ( !mpDateTable )
2390 		mpDateTable = new ImplDateTable( 256, 256 );
2391 
2392 	sal_Bool			bChanged = sal_False;
2393 	sal_uLong			nKey = rDate.GetDate();
2394 	ImplDateInfo*	pDateInfo = mpDateTable->Get( nKey );
2395 	if ( pDateInfo )
2396 		pDateInfo->maText = rText;
2397 	else
2398 	{
2399 		pDateInfo = new ImplDateInfo( rText );
2400 		mpDateTable->Insert( nKey, pDateInfo );
2401 	}
2402 	if ( pTextColor )
2403 	{
2404 		if ( pDateInfo->mpTextColor )
2405 		{
2406 			if ( *(pDateInfo->mpTextColor) != *pTextColor )
2407 			{
2408 				*(pDateInfo->mpTextColor) = *pTextColor;
2409 				bChanged = sal_True;
2410 			}
2411 		}
2412 		else
2413 		{
2414 			pDateInfo->mpTextColor = new Color( *pTextColor );
2415 			bChanged = sal_True;
2416 		}
2417 	}
2418 	else
2419 	{
2420 		if ( pDateInfo->mpTextColor )
2421 		{
2422 			delete pDateInfo->mpTextColor;
2423 			pDateInfo->mpTextColor = NULL;
2424 			bChanged = sal_True;
2425 		}
2426 	}
2427 	if ( pFrameColor )
2428 	{
2429 		if ( pDateInfo->mpFrameColor )
2430 		{
2431 			if ( *(pDateInfo->mpFrameColor) != *pFrameColor )
2432 			{
2433 				*(pDateInfo->mpFrameColor) = *pFrameColor;
2434 				bChanged = sal_True;
2435 			}
2436 		}
2437 		else
2438 		{
2439 			pDateInfo->mpFrameColor = new Color( *pFrameColor );
2440 			bChanged = sal_True;
2441 		}
2442 	}
2443 	else
2444 	{
2445 		if ( pDateInfo->mpFrameColor )
2446 		{
2447 			delete pDateInfo->mpFrameColor;
2448 			pDateInfo->mpFrameColor = NULL;
2449 			bChanged = sal_True;
2450 		}
2451 	}
2452 	if ( pDateInfo->mnFlags != nFlags )
2453 	{
2454 		pDateInfo->mnFlags = nFlags;
2455 		bChanged = sal_True;
2456 	}
2457 
2458 	if ( bChanged )
2459 		ImplUpdateDate( rDate );
2460 }
2461 
2462 // -----------------------------------------------------------------------
2463 
2464 void Calendar::RemoveDateInfo( const Date& rDate )
2465 {
2466 	if ( mpDateTable )
2467 	{
2468 		ImplDateInfo* pDateInfo = mpDateTable->Remove( rDate.GetDate() );
2469 		if ( pDateInfo )
2470 		{
2471 			delete pDateInfo;
2472 			ImplUpdateDate( rDate );
2473 		}
2474 	}
2475 }
2476 
2477 // -----------------------------------------------------------------------
2478 
2479 void Calendar::ClearDateInfo()
2480 {
2481 	if ( mpDateTable )
2482 	{
2483 		ImplDateInfo* pDateInfo = mpDateTable->First();
2484 		while ( pDateInfo )
2485 		{
2486 			sal_uLong nKey = mpDateTable->GetCurKey();
2487 			mpDateTable->Remove( nKey );
2488 			Date aDate( nKey );
2489 			ImplUpdateDate( aDate );
2490 			delete pDateInfo;
2491 			pDateInfo = mpDateTable->First();
2492 		}
2493 		delete mpDateTable;
2494 		mpDateTable = NULL;
2495 	}
2496 }
2497 
2498 // -----------------------------------------------------------------------
2499 
2500 XubString Calendar::GetDateInfoText( const Date& rDate )
2501 {
2502 	XubString aRet;
2503 	if ( mpDateTable )
2504 	{
2505 		sal_uLong			nKey = rDate.GetDate();
2506 		ImplDateInfo*	pDateInfo = mpDateTable->Get( nKey );
2507 		if ( pDateInfo )
2508 			aRet = pDateInfo->maText;
2509 	}
2510 	return aRet;
2511 }
2512 
2513 // -----------------------------------------------------------------------
2514 
2515 sal_Bool Calendar::ShowDropPos( const Point& rPos, Date& rDate )
2516 {
2517 	Date	aTempDate = maCurDate;
2518 	mnDragScrollHitTest = ImplHitTest( rPos, aTempDate );
2519 
2520 	if ( mnDragScrollHitTest )
2521 	{
2522 		if ( mnDragScrollHitTest & (CALENDAR_HITTEST_PREV | CALENDAR_HITTEST_NEXT) )
2523 		{
2524 			if ( !maDragScrollTimer.IsActive() )
2525 				maDragScrollTimer.Start();
2526 		}
2527 		else
2528 		{
2529 			maDragScrollTimer.Stop();
2530 			if ( mnDragScrollHitTest & CALENDAR_HITTEST_DAY )
2531 			{
2532 				if ( !mbDropPos || (aTempDate != maDropDate) )
2533 				{
2534 					if( mbDropPos )
2535 						ImplInvertDropPos();
2536 					maDropDate = aTempDate;
2537 					mbDropPos = sal_True;
2538 					ImplInvertDropPos();
2539 				}
2540 
2541 				rDate = maDropDate;
2542 				return sal_True;
2543 			}
2544 		}
2545 	}
2546 	else
2547 		maDragScrollTimer.Stop();
2548 
2549 	HideDropPos();
2550 	return sal_False;
2551 }
2552 
2553 // -----------------------------------------------------------------------
2554 
2555 void Calendar::HideDropPos()
2556 {
2557 	if ( mbDropPos )
2558 	{
2559 		ImplInvertDropPos();
2560 		mbDropPos = sal_False;
2561 	}
2562 }
2563 
2564 // -----------------------------------------------------------------------
2565 
2566 void Calendar::StartSelection()
2567 {
2568 	if ( mpOldSelectTable )
2569 		delete mpOldSelectTable;
2570 	maOldCurDate = maCurDate;
2571 	mpOldSelectTable = new Table( *mpSelectTable );
2572 
2573 	mbSelection = sal_True;
2574 }
2575 
2576 // -----------------------------------------------------------------------
2577 
2578 void Calendar::EndSelection()
2579 {
2580 	if ( mbDrag || mbSpinDown || mbSelection )
2581 	{
2582 		if ( !mbSelection )
2583 			ReleaseMouse();
2584 
2585 		mbDrag				= sal_False;
2586 		mbSelection 		= sal_False;
2587 		mbMultiSelection	= sal_False;
2588 		mbSpinDown			= sal_False;
2589 		mbPrevIn			= sal_False;
2590 		mbNextIn			= sal_False;
2591 	}
2592 }
2593 
2594 // -----------------------------------------------------------------------
2595 
2596 Size Calendar::CalcWindowSizePixel( long nCalcMonthPerLine,
2597 									long nCalcLines ) const
2598 {
2599 	XubString	a99Text( XubString( RTL_CONSTASCII_USTRINGPARAM( "99" ) ) );
2600 	Font		aOldFont = GetFont();
2601 
2602 	// Wochenanzeige beruecksichtigen
2603 	long nWeekWidth;
2604 	if ( mnWinStyle & WB_WEEKNUMBER )
2605 	{
2606 		Font aTempFont = aOldFont;
2607 		ImplGetWeekFont( aTempFont );
2608 		((Calendar*)this)->SetFont( aTempFont );
2609 		nWeekWidth = GetTextWidth( a99Text )+WEEKNUMBER_OFFX;
2610 		((Calendar*)this)->SetFont( aOldFont );
2611 	}
2612 	else
2613 		nWeekWidth = 0;
2614 
2615 	if ( mnWinStyle & WB_BOLDTEXT )
2616 	{
2617 		Font aFont = aOldFont;
2618 		if ( aFont.GetWeight() < WEIGHT_BOLD )
2619 			aFont.SetWeight( WEIGHT_BOLD );
2620 		else
2621 			aFont.SetWeight( WEIGHT_NORMAL );
2622 		((Calendar*)this)->SetFont( aFont );
2623 	}
2624 
2625 	Size	aSize;
2626 	long	n99TextWidth = GetTextWidth( a99Text );
2627 	long	nTextHeight = GetTextHeight();
2628 
2629 	if ( mnWinStyle & WB_BOLDTEXT )
2630 		((Calendar*)this)->SetFont( aOldFont );
2631 
2632 	aSize.Width()  += ((n99TextWidth+DAY_OFFX)*7) + nWeekWidth;
2633 	aSize.Width()  += MONTH_BORDERX*2;
2634 	aSize.Width()  *= nCalcMonthPerLine;
2635 
2636 	aSize.Height()	= nTextHeight + TITLE_OFFY + (TITLE_BORDERY*2);
2637 	aSize.Height() += nTextHeight + WEEKDAY_OFFY;
2638 	aSize.Height() += ((nTextHeight+DAY_OFFY)*6);
2639 	aSize.Height() += MONTH_OFFY;
2640 	aSize.Height() *= nCalcLines;
2641 
2642 	return aSize;
2643 }
2644 
2645 // =======================================================================
2646 
2647 #define CALFIELD_EXTRA_BUTTON_WIDTH 		14
2648 #define CALFIELD_EXTRA_BUTTON_HEIGHT		8
2649 #define CALFIELD_SEP_X						6
2650 #define CALFIELD_BORDERLINE_X				5
2651 #define CALFIELD_BORDER_YTOP				4
2652 #define CALFIELD_BORDER_Y					5
2653 
2654 // =======================================================================
2655 
2656 class ImplCFieldFloatWin : public FloatingWindow
2657 {
2658 private:
2659 	Calendar*		mpCalendar;
2660 	PushButton* 	mpTodayBtn;
2661 	PushButton* 	mpNoneBtn;
2662 	FixedLine*		mpFixedLine;
2663 
2664 public:
2665 					ImplCFieldFloatWin( Window* pParent );
2666 					~ImplCFieldFloatWin();
2667 
2668 	void			SetCalendar( Calendar* pCalendar )
2669 						{ mpCalendar = pCalendar; }
2670 
2671 	PushButton* 	EnableTodayBtn( sal_Bool bEnable );
2672 	PushButton* 	EnableNoneBtn( sal_Bool bEnable );
2673 	void			ArrangeButtons();
2674 
2675 	long			Notify( NotifyEvent& rNEvt );
2676 };
2677 
2678 // -----------------------------------------------------------------------
2679 
2680 ImplCFieldFloatWin::ImplCFieldFloatWin( Window* pParent ) :
2681 	FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW | WB_NOSHADOW  )
2682 {
2683 	mpCalendar	= NULL;
2684 	mpTodayBtn	= NULL;
2685 	mpNoneBtn	= NULL;
2686 	mpFixedLine = NULL;
2687 }
2688 
2689 // -----------------------------------------------------------------------
2690 
2691 ImplCFieldFloatWin::~ImplCFieldFloatWin()
2692 {
2693 	delete mpTodayBtn;
2694 	delete mpNoneBtn;
2695 	delete mpFixedLine;
2696 }
2697 
2698 // -----------------------------------------------------------------------
2699 
2700 PushButton* ImplCFieldFloatWin::EnableTodayBtn( sal_Bool bEnable )
2701 {
2702 	if ( bEnable )
2703 	{
2704 		if ( !mpTodayBtn )
2705 		{
2706 			mpTodayBtn = new PushButton( this, WB_NOPOINTERFOCUS );
2707 			XubString aTodayText( SvtResId( STR_SVT_CALENDAR_TODAY ) );
2708 			mpTodayBtn->SetText( aTodayText );
2709 			Size aSize;
2710 			aSize.Width()	= mpTodayBtn->GetCtrlTextWidth( mpTodayBtn->GetText() );
2711 			aSize.Height()	= mpTodayBtn->GetTextHeight();
2712 			aSize.Width()  += CALFIELD_EXTRA_BUTTON_WIDTH;
2713 			aSize.Height() += CALFIELD_EXTRA_BUTTON_HEIGHT;
2714 			mpTodayBtn->SetSizePixel( aSize );
2715 			mpTodayBtn->Show();
2716 		}
2717 	}
2718 	else
2719 	{
2720 		if ( mpTodayBtn )
2721 		{
2722 			delete mpTodayBtn;
2723 			mpTodayBtn = NULL;
2724 		}
2725 	}
2726 
2727 	return mpTodayBtn;
2728 }
2729 
2730 // -----------------------------------------------------------------------
2731 
2732 PushButton* ImplCFieldFloatWin::EnableNoneBtn( sal_Bool bEnable )
2733 {
2734 	if ( bEnable )
2735 	{
2736 		if ( !mpNoneBtn )
2737 		{
2738 			mpNoneBtn = new PushButton( this, WB_NOPOINTERFOCUS );
2739 			XubString aNoneText( SvtResId( STR_SVT_CALENDAR_NONE ) );
2740 			mpNoneBtn->SetText( aNoneText );
2741 			Size aSize;
2742 			aSize.Width()	= mpNoneBtn->GetCtrlTextWidth( mpNoneBtn->GetText() );
2743 			aSize.Height()	= mpNoneBtn->GetTextHeight();
2744 			aSize.Width()  += CALFIELD_EXTRA_BUTTON_WIDTH;
2745 			aSize.Height() += CALFIELD_EXTRA_BUTTON_HEIGHT;
2746 			mpNoneBtn->SetSizePixel( aSize );
2747 			mpNoneBtn->Show();
2748 		}
2749 	}
2750 	else
2751 	{
2752 		if ( mpNoneBtn )
2753 		{
2754 			delete mpNoneBtn;
2755 			mpNoneBtn = NULL;
2756 		}
2757 	}
2758 
2759 	return mpNoneBtn;
2760 }
2761 
2762 // -----------------------------------------------------------------------
2763 
2764 void ImplCFieldFloatWin::ArrangeButtons()
2765 {
2766 	long nBtnHeight = 0;
2767 	long nBtnWidth	= 0;
2768 	Size aOutSize	= GetOutputSizePixel();
2769 	if ( mpTodayBtn && mpNoneBtn )
2770 	{
2771 		Size aTodayBtnSize = mpTodayBtn->GetSizePixel();
2772 		Size aNoneBtnSize  = mpNoneBtn->GetSizePixel();
2773 		if ( aTodayBtnSize.Width() < aNoneBtnSize.Width() )
2774 			aTodayBtnSize.Width() = aNoneBtnSize.Width();
2775 		else
2776 			aNoneBtnSize.Width() = aTodayBtnSize.Width();
2777 		if ( aTodayBtnSize.Height() < aNoneBtnSize.Height() )
2778 			aTodayBtnSize.Height() = aNoneBtnSize.Height();
2779 		else
2780 			aNoneBtnSize.Height() = aTodayBtnSize.Height();
2781 
2782 		nBtnWidth  = aTodayBtnSize.Width() + aNoneBtnSize.Width() + CALFIELD_SEP_X;
2783 		nBtnHeight = aTodayBtnSize.Height();
2784 		long nX = (aOutSize.Width()-nBtnWidth)/2;
2785 		long nY = aOutSize.Height()+CALFIELD_BORDER_Y+CALFIELD_BORDER_YTOP;
2786 		mpTodayBtn->SetPosSizePixel( Point( nX, nY ), aTodayBtnSize );
2787 		nX += aTodayBtnSize.Width() + CALFIELD_SEP_X;
2788 		mpNoneBtn->SetPosSizePixel( Point( nX, nY ), aNoneBtnSize );
2789 	}
2790 	else if ( mpTodayBtn )
2791 	{
2792 		Size aTodayBtnSize = mpTodayBtn->GetSizePixel();
2793 		nBtnWidth  = aTodayBtnSize.Width();
2794 		nBtnHeight = aTodayBtnSize.Height();
2795 		mpTodayBtn->SetPosPixel( Point( (aOutSize.Width()-nBtnWidth)/2, aOutSize.Height()+CALFIELD_BORDER_Y+CALFIELD_BORDER_YTOP ) );
2796 	}
2797 	else if ( mpNoneBtn )
2798 	{
2799 		Size aNoneBtnSize  = mpNoneBtn->GetSizePixel();
2800 		nBtnWidth  = aNoneBtnSize.Width();
2801 		nBtnHeight = aNoneBtnSize.Height();
2802 		mpNoneBtn->SetPosPixel( Point( (aOutSize.Width()-nBtnWidth)/2, aOutSize.Height()+CALFIELD_BORDER_Y+CALFIELD_BORDER_YTOP ) );
2803 	}
2804 
2805 	if ( nBtnHeight )
2806 	{
2807 		if ( !mpFixedLine )
2808 		{
2809 			mpFixedLine = new FixedLine( this );
2810 			mpFixedLine->Show();
2811 		}
2812 		long nLineWidth = aOutSize.Width()-(CALFIELD_BORDERLINE_X*2);
2813 		mpFixedLine->SetPosSizePixel( (aOutSize.Width()-nLineWidth)/2, aOutSize.Height()+((CALFIELD_BORDER_YTOP-2)/2),
2814 									  nLineWidth, 2, WINDOW_POSSIZE_POSSIZE );
2815 		aOutSize.Height() += nBtnHeight + (CALFIELD_BORDER_Y*2) + CALFIELD_BORDER_YTOP;
2816 		SetOutputSizePixel( aOutSize );
2817 	}
2818 	else
2819 	{
2820 		if ( mpFixedLine )
2821 		{
2822 			delete mpFixedLine;
2823 			mpFixedLine = NULL;
2824 		}
2825 	}
2826 }
2827 
2828 // -----------------------------------------------------------------------
2829 
2830 long ImplCFieldFloatWin::Notify( NotifyEvent& rNEvt )
2831 {
2832 	if ( rNEvt.GetType() == EVENT_KEYINPUT )
2833 	{
2834 		const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
2835 		if ( pKEvt->GetKeyCode().GetCode() == KEY_RETURN )
2836 			mpCalendar->Select();
2837 	}
2838 
2839 	return FloatingWindow::Notify( rNEvt );
2840 }
2841 
2842 // =======================================================================
2843 
2844 CalendarField::CalendarField( Window* pParent, WinBits nWinStyle ) :
2845 	DateField( pParent, nWinStyle ),
2846 	maDefaultDate( 0, 0, 0 )
2847 {
2848 	mpFloatWin		= NULL;
2849 	mpCalendar		= NULL;
2850 	mnCalendarStyle = 0;
2851 	mbToday 		= sal_False;
2852 	mbNone			= sal_False;
2853 }
2854 
2855 // -----------------------------------------------------------------------
2856 
2857 CalendarField::CalendarField( Window* pParent, const ResId& rResId ) :
2858 	DateField( pParent, rResId ),
2859 	maDefaultDate( 0, 0, 0 )
2860 {
2861 	mpFloatWin		= NULL;
2862 	mpCalendar		= NULL;
2863 	mnCalendarStyle = 0;
2864 	mbToday 		= sal_False;
2865 	mbNone			= sal_False;
2866 }
2867 
2868 // -----------------------------------------------------------------------
2869 
2870 CalendarField::~CalendarField()
2871 {
2872 	if ( mpFloatWin )
2873 	{
2874 		delete mpCalendar;
2875 		delete mpFloatWin;
2876 	}
2877 }
2878 
2879 // -----------------------------------------------------------------------
2880 
2881 IMPL_LINK( CalendarField, ImplSelectHdl, Calendar*, pCalendar )
2882 {
2883 	if ( !pCalendar->IsTravelSelect() )
2884 	{
2885 		mpFloatWin->EndPopupMode();
2886 		EndDropDown();
2887 		GrabFocus();
2888 		Date aNewDate = mpCalendar->GetSelectDate( 0 );
2889 		if ( IsEmptyDate() || ( aNewDate != GetDate() ) )
2890 		{
2891 			SetDate( aNewDate );
2892 			SetModifyFlag();
2893 			Modify();
2894 		}
2895 		Select();
2896 	}
2897 	return 0;
2898 }
2899 
2900 // -----------------------------------------------------------------------
2901 
2902 IMPL_LINK( CalendarField, ImplClickHdl, PushButton*, pBtn )
2903 {
2904 	mpFloatWin->EndPopupMode();
2905 	EndDropDown();
2906 	GrabFocus();
2907 
2908 	if ( pBtn == mpTodayBtn )
2909 	{
2910 		Date aToday;
2911 		if ( (aToday != GetDate()) || IsEmptyDate() )
2912 		{
2913 			SetDate( aToday );
2914 			SetModifyFlag();
2915 			Modify();
2916 		}
2917 	}
2918 	else if ( pBtn == mpNoneBtn )
2919 	{
2920 		if ( !IsEmptyDate() )
2921 		{
2922 			SetEmptyDate();
2923 			SetModifyFlag();
2924 			Modify();
2925 		}
2926 	}
2927 	Select();
2928 
2929 	return 0;
2930 }
2931 
2932 // -----------------------------------------------------------------------
2933 
2934 IMPL_LINK( CalendarField, ImplPopupModeEndHdl, FloatingWindow*, EMPTYARG )
2935 {
2936 	EndDropDown();
2937 	GrabFocus();
2938 	mpCalendar->EndSelection();
2939 	return 0;
2940 }
2941 
2942 // -----------------------------------------------------------------------
2943 
2944 void CalendarField::Select()
2945 {
2946 	maSelectHdl.Call( this );
2947 }
2948 
2949 // -----------------------------------------------------------------------
2950 
2951 sal_Bool CalendarField::ShowDropDown( sal_Bool bShow )
2952 {
2953 	if ( bShow )
2954 	{
2955 		Calendar* pCalendar = GetCalendar();
2956 
2957 		Date aDate = GetDate();
2958 		if ( IsEmptyDate() || !aDate.IsValid() )
2959 		{
2960 			if ( maDefaultDate.IsValid() )
2961 				aDate = maDefaultDate;
2962 			else
2963 				aDate = Date();
2964 		}
2965 		if ( pCalendar->GetStyle() & (WB_RANGESELECT | WB_MULTISELECT) )
2966 		{
2967 			pCalendar->SetNoSelection();
2968 			pCalendar->SelectDate( aDate );
2969 		}
2970 		pCalendar->SetCurDate( aDate );
2971 		Point		aPos( GetParent()->OutputToScreenPixel( GetPosPixel() ) );
2972 		Rectangle	aRect( aPos, GetSizePixel() );
2973 		aRect.Bottom() -= 1;
2974 		mpCalendar->SetOutputSizePixel( mpCalendar->CalcWindowSizePixel() );
2975 		mpFloatWin->SetOutputSizePixel( mpCalendar->GetSizePixel() );
2976 		mpFloatWin->SetCalendar( mpCalendar );
2977 		mpTodayBtn = mpFloatWin->EnableTodayBtn( mbToday );
2978 		mpNoneBtn = mpFloatWin->EnableNoneBtn( mbNone );
2979 		if ( mpTodayBtn )
2980 			mpTodayBtn->SetClickHdl( LINK( this, CalendarField, ImplClickHdl ) );
2981 		if ( mpNoneBtn )
2982 			mpNoneBtn->SetClickHdl( LINK( this, CalendarField, ImplClickHdl ) );
2983 		mpFloatWin->ArrangeButtons();
2984 		mpCalendar->EnableCallEverySelect();
2985 		mpCalendar->StartSelection();
2986 		mpCalendar->GrabFocus();
2987 		mpCalendar->Show();
2988 		mpFloatWin->StartPopupMode( aRect, FLOATWIN_POPUPMODE_NOFOCUSCLOSE|FLOATWIN_POPUPMODE_DOWN );
2989 	}
2990 	else
2991 	{
2992 		mpFloatWin->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL );
2993 		mpCalendar->EndSelection();
2994 		EndDropDown();
2995 	}
2996 	return sal_True;
2997 }
2998 
2999 // -----------------------------------------------------------------------
3000 
3001 Calendar* CalendarField::CreateCalendar( Window* pParent )
3002 {
3003 	return new Calendar( pParent, mnCalendarStyle | WB_TABSTOP );
3004 }
3005 
3006 // -----------------------------------------------------------------------
3007 
3008 Calendar* CalendarField::GetCalendar()
3009 {
3010 	if ( !mpFloatWin )
3011 	{
3012 		mpFloatWin = new ImplCFieldFloatWin( this );
3013 		mpFloatWin->SetPopupModeEndHdl( LINK( this, CalendarField, ImplPopupModeEndHdl ) );
3014 		mpCalendar = CreateCalendar( mpFloatWin );
3015 		mpCalendar->SetPosPixel( Point() );
3016 		mpCalendar->SetSelectHdl( LINK( this, CalendarField, ImplSelectHdl ) );
3017 	}
3018 
3019 	return mpCalendar;
3020 }
3021 
3022 // -----------------------------------------------------------------------
3023 
3024 void CalendarField::StateChanged( StateChangedType nStateChange )
3025 {
3026 	DateField::StateChanged( nStateChange );
3027 
3028 	if ( ( nStateChange == STATE_CHANGE_STYLE ) && GetSubEdit() )
3029 	{
3030         WinBits nAllAlignmentBits = ( WB_LEFT | WB_CENTER | WB_RIGHT | WB_TOP | WB_VCENTER | WB_BOTTOM );
3031         WinBits nMyAlignment = GetStyle() & nAllAlignmentBits;
3032         GetSubEdit()->SetStyle( ( GetSubEdit()->GetStyle() & ~nAllAlignmentBits ) | nMyAlignment );
3033 	}
3034 }
3035 
3036