| 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 | |
| 14 | class KDatePickerAction : public QWidgetAction |
| 15 | { |
| 16 | public: |
| 17 | KDatePickerAction(KDatePicker *widget, QObject *parent) |
| 18 | : QWidgetAction(parent) |
| 19 | , mDatePicker(widget) |
| 20 | , mOriginalParent(widget->parentWidget()) |
| 21 | { |
| 22 | } |
| 23 | |
| 24 | protected: |
| 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 | |
| 40 | private: |
| 41 | KDatePicker *const mDatePicker; |
| 42 | QWidget *const mOriginalParent; |
| 43 | }; |
| 44 | |
| 45 | class : public KDateRangeControlPrivate |
| 46 | { |
| 47 | public: |
| 48 | explicit (KDatePickerPopup *qq) |
| 49 | : q(qq) |
| 50 | { |
| 51 | } |
| 52 | |
| 53 | void addMenuAction(const QString &text, const QDate &date); |
| 54 | void buildMenu(); |
| 55 | void (QAction *action); |
| 56 | void slotDateChanged(QDate); |
| 57 | |
| 58 | KDatePickerPopup *const ; |
| 59 | KDatePicker * = nullptr; |
| 60 | KDatePickerPopup::Modes ; |
| 61 | QMap<QDate, QString> ; |
| 62 | }; |
| 63 | |
| 64 | void KDatePickerPopupPrivate::(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 | |
| 81 | void KDatePickerPopupPrivate::() |
| 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 | |
| 127 | void KDatePickerPopupPrivate::(QDate date) |
| 128 | { |
| 129 | Q_EMIT q->dateChanged(date); |
| 130 | q->hide(); |
| 131 | } |
| 132 | |
| 133 | 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 | |
| 156 | KDatePickerPopup::() = default; |
| 157 | |
| 158 | KDatePicker *KDatePickerPopup::() const |
| 159 | { |
| 160 | return d->mDatePicker; |
| 161 | } |
| 162 | |
| 163 | void KDatePickerPopup::(QDate date) |
| 164 | { |
| 165 | d->mDatePicker->setDate(date); |
| 166 | } |
| 167 | |
| 168 | KDatePickerPopup::Modes KDatePickerPopup::() const |
| 169 | { |
| 170 | return d->mModes; |
| 171 | } |
| 172 | |
| 173 | void KDatePickerPopup::(KDatePickerPopup::Modes modes) |
| 174 | { |
| 175 | d->mModes = modes; |
| 176 | } |
| 177 | |
| 178 | void KDatePickerPopup::(const QDate &minDate, const QDate &maxDate) |
| 179 | { |
| 180 | d->setDateRange(minDate, maxDate); |
| 181 | d->mDatePicker->setDateRange(minDate, maxDate); |
| 182 | } |
| 183 | |
| 184 | QMap<QDate, QString> KDatePickerPopup::() const |
| 185 | { |
| 186 | return d->m_dateMap; |
| 187 | } |
| 188 | |
| 189 | void KDatePickerPopup::(const QMap<QDate, QString> &dateMap) |
| 190 | { |
| 191 | d->m_dateMap = dateMap; |
| 192 | } |
| 193 | |
| 194 | #include "moc_kdatepickerpopup.cpp" |
| 195 | |