1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/builder.hxx>
21 #include <vcl/svapp.hxx>
22 #include <vcl/help.hxx>
23 #include <vcl/kernarray.hxx>
24 #include <vcl/menu.hxx>
25 #include <vcl/settings.hxx>
26 #include <vcl/event.hxx>
27 #include <vcl/toolkit/calendar.hxx>
28 #include <vcl/commandevent.hxx>
29 #include <vcl/dockwin.hxx>
30 #include <unotools/calendarwrapper.hxx>
31 #include <unotools/localedatawrapper.hxx>
32 #include <com/sun/star/i18n/Weekdays.hpp>
33 #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
34 #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
35 #include <sal/log.hxx>
36 #include <tools/json_writer.hxx>
38 #include <calendar.hxx>
40 #include <strings.hrc>
45 #define MONTH_BORDERX 4
47 #define WEEKDAY_OFFY 3
49 #define TITLE_BORDERY 2
51 #define SPIN_OFFY TITLE_BORDERY
53 #define CALENDAR_HITTEST_DAY (sal_uInt16(0x0001))
54 #define CALENDAR_HITTEST_MONTHTITLE (sal_uInt16(0x0004))
55 #define CALENDAR_HITTEST_PREV (sal_uInt16(0x0008))
56 #define CALENDAR_HITTEST_NEXT (sal_uInt16(0x0010))
58 #define MENU_YEAR_COUNT 3
60 using namespace ::com::sun::star
;
62 static void ImplCalendarSelectDate( IntDateSet
* pTable
, const Date
& rDate
, bool bSelect
)
65 pTable
->insert( rDate
.GetDate() );
67 pTable
->erase( rDate
.GetDate() );
72 void Calendar::ImplInit( WinBits nWinStyle
)
74 mpSelectTable
.reset(new IntDateSet
);
76 mnWinStyle
= nWinStyle
;
87 OUString
aGregorian( u
"gregorian"_ustr
);
88 maCalendarWrapper
.loadCalendar( aGregorian
,
89 Application::GetAppLocaleDataWrapper().getLanguageTag().getLocale());
90 if (maCalendarWrapper
.getUniqueID() != aGregorian
)
92 SAL_WARN( "vcl.control", "Calendar::ImplInit: No ``gregorian'' calendar available for locale ``"
93 << Application::GetAppLocaleDataWrapper().getLanguageTag().getBcp47()
94 << "'' and other calendars aren't supported. Using en-US fallback." );
96 /* If we ever wanted to support other calendars than Gregorian a lot of
97 * rewrite would be necessary to internally replace use of class Date
98 * with proper class CalendarWrapper methods, get rid of fixed 12
99 * months, fixed 7 days, ... */
100 maCalendarWrapper
.loadCalendar( aGregorian
, lang::Locale( u
"en"_ustr
, u
"US"_ustr
, u
""_ustr
));
103 SetFirstDate( maCurDate
);
104 ImplCalendarSelectDate( mpSelectTable
.get(), maCurDate
, true );
106 // generate other strings
107 maDayText
= VclResId(STR_SVT_CALENDAR_DAY
);
108 maWeekText
= VclResId(STR_SVT_CALENDAR_WEEK
);
110 // create text for each day
111 for (sal_Int32 i
= 0; i
< 31; ++i
)
112 maDayTexts
[i
] = OUString::number(i
+1);
117 void Calendar::ApplySettings(vcl::RenderContext
& rRenderContext
)
119 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
120 maSelColor
= rStyleSettings
.GetHighlightTextColor();
121 SetPointFont(rRenderContext
, rStyleSettings
.GetToolFont());
122 rRenderContext
.SetTextColor(rStyleSettings
.GetFieldTextColor());
123 rRenderContext
.SetBackground(Wallpaper(rStyleSettings
.GetFieldColor()));
126 void Calendar::ImplInitSettings()
128 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
129 maSelColor
= rStyleSettings
.GetHighlightTextColor();
130 SetPointFont(*GetOutDev(), rStyleSettings
.GetToolFont());
131 SetTextColor(rStyleSettings
.GetFieldTextColor());
132 SetBackground(Wallpaper(rStyleSettings
.GetFieldColor()));
135 Calendar::Calendar(vcl::Window
* pParent
, WinBits nWinStyle
)
136 : Control(pParent
, nWinStyle
& (WB_TABSTOP
| WB_GROUP
| WB_BORDER
| WB_3DLOOK
))
137 , maCalendarWrapper(Application::GetAppLocaleDataWrapper().getComponentContext())
138 , maOldFormatFirstDate(0, 0, 1900)
139 , maOldFormatLastDate(0, 0, 1900)
140 , maFirstDate(0, 0, 1900)
141 , maOldFirstDate(0, 0, 1900)
142 , maCurDate(Date::SYSTEM
)
143 , maOldCurDate(0, 0, 1900)
145 ImplInit( nWinStyle
);
148 Calendar::~Calendar()
153 void Calendar::dispose()
155 mpSelectTable
.reset();
156 mpOldSelectTable
.reset();
160 DayOfWeek
Calendar::ImplGetWeekStart() const
162 // Map i18n::Weekdays to Date DayOfWeek
164 sal_Int16 nDay
= maCalendarWrapper
.getFirstDayOfWeek();
167 case i18n::Weekdays::SUNDAY
:
170 case i18n::Weekdays::MONDAY
:
173 case i18n::Weekdays::TUESDAY
:
176 case i18n::Weekdays::WEDNESDAY
:
179 case i18n::Weekdays::THURSDAY
:
182 case i18n::Weekdays::FRIDAY
:
185 case i18n::Weekdays::SATURDAY
:
189 SAL_WARN( "vcl.control", "Calendar::ImplGetWeekStart: broken i18n Gregorian calendar (getFirstDayOfWeek())");
195 void Calendar::ImplFormat()
202 Size aOutSize
= GetOutputSizePixel();
204 if ( (aOutSize
.Width() <= 1) || (aOutSize
.Height() <= 1) )
207 tools::Long n99TextWidth
= GetTextWidth( u
"99"_ustr
);
208 tools::Long nTextHeight
= GetTextHeight();
210 // calculate width and x-position
211 mnDayWidth
= n99TextWidth
+DAY_OFFX
;
212 mnMonthWidth
= mnDayWidth
*7;
213 mnMonthWidth
+= MONTH_BORDERX
*2;
214 mnMonthPerLine
= aOutSize
.Width() / mnMonthWidth
;
215 if ( !mnMonthPerLine
)
217 tools::Long nOver
= (aOutSize
.Width()-(mnMonthPerLine
*mnMonthWidth
)) / mnMonthPerLine
;
218 mnMonthWidth
+= nOver
;
219 mnDaysOffX
= MONTH_BORDERX
;
220 mnDaysOffX
+= nOver
/2;
222 // calculate height and y-position
223 mnDayHeight
= nTextHeight
+ DAY_OFFY
;
224 mnWeekDayOffY
= nTextHeight
+ TITLE_OFFY
+ (TITLE_BORDERY
*2);
225 mnDaysOffY
= mnWeekDayOffY
+ nTextHeight
+ WEEKDAY_OFFY
;
226 mnMonthHeight
= (mnDayHeight
*6) + mnDaysOffY
;
227 mnMonthHeight
+= MONTH_OFFY
;
228 mnLines
= aOutSize
.Height() / mnMonthHeight
;
231 mnMonthHeight
+= (aOutSize
.Height()-(mnLines
*mnMonthHeight
)) / mnLines
;
233 // calculate spinfields
234 tools::Long nSpinSize
= nTextHeight
+TITLE_BORDERY
-SPIN_OFFY
;
235 maPrevRect
.SetLeft( SPIN_OFFX
);
236 maPrevRect
.SetTop( SPIN_OFFY
);
237 maPrevRect
.SetRight( maPrevRect
.Left()+nSpinSize
);
238 maPrevRect
.SetBottom( maPrevRect
.Top()+nSpinSize
);
239 maNextRect
.SetLeft( aOutSize
.Width()-SPIN_OFFX
-nSpinSize
-1 );
240 maNextRect
.SetTop( SPIN_OFFY
);
241 maNextRect
.SetRight( maNextRect
.Left()+nSpinSize
);
242 maNextRect
.SetBottom( maNextRect
.Top()+nSpinSize
);
244 // Calculate DayOfWeekText (gets displayed in a narrow font)
245 maDayOfWeekText
.clear();
246 tools::Long nStartOffX
= 0;
247 sal_Int16 nDay
= maCalendarWrapper
.getFirstDayOfWeek();
248 for ( sal_Int16 nDayOfWeek
= 0; nDayOfWeek
< 7; nDayOfWeek
++ )
251 OUString
aDayOfWeek( maCalendarWrapper
.getDisplayName(
252 i18n::CalendarDisplayIndex::DAY
, nDay
, 2));
253 tools::Long nOffX
= (mnDayWidth
-GetTextWidth( aDayOfWeek
))/2;
258 nOffX
+= nDayOfWeek
* mnDayWidth
;
259 mnDayOfWeekAry
[nDayOfWeek
] = nOffX
;
260 maDayOfWeekText
+= aDayOfWeek
;
265 // header position for the last day of week
266 mnDayOfWeekAry
[7] = mnMonthWidth
;
271 // calculate number of days
273 DayOfWeek eStartDay
= ImplGetWeekStart();
276 Date aTempDate
= GetFirstMonth();
277 maFirstDate
= aTempDate
;
278 nWeekDay
= static_cast<sal_uInt16
>(aTempDate
.GetDayOfWeek());
279 nWeekDay
= (nWeekDay
+(7-static_cast<sal_uInt16
>(eStartDay
))) % 7;
280 maFirstDate
.AddDays( -nWeekDay
);
281 mnDayCount
= nWeekDay
;
282 sal_uInt16 nDaysInMonth
;
283 sal_uInt16 nMonthCount
= static_cast<sal_uInt16
>(mnMonthPerLine
*mnLines
);
284 for ( sal_uInt16 i
= 0; i
< nMonthCount
; i
++ )
286 nDaysInMonth
= aTempDate
.GetDaysInMonth();
287 mnDayCount
+= nDaysInMonth
;
288 aTempDate
.AddDays( nDaysInMonth
);
290 Date aTempDate2
= aTempDate
;
292 nDaysInMonth
= aTempDate2
.GetDaysInMonth();
293 aTempDate2
.AddDays( -(nDaysInMonth
-1) );
294 nWeekDay
= static_cast<sal_uInt16
>(aTempDate2
.GetDayOfWeek());
295 nWeekDay
= (nWeekDay
+(7-static_cast<sal_uInt16
>(eStartDay
))) % 7;
296 mnDayCount
+= 42-nDaysInMonth
-nWeekDay
;
299 maOtherColor
= COL_LIGHTGRAY
;
300 if ( maOtherColor
.IsRGBEqual( GetBackground().GetColor() ) )
301 maOtherColor
= COL_GRAY
;
303 Date aLastDate
= GetLastDate();
304 if ( (maOldFormatLastDate
!= aLastDate
) ||
305 (maOldFormatFirstDate
!= maFirstDate
) )
307 maOldFormatFirstDate
= maFirstDate
;
308 maOldFormatLastDate
= aLastDate
;
312 sal_Int16 nNewFirstYear
= maFirstDate
.GetYear();
313 sal_Int16 nNewLastYear
= GetLastDate().GetYear();
316 if ( nNewFirstYear
< mnFirstYear
)
318 mnFirstYear
= nNewFirstYear
;
320 if ( nNewLastYear
> mnLastYear
)
322 mnLastYear
= nNewLastYear
;
327 mnFirstYear
= nNewFirstYear
;
328 mnLastYear
= nNewLastYear
;
334 sal_uInt16
Calendar::ImplDoHitTest( const Point
& rPos
, Date
& rDate
) const
339 if ( maPrevRect
.Contains( rPos
) )
340 return CALENDAR_HITTEST_PREV
;
341 else if ( maNextRect
.Contains( rPos
) )
342 return CALENDAR_HITTEST_NEXT
;
347 DayOfWeek eStartDay
= ImplGetWeekStart();
349 rDate
= GetFirstMonth();
351 for ( tools::Long i
= 0; i
< mnLines
; i
++ )
357 tools::Long nYMonth
= nY
+mnMonthHeight
;
358 for ( tools::Long j
= 0; j
< mnMonthPerLine
; j
++ )
360 if ( (rPos
.X() < nX
) && (rPos
.Y() < nYMonth
) )
363 sal_uInt16 nDaysInMonth
= rDate
.GetDaysInMonth();
365 // matching month was found
366 if ( (rPos
.X() > nX
) && (rPos
.Y() < nYMonth
) &&
367 (rPos
.X() < nX
+mnMonthWidth
) )
369 if ( rPos
.Y() < (nY
+(TITLE_BORDERY
*2)+mnDayHeight
))
370 return CALENDAR_HITTEST_MONTHTITLE
;
373 tools::Long nDayX
= nX
+mnDaysOffX
;
374 tools::Long nDayY
= nY
+mnDaysOffY
;
375 if ( rPos
.Y() < nDayY
)
377 sal_Int32 nDayIndex
= static_cast<sal_Int32
>(rDate
.GetDayOfWeek());
378 nDayIndex
= (nDayIndex
+(7-static_cast<sal_Int32
>(eStartDay
))) % 7;
379 if ( (i
== 0) && (j
== 0) )
381 Date aTempDate
= rDate
;
382 aTempDate
.AddDays( -nDayIndex
);
383 for ( nDay
= 0; nDay
< nDayIndex
; nDay
++ )
385 nOffX
= nDayX
+ (nDay
*mnDayWidth
);
386 if ( (rPos
.Y() >= nDayY
) && (rPos
.Y() < nDayY
+mnDayHeight
) &&
387 (rPos
.X() >= nOffX
) && (rPos
.X() < nOffX
+mnDayWidth
) )
390 rDate
.AddDays( nDay
);
391 return CALENDAR_HITTEST_DAY
;
395 for ( nDay
= 1; nDay
<= nDaysInMonth
; nDay
++ )
397 if ( rPos
.Y() < nDayY
)
399 rDate
.AddDays( nDayIndex
);
402 nOffX
= nDayX
+ (nDayIndex
*mnDayWidth
);
403 if ( (rPos
.Y() >= nDayY
) && (rPos
.Y() < nDayY
+mnDayHeight
) &&
404 (rPos
.X() >= nOffX
) && (rPos
.X() < nOffX
+mnDayWidth
) )
406 rDate
.AddDays( nDay
-1 );
407 return CALENDAR_HITTEST_DAY
;
409 if ( nDayIndex
== 6 )
412 nDayY
+= mnDayHeight
;
417 if ( (i
== mnLines
-1) && (j
== mnMonthPerLine
-1) )
419 sal_uInt16 nWeekDay
= static_cast<sal_uInt16
>(rDate
.GetDayOfWeek());
420 nWeekDay
= (nWeekDay
+(7-static_cast<sal_uInt16
>(eStartDay
))) % 7;
421 sal_Int32 nDayCount
= 42-nDaysInMonth
-nWeekDay
;
422 Date aTempDate
= rDate
;
423 aTempDate
.AddDays( nDaysInMonth
);
424 for ( nDay
= 1; nDay
<= nDayCount
; nDay
++ )
426 if ( rPos
.Y() < nDayY
)
428 rDate
.AddDays( nDayIndex
);
431 nOffX
= nDayX
+ (nDayIndex
*mnDayWidth
);
432 if ( (rPos
.Y() >= nDayY
) && (rPos
.Y() < nDayY
+mnDayHeight
) &&
433 (rPos
.X() >= nOffX
) && (rPos
.X() < nOffX
+mnDayWidth
) )
436 rDate
.AddDays( nDay
-1 );
437 return CALENDAR_HITTEST_DAY
;
439 if ( nDayIndex
== 6 )
442 nDayY
+= mnDayHeight
;
451 rDate
.AddDays( nDaysInMonth
);
464 void ImplDrawSpinArrow(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
, bool bPrev
)
469 tools::Long nHeight
= rRect
.GetHeight();
470 tools::Long nWidth
= rRect
.GetWidth();
471 if (nWidth
< nHeight
)
479 tools::Rectangle
aRect(Point( rRect
.Left() + (nWidth
/ 2) - (nLines
/ 2),
480 rRect
.Top() + (nHeight
/ 2) ),
484 aRect
.AdjustLeft(nLines
);
485 aRect
.AdjustRight(nLines
);
488 rRenderContext
.DrawRect(aRect
);
489 for (i
= 0; i
< nLines
; i
++)
493 aRect
.AdjustLeft( 1 );
494 aRect
.AdjustRight( 1 );
498 aRect
.AdjustLeft( -1 );
499 aRect
.AdjustRight( -1 );
501 aRect
.AdjustTop( -1 );
502 aRect
.AdjustBottom( 1 );
503 rRenderContext
.DrawRect(aRect
);
507 } //end anonymous namespace
509 void Calendar::ImplDrawSpin(vcl::RenderContext
& rRenderContext
)
511 rRenderContext
.SetLineColor();
512 rRenderContext
.SetFillColor(rRenderContext
.GetSettings().GetStyleSettings().GetButtonTextColor());
513 tools::Rectangle aOutRect
= maPrevRect
;
514 aOutRect
.AdjustLeft(3 );
515 aOutRect
.AdjustTop(3 );
516 aOutRect
.AdjustRight( -3 );
517 aOutRect
.AdjustBottom( -3 );
518 ImplDrawSpinArrow(rRenderContext
, aOutRect
, true);
519 aOutRect
= maNextRect
;
520 aOutRect
.AdjustLeft(3 );
521 aOutRect
.AdjustTop(3 );
522 aOutRect
.AdjustRight( -3 );
523 aOutRect
.AdjustBottom( -3 );
524 ImplDrawSpinArrow(rRenderContext
, aOutRect
, false);
527 void Calendar::ImplDrawDate(vcl::RenderContext
& rRenderContext
,
528 tools::Long nX
, tools::Long nY
,
529 sal_uInt16 nDay
, sal_uInt16 nMonth
, sal_Int16 nYear
,
530 bool bOther
, sal_Int32 nToday
)
532 Color
const * pTextColor
= nullptr;
533 const OUString
& rDay
= maDayTexts
[(nDay
- 1) % std::size(maDayTexts
)];
534 tools::Rectangle
aDateRect(nX
, nY
, nX
+ mnDayWidth
- 1, nY
+ mnDayHeight
- 1);
539 if ((nDay
== maCurDate
.GetDay()) &&
540 (nMonth
== maCurDate
.GetMonth()) &&
541 (nYear
== maCurDate
.GetYear()))
547 if (mpSelectTable
->find(Date(nDay
, nMonth
, nYear
).GetDate()) != mpSelectTable
->end())
553 pTextColor
= &maSelColor
;
555 pTextColor
= &maOtherColor
;
560 // display background
561 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
564 rRenderContext
.SetLineColor();
565 rRenderContext
.SetFillColor(rStyleSettings
.GetHighlightColor());
566 rRenderContext
.DrawRect(aDateRect
);
570 tools::Long nTextX
= nX
+ (mnDayWidth
- GetTextWidth(rDay
)) - (DAY_OFFX
/ 2);
571 tools::Long nTextY
= nY
+ (mnDayHeight
- GetTextHeight()) / 2;
574 Color aOldColor
= rRenderContext
.GetTextColor();
575 rRenderContext
.SetTextColor(*pTextColor
);
576 rRenderContext
.DrawText(Point(nTextX
, nTextY
), rDay
);
577 rRenderContext
.SetTextColor(aOldColor
);
580 rRenderContext
.DrawText(Point(nTextX
, nTextY
), rDay
);
583 Date
aTodayDate(maCurDate
);
585 aTodayDate
.SetDate(nToday
);
587 aTodayDate
= Date(Date::SYSTEM
);
588 if ((nDay
== aTodayDate
.GetDay()) &&
589 (nMonth
== aTodayDate
.GetMonth()) &&
590 (nYear
== aTodayDate
.GetYear()))
592 rRenderContext
.SetLineColor(rStyleSettings
.GetWindowTextColor());
593 rRenderContext
.SetFillColor();
594 rRenderContext
.DrawRect(aDateRect
);
597 // if needed do FocusRect
598 if (bFocus
&& HasFocus())
599 ShowFocus(aDateRect
);
602 void Calendar::ImplDraw(vcl::RenderContext
& rRenderContext
)
606 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
607 Size
aOutSize(GetOutputSizePixel());
615 sal_Int32 nToday
= Date(Date::SYSTEM
).GetDate();
619 Date aDate
= GetFirstMonth();
620 DayOfWeek eStartDay
= ImplGetWeekStart();
625 for (i
= 0; i
< mnLines
; i
++)
628 rRenderContext
.SetLineColor();
629 rRenderContext
.SetFillColor(rStyleSettings
.GetFaceColor());
630 tools::Rectangle
aTitleRect(0, nY
, aOutSize
.Width() - 1, nY
+ mnDayHeight
- DAY_OFFY
+ TITLE_BORDERY
* 2);
631 rRenderContext
.DrawRect(aTitleRect
);
632 Point
aTopLeft1(aTitleRect
.Left(), aTitleRect
.Top());
633 Point
aTopLeft2(aTitleRect
.Left(), aTitleRect
.Top() + 1);
634 Point
aBottomRight1(aTitleRect
.Right(), aTitleRect
.Bottom());
635 Point
aBottomRight2(aTitleRect
.Right(), aTitleRect
.Bottom() - 1);
636 rRenderContext
.SetLineColor(rStyleSettings
.GetDarkShadowColor());
637 rRenderContext
.DrawLine(aTopLeft1
, Point(aBottomRight1
.X(), aTopLeft1
.Y()));
638 rRenderContext
.SetLineColor(rStyleSettings
.GetLightColor() );
639 rRenderContext
.DrawLine(aTopLeft2
, Point(aBottomRight2
.X(), aTopLeft2
.Y()));
640 rRenderContext
.DrawLine(aTopLeft2
, Point(aTopLeft2
.X(), aBottomRight2
.Y()));
641 rRenderContext
.SetLineColor(rStyleSettings
.GetShadowColor() );
642 rRenderContext
.DrawLine(Point(aTopLeft2
.X(), aBottomRight2
.Y()), aBottomRight2
);
643 rRenderContext
.DrawLine(Point(aBottomRight2
.X(), aTopLeft2
.Y()), aBottomRight2
);
644 rRenderContext
.SetLineColor(rStyleSettings
.GetDarkShadowColor());
645 rRenderContext
.DrawLine(Point(aTopLeft1
.X(), aBottomRight1
.Y()), aBottomRight1
);
646 Point
aSepPos1(0, aTitleRect
.Top() + TITLE_BORDERY
);
647 Point
aSepPos2(0, aTitleRect
.Bottom() - TITLE_BORDERY
);
648 for (j
= 0; j
< mnMonthPerLine
-1; j
++)
650 aSepPos1
.AdjustX(mnMonthWidth
-1 );
651 aSepPos2
.setX( aSepPos1
.X() );
652 rRenderContext
.SetLineColor(rStyleSettings
.GetShadowColor());
653 rRenderContext
.DrawLine(aSepPos1
, aSepPos2
);
654 aSepPos1
.AdjustX( 1 );
655 aSepPos2
.setX( aSepPos1
.X() );
656 rRenderContext
.SetLineColor(rStyleSettings
.GetLightColor());
657 rRenderContext
.DrawLine(aSepPos1
, aSepPos2
);
661 for (j
= 0; j
< mnMonthPerLine
; j
++)
663 nMonth
= aDate
.GetMonth();
664 nYear
= aDate
.GetYear();
666 // display month in title bar
668 nDeltaY
= nY
+ TITLE_BORDERY
;
669 OUString aMonthText
= maCalendarWrapper
.getDisplayName(i18n::CalendarDisplayIndex::MONTH
, nMonth
- 1, 1)
671 + OUString::number(nYear
);
672 tools::Long nMonthTextWidth
= rRenderContext
.GetTextWidth(aMonthText
);
673 tools::Long nMonthOffX1
= 0;
674 tools::Long nMonthOffX2
= 0;
678 nMonthOffX1
= maPrevRect
.Right() + 1;
679 if (j
== mnMonthPerLine
- 1)
680 nMonthOffX2
= aOutSize
.Width() - maNextRect
.Left() + 1;
682 tools::Long nMaxMonthWidth
= mnMonthWidth
- nMonthOffX1
- nMonthOffX2
- 4;
683 if (nMonthTextWidth
> nMaxMonthWidth
)
685 // Abbreviated month name.
686 aMonthText
= maCalendarWrapper
.getDisplayName(i18n::CalendarDisplayIndex::MONTH
, nMonth
- 1, 0)
688 + OUString::number(nYear
);
689 nMonthTextWidth
= rRenderContext
.GetTextWidth(aMonthText
);
691 tools::Long nTempOff
= (mnMonthWidth
- nMonthTextWidth
+ 1) / 2;
692 if (nTempOff
< nMonthOffX1
)
693 nDeltaX
+= nMonthOffX1
+ 1;
696 if (nTempOff
+ nMonthTextWidth
> mnMonthWidth
- nMonthOffX2
)
697 nDeltaX
+= mnMonthWidth
- nMonthOffX2
- nMonthTextWidth
;
701 rRenderContext
.SetTextColor(rStyleSettings
.GetButtonTextColor());
702 rRenderContext
.DrawText(Point(nDeltaX
, nDeltaY
), aMonthText
);
703 rRenderContext
.SetTextColor(rStyleSettings
.GetWindowTextColor());
706 nDayX
= nX
+ mnDaysOffX
;
707 nDayY
= nY
+ mnWeekDayOffY
;
708 nDeltaY
= nDayY
+ mnDayHeight
;
709 rRenderContext
.SetLineColor(rStyleSettings
.GetWindowTextColor());
710 Point
aStartPos(nDayX
, nDeltaY
);
711 rRenderContext
.DrawLine(aStartPos
, Point(nDayX
+ (7 * mnDayWidth
), nDeltaY
));
713 for (int k
=0; k
<7; ++k
)
714 aTmp
.push_back(mnDayOfWeekAry
[k
+1]);
715 rRenderContext
.DrawTextArray(Point(nDayX
+ mnDayOfWeekAry
[0], nDayY
), maDayOfWeekText
, aTmp
, {}, 0, aTmp
.size());
718 sal_uInt16 nDaysInMonth
= aDate
.GetDaysInMonth();
719 nDayX
= nX
+ mnDaysOffX
;
720 nDayY
= nY
+ mnDaysOffY
;
721 sal_uInt16 nDayIndex
= static_cast<sal_uInt16
>(aDate
.GetDayOfWeek());
722 nDayIndex
= (nDayIndex
+ (7 - static_cast<sal_uInt16
>(eStartDay
))) % 7;
723 if (i
== 0 && j
== 0)
725 Date aTempDate
= aDate
;
726 aTempDate
.AddDays( -nDayIndex
);
727 for (nDay
= 0; nDay
< nDayIndex
; ++nDay
)
729 nDeltaX
= nDayX
+ (nDay
* mnDayWidth
);
730 ImplDrawDate(rRenderContext
, nDeltaX
, nDayY
, nDay
+ aTempDate
.GetDay(),
731 aTempDate
.GetMonth(), aTempDate
.GetYear(),
735 for (nDay
= 1; nDay
<= nDaysInMonth
; nDay
++)
737 nDeltaX
= nDayX
+ (nDayIndex
* mnDayWidth
);
738 ImplDrawDate(rRenderContext
, nDeltaX
, nDayY
, nDay
, nMonth
, nYear
,
743 nDayY
+= mnDayHeight
;
748 if ((i
== mnLines
- 1) && (j
== mnMonthPerLine
- 1))
750 sal_uInt16 nWeekDay
= static_cast<sal_uInt16
>(aDate
.GetDayOfWeek());
751 nWeekDay
= (nWeekDay
+ (7 - static_cast<sal_uInt16
>(eStartDay
))) % 7;
752 sal_uInt16 nDayCount
= 42 - nDaysInMonth
- nWeekDay
;
753 Date aTempDate
= aDate
;
754 aTempDate
.AddDays( nDaysInMonth
);
755 for (nDay
= 1; nDay
<= nDayCount
; ++nDay
)
757 nDeltaX
= nDayX
+ (nDayIndex
* mnDayWidth
);
758 ImplDrawDate(rRenderContext
, nDeltaX
, nDayY
, nDay
,
759 aTempDate
.GetMonth(), aTempDate
.GetYear(),
764 nDayY
+= mnDayHeight
;
771 aDate
.AddDays( nDaysInMonth
);
779 ImplDrawSpin(rRenderContext
);
782 void Calendar::ImplUpdateDate( const Date
& rDate
)
784 if (IsReallyVisible() && IsUpdateMode())
786 tools::Rectangle
aDateRect(GetDateRect(rDate
));
787 if (!aDateRect
.IsEmpty())
789 Invalidate(aDateRect
);
794 void Calendar::ImplUpdateSelection( IntDateSet
* pOld
)
796 IntDateSet
* pNew
= mpSelectTable
.get();
798 for (auto const& nKey
: *pOld
)
800 if ( pNew
->find(nKey
) == pNew
->end() )
802 Date
aTempDate(nKey
);
803 ImplUpdateDate(aTempDate
);
807 for (auto const& nKey
: *pNew
)
809 if ( pOld
->find(nKey
) == pOld
->end() )
811 Date
aTempDate(nKey
);
812 ImplUpdateDate(aTempDate
);
817 void Calendar::ImplMouseSelect( const Date
& rDate
, sal_uInt16 nHitTest
)
819 IntDateSet
aOldSel( *mpSelectTable
);
820 Date aOldDate
= maCurDate
;
821 Date aTempDate
= rDate
;
823 if ( !(nHitTest
& CALENDAR_HITTEST_DAY
) )
826 if ( !(nHitTest
& CALENDAR_HITTEST_DAY
) )
827 aTempDate
= maOldCurDate
;
828 if ( aTempDate
!= maCurDate
)
830 maCurDate
= aTempDate
;
831 ImplCalendarSelectDate( mpSelectTable
.get(), aOldDate
, false );
832 ImplCalendarSelectDate( mpSelectTable
.get(), maCurDate
, true );
835 bool bNewSel
= aOldSel
!= *mpSelectTable
;
836 if ( (maCurDate
!= aOldDate
) || bNewSel
)
840 ImplUpdateSelection( &aOldSel
);
841 if ( !bNewSel
|| aOldSel
.find( aOldDate
.GetDate() ) == aOldSel
.end() )
842 ImplUpdateDate( aOldDate
);
843 // assure focus rectangle is displayed again
844 if ( HasFocus() || !bNewSel
845 || mpSelectTable
->find( maCurDate
.GetDate() ) == mpSelectTable
->end() )
846 ImplUpdateDate( maCurDate
);
850 void Calendar::ImplUpdate( bool bCalcNew
)
852 if (IsReallyVisible() && IsUpdateMode())
854 if (bCalcNew
&& !mbCalc
)
858 else if (!mbFormat
&& !mbCalc
)
869 void Calendar::ImplScrollCalendar( bool bPrev
)
871 Date aNewFirstMonth
= GetFirstMonth();
875 aNewFirstMonth
.AddDays( -(aNewFirstMonth
.GetDaysInMonth()-1));
878 aNewFirstMonth
.AddDays( aNewFirstMonth
.GetDaysInMonth());
879 SetFirstDate( aNewFirstMonth
);
882 void Calendar::ImplShowMenu( const Point
& rPos
, const Date
& rDate
)
886 Date aOldFirstDate
= GetFirstMonth();
887 ScopedVclPtrInstance
<PopupMenu
> aPopupMenu
;
888 sal_uInt16 nMonthOff
;
889 sal_uInt16 nCurItemId
;
890 sal_uInt16 nYear
= rDate
.GetYear()-1;
893 sal_uInt16 nYearIdCount
= 1000;
895 nMonthOff
= (rDate
.GetYear()-aOldFirstDate
.GetYear())*12;
896 if ( aOldFirstDate
.GetMonth() < rDate
.GetMonth() )
897 nMonthOff
+= rDate
.GetMonth()-aOldFirstDate
.GetMonth();
899 nMonthOff
-= aOldFirstDate
.GetMonth()-rDate
.GetMonth();
901 // construct menu (include years with different months)
902 for ( i
= 0; i
< MENU_YEAR_COUNT
; i
++ )
904 VclPtrInstance
<PopupMenu
> pYearPopupMenu
;
905 for ( j
= 1; j
<= 12; j
++ )
906 pYearPopupMenu
->InsertItem( nYearIdCount
+j
,
907 maCalendarWrapper
.getDisplayName(
908 i18n::CalendarDisplayIndex::MONTH
, j
-1, 1));
909 aPopupMenu
->InsertItem( 10+i
, OUString::number( nYear
+i
) );
910 aPopupMenu
->SetPopupMenu( 10+i
, pYearPopupMenu
);
911 nYearIdCount
+= 1000;
915 nCurItemId
= aPopupMenu
->Execute( this, rPos
);
921 sal_uInt16 nTempMonthOff
= nMonthOff
% 12;
922 sal_uInt16 nTempYearOff
= nMonthOff
/ 12;
923 sal_uInt16 nNewMonth
= nCurItemId
% 1000;
924 sal_uInt16 nNewYear
= nYear
+((nCurItemId
-1000)/1000);
925 if ( nTempMonthOff
< nNewMonth
)
926 nNewMonth
= nNewMonth
- nTempMonthOff
;
930 nNewMonth
= 12-(nTempMonthOff
-nNewMonth
);
932 nNewYear
= nNewYear
- nTempYearOff
;
933 SetFirstDate( Date( 1, nNewMonth
, nNewYear
) );
936 void Calendar::ImplTracking( const Point
& rPos
, bool bRepeat
)
938 Date aTempDate
= maCurDate
;
939 sal_uInt16 nHitTest
= ImplDoHitTest( rPos
, aTempDate
);
943 mbPrevIn
= (nHitTest
& CALENDAR_HITTEST_PREV
) != 0;
944 mbNextIn
= (nHitTest
& CALENDAR_HITTEST_NEXT
) != 0;
946 if ( bRepeat
&& (mbPrevIn
|| mbNextIn
) )
948 ImplScrollCalendar( mbPrevIn
);
952 ImplMouseSelect( aTempDate
, nHitTest
);
955 void Calendar::ImplEndTracking( bool bCancel
)
957 bool bSpinDown
= mbSpinDown
;
966 if ( maOldFirstDate
!= maFirstDate
)
967 SetFirstDate( maOldFirstDate
);
971 IntDateSet
aOldSel( *mpSelectTable
);
972 Date aOldDate
= maCurDate
;
973 maCurDate
= maOldCurDate
;
974 *mpSelectTable
= *mpOldSelectTable
;
976 ImplUpdateSelection( &aOldSel
);
977 if ( aOldSel
.find( aOldDate
.GetDate() ) == aOldSel
.end() )
978 ImplUpdateDate( aOldDate
);
979 // assure focus rectangle is displayed again
980 if ( HasFocus() || mpSelectTable
->find( maCurDate
.GetDate() ) == mpSelectTable
->end() )
981 ImplUpdateDate( maCurDate
);
990 // determine if we should scroll the visible area
991 if ( !mpSelectTable
->empty() )
993 Date
aFirstSelDate( *mpSelectTable
->begin() );
994 Date
aLastSelDate( *mpSelectTable
->rbegin() );
995 if ( aLastSelDate
< GetFirstMonth() )
996 ImplScrollCalendar( true );
997 else if ( GetLastMonth() < aFirstSelDate
)
998 ImplScrollCalendar( false );
1002 if ( !bCancel
&& ((maCurDate
!= maOldCurDate
) || (*mpOldSelectTable
!= *mpSelectTable
)) )
1005 if ( (mnWinStyle
& WB_TABSTOP
) && !bCancel
)
1008 mpOldSelectTable
.reset();
1011 void Calendar::MouseButtonDown( const MouseEvent
& rMEvt
)
1013 if ( rMEvt
.IsLeft() && !mbMenuDown
)
1015 Date aTempDate
= maCurDate
;
1016 sal_uInt16 nHitTest
= ImplDoHitTest( rMEvt
.GetPosPixel(), aTempDate
);
1019 if ( nHitTest
& CALENDAR_HITTEST_MONTHTITLE
)
1020 ImplShowMenu( rMEvt
.GetPosPixel(), aTempDate
);
1023 maOldFirstDate
= maFirstDate
;
1025 mbPrevIn
= (nHitTest
& CALENDAR_HITTEST_PREV
) != 0;
1026 mbNextIn
= (nHitTest
& CALENDAR_HITTEST_NEXT
) != 0;
1027 if ( mbPrevIn
|| mbNextIn
)
1030 ImplScrollCalendar( mbPrevIn
);
1031 // it should really read BUTTONREPEAT, therefore do not
1032 // change it to SCROLLREPEAT, check with TH,
1033 // why it could be different (71775)
1034 StartTracking( StartTrackingFlags::ButtonRepeat
);
1038 if ( (rMEvt
.GetClicks() != 2) || !(nHitTest
& CALENDAR_HITTEST_DAY
) )
1040 maOldCurDate
= maCurDate
;
1041 mpOldSelectTable
.reset(new IntDateSet( *mpSelectTable
));
1046 ImplMouseSelect( aTempDate
, nHitTest
);
1048 if (rMEvt
.GetClicks() == 2)
1049 maActivateHdl
.Call(this);
1057 Control::MouseButtonDown( rMEvt
);
1060 void Calendar::Tracking( const TrackingEvent
& rTEvt
)
1062 Point aMousePos
= rTEvt
.GetMouseEvent().GetPosPixel();
1064 if ( rTEvt
.IsTrackingEnded() )
1065 ImplEndTracking( rTEvt
.IsTrackingCanceled() );
1067 ImplTracking( aMousePos
, rTEvt
.IsTrackingRepeat() );
1070 void Calendar::KeyInput( const KeyEvent
& rKEvt
)
1072 Date aNewDate
= maCurDate
;
1074 switch ( rKEvt
.GetKeyCode().GetCode() )
1077 aNewDate
.SetDay( 1 );
1081 aNewDate
.SetDay( aNewDate
.GetDaysInMonth() );
1093 aNewDate
.AddDays( -7 );
1097 aNewDate
.AddDays( 7 );
1102 Date aTempDate
= aNewDate
;
1103 aTempDate
.AddDays( -(aNewDate
.GetDay()+1) );
1104 aNewDate
.AddDays( -aTempDate
.GetDaysInMonth() );
1109 aNewDate
.AddDays( aNewDate
.GetDaysInMonth() );
1116 Control::KeyInput( rKEvt
);
1120 if ( aNewDate
!= maCurDate
)
1122 SetCurDate( aNewDate
);
1126 if (rKEvt
.GetKeyCode().GetCode() == KEY_RETURN
)
1128 if (maActivateHdl
.IsSet())
1129 maActivateHdl
.Call(this);
1131 Control::KeyInput(rKEvt
);
1135 void Calendar::Paint( vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& )
1137 ImplDraw(rRenderContext
);
1140 void Calendar::GetFocus()
1142 ImplUpdateDate( maCurDate
);
1143 Control::GetFocus();
1146 void Calendar::LoseFocus()
1149 Control::LoseFocus();
1152 void Calendar::Resize()
1158 void Calendar::RequestHelp( const HelpEvent
& rHEvt
)
1160 if ( rHEvt
.GetMode() & (HelpEventMode::QUICK
| HelpEventMode::BALLOON
) )
1162 Date aDate
= maCurDate
;
1163 if ( GetDate( ScreenToOutputPixel( rHEvt
.GetMousePosPixel() ), aDate
) )
1165 tools::Rectangle aDateRect
= GetDateRect( aDate
);
1166 Point aPt
= OutputToScreenPixel( aDateRect
.TopLeft() );
1167 aDateRect
.SetLeft( aPt
.X() );
1168 aDateRect
.SetTop( aPt
.Y() );
1169 aPt
= OutputToScreenPixel( aDateRect
.BottomRight() );
1170 aDateRect
.SetRight( aPt
.X() );
1171 aDateRect
.SetBottom( aPt
.Y() );
1173 if ( rHEvt
.GetMode() & HelpEventMode::QUICK
)
1175 maCalendarWrapper
.setGregorianDateTime( DateTime(aDate
) );
1176 sal_uInt16 nWeek
= static_cast<sal_uInt16
>(maCalendarWrapper
.getValue( i18n::CalendarFieldIndex::WEEK_OF_YEAR
));
1177 sal_uInt16 nMonth
= aDate
.GetMonth();
1178 OUString aStr
= maDayText
1180 + OUString::number(aDate
.GetDayOfYear())
1184 + OUString::number(nWeek
);
1185 // if year is not the same, add it
1186 if ( (nMonth
== 12) && (nWeek
== 1) )
1188 aStr
+= ", " + OUString::number(aDate
.GetNextYear());
1190 else if ( (nMonth
== 1) && (nWeek
> 50) )
1192 aStr
+= ", " + OUString::number(aDate
.GetYear()-1);
1194 Help::ShowQuickHelp( this, aDateRect
, aStr
);
1200 Control::RequestHelp( rHEvt
);
1203 void Calendar::Command( const CommandEvent
& rCEvt
)
1205 if ( rCEvt
.GetCommand() == CommandEventId::ContextMenu
)
1207 if ( rCEvt
.IsMouseEvent() )
1209 Date aTempDate
= maCurDate
;
1210 sal_uInt16 nHitTest
= ImplDoHitTest( rCEvt
.GetMousePosPixel(), aTempDate
);
1211 if ( nHitTest
& CALENDAR_HITTEST_MONTHTITLE
)
1213 ImplShowMenu( rCEvt
.GetMousePosPixel(), aTempDate
);
1218 else if ( rCEvt
.GetCommand() == CommandEventId::Wheel
)
1220 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
1221 if ( pData
->GetMode() == CommandWheelMode::SCROLL
)
1223 tools::Long nNotchDelta
= pData
->GetNotchDelta();
1224 if ( nNotchDelta
< 0 )
1226 while ( nNotchDelta
< 0 )
1228 ImplScrollCalendar( true );
1234 while ( nNotchDelta
> 0 )
1236 ImplScrollCalendar( false );
1245 Control::Command( rCEvt
);
1248 void Calendar::StateChanged( StateChangedType nType
)
1250 Control::StateChanged( nType
);
1252 if ( nType
== StateChangedType::InitShow
)
1256 void Calendar::DataChanged( const DataChangedEvent
& rDCEvt
)
1258 Control::DataChanged( rDCEvt
);
1260 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
1261 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
1262 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
1263 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
1270 void Calendar::Select()
1272 maSelectHdl
.Call( this );
1275 Date
Calendar::GetFirstSelectedDate() const
1277 if ( !mpSelectTable
->empty() )
1278 return Date( *mpSelectTable
->begin() );
1281 Date
aDate( 0, 0, 0 );
1286 void Calendar::SetCurDate( const Date
& rNewDate
)
1288 if ( !rNewDate
.IsValidAndGregorian() )
1291 if ( maCurDate
== rNewDate
)
1294 bool bUpdate
= IsVisible() && IsUpdateMode();
1295 Date aOldDate
= maCurDate
;
1296 maCurDate
= rNewDate
;
1298 ImplCalendarSelectDate( mpSelectTable
.get(), aOldDate
, false );
1299 ImplCalendarSelectDate( mpSelectTable
.get(), maCurDate
, true );
1301 // shift actual date in the visible area
1302 if ( mbFormat
|| (maCurDate
< GetFirstMonth()) )
1303 SetFirstDate( maCurDate
);
1304 else if ( maCurDate
> GetLastMonth() )
1306 Date aTempDate
= GetLastMonth();
1307 tools::Long nDateOff
= maCurDate
-aTempDate
;
1308 if ( nDateOff
< 365 )
1310 Date aFirstDate
= GetFirstMonth();
1311 aFirstDate
.AddDays( aFirstDate
.GetDaysInMonth() );
1313 while ( nDateOff
> aTempDate
.GetDaysInMonth() )
1315 aFirstDate
.AddDays( aFirstDate
.GetDaysInMonth() );
1316 sal_Int32 nDaysInMonth
= aTempDate
.GetDaysInMonth();
1317 aTempDate
.AddDays( nDaysInMonth
);
1318 nDateOff
-= nDaysInMonth
;
1320 SetFirstDate( aFirstDate
);
1323 SetFirstDate( maCurDate
);
1330 ImplUpdateDate( aOldDate
);
1331 ImplUpdateDate( maCurDate
);
1336 void Calendar::SetFirstDate( const Date
& rNewFirstDate
)
1338 if ( maFirstDate
!= rNewFirstDate
)
1340 maFirstDate
= Date( 1, rNewFirstDate
.GetMonth(), rNewFirstDate
.GetYear() );
1345 Date
Calendar::GetFirstMonth() const
1347 if ( maFirstDate
.GetDay() > 1 )
1349 if ( maFirstDate
.GetMonth() == 12 )
1350 return Date( 1, 1, maFirstDate
.GetNextYear() );
1352 return Date( 1, maFirstDate
.GetMonth()+1, maFirstDate
.GetYear() );
1358 Date
Calendar::GetLastMonth() const
1360 Date aDate
= GetFirstMonth();
1361 sal_uInt16 nMonthCount
= GetMonthCount();
1362 for ( sal_uInt16 i
= 0; i
< nMonthCount
; i
++ )
1363 aDate
.AddDays( aDate
.GetDaysInMonth() );
1368 sal_uInt16
Calendar::GetMonthCount() const
1373 return static_cast<sal_uInt16
>(mnMonthPerLine
*mnLines
);
1376 bool Calendar::GetDate( const Point
& rPos
, Date
& rDate
) const
1378 Date aDate
= maCurDate
;
1379 sal_uInt16 nHitTest
= ImplDoHitTest( rPos
, aDate
);
1380 if ( nHitTest
& CALENDAR_HITTEST_DAY
)
1389 tools::Rectangle
Calendar::GetDateRect( const Date
& rDate
) const
1391 tools::Rectangle aRect
;
1393 if ( mbFormat
|| (rDate
< maFirstDate
) || (rDate
> (maFirstDate
+mnDayCount
)) )
1399 sal_uInt16 nDayIndex
;
1400 Date aDate
= GetFirstMonth();
1402 if ( rDate
< aDate
)
1404 aRect
= GetDateRect( aDate
);
1405 nDaysOff
= aDate
-rDate
;
1406 nX
= nDaysOff
*mnDayWidth
;
1407 aRect
.AdjustLeft( -nX
);
1408 aRect
.AdjustRight( -nX
);
1413 Date aLastDate
= GetLastMonth();
1414 if ( rDate
> aLastDate
)
1416 sal_Int32 nWeekDay
= static_cast<sal_Int32
>(aLastDate
.GetDayOfWeek());
1417 nWeekDay
= (nWeekDay
+(7-ImplGetWeekStart())) % 7;
1418 aLastDate
.AddDays( -nWeekDay
);
1419 aRect
= GetDateRect( aLastDate
);
1420 nDaysOff
= rDate
-aLastDate
;
1422 for ( sal_Int32 i
= 0; i
<= nDaysOff
; i
++ )
1424 if ( aLastDate
== rDate
)
1426 aRect
.AdjustLeft(nDayIndex
*mnDayWidth
);
1427 aRect
.SetRight( aRect
.Left()+mnDayWidth
);
1430 if ( nDayIndex
== 6 )
1433 aRect
.AdjustTop(mnDayHeight
);
1434 aRect
.AdjustBottom(mnDayHeight
);
1444 for ( tools::Long i
= 0; i
< mnLines
; i
++ )
1447 for ( tools::Long j
= 0; j
< mnMonthPerLine
; j
++ )
1449 sal_uInt16 nDaysInMonth
= aDate
.GetDaysInMonth();
1452 if ( (aDate
.GetMonth() == rDate
.GetMonth()) &&
1453 (aDate
.GetYear() == rDate
.GetYear()) )
1455 tools::Long nDayX
= nX
+mnDaysOffX
;
1456 tools::Long nDayY
= nY
+mnDaysOffY
;
1457 nDayIndex
= static_cast<sal_uInt16
>(aDate
.GetDayOfWeek());
1458 nDayIndex
= (nDayIndex
+(7-static_cast<sal_uInt16
>(ImplGetWeekStart()))) % 7;
1459 for ( sal_uInt16 nDay
= 1; nDay
<= nDaysInMonth
; nDay
++ )
1461 if ( nDay
== rDate
.GetDay() )
1463 aRect
.SetLeft( nDayX
+ (nDayIndex
*mnDayWidth
) );
1464 aRect
.SetTop( nDayY
);
1465 aRect
.SetRight( aRect
.Left()+mnDayWidth
);
1466 aRect
.SetBottom( aRect
.Top()+mnDayHeight
);
1469 if ( nDayIndex
== 6 )
1472 nDayY
+= mnDayHeight
;
1479 aDate
.AddDays( nDaysInMonth
);
1483 nY
+= mnMonthHeight
;
1489 void Calendar::EndSelection()
1491 if ( mbDrag
|| mbSpinDown
)
1502 Size
Calendar::CalcWindowSizePixel() const
1505 tools::Long n99TextWidth
= GetTextWidth( u
"99"_ustr
);
1506 tools::Long nTextHeight
= GetTextHeight();
1508 aSize
.AdjustWidth((n99TextWidth
+DAY_OFFX
)*7);
1509 aSize
.AdjustWidth(MONTH_BORDERX
*2 );
1511 aSize
.setHeight( nTextHeight
+ TITLE_OFFY
+ (TITLE_BORDERY
*2) );
1512 aSize
.AdjustHeight(nTextHeight
+ WEEKDAY_OFFY
);
1513 aSize
.AdjustHeight((nTextHeight
+DAY_OFFY
)*6);
1514 aSize
.AdjustHeight(MONTH_OFFY
);
1519 Size
Calendar::GetOptimalSize() const
1521 return CalcWindowSizePixel();
1524 void Calendar::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
1526 Control::DumpAsPropertyTree(rJsonWriter
);
1528 auto aDate
= GetFirstSelectedDate();
1530 rJsonWriter
.put("type", "calendar");
1531 rJsonWriter
.put("day", aDate
.GetDay());
1532 rJsonWriter
.put("month", aDate
.GetMonth());
1533 rJsonWriter
.put("year", aDate
.GetYear());
1538 class ImplCFieldFloat final
1541 std::unique_ptr
<weld::Builder
> mxBuilder
;
1542 std::unique_ptr
<weld::Container
> mxContainer
;
1543 std::unique_ptr
<weld::Calendar
> mxCalendar
;
1544 std::unique_ptr
<weld::Button
> mxTodayBtn
;
1545 std::unique_ptr
<weld::Button
> mxNoneBtn
;
1548 ImplCFieldFloat(vcl::Window
* pContainer
)
1549 : mxBuilder(Application::CreateInterimBuilder(pContainer
, u
"svt/ui/calendar.ui"_ustr
, false))
1550 , mxContainer(mxBuilder
->weld_container(u
"Calendar"_ustr
))
1551 , mxCalendar(mxBuilder
->weld_calendar(u
"date"_ustr
))
1552 , mxTodayBtn(mxBuilder
->weld_button(u
"today"_ustr
))
1553 , mxNoneBtn(mxBuilder
->weld_button(u
"none"_ustr
))
1557 weld::Calendar
* GetCalendar() { return mxCalendar
.get(); }
1558 weld::Button
* EnableTodayBtn(bool bEnable
);
1559 weld::Button
* EnableNoneBtn(bool bEnable
);
1563 mxCalendar
->grab_focus();
1568 struct ImplCFieldFloatWin
: public DropdownDockingWindow
1570 explicit ImplCFieldFloatWin(vcl::Window
* pParent
);
1571 virtual void dispose() override
;
1572 virtual ~ImplCFieldFloatWin() override
;
1573 virtual void GetFocus() override
;
1575 std::unique_ptr
<ImplCFieldFloat
> mxWidget
;
1578 ImplCFieldFloatWin::ImplCFieldFloatWin(vcl::Window
* pParent
)
1579 : DropdownDockingWindow(pParent
)
1581 setDeferredProperties();
1582 mxWidget
.reset(new ImplCFieldFloat(m_xBox
.get()));
1585 ImplCFieldFloatWin::~ImplCFieldFloatWin()
1590 void ImplCFieldFloatWin::dispose()
1593 DropdownDockingWindow::dispose();
1596 void ImplCFieldFloatWin::GetFocus()
1598 DropdownDockingWindow::GetFocus();
1601 mxWidget
->GrabFocus();
1604 weld::Button
* ImplCFieldFloat::EnableTodayBtn(bool bEnable
)
1606 mxTodayBtn
->set_visible(bEnable
);
1607 return bEnable
? mxTodayBtn
.get() : nullptr;
1610 weld::Button
* ImplCFieldFloat::EnableNoneBtn(bool bEnable
)
1612 mxNoneBtn
->set_visible(bEnable
);
1613 return bEnable
? mxNoneBtn
.get() : nullptr;
1616 CalendarField::CalendarField(vcl::Window
* pParent
, WinBits nWinStyle
)
1617 : DateField(pParent
, nWinStyle
)
1618 , mpFloatWin(nullptr)
1619 , mpTodayBtn(nullptr)
1620 , mpNoneBtn(nullptr)
1626 CalendarField::~CalendarField()
1631 void CalendarField::dispose()
1633 mpTodayBtn
= nullptr;
1634 mpNoneBtn
= nullptr;
1635 mpFloatWin
.disposeAndClear();
1636 DateField::dispose();
1639 IMPL_LINK(CalendarField
, ImplSelectHdl
, weld::Calendar
&, rCalendar
, void)
1641 Date aNewDate
= rCalendar
.get_date();
1643 vcl::Window::GetDockingManager()->EndPopupMode(mpFloatWin
);
1644 mpFloatWin
->EnableDocking(false);
1647 if ( IsEmptyDate() || ( aNewDate
!= GetDate() ) )
1649 SetDate( aNewDate
);
1655 IMPL_LINK(CalendarField
, ImplClickHdl
, weld::Button
&, rBtn
, void)
1657 vcl::Window::GetDockingManager()->EndPopupMode(mpFloatWin
);
1658 mpFloatWin
->EnableDocking(false);
1662 if (&rBtn
== mpTodayBtn
)
1664 Date
aToday( Date::SYSTEM
);
1665 if ( (aToday
!= GetDate()) || IsEmptyDate() )
1672 else if (&rBtn
== mpNoneBtn
)
1674 if ( !IsEmptyDate() )
1683 IMPL_LINK_NOARG(CalendarField
, ImplPopupModeEndHdl
, FloatingWindow
*, void)
1689 bool CalendarField::ShowDropDown( bool bShow
)
1694 mpFloatWin
= VclPtr
<ImplCFieldFloatWin
>::Create( this );
1696 Date aDate
= GetDate();
1697 if ( IsEmptyDate() || !aDate
.IsValidAndGregorian() )
1699 aDate
= Date( Date::SYSTEM
);
1701 weld::Calendar
* pCalendar
= mpFloatWin
->mxWidget
->GetCalendar();
1702 pCalendar
->set_date( aDate
);
1703 pCalendar
->connect_activated(LINK(this, CalendarField
, ImplSelectHdl
));
1704 mpTodayBtn
= mpFloatWin
->mxWidget
->EnableTodayBtn(mbToday
);
1705 mpNoneBtn
= mpFloatWin
->mxWidget
->EnableNoneBtn(mbNone
);
1707 mpTodayBtn
->connect_clicked( LINK( this, CalendarField
, ImplClickHdl
) );
1709 mpNoneBtn
->connect_clicked( LINK( this, CalendarField
, ImplClickHdl
) );
1710 Point
aPos(GetParent()->OutputToScreenPixel(GetPosPixel()));
1711 tools::Rectangle
aRect(aPos
, GetSizePixel());
1712 aRect
.AdjustBottom( -1 );
1713 DockingManager
* pDockingManager
= vcl::Window::GetDockingManager();
1714 mpFloatWin
->EnableDocking(true);
1715 pDockingManager
->SetPopupModeEndHdl(mpFloatWin
, LINK(this, CalendarField
, ImplPopupModeEndHdl
));
1716 pDockingManager
->StartPopupMode(mpFloatWin
, aRect
, FloatWinPopupFlags::Down
| FloatWinPopupFlags::GrabFocus
);
1720 vcl::Window::GetDockingManager()->EndPopupMode(mpFloatWin
);
1721 mpFloatWin
->EnableDocking(false);
1727 void CalendarField::StateChanged( StateChangedType nStateChange
)
1729 DateField::StateChanged( nStateChange
);
1731 if ( ( nStateChange
== StateChangedType::Style
) && GetSubEdit() )
1733 WinBits nAllAlignmentBits
= ( WB_LEFT
| WB_CENTER
| WB_RIGHT
| WB_TOP
| WB_VCENTER
| WB_BOTTOM
);
1734 WinBits nMyAlignment
= GetStyle() & nAllAlignmentBits
;
1735 GetSubEdit()->SetStyle( ( GetSubEdit()->GetStyle() & ~nAllAlignmentBits
) | nMyAlignment
);
1739 // tdf#142783 consider the Edit and its DropDown as one compound control for the purpose of
1740 // notification of loss of focus from the control
1741 bool CalendarField::FocusWindowBelongsToControl(const vcl::Window
* pFocusWin
) const
1743 return DateField::FocusWindowBelongsToControl(pFocusWin
) || (mpFloatWin
&& mpFloatWin
->ImplIsWindowOrChild(pFocusWin
));
1746 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */