update emoji autocorrect entries from po-files
[LibreOffice.git] / svtools / source / control / calendar.cxx
blobd0ae9e4daeebb50c9dba2a854f13eed1c93867c3
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 <rtl/strbuf.hxx>
21 #include <vcl/svapp.hxx>
22 #include <vcl/help.hxx>
23 #include <vcl/menu.hxx>
24 #include <vcl/decoview.hxx>
25 #include <vcl/floatwin.hxx>
26 #include <vcl/button.hxx>
27 #include <vcl/fixed.hxx>
28 #include <vcl/settings.hxx>
29 #include <comphelper/processfactory.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>
36 #include <svtools/svtools.hrc>
37 #include <svtools/svtresid.hxx>
38 #include <svtools/calendar.hxx>
39 #include <boost/scoped_ptr.hpp>
41 #define DAY_OFFX 4
42 #define DAY_OFFY 2
43 #define MONTH_BORDERX 4
44 #define MONTH_OFFY 3
45 #define WEEKNUMBER_OFFX 4
46 #define WEEKDAY_OFFY 3
47 #define TITLE_OFFY 3
48 #define TITLE_BORDERY 2
49 #define SPIN_OFFX 4
50 #define SPIN_OFFY TITLE_BORDERY
52 #define WEEKNUMBER_HEIGHT 85
54 #define CALENDAR_HITTEST_DAY ((sal_uInt16)0x0001)
55 #define CALENDAR_HITTEST_MONTHTITLE ((sal_uInt16)0x0004)
56 #define CALENDAR_HITTEST_PREV ((sal_uInt16)0x0008)
57 #define CALENDAR_HITTEST_NEXT ((sal_uInt16)0x0010)
59 #define MENU_YEAR_COUNT 3
61 using namespace ::com::sun::star;
63 static void ImplCalendarSelectDate( IntDateSet* pTable, const Date& rDate, bool bSelect )
65 if ( bSelect )
66 pTable->insert( rDate.GetDate() );
67 else
68 pTable->erase( rDate.GetDate() );
71 static void ImplCalendarSelectDateRange( IntDateSet* pTable,
72 const Date& rStartDate,
73 const Date& rEndDate,
74 bool bSelect )
76 Date aStartDate = rStartDate;
77 Date aEndDate = rEndDate;
78 if ( aStartDate > aEndDate )
80 Date aTempDate = aStartDate;
81 aStartDate = aEndDate;
82 aEndDate = aTempDate;
85 if ( bSelect )
87 while ( aStartDate <= aEndDate )
89 pTable->insert( aStartDate.GetDate() );
90 ++aStartDate;
93 else
95 for ( IntDateSet::const_iterator it = pTable->begin(); it != pTable->end(); )
97 Date aDate( *it );
98 if ( aDate > aEndDate )
99 break;
101 if ( aDate >= aStartDate )
102 it = pTable->erase(it);
103 else
104 ++it;
109 static void ImplCalendarUnSelectDateRange( IntDateSet* pTable,
110 IntDateSet* pOldTable,
111 const Date& rStartDate,
112 const Date& rEndDate )
114 Date aStartDate = rStartDate;
115 Date aEndDate = rEndDate;
116 if ( aStartDate > aEndDate )
118 Date aTempDate = aStartDate;
119 aStartDate = aEndDate;
120 aEndDate = aTempDate;
123 for ( IntDateSet::const_iterator it = pTable->begin(); it != pTable->end(); )
125 Date aDate( *it );
126 if ( aDate > aEndDate )
127 break;
129 if ( aDate >= aStartDate )
130 it = pTable->erase(it);
131 else
132 ++it;
135 for ( IntDateSet::const_iterator it = pOldTable->begin(); it != pOldTable->end(); ++it )
137 Date aDate( *it );
138 if ( aDate > aEndDate )
139 break;
140 if ( aDate >= aStartDate )
141 pTable->insert( aDate.GetDate() );
145 inline void ImplCalendarClearSelectDate( IntDateSet* pTable )
147 pTable->clear();
150 void Calendar::ImplInit( WinBits nWinStyle )
152 mpSelectTable = new IntDateSet;
153 mpOldSelectTable = NULL;
154 mpRestoreSelectTable = NULL;
155 mpStandardColor = NULL;
156 mpSaturdayColor = NULL;
157 mpSundayColor = NULL;
158 mnDayCount = 0;
159 mnWinStyle = nWinStyle;
160 mnFirstYear = 0;
161 mnLastYear = 0;
162 mnRequestYear = 0;
163 mbCalc = true;
164 mbFormat = true;
165 mbDrag = false;
166 mbSelection = false;
167 mbMultiSelection = false;
168 mbWeekSel = false;
169 mbUnSel = false;
170 mbMenuDown = false;
171 mbSpinDown = false;
172 mbPrevIn = false;
173 mbNextIn = false;
174 mbDirect = false;
175 mbInSelChange = false;
176 mbTravelSelect = false;
177 mbScrollDateRange = false;
178 mbSelLeft = false;
179 mbAllSel = false;
180 mbDropPos = false;
182 OUString aGregorian( "gregorian");
183 maCalendarWrapper.loadCalendar( aGregorian,
184 Application::GetAppLocaleDataWrapper().getLanguageTag().getLocale());
185 if (maCalendarWrapper.getUniqueID() != aGregorian)
187 SAL_WARN( "svtools.control", "Calendar::ImplInit: No ``gregorian'' calendar available for locale ``"
188 << Application::GetAppLocaleDataWrapper().getLanguageTag().getBcp47()
189 << "'' and other calendars aren't supported. Using en-US fallback." );
191 /* If we ever wanted to support other calendars than Gregorian a lot of
192 * rewrite would be necessary to internally replace use of class Date
193 * with proper class CalendarWrapper methods, get rid of fixed 12
194 * months, fixed 7 days, ... */
195 maCalendarWrapper.loadCalendar( aGregorian, lang::Locale( "en", "US", ""));
198 SetFirstDate( maCurDate );
199 ImplCalendarSelectDate( mpSelectTable, maCurDate, true );
201 // Sonstige Strings erzeugen
202 maDayText = SVT_RESSTR(STR_SVT_CALENDAR_DAY);
203 maWeekText = SVT_RESSTR(STR_SVT_CALENDAR_WEEK);
205 // Tagestexte anlegen
206 for (sal_Int32 i = 0; i < 31; ++i)
207 maDayTexts[i] = OUString::number(i+1);
209 maDragScrollTimer.SetTimeoutHdl( LINK( this, Calendar, ScrollHdl ) );
210 maDragScrollTimer.SetTimeout( GetSettings().GetMouseSettings().GetScrollRepeat() );
211 mnDragScrollHitTest = 0;
213 ImplInitSettings();
216 void Calendar::ApplySettings(vcl::RenderContext& rRenderContext)
218 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
219 maSelColor = rStyleSettings.GetHighlightTextColor();
220 SetPointFont(rRenderContext, rStyleSettings.GetToolFont());
221 rRenderContext.SetTextColor(rStyleSettings.GetFieldTextColor());
222 rRenderContext.SetBackground(Wallpaper(rStyleSettings.GetFieldColor()));
225 void Calendar::ImplInitSettings()
227 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
228 maSelColor = rStyleSettings.GetHighlightTextColor();
229 SetPointFont(*this, rStyleSettings.GetToolFont());
230 SetTextColor(rStyleSettings.GetFieldTextColor());
231 SetBackground(Wallpaper(rStyleSettings.GetFieldColor()));
234 Calendar::Calendar( vcl::Window* pParent, WinBits nWinStyle ) :
235 Control( pParent, nWinStyle & (WB_TABSTOP | WB_GROUP | WB_BORDER | WB_3DLOOK | WB_RANGESELECT | WB_MULTISELECT) ),
236 maCalendarWrapper( Application::GetAppLocaleDataWrapper().getComponentContext() ),
237 maOldFormatFirstDate( 0, 0, 1900 ),
238 maOldFormatLastDate( 0, 0, 1900 ),
239 maFirstDate( 0, 0, 1900 ),
240 maOldFirstDate( 0, 0, 1900 ),
241 maCurDate( Date::SYSTEM ),
242 maOldCurDate( 0, 0, 1900 ),
243 maAnchorDate( maCurDate ),
244 maDropDate( 0, 0, 1900 )
246 ImplInit( nWinStyle );
249 Calendar::~Calendar()
251 disposeOnce();
254 void Calendar::dispose()
256 delete mpStandardColor;
257 delete mpSaturdayColor;
258 delete mpSundayColor;
260 delete mpSelectTable;
261 delete mpOldSelectTable;
262 delete mpRestoreSelectTable;
263 Control::dispose();
266 DayOfWeek Calendar::ImplGetWeekStart() const
268 // Map i18n::Weekdays to Date DayOfWeek
269 DayOfWeek eDay;
270 sal_Int16 nDay = maCalendarWrapper.getFirstDayOfWeek();
271 switch (nDay)
273 case i18n::Weekdays::SUNDAY :
274 eDay = SUNDAY;
275 break;
276 case i18n::Weekdays::MONDAY :
277 eDay = MONDAY;
278 break;
279 case i18n::Weekdays::TUESDAY :
280 eDay = TUESDAY;
281 break;
282 case i18n::Weekdays::WEDNESDAY :
283 eDay = WEDNESDAY;
284 break;
285 case i18n::Weekdays::THURSDAY :
286 eDay = THURSDAY;
287 break;
288 case i18n::Weekdays::FRIDAY :
289 eDay = FRIDAY;
290 break;
291 case i18n::Weekdays::SATURDAY :
292 eDay = SATURDAY;
293 break;
294 default:
295 SAL_WARN( "svtools.control", "Calendar::ImplGetWeekStart: broken i18n Gregorian calendar (getFirstDayOfWeek())");
296 eDay = SUNDAY;
298 return eDay;
301 void Calendar::ImplGetWeekFont( vcl::Font& rFont ) const
303 // weeknumber is displayed in WEEKNUMBER_HEIGHT%-Fontheight
304 Size aFontSize = rFont.GetSize();
305 aFontSize.Height() *= WEEKNUMBER_HEIGHT;
306 aFontSize.Height() /= 100;
307 rFont.SetSize( aFontSize );
308 rFont.SetWeight( WEIGHT_NORMAL );
311 void Calendar::ImplFormat()
313 if ( !mbFormat )
314 return;
316 if ( mbCalc )
318 Size aOutSize = GetOutputSizePixel();
320 if ( (aOutSize.Width() <= 1) || (aOutSize.Height() <= 1) )
321 return;
323 OUString a99Text("99");
325 vcl::Font aOldFont = GetFont();
327 // Wochenanzeige beruecksichtigen
328 if ( mnWinStyle & WB_WEEKNUMBER )
330 vcl::Font aTempFont = aOldFont;
331 ImplGetWeekFont( aTempFont );
332 SetFont( aTempFont );
333 mnWeekWidth = GetTextWidth( a99Text )+WEEKNUMBER_OFFX;
334 SetFont( aOldFont );
336 else
337 mnWeekWidth = 0;
339 if ( mnWinStyle & WB_BOLDTEXT )
341 vcl::Font aFont = aOldFont;
342 if ( aFont.GetWeight() < WEIGHT_BOLD )
343 aFont.SetWeight( WEIGHT_BOLD );
344 else
345 aFont.SetWeight( WEIGHT_NORMAL );
346 SetFont( aFont );
349 long n99TextWidth = GetTextWidth( a99Text );
350 long nTextHeight = GetTextHeight();
352 // calculate width and x-position
353 mnDayWidth = n99TextWidth+DAY_OFFX;
354 mnMonthWidth = mnDayWidth*7;
355 mnMonthWidth += mnWeekWidth;
356 mnMonthWidth += MONTH_BORDERX*2;
357 mnMonthPerLine = aOutSize.Width() / mnMonthWidth;
358 if ( !mnMonthPerLine )
359 mnMonthPerLine = 1;
360 long nOver = ((aOutSize.Width()-(mnMonthPerLine*mnMonthWidth)) / mnMonthPerLine);
361 mnMonthWidth += nOver;
362 mnDaysOffX = MONTH_BORDERX;
363 mnDaysOffX += nOver/2;
364 mnDaysOffX += mnWeekWidth;
366 // calculate height and y-position
367 mnDayHeight = nTextHeight + DAY_OFFY;
368 mnWeekDayOffY = nTextHeight + TITLE_OFFY + (TITLE_BORDERY*2);
369 mnDaysOffY = mnWeekDayOffY + nTextHeight + WEEKDAY_OFFY;
370 mnMonthHeight = (mnDayHeight*6) + mnDaysOffY;
371 mnMonthHeight += MONTH_OFFY;
372 mnLines = aOutSize.Height() / mnMonthHeight;
373 if ( !mnLines )
374 mnLines = 1;
375 mnMonthHeight += (aOutSize.Height()-(mnLines*mnMonthHeight)) / mnLines;
377 // calculate spinfields
378 long nSpinSize = nTextHeight+TITLE_BORDERY-SPIN_OFFY;
379 maPrevRect.Left() = SPIN_OFFX;
380 maPrevRect.Top() = SPIN_OFFY;
381 maPrevRect.Right() = maPrevRect.Left()+nSpinSize;
382 maPrevRect.Bottom() = maPrevRect.Top()+nSpinSize;
383 maNextRect.Left() = aOutSize.Width()-SPIN_OFFX-nSpinSize-1;
384 maNextRect.Top() = SPIN_OFFY;
385 maNextRect.Right() = maNextRect.Left()+nSpinSize;
386 maNextRect.Bottom() = maNextRect.Top()+nSpinSize;
388 if ( mnWinStyle & WB_BOLDTEXT )
389 SetFont( aOldFont );
391 // Calculate DayOfWeekText (gets displayed in a narrow font)
392 maDayOfWeekText.clear();
393 long nStartOffX = 0;
394 sal_Int16 nDay = maCalendarWrapper.getFirstDayOfWeek();
395 for ( sal_Int16 nDayOfWeek = 0; nDayOfWeek < 7; nDayOfWeek++ )
397 // Use narrow name.
398 OUString aDayOfWeek( maCalendarWrapper.getDisplayName(
399 i18n::CalendarDisplayIndex::DAY, nDay, 2));
400 long nOffX = (mnDayWidth-GetTextWidth( aDayOfWeek ))/2;
401 if ( mnWinStyle & WB_BOLDTEXT )
402 nOffX++;
403 if ( !nDayOfWeek )
404 nStartOffX = nOffX;
405 else
406 nOffX -= nStartOffX;
407 nOffX += nDayOfWeek * mnDayWidth;
408 mnDayOfWeekAry[nDayOfWeek] = nOffX;
409 maDayOfWeekText += aDayOfWeek;
410 nDay++;
411 nDay %= 7;
414 mbCalc = false;
417 // calculate number of days
419 DayOfWeek eStartDay = ImplGetWeekStart();
421 sal_uInt16 nWeekDay;
422 Date aTempDate = GetFirstMonth();
423 maFirstDate = aTempDate;
424 nWeekDay = (sal_uInt16)aTempDate.GetDayOfWeek();
425 nWeekDay = (nWeekDay+(7-(sal_uInt16)eStartDay)) % 7;
426 maFirstDate -= (sal_uLong)nWeekDay;
427 mnDayCount = nWeekDay;
428 sal_uInt16 nDaysInMonth;
429 sal_uInt16 nMonthCount = (sal_uInt16)(mnMonthPerLine*mnLines);
430 for ( sal_uInt16 i = 0; i < nMonthCount; i++ )
432 nDaysInMonth = aTempDate.GetDaysInMonth();
433 mnDayCount += nDaysInMonth;
434 aTempDate += nDaysInMonth;
436 Date aTempDate2 = aTempDate;
437 --aTempDate2;
438 nDaysInMonth = aTempDate2.GetDaysInMonth();
439 aTempDate2 -= nDaysInMonth-1;
440 nWeekDay = (sal_uInt16)aTempDate2.GetDayOfWeek();
441 nWeekDay = (nWeekDay+(7-(sal_uInt16)eStartDay)) % 7;
442 mnDayCount += 42-nDaysInMonth-nWeekDay;
444 // determine colours
445 maOtherColor = Color( COL_LIGHTGRAY );
446 if ( maOtherColor.IsRGBEqual( GetBackground().GetColor() ) )
447 maOtherColor.SetColor( COL_GRAY );
449 Date aLastDate = GetLastDate();
450 if ( (maOldFormatLastDate != aLastDate) ||
451 (maOldFormatFirstDate != maFirstDate) )
453 maOldFormatFirstDate = maFirstDate;
454 maOldFormatLastDate = aLastDate;
455 DateRangeChanged();
458 // get DateInfo
459 sal_uInt16 nNewFirstYear = maFirstDate.GetYear();
460 sal_uInt16 nNewLastYear = GetLastDate().GetYear();
461 if ( mnFirstYear )
463 if ( nNewFirstYear < mnFirstYear )
465 for ( mnRequestYear = nNewFirstYear; mnRequestYear < mnFirstYear; mnRequestYear++ )
466 RequestDateInfo();
467 mnFirstYear = nNewFirstYear;
469 if ( nNewLastYear > mnLastYear )
471 for ( mnRequestYear = mnLastYear; mnRequestYear < nNewLastYear; mnRequestYear++ )
472 RequestDateInfo();
473 mnLastYear = nNewLastYear;
476 else
478 for ( mnRequestYear = nNewFirstYear; mnRequestYear < nNewLastYear; mnRequestYear++ )
479 RequestDateInfo();
480 mnFirstYear = nNewFirstYear;
481 mnLastYear = nNewLastYear;
483 mnRequestYear = 0;
485 mbFormat = false;
488 sal_uInt16 Calendar::ImplHitTest( const Point& rPos, Date& rDate ) const
490 if ( mbFormat )
491 return 0;
493 if ( maPrevRect.IsInside( rPos ) )
494 return CALENDAR_HITTEST_PREV;
495 else if ( maNextRect.IsInside( rPos ) )
496 return CALENDAR_HITTEST_NEXT;
498 long nY;
499 long nOffX;
500 sal_uInt16 nDay;
501 DayOfWeek eStartDay = ImplGetWeekStart();
503 rDate = GetFirstMonth();
504 nY = 0;
505 for ( long i = 0; i < mnLines; i++ )
507 if ( rPos.Y() < nY )
508 return 0;
510 long nX = 0;
511 long nYMonth = nY+mnMonthHeight;
512 for ( long j = 0; j < mnMonthPerLine; j++ )
514 if ( (rPos.X() < nX) && (rPos.Y() < nYMonth) )
515 return 0;
517 sal_uInt16 nDaysInMonth = rDate.GetDaysInMonth();
519 // matching month was found
520 if ( (rPos.X() > nX) && (rPos.Y() < nYMonth) &&
521 (rPos.X() < nX+mnMonthWidth) )
523 if ( rPos.Y() < (nY+(TITLE_BORDERY*2)+mnDayHeight))
524 return CALENDAR_HITTEST_MONTHTITLE;
525 else
527 long nDayX = nX+mnDaysOffX;
528 long nDayY = nY+mnDaysOffY;
529 if ( rPos.Y() < nDayY )
530 return 0;
531 sal_uInt16 nDayIndex = (sal_uInt16)rDate.GetDayOfWeek();
532 nDayIndex = (nDayIndex+(7-(sal_uInt16)eStartDay)) % 7;
533 if ( (i == 0) && (j == 0) )
535 Date aTempDate = rDate;
536 aTempDate -= nDayIndex;
537 for ( nDay = 0; nDay < nDayIndex; nDay++ )
539 nOffX = nDayX + (nDay*mnDayWidth);
540 if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) &&
541 (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) )
543 rDate = aTempDate;
544 rDate += nDay;
545 return CALENDAR_HITTEST_DAY;
549 for ( nDay = 1; nDay <= nDaysInMonth; nDay++ )
551 if ( rPos.Y() < nDayY )
553 rDate += nDayIndex;
554 return 0;
556 nOffX = nDayX + (nDayIndex*mnDayWidth);
557 if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) &&
558 (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) )
560 rDate += nDay-1;
561 return CALENDAR_HITTEST_DAY;
563 if ( nDayIndex == 6 )
565 nDayIndex = 0;
566 nDayY += mnDayHeight;
568 else
569 nDayIndex++;
571 if ( (i == mnLines-1) && (j == mnMonthPerLine-1) )
573 sal_uInt16 nWeekDay = (sal_uInt16)rDate.GetDayOfWeek();
574 nWeekDay = (nWeekDay+(7-(sal_uInt16)eStartDay)) % 7;
575 sal_uInt16 nDayCount = 42-nDaysInMonth-nWeekDay;
576 Date aTempDate = rDate;
577 aTempDate += nDaysInMonth;
578 for ( nDay = 1; nDay <= nDayCount; nDay++ )
580 if ( rPos.Y() < nDayY )
582 rDate += nDayIndex;
583 return 0;
585 nOffX = nDayX + (nDayIndex*mnDayWidth);
586 if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) &&
587 (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) )
589 rDate = aTempDate;
590 rDate += nDay-1;
591 return CALENDAR_HITTEST_DAY;
593 if ( nDayIndex == 6 )
595 nDayIndex = 0;
596 nDayY += mnDayHeight;
598 else
599 nDayIndex++;
605 rDate += nDaysInMonth;
606 nX += mnMonthWidth;
609 nY += mnMonthHeight;
612 return 0;
615 namespace
618 static void ImplDrawSpinArrow(vcl::RenderContext& rRenderContext, const Rectangle& rRect, bool bPrev)
620 long i;
621 long n;
622 long nLines;
623 long nHeight = rRect.GetHeight();
624 long nWidth = rRect.GetWidth();
625 if (nWidth < nHeight)
626 n = nWidth;
627 else
628 n = nHeight;
629 if (!(n & 0x01))
630 n--;
631 nLines = n/2;
633 Rectangle aRect(Point( rRect.Left() + (nWidth / 2) - (nLines / 2),
634 rRect.Top() + (nHeight / 2) ),
635 Size(1, 1));
636 if (!bPrev)
638 aRect.Left() += nLines;
639 aRect.Right() += nLines;
642 rRenderContext.DrawRect(aRect);
643 for (i = 0; i < nLines; i++)
645 if (bPrev)
647 aRect.Left()++;
648 aRect.Right()++;
650 else
652 aRect.Left()--;
653 aRect.Right()--;
655 aRect.Top()--;
656 aRect.Bottom()++;
657 rRenderContext.DrawRect(aRect);
661 } //end anonymous namespace
663 void Calendar::ImplDrawSpin(vcl::RenderContext& rRenderContext, bool bDrawPrev, bool bDrawNext )
665 if (!bDrawPrev && !bDrawNext)
666 return;
668 rRenderContext.SetLineColor();
669 rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetButtonTextColor());
670 if (bDrawPrev)
672 Rectangle aOutRect = maPrevRect;
673 aOutRect.Left() += 3;
674 aOutRect.Top() += 3;
675 aOutRect.Right() -= 3;
676 aOutRect.Bottom() -= 3;
677 ImplDrawSpinArrow(rRenderContext, aOutRect, true);
679 if (bDrawNext)
681 Rectangle aOutRect = maNextRect;
682 aOutRect.Left() += 3;
683 aOutRect.Top() += 3;
684 aOutRect.Right() -= 3;
685 aOutRect.Bottom() -= 3;
686 ImplDrawSpinArrow(rRenderContext, aOutRect, false);
690 void Calendar::ImplDrawDate(vcl::RenderContext& rRenderContext,
691 long nX, long nY,
692 sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear,
693 DayOfWeek eDayOfWeek,
694 bool bBack, bool bOther, sal_uLong nToday )
696 Color* pTextColor = NULL;
697 const OUString& rDay = maDayTexts[nDay - 1];
698 Rectangle aDateRect(nX, nY, nX + mnDayWidth - 1, nY + mnDayHeight - 1);
700 bool bSel = false;
701 bool bFocus = false;
702 // actual day
703 if ((nDay == maCurDate.GetDay()) &&
704 (nMonth == maCurDate.GetMonth()) &&
705 (nYear == maCurDate.GetYear()))
707 bFocus = true;
709 if (mpSelectTable)
711 if (mpSelectTable->find(Date(nDay, nMonth, nYear).GetDate()) != mpSelectTable->end())
712 bSel = true;
715 // get textcolour
716 if (bSel)
717 pTextColor = &maSelColor;
718 else if (bOther)
719 pTextColor = &maOtherColor;
720 else
722 if (eDayOfWeek == SATURDAY)
723 pTextColor = mpSaturdayColor;
724 else if (eDayOfWeek == SUNDAY)
725 pTextColor = mpSundayColor;
726 if (!pTextColor)
727 pTextColor = mpStandardColor;
730 if (bFocus)
731 HideFocus();
733 // display background
734 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
735 if (bSel || bBack)
737 if (bSel)
739 rRenderContext.SetLineColor();
740 rRenderContext.SetFillColor(rStyleSettings.GetHighlightColor());
741 rRenderContext.DrawRect(aDateRect);
743 else
744 rRenderContext.Erase(aDateRect);
747 // display text
748 long nTextX = nX + (mnDayWidth - GetTextWidth(rDay)) - (DAY_OFFX / 2);
749 long nTextY = nY + (mnDayHeight - GetTextHeight()) / 2;
750 if (pTextColor)
752 Color aOldColor = rRenderContext.GetTextColor();
753 rRenderContext.SetTextColor(*pTextColor);
754 rRenderContext.DrawText(Point(nTextX, nTextY), rDay);
755 rRenderContext.SetTextColor(aOldColor);
757 else
758 rRenderContext.DrawText(Point(nTextX, nTextY), rDay);
760 // today
761 Date aTodayDate(maCurDate);
762 if (nToday)
763 aTodayDate.SetDate(nToday);
764 else
765 aTodayDate = Date(Date::SYSTEM);
766 if ((nDay == aTodayDate.GetDay()) &&
767 (nMonth == aTodayDate.GetMonth()) &&
768 (nYear == aTodayDate.GetYear()))
770 rRenderContext.SetLineColor(rStyleSettings.GetWindowTextColor());
771 rRenderContext.SetFillColor();
772 rRenderContext.DrawRect(aDateRect);
775 // if needed do FocusRect
776 if (bFocus && HasFocus())
777 ShowFocus(aDateRect);
779 if (mbDropPos && maDropDate == Date(nDay, nMonth, nYear))
780 ImplInvertDropPos();
783 void Calendar::ImplDraw(vcl::RenderContext& rRenderContext, bool bPaint)
785 ImplFormat();
787 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
788 Size aOutSize(GetOutputSizePixel());
789 long i;
790 long j;
791 long nY;
792 long nDeltaX;
793 long nDeltaY;
794 long nDayX;
795 long nDayY;
796 sal_uLong nToday = Date(Date::SYSTEM).GetDate();
797 sal_uInt16 nDay;
798 sal_uInt16 nMonth;
799 sal_uInt16 nYear;
800 Date aDate = GetFirstMonth();
801 DayOfWeek eStartDay = ImplGetWeekStart();
803 HideFocus();
805 nY = 0;
806 for (i = 0; i < mnLines; i++)
808 // display title bar
809 rRenderContext.SetLineColor();
810 rRenderContext.SetFillColor(rStyleSettings.GetFaceColor());
811 Rectangle aTitleRect(0, nY, aOutSize.Width() - 1, nY + mnDayHeight - DAY_OFFY + TITLE_BORDERY * 2);
812 if (!bPaint)
814 Rectangle aTempRect(1, aTitleRect.Top() + TITLE_BORDERY,
815 aOutSize.Width() - 2,
816 aTitleRect.Bottom() - TITLE_BORDERY);
817 if (!i)
819 aTempRect.Left() = maPrevRect.Right() + 1;
820 aTempRect.Right() = maNextRect.Left() - 1;
822 rRenderContext.DrawRect(aTempRect);
824 else
826 rRenderContext.DrawRect(aTitleRect);
827 Point aTopLeft1(aTitleRect.Left(), aTitleRect.Top());
828 Point aTopLeft2(aTitleRect.Left(), aTitleRect.Top() + 1);
829 Point aBottomRight1(aTitleRect.Right(), aTitleRect.Bottom());
830 Point aBottomRight2(aTitleRect.Right(), aTitleRect.Bottom() - 1);
831 rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
832 rRenderContext.DrawLine(aTopLeft1, Point(aBottomRight1.X(), aTopLeft1.Y()));
833 rRenderContext.SetLineColor(rStyleSettings.GetLightColor() );
834 rRenderContext.DrawLine(aTopLeft2, Point(aBottomRight2.X(), aTopLeft2.Y()));
835 rRenderContext.DrawLine(aTopLeft2, Point(aTopLeft2.X(), aBottomRight2.Y()));
836 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor() );
837 rRenderContext.DrawLine(Point(aTopLeft2.X(), aBottomRight2.Y()), aBottomRight2);
838 rRenderContext.DrawLine(Point(aBottomRight2.X(), aTopLeft2.Y()), aBottomRight2);
839 rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
840 rRenderContext.DrawLine(Point(aTopLeft1.X(), aBottomRight1.Y()), aBottomRight1);
842 Point aSepPos1(0, aTitleRect.Top() + TITLE_BORDERY);
843 Point aSepPos2(0, aTitleRect.Bottom() - TITLE_BORDERY);
844 for (j = 0; j < mnMonthPerLine-1; j++)
846 aSepPos1.X() += mnMonthWidth-1;
847 aSepPos2.X() = aSepPos1.X();
848 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
849 rRenderContext.DrawLine(aSepPos1, aSepPos2);
850 aSepPos1.X()++;
851 aSepPos2.X() = aSepPos1.X();
852 rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
853 rRenderContext.DrawLine(aSepPos1, aSepPos2);
856 long nX = 0;
857 for (j = 0; j < mnMonthPerLine; j++)
859 nMonth = aDate.GetMonth();
860 nYear = aDate.GetYear();
862 // display month in title bar
863 nDeltaX = nX;
864 nDeltaY = nY + TITLE_BORDERY;
865 OUString aMonthText(maCalendarWrapper.getDisplayName(i18n::CalendarDisplayIndex::MONTH, nMonth - 1, 1));
866 aMonthText += " ";
867 aMonthText += OUString::number(nYear);
868 long nMonthTextWidth = rRenderContext.GetTextWidth(aMonthText);
869 long nMonthOffX1 = 0;
870 long nMonthOffX2 = 0;
871 if (i == 0)
873 if (j == 0)
874 nMonthOffX1 = maPrevRect.Right() + 1;
875 if (j == mnMonthPerLine - 1)
876 nMonthOffX2 = aOutSize.Width() - maNextRect.Left() + 1;
878 long nMaxMonthWidth = mnMonthWidth - nMonthOffX1 - nMonthOffX2 - 4;
879 if (nMonthTextWidth > nMaxMonthWidth)
881 // Abbreviated month name.
882 aMonthText = maCalendarWrapper.getDisplayName(i18n::CalendarDisplayIndex::MONTH, nMonth - 1, 0);
883 aMonthText += " ";
884 aMonthText += OUString::number(nYear);
885 nMonthTextWidth = rRenderContext.GetTextWidth(aMonthText);
887 long nTempOff = (mnMonthWidth - nMonthTextWidth + 1) / 2;
888 if (nTempOff < nMonthOffX1)
889 nDeltaX += nMonthOffX1 + 1;
890 else
892 if (nTempOff + nMonthTextWidth > mnMonthWidth - nMonthOffX2)
893 nDeltaX += mnMonthWidth - nMonthOffX2 - nMonthTextWidth;
894 else
895 nDeltaX += nTempOff;
897 rRenderContext.SetTextColor(rStyleSettings.GetButtonTextColor());
898 rRenderContext.DrawText(Point(nDeltaX, nDeltaY), aMonthText);
899 rRenderContext.SetTextColor(rStyleSettings.GetWindowTextColor());
901 // display week bar
902 if (bPaint)
904 nDayX = nX + mnDaysOffX;
905 nDayY = nY + mnWeekDayOffY;
906 nDeltaY = nDayY + mnDayHeight;
907 rRenderContext.SetLineColor(rStyleSettings.GetWindowTextColor());
908 Point aStartPos(nDayX, nDeltaY);
909 if (mnWinStyle & WB_WEEKNUMBER)
910 aStartPos.X() -= WEEKNUMBER_OFFX - 2;
911 rRenderContext.DrawLine(aStartPos, Point(nDayX + (7 * mnDayWidth), nDeltaY));
912 rRenderContext.DrawTextArray(Point(nDayX + mnDayOfWeekAry[0], nDayY), maDayOfWeekText, &(mnDayOfWeekAry[1]));
915 // display weeknumbers
916 if (mnWinStyle & WB_WEEKNUMBER)
918 nDayX = nX + mnDaysOffX;
919 nDayY = nY + mnWeekDayOffY;
920 nDeltaY = nDayY + mnDayHeight;
921 long nMonthHeight = mnDayHeight * 6;
922 if (bPaint)
924 rRenderContext.DrawLine(Point(nDayX - WEEKNUMBER_OFFX + 2, nDeltaY),
925 Point(nDayX - WEEKNUMBER_OFFX + 2, nDeltaY + nMonthHeight));
927 else
929 rRenderContext.Erase(Rectangle(nDayX - mnWeekWidth - WEEKNUMBER_OFFX, nDeltaY,
930 nDayX - WEEKNUMBER_OFFX - 1, nDeltaY + nMonthHeight));
932 vcl::Font aOldFont = rRenderContext.GetFont();
933 vcl::Font aTempFont = aOldFont;
934 ImplGetWeekFont(aTempFont);
935 rRenderContext.SetFont(aTempFont);
936 nDayX -= mnWeekWidth;
937 nDayY = nY + mnDaysOffY;
938 maCalendarWrapper.setGregorianDateTime(aDate);
939 for (sal_uInt16 nWeekCount = 0; nWeekCount < 6; ++nWeekCount)
941 sal_Int32 nWeek = maCalendarWrapper.getValue(i18n::CalendarFieldIndex::WEEK_OF_YEAR);
942 OUString aWeekText(OUString::number(nWeek));
943 long nOffX = (mnWeekWidth - WEEKNUMBER_OFFX) - rRenderContext.GetTextWidth(aWeekText);
944 long nOffY = (mnDayHeight - GetTextHeight()) / 2;
945 rRenderContext.DrawText(Point(nDayX + nOffX, nDayY + nOffY), aWeekText);
946 nDayY += mnDayHeight;
947 maCalendarWrapper.addValue(i18n::CalendarFieldIndex::DAY_OF_MONTH, 7);
949 rRenderContext.SetFont(aOldFont);
952 // display days
953 sal_uInt16 nDaysInMonth = aDate.GetDaysInMonth();
954 nDayX = nX + mnDaysOffX;
955 nDayY = nY + mnDaysOffY;
956 if (!bPaint)
958 Rectangle aClearRect(nDayX, nDayY,
959 nDayX + (7 * mnDayWidth) - 1, nDayY + (6 * mnDayHeight) - 1);
960 rRenderContext.Erase(aClearRect);
962 sal_uInt16 nDayIndex = (sal_uInt16) aDate.GetDayOfWeek();
963 nDayIndex = (nDayIndex + (7 - (sal_uInt16)eStartDay)) % 7;
964 if (i == 0 && j == 0)
966 Date aTempDate = aDate;
967 aTempDate -= nDayIndex;
968 for (nDay = 0; nDay < nDayIndex; ++nDay)
970 nDeltaX = nDayX + (nDay * mnDayWidth);
971 ImplDrawDate(rRenderContext, nDeltaX, nDayY, nDay + aTempDate.GetDay(),
972 aTempDate.GetMonth(), aTempDate.GetYear(),
973 (DayOfWeek)((nDay + (sal_uInt16)eStartDay) % 7), false, true, nToday);
976 for (nDay = 1; nDay <= nDaysInMonth; nDay++)
978 nDeltaX = nDayX + (nDayIndex * mnDayWidth);
979 ImplDrawDate(rRenderContext, nDeltaX, nDayY, nDay, nMonth, nYear,
980 (DayOfWeek)((nDayIndex + (sal_uInt16)eStartDay) % 7),
981 false, false, nToday);
982 if (nDayIndex == 6)
984 nDayIndex = 0;
985 nDayY += mnDayHeight;
987 else
988 nDayIndex++;
990 if ((i == mnLines - 1) && (j == mnMonthPerLine - 1))
992 sal_uInt16 nWeekDay = (sal_uInt16)aDate.GetDayOfWeek();
993 nWeekDay = (nWeekDay + (7 - (sal_uInt16)eStartDay)) % 7;
994 sal_uInt16 nDayCount = 42 - nDaysInMonth - nWeekDay;
995 Date aTempDate = aDate;
996 aTempDate += nDaysInMonth;
997 for (nDay = 1; nDay <= nDayCount; ++nDay)
999 nDeltaX = nDayX + (nDayIndex * mnDayWidth);
1000 ImplDrawDate(rRenderContext, nDeltaX, nDayY, nDay,
1001 aTempDate.GetMonth(), aTempDate.GetYear(),
1002 (DayOfWeek)((nDayIndex + (sal_uInt16)eStartDay) % 7),
1003 false, true, nToday);
1004 if (nDayIndex == 6)
1006 nDayIndex = 0;
1007 nDayY += mnDayHeight;
1009 else
1010 nDayIndex++;
1014 aDate += nDaysInMonth;
1015 nX += mnMonthWidth;
1018 nY += mnMonthHeight;
1021 // draw spin buttons
1022 if (bPaint)
1023 ImplDrawSpin(rRenderContext);
1026 void Calendar::ImplUpdateDate( const Date& rDate )
1028 if (IsReallyVisible() && IsUpdateMode())
1030 Rectangle aDateRect(GetDateRect(rDate));
1031 if (!aDateRect.IsEmpty())
1033 Invalidate(aDateRect);
1038 void Calendar::ImplUpdateSelection( IntDateSet* pOld )
1040 IntDateSet* pNew = mpSelectTable;
1042 for ( IntDateSet::const_iterator it = pOld->begin(); it != pOld->end(); ++it )
1044 sal_uLong nKey = *it;
1045 if ( pNew->find( nKey ) == pNew->end() )
1047 Date aTempDate( nKey );
1048 ImplUpdateDate( aTempDate );
1052 for ( IntDateSet::const_iterator it = pNew->begin(); it != pNew->end(); ++it )
1054 sal_uLong nKey = *it;
1055 if ( pOld->find( nKey ) == pOld->end() )
1057 Date aTempDate( nKey );
1058 ImplUpdateDate( aTempDate );
1063 void Calendar::ImplMouseSelect( const Date& rDate, sal_uInt16 nHitTest,
1064 bool bMove, bool bExpand, bool bExtended )
1066 boost::scoped_ptr<IntDateSet> pOldSel(new IntDateSet( *mpSelectTable ));
1067 Date aOldDate = maCurDate;
1068 Date aTempDate = rDate;
1070 if ( !(nHitTest & CALENDAR_HITTEST_DAY) )
1071 --aTempDate;
1073 if ( mbMultiSelection )
1075 maCurDate = aTempDate;
1076 mbSelLeft = aTempDate < maAnchorDate;
1078 if ( bMove )
1080 if ( mbSelLeft )
1082 ImplCalendarUnSelectDateRange( mpSelectTable, mpRestoreSelectTable, Date( 1, 1, 0 ), aTempDate );
1083 ImplCalendarUnSelectDateRange( mpSelectTable, mpRestoreSelectTable, maAnchorDate, Date( 31, 12, 9999 ) );
1085 else
1087 ImplCalendarUnSelectDateRange( mpSelectTable, mpRestoreSelectTable, Date( 1, 1, 0 ), maAnchorDate );
1088 ImplCalendarUnSelectDateRange( mpSelectTable, mpRestoreSelectTable, aTempDate, Date( 31, 12, 9999 ) );
1090 ImplCalendarSelectDateRange( mpSelectTable, aTempDate, maAnchorDate, !mbUnSel );
1092 else
1094 if ( bExpand )
1096 if ( !bExtended )
1098 if ( mbSelLeft )
1100 ImplCalendarSelectDateRange( mpSelectTable, Date( 1, 1, 0 ), aTempDate, false );
1101 ImplCalendarSelectDateRange( mpSelectTable, maAnchorDate, Date( 31, 12, 9999 ), false );
1103 else
1105 ImplCalendarSelectDateRange( mpSelectTable, Date( 1, 1, 0 ), maAnchorDate, false );
1106 ImplCalendarSelectDateRange( mpSelectTable, aTempDate, Date( 31, 12, 9999 ), false );
1109 ImplCalendarSelectDateRange( mpSelectTable, aTempDate, maAnchorDate, true );
1111 else if ( bExtended && !(mnWinStyle & WB_RANGESELECT) )
1113 maAnchorDate = aTempDate;
1114 if ( IsDateSelected( aTempDate ) )
1116 mbUnSel = true;
1117 ImplCalendarSelectDate( mpSelectTable, aTempDate, false );
1119 else
1121 ImplCalendarSelectDate( mpSelectTable, aTempDate, true );
1124 else
1126 maAnchorDate = aTempDate;
1127 ImplCalendarClearSelectDate( mpSelectTable );
1128 ImplCalendarSelectDate( mpSelectTable, aTempDate, true );
1131 mpRestoreSelectTable = new IntDateSet( *mpSelectTable );
1134 else
1136 if ( aTempDate < maCurDate )
1137 mbSelLeft = true;
1138 else
1139 mbSelLeft = false;
1140 if ( !(nHitTest & CALENDAR_HITTEST_DAY) )
1141 aTempDate = maOldCurDate;
1142 if ( !bMove )
1143 maAnchorDate = aTempDate;
1144 if ( aTempDate != maCurDate )
1146 maCurDate = aTempDate;
1147 ImplCalendarSelectDate( mpSelectTable, aOldDate, false );
1148 ImplCalendarSelectDate( mpSelectTable, maCurDate, true );
1152 bool bNewSel = *pOldSel != *mpSelectTable;
1153 if ( (maCurDate != aOldDate) || bNewSel )
1155 if ( bNewSel )
1157 mbInSelChange = true;
1158 SelectionChanging();
1159 mbInSelChange = false;
1161 HideFocus();
1162 if ( bNewSel )
1163 ImplUpdateSelection( pOldSel.get() );
1164 if ( !bNewSel || pOldSel->find( aOldDate.GetDate() ) == pOldSel->end() )
1165 ImplUpdateDate( aOldDate );
1166 // assure focus rectangle is displayed again
1167 if ( HasFocus() || !bNewSel
1168 || mpSelectTable->find( maCurDate.GetDate() ) == mpSelectTable->end() )
1169 ImplUpdateDate( maCurDate );
1173 void Calendar::ImplUpdate( bool bCalcNew )
1175 if (IsReallyVisible() && IsUpdateMode())
1177 if (bCalcNew && !mbCalc)
1179 Invalidate();
1181 else if (!mbFormat && !mbCalc)
1183 Invalidate();
1187 if (bCalcNew)
1188 mbCalc = true;
1189 mbFormat = true;
1192 void Calendar::ImplInvertDropPos()
1194 Rectangle aRect = GetDateRect( maDropDate );//this is one Pixel to width and one to heigh
1195 aRect.Bottom() = aRect.Top()+mnDayHeight-1;
1196 aRect.Right() = aRect.Left()+mnDayWidth-1;
1197 Invert( aRect );
1200 void Calendar::ImplScroll( bool bPrev )
1202 Date aNewFirstMonth = GetFirstMonth();
1203 if ( bPrev )
1205 --aNewFirstMonth;
1206 aNewFirstMonth -= aNewFirstMonth.GetDaysInMonth()-1;
1208 else
1209 aNewFirstMonth += aNewFirstMonth.GetDaysInMonth();
1210 mbDirect = true;
1211 SetFirstDate( aNewFirstMonth );
1212 mbDirect = false;
1215 void Calendar::ImplShowMenu( const Point& rPos, const Date& rDate )
1217 EndSelection();
1219 Date aOldFirstDate = GetFirstMonth();
1220 PopupMenu aPopupMenu;
1221 PopupMenu* pYearPopupMenus[MENU_YEAR_COUNT];
1222 sal_uInt16 nMonthOff;
1223 sal_uInt16 nCurItemId;
1224 sal_uInt16 nYear = rDate.GetYear()-1;
1225 sal_uInt16 i;
1226 sal_uInt16 j;
1227 sal_uInt16 nYearIdCount = 1000;
1229 nMonthOff = (rDate.GetYear()-aOldFirstDate.GetYear())*12;
1230 if ( aOldFirstDate.GetMonth() < rDate.GetMonth() )
1231 nMonthOff += rDate.GetMonth()-aOldFirstDate.GetMonth();
1232 else
1233 nMonthOff -= aOldFirstDate.GetMonth()-rDate.GetMonth();
1235 // construct menu (include years with different months)
1236 for ( i = 0; i < MENU_YEAR_COUNT; i++ )
1238 pYearPopupMenus[i] = new PopupMenu;
1239 for ( j = 1; j <= 12; j++ )
1240 pYearPopupMenus[i]->InsertItem( nYearIdCount+j,
1241 maCalendarWrapper.getDisplayName(
1242 i18n::CalendarDisplayIndex::MONTH, j-1, 1));
1243 aPopupMenu.InsertItem( 10+i, OUString::number( nYear+i ) );
1244 aPopupMenu.SetPopupMenu( 10+i, pYearPopupMenus[i] );
1245 nYearIdCount += 1000;
1248 mbMenuDown = true;
1249 nCurItemId = aPopupMenu.Execute( this, rPos );
1250 mbMenuDown = false;
1252 // destroy menu
1253 aPopupMenu.SetPopupMenu( 2, NULL );
1254 for ( i = 0; i < MENU_YEAR_COUNT; i++ )
1256 aPopupMenu.SetPopupMenu( 10+i, NULL );
1257 delete pYearPopupMenus[i];
1260 if ( nCurItemId )
1262 sal_uInt16 nTempMonthOff = nMonthOff % 12;
1263 sal_uInt16 nTempYearOff = nMonthOff / 12;
1264 sal_uInt16 nNewMonth = nCurItemId % 1000;
1265 sal_uInt16 nNewYear = nYear+((nCurItemId-1000)/1000);
1266 if ( nTempMonthOff < nNewMonth )
1267 nNewMonth = nNewMonth - nTempMonthOff;
1268 else
1270 nNewYear--;
1271 nNewMonth = 12-(nTempMonthOff-nNewMonth);
1273 nNewYear = nNewYear - nTempYearOff;
1274 SetFirstDate( Date( 1, nNewMonth, nNewYear ) );
1278 void Calendar::ImplTracking( const Point& rPos, bool bRepeat )
1280 Date aTempDate = maCurDate;
1281 sal_uInt16 nHitTest = ImplHitTest( rPos, aTempDate );
1283 if ( mbSpinDown )
1285 mbPrevIn = (nHitTest & CALENDAR_HITTEST_PREV) != 0;
1286 mbNextIn = (nHitTest & CALENDAR_HITTEST_NEXT) != 0;
1288 if ( bRepeat && (mbPrevIn || mbNextIn) )
1290 mbScrollDateRange = true;
1291 ImplScroll( mbPrevIn );
1292 mbScrollDateRange = false;
1295 else
1296 ImplMouseSelect( aTempDate, nHitTest, true, false, false );
1299 void Calendar::ImplEndTracking( bool bCancel )
1301 bool bSelection = mbSelection;
1302 bool bSpinDown = mbSpinDown;
1304 mbDrag = false;
1305 mbSelection = false;
1306 mbMultiSelection = false;
1307 mbUnSel = false;
1308 mbSpinDown = false;
1309 mbPrevIn = false;
1310 mbNextIn = false;
1312 if ( bCancel )
1314 if ( maOldFirstDate != maFirstDate )
1315 SetFirstDate( maOldFirstDate );
1317 if ( !bSpinDown )
1319 boost::scoped_ptr<IntDateSet> pOldSel(new IntDateSet( *mpSelectTable ));
1320 Date aOldDate = maCurDate;
1321 maCurDate = maOldCurDate;
1322 *mpSelectTable = *mpOldSelectTable;
1323 HideFocus();
1324 ImplUpdateSelection( pOldSel.get() );
1325 if ( pOldSel->find( aOldDate.GetDate() ) == pOldSel->end() )
1326 ImplUpdateDate( aOldDate );
1327 // assure focus rectangle is displayed again
1328 if ( HasFocus() || mpSelectTable->find( maCurDate.GetDate() ) == mpSelectTable->end() )
1329 ImplUpdateDate( maCurDate );
1333 if ( !bSpinDown )
1335 if ( !bCancel )
1337 // determine if we should scroll the visible area
1338 sal_uLong nSelCount = mpSelectTable->size();
1339 if ( nSelCount )
1341 Date aFirstSelDate( *mpSelectTable->begin() );
1342 Date aLastSelDate( *mpSelectTable->rbegin() );
1343 if ( aLastSelDate < GetFirstMonth() )
1344 ImplScroll( true );
1345 else if ( GetLastMonth() < aFirstSelDate )
1346 ImplScroll( false );
1350 if ( mbAllSel ||
1351 (!bCancel && ((maCurDate != maOldCurDate) || (*mpOldSelectTable != *mpSelectTable))) )
1352 Select();
1354 if ( !bSelection && (mnWinStyle & WB_TABSTOP) && !bCancel )
1355 GrabFocus();
1357 delete mpOldSelectTable;
1358 mpOldSelectTable = NULL;
1359 delete mpRestoreSelectTable;
1360 mpRestoreSelectTable = NULL;
1364 IMPL_LINK_NOARG_TYPED( Calendar, ScrollHdl, Timer*, void )
1366 bool bPrevIn = (mnDragScrollHitTest & CALENDAR_HITTEST_PREV) != 0;
1367 bool bNextIn = (mnDragScrollHitTest & CALENDAR_HITTEST_NEXT) != 0;
1368 if( bNextIn || bPrevIn )
1370 mbScrollDateRange = true;
1371 ImplScroll( bPrevIn );
1372 mbScrollDateRange = false;
1376 void Calendar::MouseButtonDown( const MouseEvent& rMEvt )
1378 if ( rMEvt.IsLeft() && !mbMenuDown )
1380 Date aTempDate = maCurDate;
1381 sal_uInt16 nHitTest = ImplHitTest( rMEvt.GetPosPixel(), aTempDate );
1382 if ( nHitTest )
1384 if ( nHitTest & CALENDAR_HITTEST_MONTHTITLE )
1385 ImplShowMenu( rMEvt.GetPosPixel(), aTempDate );
1386 else
1388 maOldFirstDate = maFirstDate;
1390 mbPrevIn = (nHitTest & CALENDAR_HITTEST_PREV) != 0;
1391 mbNextIn = (nHitTest & CALENDAR_HITTEST_NEXT) != 0;
1392 if ( mbPrevIn || mbNextIn )
1394 mbSpinDown = true;
1395 mbScrollDateRange = true;
1396 ImplScroll( mbPrevIn );
1397 mbScrollDateRange = false;
1398 // it should really read BUTTONREPEAT, therefore do not
1399 // change it to SCROLLREPEAT, check with TH,
1400 // why it could be different (71775)
1401 StartTracking( STARTTRACK_BUTTONREPEAT );
1403 else
1405 if ( (rMEvt.GetClicks() == 2) && (nHitTest & CALENDAR_HITTEST_DAY) )
1406 DoubleClick();
1407 else
1409 if ( mpOldSelectTable )
1410 delete mpOldSelectTable;
1411 maOldCurDate = maCurDate;
1412 mpOldSelectTable = new IntDateSet( *mpSelectTable );
1414 if ( !mbSelection )
1416 mbDrag = true;
1417 StartTracking();
1420 mbMultiSelection = (mnWinStyle & (WB_MULTISELECT | WB_RANGESELECT)) != 0;
1421 if ( (nHitTest & CALENDAR_HITTEST_DAY) && mbMultiSelection )
1422 mbWeekSel = true;
1423 else
1424 mbWeekSel = false;
1425 ImplMouseSelect( aTempDate, nHitTest, false, rMEvt.IsShift(), rMEvt.IsMod1() );
1431 return;
1434 Control::MouseButtonDown( rMEvt );
1437 void Calendar::MouseButtonUp( const MouseEvent& rMEvt )
1439 if ( rMEvt.IsLeft() && mbSelection )
1440 ImplEndTracking( false );
1441 else
1442 Control::MouseButtonUp( rMEvt );
1445 void Calendar::MouseMove( const MouseEvent& rMEvt )
1447 if ( mbSelection && rMEvt.GetButtons() )
1448 ImplTracking( rMEvt.GetPosPixel(), false );
1449 else
1450 Control::MouseMove( rMEvt );
1453 void Calendar::Tracking( const TrackingEvent& rTEvt )
1455 Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel();
1457 if ( rTEvt.IsTrackingEnded() )
1458 ImplEndTracking( rTEvt.IsTrackingCanceled() );
1459 else
1460 ImplTracking( aMousePos, rTEvt.IsTrackingRepeat() );
1463 void Calendar::KeyInput( const KeyEvent& rKEvt )
1465 Date aNewDate = maCurDate;
1466 bool bMultiSel = (mnWinStyle & (WB_RANGESELECT | WB_MULTISELECT)) != 0;
1467 bool bExpand = rKEvt.GetKeyCode().IsShift();
1468 bool bExtended = rKEvt.GetKeyCode().IsMod1();
1470 switch ( rKEvt.GetKeyCode().GetCode() )
1472 case KEY_HOME:
1473 aNewDate.SetDay( 1 );
1474 break;
1476 case KEY_END:
1477 aNewDate.SetDay( aNewDate.GetDaysInMonth() );
1478 break;
1480 case KEY_LEFT:
1481 --aNewDate;
1482 break;
1484 case KEY_RIGHT:
1485 ++aNewDate;
1486 break;
1488 case KEY_UP:
1489 aNewDate -= 7;
1490 break;
1492 case KEY_DOWN:
1493 aNewDate += 7;
1494 break;
1496 case KEY_PAGEUP:
1498 Date aTempDate = aNewDate;
1499 aTempDate -= aNewDate.GetDay()+1;
1500 aNewDate -= aTempDate.GetDaysInMonth();
1502 break;
1504 case KEY_PAGEDOWN:
1505 aNewDate += aNewDate.GetDaysInMonth();
1506 break;
1508 case KEY_SPACE:
1509 if ( bMultiSel && !(mnWinStyle & WB_RANGESELECT) )
1511 if ( !bExpand )
1513 bool bDateSel = IsDateSelected( maCurDate );
1514 SelectDate( maCurDate, !bDateSel );
1515 mbSelLeft = false;
1516 SelectionChanging();
1517 mbTravelSelect = true;
1518 Select();
1519 mbTravelSelect = false;
1522 else
1523 Control::KeyInput( rKEvt );
1524 break;
1526 default:
1527 Control::KeyInput( rKEvt );
1528 break;
1531 if ( aNewDate != maCurDate )
1533 if ( bMultiSel && bExpand )
1535 boost::scoped_ptr<IntDateSet> pOldSel(new IntDateSet( *mpSelectTable ));
1536 Date aOldAnchorDate = maAnchorDate;
1537 mbSelLeft = aNewDate < maAnchorDate;
1538 if ( !bExtended )
1540 if ( mbSelLeft )
1542 ImplCalendarSelectDateRange( mpSelectTable, Date( 1, 1, 0 ), aNewDate, false );
1543 ImplCalendarSelectDateRange( mpSelectTable, maAnchorDate, Date( 31, 12, 9999 ), false );
1545 else
1547 ImplCalendarSelectDateRange( mpSelectTable, Date( 1, 1, 0 ), maAnchorDate, false );
1548 ImplCalendarSelectDateRange( mpSelectTable, aNewDate, Date( 31, 12, 9999 ), false );
1551 ImplCalendarSelectDateRange( mpSelectTable, aNewDate, maAnchorDate, true );
1552 mbDirect = true;
1553 SetCurDate( aNewDate );
1554 mbDirect = false;
1555 maAnchorDate = aOldAnchorDate;
1556 mbInSelChange = true;
1557 SelectionChanging();
1558 mbInSelChange = false;
1559 ImplUpdateSelection( pOldSel.get() );
1561 else
1563 if ( mnWinStyle & WB_RANGESELECT )
1565 SetNoSelection();
1566 SelectDate( aNewDate, true );
1568 mbDirect = true;
1569 SetCurDate( aNewDate );
1570 mbDirect = false;
1572 mbTravelSelect = true;
1573 Select();
1574 mbTravelSelect = false;
1578 void Calendar::Paint( vcl::RenderContext& rRenderContext, const Rectangle& )
1580 ImplDraw(rRenderContext, true);
1583 void Calendar::GetFocus()
1585 ImplUpdateDate( maCurDate );
1586 Control::GetFocus();
1589 void Calendar::LoseFocus()
1591 HideFocus();
1592 Control::LoseFocus();
1595 void Calendar::Resize()
1597 ImplUpdate( true );
1598 Control::Resize();
1601 void Calendar::RequestHelp( const HelpEvent& rHEvt )
1603 if ( rHEvt.GetMode() & (HelpEventMode::QUICK | HelpEventMode::BALLOON) )
1605 Date aDate = maCurDate;
1606 if ( GetDate( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ), aDate ) )
1608 Rectangle aDateRect = GetDateRect( aDate );
1609 Point aPt = OutputToScreenPixel( aDateRect.TopLeft() );
1610 aDateRect.Left() = aPt.X();
1611 aDateRect.Top() = aPt.Y();
1612 aPt = OutputToScreenPixel( aDateRect.BottomRight() );
1613 aDateRect.Right() = aPt.X();
1614 aDateRect.Bottom() = aPt.Y();
1616 if ( rHEvt.GetMode() & HelpEventMode::QUICK )
1618 maCalendarWrapper.setGregorianDateTime( aDate);
1619 sal_uInt16 nWeek = (sal_uInt16) maCalendarWrapper.getValue( i18n::CalendarFieldIndex::WEEK_OF_YEAR);
1620 sal_uInt16 nMonth = aDate.GetMonth();
1621 OUString aStr( maDayText );
1622 aStr += ": ";
1623 aStr += OUString::number(aDate.GetDayOfYear());
1624 aStr += " / ";
1625 aStr += maWeekText;
1626 aStr += ": ";
1627 aStr += OUString::number(nWeek);
1628 // if year is not the same, add it
1629 if ( (nMonth == 12) && (nWeek == 1) )
1631 aStr += ", ";
1632 aStr += OUString::number(aDate.GetYear()+1);
1634 else if ( (nMonth == 1) && (nWeek > 50) )
1636 aStr += ", ";
1637 aStr += OUString::number(aDate.GetYear()-1);
1639 Help::ShowQuickHelp( this, aDateRect, aStr );
1640 return;
1645 Control::RequestHelp( rHEvt );
1648 void Calendar::Command( const CommandEvent& rCEvt )
1650 if ( rCEvt.GetCommand() == CommandEventId::ContextMenu )
1652 if ( !mbSelection && rCEvt.IsMouseEvent() )
1654 Date aTempDate = maCurDate;
1655 sal_uInt16 nHitTest = ImplHitTest( rCEvt.GetMousePosPixel(), aTempDate );
1656 if ( nHitTest & CALENDAR_HITTEST_MONTHTITLE )
1658 ImplShowMenu( rCEvt.GetMousePosPixel(), aTempDate );
1659 return;
1663 else if ( rCEvt.GetCommand() == CommandEventId::Wheel )
1665 const CommandWheelData* pData = rCEvt.GetWheelData();
1666 if ( pData->GetMode() == CommandWheelMode::SCROLL )
1668 long nNotchDelta = pData->GetNotchDelta();
1669 if ( nNotchDelta < 0 )
1671 while ( nNotchDelta < 0 )
1673 ImplScroll( true );
1674 nNotchDelta++;
1677 else
1679 while ( nNotchDelta > 0 )
1681 ImplScroll( false );
1682 nNotchDelta--;
1686 return;
1690 Control::Command( rCEvt );
1693 void Calendar::StateChanged( StateChangedType nType )
1695 Control::StateChanged( nType );
1697 if ( nType == StateChangedType::InitShow )
1698 ImplFormat();
1701 void Calendar::DataChanged( const DataChangedEvent& rDCEvt )
1703 Control::DataChanged( rDCEvt );
1705 if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
1706 (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
1707 ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
1708 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
1710 ImplInitSettings();
1711 Invalidate();
1715 void Calendar::SelectionChanging()
1717 maSelectionChangingHdl.Call( this );
1720 void Calendar::DateRangeChanged()
1722 maDateRangeChangedHdl.Call( this );
1725 void Calendar::RequestDateInfo()
1727 maRequestDateInfoHdl.Call( this );
1730 void Calendar::DoubleClick()
1732 maDoubleClickHdl.Call( this );
1735 void Calendar::Select()
1737 maSelectHdl.Call( this );
1740 void Calendar::SelectDate( const Date& rDate, bool bSelect )
1742 if ( !rDate.IsValidAndGregorian() )
1743 return;
1745 boost::scoped_ptr<IntDateSet> pOldSel;
1747 if ( !mbInSelChange )
1748 pOldSel.reset(new IntDateSet( *mpSelectTable ));
1750 ImplCalendarSelectDate( mpSelectTable, rDate, bSelect );
1752 if ( pOldSel )
1753 ImplUpdateSelection( pOldSel.get() );
1756 void Calendar::SetNoSelection()
1758 boost::scoped_ptr<IntDateSet> pOldSel;
1760 if ( !mbInSelChange )
1761 pOldSel.reset(new IntDateSet( *mpSelectTable ));
1763 ImplCalendarClearSelectDate( mpSelectTable );
1765 if ( pOldSel )
1766 ImplUpdateSelection( pOldSel.get() );
1769 bool Calendar::IsDateSelected( const Date& rDate ) const
1771 return mpSelectTable->find( rDate.GetDate() ) != mpSelectTable->end();
1774 Date Calendar::GetFirstSelectedDate() const
1776 if ( !mpSelectTable->empty() )
1777 return Date( *mpSelectTable->begin() );
1778 else
1780 Date aDate( 0, 0, 0 );
1781 return aDate;
1785 void Calendar::SetCurDate( const Date& rNewDate )
1787 if ( !rNewDate.IsValidAndGregorian() )
1788 return;
1790 if ( maCurDate != rNewDate )
1792 bool bUpdate = IsVisible() && IsUpdateMode();
1793 Date aOldDate = maCurDate;
1794 maCurDate = rNewDate;
1795 maAnchorDate = maCurDate;
1797 if ( !(mnWinStyle & (WB_RANGESELECT | WB_MULTISELECT)) )
1799 ImplCalendarSelectDate( mpSelectTable, aOldDate, false );
1800 ImplCalendarSelectDate( mpSelectTable, maCurDate, true );
1802 else if ( !HasFocus() )
1803 bUpdate = false;
1805 // shift actual date in the visible area
1806 if ( mbFormat || (maCurDate < GetFirstMonth()) )
1807 SetFirstDate( maCurDate );
1808 else if ( maCurDate > GetLastMonth() )
1810 Date aTempDate = GetLastMonth();
1811 long nDateOff = maCurDate-aTempDate;
1812 if ( nDateOff < 365 )
1814 Date aFirstDate = GetFirstMonth();
1815 aFirstDate += aFirstDate.GetDaysInMonth();
1816 ++aTempDate;
1817 while ( nDateOff > aTempDate.GetDaysInMonth() )
1819 aFirstDate += aFirstDate.GetDaysInMonth();
1820 long nDaysInMonth = aTempDate.GetDaysInMonth();
1821 aTempDate += nDaysInMonth;
1822 nDateOff -= nDaysInMonth;
1824 SetFirstDate( aFirstDate );
1826 else
1827 SetFirstDate( maCurDate );
1829 else
1831 if ( bUpdate )
1833 HideFocus();
1834 ImplUpdateDate( aOldDate );
1835 ImplUpdateDate( maCurDate );
1841 void Calendar::SetFirstDate( const Date& rNewFirstDate )
1843 if ( maFirstDate != rNewFirstDate )
1845 maFirstDate = Date( 1, rNewFirstDate.GetMonth(), rNewFirstDate.GetYear() );
1846 mbDropPos = false;
1847 ImplUpdate();
1851 Date Calendar::GetFirstMonth() const
1853 if ( maFirstDate.GetDay() > 1 )
1855 if ( maFirstDate.GetMonth() == 12 )
1856 return Date( 1, 1, maFirstDate.GetYear()+1 );
1857 else
1858 return Date( 1, maFirstDate.GetMonth()+1, maFirstDate.GetYear() );
1860 else
1861 return maFirstDate;
1864 Date Calendar::GetLastMonth() const
1866 Date aDate = GetFirstMonth();
1867 sal_uInt16 nMonthCount = GetMonthCount();
1868 for ( sal_uInt16 i = 0; i < nMonthCount; i++ )
1869 aDate += aDate.GetDaysInMonth();
1870 --aDate;
1871 return aDate;
1874 sal_uInt16 Calendar::GetMonthCount() const
1876 if ( mbFormat )
1877 return 1;
1878 else
1879 return (sal_uInt16)(mnMonthPerLine*mnLines);
1882 bool Calendar::GetDate( const Point& rPos, Date& rDate ) const
1884 Date aDate = maCurDate;
1885 sal_uInt16 nHitTest = ImplHitTest( rPos, aDate );
1886 if ( nHitTest & CALENDAR_HITTEST_DAY )
1888 rDate = aDate;
1889 return true;
1891 else
1892 return false;
1895 Rectangle Calendar::GetDateRect( const Date& rDate ) const
1897 Rectangle aRect;
1899 if ( mbFormat || (rDate < maFirstDate) || (rDate > (maFirstDate+mnDayCount)) )
1900 return aRect;
1902 long nX;
1903 long nY;
1904 sal_uLong nDaysOff;
1905 sal_uInt16 nDayIndex;
1906 Date aDate = GetFirstMonth();
1908 if ( rDate < aDate )
1910 aRect = GetDateRect( aDate );
1911 nDaysOff = aDate-rDate;
1912 nX = (long)(nDaysOff*mnDayWidth);
1913 aRect.Left() -= nX;
1914 aRect.Right() -= nX;
1915 return aRect;
1917 else
1919 Date aLastDate = GetLastMonth();
1920 if ( rDate > aLastDate )
1922 sal_uInt16 nWeekDay = (sal_uInt16)aLastDate.GetDayOfWeek();
1923 nWeekDay = (nWeekDay+(7-(sal_uInt16)ImplGetWeekStart())) % 7;
1924 aLastDate -= nWeekDay;
1925 aRect = GetDateRect( aLastDate );
1926 nDaysOff = rDate-aLastDate;
1927 nDayIndex = 0;
1928 for ( sal_uInt16 i = 0; i <= nDaysOff; i++ )
1930 if ( aLastDate == rDate )
1932 aRect.Left() += nDayIndex*mnDayWidth;
1933 aRect.Right() = aRect.Left()+mnDayWidth;
1934 return aRect;
1936 if ( nDayIndex == 6 )
1938 nDayIndex = 0;
1939 aRect.Top() += mnDayHeight;
1940 aRect.Bottom() += mnDayHeight;
1942 else
1943 nDayIndex++;
1944 ++aLastDate;
1949 nY = 0;
1950 for ( long i = 0; i < mnLines; i++ )
1952 nX = 0;
1953 for ( long j = 0; j < mnMonthPerLine; j++ )
1955 sal_uInt16 nDaysInMonth = aDate.GetDaysInMonth();
1957 // month is called
1958 if ( (aDate.GetMonth() == rDate.GetMonth()) &&
1959 (aDate.GetYear() == rDate.GetYear()) )
1961 long nDayX = nX+mnDaysOffX;
1962 long nDayY = nY+mnDaysOffY;
1963 nDayIndex = (sal_uInt16)aDate.GetDayOfWeek();
1964 nDayIndex = (nDayIndex+(7-(sal_uInt16)ImplGetWeekStart())) % 7;
1965 for ( sal_uInt16 nDay = 1; nDay <= nDaysInMonth; nDay++ )
1967 if ( nDay == rDate.GetDay() )
1969 aRect.Left() = nDayX + (nDayIndex*mnDayWidth);
1970 aRect.Top() = nDayY;
1971 aRect.Right() = aRect.Left()+mnDayWidth;
1972 aRect.Bottom() = aRect.Top()+mnDayHeight;
1973 break;
1975 if ( nDayIndex == 6 )
1977 nDayIndex = 0;
1978 nDayY += mnDayHeight;
1980 else
1981 nDayIndex++;
1985 aDate += nDaysInMonth;
1986 nX += mnMonthWidth;
1989 nY += mnMonthHeight;
1992 return aRect;
1995 void Calendar::StartSelection()
1997 if ( mpOldSelectTable )
1998 delete mpOldSelectTable;
1999 maOldCurDate = maCurDate;
2000 mpOldSelectTable = new IntDateSet( *mpSelectTable );
2002 mbSelection = true;
2005 void Calendar::EndSelection()
2007 if ( mbDrag || mbSpinDown || mbSelection )
2009 if ( !mbSelection )
2010 ReleaseMouse();
2012 mbDrag = false;
2013 mbSelection = false;
2014 mbMultiSelection = false;
2015 mbSpinDown = false;
2016 mbPrevIn = false;
2017 mbNextIn = false;
2021 Size Calendar::CalcWindowSizePixel( long nCalcMonthPerLine,
2022 long nCalcLines ) const
2024 OUString a99Text("99");
2025 vcl::Font aOldFont = GetFont();
2027 // take display of week into account
2028 long nWeekWidth;
2029 if ( mnWinStyle & WB_WEEKNUMBER )
2031 vcl::Font aTempFont = aOldFont;
2032 ImplGetWeekFont( aTempFont );
2033 const_cast<Calendar*>(this)->SetFont( aTempFont );
2034 nWeekWidth = GetTextWidth( a99Text )+WEEKNUMBER_OFFX;
2035 const_cast<Calendar*>(this)->SetFont( aOldFont );
2037 else
2038 nWeekWidth = 0;
2040 if ( mnWinStyle & WB_BOLDTEXT )
2042 vcl::Font aFont = aOldFont;
2043 if ( aFont.GetWeight() < WEIGHT_BOLD )
2044 aFont.SetWeight( WEIGHT_BOLD );
2045 else
2046 aFont.SetWeight( WEIGHT_NORMAL );
2047 const_cast<Calendar*>(this)->SetFont( aFont );
2050 Size aSize;
2051 long n99TextWidth = GetTextWidth( a99Text );
2052 long nTextHeight = GetTextHeight();
2054 if ( mnWinStyle & WB_BOLDTEXT )
2055 const_cast<Calendar*>(this)->SetFont( aOldFont );
2057 aSize.Width() += ((n99TextWidth+DAY_OFFX)*7) + nWeekWidth;
2058 aSize.Width() += MONTH_BORDERX*2;
2059 aSize.Width() *= nCalcMonthPerLine;
2061 aSize.Height() = nTextHeight + TITLE_OFFY + (TITLE_BORDERY*2);
2062 aSize.Height() += nTextHeight + WEEKDAY_OFFY;
2063 aSize.Height() += ((nTextHeight+DAY_OFFY)*6);
2064 aSize.Height() += MONTH_OFFY;
2065 aSize.Height() *= nCalcLines;
2067 return aSize;
2070 #define CALFIELD_EXTRA_BUTTON_WIDTH 14
2071 #define CALFIELD_EXTRA_BUTTON_HEIGHT 8
2072 #define CALFIELD_SEP_X 6
2073 #define CALFIELD_BORDERLINE_X 5
2074 #define CALFIELD_BORDER_YTOP 4
2075 #define CALFIELD_BORDER_Y 5
2077 class ImplCFieldFloatWin : public FloatingWindow
2079 private:
2080 VclPtr<Calendar> mpCalendar;
2081 VclPtr<PushButton> mpTodayBtn;
2082 VclPtr<PushButton> mpNoneBtn;
2083 VclPtr<FixedLine> mpFixedLine;
2085 public:
2086 ImplCFieldFloatWin( vcl::Window* pParent );
2087 virtual ~ImplCFieldFloatWin();
2088 virtual void dispose() SAL_OVERRIDE;
2090 void SetCalendar( Calendar* pCalendar )
2091 { mpCalendar = pCalendar; }
2093 PushButton* EnableTodayBtn( bool bEnable );
2094 PushButton* EnableNoneBtn( bool bEnable );
2095 void ArrangeButtons();
2097 virtual bool Notify( NotifyEvent& rNEvt ) SAL_OVERRIDE;
2100 ImplCFieldFloatWin::ImplCFieldFloatWin( vcl::Window* pParent ) :
2101 FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW | WB_NOSHADOW )
2103 mpCalendar = NULL;
2104 mpTodayBtn = NULL;
2105 mpNoneBtn = NULL;
2106 mpFixedLine = NULL;
2109 ImplCFieldFloatWin::~ImplCFieldFloatWin()
2111 disposeOnce();
2114 void ImplCFieldFloatWin::dispose()
2116 mpTodayBtn.disposeAndClear();
2117 mpNoneBtn.disposeAndClear();
2118 mpFixedLine.disposeAndClear();
2119 mpCalendar.clear();
2120 FloatingWindow::dispose();
2123 PushButton* ImplCFieldFloatWin::EnableTodayBtn( bool bEnable )
2125 if ( bEnable )
2127 if ( !mpTodayBtn )
2129 mpTodayBtn = VclPtr<PushButton>::Create( this, WB_NOPOINTERFOCUS );
2130 OUString aTodayText(SVT_RESSTR(STR_SVT_CALENDAR_TODAY));
2131 mpTodayBtn->SetText( aTodayText );
2132 Size aSize;
2133 aSize.Width() = mpTodayBtn->GetCtrlTextWidth( mpTodayBtn->GetText() );
2134 aSize.Height() = mpTodayBtn->GetTextHeight();
2135 aSize.Width() += CALFIELD_EXTRA_BUTTON_WIDTH;
2136 aSize.Height() += CALFIELD_EXTRA_BUTTON_HEIGHT;
2137 mpTodayBtn->SetSizePixel( aSize );
2138 mpTodayBtn->Show();
2141 else
2143 mpTodayBtn.disposeAndClear();
2146 return mpTodayBtn;
2149 PushButton* ImplCFieldFloatWin::EnableNoneBtn( bool bEnable )
2151 if ( bEnable )
2153 if ( !mpNoneBtn )
2155 mpNoneBtn = VclPtr<PushButton>::Create( this, WB_NOPOINTERFOCUS );
2156 OUString aNoneText(SVT_RESSTR(STR_SVT_CALENDAR_NONE));
2157 mpNoneBtn->SetText( aNoneText );
2158 Size aSize;
2159 aSize.Width() = mpNoneBtn->GetCtrlTextWidth( mpNoneBtn->GetText() );
2160 aSize.Height() = mpNoneBtn->GetTextHeight();
2161 aSize.Width() += CALFIELD_EXTRA_BUTTON_WIDTH;
2162 aSize.Height() += CALFIELD_EXTRA_BUTTON_HEIGHT;
2163 mpNoneBtn->SetSizePixel( aSize );
2164 mpNoneBtn->Show();
2167 else
2169 mpNoneBtn.disposeAndClear();
2172 return mpNoneBtn;
2175 void ImplCFieldFloatWin::ArrangeButtons()
2177 long nBtnHeight = 0;
2178 long nBtnWidth = 0;
2179 Size aOutSize = GetOutputSizePixel();
2180 if ( mpTodayBtn && mpNoneBtn )
2182 Size aTodayBtnSize = mpTodayBtn->GetSizePixel();
2183 Size aNoneBtnSize = mpNoneBtn->GetSizePixel();
2184 if ( aTodayBtnSize.Width() < aNoneBtnSize.Width() )
2185 aTodayBtnSize.Width() = aNoneBtnSize.Width();
2186 else
2187 aNoneBtnSize.Width() = aTodayBtnSize.Width();
2188 if ( aTodayBtnSize.Height() < aNoneBtnSize.Height() )
2189 aTodayBtnSize.Height() = aNoneBtnSize.Height();
2190 else
2191 aNoneBtnSize.Height() = aTodayBtnSize.Height();
2193 nBtnWidth = aTodayBtnSize.Width() + aNoneBtnSize.Width() + CALFIELD_SEP_X;
2194 nBtnHeight = aTodayBtnSize.Height();
2195 long nX = (aOutSize.Width()-nBtnWidth)/2;
2196 long nY = aOutSize.Height()+CALFIELD_BORDER_Y+CALFIELD_BORDER_YTOP;
2197 mpTodayBtn->SetPosSizePixel( Point( nX, nY ), aTodayBtnSize );
2198 nX += aTodayBtnSize.Width() + CALFIELD_SEP_X;
2199 mpNoneBtn->SetPosSizePixel( Point( nX, nY ), aNoneBtnSize );
2201 else if ( mpTodayBtn )
2203 Size aTodayBtnSize = mpTodayBtn->GetSizePixel();
2204 nBtnWidth = aTodayBtnSize.Width();
2205 nBtnHeight = aTodayBtnSize.Height();
2206 mpTodayBtn->SetPosPixel( Point( (aOutSize.Width()-nBtnWidth)/2, aOutSize.Height()+CALFIELD_BORDER_Y+CALFIELD_BORDER_YTOP ) );
2208 else if ( mpNoneBtn )
2210 Size aNoneBtnSize = mpNoneBtn->GetSizePixel();
2211 nBtnWidth = aNoneBtnSize.Width();
2212 nBtnHeight = aNoneBtnSize.Height();
2213 mpNoneBtn->SetPosPixel( Point( (aOutSize.Width()-nBtnWidth)/2, aOutSize.Height()+CALFIELD_BORDER_Y+CALFIELD_BORDER_YTOP ) );
2216 if ( nBtnHeight )
2218 if ( !mpFixedLine )
2220 mpFixedLine = VclPtr<FixedLine>::Create( this );
2221 mpFixedLine->Show();
2223 long nLineWidth = aOutSize.Width()-(CALFIELD_BORDERLINE_X*2);
2224 mpFixedLine->setPosSizePixel( (aOutSize.Width()-nLineWidth)/2, aOutSize.Height()+((CALFIELD_BORDER_YTOP-2)/2),
2225 nLineWidth, 2, PosSizeFlags::PosSize );
2226 aOutSize.Height() += nBtnHeight + (CALFIELD_BORDER_Y*2) + CALFIELD_BORDER_YTOP;
2227 SetOutputSizePixel( aOutSize );
2229 else
2231 mpFixedLine.disposeAndClear();
2235 bool ImplCFieldFloatWin::Notify( NotifyEvent& rNEvt )
2237 if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
2239 const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
2240 if ( pKEvt->GetKeyCode().GetCode() == KEY_RETURN )
2241 mpCalendar->Select();
2244 return FloatingWindow::Notify( rNEvt );
2247 CalendarField::CalendarField(vcl::Window* pParent, WinBits nWinStyle)
2248 : DateField(pParent, nWinStyle)
2249 , mpFloatWin(NULL)
2250 , mpCalendar(NULL)
2251 , mnCalendarStyle(0)
2252 , mpTodayBtn(NULL)
2253 , mpNoneBtn(NULL)
2254 , maDefaultDate( 0, 0, 0 )
2255 , mbToday(false)
2256 , mbNone(false)
2260 CalendarField::~CalendarField()
2262 disposeOnce();
2265 void CalendarField::dispose()
2267 mpCalendar.disposeAndClear();
2268 mpFloatWin.disposeAndClear();
2269 mpTodayBtn.clear();
2270 mpNoneBtn.clear();
2271 DateField::dispose();
2274 IMPL_LINK( CalendarField, ImplSelectHdl, Calendar*, pCalendar )
2276 if ( !pCalendar->IsTravelSelect() )
2278 mpFloatWin->EndPopupMode();
2279 EndDropDown();
2280 GrabFocus();
2281 Date aNewDate = mpCalendar->GetFirstSelectedDate();
2282 if ( IsEmptyDate() || ( aNewDate != GetDate() ) )
2284 SetDate( aNewDate );
2285 SetModifyFlag();
2286 Modify();
2288 Select();
2290 return 0;
2293 IMPL_LINK( CalendarField, ImplClickHdl, PushButton*, pBtn )
2295 mpFloatWin->EndPopupMode();
2296 EndDropDown();
2297 GrabFocus();
2299 if ( pBtn == mpTodayBtn )
2301 Date aToday( Date::SYSTEM );
2302 if ( (aToday != GetDate()) || IsEmptyDate() )
2304 SetDate( aToday );
2305 SetModifyFlag();
2306 Modify();
2309 else if ( pBtn == mpNoneBtn )
2311 if ( !IsEmptyDate() )
2313 SetEmptyDate();
2314 SetModifyFlag();
2315 Modify();
2318 Select();
2320 return 0;
2323 IMPL_LINK_NOARG(CalendarField, ImplPopupModeEndHdl)
2325 EndDropDown();
2326 GrabFocus();
2327 mpCalendar->EndSelection();
2328 return 0;
2331 void CalendarField::Select()
2333 maSelectHdl.Call( this );
2336 bool CalendarField::ShowDropDown( bool bShow )
2338 if ( bShow )
2340 Calendar* pCalendar = GetCalendar();
2342 Date aDate = GetDate();
2343 if ( IsEmptyDate() || !aDate.IsValidAndGregorian() )
2345 if ( maDefaultDate.IsValidAndGregorian() )
2346 aDate = maDefaultDate;
2347 else
2348 aDate = Date( Date::SYSTEM );
2350 if ( pCalendar->GetStyle() & (WB_RANGESELECT | WB_MULTISELECT) )
2352 pCalendar->SetNoSelection();
2353 pCalendar->SelectDate( aDate );
2355 pCalendar->SetCurDate( aDate );
2356 Point aPos( GetParent()->OutputToScreenPixel( GetPosPixel() ) );
2357 Rectangle aRect( aPos, GetSizePixel() );
2358 aRect.Bottom() -= 1;
2359 mpCalendar->SetOutputSizePixel( mpCalendar->CalcWindowSizePixel() );
2360 mpFloatWin->SetOutputSizePixel( mpCalendar->GetSizePixel() );
2361 mpFloatWin->SetCalendar( mpCalendar );
2362 mpTodayBtn = mpFloatWin->EnableTodayBtn( mbToday );
2363 mpNoneBtn = mpFloatWin->EnableNoneBtn( mbNone );
2364 if ( mpTodayBtn )
2365 mpTodayBtn->SetClickHdl( LINK( this, CalendarField, ImplClickHdl ) );
2366 if ( mpNoneBtn )
2367 mpNoneBtn->SetClickHdl( LINK( this, CalendarField, ImplClickHdl ) );
2368 mpFloatWin->ArrangeButtons();
2369 mpCalendar->EnableCallEverySelect();
2370 mpCalendar->StartSelection();
2371 mpCalendar->GrabFocus();
2372 mpCalendar->Show();
2373 mpFloatWin->StartPopupMode( aRect, FloatWinPopupFlags::NoFocusClose|FloatWinPopupFlags::Down );
2375 else
2377 mpFloatWin->EndPopupMode( FloatWinPopupEndFlags::Cancel );
2378 mpCalendar->EndSelection();
2379 EndDropDown();
2381 return true;
2384 VclPtr<Calendar> CalendarField::CreateCalendar( vcl::Window* pParent )
2386 return VclPtr<Calendar>::Create( pParent, mnCalendarStyle | WB_TABSTOP );
2389 Calendar* CalendarField::GetCalendar()
2391 if ( !mpFloatWin )
2393 mpFloatWin = VclPtr<ImplCFieldFloatWin>::Create( this );
2394 mpFloatWin->SetPopupModeEndHdl( LINK( this, CalendarField, ImplPopupModeEndHdl ) );
2395 mpCalendar = CreateCalendar( mpFloatWin );
2396 mpCalendar->SetPosPixel( Point() );
2397 mpCalendar->SetSelectHdl( LINK( this, CalendarField, ImplSelectHdl ) );
2400 return mpCalendar;
2403 void CalendarField::StateChanged( StateChangedType nStateChange )
2405 DateField::StateChanged( nStateChange );
2407 if ( ( nStateChange == StateChangedType::Style ) && GetSubEdit() )
2409 WinBits nAllAlignmentBits = ( WB_LEFT | WB_CENTER | WB_RIGHT | WB_TOP | WB_VCENTER | WB_BOTTOM );
2410 WinBits nMyAlignment = GetStyle() & nAllAlignmentBits;
2411 GetSubEdit()->SetStyle( ( GetSubEdit()->GetStyle() & ~nAllAlignmentBits ) | nMyAlignment );
2415 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */