Bug Summary

File:home/maarten/src/libreoffice/core/include/rtl/ref.hxx
Warning:line 192, column 9
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name calendar.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/glm -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/libmount -isystem /usr/include/blkid -isystem /usr/include/cairo -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/pixman-1 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/libxml2 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/dbus-1.0 -isystem /usr/lib64/dbus-1.0/include -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D VCL_DLLIMPLEMENTATION -D DLLIMPLEMENTATION_UITEST -D CUI_DLL_NAME="libcuilo.so" -D DESKTOP_DETECTOR_DLL_NAME="libdesktop_detectorlo.so" -D TK_DLL_NAME="libtklo.so" -D SYSTEM_ZLIB -D GLM_FORCE_CTOR_INIT -D SK_USER_CONFIG_HEADER=</home/maarten/src/libreoffice/core/config_host/config_skia.h> -D SKIA_DLL -D ENABLE_CUPS -D HAVE_VALGRIND_HEADERS -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/epoxy/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/core -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/effects -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/config -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/ports -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/third_party/vulkan -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/tools/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia -I /home/maarten/src/libreoffice/core/external/skia/inc/ -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/lcms2/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/harfbuzz/src -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/graphite/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium/public -D COMPONENT_BUILD -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libpng -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libjpeg-turbo -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/vcl/inc -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libxml2 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/vcl/source/control/calendar.cxx

/home/maarten/src/libreoffice/core/vcl/source/control/calendar.cxx

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

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

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#ifndef INCLUDED_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
2
Calling copy constructor for 'Reference<ImplCFieldFloatWin>'
5
Returning from copy constructor for 'Reference<ImplCFieldFloatWin>'
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
6
Calling 'Reference::clear'
13
Returning; memory was released
205 if (aTmp.get()) {
14
Calling 'Reference::get'
206 aTmp->disposeOnce();
207 }
208 }
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

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#ifndef INCLUDED_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
3
Assuming field 'm_pBody' is non-null
4
Taking true branch
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody)
113 m_pBody->release();
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody)
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld)
127 pOld->release();
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody
6.1
Field 'm_pBody' is non-null
6.1
Field 'm_pBody' is non-null
6.1
Field 'm_pBody' is non-null
6.1
Field 'm_pBody' is non-null
)
7
Taking true branch
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
8
Calling 'VclReferenceBase::release'
12
Returning; memory was released
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
15
Use of memory after it is freed
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

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#ifndef INCLUDED_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
9
Assuming the condition is true
10
Taking true branch
40 delete this;
11
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif