1/*
2 SPDX-FileCopyrightText: 2004 Bram Schoenmakers <bramschoenmakers@kde.nl>
3 SPDX-License-Identifier: LGPL-2.0-or-later
4*/
5
6#include "kdatepickerpopup.h"
7#include "kdatepicker.h"
8#include "kdaterangecontrol_p.h"
9
10#include <QDateTime>
11#include <QLocale>
12#include <QWidgetAction>
13
14class KDatePickerAction : public QWidgetAction
15{
16public:
17 KDatePickerAction(KDatePicker *widget, QObject *parent)
18 : QWidgetAction(parent)
19 , mDatePicker(widget)
20 , mOriginalParent(widget->parentWidget())
21 {
22 }
23
24protected:
25 QWidget *createWidget(QWidget *parent) override
26 {
27 mDatePicker->setParent(parent);
28 return mDatePicker;
29 }
30
31 void deleteWidget(QWidget *widget) override
32 {
33 if (widget != mDatePicker) {
34 return;
35 }
36
37 mDatePicker->setParent(mOriginalParent);
38 }
39
40private:
41 KDatePicker *const mDatePicker;
42 QWidget *const mOriginalParent;
43};
44
45class KDatePickerPopupPrivate : public KDateRangeControlPrivate
46{
47public:
48 explicit KDatePickerPopupPrivate(KDatePickerPopup *qq)
49 : q(qq)
50 {
51 }
52
53 void addMenuAction(const QString &text, const QDate &date);
54 void buildMenu();
55 void menuActionTriggered(QAction *action);
56 void slotDateChanged(QDate);
57
58 KDatePickerPopup *const q;
59 KDatePicker *mDatePicker = nullptr;
60 KDatePickerPopup::Modes mModes;
61 QMap<QDate, QString> m_dateMap;
62};
63
64void KDatePickerPopupPrivate::addMenuAction(const QString &text, const QDate &date)
65{
66 // skip out-of-range dates
67 // an invalid date is ok though, that's for the "No Date" action
68 if (date.isValid() && !isInDateRange(date)) {
69 return;
70 }
71
72 QAction *action = new QAction(q);
73 action->setText(text);
74 action->setData(date);
75 QObject::connect(sender: action, signal: &QAction::triggered, context: q, slot: [this, action]() {
76 Q_EMIT q->dateChanged(date: action->data().toDate());
77 });
78 q->addAction(action);
79}
80
81void KDatePickerPopupPrivate::buildMenu()
82{
83 q->clear();
84
85 if (mModes & KDatePickerPopup::DatePicker) {
86 q->addAction(action: new KDatePickerAction(mDatePicker, q));
87
88 if ((mModes & KDatePickerPopup::NoDate) || (mModes & KDatePickerPopup::Words)) {
89 q->addSeparator();
90 }
91 }
92
93 if (mModes & KDatePickerPopup::Words) {
94 if (m_dateMap.isEmpty()) {
95 const QDate today = QDate::currentDate();
96 addMenuAction(text: KDatePickerPopup::tr(s: "Next Year", c: "@option next year"), date: today.addYears(years: 1));
97 addMenuAction(text: KDatePickerPopup::tr(s: "Next Month", c: "@option next month"), date: today.addMonths(months: 1));
98 addMenuAction(text: KDatePickerPopup::tr(s: "Next Week", c: "@option next week"), date: today.addDays(days: 7));
99 addMenuAction(text: KDatePickerPopup::tr(s: "Tomorrow", c: "@option tomorrow"), date: today.addDays(days: 1));
100 addMenuAction(text: KDatePickerPopup::tr(s: "Today", c: "@option today"), date: today);
101 addMenuAction(text: KDatePickerPopup::tr(s: "Yesterday", c: "@option yesterday"), date: today.addDays(days: -1));
102 addMenuAction(text: KDatePickerPopup::tr(s: "Last Week", c: "@option last week"), date: today.addDays(days: -7));
103 addMenuAction(text: KDatePickerPopup::tr(s: "Last Month", c: "@option last month"), date: today.addMonths(months: -1));
104 addMenuAction(text: KDatePickerPopup::tr(s: "Last Year", c: "@option last year"), date: today.addYears(years: -1));
105 } else {
106 for (auto it = m_dateMap.constBegin(); it != m_dateMap.constEnd(); ++it) {
107 if (it.value().isEmpty()) {
108 addMenuAction(text: QLocale().toString(date: it.key()), date: it.key());
109 } else if (it.value().toLower() == QLatin1String("separator")) {
110 q->addSeparator();
111 } else {
112 addMenuAction(text: it.value(), date: it.key());
113 }
114 }
115 }
116
117 if (mModes & KDatePickerPopup::NoDate) {
118 q->addSeparator();
119 }
120 }
121
122 if (mModes & KDatePickerPopup::NoDate) {
123 addMenuAction(text: KDatePickerPopup::tr(s: "No Date", c: "@option do not specify a date"), date: QDate());
124 }
125}
126
127void KDatePickerPopupPrivate::slotDateChanged(QDate date)
128{
129 Q_EMIT q->dateChanged(date);
130 q->hide();
131}
132
133KDatePickerPopup::KDatePickerPopup(Modes modes, QDate date, QWidget *parent)
134 : QMenu(parent)
135 , d(new KDatePickerPopupPrivate(this))
136{
137 d->mModes = modes;
138
139 d->mDatePicker = new KDatePicker(this);
140 d->mDatePicker->setCloseButton(false);
141
142 connect(sender: d->mDatePicker, signal: &KDatePicker::dateEntered, context: this, slot: [this](QDate date) {
143 d->slotDateChanged(date);
144 });
145 connect(sender: d->mDatePicker, signal: &KDatePicker::dateSelected, context: this, slot: [this](QDate date) {
146 d->slotDateChanged(date);
147 });
148
149 d->mDatePicker->setDate(date);
150
151 connect(sender: this, signal: &QMenu::aboutToShow, context: this, slot: [this]() {
152 d->buildMenu();
153 });
154}
155
156KDatePickerPopup::~KDatePickerPopup() = default;
157
158KDatePicker *KDatePickerPopup::datePicker() const
159{
160 return d->mDatePicker;
161}
162
163void KDatePickerPopup::setDate(QDate date)
164{
165 d->mDatePicker->setDate(date);
166}
167
168KDatePickerPopup::Modes KDatePickerPopup::modes() const
169{
170 return d->mModes;
171}
172
173void KDatePickerPopup::setModes(KDatePickerPopup::Modes modes)
174{
175 d->mModes = modes;
176}
177
178void KDatePickerPopup::setDateRange(const QDate &minDate, const QDate &maxDate)
179{
180 d->setDateRange(minDate, maxDate);
181}
182
183QMap<QDate, QString> KDatePickerPopup::dateMap() const
184{
185 return d->m_dateMap;
186}
187
188void KDatePickerPopup::setDateMap(const QMap<QDate, QString> &dateMap)
189{
190 d->m_dateMap = dateMap;
191}
192
193#include "moc_kdatepickerpopup.cpp"
194

source code of kwidgetsaddons/src/kdatepickerpopup.cpp