xref: /trunk/main/svtools/source/control/calendar.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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