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/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/toolkit/calendar.hxx>
26 #include <vcl/commandevent.hxx>
27 #include <vcl/dockwin.hxx>
28 #include <unotools/calendarwrapper.hxx>
29 #include <unotools/localedatawrapper.hxx>
30 #include <com/sun/star/i18n/Weekdays.hpp>
31 #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
32 #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
33 #include <sal/log.hxx>
35 #include <calendar.hxx>
37 #include <strings.hrc>
42 #define MONTH_BORDERX 4
44 #define WEEKDAY_OFFY 3
46 #define TITLE_BORDERY 2
48 #define SPIN_OFFY TITLE_BORDERY
50 #define CALENDAR_HITTEST_DAY (sal_uInt16(0x0001))
51 #define CALENDAR_HITTEST_MONTHTITLE (sal_uInt16(0x0004))
52 #define CALENDAR_HITTEST_PREV (sal_uInt16(0x0008))
53 #define CALENDAR_HITTEST_NEXT (sal_uInt16(0x0010))
55 #define MENU_YEAR_COUNT 3
57 using namespace ::com::sun::star
;
59 static void ImplCalendarSelectDate( IntDateSet
* pTable
, const Date
& rDate
, bool bSelect
)
62 pTable
->insert( rDate
.GetDate() );
64 pTable
->erase( rDate
.GetDate() );
69 void Calendar::ImplInit( WinBits nWinStyle
)
71 mpSelectTable
.reset(new IntDateSet
);
73 mnWinStyle
= nWinStyle
;
84 OUString
aGregorian( "gregorian");
85 maCalendarWrapper
.loadCalendar( aGregorian
,
86 Application::GetAppLocaleDataWrapper().getLanguageTag().getLocale());
87 if (maCalendarWrapper
.getUniqueID() != aGregorian
)
89 SAL_WARN( "vcl.control", "Calendar::ImplInit: No ``gregorian'' calendar available for locale ``"
90 << Application::GetAppLocaleDataWrapper().getLanguageTag().getBcp47()
91 << "'' and other calendars aren't supported. Using en-US fallback." );
93 /* If we ever wanted to support other calendars than Gregorian a lot of
94 * rewrite would be necessary to internally replace use of class Date
95 * with proper class CalendarWrapper methods, get rid of fixed 12
96 * months, fixed 7 days, ... */
97 maCalendarWrapper
.loadCalendar( aGregorian
, lang::Locale( "en", "US", ""));
100 SetFirstDate( maCurDate
);
101 ImplCalendarSelectDate( mpSelectTable
.get(), maCurDate
, true );
103 // Sonstige Strings erzeugen
104 maDayText
= VclResId(STR_SVT_CALENDAR_DAY
);
105 maWeekText
= VclResId(STR_SVT_CALENDAR_WEEK
);
107 // Tagestexte anlegen
108 for (sal_Int32 i
= 0; i
< 31; ++i
)
109 maDayTexts
[i
] = OUString::number(i
+1);
114 void Calendar::ApplySettings(vcl::RenderContext
& rRenderContext
)
116 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
117 maSelColor
= rStyleSettings
.GetHighlightTextColor();
118 SetPointFont(rRenderContext
, rStyleSettings
.GetToolFont());
119 rRenderContext
.SetTextColor(rStyleSettings
.GetFieldTextColor());
120 rRenderContext
.SetBackground(Wallpaper(rStyleSettings
.GetFieldColor()));
123 void Calendar::ImplInitSettings()
125 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
126 maSelColor
= rStyleSettings
.GetHighlightTextColor();
127 SetPointFont(*this, rStyleSettings
.GetToolFont());
128 SetTextColor(rStyleSettings
.GetFieldTextColor());
129 SetBackground(Wallpaper(rStyleSettings
.GetFieldColor()));
132 Calendar::Calendar( vcl::Window
* pParent
, WinBits nWinStyle
) :
133 Control( pParent
, nWinStyle
& (WB_TABSTOP
| WB_GROUP
| WB_BORDER
| WB_3DLOOK
) ),
134 maCalendarWrapper( Application::GetAppLocaleDataWrapper().getComponentContext() ),
135 maOldFormatFirstDate( 0, 0, 1900 ),
136 maOldFormatLastDate( 0, 0, 1900 ),
137 maFirstDate( 0, 0, 1900 ),
138 maOldFirstDate( 0, 0, 1900 ),
139 maCurDate( Date::SYSTEM
),
140 maOldCurDate( 0, 0, 1900 )
142 ImplInit( nWinStyle
);
145 Calendar::~Calendar()
150 void Calendar::dispose()
152 mpSelectTable
.reset();
153 mpOldSelectTable
.reset();
157 DayOfWeek
Calendar::ImplGetWeekStart() const
159 // Map i18n::Weekdays to Date DayOfWeek
161 sal_Int16 nDay
= maCalendarWrapper
.getFirstDayOfWeek();
164 case i18n::Weekdays::SUNDAY
:
167 case i18n::Weekdays::MONDAY
:
170 case i18n::Weekdays::TUESDAY
:
173 case i18n::Weekdays::WEDNESDAY
:
176 case i18n::Weekdays::THURSDAY
:
179 case i18n::Weekdays::FRIDAY
:
182 case i18n::Weekdays::SATURDAY
:
186 SAL_WARN( "vcl.control", "Calendar::ImplGetWeekStart: broken i18n Gregorian calendar (getFirstDayOfWeek())");
192 void Calendar::ImplFormat()
199 Size aOutSize
= GetOutputSizePixel();
201 if ( (aOutSize
.Width() <= 1) || (aOutSize
.Height() <= 1) )
204 tools::Long n99TextWidth
= GetTextWidth( "99" );
205 tools::Long nTextHeight
= GetTextHeight();
207 // calculate width and x-position
208 mnDayWidth
= n99TextWidth
+DAY_OFFX
;
209 mnMonthWidth
= mnDayWidth
*7;
210 mnMonthWidth
+= MONTH_BORDERX
*2;
211 mnMonthPerLine
= aOutSize
.Width() / mnMonthWidth
;
212 if ( !mnMonthPerLine
)
214 tools::Long nOver
= (aOutSize
.Width()-(mnMonthPerLine
*mnMonthWidth
)) / mnMonthPerLine
;
215 mnMonthWidth
+= nOver
;
216 mnDaysOffX
= MONTH_BORDERX
;
217 mnDaysOffX
+= nOver
/2;
219 // calculate height and y-position
220 mnDayHeight
= nTextHeight
+ DAY_OFFY
;
221 mnWeekDayOffY
= nTextHeight
+ TITLE_OFFY
+ (TITLE_BORDERY
*2);
222 mnDaysOffY
= mnWeekDayOffY
+ nTextHeight
+ WEEKDAY_OFFY
;
223 mnMonthHeight
= (mnDayHeight
*6) + mnDaysOffY
;
224 mnMonthHeight
+= MONTH_OFFY
;
225 mnLines
= aOutSize
.Height() / mnMonthHeight
;
228 mnMonthHeight
+= (aOutSize
.Height()-(mnLines
*mnMonthHeight
)) / mnLines
;
230 // calculate spinfields
231 tools::Long nSpinSize
= nTextHeight
+TITLE_BORDERY
-SPIN_OFFY
;
232 maPrevRect
.SetLeft( SPIN_OFFX
);
233 maPrevRect
.SetTop( SPIN_OFFY
);
234 maPrevRect
.SetRight( maPrevRect
.Left()+nSpinSize
);
235 maPrevRect
.SetBottom( maPrevRect
.Top()+nSpinSize
);
236 maNextRect
.SetLeft( aOutSize
.Width()-SPIN_OFFX
-nSpinSize
-1 );
237 maNextRect
.SetTop( SPIN_OFFY
);
238 maNextRect
.SetRight( maNextRect
.Left()+nSpinSize
);
239 maNextRect
.SetBottom( maNextRect
.Top()+nSpinSize
);
241 // Calculate DayOfWeekText (gets displayed in a narrow font)
242 maDayOfWeekText
.clear();
243 tools::Long nStartOffX
= 0;
244 sal_Int16 nDay
= maCalendarWrapper
.getFirstDayOfWeek();
245 for ( sal_Int16 nDayOfWeek
= 0; nDayOfWeek
< 7; nDayOfWeek
++ )
248 OUString
aDayOfWeek( maCalendarWrapper
.getDisplayName(
249 i18n::CalendarDisplayIndex::DAY
, nDay
, 2));
250 tools::Long nOffX
= (mnDayWidth
-GetTextWidth( aDayOfWeek
))/2;
255 nOffX
+= nDayOfWeek
* mnDayWidth
;
256 mnDayOfWeekAry
[nDayOfWeek
] = nOffX
;
257 maDayOfWeekText
+= aDayOfWeek
;
265 // calculate number of days
267 DayOfWeek eStartDay
= ImplGetWeekStart();
270 Date aTempDate
= GetFirstMonth();
271 maFirstDate
= aTempDate
;
272 nWeekDay
= static_cast<sal_uInt16
>(aTempDate
.GetDayOfWeek());
273 nWeekDay
= (nWeekDay
+(7-static_cast<sal_uInt16
>(eStartDay
))) % 7;
274 maFirstDate
.AddDays( -nWeekDay
);
275 mnDayCount
= nWeekDay
;
276 sal_uInt16 nDaysInMonth
;
277 sal_uInt16 nMonthCount
= static_cast<sal_uInt16
>(mnMonthPerLine
*mnLines
);
278 for ( sal_uInt16 i
= 0; i
< nMonthCount
; i
++ )
280 nDaysInMonth
= aTempDate
.GetDaysInMonth();
281 mnDayCount
+= nDaysInMonth
;
282 aTempDate
.AddDays( nDaysInMonth
);
284 Date aTempDate2
= aTempDate
;
286 nDaysInMonth
= aTempDate2
.GetDaysInMonth();
287 aTempDate2
.AddDays( -(nDaysInMonth
-1) );
288 nWeekDay
= static_cast<sal_uInt16
>(aTempDate2
.GetDayOfWeek());
289 nWeekDay
= (nWeekDay
+(7-static_cast<sal_uInt16
>(eStartDay
))) % 7;
290 mnDayCount
+= 42-nDaysInMonth
-nWeekDay
;
293 maOtherColor
= COL_LIGHTGRAY
;
294 if ( maOtherColor
.IsRGBEqual( GetBackground().GetColor() ) )
295 maOtherColor
= COL_GRAY
;
297 Date aLastDate
= GetLastDate();
298 if ( (maOldFormatLastDate
!= aLastDate
) ||
299 (maOldFormatFirstDate
!= maFirstDate
) )
301 maOldFormatFirstDate
= maFirstDate
;
302 maOldFormatLastDate
= aLastDate
;
306 sal_Int16 nNewFirstYear
= maFirstDate
.GetYear();
307 sal_Int16 nNewLastYear
= GetLastDate().GetYear();
310 if ( nNewFirstYear
< mnFirstYear
)
312 mnFirstYear
= nNewFirstYear
;
314 if ( nNewLastYear
> mnLastYear
)
316 mnLastYear
= nNewLastYear
;
321 mnFirstYear
= nNewFirstYear
;
322 mnLastYear
= nNewLastYear
;
328 sal_uInt16
Calendar::ImplHitTest( const Point
& rPos
, Date
& rDate
) const
333 if ( maPrevRect
.IsInside( rPos
) )
334 return CALENDAR_HITTEST_PREV
;
335 else if ( maNextRect
.IsInside( rPos
) )
336 return CALENDAR_HITTEST_NEXT
;
341 DayOfWeek eStartDay
= ImplGetWeekStart();
343 rDate
= GetFirstMonth();
345 for ( tools::Long i
= 0; i
< mnLines
; i
++ )
351 tools::Long nYMonth
= nY
+mnMonthHeight
;
352 for ( tools::Long j
= 0; j
< mnMonthPerLine
; j
++ )
354 if ( (rPos
.X() < nX
) && (rPos
.Y() < nYMonth
) )
357 sal_uInt16 nDaysInMonth
= rDate
.GetDaysInMonth();
359 // matching month was found
360 if ( (rPos
.X() > nX
) && (rPos
.Y() < nYMonth
) &&
361 (rPos
.X() < nX
+mnMonthWidth
) )
363 if ( rPos
.Y() < (nY
+(TITLE_BORDERY
*2)+mnDayHeight
))
364 return CALENDAR_HITTEST_MONTHTITLE
;
367 tools::Long nDayX
= nX
+mnDaysOffX
;
368 tools::Long nDayY
= nY
+mnDaysOffY
;
369 if ( rPos
.Y() < nDayY
)
371 sal_Int32 nDayIndex
= static_cast<sal_Int32
>(rDate
.GetDayOfWeek());
372 nDayIndex
= (nDayIndex
+(7-static_cast<sal_Int32
>(eStartDay
))) % 7;
373 if ( (i
== 0) && (j
== 0) )
375 Date aTempDate
= rDate
;
376 aTempDate
.AddDays( -nDayIndex
);
377 for ( nDay
= 0; nDay
< nDayIndex
; nDay
++ )
379 nOffX
= nDayX
+ (nDay
*mnDayWidth
);
380 if ( (rPos
.Y() >= nDayY
) && (rPos
.Y() < nDayY
+mnDayHeight
) &&
381 (rPos
.X() >= nOffX
) && (rPos
.X() < nOffX
+mnDayWidth
) )
384 rDate
.AddDays( nDay
);
385 return CALENDAR_HITTEST_DAY
;
389 for ( nDay
= 1; nDay
<= nDaysInMonth
; nDay
++ )
391 if ( rPos
.Y() < nDayY
)
393 rDate
.AddDays( nDayIndex
);
396 nOffX
= nDayX
+ (nDayIndex
*mnDayWidth
);
397 if ( (rPos
.Y() >= nDayY
) && (rPos
.Y() < nDayY
+mnDayHeight
) &&
398 (rPos
.X() >= nOffX
) && (rPos
.X() < nOffX
+mnDayWidth
) )
400 rDate
.AddDays( nDay
-1 );
401 return CALENDAR_HITTEST_DAY
;
403 if ( nDayIndex
== 6 )
406 nDayY
+= mnDayHeight
;
411 if ( (i
== mnLines
-1) && (j
== mnMonthPerLine
-1) )
413 sal_uInt16 nWeekDay
= static_cast<sal_uInt16
>(rDate
.GetDayOfWeek());
414 nWeekDay
= (nWeekDay
+(7-static_cast<sal_uInt16
>(eStartDay
))) % 7;
415 sal_Int32 nDayCount
= 42-nDaysInMonth
-nWeekDay
;
416 Date aTempDate
= rDate
;
417 aTempDate
.AddDays( nDaysInMonth
);
418 for ( nDay
= 1; nDay
<= nDayCount
; nDay
++ )
420 if ( rPos
.Y() < nDayY
)
422 rDate
.AddDays( nDayIndex
);
425 nOffX
= nDayX
+ (nDayIndex
*mnDayWidth
);
426 if ( (rPos
.Y() >= nDayY
) && (rPos
.Y() < nDayY
+mnDayHeight
) &&
427 (rPos
.X() >= nOffX
) && (rPos
.X() < nOffX
+mnDayWidth
) )
430 rDate
.AddDays( nDay
-1 );
431 return CALENDAR_HITTEST_DAY
;
433 if ( nDayIndex
== 6 )
436 nDayY
+= mnDayHeight
;
445 rDate
.AddDays( nDaysInMonth
);
458 void ImplDrawSpinArrow(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
, bool bPrev
)
463 tools::Long nHeight
= rRect
.GetHeight();
464 tools::Long nWidth
= rRect
.GetWidth();
465 if (nWidth
< nHeight
)
473 tools::Rectangle
aRect(Point( rRect
.Left() + (nWidth
/ 2) - (nLines
/ 2),
474 rRect
.Top() + (nHeight
/ 2) ),
478 aRect
.AdjustLeft(nLines
);
479 aRect
.AdjustRight(nLines
);
482 rRenderContext
.DrawRect(aRect
);
483 for (i
= 0; i
< nLines
; i
++)
487 aRect
.AdjustLeft( 1 );
488 aRect
.AdjustRight( 1 );
492 aRect
.AdjustLeft( -1 );
493 aRect
.AdjustRight( -1 );
495 aRect
.AdjustTop( -1 );
496 aRect
.AdjustBottom( 1 );
497 rRenderContext
.DrawRect(aRect
);
501 } //end anonymous namespace
503 void Calendar::ImplDrawSpin(vcl::RenderContext
& rRenderContext
)
505 rRenderContext
.SetLineColor();
506 rRenderContext
.SetFillColor(rRenderContext
.GetSettings().GetStyleSettings().GetButtonTextColor());
507 tools::Rectangle aOutRect
= maPrevRect
;
508 aOutRect
.AdjustLeft(3 );
509 aOutRect
.AdjustTop(3 );
510 aOutRect
.AdjustRight( -3 );
511 aOutRect
.AdjustBottom( -3 );
512 ImplDrawSpinArrow(rRenderContext
, aOutRect
, true);
513 aOutRect
= maNextRect
;
514 aOutRect
.AdjustLeft(3 );
515 aOutRect
.AdjustTop(3 );
516 aOutRect
.AdjustRight( -3 );
517 aOutRect
.AdjustBottom( -3 );
518 ImplDrawSpinArrow(rRenderContext
, aOutRect
, false);
521 void Calendar::ImplDrawDate(vcl::RenderContext
& rRenderContext
,
522 tools::Long nX
, tools::Long nY
,
523 sal_uInt16 nDay
, sal_uInt16 nMonth
, sal_Int16 nYear
,
524 bool bOther
, sal_Int32 nToday
)
526 Color
const * pTextColor
= nullptr;
527 const OUString
& rDay
= maDayTexts
[nDay
- 1];
528 tools::Rectangle
aDateRect(nX
, nY
, nX
+ mnDayWidth
- 1, nY
+ mnDayHeight
- 1);
533 if ((nDay
== maCurDate
.GetDay()) &&
534 (nMonth
== maCurDate
.GetMonth()) &&
535 (nYear
== maCurDate
.GetYear()))
541 if (mpSelectTable
->find(Date(nDay
, nMonth
, nYear
).GetDate()) != mpSelectTable
->end())
547 pTextColor
= &maSelColor
;
549 pTextColor
= &maOtherColor
;
554 // display background
555 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
558 rRenderContext
.SetLineColor();
559 rRenderContext
.SetFillColor(rStyleSettings
.GetHighlightColor());
560 rRenderContext
.DrawRect(aDateRect
);
564 tools::Long nTextX
= nX
+ (mnDayWidth
- GetTextWidth(rDay
)) - (DAY_OFFX
/ 2);
565 tools::Long nTextY
= nY
+ (mnDayHeight
- GetTextHeight()) / 2;
568 Color aOldColor
= rRenderContext
.GetTextColor();
569 rRenderContext
.SetTextColor(*pTextColor
);
570 rRenderContext
.DrawText(Point(nTextX
, nTextY
), rDay
);
571 rRenderContext
.SetTextColor(aOldColor
);
574 rRenderContext
.DrawText(Point(nTextX
, nTextY
), rDay
);
577 Date
aTodayDate(maCurDate
);
579 aTodayDate
.SetDate(nToday
);
581 aTodayDate
= Date(Date::SYSTEM
);
582 if ((nDay
== aTodayDate
.GetDay()) &&
583 (nMonth
== aTodayDate
.GetMonth()) &&
584 (nYear
== aTodayDate
.GetYear()))
586 rRenderContext
.SetLineColor(rStyleSettings
.GetWindowTextColor());
587 rRenderContext
.SetFillColor();
588 rRenderContext
.DrawRect(aDateRect
);
591 // if needed do FocusRect
592 if (bFocus
&& HasFocus())
593 ShowFocus(aDateRect
);
596 void Calendar::ImplDraw(vcl::RenderContext
& rRenderContext
)
600 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
601 Size
aOutSize(GetOutputSizePixel());
609 sal_Int32 nToday
= Date(Date::SYSTEM
).GetDate();
613 Date aDate
= GetFirstMonth();
614 DayOfWeek eStartDay
= ImplGetWeekStart();
619 for (i
= 0; i
< mnLines
; i
++)
622 rRenderContext
.SetLineColor();
623 rRenderContext
.SetFillColor(rStyleSettings
.GetFaceColor());
624 tools::Rectangle
aTitleRect(0, nY
, aOutSize
.Width() - 1, nY
+ mnDayHeight
- DAY_OFFY
+ TITLE_BORDERY
* 2);
625 rRenderContext
.DrawRect(aTitleRect
);
626 Point
aTopLeft1(aTitleRect
.Left(), aTitleRect
.Top());
627 Point
aTopLeft2(aTitleRect
.Left(), aTitleRect
.Top() + 1);
628 Point
aBottomRight1(aTitleRect
.Right(), aTitleRect
.Bottom());
629 Point
aBottomRight2(aTitleRect
.Right(), aTitleRect
.Bottom() - 1);
630 rRenderContext
.SetLineColor(rStyleSettings
.GetDarkShadowColor());
631 rRenderContext
.DrawLine(aTopLeft1
, Point(aBottomRight1
.X(), aTopLeft1
.Y()));
632 rRenderContext
.SetLineColor(rStyleSettings
.GetLightColor() );
633 rRenderContext
.DrawLine(aTopLeft2
, Point(aBottomRight2
.X(), aTopLeft2
.Y()));
634 rRenderContext
.DrawLine(aTopLeft2
, Point(aTopLeft2
.X(), aBottomRight2
.Y()));
635 rRenderContext
.SetLineColor(rStyleSettings
.GetShadowColor() );
636 rRenderContext
.DrawLine(Point(aTopLeft2
.X(), aBottomRight2
.Y()), aBottomRight2
);
637 rRenderContext
.DrawLine(Point(aBottomRight2
.X(), aTopLeft2
.Y()), aBottomRight2
);
638 rRenderContext
.SetLineColor(rStyleSettings
.GetDarkShadowColor());
639 rRenderContext
.DrawLine(Point(aTopLeft1
.X(), aBottomRight1
.Y()), aBottomRight1
);
640 Point
aSepPos1(0, aTitleRect
.Top() + TITLE_BORDERY
);
641 Point
aSepPos2(0, aTitleRect
.Bottom() - TITLE_BORDERY
);
642 for (j
= 0; j
< mnMonthPerLine
-1; j
++)
644 aSepPos1
.AdjustX(mnMonthWidth
-1 );
645 aSepPos2
.setX( aSepPos1
.X() );
646 rRenderContext
.SetLineColor(rStyleSettings
.GetShadowColor());
647 rRenderContext
.DrawLine(aSepPos1
, aSepPos2
);
648 aSepPos1
.AdjustX( 1 );
649 aSepPos2
.setX( aSepPos1
.X() );
650 rRenderContext
.SetLineColor(rStyleSettings
.GetLightColor());
651 rRenderContext
.DrawLine(aSepPos1
, aSepPos2
);
655 for (j
= 0; j
< mnMonthPerLine
; j
++)
657 nMonth
= aDate
.GetMonth();
658 nYear
= aDate
.GetYear();
660 // display month in title bar
662 nDeltaY
= nY
+ TITLE_BORDERY
;
663 OUString aMonthText
= maCalendarWrapper
.getDisplayName(i18n::CalendarDisplayIndex::MONTH
, nMonth
- 1, 1)
665 + OUString::number(nYear
);
666 tools::Long nMonthTextWidth
= rRenderContext
.GetTextWidth(aMonthText
);
667 tools::Long nMonthOffX1
= 0;
668 tools::Long nMonthOffX2
= 0;
672 nMonthOffX1
= maPrevRect
.Right() + 1;
673 if (j
== mnMonthPerLine
- 1)
674 nMonthOffX2
= aOutSize
.Width() - maNextRect
.Left() + 1;
676 tools::Long nMaxMonthWidth
= mnMonthWidth
- nMonthOffX1
- nMonthOffX2
- 4;
677 if (nMonthTextWidth
> nMaxMonthWidth
)
679 // Abbreviated month name.
680 aMonthText
= maCalendarWrapper
.getDisplayName(i18n::CalendarDisplayIndex::MONTH
, nMonth
- 1, 0)
682 + OUString::number(nYear
);
683 nMonthTextWidth
= rRenderContext
.GetTextWidth(aMonthText
);
685 tools::Long nTempOff
= (mnMonthWidth
- nMonthTextWidth
+ 1) / 2;
686 if (nTempOff
< nMonthOffX1
)
687 nDeltaX
+= nMonthOffX1
+ 1;
690 if (nTempOff
+ nMonthTextWidth
> mnMonthWidth
- nMonthOffX2
)
691 nDeltaX
+= mnMonthWidth
- nMonthOffX2
- nMonthTextWidth
;
695 rRenderContext
.SetTextColor(rStyleSettings
.GetButtonTextColor());
696 rRenderContext
.DrawText(Point(nDeltaX
, nDeltaY
), aMonthText
);
697 rRenderContext
.SetTextColor(rStyleSettings
.GetWindowTextColor());
700 nDayX
= nX
+ mnDaysOffX
;
701 nDayY
= nY
+ mnWeekDayOffY
;
702 nDeltaY
= nDayY
+ mnDayHeight
;
703 rRenderContext
.SetLineColor(rStyleSettings
.GetWindowTextColor());
704 Point
aStartPos(nDayX
, nDeltaY
);
705 rRenderContext
.DrawLine(aStartPos
, Point(nDayX
+ (7 * mnDayWidth
), nDeltaY
));
706 rRenderContext
.DrawTextArray(Point(nDayX
+ mnDayOfWeekAry
[0], nDayY
), maDayOfWeekText
, &(mnDayOfWeekAry
[1]));
709 sal_uInt16 nDaysInMonth
= aDate
.GetDaysInMonth();
710 nDayX
= nX
+ mnDaysOffX
;
711 nDayY
= nY
+ mnDaysOffY
;
712 sal_uInt16 nDayIndex
= static_cast<sal_uInt16
>(aDate
.GetDayOfWeek());
713 nDayIndex
= (nDayIndex
+ (7 - static_cast<sal_uInt16
>(eStartDay
))) % 7;
714 if (i
== 0 && j
== 0)
716 Date aTempDate
= aDate
;
717 aTempDate
.AddDays( -nDayIndex
);
718 for (nDay
= 0; nDay
< nDayIndex
; ++nDay
)
720 nDeltaX
= nDayX
+ (nDay
* mnDayWidth
);
721 ImplDrawDate(rRenderContext
, nDeltaX
, nDayY
, nDay
+ aTempDate
.GetDay(),
722 aTempDate
.GetMonth(), aTempDate
.GetYear(),
726 for (nDay
= 1; nDay
<= nDaysInMonth
; nDay
++)
728 nDeltaX
= nDayX
+ (nDayIndex
* mnDayWidth
);
729 ImplDrawDate(rRenderContext
, nDeltaX
, nDayY
, nDay
, nMonth
, nYear
,
734 nDayY
+= mnDayHeight
;
739 if ((i
== mnLines
- 1) && (j
== mnMonthPerLine
- 1))
741 sal_uInt16 nWeekDay
= static_cast<sal_uInt16
>(aDate
.GetDayOfWeek());
742 nWeekDay
= (nWeekDay
+ (7 - static_cast<sal_uInt16
>(eStartDay
))) % 7;
743 sal_uInt16 nDayCount
= 42 - nDaysInMonth
- nWeekDay
;
744 Date aTempDate
= aDate
;
745 aTempDate
.AddDays( nDaysInMonth
);
746 for (nDay
= 1; nDay
<= nDayCount
; ++nDay
)
748 nDeltaX
= nDayX
+ (nDayIndex
* mnDayWidth
);
749 ImplDrawDate(rRenderContext
, nDeltaX
, nDayY
, nDay
,
750 aTempDate
.GetMonth(), aTempDate
.GetYear(),
755 nDayY
+= mnDayHeight
;
762 aDate
.AddDays( nDaysInMonth
);
770 ImplDrawSpin(rRenderContext
);
773 void Calendar::ImplUpdateDate( const Date
& rDate
)
775 if (IsReallyVisible() && IsUpdateMode())
777 tools::Rectangle
aDateRect(GetDateRect(rDate
));
778 if (!aDateRect
.IsEmpty())
780 Invalidate(aDateRect
);
785 void Calendar::ImplUpdateSelection( IntDateSet
* pOld
)
787 IntDateSet
* pNew
= mpSelectTable
.get();
789 for (auto const& nKey
: *pOld
)
791 if ( pNew
->find(nKey
) == pNew
->end() )
793 Date
aTempDate(nKey
);
794 ImplUpdateDate(aTempDate
);
798 for (auto const& nKey
: *pNew
)
800 if ( pOld
->find(nKey
) == pOld
->end() )
802 Date
aTempDate(nKey
);
803 ImplUpdateDate(aTempDate
);
808 void Calendar::ImplMouseSelect( const Date
& rDate
, sal_uInt16 nHitTest
)
810 std::unique_ptr
<IntDateSet
> pOldSel(new IntDateSet( *mpSelectTable
));
811 Date aOldDate
= maCurDate
;
812 Date aTempDate
= rDate
;
814 if ( !(nHitTest
& CALENDAR_HITTEST_DAY
) )
817 if ( !(nHitTest
& CALENDAR_HITTEST_DAY
) )
818 aTempDate
= maOldCurDate
;
819 if ( aTempDate
!= maCurDate
)
821 maCurDate
= aTempDate
;
822 ImplCalendarSelectDate( mpSelectTable
.get(), aOldDate
, false );
823 ImplCalendarSelectDate( mpSelectTable
.get(), maCurDate
, true );
826 bool bNewSel
= *pOldSel
!= *mpSelectTable
;
827 if ( (maCurDate
!= aOldDate
) || bNewSel
)
831 ImplUpdateSelection( pOldSel
.get() );
832 if ( !bNewSel
|| pOldSel
->find( aOldDate
.GetDate() ) == pOldSel
->end() )
833 ImplUpdateDate( aOldDate
);
834 // assure focus rectangle is displayed again
835 if ( HasFocus() || !bNewSel
836 || mpSelectTable
->find( maCurDate
.GetDate() ) == mpSelectTable
->end() )
837 ImplUpdateDate( maCurDate
);
841 void Calendar::ImplUpdate( bool bCalcNew
)
843 if (IsReallyVisible() && IsUpdateMode())
845 if (bCalcNew
&& !mbCalc
)
849 else if (!mbFormat
&& !mbCalc
)
860 void Calendar::ImplScroll( bool bPrev
)
862 Date aNewFirstMonth
= GetFirstMonth();
866 aNewFirstMonth
.AddDays( -(aNewFirstMonth
.GetDaysInMonth()-1));
869 aNewFirstMonth
.AddDays( aNewFirstMonth
.GetDaysInMonth());
870 SetFirstDate( aNewFirstMonth
);
873 void Calendar::ImplShowMenu( const Point
& rPos
, const Date
& rDate
)
877 Date aOldFirstDate
= GetFirstMonth();
878 ScopedVclPtrInstance
<PopupMenu
> aPopupMenu
;
879 sal_uInt16 nMonthOff
;
880 sal_uInt16 nCurItemId
;
881 sal_uInt16 nYear
= rDate
.GetYear()-1;
884 sal_uInt16 nYearIdCount
= 1000;
886 nMonthOff
= (rDate
.GetYear()-aOldFirstDate
.GetYear())*12;
887 if ( aOldFirstDate
.GetMonth() < rDate
.GetMonth() )
888 nMonthOff
+= rDate
.GetMonth()-aOldFirstDate
.GetMonth();
890 nMonthOff
-= aOldFirstDate
.GetMonth()-rDate
.GetMonth();
892 // construct menu (include years with different months)
893 for ( i
= 0; i
< MENU_YEAR_COUNT
; i
++ )
895 VclPtrInstance
<PopupMenu
> pYearPopupMenu
;
896 for ( j
= 1; j
<= 12; j
++ )
897 pYearPopupMenu
->InsertItem( nYearIdCount
+j
,
898 maCalendarWrapper
.getDisplayName(
899 i18n::CalendarDisplayIndex::MONTH
, j
-1, 1));
900 aPopupMenu
->InsertItem( 10+i
, OUString::number( nYear
+i
) );
901 aPopupMenu
->SetPopupMenu( 10+i
, pYearPopupMenu
);
902 nYearIdCount
+= 1000;
906 nCurItemId
= aPopupMenu
->Execute( this, rPos
);
912 sal_uInt16 nTempMonthOff
= nMonthOff
% 12;
913 sal_uInt16 nTempYearOff
= nMonthOff
/ 12;
914 sal_uInt16 nNewMonth
= nCurItemId
% 1000;
915 sal_uInt16 nNewYear
= nYear
+((nCurItemId
-1000)/1000);
916 if ( nTempMonthOff
< nNewMonth
)
917 nNewMonth
= nNewMonth
- nTempMonthOff
;
921 nNewMonth
= 12-(nTempMonthOff
-nNewMonth
);
923 nNewYear
= nNewYear
- nTempYearOff
;
924 SetFirstDate( Date( 1, nNewMonth
, nNewYear
) );
927 void Calendar::ImplTracking( const Point
& rPos
, bool bRepeat
)
929 Date aTempDate
= maCurDate
;
930 sal_uInt16 nHitTest
= ImplHitTest( rPos
, aTempDate
);
934 mbPrevIn
= (nHitTest
& CALENDAR_HITTEST_PREV
) != 0;
935 mbNextIn
= (nHitTest
& CALENDAR_HITTEST_NEXT
) != 0;
937 if ( bRepeat
&& (mbPrevIn
|| mbNextIn
) )
939 ImplScroll( mbPrevIn
);
943 ImplMouseSelect( aTempDate
, nHitTest
);
946 void Calendar::ImplEndTracking( bool bCancel
)
948 bool bSelection
= false;
949 bool bSpinDown
= mbSpinDown
;
958 if ( maOldFirstDate
!= maFirstDate
)
959 SetFirstDate( maOldFirstDate
);
963 std::unique_ptr
<IntDateSet
> pOldSel(new IntDateSet( *mpSelectTable
));
964 Date aOldDate
= maCurDate
;
965 maCurDate
= maOldCurDate
;
966 *mpSelectTable
= *mpOldSelectTable
;
968 ImplUpdateSelection( pOldSel
.get() );
969 if ( pOldSel
->find( aOldDate
.GetDate() ) == pOldSel
->end() )
970 ImplUpdateDate( aOldDate
);
971 // assure focus rectangle is displayed again
972 if ( HasFocus() || mpSelectTable
->find( maCurDate
.GetDate() ) == mpSelectTable
->end() )
973 ImplUpdateDate( maCurDate
);
982 // determine if we should scroll the visible area
983 if ( !mpSelectTable
->empty() )
985 Date
aFirstSelDate( *mpSelectTable
->begin() );
986 Date
aLastSelDate( *mpSelectTable
->rbegin() );
987 if ( aLastSelDate
< GetFirstMonth() )
989 else if ( GetLastMonth() < aFirstSelDate
)
994 if ( !bCancel
&& ((maCurDate
!= maOldCurDate
) || (*mpOldSelectTable
!= *mpSelectTable
)) )
997 if ( !bSelection
&& (mnWinStyle
& WB_TABSTOP
) && !bCancel
)
1000 mpOldSelectTable
.reset();
1003 void Calendar::MouseButtonDown( const MouseEvent
& rMEvt
)
1005 if ( rMEvt
.IsLeft() && !mbMenuDown
)
1007 Date aTempDate
= maCurDate
;
1008 sal_uInt16 nHitTest
= ImplHitTest( rMEvt
.GetPosPixel(), aTempDate
);
1011 if ( nHitTest
& CALENDAR_HITTEST_MONTHTITLE
)
1012 ImplShowMenu( rMEvt
.GetPosPixel(), aTempDate
);
1015 maOldFirstDate
= maFirstDate
;
1017 mbPrevIn
= (nHitTest
& CALENDAR_HITTEST_PREV
) != 0;
1018 mbNextIn
= (nHitTest
& CALENDAR_HITTEST_NEXT
) != 0;
1019 if ( mbPrevIn
|| mbNextIn
)
1022 ImplScroll( mbPrevIn
);
1023 // it should really read BUTTONREPEAT, therefore do not
1024 // change it to SCROLLREPEAT, check with TH,
1025 // why it could be different (71775)
1026 StartTracking( StartTrackingFlags::ButtonRepeat
);
1030 if ( (rMEvt
.GetClicks() != 2) || !(nHitTest
& CALENDAR_HITTEST_DAY
) )
1032 maOldCurDate
= maCurDate
;
1033 mpOldSelectTable
.reset(new IntDateSet( *mpSelectTable
));
1038 ImplMouseSelect( aTempDate
, nHitTest
);
1040 if (rMEvt
.GetClicks() == 2)
1041 maActivateHdl
.Call(this);
1049 Control::MouseButtonDown( rMEvt
);
1052 void Calendar::Tracking( const TrackingEvent
& rTEvt
)
1054 Point aMousePos
= rTEvt
.GetMouseEvent().GetPosPixel();
1056 if ( rTEvt
.IsTrackingEnded() )
1057 ImplEndTracking( rTEvt
.IsTrackingCanceled() );
1059 ImplTracking( aMousePos
, rTEvt
.IsTrackingRepeat() );
1062 void Calendar::KeyInput( const KeyEvent
& rKEvt
)
1064 Date aNewDate
= maCurDate
;
1066 switch ( rKEvt
.GetKeyCode().GetCode() )
1069 aNewDate
.SetDay( 1 );
1073 aNewDate
.SetDay( aNewDate
.GetDaysInMonth() );
1085 aNewDate
.AddDays( -7 );
1089 aNewDate
.AddDays( 7 );
1094 Date aTempDate
= aNewDate
;
1095 aTempDate
.AddDays( -(aNewDate
.GetDay()+1) );
1096 aNewDate
.AddDays( -aTempDate
.GetDaysInMonth() );
1101 aNewDate
.AddDays( aNewDate
.GetDaysInMonth() );
1108 Control::KeyInput( rKEvt
);
1112 if ( aNewDate
!= maCurDate
)
1114 SetCurDate( aNewDate
);
1118 if (rKEvt
.GetKeyCode().GetCode() == KEY_RETURN
)
1120 if (maActivateHdl
.IsSet())
1121 maActivateHdl
.Call(this);
1123 Control::KeyInput(rKEvt
);
1127 void Calendar::Paint( vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& )
1129 ImplDraw(rRenderContext
);
1132 void Calendar::GetFocus()
1134 ImplUpdateDate( maCurDate
);
1135 Control::GetFocus();
1138 void Calendar::LoseFocus()
1141 Control::LoseFocus();
1144 void Calendar::Resize()
1150 void Calendar::RequestHelp( const HelpEvent
& rHEvt
)
1152 if ( rHEvt
.GetMode() & (HelpEventMode::QUICK
| HelpEventMode::BALLOON
) )
1154 Date aDate
= maCurDate
;
1155 if ( GetDate( ScreenToOutputPixel( rHEvt
.GetMousePosPixel() ), aDate
) )
1157 tools::Rectangle aDateRect
= GetDateRect( aDate
);
1158 Point aPt
= OutputToScreenPixel( aDateRect
.TopLeft() );
1159 aDateRect
.SetLeft( aPt
.X() );
1160 aDateRect
.SetTop( aPt
.Y() );
1161 aPt
= OutputToScreenPixel( aDateRect
.BottomRight() );
1162 aDateRect
.SetRight( aPt
.X() );
1163 aDateRect
.SetBottom( aPt
.Y() );
1165 if ( rHEvt
.GetMode() & HelpEventMode::QUICK
)
1167 maCalendarWrapper
.setGregorianDateTime( aDate
);
1168 sal_uInt16 nWeek
= static_cast<sal_uInt16
>(maCalendarWrapper
.getValue( i18n::CalendarFieldIndex::WEEK_OF_YEAR
));
1169 sal_uInt16 nMonth
= aDate
.GetMonth();
1170 OUString aStr
= maDayText
1172 + OUString::number(aDate
.GetDayOfYear())
1176 + OUString::number(nWeek
);
1177 // if year is not the same, add it
1178 if ( (nMonth
== 12) && (nWeek
== 1) )
1180 aStr
+= ", " + OUString::number(aDate
.GetNextYear());
1182 else if ( (nMonth
== 1) && (nWeek
> 50) )
1184 aStr
+= ", " + OUString::number(aDate
.GetYear()-1);
1186 Help::ShowQuickHelp( this, aDateRect
, aStr
);
1192 Control::RequestHelp( rHEvt
);
1195 void Calendar::Command( const CommandEvent
& rCEvt
)
1197 if ( rCEvt
.GetCommand() == CommandEventId::ContextMenu
)
1199 if ( rCEvt
.IsMouseEvent() )
1201 Date aTempDate
= maCurDate
;
1202 sal_uInt16 nHitTest
= ImplHitTest( rCEvt
.GetMousePosPixel(), aTempDate
);
1203 if ( nHitTest
& CALENDAR_HITTEST_MONTHTITLE
)
1205 ImplShowMenu( rCEvt
.GetMousePosPixel(), aTempDate
);
1210 else if ( rCEvt
.GetCommand() == CommandEventId::Wheel
)
1212 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
1213 if ( pData
->GetMode() == CommandWheelMode::SCROLL
)
1215 tools::Long nNotchDelta
= pData
->GetNotchDelta();
1216 if ( nNotchDelta
< 0 )
1218 while ( nNotchDelta
< 0 )
1226 while ( nNotchDelta
> 0 )
1228 ImplScroll( false );
1237 Control::Command( rCEvt
);
1240 void Calendar::StateChanged( StateChangedType nType
)
1242 Control::StateChanged( nType
);
1244 if ( nType
== StateChangedType::InitShow
)
1248 void Calendar::DataChanged( const DataChangedEvent
& rDCEvt
)
1250 Control::DataChanged( rDCEvt
);
1252 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
1253 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
1254 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
1255 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
1262 void Calendar::Select()
1264 maSelectHdl
.Call( this );
1267 Date
Calendar::GetFirstSelectedDate() const
1269 if ( !mpSelectTable
->empty() )
1270 return Date( *mpSelectTable
->begin() );
1273 Date
aDate( 0, 0, 0 );
1278 void Calendar::SetCurDate( const Date
& rNewDate
)
1280 if ( !rNewDate
.IsValidAndGregorian() )
1283 if ( maCurDate
== rNewDate
)
1286 bool bUpdate
= IsVisible() && IsUpdateMode();
1287 Date aOldDate
= maCurDate
;
1288 maCurDate
= rNewDate
;
1290 ImplCalendarSelectDate( mpSelectTable
.get(), aOldDate
, false );
1291 ImplCalendarSelectDate( mpSelectTable
.get(), maCurDate
, true );
1293 // shift actual date in the visible area
1294 if ( mbFormat
|| (maCurDate
< GetFirstMonth()) )
1295 SetFirstDate( maCurDate
);
1296 else if ( maCurDate
> GetLastMonth() )
1298 Date aTempDate
= GetLastMonth();
1299 tools::Long nDateOff
= maCurDate
-aTempDate
;
1300 if ( nDateOff
< 365 )
1302 Date aFirstDate
= GetFirstMonth();
1303 aFirstDate
.AddDays( aFirstDate
.GetDaysInMonth() );
1305 while ( nDateOff
> aTempDate
.GetDaysInMonth() )
1307 aFirstDate
.AddDays( aFirstDate
.GetDaysInMonth() );
1308 sal_Int32 nDaysInMonth
= aTempDate
.GetDaysInMonth();
1309 aTempDate
.AddDays( nDaysInMonth
);
1310 nDateOff
-= nDaysInMonth
;
1312 SetFirstDate( aFirstDate
);
1315 SetFirstDate( maCurDate
);
1322 ImplUpdateDate( aOldDate
);
1323 ImplUpdateDate( maCurDate
);
1328 void Calendar::SetFirstDate( const Date
& rNewFirstDate
)
1330 if ( maFirstDate
!= rNewFirstDate
)
1332 maFirstDate
= Date( 1, rNewFirstDate
.GetMonth(), rNewFirstDate
.GetYear() );
1337 Date
Calendar::GetFirstMonth() const
1339 if ( maFirstDate
.GetDay() > 1 )
1341 if ( maFirstDate
.GetMonth() == 12 )
1342 return Date( 1, 1, maFirstDate
.GetNextYear() );
1344 return Date( 1, maFirstDate
.GetMonth()+1, maFirstDate
.GetYear() );
1350 Date
Calendar::GetLastMonth() const
1352 Date aDate
= GetFirstMonth();
1353 sal_uInt16 nMonthCount
= GetMonthCount();
1354 for ( sal_uInt16 i
= 0; i
< nMonthCount
; i
++ )
1355 aDate
.AddDays( aDate
.GetDaysInMonth() );
1360 sal_uInt16
Calendar::GetMonthCount() const
1365 return static_cast<sal_uInt16
>(mnMonthPerLine
*mnLines
);
1368 bool Calendar::GetDate( const Point
& rPos
, Date
& rDate
) const
1370 Date aDate
= maCurDate
;
1371 sal_uInt16 nHitTest
= ImplHitTest( rPos
, aDate
);
1372 if ( nHitTest
& CALENDAR_HITTEST_DAY
)
1381 tools::Rectangle
Calendar::GetDateRect( const Date
& rDate
) const
1383 tools::Rectangle aRect
;
1385 if ( mbFormat
|| (rDate
< maFirstDate
) || (rDate
> (maFirstDate
+mnDayCount
)) )
1391 sal_uInt16 nDayIndex
;
1392 Date aDate
= GetFirstMonth();
1394 if ( rDate
< aDate
)
1396 aRect
= GetDateRect( aDate
);
1397 nDaysOff
= aDate
-rDate
;
1398 nX
= nDaysOff
*mnDayWidth
;
1399 aRect
.AdjustLeft( -nX
);
1400 aRect
.AdjustRight( -nX
);
1405 Date aLastDate
= GetLastMonth();
1406 if ( rDate
> aLastDate
)
1408 sal_Int32 nWeekDay
= static_cast<sal_Int32
>(aLastDate
.GetDayOfWeek());
1409 nWeekDay
= (nWeekDay
+(7-ImplGetWeekStart())) % 7;
1410 aLastDate
.AddDays( -nWeekDay
);
1411 aRect
= GetDateRect( aLastDate
);
1412 nDaysOff
= rDate
-aLastDate
;
1414 for ( sal_Int32 i
= 0; i
<= nDaysOff
; i
++ )
1416 if ( aLastDate
== rDate
)
1418 aRect
.AdjustLeft(nDayIndex
*mnDayWidth
);
1419 aRect
.SetRight( aRect
.Left()+mnDayWidth
);
1422 if ( nDayIndex
== 6 )
1425 aRect
.AdjustTop(mnDayHeight
);
1426 aRect
.AdjustBottom(mnDayHeight
);
1436 for ( tools::Long i
= 0; i
< mnLines
; i
++ )
1439 for ( tools::Long j
= 0; j
< mnMonthPerLine
; j
++ )
1441 sal_uInt16 nDaysInMonth
= aDate
.GetDaysInMonth();
1444 if ( (aDate
.GetMonth() == rDate
.GetMonth()) &&
1445 (aDate
.GetYear() == rDate
.GetYear()) )
1447 tools::Long nDayX
= nX
+mnDaysOffX
;
1448 tools::Long nDayY
= nY
+mnDaysOffY
;
1449 nDayIndex
= static_cast<sal_uInt16
>(aDate
.GetDayOfWeek());
1450 nDayIndex
= (nDayIndex
+(7-static_cast<sal_uInt16
>(ImplGetWeekStart()))) % 7;
1451 for ( sal_uInt16 nDay
= 1; nDay
<= nDaysInMonth
; nDay
++ )
1453 if ( nDay
== rDate
.GetDay() )
1455 aRect
.SetLeft( nDayX
+ (nDayIndex
*mnDayWidth
) );
1456 aRect
.SetTop( nDayY
);
1457 aRect
.SetRight( aRect
.Left()+mnDayWidth
);
1458 aRect
.SetBottom( aRect
.Top()+mnDayHeight
);
1461 if ( nDayIndex
== 6 )
1464 nDayY
+= mnDayHeight
;
1471 aDate
.AddDays( nDaysInMonth
);
1475 nY
+= mnMonthHeight
;
1481 void Calendar::EndSelection()
1483 if ( mbDrag
|| mbSpinDown
)
1494 Size
Calendar::CalcWindowSizePixel() const
1497 tools::Long n99TextWidth
= GetTextWidth( "99" );
1498 tools::Long nTextHeight
= GetTextHeight();
1500 aSize
.AdjustWidth((n99TextWidth
+DAY_OFFX
)*7);
1501 aSize
.AdjustWidth(MONTH_BORDERX
*2 );
1503 aSize
.setHeight( nTextHeight
+ TITLE_OFFY
+ (TITLE_BORDERY
*2) );
1504 aSize
.AdjustHeight(nTextHeight
+ WEEKDAY_OFFY
);
1505 aSize
.AdjustHeight((nTextHeight
+DAY_OFFY
)*6);
1506 aSize
.AdjustHeight(MONTH_OFFY
);
1511 Size
Calendar::GetOptimalSize() const
1513 return CalcWindowSizePixel();
1518 class ImplCFieldFloat final
1521 std::unique_ptr
<weld::Builder
> mxBuilder
;
1522 std::unique_ptr
<weld::Container
> mxContainer
;
1523 std::unique_ptr
<weld::Calendar
> mxCalendar
;
1524 std::unique_ptr
<weld::Button
> mxTodayBtn
;
1525 std::unique_ptr
<weld::Button
> mxNoneBtn
;
1528 ImplCFieldFloat(vcl::Window
* pContainer
)
1529 : mxBuilder(Application::CreateInterimBuilder(pContainer
, "svt/ui/calendar.ui", false))
1530 , mxContainer(mxBuilder
->weld_container("Calendar"))
1531 , mxCalendar(mxBuilder
->weld_calendar("date"))
1532 , mxTodayBtn(mxBuilder
->weld_button("today"))
1533 , mxNoneBtn(mxBuilder
->weld_button("none"))
1537 weld::Calendar
* GetCalendar() { return mxCalendar
.get(); }
1538 weld::Button
* EnableTodayBtn(bool bEnable
);
1539 weld::Button
* EnableNoneBtn(bool bEnable
);
1543 mxCalendar
->grab_focus();
1548 struct ImplCFieldFloatWin
: public DockingWindow
1550 explicit ImplCFieldFloatWin(vcl::Window
* pParent
);
1551 virtual void dispose() override
;
1552 virtual ~ImplCFieldFloatWin() override
;
1553 virtual void GetFocus() override
;
1555 VclPtr
<vcl::Window
> mxBox
;
1556 std::unique_ptr
<ImplCFieldFloat
> mxWidget
;
1559 ImplCFieldFloatWin::ImplCFieldFloatWin(vcl::Window
* pParent
)
1560 : DockingWindow(pParent
, "InterimDockParent", "svx/ui/interimdockparent.ui")
1563 setDeferredProperties();
1564 mxWidget
.reset(new ImplCFieldFloat(mxBox
.get()));
1567 ImplCFieldFloatWin::~ImplCFieldFloatWin()
1572 void ImplCFieldFloatWin::dispose()
1575 mxBox
.disposeAndClear();
1576 DockingWindow::dispose();
1579 void ImplCFieldFloatWin::GetFocus()
1581 DockingWindow::GetFocus();
1584 mxWidget
->GrabFocus();
1587 weld::Button
* ImplCFieldFloat::EnableTodayBtn(bool bEnable
)
1589 mxTodayBtn
->set_visible(bEnable
);
1590 return bEnable
? mxTodayBtn
.get() : nullptr;
1593 weld::Button
* ImplCFieldFloat::EnableNoneBtn(bool bEnable
)
1595 mxNoneBtn
->set_visible(bEnable
);
1596 return bEnable
? mxNoneBtn
.get() : nullptr;
1599 CalendarField::CalendarField(vcl::Window
* pParent
, WinBits nWinStyle
)
1600 : DateField(pParent
, nWinStyle
)
1601 , mpFloatWin(nullptr)
1602 , mpTodayBtn(nullptr)
1603 , mpNoneBtn(nullptr)
1609 CalendarField::~CalendarField()
1614 void CalendarField::dispose()
1616 mpTodayBtn
= nullptr;
1617 mpNoneBtn
= nullptr;
1618 mpFloatWin
.disposeAndClear();
1619 DateField::dispose();
1622 IMPL_LINK(CalendarField
, ImplSelectHdl
, weld::Calendar
&, rCalendar
, void)
1624 Date aNewDate
= rCalendar
.get_date();
1626 vcl::Window::GetDockingManager()->EndPopupMode(mpFloatWin
);
1627 mpFloatWin
->EnableDocking(false);
1630 if ( IsEmptyDate() || ( aNewDate
!= GetDate() ) )
1632 SetDate( aNewDate
);
1638 IMPL_LINK(CalendarField
, ImplClickHdl
, weld::Button
&, rBtn
, void)
1640 vcl::Window::GetDockingManager()->EndPopupMode(mpFloatWin
);
1641 mpFloatWin
->EnableDocking(false);
1645 if (&rBtn
== mpTodayBtn
)
1647 Date
aToday( Date::SYSTEM
);
1648 if ( (aToday
!= GetDate()) || IsEmptyDate() )
1655 else if (&rBtn
== mpNoneBtn
)
1657 if ( !IsEmptyDate() )
1666 IMPL_LINK_NOARG(CalendarField
, ImplPopupModeEndHdl
, FloatingWindow
*, void)
1672 bool CalendarField::ShowDropDown( bool bShow
)
1677 mpFloatWin
= VclPtr
<ImplCFieldFloatWin
>::Create( this );
1679 Date aDate
= GetDate();
1680 if ( IsEmptyDate() || !aDate
.IsValidAndGregorian() )
1682 aDate
= Date( Date::SYSTEM
);
1684 weld::Calendar
* pCalendar
= mpFloatWin
->mxWidget
->GetCalendar();
1685 pCalendar
->set_date( aDate
);
1686 pCalendar
->connect_activated(LINK(this, CalendarField
, ImplSelectHdl
));
1687 mpTodayBtn
= mpFloatWin
->mxWidget
->EnableTodayBtn(mbToday
);
1688 mpNoneBtn
= mpFloatWin
->mxWidget
->EnableNoneBtn(mbNone
);
1690 mpTodayBtn
->connect_clicked( LINK( this, CalendarField
, ImplClickHdl
) );
1692 mpNoneBtn
->connect_clicked( LINK( this, CalendarField
, ImplClickHdl
) );
1693 Point
aPos(GetParent()->OutputToScreenPixel(GetPosPixel()));
1694 tools::Rectangle
aRect(aPos
, GetSizePixel());
1695 aRect
.AdjustBottom( -1 );
1696 DockingManager
* pDockingManager
= vcl::Window::GetDockingManager();
1697 mpFloatWin
->EnableDocking(true);
1698 pDockingManager
->SetPopupModeEndHdl(mpFloatWin
, LINK(this, CalendarField
, ImplPopupModeEndHdl
));
1699 pDockingManager
->StartPopupMode(mpFloatWin
, aRect
, FloatWinPopupFlags::Down
| FloatWinPopupFlags::GrabFocus
);
1703 vcl::Window::GetDockingManager()->EndPopupMode(mpFloatWin
);
1704 mpFloatWin
->EnableDocking(false);
1710 void CalendarField::StateChanged( StateChangedType nStateChange
)
1712 DateField::StateChanged( nStateChange
);
1714 if ( ( nStateChange
== StateChangedType::Style
) && GetSubEdit() )
1716 WinBits nAllAlignmentBits
= ( WB_LEFT
| WB_CENTER
| WB_RIGHT
| WB_TOP
| WB_VCENTER
| WB_BOTTOM
);
1717 WinBits nMyAlignment
= GetStyle() & nAllAlignmentBits
;
1718 GetSubEdit()->SetStyle( ( GetSubEdit()->GetStyle() & ~nAllAlignmentBits
) | nMyAlignment
);
1722 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */