Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */