bump product version to 6.4.0.3
[LibreOffice.git] / vcl / source / control / calendar.cxx
blob22d3d9f56ab3fd74fe56ae6a8422b67e59bab5cd
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/svapp.hxx>
21 #include <vcl/help.hxx>
22 #include <vcl/menu.hxx>
23 #include <vcl/settings.hxx>
24 #include <vcl/event.hxx>
25 #include <vcl/commandevent.hxx>
26 #include <unotools/calendarwrapper.hxx>
27 #include <unotools/localedatawrapper.hxx>
28 #include <com/sun/star/i18n/Weekdays.hpp>
29 #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
30 #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
31 #include <sal/log.hxx>
33 #include <vcl/calendar.hxx>
34 #include <svdata.hxx>
35 #include <strings.hrc>
36 #include <memory>
38 #define DAY_OFFX 4
39 #define DAY_OFFY 2
40 #define MONTH_BORDERX 4
41 #define MONTH_OFFY 3
42 #define WEEKDAY_OFFY 3
43 #define TITLE_OFFY 3
44 #define TITLE_BORDERY 2
45 #define SPIN_OFFX 4
46 #define SPIN_OFFY TITLE_BORDERY
48 #define CALENDAR_HITTEST_DAY (sal_uInt16(0x0001))
49 #define CALENDAR_HITTEST_MONTHTITLE (sal_uInt16(0x0004))
50 #define CALENDAR_HITTEST_PREV (sal_uInt16(0x0008))
51 #define CALENDAR_HITTEST_NEXT (sal_uInt16(0x0010))
53 #define MENU_YEAR_COUNT 3
55 using namespace ::com::sun::star;
57 static void ImplCalendarSelectDate( IntDateSet* pTable, const Date& rDate, bool bSelect )
59 if ( bSelect )
60 pTable->insert( rDate.GetDate() );
61 else
62 pTable->erase( rDate.GetDate() );
67 void Calendar::ImplInit( WinBits nWinStyle )
69 mpSelectTable.reset(new IntDateSet);
70 mnDayCount = 0;
71 mnWinStyle = nWinStyle;
72 mnFirstYear = 0;
73 mnLastYear = 0;
74 mbCalc = true;
75 mbFormat = true;
76 mbDrag = false;
77 mbSelection = false;
78 mbMenuDown = false;
79 mbSpinDown = false;
80 mbPrevIn = false;
81 mbNextIn = false;
82 mbTravelSelect = false;
83 mbAllSel = false;
85 OUString aGregorian( "gregorian");
86 maCalendarWrapper.loadCalendar( aGregorian,
87 Application::GetAppLocaleDataWrapper().getLanguageTag().getLocale());
88 if (maCalendarWrapper.getUniqueID() != aGregorian)
90 SAL_WARN( "vcl.control", "Calendar::ImplInit: No ``gregorian'' calendar available for locale ``"
91 << Application::GetAppLocaleDataWrapper().getLanguageTag().getBcp47()
92 << "'' and other calendars aren't supported. Using en-US fallback." );
94 /* If we ever wanted to support other calendars than Gregorian a lot of
95 * rewrite would be necessary to internally replace use of class Date
96 * with proper class CalendarWrapper methods, get rid of fixed 12
97 * months, fixed 7 days, ... */
98 maCalendarWrapper.loadCalendar( aGregorian, lang::Locale( "en", "US", ""));
101 SetFirstDate( maCurDate );
102 ImplCalendarSelectDate( mpSelectTable.get(), maCurDate, true );
104 // Sonstige Strings erzeugen
105 maDayText = VclResId(STR_SVT_CALENDAR_DAY);
106 maWeekText = VclResId(STR_SVT_CALENDAR_WEEK);
108 // Tagestexte anlegen
109 for (sal_Int32 i = 0; i < 31; ++i)
110 maDayTexts[i] = OUString::number(i+1);
112 ImplInitSettings();
115 void Calendar::ApplySettings(vcl::RenderContext& rRenderContext)
117 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
118 maSelColor = rStyleSettings.GetHighlightTextColor();
119 SetPointFont(rRenderContext, rStyleSettings.GetToolFont());
120 rRenderContext.SetTextColor(rStyleSettings.GetFieldTextColor());
121 rRenderContext.SetBackground(Wallpaper(rStyleSettings.GetFieldColor()));
124 void Calendar::ImplInitSettings()
126 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
127 maSelColor = rStyleSettings.GetHighlightTextColor();
128 SetPointFont(*this, rStyleSettings.GetToolFont());
129 SetTextColor(rStyleSettings.GetFieldTextColor());
130 SetBackground(Wallpaper(rStyleSettings.GetFieldColor()));
133 Calendar::Calendar( vcl::Window* pParent, WinBits nWinStyle ) :
134 Control( pParent, nWinStyle & (WB_TABSTOP | WB_GROUP | WB_BORDER | WB_3DLOOK) ),
135 maCalendarWrapper( Application::GetAppLocaleDataWrapper().getComponentContext() ),
136 maOldFormatFirstDate( 0, 0, 1900 ),
137 maOldFormatLastDate( 0, 0, 1900 ),
138 maFirstDate( 0, 0, 1900 ),
139 maOldFirstDate( 0, 0, 1900 ),
140 maCurDate( Date::SYSTEM ),
141 maOldCurDate( 0, 0, 1900 )
143 ImplInit( nWinStyle );
146 Calendar::~Calendar()
148 disposeOnce();
151 void Calendar::dispose()
153 mpSelectTable.reset();
154 mpOldSelectTable.reset();
155 Control::dispose();
158 DayOfWeek Calendar::ImplGetWeekStart() const
160 // Map i18n::Weekdays to Date DayOfWeek
161 DayOfWeek eDay;
162 sal_Int16 nDay = maCalendarWrapper.getFirstDayOfWeek();
163 switch (nDay)
165 case i18n::Weekdays::SUNDAY :
166 eDay = SUNDAY;
167 break;
168 case i18n::Weekdays::MONDAY :
169 eDay = MONDAY;
170 break;
171 case i18n::Weekdays::TUESDAY :
172 eDay = TUESDAY;
173 break;
174 case i18n::Weekdays::WEDNESDAY :
175 eDay = WEDNESDAY;
176 break;
177 case i18n::Weekdays::THURSDAY :
178 eDay = THURSDAY;
179 break;
180 case i18n::Weekdays::FRIDAY :
181 eDay = FRIDAY;
182 break;
183 case i18n::Weekdays::SATURDAY :
184 eDay = SATURDAY;
185 break;
186 default:
187 SAL_WARN( "vcl.control", "Calendar::ImplGetWeekStart: broken i18n Gregorian calendar (getFirstDayOfWeek())");
188 eDay = SUNDAY;
190 return eDay;
193 void Calendar::ImplFormat()
195 if ( !mbFormat )
196 return;
198 if ( mbCalc )
200 Size aOutSize = GetOutputSizePixel();
202 if ( (aOutSize.Width() <= 1) || (aOutSize.Height() <= 1) )
203 return;
205 OUString const a99Text("99");
207 vcl::Font aOldFont = GetFont();
209 long n99TextWidth = GetTextWidth( a99Text );
210 long nTextHeight = GetTextHeight();
212 // calculate width and x-position
213 mnDayWidth = n99TextWidth+DAY_OFFX;
214 mnMonthWidth = mnDayWidth*7;
215 mnMonthWidth += MONTH_BORDERX*2;
216 mnMonthPerLine = aOutSize.Width() / mnMonthWidth;
217 if ( !mnMonthPerLine )
218 mnMonthPerLine = 1;
219 long nOver = (aOutSize.Width()-(mnMonthPerLine*mnMonthWidth)) / mnMonthPerLine;
220 mnMonthWidth += nOver;
221 mnDaysOffX = MONTH_BORDERX;
222 mnDaysOffX += nOver/2;
224 // calculate height and y-position
225 mnDayHeight = nTextHeight + DAY_OFFY;
226 mnWeekDayOffY = nTextHeight + TITLE_OFFY + (TITLE_BORDERY*2);
227 mnDaysOffY = mnWeekDayOffY + nTextHeight + WEEKDAY_OFFY;
228 mnMonthHeight = (mnDayHeight*6) + mnDaysOffY;
229 mnMonthHeight += MONTH_OFFY;
230 mnLines = aOutSize.Height() / mnMonthHeight;
231 if ( !mnLines )
232 mnLines = 1;
233 mnMonthHeight += (aOutSize.Height()-(mnLines*mnMonthHeight)) / mnLines;
235 // calculate spinfields
236 long nSpinSize = nTextHeight+TITLE_BORDERY-SPIN_OFFY;
237 maPrevRect.SetLeft( SPIN_OFFX );
238 maPrevRect.SetTop( SPIN_OFFY );
239 maPrevRect.SetRight( maPrevRect.Left()+nSpinSize );
240 maPrevRect.SetBottom( maPrevRect.Top()+nSpinSize );
241 maNextRect.SetLeft( aOutSize.Width()-SPIN_OFFX-nSpinSize-1 );
242 maNextRect.SetTop( SPIN_OFFY );
243 maNextRect.SetRight( maNextRect.Left()+nSpinSize );
244 maNextRect.SetBottom( maNextRect.Top()+nSpinSize );
246 // Calculate DayOfWeekText (gets displayed in a narrow font)
247 maDayOfWeekText.clear();
248 long nStartOffX = 0;
249 sal_Int16 nDay = maCalendarWrapper.getFirstDayOfWeek();
250 for ( sal_Int16 nDayOfWeek = 0; nDayOfWeek < 7; nDayOfWeek++ )
252 // Use narrow name.
253 OUString aDayOfWeek( maCalendarWrapper.getDisplayName(
254 i18n::CalendarDisplayIndex::DAY, nDay, 2));
255 long nOffX = (mnDayWidth-GetTextWidth( aDayOfWeek ))/2;
256 if ( !nDayOfWeek )
257 nStartOffX = nOffX;
258 else
259 nOffX -= nStartOffX;
260 nOffX += nDayOfWeek * mnDayWidth;
261 mnDayOfWeekAry[nDayOfWeek] = nOffX;
262 maDayOfWeekText += aDayOfWeek;
263 nDay++;
264 nDay %= 7;
267 mbCalc = false;
270 // calculate number of days
272 DayOfWeek eStartDay = ImplGetWeekStart();
274 sal_uInt16 nWeekDay;
275 Date aTempDate = GetFirstMonth();
276 maFirstDate = aTempDate;
277 nWeekDay = static_cast<sal_uInt16>(aTempDate.GetDayOfWeek());
278 nWeekDay = (nWeekDay+(7-static_cast<sal_uInt16>(eStartDay))) % 7;
279 maFirstDate.AddDays( -nWeekDay );
280 mnDayCount = nWeekDay;
281 sal_uInt16 nDaysInMonth;
282 sal_uInt16 nMonthCount = static_cast<sal_uInt16>(mnMonthPerLine*mnLines);
283 for ( sal_uInt16 i = 0; i < nMonthCount; i++ )
285 nDaysInMonth = aTempDate.GetDaysInMonth();
286 mnDayCount += nDaysInMonth;
287 aTempDate.AddDays( nDaysInMonth );
289 Date aTempDate2 = aTempDate;
290 --aTempDate2;
291 nDaysInMonth = aTempDate2.GetDaysInMonth();
292 aTempDate2.AddDays( -(nDaysInMonth-1) );
293 nWeekDay = static_cast<sal_uInt16>(aTempDate2.GetDayOfWeek());
294 nWeekDay = (nWeekDay+(7-static_cast<sal_uInt16>(eStartDay))) % 7;
295 mnDayCount += 42-nDaysInMonth-nWeekDay;
297 // determine colours
298 maOtherColor = COL_LIGHTGRAY;
299 if ( maOtherColor.IsRGBEqual( GetBackground().GetColor() ) )
300 maOtherColor = COL_GRAY;
302 Date aLastDate = GetLastDate();
303 if ( (maOldFormatLastDate != aLastDate) ||
304 (maOldFormatFirstDate != maFirstDate) )
306 maOldFormatFirstDate = maFirstDate;
307 maOldFormatLastDate = aLastDate;
310 // get DateInfo
311 sal_Int16 nNewFirstYear = maFirstDate.GetYear();
312 sal_Int16 nNewLastYear = GetLastDate().GetYear();
313 if ( mnFirstYear )
315 if ( nNewFirstYear < mnFirstYear )
317 mnFirstYear = nNewFirstYear;
319 if ( nNewLastYear > mnLastYear )
321 mnLastYear = nNewLastYear;
324 else
326 mnFirstYear = nNewFirstYear;
327 mnLastYear = nNewLastYear;
330 mbFormat = false;
333 sal_uInt16 Calendar::ImplHitTest( const Point& rPos, Date& rDate ) const
335 if ( mbFormat )
336 return 0;
338 if ( maPrevRect.IsInside( rPos ) )
339 return CALENDAR_HITTEST_PREV;
340 else if ( maNextRect.IsInside( rPos ) )
341 return CALENDAR_HITTEST_NEXT;
343 long nY;
344 long nOffX;
345 sal_Int32 nDay;
346 DayOfWeek eStartDay = ImplGetWeekStart();
348 rDate = GetFirstMonth();
349 nY = 0;
350 for ( long i = 0; i < mnLines; i++ )
352 if ( rPos.Y() < nY )
353 return 0;
355 long nX = 0;
356 long nYMonth = nY+mnMonthHeight;
357 for ( long j = 0; j < mnMonthPerLine; j++ )
359 if ( (rPos.X() < nX) && (rPos.Y() < nYMonth) )
360 return 0;
362 sal_uInt16 nDaysInMonth = rDate.GetDaysInMonth();
364 // matching month was found
365 if ( (rPos.X() > nX) && (rPos.Y() < nYMonth) &&
366 (rPos.X() < nX+mnMonthWidth) )
368 if ( rPos.Y() < (nY+(TITLE_BORDERY*2)+mnDayHeight))
369 return CALENDAR_HITTEST_MONTHTITLE;
370 else
372 long nDayX = nX+mnDaysOffX;
373 long nDayY = nY+mnDaysOffY;
374 if ( rPos.Y() < nDayY )
375 return 0;
376 sal_Int32 nDayIndex = static_cast<sal_Int32>(rDate.GetDayOfWeek());
377 nDayIndex = (nDayIndex+(7-static_cast<sal_Int32>(eStartDay))) % 7;
378 if ( (i == 0) && (j == 0) )
380 Date aTempDate = rDate;
381 aTempDate.AddDays( -nDayIndex );
382 for ( nDay = 0; nDay < nDayIndex; nDay++ )
384 nOffX = nDayX + (nDay*mnDayWidth);
385 if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) &&
386 (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) )
388 rDate = aTempDate;
389 rDate.AddDays( nDay );
390 return CALENDAR_HITTEST_DAY;
394 for ( nDay = 1; nDay <= nDaysInMonth; nDay++ )
396 if ( rPos.Y() < nDayY )
398 rDate.AddDays( nDayIndex );
399 return 0;
401 nOffX = nDayX + (nDayIndex*mnDayWidth);
402 if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) &&
403 (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) )
405 rDate.AddDays( nDay-1 );
406 return CALENDAR_HITTEST_DAY;
408 if ( nDayIndex == 6 )
410 nDayIndex = 0;
411 nDayY += mnDayHeight;
413 else
414 nDayIndex++;
416 if ( (i == mnLines-1) && (j == mnMonthPerLine-1) )
418 sal_uInt16 nWeekDay = static_cast<sal_uInt16>(rDate.GetDayOfWeek());
419 nWeekDay = (nWeekDay+(7-static_cast<sal_uInt16>(eStartDay))) % 7;
420 sal_Int32 nDayCount = 42-nDaysInMonth-nWeekDay;
421 Date aTempDate = rDate;
422 aTempDate.AddDays( nDaysInMonth );
423 for ( nDay = 1; nDay <= nDayCount; nDay++ )
425 if ( rPos.Y() < nDayY )
427 rDate.AddDays( nDayIndex );
428 return 0;
430 nOffX = nDayX + (nDayIndex*mnDayWidth);
431 if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) &&
432 (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) )
434 rDate = aTempDate;
435 rDate.AddDays( nDay-1 );
436 return CALENDAR_HITTEST_DAY;
438 if ( nDayIndex == 6 )
440 nDayIndex = 0;
441 nDayY += mnDayHeight;
443 else
444 nDayIndex++;
450 rDate.AddDays( nDaysInMonth );
451 nX += mnMonthWidth;
454 nY += mnMonthHeight;
457 return 0;
460 namespace
463 void ImplDrawSpinArrow(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, bool bPrev)
465 long i;
466 long n;
467 long nLines;
468 long nHeight = rRect.GetHeight();
469 long nWidth = rRect.GetWidth();
470 if (nWidth < nHeight)
471 n = nWidth;
472 else
473 n = nHeight;
474 if (!(n & 0x01))
475 n--;
476 nLines = n/2;
478 tools::Rectangle aRect(Point( rRect.Left() + (nWidth / 2) - (nLines / 2),
479 rRect.Top() + (nHeight / 2) ),
480 Size(1, 1));
481 if (!bPrev)
483 aRect.AdjustLeft(nLines );
484 aRect.AdjustRight(nLines );
487 rRenderContext.DrawRect(aRect);
488 for (i = 0; i < nLines; i++)
490 if (bPrev)
492 aRect.AdjustLeft( 1 );
493 aRect.AdjustRight( 1 );
495 else
497 aRect.AdjustLeft( -1 );
498 aRect.AdjustRight( -1 );
500 aRect.AdjustTop( -1 );
501 aRect.AdjustBottom( 1 );
502 rRenderContext.DrawRect(aRect);
506 } //end anonymous namespace
508 void Calendar::ImplDrawSpin(vcl::RenderContext& rRenderContext )
510 rRenderContext.SetLineColor();
511 rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetButtonTextColor());
512 tools::Rectangle aOutRect = maPrevRect;
513 aOutRect.AdjustLeft(3 );
514 aOutRect.AdjustTop(3 );
515 aOutRect.AdjustRight( -3 );
516 aOutRect.AdjustBottom( -3 );
517 ImplDrawSpinArrow(rRenderContext, aOutRect, true);
518 aOutRect = maNextRect;
519 aOutRect.AdjustLeft(3 );
520 aOutRect.AdjustTop(3 );
521 aOutRect.AdjustRight( -3 );
522 aOutRect.AdjustBottom( -3 );
523 ImplDrawSpinArrow(rRenderContext, aOutRect, false);
526 void Calendar::ImplDrawDate(vcl::RenderContext& rRenderContext,
527 long nX, long nY,
528 sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear,
529 bool bOther, sal_Int32 nToday )
531 Color const * pTextColor = nullptr;
532 const OUString& rDay = maDayTexts[nDay - 1];
533 tools::Rectangle aDateRect(nX, nY, nX + mnDayWidth - 1, nY + mnDayHeight - 1);
535 bool bSel = false;
536 bool bFocus = false;
537 // actual day
538 if ((nDay == maCurDate.GetDay()) &&
539 (nMonth == maCurDate.GetMonth()) &&
540 (nYear == maCurDate.GetYear()))
542 bFocus = true;
544 if (mpSelectTable)
546 if (mpSelectTable->find(Date(nDay, nMonth, nYear).GetDate()) != mpSelectTable->end())
547 bSel = true;
550 // get textcolour
551 if (bSel)
552 pTextColor = &maSelColor;
553 else if (bOther)
554 pTextColor = &maOtherColor;
556 if (bFocus)
557 HideFocus();
559 // display background
560 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
561 if (bSel)
563 rRenderContext.SetLineColor();
564 rRenderContext.SetFillColor(rStyleSettings.GetHighlightColor());
565 rRenderContext.DrawRect(aDateRect);
568 // display text
569 long nTextX = nX + (mnDayWidth - GetTextWidth(rDay)) - (DAY_OFFX / 2);
570 long nTextY = nY + (mnDayHeight - GetTextHeight()) / 2;
571 if (pTextColor)
573 Color aOldColor = rRenderContext.GetTextColor();
574 rRenderContext.SetTextColor(*pTextColor);
575 rRenderContext.DrawText(Point(nTextX, nTextY), rDay);
576 rRenderContext.SetTextColor(aOldColor);
578 else
579 rRenderContext.DrawText(Point(nTextX, nTextY), rDay);
581 // today
582 Date aTodayDate(maCurDate);
583 if (nToday)
584 aTodayDate.SetDate(nToday);
585 else
586 aTodayDate = Date(Date::SYSTEM);
587 if ((nDay == aTodayDate.GetDay()) &&
588 (nMonth == aTodayDate.GetMonth()) &&
589 (nYear == aTodayDate.GetYear()))
591 rRenderContext.SetLineColor(rStyleSettings.GetWindowTextColor());
592 rRenderContext.SetFillColor();
593 rRenderContext.DrawRect(aDateRect);
596 // if needed do FocusRect
597 if (bFocus && HasFocus())
598 ShowFocus(aDateRect);
601 void Calendar::ImplDraw(vcl::RenderContext& rRenderContext)
603 ImplFormat();
605 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
606 Size aOutSize(GetOutputSizePixel());
607 long i;
608 long j;
609 long nY;
610 long nDeltaX;
611 long nDeltaY;
612 long nDayX;
613 long nDayY;
614 sal_Int32 nToday = Date(Date::SYSTEM).GetDate();
615 sal_uInt16 nDay;
616 sal_uInt16 nMonth;
617 sal_Int16 nYear;
618 Date aDate = GetFirstMonth();
619 DayOfWeek eStartDay = ImplGetWeekStart();
621 HideFocus();
623 nY = 0;
624 for (i = 0; i < mnLines; i++)
626 // display title bar
627 rRenderContext.SetLineColor();
628 rRenderContext.SetFillColor(rStyleSettings.GetFaceColor());
629 tools::Rectangle aTitleRect(0, nY, aOutSize.Width() - 1, nY + mnDayHeight - DAY_OFFY + TITLE_BORDERY * 2);
630 rRenderContext.DrawRect(aTitleRect);
631 Point aTopLeft1(aTitleRect.Left(), aTitleRect.Top());
632 Point aTopLeft2(aTitleRect.Left(), aTitleRect.Top() + 1);
633 Point aBottomRight1(aTitleRect.Right(), aTitleRect.Bottom());
634 Point aBottomRight2(aTitleRect.Right(), aTitleRect.Bottom() - 1);
635 rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
636 rRenderContext.DrawLine(aTopLeft1, Point(aBottomRight1.X(), aTopLeft1.Y()));
637 rRenderContext.SetLineColor(rStyleSettings.GetLightColor() );
638 rRenderContext.DrawLine(aTopLeft2, Point(aBottomRight2.X(), aTopLeft2.Y()));
639 rRenderContext.DrawLine(aTopLeft2, Point(aTopLeft2.X(), aBottomRight2.Y()));
640 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor() );
641 rRenderContext.DrawLine(Point(aTopLeft2.X(), aBottomRight2.Y()), aBottomRight2);
642 rRenderContext.DrawLine(Point(aBottomRight2.X(), aTopLeft2.Y()), aBottomRight2);
643 rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
644 rRenderContext.DrawLine(Point(aTopLeft1.X(), aBottomRight1.Y()), aBottomRight1);
645 Point aSepPos1(0, aTitleRect.Top() + TITLE_BORDERY);
646 Point aSepPos2(0, aTitleRect.Bottom() - TITLE_BORDERY);
647 for (j = 0; j < mnMonthPerLine-1; j++)
649 aSepPos1.AdjustX(mnMonthWidth-1 );
650 aSepPos2.setX( aSepPos1.X() );
651 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
652 rRenderContext.DrawLine(aSepPos1, aSepPos2);
653 aSepPos1.AdjustX( 1 );
654 aSepPos2.setX( aSepPos1.X() );
655 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
656 rRenderContext.DrawLine(aSepPos1, aSepPos2);
659 long nX = 0;
660 for (j = 0; j < mnMonthPerLine; j++)
662 nMonth = aDate.GetMonth();
663 nYear = aDate.GetYear();
665 // display month in title bar
666 nDeltaX = nX;
667 nDeltaY = nY + TITLE_BORDERY;
668 OUString aMonthText = maCalendarWrapper.getDisplayName(i18n::CalendarDisplayIndex::MONTH, nMonth - 1, 1)
669 + " "
670 + OUString::number(nYear);
671 long nMonthTextWidth = rRenderContext.GetTextWidth(aMonthText);
672 long nMonthOffX1 = 0;
673 long nMonthOffX2 = 0;
674 if (i == 0)
676 if (j == 0)
677 nMonthOffX1 = maPrevRect.Right() + 1;
678 if (j == mnMonthPerLine - 1)
679 nMonthOffX2 = aOutSize.Width() - maNextRect.Left() + 1;
681 long nMaxMonthWidth = mnMonthWidth - nMonthOffX1 - nMonthOffX2 - 4;
682 if (nMonthTextWidth > nMaxMonthWidth)
684 // Abbreviated month name.
685 aMonthText = maCalendarWrapper.getDisplayName(i18n::CalendarDisplayIndex::MONTH, nMonth - 1, 0)
686 + " "
687 + OUString::number(nYear);
688 nMonthTextWidth = rRenderContext.GetTextWidth(aMonthText);
690 long nTempOff = (mnMonthWidth - nMonthTextWidth + 1) / 2;
691 if (nTempOff < nMonthOffX1)
692 nDeltaX += nMonthOffX1 + 1;
693 else
695 if (nTempOff + nMonthTextWidth > mnMonthWidth - nMonthOffX2)
696 nDeltaX += mnMonthWidth - nMonthOffX2 - nMonthTextWidth;
697 else
698 nDeltaX += nTempOff;
700 rRenderContext.SetTextColor(rStyleSettings.GetButtonTextColor());
701 rRenderContext.DrawText(Point(nDeltaX, nDeltaY), aMonthText);
702 rRenderContext.SetTextColor(rStyleSettings.GetWindowTextColor());
704 // display week bar
705 nDayX = nX + mnDaysOffX;
706 nDayY = nY + mnWeekDayOffY;
707 nDeltaY = nDayY + mnDayHeight;
708 rRenderContext.SetLineColor(rStyleSettings.GetWindowTextColor());
709 Point aStartPos(nDayX, nDeltaY);
710 rRenderContext.DrawLine(aStartPos, Point(nDayX + (7 * mnDayWidth), nDeltaY));
711 rRenderContext.DrawTextArray(Point(nDayX + mnDayOfWeekAry[0], nDayY), maDayOfWeekText, &(mnDayOfWeekAry[1]));
713 // display days
714 sal_uInt16 nDaysInMonth = aDate.GetDaysInMonth();
715 nDayX = nX + mnDaysOffX;
716 nDayY = nY + mnDaysOffY;
717 sal_uInt16 nDayIndex = static_cast<sal_uInt16>(aDate.GetDayOfWeek());
718 nDayIndex = (nDayIndex + (7 - static_cast<sal_uInt16>(eStartDay))) % 7;
719 if (i == 0 && j == 0)
721 Date aTempDate = aDate;
722 aTempDate.AddDays( -nDayIndex );
723 for (nDay = 0; nDay < nDayIndex; ++nDay)
725 nDeltaX = nDayX + (nDay * mnDayWidth);
726 ImplDrawDate(rRenderContext, nDeltaX, nDayY, nDay + aTempDate.GetDay(),
727 aTempDate.GetMonth(), aTempDate.GetYear(),
728 true, nToday);
731 for (nDay = 1; nDay <= nDaysInMonth; nDay++)
733 nDeltaX = nDayX + (nDayIndex * mnDayWidth);
734 ImplDrawDate(rRenderContext, nDeltaX, nDayY, nDay, nMonth, nYear,
735 false, nToday);
736 if (nDayIndex == 6)
738 nDayIndex = 0;
739 nDayY += mnDayHeight;
741 else
742 nDayIndex++;
744 if ((i == mnLines - 1) && (j == mnMonthPerLine - 1))
746 sal_uInt16 nWeekDay = static_cast<sal_uInt16>(aDate.GetDayOfWeek());
747 nWeekDay = (nWeekDay + (7 - static_cast<sal_uInt16>(eStartDay))) % 7;
748 sal_uInt16 nDayCount = 42 - nDaysInMonth - nWeekDay;
749 Date aTempDate = aDate;
750 aTempDate.AddDays( nDaysInMonth );
751 for (nDay = 1; nDay <= nDayCount; ++nDay)
753 nDeltaX = nDayX + (nDayIndex * mnDayWidth);
754 ImplDrawDate(rRenderContext, nDeltaX, nDayY, nDay,
755 aTempDate.GetMonth(), aTempDate.GetYear(),
756 true, nToday);
757 if (nDayIndex == 6)
759 nDayIndex = 0;
760 nDayY += mnDayHeight;
762 else
763 nDayIndex++;
767 aDate.AddDays( nDaysInMonth );
768 nX += mnMonthWidth;
771 nY += mnMonthHeight;
774 // draw spin buttons
775 ImplDrawSpin(rRenderContext);
778 void Calendar::ImplUpdateDate( const Date& rDate )
780 if (IsReallyVisible() && IsUpdateMode())
782 tools::Rectangle aDateRect(GetDateRect(rDate));
783 if (!aDateRect.IsEmpty())
785 Invalidate(aDateRect);
790 void Calendar::ImplUpdateSelection( IntDateSet* pOld )
792 IntDateSet* pNew = mpSelectTable.get();
794 for (auto const& nKey : *pOld)
796 if ( pNew->find(nKey) == pNew->end() )
798 Date aTempDate(nKey);
799 ImplUpdateDate(aTempDate);
803 for (auto const& nKey : *pNew)
805 if ( pOld->find(nKey) == pOld->end() )
807 Date aTempDate(nKey);
808 ImplUpdateDate(aTempDate);
813 void Calendar::ImplMouseSelect( const Date& rDate, sal_uInt16 nHitTest )
815 std::unique_ptr<IntDateSet> pOldSel(new IntDateSet( *mpSelectTable ));
816 Date aOldDate = maCurDate;
817 Date aTempDate = rDate;
819 if ( !(nHitTest & CALENDAR_HITTEST_DAY) )
820 --aTempDate;
822 if ( !(nHitTest & CALENDAR_HITTEST_DAY) )
823 aTempDate = maOldCurDate;
824 if ( aTempDate != maCurDate )
826 maCurDate = aTempDate;
827 ImplCalendarSelectDate( mpSelectTable.get(), aOldDate, false );
828 ImplCalendarSelectDate( mpSelectTable.get(), maCurDate, true );
831 bool bNewSel = *pOldSel != *mpSelectTable;
832 if ( (maCurDate != aOldDate) || bNewSel )
834 HideFocus();
835 if ( bNewSel )
836 ImplUpdateSelection( pOldSel.get() );
837 if ( !bNewSel || pOldSel->find( aOldDate.GetDate() ) == pOldSel->end() )
838 ImplUpdateDate( aOldDate );
839 // assure focus rectangle is displayed again
840 if ( HasFocus() || !bNewSel
841 || mpSelectTable->find( maCurDate.GetDate() ) == mpSelectTable->end() )
842 ImplUpdateDate( maCurDate );
846 void Calendar::ImplUpdate( bool bCalcNew )
848 if (IsReallyVisible() && IsUpdateMode())
850 if (bCalcNew && !mbCalc)
852 Invalidate();
854 else if (!mbFormat && !mbCalc)
856 Invalidate();
860 if (bCalcNew)
861 mbCalc = true;
862 mbFormat = true;
865 void Calendar::ImplScroll( bool bPrev )
867 Date aNewFirstMonth = GetFirstMonth();
868 if ( bPrev )
870 --aNewFirstMonth;
871 aNewFirstMonth.AddDays( -(aNewFirstMonth.GetDaysInMonth()-1));
873 else
874 aNewFirstMonth.AddDays( aNewFirstMonth.GetDaysInMonth());
875 SetFirstDate( aNewFirstMonth );
878 void Calendar::ImplShowMenu( const Point& rPos, const Date& rDate )
880 EndSelection();
882 Date aOldFirstDate = GetFirstMonth();
883 ScopedVclPtrInstance<PopupMenu> aPopupMenu;
884 sal_uInt16 nMonthOff;
885 sal_uInt16 nCurItemId;
886 sal_uInt16 nYear = rDate.GetYear()-1;
887 sal_uInt16 i;
888 sal_uInt16 j;
889 sal_uInt16 nYearIdCount = 1000;
891 nMonthOff = (rDate.GetYear()-aOldFirstDate.GetYear())*12;
892 if ( aOldFirstDate.GetMonth() < rDate.GetMonth() )
893 nMonthOff += rDate.GetMonth()-aOldFirstDate.GetMonth();
894 else
895 nMonthOff -= aOldFirstDate.GetMonth()-rDate.GetMonth();
897 // construct menu (include years with different months)
898 for ( i = 0; i < MENU_YEAR_COUNT; i++ )
900 VclPtrInstance<PopupMenu> pYearPopupMenu;
901 for ( j = 1; j <= 12; j++ )
902 pYearPopupMenu->InsertItem( nYearIdCount+j,
903 maCalendarWrapper.getDisplayName(
904 i18n::CalendarDisplayIndex::MONTH, j-1, 1));
905 aPopupMenu->InsertItem( 10+i, OUString::number( nYear+i ) );
906 aPopupMenu->SetPopupMenu( 10+i, pYearPopupMenu );
907 nYearIdCount += 1000;
910 mbMenuDown = true;
911 nCurItemId = aPopupMenu->Execute( this, rPos );
912 mbMenuDown = false;
914 if ( !nCurItemId )
915 return;
917 sal_uInt16 nTempMonthOff = nMonthOff % 12;
918 sal_uInt16 nTempYearOff = nMonthOff / 12;
919 sal_uInt16 nNewMonth = nCurItemId % 1000;
920 sal_uInt16 nNewYear = nYear+((nCurItemId-1000)/1000);
921 if ( nTempMonthOff < nNewMonth )
922 nNewMonth = nNewMonth - nTempMonthOff;
923 else
925 nNewYear--;
926 nNewMonth = 12-(nTempMonthOff-nNewMonth);
928 nNewYear = nNewYear - nTempYearOff;
929 SetFirstDate( Date( 1, nNewMonth, nNewYear ) );
932 void Calendar::ImplTracking( const Point& rPos, bool bRepeat )
934 Date aTempDate = maCurDate;
935 sal_uInt16 nHitTest = ImplHitTest( rPos, aTempDate );
937 if ( mbSpinDown )
939 mbPrevIn = (nHitTest & CALENDAR_HITTEST_PREV) != 0;
940 mbNextIn = (nHitTest & CALENDAR_HITTEST_NEXT) != 0;
942 if ( bRepeat && (mbPrevIn || mbNextIn) )
944 ImplScroll( mbPrevIn );
947 else
948 ImplMouseSelect( aTempDate, nHitTest );
951 void Calendar::ImplEndTracking( bool bCancel )
953 bool bSelection = mbSelection;
954 bool bSpinDown = mbSpinDown;
956 mbDrag = false;
957 mbSelection = false;
958 mbSpinDown = false;
959 mbPrevIn = false;
960 mbNextIn = false;
962 if ( bCancel )
964 if ( maOldFirstDate != maFirstDate )
965 SetFirstDate( maOldFirstDate );
967 if ( !bSpinDown )
969 std::unique_ptr<IntDateSet> pOldSel(new IntDateSet( *mpSelectTable ));
970 Date aOldDate = maCurDate;
971 maCurDate = maOldCurDate;
972 *mpSelectTable = *mpOldSelectTable;
973 HideFocus();
974 ImplUpdateSelection( pOldSel.get() );
975 if ( pOldSel->find( aOldDate.GetDate() ) == pOldSel->end() )
976 ImplUpdateDate( aOldDate );
977 // assure focus rectangle is displayed again
978 if ( HasFocus() || mpSelectTable->find( maCurDate.GetDate() ) == mpSelectTable->end() )
979 ImplUpdateDate( maCurDate );
983 if ( bSpinDown )
984 return;
986 if ( !bCancel )
988 // determine if we should scroll the visible area
989 if ( !mpSelectTable->empty() )
991 Date aFirstSelDate( *mpSelectTable->begin() );
992 Date aLastSelDate( *mpSelectTable->rbegin() );
993 if ( aLastSelDate < GetFirstMonth() )
994 ImplScroll( true );
995 else if ( GetLastMonth() < aFirstSelDate )
996 ImplScroll( false );
1000 if ( mbAllSel ||
1001 (!bCancel && ((maCurDate != maOldCurDate) || (*mpOldSelectTable != *mpSelectTable))) )
1002 Select();
1004 if ( !bSelection && (mnWinStyle & WB_TABSTOP) && !bCancel )
1005 GrabFocus();
1007 mpOldSelectTable.reset();
1010 void Calendar::MouseButtonDown( const MouseEvent& rMEvt )
1012 if ( rMEvt.IsLeft() && !mbMenuDown )
1014 Date aTempDate = maCurDate;
1015 sal_uInt16 nHitTest = ImplHitTest( rMEvt.GetPosPixel(), aTempDate );
1016 if ( nHitTest )
1018 if ( nHitTest & CALENDAR_HITTEST_MONTHTITLE )
1019 ImplShowMenu( rMEvt.GetPosPixel(), aTempDate );
1020 else
1022 maOldFirstDate = maFirstDate;
1024 mbPrevIn = (nHitTest & CALENDAR_HITTEST_PREV) != 0;
1025 mbNextIn = (nHitTest & CALENDAR_HITTEST_NEXT) != 0;
1026 if ( mbPrevIn || mbNextIn )
1028 mbSpinDown = true;
1029 ImplScroll( mbPrevIn );
1030 // it should really read BUTTONREPEAT, therefore do not
1031 // change it to SCROLLREPEAT, check with TH,
1032 // why it could be different (71775)
1033 StartTracking( StartTrackingFlags::ButtonRepeat );
1035 else
1037 if ( (rMEvt.GetClicks() != 2) || !(nHitTest & CALENDAR_HITTEST_DAY) )
1039 maOldCurDate = maCurDate;
1040 mpOldSelectTable.reset(new IntDateSet( *mpSelectTable ));
1042 if ( !mbSelection )
1044 mbDrag = true;
1045 StartTracking();
1048 ImplMouseSelect( aTempDate, nHitTest );
1050 if (rMEvt.GetClicks() == 2)
1051 maActivateHdl.Call(this);
1056 return;
1059 Control::MouseButtonDown( rMEvt );
1062 void Calendar::MouseButtonUp( const MouseEvent& rMEvt )
1064 if ( rMEvt.IsLeft() && mbSelection )
1065 ImplEndTracking( false );
1066 else
1067 Control::MouseButtonUp( rMEvt );
1070 void Calendar::MouseMove( const MouseEvent& rMEvt )
1072 if ( mbSelection && rMEvt.GetButtons() )
1073 ImplTracking( rMEvt.GetPosPixel(), false );
1074 else
1075 Control::MouseMove( rMEvt );
1078 void Calendar::Tracking( const TrackingEvent& rTEvt )
1080 Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel();
1082 if ( rTEvt.IsTrackingEnded() )
1083 ImplEndTracking( rTEvt.IsTrackingCanceled() );
1084 else
1085 ImplTracking( aMousePos, rTEvt.IsTrackingRepeat() );
1088 void Calendar::KeyInput( const KeyEvent& rKEvt )
1090 Date aNewDate = maCurDate;
1092 switch ( rKEvt.GetKeyCode().GetCode() )
1094 case KEY_HOME:
1095 aNewDate.SetDay( 1 );
1096 break;
1098 case KEY_END:
1099 aNewDate.SetDay( aNewDate.GetDaysInMonth() );
1100 break;
1102 case KEY_LEFT:
1103 --aNewDate;
1104 break;
1106 case KEY_RIGHT:
1107 ++aNewDate;
1108 break;
1110 case KEY_UP:
1111 aNewDate.AddDays( -7 );
1112 break;
1114 case KEY_DOWN:
1115 aNewDate.AddDays( 7 );
1116 break;
1118 case KEY_PAGEUP:
1120 Date aTempDate = aNewDate;
1121 aTempDate.AddDays( -(aNewDate.GetDay()+1) );
1122 aNewDate.AddDays( -aTempDate.GetDaysInMonth() );
1124 break;
1126 case KEY_PAGEDOWN:
1127 aNewDate.AddDays( aNewDate.GetDaysInMonth() );
1128 break;
1130 case KEY_RETURN:
1131 break;
1133 default:
1134 Control::KeyInput( rKEvt );
1135 break;
1138 if ( aNewDate != maCurDate )
1140 SetCurDate( aNewDate );
1141 mbTravelSelect = true;
1142 Select();
1143 mbTravelSelect = false;
1146 if (rKEvt.GetKeyCode().GetCode() == KEY_RETURN)
1148 if (maActivateHdl.IsSet())
1149 maActivateHdl.Call(this);
1150 else
1151 Control::KeyInput(rKEvt);
1155 void Calendar::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& )
1157 ImplDraw(rRenderContext);
1160 void Calendar::GetFocus()
1162 ImplUpdateDate( maCurDate );
1163 Control::GetFocus();
1166 void Calendar::LoseFocus()
1168 HideFocus();
1169 Control::LoseFocus();
1172 void Calendar::Resize()
1174 ImplUpdate( true );
1175 Control::Resize();
1178 void Calendar::RequestHelp( const HelpEvent& rHEvt )
1180 if ( rHEvt.GetMode() & (HelpEventMode::QUICK | HelpEventMode::BALLOON) )
1182 Date aDate = maCurDate;
1183 if ( GetDate( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ), aDate ) )
1185 tools::Rectangle aDateRect = GetDateRect( aDate );
1186 Point aPt = OutputToScreenPixel( aDateRect.TopLeft() );
1187 aDateRect.SetLeft( aPt.X() );
1188 aDateRect.SetTop( aPt.Y() );
1189 aPt = OutputToScreenPixel( aDateRect.BottomRight() );
1190 aDateRect.SetRight( aPt.X() );
1191 aDateRect.SetBottom( aPt.Y() );
1193 if ( rHEvt.GetMode() & HelpEventMode::QUICK )
1195 maCalendarWrapper.setGregorianDateTime( aDate);
1196 sal_uInt16 nWeek = static_cast<sal_uInt16>(maCalendarWrapper.getValue( i18n::CalendarFieldIndex::WEEK_OF_YEAR));
1197 sal_uInt16 nMonth = aDate.GetMonth();
1198 OUString aStr = maDayText
1199 + ": "
1200 + OUString::number(aDate.GetDayOfYear())
1201 + " / "
1202 + maWeekText
1203 + ": "
1204 + OUString::number(nWeek);
1205 // if year is not the same, add it
1206 if ( (nMonth == 12) && (nWeek == 1) )
1208 aStr += ", " + OUString::number(aDate.GetNextYear());
1210 else if ( (nMonth == 1) && (nWeek > 50) )
1212 aStr += ", " + OUString::number(aDate.GetYear()-1);
1214 Help::ShowQuickHelp( this, aDateRect, aStr );
1215 return;
1220 Control::RequestHelp( rHEvt );
1223 void Calendar::Command( const CommandEvent& rCEvt )
1225 if ( rCEvt.GetCommand() == CommandEventId::ContextMenu )
1227 if ( !mbSelection && rCEvt.IsMouseEvent() )
1229 Date aTempDate = maCurDate;
1230 sal_uInt16 nHitTest = ImplHitTest( rCEvt.GetMousePosPixel(), aTempDate );
1231 if ( nHitTest & CALENDAR_HITTEST_MONTHTITLE )
1233 ImplShowMenu( rCEvt.GetMousePosPixel(), aTempDate );
1234 return;
1238 else if ( rCEvt.GetCommand() == CommandEventId::Wheel )
1240 const CommandWheelData* pData = rCEvt.GetWheelData();
1241 if ( pData->GetMode() == CommandWheelMode::SCROLL )
1243 long nNotchDelta = pData->GetNotchDelta();
1244 if ( nNotchDelta < 0 )
1246 while ( nNotchDelta < 0 )
1248 ImplScroll( true );
1249 nNotchDelta++;
1252 else
1254 while ( nNotchDelta > 0 )
1256 ImplScroll( false );
1257 nNotchDelta--;
1261 return;
1265 Control::Command( rCEvt );
1268 void Calendar::StateChanged( StateChangedType nType )
1270 Control::StateChanged( nType );
1272 if ( nType == StateChangedType::InitShow )
1273 ImplFormat();
1276 void Calendar::DataChanged( const DataChangedEvent& rDCEvt )
1278 Control::DataChanged( rDCEvt );
1280 if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
1281 (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
1282 ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
1283 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
1285 ImplInitSettings();
1286 Invalidate();
1290 void Calendar::Select()
1292 maSelectHdl.Call( this );
1295 Date Calendar::GetFirstSelectedDate() const
1297 if ( !mpSelectTable->empty() )
1298 return Date( *mpSelectTable->begin() );
1299 else
1301 Date aDate( 0, 0, 0 );
1302 return aDate;
1306 void Calendar::SetCurDate( const Date& rNewDate )
1308 if ( !rNewDate.IsValidAndGregorian() )
1309 return;
1311 if ( maCurDate == rNewDate )
1312 return;
1314 bool bUpdate = IsVisible() && IsUpdateMode();
1315 Date aOldDate = maCurDate;
1316 maCurDate = rNewDate;
1318 ImplCalendarSelectDate( mpSelectTable.get(), aOldDate, false );
1319 ImplCalendarSelectDate( mpSelectTable.get(), maCurDate, true );
1321 // shift actual date in the visible area
1322 if ( mbFormat || (maCurDate < GetFirstMonth()) )
1323 SetFirstDate( maCurDate );
1324 else if ( maCurDate > GetLastMonth() )
1326 Date aTempDate = GetLastMonth();
1327 long nDateOff = maCurDate-aTempDate;
1328 if ( nDateOff < 365 )
1330 Date aFirstDate = GetFirstMonth();
1331 aFirstDate.AddDays( aFirstDate.GetDaysInMonth() );
1332 ++aTempDate;
1333 while ( nDateOff > aTempDate.GetDaysInMonth() )
1335 aFirstDate.AddDays( aFirstDate.GetDaysInMonth() );
1336 sal_Int32 nDaysInMonth = aTempDate.GetDaysInMonth();
1337 aTempDate.AddDays( nDaysInMonth );
1338 nDateOff -= nDaysInMonth;
1340 SetFirstDate( aFirstDate );
1342 else
1343 SetFirstDate( maCurDate );
1345 else
1347 if ( bUpdate )
1349 HideFocus();
1350 ImplUpdateDate( aOldDate );
1351 ImplUpdateDate( maCurDate );
1356 void Calendar::SetFirstDate( const Date& rNewFirstDate )
1358 if ( maFirstDate != rNewFirstDate )
1360 maFirstDate = Date( 1, rNewFirstDate.GetMonth(), rNewFirstDate.GetYear() );
1361 ImplUpdate();
1365 Date Calendar::GetFirstMonth() const
1367 if ( maFirstDate.GetDay() > 1 )
1369 if ( maFirstDate.GetMonth() == 12 )
1370 return Date( 1, 1, maFirstDate.GetNextYear() );
1371 else
1372 return Date( 1, maFirstDate.GetMonth()+1, maFirstDate.GetYear() );
1374 else
1375 return maFirstDate;
1378 Date Calendar::GetLastMonth() const
1380 Date aDate = GetFirstMonth();
1381 sal_uInt16 nMonthCount = GetMonthCount();
1382 for ( sal_uInt16 i = 0; i < nMonthCount; i++ )
1383 aDate.AddDays( aDate.GetDaysInMonth() );
1384 --aDate;
1385 return aDate;
1388 sal_uInt16 Calendar::GetMonthCount() const
1390 if ( mbFormat )
1391 return 1;
1392 else
1393 return static_cast<sal_uInt16>(mnMonthPerLine*mnLines);
1396 bool Calendar::GetDate( const Point& rPos, Date& rDate ) const
1398 Date aDate = maCurDate;
1399 sal_uInt16 nHitTest = ImplHitTest( rPos, aDate );
1400 if ( nHitTest & CALENDAR_HITTEST_DAY )
1402 rDate = aDate;
1403 return true;
1405 else
1406 return false;
1409 tools::Rectangle Calendar::GetDateRect( const Date& rDate ) const
1411 tools::Rectangle aRect;
1413 if ( mbFormat || (rDate < maFirstDate) || (rDate > (maFirstDate+mnDayCount)) )
1414 return aRect;
1416 long nX;
1417 long nY;
1418 sal_Int32 nDaysOff;
1419 sal_uInt16 nDayIndex;
1420 Date aDate = GetFirstMonth();
1422 if ( rDate < aDate )
1424 aRect = GetDateRect( aDate );
1425 nDaysOff = aDate-rDate;
1426 nX = nDaysOff*mnDayWidth;
1427 aRect.AdjustLeft( -nX );
1428 aRect.AdjustRight( -nX );
1429 return aRect;
1431 else
1433 Date aLastDate = GetLastMonth();
1434 if ( rDate > aLastDate )
1436 sal_Int32 nWeekDay = static_cast<sal_Int32>(aLastDate.GetDayOfWeek());
1437 nWeekDay = (nWeekDay+(7-ImplGetWeekStart())) % 7;
1438 aLastDate.AddDays( -nWeekDay );
1439 aRect = GetDateRect( aLastDate );
1440 nDaysOff = rDate-aLastDate;
1441 nDayIndex = 0;
1442 for ( sal_Int32 i = 0; i <= nDaysOff; i++ )
1444 if ( aLastDate == rDate )
1446 aRect.AdjustLeft(nDayIndex*mnDayWidth );
1447 aRect.SetRight( aRect.Left()+mnDayWidth );
1448 return aRect;
1450 if ( nDayIndex == 6 )
1452 nDayIndex = 0;
1453 aRect.AdjustTop(mnDayHeight );
1454 aRect.AdjustBottom(mnDayHeight );
1456 else
1457 nDayIndex++;
1458 ++aLastDate;
1463 nY = 0;
1464 for ( long i = 0; i < mnLines; i++ )
1466 nX = 0;
1467 for ( long j = 0; j < mnMonthPerLine; j++ )
1469 sal_uInt16 nDaysInMonth = aDate.GetDaysInMonth();
1471 // month is called
1472 if ( (aDate.GetMonth() == rDate.GetMonth()) &&
1473 (aDate.GetYear() == rDate.GetYear()) )
1475 long nDayX = nX+mnDaysOffX;
1476 long nDayY = nY+mnDaysOffY;
1477 nDayIndex = static_cast<sal_uInt16>(aDate.GetDayOfWeek());
1478 nDayIndex = (nDayIndex+(7-static_cast<sal_uInt16>(ImplGetWeekStart()))) % 7;
1479 for ( sal_uInt16 nDay = 1; nDay <= nDaysInMonth; nDay++ )
1481 if ( nDay == rDate.GetDay() )
1483 aRect.SetLeft( nDayX + (nDayIndex*mnDayWidth) );
1484 aRect.SetTop( nDayY );
1485 aRect.SetRight( aRect.Left()+mnDayWidth );
1486 aRect.SetBottom( aRect.Top()+mnDayHeight );
1487 break;
1489 if ( nDayIndex == 6 )
1491 nDayIndex = 0;
1492 nDayY += mnDayHeight;
1494 else
1495 nDayIndex++;
1499 aDate.AddDays( nDaysInMonth );
1500 nX += mnMonthWidth;
1503 nY += mnMonthHeight;
1506 return aRect;
1509 void Calendar::StartSelection()
1511 maOldCurDate = maCurDate;
1512 mpOldSelectTable.reset(new IntDateSet( *mpSelectTable ));
1514 mbSelection = true;
1517 void Calendar::EndSelection()
1519 if ( mbDrag || mbSpinDown || mbSelection )
1521 if ( !mbSelection )
1522 ReleaseMouse();
1524 mbDrag = false;
1525 mbSelection = false;
1526 mbSpinDown = false;
1527 mbPrevIn = false;
1528 mbNextIn = false;
1532 Size Calendar::CalcWindowSizePixel() const
1534 OUString const a99Text("99");
1535 vcl::Font aOldFont = GetFont();
1537 Size aSize;
1538 long n99TextWidth = GetTextWidth( a99Text );
1539 long nTextHeight = GetTextHeight();
1541 aSize.AdjustWidth((n99TextWidth+DAY_OFFX)*7);
1542 aSize.AdjustWidth(MONTH_BORDERX*2 );
1544 aSize.setHeight( nTextHeight + TITLE_OFFY + (TITLE_BORDERY*2) );
1545 aSize.AdjustHeight(nTextHeight + WEEKDAY_OFFY );
1546 aSize.AdjustHeight((nTextHeight+DAY_OFFY)*6);
1547 aSize.AdjustHeight(MONTH_OFFY );
1549 return aSize;
1552 Size Calendar::GetOptimalSize() const
1554 return CalcWindowSizePixel();
1557 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */