/src/libreoffice/vcl/source/control/calendar.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
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/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
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 . |
18 | | */ |
19 | | |
20 | | #include <tools/json_writer.hxx> |
21 | | #include <vcl/help.hxx> |
22 | | #include <vcl/menu.hxx> |
23 | | #include <vcl/event.hxx> |
24 | | #include <vcl/toolkit/calendar.hxx> |
25 | | #include <vcl/commandevent.hxx> |
26 | | #include <vcl/dockwin.hxx> |
27 | | #include <vcl/weld/Builder.hxx> |
28 | | #include <unotools/localedatawrapper.hxx> |
29 | | |
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 | | |
34 | | #include <calendar.hxx> |
35 | | #include <svdata.hxx> |
36 | | #include <strings.hrc> |
37 | | #include <memory> |
38 | | |
39 | | constexpr tools::Long DAY_OFFX = 4; |
40 | | constexpr tools::Long DAY_OFFY = 2; |
41 | | constexpr tools::Long MONTH_BORDERX = 4; |
42 | | constexpr tools::Long MONTH_OFFY = 3; |
43 | | constexpr tools::Long WEEKDAY_OFFY = 3; |
44 | | constexpr tools::Long TITLE_OFFY = 3; |
45 | | constexpr tools::Long TITLE_BORDERY = 2; |
46 | | constexpr tools::Long SPIN_OFFX = 4; |
47 | | constexpr tools::Long SPIN_OFFY = TITLE_BORDERY; |
48 | | |
49 | | constexpr sal_uInt16 CALENDAR_HITTEST_DAY = 0x0001; |
50 | | constexpr sal_uInt16 CALENDAR_HITTEST_MONTHTITLE = 0x0004; |
51 | | constexpr sal_uInt16 CALENDAR_HITTEST_PREV = 0x0008; |
52 | | constexpr sal_uInt16 CALENDAR_HITTEST_NEXT = 0x0010; |
53 | | |
54 | | constexpr sal_uInt16 MENU_YEAR_COUNT = 3; |
55 | | |
56 | | using namespace ::com::sun::star; |
57 | | |
58 | | static void ImplCalendarSelectDate(IntDateSet* pTable, const Date& rDate, bool bSelect) |
59 | 0 | { |
60 | 0 | if ( bSelect ) |
61 | 0 | pTable->insert( rDate.GetDate() ); |
62 | 0 | else |
63 | 0 | pTable->erase( rDate.GetDate() ); |
64 | 0 | } |
65 | | |
66 | | void Calendar::ImplInit( WinBits nWinStyle ) |
67 | 0 | { |
68 | 0 | mpSelectTable.reset(new IntDateSet); |
69 | 0 | mnDayCount = 0; |
70 | 0 | mnWinStyle = nWinStyle; |
71 | 0 | mnFirstYear = 0; |
72 | 0 | mnLastYear = 0; |
73 | 0 | mbCalc = true; |
74 | 0 | mbFormat = true; |
75 | 0 | mbDrag = false; |
76 | 0 | mbMenuDown = false; |
77 | 0 | mbSpinDown = false; |
78 | 0 | mbPrevIn = false; |
79 | 0 | mbNextIn = false; |
80 | |
|
81 | 0 | const OUString aGregorian(u"gregorian"_ustr); |
82 | 0 | maCalendarWrapper.loadCalendar( aGregorian, |
83 | 0 | Application::GetAppLocaleDataWrapper().getLanguageTag().getLocale()); |
84 | |
|
85 | 0 | if (maCalendarWrapper.getUniqueID() != aGregorian) |
86 | 0 | { |
87 | 0 | SAL_WARN( "vcl.control", "Calendar::ImplInit: No ``gregorian'' calendar available for locale ``" |
88 | 0 | << Application::GetAppLocaleDataWrapper().getLanguageTag().getBcp47() |
89 | 0 | << "'' and other calendars aren't supported. Using en-US fallback." ); |
90 | | |
91 | | /* If we ever wanted to support other calendars than Gregorian a lot of |
92 | | * rewrite would be necessary to internally replace use of class Date |
93 | | * with proper class CalendarWrapper methods, get rid of fixed 12 |
94 | | * months, fixed 7 days, ... */ |
95 | 0 | maCalendarWrapper.loadCalendar( aGregorian, lang::Locale( u"en"_ustr, u"US"_ustr, u""_ustr)); |
96 | 0 | } |
97 | | |
98 | 0 | SetFirstDate( maCurDate ); |
99 | 0 | ImplCalendarSelectDate( mpSelectTable.get(), maCurDate, true ); |
100 | | |
101 | | // generate other strings |
102 | 0 | maDayText = VclResId(STR_SVT_CALENDAR_DAY); |
103 | 0 | maWeekText = VclResId(STR_SVT_CALENDAR_WEEK); |
104 | | |
105 | | // create text for each day |
106 | 0 | for (sal_Int32 i = 0; i < 31; ++i) |
107 | 0 | { |
108 | 0 | maDayTexts[i] = OUString::number(i+1); |
109 | 0 | } |
110 | |
|
111 | 0 | ImplInitSettings(); |
112 | 0 | } |
113 | | |
114 | | void Calendar::ApplySettings(vcl::RenderContext& rRenderContext) |
115 | 0 | { |
116 | 0 | const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); |
117 | 0 | maSelColor = rStyleSettings.GetHighlightTextColor(); |
118 | 0 | SetPointFont(rRenderContext, rStyleSettings.GetToolFont()); |
119 | 0 | rRenderContext.SetTextColor(rStyleSettings.GetFieldTextColor()); |
120 | 0 | rRenderContext.SetBackground(Wallpaper(rStyleSettings.GetFieldColor())); |
121 | 0 | } |
122 | | |
123 | | void Calendar::ImplInitSettings() |
124 | 0 | { |
125 | 0 | const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); |
126 | 0 | maSelColor = rStyleSettings.GetHighlightTextColor(); |
127 | 0 | SetPointFont(*GetOutDev(), rStyleSettings.GetToolFont()); |
128 | 0 | SetTextColor(rStyleSettings.GetFieldTextColor()); |
129 | 0 | SetBackground(Wallpaper(rStyleSettings.GetFieldColor())); |
130 | 0 | } |
131 | | |
132 | | Calendar::Calendar(vcl::Window* pParent, WinBits nWinStyle) |
133 | 0 | : Control(pParent, nWinStyle & (WB_TABSTOP | WB_GROUP | WB_BORDER | WB_3DLOOK)) |
134 | 0 | , maCalendarWrapper(Application::GetAppLocaleDataWrapper().getComponentContext()) |
135 | 0 | , maOldFormatFirstDate(0, 0, 1900) |
136 | 0 | , maOldFormatLastDate(0, 0, 1900) |
137 | 0 | , maFirstDate(0, 0, 1900) |
138 | 0 | , maOldFirstDate(0, 0, 1900) |
139 | 0 | , maCurDate(Date::SYSTEM) |
140 | 0 | , maOldCurDate(0, 0, 1900) |
141 | 0 | { |
142 | 0 | ImplInit( nWinStyle ); |
143 | 0 | } Unexecuted instantiation: Calendar::Calendar(vcl::Window*, long) Unexecuted instantiation: Calendar::Calendar(vcl::Window*, long) |
144 | | |
145 | | Calendar::~Calendar() |
146 | 0 | { |
147 | 0 | disposeOnce(); |
148 | 0 | } |
149 | | |
150 | | void Calendar::dispose() |
151 | 0 | { |
152 | 0 | mpSelectTable.reset(); |
153 | 0 | mpOldSelectTable.reset(); |
154 | 0 | Control::dispose(); |
155 | 0 | } |
156 | | |
157 | | DayOfWeek Calendar::ImplGetWeekStart() const |
158 | 0 | { |
159 | | // Map i18n::Weekdays to Date DayOfWeek |
160 | 0 | DayOfWeek eDay; |
161 | 0 | const sal_Int16 nDay = maCalendarWrapper.getFirstDayOfWeek(); |
162 | |
|
163 | 0 | switch (nDay) |
164 | 0 | { |
165 | 0 | case i18n::Weekdays::SUNDAY : |
166 | 0 | eDay = SUNDAY; |
167 | 0 | break; |
168 | 0 | case i18n::Weekdays::MONDAY : |
169 | 0 | eDay = MONDAY; |
170 | 0 | break; |
171 | 0 | case i18n::Weekdays::TUESDAY : |
172 | 0 | eDay = TUESDAY; |
173 | 0 | break; |
174 | 0 | case i18n::Weekdays::WEDNESDAY : |
175 | 0 | eDay = WEDNESDAY; |
176 | 0 | break; |
177 | 0 | case i18n::Weekdays::THURSDAY : |
178 | 0 | eDay = THURSDAY; |
179 | 0 | break; |
180 | 0 | case i18n::Weekdays::FRIDAY : |
181 | 0 | eDay = FRIDAY; |
182 | 0 | break; |
183 | 0 | case i18n::Weekdays::SATURDAY : |
184 | 0 | eDay = SATURDAY; |
185 | 0 | break; |
186 | 0 | default: |
187 | 0 | SAL_WARN( "vcl.control", "Calendar::ImplGetWeekStart: broken i18n Gregorian calendar (getFirstDayOfWeek())"); |
188 | 0 | eDay = SUNDAY; |
189 | 0 | } |
190 | 0 | return eDay; |
191 | 0 | } |
192 | | |
193 | | void Calendar::ImplFormat() |
194 | 0 | { |
195 | 0 | if ( !mbFormat ) |
196 | 0 | return; |
197 | | |
198 | 0 | if ( mbCalc ) |
199 | 0 | { |
200 | 0 | const Size aOutSize = GetOutputSizePixel(); |
201 | |
|
202 | 0 | if ( (aOutSize.Width() <= 1) || (aOutSize.Height() <= 1) ) |
203 | 0 | return; |
204 | | |
205 | 0 | tools::Long n99TextWidth = GetTextWidth( u"99"_ustr ); |
206 | 0 | tools::Long nTextHeight = GetTextHeight(); |
207 | | |
208 | | // calculate width and x-position |
209 | 0 | mnDayWidth = n99TextWidth+DAY_OFFX; |
210 | 0 | mnMonthWidth = mnDayWidth*7; |
211 | 0 | mnMonthWidth += MONTH_BORDERX*2; |
212 | 0 | mnMonthPerLine = aOutSize.Width() / mnMonthWidth; |
213 | |
|
214 | 0 | if ( !mnMonthPerLine ) |
215 | 0 | mnMonthPerLine = 1; |
216 | |
|
217 | 0 | const tools::Long nOver = aOutSize.Width() - (mnMonthPerLine * mnMonthWidth) / mnMonthPerLine; |
218 | 0 | mnMonthWidth += nOver; |
219 | 0 | mnDaysOffX = MONTH_BORDERX; |
220 | 0 | mnDaysOffX += nOver/2; |
221 | | |
222 | | // calculate height and y-position |
223 | 0 | mnDayHeight = nTextHeight + DAY_OFFY; |
224 | 0 | mnWeekDayOffY = nTextHeight + TITLE_OFFY + (TITLE_BORDERY*2); |
225 | 0 | mnDaysOffY = mnWeekDayOffY + nTextHeight + WEEKDAY_OFFY; |
226 | 0 | mnMonthHeight = (mnDayHeight*6) + mnDaysOffY; |
227 | 0 | mnMonthHeight += MONTH_OFFY; |
228 | 0 | mnLines = aOutSize.Height() / mnMonthHeight; |
229 | |
|
230 | 0 | if ( !mnLines ) |
231 | 0 | mnLines = 1; |
232 | |
|
233 | 0 | mnMonthHeight += (aOutSize.Height()-(mnLines*mnMonthHeight)) / mnLines; |
234 | | |
235 | | // calculate spinfields |
236 | 0 | const tools::Long nSpinSize = nTextHeight + TITLE_BORDERY - SPIN_OFFY; |
237 | |
|
238 | 0 | maPrevRect.SetLeft( SPIN_OFFX ); |
239 | 0 | maPrevRect.SetTop( SPIN_OFFY ); |
240 | 0 | maPrevRect.SetRight( maPrevRect.Left()+nSpinSize ); |
241 | 0 | maPrevRect.SetBottom( maPrevRect.Top()+nSpinSize ); |
242 | 0 | maNextRect.SetLeft( aOutSize.Width()-SPIN_OFFX-nSpinSize-1 ); |
243 | 0 | maNextRect.SetTop( SPIN_OFFY ); |
244 | 0 | maNextRect.SetRight( maNextRect.Left()+nSpinSize ); |
245 | 0 | maNextRect.SetBottom( maNextRect.Top()+nSpinSize ); |
246 | | |
247 | | // Calculate DayOfWeekText (gets displayed in a narrow font) |
248 | 0 | maDayOfWeekText.clear(); |
249 | 0 | tools::Long nStartOffX = 0; |
250 | 0 | sal_Int16 nDay = maCalendarWrapper.getFirstDayOfWeek(); |
251 | |
|
252 | 0 | for ( sal_Int16 nDayOfWeek = 0; nDayOfWeek < 7; nDayOfWeek++ ) |
253 | 0 | { |
254 | | // Use narrow name. |
255 | 0 | const OUString aDayOfWeek(maCalendarWrapper.getDisplayName( |
256 | 0 | i18n::CalendarDisplayIndex::DAY, nDay, 2)); |
257 | |
|
258 | 0 | tools::Long nOffX = (mnDayWidth-GetTextWidth( aDayOfWeek ))/2; |
259 | |
|
260 | 0 | if ( !nDayOfWeek ) |
261 | 0 | nStartOffX = nOffX; |
262 | 0 | else |
263 | 0 | nOffX -= nStartOffX; |
264 | |
|
265 | 0 | nOffX += nDayOfWeek * mnDayWidth; |
266 | 0 | mnDayOfWeekAry[nDayOfWeek] = nOffX; |
267 | 0 | maDayOfWeekText += aDayOfWeek; |
268 | 0 | nDay++; |
269 | 0 | nDay %= 7; |
270 | 0 | } |
271 | | |
272 | | // header position for the last day of week |
273 | 0 | mnDayOfWeekAry[7] = mnMonthWidth; |
274 | |
|
275 | 0 | mbCalc = false; |
276 | 0 | } |
277 | | |
278 | | // calculate number of days |
279 | | |
280 | 0 | const DayOfWeek eStartDay = ImplGetWeekStart(); |
281 | |
|
282 | 0 | sal_uInt16 nWeekDay; |
283 | 0 | Date aTempDate = GetFirstMonth(); |
284 | 0 | maFirstDate = aTempDate; |
285 | 0 | nWeekDay = static_cast<sal_uInt16>(aTempDate.GetDayOfWeek()); |
286 | 0 | nWeekDay = (nWeekDay+(7-static_cast<sal_uInt16>(eStartDay))) % 7; |
287 | 0 | maFirstDate.AddDays( -nWeekDay ); |
288 | 0 | mnDayCount = nWeekDay; |
289 | 0 | sal_uInt16 nDaysInMonth; |
290 | 0 | sal_uInt16 nMonthCount = static_cast<sal_uInt16>(mnMonthPerLine*mnLines); |
291 | |
|
292 | 0 | for ( sal_uInt16 i = 0; i < nMonthCount; i++ ) |
293 | 0 | { |
294 | 0 | nDaysInMonth = aTempDate.GetDaysInMonth(); |
295 | 0 | mnDayCount += nDaysInMonth; |
296 | 0 | aTempDate.AddDays( nDaysInMonth ); |
297 | 0 | } |
298 | |
|
299 | 0 | Date aTempDate2 = aTempDate; |
300 | 0 | --aTempDate2; |
301 | 0 | nDaysInMonth = aTempDate2.GetDaysInMonth(); |
302 | 0 | aTempDate2.AddDays( -(nDaysInMonth-1) ); |
303 | 0 | nWeekDay = static_cast<sal_uInt16>(aTempDate2.GetDayOfWeek()); |
304 | 0 | nWeekDay = (nWeekDay+(7-static_cast<sal_uInt16>(eStartDay))) % 7; |
305 | 0 | mnDayCount += 42-nDaysInMonth-nWeekDay; |
306 | | |
307 | | // determine colours |
308 | 0 | maOtherColor = COL_LIGHTGRAY; |
309 | 0 | if ( maOtherColor.IsRGBEqual( GetBackground().GetColor() ) ) |
310 | 0 | maOtherColor = COL_GRAY; |
311 | |
|
312 | 0 | Date aLastDate = GetLastDate(); |
313 | 0 | if ( (maOldFormatLastDate != aLastDate) || |
314 | 0 | (maOldFormatFirstDate != maFirstDate) ) |
315 | 0 | { |
316 | 0 | maOldFormatFirstDate = maFirstDate; |
317 | 0 | maOldFormatLastDate = aLastDate; |
318 | 0 | } |
319 | | |
320 | | // get DateInfo |
321 | 0 | const sal_Int16 nNewFirstYear = maFirstDate.GetYear(); |
322 | 0 | const sal_Int16 nNewLastYear = GetLastDate().GetYear(); |
323 | |
|
324 | 0 | if ( mnFirstYear ) |
325 | 0 | { |
326 | 0 | if ( nNewFirstYear < mnFirstYear ) |
327 | 0 | mnFirstYear = nNewFirstYear; |
328 | |
|
329 | 0 | if ( nNewLastYear > mnLastYear ) |
330 | 0 | mnLastYear = nNewLastYear; |
331 | 0 | } |
332 | 0 | else |
333 | 0 | { |
334 | 0 | mnFirstYear = nNewFirstYear; |
335 | 0 | mnLastYear = nNewLastYear; |
336 | 0 | } |
337 | |
|
338 | 0 | mbFormat = false; |
339 | 0 | } |
340 | | |
341 | | sal_uInt16 Calendar::ImplDoHitTest(const Point& rPos, Date& rDate) const |
342 | 0 | { |
343 | 0 | if ( mbFormat ) |
344 | 0 | return 0; |
345 | | |
346 | 0 | if ( maPrevRect.Contains( rPos ) ) |
347 | 0 | return CALENDAR_HITTEST_PREV; |
348 | 0 | else if ( maNextRect.Contains( rPos ) ) |
349 | 0 | return CALENDAR_HITTEST_NEXT; |
350 | | |
351 | 0 | tools::Long nY; |
352 | 0 | tools::Long nOffX; |
353 | 0 | sal_Int32 nDay; |
354 | 0 | const DayOfWeek eStartDay = ImplGetWeekStart(); |
355 | |
|
356 | 0 | rDate = GetFirstMonth(); |
357 | 0 | nY = 0; |
358 | 0 | for ( tools::Long i = 0; i < mnLines; i++ ) |
359 | 0 | { |
360 | 0 | if ( rPos.Y() < nY ) |
361 | 0 | return 0; |
362 | | |
363 | 0 | tools::Long nX = 0; |
364 | 0 | const tools::Long nYMonth = nY + mnMonthHeight; |
365 | |
|
366 | 0 | for ( tools::Long j = 0; j < mnMonthPerLine; j++ ) |
367 | 0 | { |
368 | 0 | if ( (rPos.X() < nX) && (rPos.Y() < nYMonth) ) |
369 | 0 | return 0; |
370 | | |
371 | 0 | sal_uInt16 nDaysInMonth = rDate.GetDaysInMonth(); |
372 | | |
373 | | // matching month was found |
374 | 0 | if ( (rPos.X() > nX) && (rPos.Y() < nYMonth) && |
375 | 0 | (rPos.X() < nX+mnMonthWidth) ) |
376 | 0 | { |
377 | 0 | if ( rPos.Y() < (nY+(TITLE_BORDERY*2)+mnDayHeight)) |
378 | 0 | { |
379 | 0 | return CALENDAR_HITTEST_MONTHTITLE; |
380 | 0 | } |
381 | 0 | else |
382 | 0 | { |
383 | 0 | tools::Long nDayX = nX+mnDaysOffX; |
384 | 0 | tools::Long nDayY = nY+mnDaysOffY; |
385 | |
|
386 | 0 | if ( rPos.Y() < nDayY ) |
387 | 0 | return 0; |
388 | | |
389 | 0 | sal_Int32 nDayIndex = static_cast<sal_Int32>(rDate.GetDayOfWeek()); |
390 | 0 | nDayIndex = (nDayIndex+(7-static_cast<sal_Int32>(eStartDay))) % 7; |
391 | |
|
392 | 0 | if ( (i == 0) && (j == 0) ) |
393 | 0 | { |
394 | 0 | Date aTempDate = rDate; |
395 | 0 | aTempDate.AddDays( -nDayIndex ); |
396 | |
|
397 | 0 | for ( nDay = 0; nDay < nDayIndex; nDay++ ) |
398 | 0 | { |
399 | 0 | nOffX = nDayX + (nDay*mnDayWidth); |
400 | 0 | if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) && |
401 | 0 | (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) ) |
402 | 0 | { |
403 | 0 | rDate = aTempDate; |
404 | 0 | rDate.AddDays( nDay ); |
405 | 0 | return CALENDAR_HITTEST_DAY; |
406 | 0 | } |
407 | 0 | } |
408 | 0 | } |
409 | | |
410 | 0 | for ( nDay = 1; nDay <= nDaysInMonth; nDay++ ) |
411 | 0 | { |
412 | 0 | if ( rPos.Y() < nDayY ) |
413 | 0 | { |
414 | 0 | rDate.AddDays( nDayIndex ); |
415 | 0 | return 0; |
416 | 0 | } |
417 | | |
418 | 0 | nOffX = nDayX + (nDayIndex*mnDayWidth); |
419 | |
|
420 | 0 | if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) && |
421 | 0 | (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) ) |
422 | 0 | { |
423 | 0 | rDate.AddDays( nDay-1 ); |
424 | 0 | return CALENDAR_HITTEST_DAY; |
425 | 0 | } |
426 | | |
427 | 0 | if ( nDayIndex == 6 ) |
428 | 0 | { |
429 | 0 | nDayIndex = 0; |
430 | 0 | nDayY += mnDayHeight; |
431 | 0 | } |
432 | 0 | else |
433 | 0 | { |
434 | 0 | nDayIndex++; |
435 | 0 | } |
436 | 0 | } |
437 | | |
438 | 0 | if ( (i == mnLines-1) && (j == mnMonthPerLine-1) ) |
439 | 0 | { |
440 | 0 | sal_uInt16 nWeekDay = static_cast<sal_uInt16>(rDate.GetDayOfWeek()); |
441 | 0 | nWeekDay = (nWeekDay + (7-static_cast<sal_uInt16>(eStartDay))) % 7; |
442 | 0 | const sal_Int32 nDayCount = 42 - nDaysInMonth - nWeekDay; |
443 | 0 | Date aTempDate = rDate; |
444 | 0 | aTempDate.AddDays( nDaysInMonth ); |
445 | 0 | for ( nDay = 1; nDay <= nDayCount; nDay++ ) |
446 | 0 | { |
447 | 0 | if ( rPos.Y() < nDayY ) |
448 | 0 | { |
449 | 0 | rDate.AddDays( nDayIndex ); |
450 | 0 | return 0; |
451 | 0 | } |
452 | | |
453 | 0 | nOffX = nDayX + (nDayIndex*mnDayWidth); |
454 | |
|
455 | 0 | if ( (rPos.Y() >= nDayY) && (rPos.Y() < nDayY+mnDayHeight) && |
456 | 0 | (rPos.X() >= nOffX) && (rPos.X() < nOffX+mnDayWidth) ) |
457 | 0 | { |
458 | 0 | rDate = aTempDate; |
459 | 0 | rDate.AddDays( nDay-1 ); |
460 | 0 | return CALENDAR_HITTEST_DAY; |
461 | 0 | } |
462 | | |
463 | 0 | if ( nDayIndex == 6 ) |
464 | 0 | { |
465 | 0 | nDayIndex = 0; |
466 | 0 | nDayY += mnDayHeight; |
467 | 0 | } |
468 | 0 | else |
469 | 0 | { |
470 | 0 | nDayIndex++; |
471 | 0 | } |
472 | 0 | } |
473 | 0 | } |
474 | 0 | } |
475 | 0 | } |
476 | | |
477 | 0 | rDate.AddDays( nDaysInMonth ); |
478 | 0 | nX += mnMonthWidth; |
479 | 0 | } |
480 | | |
481 | 0 | nY += mnMonthHeight; |
482 | 0 | } |
483 | | |
484 | 0 | return 0; |
485 | 0 | } |
486 | | |
487 | | namespace |
488 | | { |
489 | | |
490 | | void ImplDrawSpinArrow(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, bool bPrev) |
491 | 0 | { |
492 | 0 | tools::Long i; |
493 | 0 | tools::Long n; |
494 | 0 | tools::Long nLines; |
495 | 0 | const tools::Long nHeight = rRect.GetHeight(); |
496 | 0 | const tools::Long nWidth = rRect.GetWidth(); |
497 | |
|
498 | 0 | if (nWidth < nHeight) |
499 | 0 | n = nWidth; |
500 | 0 | else |
501 | 0 | n = nHeight; |
502 | |
|
503 | 0 | if (!(n & 0x01)) |
504 | 0 | n--; |
505 | |
|
506 | 0 | nLines = n/2; |
507 | |
|
508 | 0 | tools::Rectangle aRect(Point( rRect.Left() + (nWidth / 2) - (nLines / 2), |
509 | 0 | rRect.Top() + (nHeight / 2) ), |
510 | 0 | Size(1, 1)); |
511 | 0 | if (!bPrev) |
512 | 0 | { |
513 | 0 | aRect.AdjustLeft(nLines ); |
514 | 0 | aRect.AdjustRight(nLines ); |
515 | 0 | } |
516 | |
|
517 | 0 | rRenderContext.DrawRect(aRect); |
518 | |
|
519 | 0 | for (i = 0; i < nLines; i++) |
520 | 0 | { |
521 | 0 | if (bPrev) |
522 | 0 | { |
523 | 0 | aRect.AdjustLeft( 1 ); |
524 | 0 | aRect.AdjustRight( 1 ); |
525 | 0 | } |
526 | 0 | else |
527 | 0 | { |
528 | 0 | aRect.AdjustLeft( -1 ); |
529 | 0 | aRect.AdjustRight( -1 ); |
530 | 0 | } |
531 | |
|
532 | 0 | aRect.AdjustTop( -1 ); |
533 | 0 | aRect.AdjustBottom( 1 ); |
534 | 0 | rRenderContext.DrawRect(aRect); |
535 | 0 | } |
536 | 0 | } |
537 | | |
538 | | } //end anonymous namespace |
539 | | |
540 | | void Calendar::ImplDrawSpin(vcl::RenderContext& rRenderContext ) |
541 | 0 | { |
542 | 0 | rRenderContext.SetLineColor(); |
543 | 0 | rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetButtonTextColor()); |
544 | |
|
545 | 0 | tools::Rectangle aOutRect = maPrevRect; |
546 | 0 | aOutRect.AdjustLeft(3 ); |
547 | 0 | aOutRect.AdjustTop(3 ); |
548 | 0 | aOutRect.AdjustRight( -3 ); |
549 | 0 | aOutRect.AdjustBottom( -3 ); |
550 | |
|
551 | 0 | ImplDrawSpinArrow(rRenderContext, aOutRect, true); |
552 | |
|
553 | 0 | aOutRect = maNextRect; |
554 | 0 | aOutRect.AdjustLeft(3 ); |
555 | 0 | aOutRect.AdjustTop(3 ); |
556 | 0 | aOutRect.AdjustRight( -3 ); |
557 | 0 | aOutRect.AdjustBottom( -3 ); |
558 | |
|
559 | 0 | ImplDrawSpinArrow(rRenderContext, aOutRect, false); |
560 | 0 | } |
561 | | |
562 | | void Calendar::ImplDrawDate(vcl::RenderContext& rRenderContext, |
563 | | tools::Long nX, tools::Long nY, |
564 | | sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear, |
565 | | bool bOther, sal_Int32 nToday ) |
566 | 0 | { |
567 | 0 | Color const* pTextColor = nullptr; |
568 | 0 | const OUString& rDay = maDayTexts[(nDay - 1) % std::size(maDayTexts)]; |
569 | 0 | tools::Rectangle aDateRect(nX, nY, nX + mnDayWidth - 1, nY + mnDayHeight - 1); |
570 | |
|
571 | 0 | bool bSel = false; |
572 | 0 | bool bFocus = false; |
573 | | |
574 | | // actual day |
575 | 0 | if ((nDay == maCurDate.GetDay()) && |
576 | 0 | (nMonth == maCurDate.GetMonth()) && |
577 | 0 | (nYear == maCurDate.GetYear())) |
578 | 0 | { |
579 | 0 | bFocus = true; |
580 | 0 | } |
581 | |
|
582 | 0 | if (mpSelectTable) |
583 | 0 | { |
584 | 0 | if (mpSelectTable->find(Date(nDay, nMonth, nYear).GetDate()) != mpSelectTable->end()) |
585 | 0 | bSel = true; |
586 | 0 | } |
587 | | |
588 | | // get textcolour |
589 | 0 | if (bSel) |
590 | 0 | pTextColor = &maSelColor; |
591 | 0 | else if (bOther) |
592 | 0 | pTextColor = &maOtherColor; |
593 | |
|
594 | 0 | if (bFocus) |
595 | 0 | HideFocus(); |
596 | | |
597 | | // display background |
598 | 0 | const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); |
599 | |
|
600 | 0 | if (bSel) |
601 | 0 | { |
602 | 0 | rRenderContext.SetLineColor(); |
603 | 0 | rRenderContext.SetFillColor(rStyleSettings.GetHighlightColor()); |
604 | 0 | rRenderContext.DrawRect(aDateRect); |
605 | 0 | } |
606 | | |
607 | | // display text |
608 | 0 | const tools::Long nTextX = nX + (mnDayWidth - GetTextWidth(rDay)) - (DAY_OFFX / 2); |
609 | 0 | const tools::Long nTextY = nY + (mnDayHeight - GetTextHeight()) / 2; |
610 | |
|
611 | 0 | if (pTextColor) |
612 | 0 | { |
613 | 0 | Color aOldColor = rRenderContext.GetTextColor(); |
614 | 0 | rRenderContext.SetTextColor(*pTextColor); |
615 | 0 | rRenderContext.DrawText(Point(nTextX, nTextY), rDay); |
616 | 0 | rRenderContext.SetTextColor(aOldColor); |
617 | 0 | } |
618 | 0 | else |
619 | 0 | { |
620 | 0 | rRenderContext.DrawText(Point(nTextX, nTextY), rDay); |
621 | 0 | } |
622 | | |
623 | | // today |
624 | 0 | Date aTodayDate(maCurDate); |
625 | |
|
626 | 0 | if (nToday) |
627 | 0 | aTodayDate.SetDate(nToday); |
628 | 0 | else |
629 | 0 | aTodayDate = Date(Date::SYSTEM); |
630 | |
|
631 | 0 | if ((nDay == aTodayDate.GetDay()) && |
632 | 0 | (nMonth == aTodayDate.GetMonth()) && |
633 | 0 | (nYear == aTodayDate.GetYear())) |
634 | 0 | { |
635 | 0 | rRenderContext.SetLineColor(rStyleSettings.GetWindowTextColor()); |
636 | 0 | rRenderContext.SetFillColor(); |
637 | 0 | rRenderContext.DrawRect(aDateRect); |
638 | 0 | } |
639 | | |
640 | | // if needed do FocusRect |
641 | 0 | if (bFocus && HasFocus()) |
642 | 0 | ShowFocus(aDateRect); |
643 | 0 | } |
644 | | |
645 | | void Calendar::ImplDraw(vcl::RenderContext& rRenderContext) |
646 | 0 | { |
647 | 0 | ImplFormat(); |
648 | |
|
649 | 0 | const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); |
650 | |
|
651 | 0 | Size aOutSize(GetOutputSizePixel()); |
652 | |
|
653 | 0 | tools::Long i; |
654 | 0 | tools::Long j; |
655 | 0 | tools::Long nY; |
656 | 0 | tools::Long nDeltaX; |
657 | 0 | tools::Long nDeltaY; |
658 | 0 | tools::Long nDayX; |
659 | 0 | tools::Long nDayY; |
660 | 0 | const sal_Int32 nToday = Date(Date::SYSTEM).GetDate(); |
661 | 0 | sal_uInt16 nDay; |
662 | 0 | sal_uInt16 nMonth; |
663 | 0 | sal_Int16 nYear; |
664 | 0 | Date aDate = GetFirstMonth(); |
665 | 0 | const DayOfWeek eStartDay = ImplGetWeekStart(); |
666 | |
|
667 | 0 | HideFocus(); |
668 | |
|
669 | 0 | nY = 0; |
670 | |
|
671 | 0 | for (i = 0; i < mnLines; i++) |
672 | 0 | { |
673 | | // display title bar |
674 | 0 | rRenderContext.SetLineColor(); |
675 | 0 | rRenderContext.SetFillColor(rStyleSettings.GetFaceColor()); |
676 | |
|
677 | 0 | tools::Rectangle aTitleRect(0, nY, aOutSize.Width() - 1, nY + mnDayHeight - DAY_OFFY + TITLE_BORDERY * 2); |
678 | |
|
679 | 0 | rRenderContext.DrawRect(aTitleRect); |
680 | |
|
681 | 0 | Point aTopLeft1(aTitleRect.Left(), aTitleRect.Top()); |
682 | 0 | Point aTopLeft2(aTitleRect.Left(), aTitleRect.Top() + 1); |
683 | 0 | Point aBottomRight1(aTitleRect.Right(), aTitleRect.Bottom()); |
684 | 0 | Point aBottomRight2(aTitleRect.Right(), aTitleRect.Bottom() - 1); |
685 | |
|
686 | 0 | rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor()); |
687 | 0 | rRenderContext.DrawLine(aTopLeft1, Point(aBottomRight1.X(), aTopLeft1.Y())); |
688 | 0 | rRenderContext.SetLineColor(rStyleSettings.GetLightColor() ); |
689 | 0 | rRenderContext.DrawLine(aTopLeft2, Point(aBottomRight2.X(), aTopLeft2.Y())); |
690 | 0 | rRenderContext.DrawLine(aTopLeft2, Point(aTopLeft2.X(), aBottomRight2.Y())); |
691 | 0 | rRenderContext.SetLineColor(rStyleSettings.GetShadowColor() ); |
692 | 0 | rRenderContext.DrawLine(Point(aTopLeft2.X(), aBottomRight2.Y()), aBottomRight2); |
693 | 0 | rRenderContext.DrawLine(Point(aBottomRight2.X(), aTopLeft2.Y()), aBottomRight2); |
694 | 0 | rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor()); |
695 | 0 | rRenderContext.DrawLine(Point(aTopLeft1.X(), aBottomRight1.Y()), aBottomRight1); |
696 | |
|
697 | 0 | Point aSepPos1(0, aTitleRect.Top() + TITLE_BORDERY); |
698 | 0 | Point aSepPos2(0, aTitleRect.Bottom() - TITLE_BORDERY); |
699 | |
|
700 | 0 | for (j = 0; j < mnMonthPerLine-1; j++) |
701 | 0 | { |
702 | 0 | aSepPos1.AdjustX(mnMonthWidth-1 ); |
703 | 0 | aSepPos2.setX( aSepPos1.X() ); |
704 | |
|
705 | 0 | rRenderContext.SetLineColor(rStyleSettings.GetShadowColor()); |
706 | 0 | rRenderContext.DrawLine(aSepPos1, aSepPos2); |
707 | |
|
708 | 0 | aSepPos1.AdjustX( 1 ); |
709 | 0 | aSepPos2.setX( aSepPos1.X() ); |
710 | |
|
711 | 0 | rRenderContext.SetLineColor(rStyleSettings.GetLightColor()); |
712 | 0 | rRenderContext.DrawLine(aSepPos1, aSepPos2); |
713 | 0 | } |
714 | |
|
715 | 0 | tools::Long nX = 0; |
716 | |
|
717 | 0 | for (j = 0; j < mnMonthPerLine; j++) |
718 | 0 | { |
719 | 0 | nMonth = aDate.GetMonth(); |
720 | 0 | nYear = aDate.GetYear(); |
721 | | |
722 | | // display month in title bar |
723 | 0 | nDeltaX = nX; |
724 | 0 | nDeltaY = nY + TITLE_BORDERY; |
725 | 0 | OUString aMonthText = maCalendarWrapper.getDisplayName(i18n::CalendarDisplayIndex::MONTH, nMonth - 1, 1) |
726 | 0 | + " " |
727 | 0 | + OUString::number(nYear); |
728 | |
|
729 | 0 | tools::Long nMonthTextWidth = rRenderContext.GetTextWidth(aMonthText); |
730 | 0 | tools::Long nMonthOffX1 = 0; |
731 | 0 | tools::Long nMonthOffX2 = 0; |
732 | |
|
733 | 0 | if (i == 0) |
734 | 0 | { |
735 | 0 | if (j == 0) |
736 | 0 | nMonthOffX1 = maPrevRect.Right() + 1; |
737 | |
|
738 | 0 | if (j == mnMonthPerLine - 1) |
739 | 0 | nMonthOffX2 = aOutSize.Width() - maNextRect.Left() + 1; |
740 | 0 | } |
741 | |
|
742 | 0 | const tools::Long nMaxMonthWidth = mnMonthWidth - nMonthOffX1 - nMonthOffX2 - 4; |
743 | |
|
744 | 0 | if (nMonthTextWidth > nMaxMonthWidth) |
745 | 0 | { |
746 | | // Abbreviated month name. |
747 | 0 | aMonthText = maCalendarWrapper.getDisplayName(i18n::CalendarDisplayIndex::MONTH, nMonth - 1, 0) |
748 | 0 | + " " |
749 | 0 | + OUString::number(nYear); |
750 | 0 | nMonthTextWidth = rRenderContext.GetTextWidth(aMonthText); |
751 | 0 | } |
752 | |
|
753 | 0 | tools::Long nTempOff = (mnMonthWidth - nMonthTextWidth + 1) / 2; |
754 | |
|
755 | 0 | if (nTempOff < nMonthOffX1) |
756 | 0 | { |
757 | 0 | nDeltaX += nMonthOffX1 + 1; |
758 | 0 | } |
759 | 0 | else |
760 | 0 | { |
761 | 0 | if (nTempOff + nMonthTextWidth > mnMonthWidth - nMonthOffX2) |
762 | 0 | nDeltaX += mnMonthWidth - nMonthOffX2 - nMonthTextWidth; |
763 | 0 | else |
764 | 0 | nDeltaX += nTempOff; |
765 | 0 | } |
766 | |
|
767 | 0 | rRenderContext.SetTextColor(rStyleSettings.GetButtonTextColor()); |
768 | 0 | rRenderContext.DrawText(Point(nDeltaX, nDeltaY), aMonthText); |
769 | 0 | rRenderContext.SetTextColor(rStyleSettings.GetWindowTextColor()); |
770 | | |
771 | | // display week bar |
772 | 0 | nDayX = nX + mnDaysOffX; |
773 | 0 | nDayY = nY + mnWeekDayOffY; |
774 | 0 | nDeltaY = nDayY + mnDayHeight; |
775 | |
|
776 | 0 | rRenderContext.SetLineColor(rStyleSettings.GetWindowTextColor()); |
777 | |
|
778 | 0 | const Point aStartPos(nDayX, nDeltaY); |
779 | |
|
780 | 0 | rRenderContext.DrawLine(aStartPos, Point(nDayX + (7 * mnDayWidth), nDeltaY)); |
781 | |
|
782 | 0 | KernArray aTmp; |
783 | |
|
784 | 0 | for (int k=0; k<7; ++k) |
785 | 0 | { |
786 | 0 | aTmp.push_back(mnDayOfWeekAry[k+1]); |
787 | 0 | } |
788 | |
|
789 | 0 | rRenderContext.DrawTextArray(Point(nDayX + mnDayOfWeekAry[0], nDayY), maDayOfWeekText, aTmp, {}, 0, aTmp.size()); |
790 | | |
791 | | // display days |
792 | 0 | const sal_uInt16 nDaysInMonth = aDate.GetDaysInMonth(); |
793 | 0 | nDayX = nX + mnDaysOffX; |
794 | 0 | nDayY = nY + mnDaysOffY; |
795 | 0 | sal_uInt16 nDayIndex = static_cast<sal_uInt16>(aDate.GetDayOfWeek()); |
796 | 0 | nDayIndex = (nDayIndex + (7 - static_cast<sal_uInt16>(eStartDay))) % 7; |
797 | |
|
798 | 0 | if (i == 0 && j == 0) |
799 | 0 | { |
800 | 0 | Date aTempDate = aDate; |
801 | 0 | aTempDate.AddDays( -nDayIndex ); |
802 | 0 | for (nDay = 0; nDay < nDayIndex; ++nDay) |
803 | 0 | { |
804 | 0 | nDeltaX = nDayX + (nDay * mnDayWidth); |
805 | 0 | ImplDrawDate(rRenderContext, nDeltaX, nDayY, nDay + aTempDate.GetDay(), |
806 | 0 | aTempDate.GetMonth(), aTempDate.GetYear(), |
807 | 0 | true, nToday); |
808 | 0 | } |
809 | 0 | } |
810 | |
|
811 | 0 | for (nDay = 1; nDay <= nDaysInMonth; nDay++) |
812 | 0 | { |
813 | 0 | nDeltaX = nDayX + (nDayIndex * mnDayWidth); |
814 | 0 | ImplDrawDate(rRenderContext, nDeltaX, nDayY, nDay, nMonth, nYear, |
815 | 0 | false, nToday); |
816 | 0 | if (nDayIndex == 6) |
817 | 0 | { |
818 | 0 | nDayIndex = 0; |
819 | 0 | nDayY += mnDayHeight; |
820 | 0 | } |
821 | 0 | else |
822 | 0 | { |
823 | 0 | nDayIndex++; |
824 | 0 | } |
825 | 0 | } |
826 | |
|
827 | 0 | if ((i == mnLines - 1) && (j == mnMonthPerLine - 1)) |
828 | 0 | { |
829 | 0 | sal_uInt16 nWeekDay = static_cast<sal_uInt16>(aDate.GetDayOfWeek()); |
830 | 0 | nWeekDay = (nWeekDay + (7 - static_cast<sal_uInt16>(eStartDay))) % 7; |
831 | 0 | const sal_uInt16 nDayCount = 42 - nDaysInMonth - nWeekDay; |
832 | 0 | Date aTempDate = aDate; |
833 | 0 | aTempDate.AddDays( nDaysInMonth ); |
834 | |
|
835 | 0 | for (nDay = 1; nDay <= nDayCount; ++nDay) |
836 | 0 | { |
837 | 0 | nDeltaX = nDayX + (nDayIndex * mnDayWidth); |
838 | 0 | ImplDrawDate(rRenderContext, nDeltaX, nDayY, nDay, |
839 | 0 | aTempDate.GetMonth(), aTempDate.GetYear(), |
840 | 0 | true, nToday); |
841 | 0 | if (nDayIndex == 6) |
842 | 0 | { |
843 | 0 | nDayIndex = 0; |
844 | 0 | nDayY += mnDayHeight; |
845 | 0 | } |
846 | 0 | else |
847 | 0 | { |
848 | 0 | nDayIndex++; |
849 | 0 | } |
850 | 0 | } |
851 | 0 | } |
852 | |
|
853 | 0 | aDate.AddDays( nDaysInMonth ); |
854 | 0 | nX += mnMonthWidth; |
855 | 0 | } |
856 | |
|
857 | 0 | nY += mnMonthHeight; |
858 | 0 | } |
859 | | |
860 | | // draw spin buttons |
861 | 0 | ImplDrawSpin(rRenderContext); |
862 | 0 | } |
863 | | |
864 | | void Calendar::ImplUpdateDate(const Date& rDate) |
865 | 0 | { |
866 | 0 | if (!IsReallyVisible() || !IsUpdateMode()) |
867 | 0 | return; |
868 | | |
869 | 0 | tools::Rectangle aDateRect(GetDateRect(rDate)); |
870 | |
|
871 | 0 | if (!aDateRect.IsEmpty()) |
872 | 0 | Invalidate(aDateRect); |
873 | 0 | } |
874 | | |
875 | | void Calendar::ImplUpdateSelection( IntDateSet* pOld ) |
876 | 0 | { |
877 | 0 | IntDateSet* pNew = mpSelectTable.get(); |
878 | |
|
879 | 0 | for (auto const& nKey : *pOld) |
880 | 0 | { |
881 | 0 | if ( pNew->find(nKey) == pNew->end() ) |
882 | 0 | { |
883 | 0 | const Date aTempDate(nKey); |
884 | 0 | ImplUpdateDate(aTempDate); |
885 | 0 | } |
886 | 0 | } |
887 | |
|
888 | 0 | for (auto const& nKey : *pNew) |
889 | 0 | { |
890 | 0 | if ( pOld->find(nKey) == pOld->end() ) |
891 | 0 | { |
892 | 0 | const Date aTempDate(nKey); |
893 | 0 | ImplUpdateDate(aTempDate); |
894 | 0 | } |
895 | 0 | } |
896 | 0 | } |
897 | | |
898 | | void Calendar::ImplMouseSelect(const Date& rDate, sal_uInt16 nHitTest) |
899 | 0 | { |
900 | 0 | IntDateSet aOldSel( *mpSelectTable ); |
901 | 0 | const Date aOldDate = maCurDate; |
902 | 0 | Date aTempDate = rDate; |
903 | |
|
904 | 0 | if ( !(nHitTest & CALENDAR_HITTEST_DAY) ) |
905 | 0 | --aTempDate; |
906 | |
|
907 | 0 | if ( !(nHitTest & CALENDAR_HITTEST_DAY) ) |
908 | 0 | aTempDate = maOldCurDate; |
909 | |
|
910 | 0 | if ( aTempDate != maCurDate ) |
911 | 0 | { |
912 | 0 | maCurDate = aTempDate; |
913 | 0 | ImplCalendarSelectDate( mpSelectTable.get(), aOldDate, false ); |
914 | 0 | ImplCalendarSelectDate( mpSelectTable.get(), maCurDate, true ); |
915 | 0 | } |
916 | |
|
917 | 0 | const bool bNewSel = aOldSel != *mpSelectTable; |
918 | |
|
919 | 0 | if (maCurDate == aOldDate && !bNewSel) |
920 | 0 | return; |
921 | | |
922 | 0 | HideFocus(); |
923 | |
|
924 | 0 | if ( bNewSel ) |
925 | 0 | ImplUpdateSelection( &aOldSel ); |
926 | |
|
927 | 0 | if ( !bNewSel || aOldSel.find( aOldDate.GetDate() ) == aOldSel.end() ) |
928 | 0 | ImplUpdateDate( aOldDate ); |
929 | | |
930 | | // assure focus rectangle is displayed again |
931 | 0 | if ( HasFocus() || !bNewSel |
932 | 0 | || mpSelectTable->find( maCurDate.GetDate() ) == mpSelectTable->end() ) |
933 | 0 | { |
934 | 0 | ImplUpdateDate( maCurDate ); |
935 | 0 | } |
936 | 0 | } |
937 | | |
938 | | void Calendar::ImplUpdate( bool bCalcNew ) |
939 | 0 | { |
940 | 0 | if (IsReallyVisible() && IsUpdateMode()) |
941 | 0 | { |
942 | 0 | if (bCalcNew && !mbCalc) |
943 | 0 | Invalidate(); |
944 | 0 | else if (!mbFormat && !mbCalc) |
945 | 0 | Invalidate(); |
946 | 0 | } |
947 | |
|
948 | 0 | if (bCalcNew) |
949 | 0 | mbCalc = true; |
950 | |
|
951 | 0 | mbFormat = true; |
952 | 0 | } |
953 | | |
954 | | void Calendar::ImplScrollCalendar( bool bPrev ) |
955 | 0 | { |
956 | 0 | Date aNewFirstMonth = GetFirstMonth(); |
957 | |
|
958 | 0 | if ( bPrev ) |
959 | 0 | { |
960 | 0 | --aNewFirstMonth; |
961 | 0 | aNewFirstMonth.AddDays( -(aNewFirstMonth.GetDaysInMonth()-1)); |
962 | 0 | } |
963 | 0 | else |
964 | 0 | { |
965 | 0 | aNewFirstMonth.AddDays( aNewFirstMonth.GetDaysInMonth()); |
966 | 0 | } |
967 | |
|
968 | 0 | SetFirstDate( aNewFirstMonth ); |
969 | 0 | } |
970 | | |
971 | | void Calendar::ImplShowMenu(const Point& rPos, const Date& rDate) |
972 | 0 | { |
973 | 0 | EndSelection(); |
974 | |
|
975 | 0 | Date aOldFirstDate = GetFirstMonth(); |
976 | 0 | ScopedVclPtrInstance<PopupMenu> aPopupMenu; |
977 | 0 | sal_uInt16 nMonthOff; |
978 | 0 | sal_uInt16 nCurItemId; |
979 | 0 | const sal_uInt16 nYear = rDate.GetYear() - 1; |
980 | 0 | sal_uInt16 i; |
981 | 0 | sal_uInt16 j; |
982 | 0 | sal_uInt16 nYearIdCount = 1000; |
983 | |
|
984 | 0 | nMonthOff = (rDate.GetYear()-aOldFirstDate.GetYear())*12; |
985 | |
|
986 | 0 | if ( aOldFirstDate.GetMonth() < rDate.GetMonth() ) |
987 | 0 | nMonthOff += rDate.GetMonth()-aOldFirstDate.GetMonth(); |
988 | 0 | else |
989 | 0 | nMonthOff -= aOldFirstDate.GetMonth()-rDate.GetMonth(); |
990 | | |
991 | | // construct menu (include years with different months) |
992 | 0 | for ( i = 0; i < MENU_YEAR_COUNT; i++ ) |
993 | 0 | { |
994 | 0 | VclPtrInstance<PopupMenu> pYearPopupMenu; |
995 | 0 | for ( j = 1; j <= 12; j++ ) |
996 | 0 | { |
997 | 0 | pYearPopupMenu->InsertItem( nYearIdCount+j, |
998 | 0 | maCalendarWrapper.getDisplayName( |
999 | 0 | i18n::CalendarDisplayIndex::MONTH, j-1, 1)); |
1000 | 0 | } |
1001 | |
|
1002 | 0 | aPopupMenu->InsertItem( 10+i, OUString::number( nYear+i ) ); |
1003 | 0 | aPopupMenu->SetPopupMenu( 10+i, pYearPopupMenu ); |
1004 | 0 | nYearIdCount += 1000; |
1005 | 0 | } |
1006 | |
|
1007 | 0 | mbMenuDown = true; |
1008 | 0 | nCurItemId = aPopupMenu->Execute(*this, rPos); |
1009 | 0 | mbMenuDown = false; |
1010 | |
|
1011 | 0 | if ( !nCurItemId ) |
1012 | 0 | return; |
1013 | | |
1014 | 0 | const sal_uInt16 nTempMonthOff = nMonthOff % 12; |
1015 | 0 | const sal_uInt16 nTempYearOff = nMonthOff / 12; |
1016 | 0 | sal_uInt16 nNewMonth = nCurItemId % 1000; |
1017 | 0 | sal_uInt16 nNewYear = nYear+((nCurItemId-1000)/1000); |
1018 | |
|
1019 | 0 | if ( nTempMonthOff < nNewMonth ) |
1020 | 0 | { |
1021 | 0 | nNewMonth = nNewMonth - nTempMonthOff; |
1022 | 0 | } |
1023 | 0 | else |
1024 | 0 | { |
1025 | 0 | nNewYear--; |
1026 | 0 | nNewMonth = 12-(nTempMonthOff-nNewMonth); |
1027 | 0 | } |
1028 | |
|
1029 | 0 | nNewYear = nNewYear - nTempYearOff; |
1030 | 0 | SetFirstDate( Date( 1, nNewMonth, nNewYear ) ); |
1031 | 0 | } |
1032 | | |
1033 | | void Calendar::ImplTracking(const Point& rPos, bool bRepeat) |
1034 | 0 | { |
1035 | 0 | Date aTempDate = maCurDate; |
1036 | 0 | const sal_uInt16 nHitTest = ImplDoHitTest(rPos, aTempDate); |
1037 | |
|
1038 | 0 | if (!mbSpinDown) |
1039 | 0 | { |
1040 | 0 | ImplMouseSelect( aTempDate, nHitTest ); |
1041 | 0 | return; |
1042 | 0 | } |
1043 | | |
1044 | 0 | mbPrevIn = (nHitTest & CALENDAR_HITTEST_PREV) != 0; |
1045 | 0 | mbNextIn = (nHitTest & CALENDAR_HITTEST_NEXT) != 0; |
1046 | |
|
1047 | 0 | if ( bRepeat && (mbPrevIn || mbNextIn) ) |
1048 | 0 | ImplScrollCalendar( mbPrevIn ); |
1049 | 0 | } |
1050 | | |
1051 | | void Calendar::ImplEndTracking( bool bCancel ) |
1052 | 0 | { |
1053 | 0 | const bool bSpinDown = mbSpinDown; |
1054 | |
|
1055 | 0 | mbDrag = false; |
1056 | 0 | mbSpinDown = false; |
1057 | 0 | mbPrevIn = false; |
1058 | 0 | mbNextIn = false; |
1059 | |
|
1060 | 0 | if ( bCancel ) |
1061 | 0 | { |
1062 | 0 | if ( maOldFirstDate != maFirstDate ) |
1063 | 0 | SetFirstDate( maOldFirstDate ); |
1064 | |
|
1065 | 0 | if ( !bSpinDown ) |
1066 | 0 | { |
1067 | 0 | IntDateSet aOldSel( *mpSelectTable ); |
1068 | 0 | const Date aOldDate = maCurDate; |
1069 | 0 | maCurDate = maOldCurDate; |
1070 | 0 | *mpSelectTable = *mpOldSelectTable; |
1071 | |
|
1072 | 0 | HideFocus(); |
1073 | 0 | ImplUpdateSelection( &aOldSel ); |
1074 | |
|
1075 | 0 | if ( aOldSel.find( aOldDate.GetDate() ) == aOldSel.end() ) |
1076 | 0 | ImplUpdateDate( aOldDate ); |
1077 | | |
1078 | | // assure focus rectangle is displayed again |
1079 | 0 | if ( HasFocus() || mpSelectTable->find( maCurDate.GetDate() ) == mpSelectTable->end() ) |
1080 | 0 | ImplUpdateDate( maCurDate ); |
1081 | 0 | } |
1082 | 0 | } |
1083 | |
|
1084 | 0 | if ( bSpinDown ) |
1085 | 0 | return; |
1086 | | |
1087 | 0 | if ( !bCancel ) |
1088 | 0 | { |
1089 | | // determine if we should scroll the visible area |
1090 | 0 | if ( !mpSelectTable->empty() ) |
1091 | 0 | { |
1092 | 0 | const Date aFirstSelDate(*mpSelectTable->begin()); |
1093 | 0 | const Date aLastSelDate(*mpSelectTable->rbegin()); |
1094 | |
|
1095 | 0 | if ( aLastSelDate < GetFirstMonth() ) |
1096 | 0 | ImplScrollCalendar( true ); |
1097 | 0 | else if ( GetLastMonth() < aFirstSelDate ) |
1098 | 0 | ImplScrollCalendar( false ); |
1099 | 0 | } |
1100 | 0 | } |
1101 | |
|
1102 | 0 | if ( !bCancel && ((maCurDate != maOldCurDate) || (*mpOldSelectTable != *mpSelectTable)) ) |
1103 | 0 | Select(); |
1104 | |
|
1105 | 0 | if ( (mnWinStyle & WB_TABSTOP) && !bCancel ) |
1106 | 0 | GrabFocus(); |
1107 | |
|
1108 | 0 | mpOldSelectTable.reset(); |
1109 | 0 | } |
1110 | | |
1111 | | void Calendar::MouseButtonDown(const MouseEvent& rMEvt) |
1112 | 0 | { |
1113 | 0 | if (!rMEvt.IsLeft() || mbMenuDown) |
1114 | 0 | { |
1115 | 0 | Control::MouseButtonDown( rMEvt ); |
1116 | 0 | return; |
1117 | 0 | } |
1118 | | |
1119 | 0 | Date aTempDate = maCurDate; |
1120 | 0 | const sal_uInt16 nHitTest = ImplDoHitTest(rMEvt.GetPosPixel(), aTempDate); |
1121 | |
|
1122 | 0 | if (!nHitTest) |
1123 | 0 | return; |
1124 | | |
1125 | 0 | if (nHitTest & CALENDAR_HITTEST_MONTHTITLE) |
1126 | 0 | { |
1127 | 0 | ImplShowMenu( rMEvt.GetPosPixel(), aTempDate ); |
1128 | 0 | return; |
1129 | 0 | } |
1130 | | |
1131 | 0 | maOldFirstDate = maFirstDate; |
1132 | |
|
1133 | 0 | mbPrevIn = (nHitTest & CALENDAR_HITTEST_PREV) != 0; |
1134 | 0 | mbNextIn = (nHitTest & CALENDAR_HITTEST_NEXT) != 0; |
1135 | |
|
1136 | 0 | if ( mbPrevIn || mbNextIn ) |
1137 | 0 | { |
1138 | 0 | mbSpinDown = true; |
1139 | |
|
1140 | 0 | ImplScrollCalendar( mbPrevIn ); |
1141 | | |
1142 | | // it should really read BUTTONREPEAT, therefore do not |
1143 | | // change it to SCROLLREPEAT, check with TH, |
1144 | | // why it could be different (71775) |
1145 | 0 | StartTracking( StartTrackingFlags::ButtonRepeat ); |
1146 | |
|
1147 | 0 | return; |
1148 | 0 | } |
1149 | | |
1150 | 0 | if ( (rMEvt.GetClicks() != 2) || !(nHitTest & CALENDAR_HITTEST_DAY) ) |
1151 | 0 | { |
1152 | 0 | maOldCurDate = maCurDate; |
1153 | 0 | mpOldSelectTable.reset(new IntDateSet( *mpSelectTable )); |
1154 | |
|
1155 | 0 | mbDrag = true; |
1156 | 0 | StartTracking(); |
1157 | |
|
1158 | 0 | ImplMouseSelect( aTempDate, nHitTest ); |
1159 | 0 | } |
1160 | |
|
1161 | 0 | if (rMEvt.GetClicks() == 2) |
1162 | 0 | maActivateHdl.Call(this); |
1163 | 0 | } |
1164 | | |
1165 | | void Calendar::Tracking(const TrackingEvent& rTEvt) |
1166 | 0 | { |
1167 | 0 | Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel(); |
1168 | |
|
1169 | 0 | if ( rTEvt.IsTrackingEnded() ) |
1170 | 0 | ImplEndTracking( rTEvt.IsTrackingCanceled() ); |
1171 | 0 | else |
1172 | 0 | ImplTracking( aMousePos, rTEvt.IsTrackingRepeat() ); |
1173 | 0 | } |
1174 | | |
1175 | | void Calendar::KeyInput(const KeyEvent& rKEvt) |
1176 | 0 | { |
1177 | 0 | Date aNewDate = maCurDate; |
1178 | |
|
1179 | 0 | switch ( rKEvt.GetKeyCode().GetCode() ) |
1180 | 0 | { |
1181 | 0 | case KEY_HOME: |
1182 | 0 | aNewDate.SetDay( 1 ); |
1183 | 0 | break; |
1184 | | |
1185 | 0 | case KEY_END: |
1186 | 0 | aNewDate.SetDay( aNewDate.GetDaysInMonth() ); |
1187 | 0 | break; |
1188 | | |
1189 | 0 | case KEY_LEFT: |
1190 | 0 | --aNewDate; |
1191 | 0 | break; |
1192 | | |
1193 | 0 | case KEY_RIGHT: |
1194 | 0 | ++aNewDate; |
1195 | 0 | break; |
1196 | | |
1197 | 0 | case KEY_UP: |
1198 | 0 | aNewDate.AddDays( -7 ); |
1199 | 0 | break; |
1200 | | |
1201 | 0 | case KEY_DOWN: |
1202 | 0 | aNewDate.AddDays( 7 ); |
1203 | 0 | break; |
1204 | | |
1205 | 0 | case KEY_PAGEUP: |
1206 | 0 | { |
1207 | 0 | Date aTempDate = aNewDate; |
1208 | 0 | aTempDate.AddDays( -(aNewDate.GetDay()+1) ); |
1209 | 0 | aNewDate.AddDays( -aTempDate.GetDaysInMonth() ); |
1210 | 0 | } |
1211 | 0 | break; |
1212 | | |
1213 | 0 | case KEY_PAGEDOWN: |
1214 | 0 | aNewDate.AddDays( aNewDate.GetDaysInMonth() ); |
1215 | 0 | break; |
1216 | | |
1217 | 0 | case KEY_RETURN: |
1218 | 0 | break; |
1219 | | |
1220 | 0 | default: |
1221 | 0 | Control::KeyInput( rKEvt ); |
1222 | 0 | break; |
1223 | 0 | } |
1224 | | |
1225 | 0 | if ( aNewDate != maCurDate ) |
1226 | 0 | { |
1227 | 0 | SetCurDate( aNewDate ); |
1228 | 0 | Select(); |
1229 | 0 | } |
1230 | |
|
1231 | 0 | if (rKEvt.GetKeyCode().GetCode() == KEY_RETURN) |
1232 | 0 | { |
1233 | 0 | if (maActivateHdl.IsSet()) |
1234 | 0 | maActivateHdl.Call(this); |
1235 | 0 | else |
1236 | 0 | Control::KeyInput(rKEvt); |
1237 | 0 | } |
1238 | 0 | } |
1239 | | |
1240 | | void Calendar::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) |
1241 | 0 | { |
1242 | 0 | ImplDraw(rRenderContext); |
1243 | 0 | } |
1244 | | |
1245 | | void Calendar::GetFocus() |
1246 | 0 | { |
1247 | 0 | ImplUpdateDate( maCurDate ); |
1248 | 0 | Control::GetFocus(); |
1249 | 0 | } |
1250 | | |
1251 | | void Calendar::LoseFocus() |
1252 | 0 | { |
1253 | 0 | HideFocus(); |
1254 | 0 | Control::LoseFocus(); |
1255 | 0 | } |
1256 | | |
1257 | | void Calendar::Resize() |
1258 | 0 | { |
1259 | 0 | ImplUpdate( true ); |
1260 | 0 | Control::Resize(); |
1261 | 0 | } |
1262 | | |
1263 | | void Calendar::RequestHelp(const HelpEvent& rHEvt) |
1264 | 0 | { |
1265 | 0 | if (!(rHEvt.GetMode() & (HelpEventMode::QUICK | HelpEventMode::BALLOON))) |
1266 | 0 | { |
1267 | 0 | Control::RequestHelp(rHEvt); |
1268 | 0 | return; |
1269 | 0 | } |
1270 | | |
1271 | 0 | Date aDate = maCurDate; |
1272 | |
|
1273 | 0 | if (!GetDate( ScreenToOutputPixel(rHEvt.GetMousePosPixel()), aDate )) |
1274 | 0 | return; |
1275 | | |
1276 | 0 | tools::Rectangle aDateRect = GetDateRect( aDate ); |
1277 | 0 | Point aPt = OutputToScreenPixel( aDateRect.TopLeft() ); |
1278 | 0 | aDateRect.SetLeft( aPt.X() ); |
1279 | 0 | aDateRect.SetTop( aPt.Y() ); |
1280 | 0 | aPt = OutputToScreenPixel( aDateRect.BottomRight() ); |
1281 | 0 | aDateRect.SetRight( aPt.X() ); |
1282 | 0 | aDateRect.SetBottom( aPt.Y() ); |
1283 | |
|
1284 | 0 | if (!(rHEvt.GetMode() & HelpEventMode::QUICK)) |
1285 | 0 | return; |
1286 | | |
1287 | 0 | maCalendarWrapper.setGregorianDateTime( DateTime(aDate) ); |
1288 | 0 | const sal_uInt16 nWeek = static_cast<sal_uInt16>(maCalendarWrapper.getValue(i18n::CalendarFieldIndex::WEEK_OF_YEAR)); |
1289 | 0 | const sal_uInt16 nMonth = aDate.GetMonth(); |
1290 | 0 | OUString aStr = maDayText |
1291 | 0 | + ": " |
1292 | 0 | + OUString::number(aDate.GetDayOfYear()) |
1293 | 0 | + " / " |
1294 | 0 | + maWeekText |
1295 | 0 | + ": " |
1296 | 0 | + OUString::number(nWeek); |
1297 | | |
1298 | | // if year is not the same, add it |
1299 | 0 | if ( (nMonth == 12) && (nWeek == 1) ) |
1300 | 0 | aStr += ", " + OUString::number(aDate.GetNextYear()); |
1301 | 0 | else if ( (nMonth == 1) && (nWeek > 50) ) |
1302 | 0 | aStr += ", " + OUString::number(aDate.GetYear()-1); |
1303 | |
|
1304 | 0 | Help::ShowQuickHelp( this, aDateRect, aStr ); |
1305 | 0 | } |
1306 | | |
1307 | | void Calendar::Command(const CommandEvent& rCEvt) |
1308 | 0 | { |
1309 | 0 | if ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) |
1310 | 0 | { |
1311 | 0 | if ( rCEvt.IsMouseEvent() ) |
1312 | 0 | { |
1313 | 0 | Date aTempDate = maCurDate; |
1314 | 0 | const sal_uInt16 nHitTest = ImplDoHitTest(rCEvt.GetMousePosPixel(), aTempDate); |
1315 | |
|
1316 | 0 | if ( nHitTest & CALENDAR_HITTEST_MONTHTITLE ) |
1317 | 0 | { |
1318 | 0 | ImplShowMenu( rCEvt.GetMousePosPixel(), aTempDate ); |
1319 | 0 | return; |
1320 | 0 | } |
1321 | 0 | } |
1322 | 0 | } |
1323 | 0 | else if ( rCEvt.GetCommand() == CommandEventId::Wheel ) |
1324 | 0 | { |
1325 | 0 | CommandWheelData const* const pData = rCEvt.GetWheelData(); |
1326 | |
|
1327 | 0 | if ( pData->GetMode() == CommandWheelMode::SCROLL ) |
1328 | 0 | { |
1329 | 0 | tools::Long nNotchDelta = pData->GetNotchDelta(); |
1330 | 0 | if ( nNotchDelta < 0 ) |
1331 | 0 | { |
1332 | 0 | while ( nNotchDelta < 0 ) |
1333 | 0 | { |
1334 | 0 | ImplScrollCalendar( true ); |
1335 | 0 | nNotchDelta++; |
1336 | 0 | } |
1337 | 0 | } |
1338 | 0 | else |
1339 | 0 | { |
1340 | 0 | while ( nNotchDelta > 0 ) |
1341 | 0 | { |
1342 | 0 | ImplScrollCalendar( false ); |
1343 | 0 | nNotchDelta--; |
1344 | 0 | } |
1345 | 0 | } |
1346 | |
|
1347 | 0 | return; |
1348 | 0 | } |
1349 | 0 | } |
1350 | | |
1351 | 0 | Control::Command( rCEvt ); |
1352 | 0 | } |
1353 | | |
1354 | | void Calendar::StateChanged( StateChangedType nType ) |
1355 | 0 | { |
1356 | 0 | Control::StateChanged( nType ); |
1357 | |
|
1358 | 0 | if ( nType == StateChangedType::InitShow ) |
1359 | 0 | ImplFormat(); |
1360 | 0 | } |
1361 | | |
1362 | | void Calendar::DataChanged(const DataChangedEvent& rDCEvt) |
1363 | 0 | { |
1364 | 0 | Control::DataChanged( rDCEvt ); |
1365 | |
|
1366 | 0 | if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) || |
1367 | 0 | (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) || |
1368 | 0 | ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) && |
1369 | 0 | (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) ) |
1370 | 0 | { |
1371 | 0 | ImplInitSettings(); |
1372 | 0 | Invalidate(); |
1373 | 0 | } |
1374 | 0 | } |
1375 | | |
1376 | | void Calendar::Select() |
1377 | 0 | { |
1378 | 0 | maSelectHdl.Call( this ); |
1379 | 0 | } |
1380 | | |
1381 | | Date Calendar::GetFirstSelectedDate() const |
1382 | 0 | { |
1383 | 0 | if ( !mpSelectTable->empty() ) |
1384 | 0 | return Date( *mpSelectTable->begin() ); |
1385 | | |
1386 | 0 | Date aDate( 0, 0, 0 ); |
1387 | 0 | return aDate; |
1388 | 0 | } |
1389 | | |
1390 | | void Calendar::SetCurDate(const Date& rNewDate) |
1391 | 0 | { |
1392 | 0 | if ( !rNewDate.IsValidAndGregorian() ) |
1393 | 0 | return; |
1394 | | |
1395 | 0 | if ( maCurDate == rNewDate ) |
1396 | 0 | return; |
1397 | | |
1398 | 0 | bool bUpdate = IsVisible() && IsUpdateMode(); |
1399 | 0 | Date aOldDate = maCurDate; |
1400 | 0 | maCurDate = rNewDate; |
1401 | |
|
1402 | 0 | ImplCalendarSelectDate( mpSelectTable.get(), aOldDate, false ); |
1403 | 0 | ImplCalendarSelectDate( mpSelectTable.get(), maCurDate, true ); |
1404 | | |
1405 | | // shift actual date in the visible area |
1406 | 0 | if ( mbFormat || (maCurDate < GetFirstMonth()) ) |
1407 | 0 | { |
1408 | 0 | SetFirstDate( maCurDate ); |
1409 | 0 | } |
1410 | 0 | else if ( maCurDate > GetLastMonth() ) |
1411 | 0 | { |
1412 | 0 | Date aTempDate = GetLastMonth(); |
1413 | 0 | tools::Long nDateOff = maCurDate-aTempDate; |
1414 | 0 | if ( nDateOff < 365 ) |
1415 | 0 | { |
1416 | 0 | Date aFirstDate = GetFirstMonth(); |
1417 | 0 | aFirstDate.AddDays( aFirstDate.GetDaysInMonth() ); |
1418 | 0 | ++aTempDate; |
1419 | 0 | while ( nDateOff > aTempDate.GetDaysInMonth() ) |
1420 | 0 | { |
1421 | 0 | aFirstDate.AddDays( aFirstDate.GetDaysInMonth() ); |
1422 | 0 | sal_Int32 nDaysInMonth = aTempDate.GetDaysInMonth(); |
1423 | 0 | aTempDate.AddDays( nDaysInMonth ); |
1424 | 0 | nDateOff -= nDaysInMonth; |
1425 | 0 | } |
1426 | 0 | SetFirstDate( aFirstDate ); |
1427 | 0 | } |
1428 | 0 | else |
1429 | 0 | SetFirstDate( maCurDate ); |
1430 | 0 | } |
1431 | 0 | else |
1432 | 0 | { |
1433 | 0 | if ( bUpdate ) |
1434 | 0 | { |
1435 | 0 | HideFocus(); |
1436 | 0 | ImplUpdateDate( aOldDate ); |
1437 | 0 | ImplUpdateDate( maCurDate ); |
1438 | 0 | } |
1439 | 0 | } |
1440 | 0 | } |
1441 | | |
1442 | | void Calendar::SetFirstDate(const Date& rNewFirstDate) |
1443 | 0 | { |
1444 | 0 | if ( maFirstDate != rNewFirstDate ) |
1445 | 0 | { |
1446 | 0 | maFirstDate = Date( 1, rNewFirstDate.GetMonth(), rNewFirstDate.GetYear() ); |
1447 | 0 | ImplUpdate(); |
1448 | 0 | } |
1449 | 0 | } |
1450 | | |
1451 | | Date Calendar::GetFirstMonth() const |
1452 | 0 | { |
1453 | 0 | if (maFirstDate.GetDay() > 1) |
1454 | 0 | { |
1455 | 0 | if (maFirstDate.GetMonth() == 12) |
1456 | 0 | return Date(1, 1, maFirstDate.GetNextYear()); |
1457 | 0 | else |
1458 | 0 | return Date(1, maFirstDate.GetMonth()+1, maFirstDate.GetYear()); |
1459 | 0 | } |
1460 | | |
1461 | 0 | return maFirstDate; |
1462 | 0 | } |
1463 | | |
1464 | | Date Calendar::GetLastMonth() const |
1465 | 0 | { |
1466 | 0 | Date aDate = GetFirstMonth(); |
1467 | 0 | const sal_uInt16 nMonthCount = GetMonthCount(); |
1468 | |
|
1469 | 0 | for ( sal_uInt16 i = 0; i < nMonthCount; i++ ) |
1470 | 0 | { |
1471 | 0 | aDate.AddDays( aDate.GetDaysInMonth() ); |
1472 | 0 | } |
1473 | |
|
1474 | 0 | --aDate; |
1475 | |
|
1476 | 0 | return aDate; |
1477 | 0 | } |
1478 | | |
1479 | | sal_uInt16 Calendar::GetMonthCount() const |
1480 | 0 | { |
1481 | 0 | if (mbFormat) |
1482 | 0 | return 1; |
1483 | | |
1484 | 0 | return static_cast<sal_uInt16>(mnMonthPerLine*mnLines); |
1485 | 0 | } |
1486 | | |
1487 | | bool Calendar::GetDate(const Point& rPos, Date& rDate) const |
1488 | 0 | { |
1489 | 0 | Date aDate = maCurDate; |
1490 | 0 | const sal_uInt16 nHitTest = ImplDoHitTest(rPos, aDate); |
1491 | |
|
1492 | 0 | if (nHitTest & CALENDAR_HITTEST_DAY) |
1493 | 0 | { |
1494 | 0 | rDate = aDate; |
1495 | 0 | return true; |
1496 | 0 | } |
1497 | | |
1498 | 0 | return false; |
1499 | 0 | } |
1500 | | |
1501 | | tools::Rectangle Calendar::GetDateRect(const Date& rDate) const |
1502 | 0 | { |
1503 | 0 | tools::Rectangle aRect; |
1504 | |
|
1505 | 0 | if ( mbFormat || (rDate < maFirstDate) || (rDate > (maFirstDate+mnDayCount)) ) |
1506 | 0 | return aRect; |
1507 | | |
1508 | 0 | tools::Long nX; |
1509 | 0 | tools::Long nY; |
1510 | 0 | sal_Int32 nDaysOff; |
1511 | 0 | sal_uInt16 nDayIndex; |
1512 | 0 | Date aDate = GetFirstMonth(); |
1513 | |
|
1514 | 0 | if ( rDate < aDate ) |
1515 | 0 | { |
1516 | 0 | aRect = GetDateRect( aDate ); |
1517 | 0 | nDaysOff = aDate-rDate; |
1518 | 0 | nX = nDaysOff*mnDayWidth; |
1519 | 0 | aRect.AdjustLeft( -nX ); |
1520 | 0 | aRect.AdjustRight( -nX ); |
1521 | |
|
1522 | 0 | return aRect; |
1523 | 0 | } |
1524 | 0 | else |
1525 | 0 | { |
1526 | 0 | Date aLastDate = GetLastMonth(); |
1527 | |
|
1528 | 0 | if ( rDate > aLastDate ) |
1529 | 0 | { |
1530 | 0 | sal_Int32 nWeekDay = static_cast<sal_Int32>(aLastDate.GetDayOfWeek()); |
1531 | 0 | nWeekDay = (nWeekDay+(7-ImplGetWeekStart())) % 7; |
1532 | 0 | aLastDate.AddDays( -nWeekDay ); |
1533 | 0 | aRect = GetDateRect( aLastDate ); |
1534 | 0 | nDaysOff = rDate-aLastDate; |
1535 | 0 | nDayIndex = 0; |
1536 | |
|
1537 | 0 | for ( sal_Int32 i = 0; i <= nDaysOff; i++ ) |
1538 | 0 | { |
1539 | 0 | if ( aLastDate == rDate ) |
1540 | 0 | { |
1541 | 0 | aRect.AdjustLeft(nDayIndex*mnDayWidth ); |
1542 | 0 | aRect.SetRight( aRect.Left()+mnDayWidth ); |
1543 | 0 | return aRect; |
1544 | 0 | } |
1545 | | |
1546 | 0 | if ( nDayIndex == 6 ) |
1547 | 0 | { |
1548 | 0 | nDayIndex = 0; |
1549 | 0 | aRect.AdjustTop(mnDayHeight ); |
1550 | 0 | aRect.AdjustBottom(mnDayHeight ); |
1551 | 0 | } |
1552 | 0 | else |
1553 | 0 | { |
1554 | 0 | nDayIndex++; |
1555 | 0 | } |
1556 | |
|
1557 | 0 | ++aLastDate; |
1558 | 0 | } |
1559 | 0 | } |
1560 | 0 | } |
1561 | | |
1562 | 0 | nY = 0; |
1563 | |
|
1564 | 0 | for ( tools::Long i = 0; i < mnLines; i++ ) |
1565 | 0 | { |
1566 | 0 | nX = 0; |
1567 | |
|
1568 | 0 | for ( tools::Long j = 0; j < mnMonthPerLine; j++ ) |
1569 | 0 | { |
1570 | 0 | sal_uInt16 nDaysInMonth = aDate.GetDaysInMonth(); |
1571 | | |
1572 | | // month is called |
1573 | 0 | if ( (aDate.GetMonth() == rDate.GetMonth()) && |
1574 | 0 | (aDate.GetYear() == rDate.GetYear()) ) |
1575 | 0 | { |
1576 | 0 | const tools::Long nDayX = nX + mnDaysOffX; |
1577 | 0 | tools::Long nDayY = nY+mnDaysOffY; |
1578 | 0 | nDayIndex = static_cast<sal_uInt16>(aDate.GetDayOfWeek()); |
1579 | 0 | nDayIndex = (nDayIndex+(7-static_cast<sal_uInt16>(ImplGetWeekStart()))) % 7; |
1580 | 0 | for ( sal_uInt16 nDay = 1; nDay <= nDaysInMonth; nDay++ ) |
1581 | 0 | { |
1582 | 0 | if ( nDay == rDate.GetDay() ) |
1583 | 0 | { |
1584 | 0 | aRect.SetLeft( nDayX + (nDayIndex*mnDayWidth) ); |
1585 | 0 | aRect.SetTop( nDayY ); |
1586 | 0 | aRect.SetRight( aRect.Left()+mnDayWidth ); |
1587 | 0 | aRect.SetBottom( aRect.Top()+mnDayHeight ); |
1588 | 0 | break; |
1589 | 0 | } |
1590 | | |
1591 | 0 | if ( nDayIndex == 6 ) |
1592 | 0 | { |
1593 | 0 | nDayIndex = 0; |
1594 | 0 | nDayY += mnDayHeight; |
1595 | 0 | } |
1596 | 0 | else |
1597 | 0 | { |
1598 | 0 | nDayIndex++; |
1599 | 0 | } |
1600 | 0 | } |
1601 | 0 | } |
1602 | |
|
1603 | 0 | aDate.AddDays( nDaysInMonth ); |
1604 | 0 | nX += mnMonthWidth; |
1605 | 0 | } |
1606 | |
|
1607 | 0 | nY += mnMonthHeight; |
1608 | 0 | } |
1609 | |
|
1610 | 0 | return aRect; |
1611 | 0 | } |
1612 | | |
1613 | | void Calendar::EndSelection() |
1614 | 0 | { |
1615 | 0 | if ( mbDrag || mbSpinDown ) |
1616 | 0 | { |
1617 | 0 | ReleaseMouse(); |
1618 | |
|
1619 | 0 | mbDrag = false; |
1620 | 0 | mbSpinDown = false; |
1621 | 0 | mbPrevIn = false; |
1622 | 0 | mbNextIn = false; |
1623 | 0 | } |
1624 | 0 | } |
1625 | | |
1626 | | Size Calendar::CalcWindowSizePixel() const |
1627 | 0 | { |
1628 | 0 | Size aSize; |
1629 | 0 | const tools::Long n99TextWidth = GetTextWidth(u"99"_ustr); |
1630 | 0 | const tools::Long nTextHeight = GetTextHeight(); |
1631 | |
|
1632 | 0 | aSize.AdjustWidth((n99TextWidth+DAY_OFFX)*7); |
1633 | 0 | aSize.AdjustWidth(MONTH_BORDERX*2 ); |
1634 | |
|
1635 | 0 | aSize.setHeight( nTextHeight + TITLE_OFFY + (TITLE_BORDERY*2) ); |
1636 | 0 | aSize.AdjustHeight(nTextHeight + WEEKDAY_OFFY ); |
1637 | 0 | aSize.AdjustHeight((nTextHeight+DAY_OFFY)*6); |
1638 | 0 | aSize.AdjustHeight(MONTH_OFFY ); |
1639 | |
|
1640 | 0 | return aSize; |
1641 | 0 | } |
1642 | | |
1643 | | Size Calendar::GetOptimalSize() const |
1644 | 0 | { |
1645 | 0 | return CalcWindowSizePixel(); |
1646 | 0 | } |
1647 | | |
1648 | | void Calendar::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) |
1649 | 0 | { |
1650 | 0 | Control::DumpAsPropertyTree(rJsonWriter); |
1651 | |
|
1652 | 0 | const auto aDate = GetFirstSelectedDate(); |
1653 | |
|
1654 | 0 | rJsonWriter.put("type", "calendar"); |
1655 | 0 | rJsonWriter.put("day", aDate.GetDay()); |
1656 | 0 | rJsonWriter.put("month", aDate.GetMonth()); |
1657 | 0 | rJsonWriter.put("year", aDate.GetYear()); |
1658 | 0 | } |
1659 | | |
1660 | | namespace |
1661 | | { |
1662 | | class ImplCFieldFloat final |
1663 | | { |
1664 | | private: |
1665 | | std::unique_ptr<weld::Builder> mxBuilder; |
1666 | | std::unique_ptr<weld::Container> mxContainer; |
1667 | | std::unique_ptr<weld::Calendar> mxCalendar; |
1668 | | std::unique_ptr<weld::Button> mxTodayBtn; |
1669 | | std::unique_ptr<weld::Button> mxNoneBtn; |
1670 | | |
1671 | | public: |
1672 | | ImplCFieldFloat(vcl::Window* pContainer) |
1673 | 0 | : mxBuilder(Application::CreateInterimBuilder(pContainer, u"svt/ui/calendar.ui"_ustr, false)) |
1674 | 0 | , mxContainer(mxBuilder->weld_container(u"Calendar"_ustr)) |
1675 | 0 | , mxCalendar(mxBuilder->weld_calendar(u"date"_ustr)) |
1676 | 0 | , mxTodayBtn(mxBuilder->weld_button(u"today"_ustr)) |
1677 | 0 | , mxNoneBtn(mxBuilder->weld_button(u"none"_ustr)) |
1678 | 0 | { |
1679 | 0 | } |
1680 | | |
1681 | 0 | weld::Calendar* GetCalendar() { return mxCalendar.get(); } |
1682 | | weld::Button* EnableTodayBtn(bool bEnable); |
1683 | | weld::Button* EnableNoneBtn(bool bEnable); |
1684 | | |
1685 | | void GrabFocus() |
1686 | 0 | { |
1687 | 0 | mxCalendar->grab_focus(); |
1688 | 0 | } |
1689 | | }; |
1690 | | } |
1691 | | |
1692 | | struct ImplCFieldFloatWin : public DropdownDockingWindow |
1693 | | { |
1694 | | explicit ImplCFieldFloatWin(vcl::Window* pParent); |
1695 | | virtual void dispose() override; |
1696 | | virtual ~ImplCFieldFloatWin() override; |
1697 | | virtual void GetFocus() override; |
1698 | | |
1699 | | std::unique_ptr<ImplCFieldFloat> mxWidget; |
1700 | | }; |
1701 | | |
1702 | | ImplCFieldFloatWin::ImplCFieldFloatWin(vcl::Window* pParent) |
1703 | 0 | : DropdownDockingWindow(pParent) |
1704 | 0 | { |
1705 | 0 | setDeferredProperties(); |
1706 | 0 | mxWidget.reset(new ImplCFieldFloat(m_xBox.get())); |
1707 | 0 | } Unexecuted instantiation: ImplCFieldFloatWin::ImplCFieldFloatWin(vcl::Window*) Unexecuted instantiation: ImplCFieldFloatWin::ImplCFieldFloatWin(vcl::Window*) |
1708 | | |
1709 | | ImplCFieldFloatWin::~ImplCFieldFloatWin() |
1710 | 0 | { |
1711 | 0 | disposeOnce(); |
1712 | 0 | } |
1713 | | |
1714 | | void ImplCFieldFloatWin::dispose() |
1715 | 0 | { |
1716 | 0 | mxWidget.reset(); |
1717 | 0 | DropdownDockingWindow::dispose(); |
1718 | 0 | } |
1719 | | |
1720 | | void ImplCFieldFloatWin::GetFocus() |
1721 | 0 | { |
1722 | 0 | DropdownDockingWindow::GetFocus(); |
1723 | |
|
1724 | 0 | if (!mxWidget) |
1725 | 0 | return; |
1726 | | |
1727 | 0 | mxWidget->GrabFocus(); |
1728 | 0 | } |
1729 | | |
1730 | | weld::Button* ImplCFieldFloat::EnableTodayBtn(bool bEnable) |
1731 | 0 | { |
1732 | 0 | mxTodayBtn->set_visible(bEnable); |
1733 | 0 | return bEnable ? mxTodayBtn.get() : nullptr; |
1734 | 0 | } |
1735 | | |
1736 | | weld::Button* ImplCFieldFloat::EnableNoneBtn(bool bEnable) |
1737 | 0 | { |
1738 | 0 | mxNoneBtn->set_visible(bEnable); |
1739 | 0 | return bEnable ? mxNoneBtn.get() : nullptr; |
1740 | 0 | } |
1741 | | |
1742 | | CalendarField::CalendarField(vcl::Window* pParent, WinBits nWinStyle) |
1743 | 0 | : DateField(pParent, nWinStyle) |
1744 | 0 | , mpFloatWin(nullptr) |
1745 | 0 | , mpTodayBtn(nullptr) |
1746 | 0 | , mpNoneBtn(nullptr) |
1747 | 0 | , mbToday(false) |
1748 | 0 | , mbNone(false) |
1749 | 0 | { |
1750 | 0 | } Unexecuted instantiation: CalendarField::CalendarField(vcl::Window*, long) Unexecuted instantiation: CalendarField::CalendarField(vcl::Window*, long) |
1751 | | |
1752 | | CalendarField::~CalendarField() |
1753 | 0 | { |
1754 | 0 | disposeOnce(); |
1755 | 0 | } |
1756 | | |
1757 | | void CalendarField::dispose() |
1758 | 0 | { |
1759 | 0 | mpTodayBtn = nullptr; |
1760 | 0 | mpNoneBtn = nullptr; |
1761 | 0 | mpFloatWin.disposeAndClear(); |
1762 | 0 | DateField::dispose(); |
1763 | 0 | } |
1764 | | |
1765 | | IMPL_LINK(CalendarField, ImplSelectHdl, weld::Calendar&, rCalendar, void) |
1766 | 0 | { |
1767 | 0 | Date aNewDate = rCalendar.get_date(); |
1768 | |
|
1769 | 0 | vcl::Window::GetDockingManager()->EndPopupMode(mpFloatWin); |
1770 | 0 | mpFloatWin->EnableDocking(false); |
1771 | |
|
1772 | 0 | EndDropDown(); |
1773 | 0 | GrabFocus(); |
1774 | |
|
1775 | 0 | if ( IsEmptyDate() || ( aNewDate != GetDate() ) ) |
1776 | 0 | { |
1777 | 0 | SetDate( aNewDate ); |
1778 | 0 | SetModifyFlag(); |
1779 | 0 | Modify(); |
1780 | 0 | } |
1781 | 0 | } |
1782 | | |
1783 | | IMPL_LINK(CalendarField, ImplClickHdl, weld::Button&, rBtn, void) |
1784 | 0 | { |
1785 | 0 | vcl::Window::GetDockingManager()->EndPopupMode(mpFloatWin); |
1786 | 0 | mpFloatWin->EnableDocking(false); |
1787 | 0 | EndDropDown(); |
1788 | 0 | GrabFocus(); |
1789 | |
|
1790 | 0 | if (&rBtn == mpTodayBtn) |
1791 | 0 | { |
1792 | 0 | Date aToday( Date::SYSTEM ); |
1793 | 0 | if ( (aToday != GetDate()) || IsEmptyDate() ) |
1794 | 0 | { |
1795 | 0 | SetDate( aToday ); |
1796 | 0 | SetModifyFlag(); |
1797 | 0 | Modify(); |
1798 | 0 | } |
1799 | 0 | } |
1800 | 0 | else if (&rBtn == mpNoneBtn) |
1801 | 0 | { |
1802 | 0 | if ( !IsEmptyDate() ) |
1803 | 0 | { |
1804 | 0 | SetEmptyDate(); |
1805 | 0 | SetModifyFlag(); |
1806 | 0 | Modify(); |
1807 | 0 | } |
1808 | 0 | } |
1809 | 0 | } |
1810 | | |
1811 | | IMPL_LINK_NOARG(CalendarField, ImplPopupModeEndHdl, FloatingWindow*, void) |
1812 | 0 | { |
1813 | 0 | EndDropDown(); |
1814 | 0 | GrabFocus(); |
1815 | 0 | } |
1816 | | |
1817 | | bool CalendarField::ShowDropDown( bool bShow ) |
1818 | 0 | { |
1819 | 0 | if (!bShow) |
1820 | 0 | { |
1821 | 0 | vcl::Window::GetDockingManager()->EndPopupMode(mpFloatWin); |
1822 | |
|
1823 | 0 | mpFloatWin->EnableDocking(false); |
1824 | |
|
1825 | 0 | EndDropDown(); |
1826 | |
|
1827 | 0 | return true; |
1828 | 0 | } |
1829 | | |
1830 | 0 | if ( !mpFloatWin ) |
1831 | 0 | mpFloatWin = VclPtr<ImplCFieldFloatWin>::Create( this ); |
1832 | |
|
1833 | 0 | Date aDate = GetDate(); |
1834 | |
|
1835 | 0 | if ( IsEmptyDate() || !aDate.IsValidAndGregorian() ) |
1836 | 0 | aDate = Date( Date::SYSTEM ); |
1837 | |
|
1838 | 0 | weld::Calendar* pCalendar = mpFloatWin->mxWidget->GetCalendar(); |
1839 | 0 | pCalendar->set_date( aDate ); |
1840 | 0 | pCalendar->connect_activated(LINK(this, CalendarField, ImplSelectHdl)); |
1841 | |
|
1842 | 0 | mpTodayBtn = mpFloatWin->mxWidget->EnableTodayBtn(mbToday); |
1843 | 0 | mpNoneBtn = mpFloatWin->mxWidget->EnableNoneBtn(mbNone); |
1844 | |
|
1845 | 0 | if (mpTodayBtn) |
1846 | 0 | mpTodayBtn->connect_clicked( LINK( this, CalendarField, ImplClickHdl ) ); |
1847 | |
|
1848 | 0 | if (mpNoneBtn) |
1849 | 0 | mpNoneBtn->connect_clicked( LINK( this, CalendarField, ImplClickHdl ) ); |
1850 | |
|
1851 | 0 | const Point aPos(GetParent()->OutputToScreenPixel(GetPosPixel())); |
1852 | |
|
1853 | 0 | tools::Rectangle aRect(aPos, GetSizePixel()); |
1854 | 0 | aRect.AdjustBottom( -1 ); |
1855 | |
|
1856 | 0 | DockingManager* pDockingManager = vcl::Window::GetDockingManager(); |
1857 | 0 | mpFloatWin->EnableDocking(true); |
1858 | 0 | pDockingManager->SetPopupModeEndHdl(mpFloatWin, LINK(this, CalendarField, ImplPopupModeEndHdl)); |
1859 | 0 | pDockingManager->StartPopupMode(mpFloatWin, aRect, FloatWinPopupFlags::Down | FloatWinPopupFlags::GrabFocus); |
1860 | |
|
1861 | 0 | return true; |
1862 | 0 | } |
1863 | | |
1864 | | void CalendarField::StateChanged( StateChangedType nStateChange ) |
1865 | 0 | { |
1866 | 0 | DateField::StateChanged( nStateChange ); |
1867 | |
|
1868 | 0 | if ( ( nStateChange == StateChangedType::Style ) && GetSubEdit() ) |
1869 | 0 | { |
1870 | 0 | const WinBits nAllAlignmentBits = (WB_LEFT | WB_CENTER | WB_RIGHT | WB_TOP | WB_VCENTER | WB_BOTTOM); |
1871 | 0 | const WinBits nMyAlignment = GetStyle() & nAllAlignmentBits; |
1872 | 0 | GetSubEdit()->SetStyle( ( GetSubEdit()->GetStyle() & ~nAllAlignmentBits ) | nMyAlignment ); |
1873 | 0 | } |
1874 | 0 | } |
1875 | | |
1876 | | // tdf#142783 consider the Edit and its DropDown as one compound control for the purpose of |
1877 | | // notification of loss of focus from the control |
1878 | | bool CalendarField::FocusWindowBelongsToControl(const vcl::Window* pFocusWin) const |
1879 | 0 | { |
1880 | 0 | return DateField::FocusWindowBelongsToControl(pFocusWin) || (mpFloatWin && mpFloatWin->ImplIsWindowOrChild(pFocusWin)); |
1881 | 0 | } |
1882 | | |
1883 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |