File indexing completed on 2024-04-28 03:59:03

0001 /*
0002   SPDX-FileCopyrightText: 2004 Bram Schoenmakers <bramschoenmakers@kde.nl>
0003   SPDX-License-Identifier: LGPL-2.0-or-later
0004 */
0005 
0006 #include "kdatepickerpopup.h"
0007 #include "kdatepicker.h"
0008 #include "kdaterangecontrol_p.h"
0009 
0010 #include <QDateTime>
0011 #include <QLocale>
0012 #include <QWidgetAction>
0013 
0014 class KDatePickerAction : public QWidgetAction
0015 {
0016 public:
0017     KDatePickerAction(KDatePicker *widget, QObject *parent)
0018         : QWidgetAction(parent)
0019         , mDatePicker(widget)
0020         , mOriginalParent(widget->parentWidget())
0021     {
0022     }
0023 
0024 protected:
0025     QWidget *createWidget(QWidget *parent) override
0026     {
0027         mDatePicker->setParent(parent);
0028         return mDatePicker;
0029     }
0030 
0031     void deleteWidget(QWidget *widget) override
0032     {
0033         if (widget != mDatePicker) {
0034             return;
0035         }
0036 
0037         mDatePicker->setParent(mOriginalParent);
0038     }
0039 
0040 private:
0041     KDatePicker *const mDatePicker;
0042     QWidget *const mOriginalParent;
0043 };
0044 
0045 class KDatePickerPopupPrivate : public KDateRangeControlPrivate
0046 {
0047 public:
0048     explicit KDatePickerPopupPrivate(KDatePickerPopup *qq)
0049         : q(qq)
0050     {
0051     }
0052 
0053     void addMenuAction(const QString &text, const QDate &date);
0054     void buildMenu();
0055     void menuActionTriggered(QAction *action);
0056     void slotDateChanged(QDate);
0057 
0058     KDatePickerPopup *const q;
0059     KDatePicker *mDatePicker = nullptr;
0060     KDatePickerPopup::Modes mModes;
0061     QMap<QDate, QString> m_dateMap;
0062 };
0063 
0064 void KDatePickerPopupPrivate::addMenuAction(const QString &text, const QDate &date)
0065 {
0066     // skip out-of-range dates
0067     // an invalid date is ok though, that's for the "No Date" action
0068     if (date.isValid() && !isInDateRange(date)) {
0069         return;
0070     }
0071 
0072     QAction *action = new QAction(q);
0073     action->setText(text);
0074     action->setData(date);
0075     QObject::connect(action, &QAction::triggered, q, [this, action]() {
0076         Q_EMIT q->dateChanged(action->data().toDate());
0077     });
0078     q->addAction(action);
0079 }
0080 
0081 void KDatePickerPopupPrivate::buildMenu()
0082 {
0083     q->clear();
0084 
0085     if (mModes & KDatePickerPopup::DatePicker) {
0086         q->addAction(new KDatePickerAction(mDatePicker, q));
0087 
0088         if ((mModes & KDatePickerPopup::NoDate) || (mModes & KDatePickerPopup::Words)) {
0089             q->addSeparator();
0090         }
0091     }
0092 
0093     if (mModes & KDatePickerPopup::Words) {
0094         if (m_dateMap.isEmpty()) {
0095             const QDate today = QDate::currentDate();
0096             addMenuAction(KDatePickerPopup::tr("Next Year", "@option next year"), today.addYears(1));
0097             addMenuAction(KDatePickerPopup::tr("Next Month", "@option next month"), today.addMonths(1));
0098             addMenuAction(KDatePickerPopup::tr("Next Week", "@option next week"), today.addDays(7));
0099             addMenuAction(KDatePickerPopup::tr("Tomorrow", "@option tomorrow"), today.addDays(1));
0100             addMenuAction(KDatePickerPopup::tr("Today", "@option today"), today);
0101             addMenuAction(KDatePickerPopup::tr("Yesterday", "@option yesterday"), today.addDays(-1));
0102             addMenuAction(KDatePickerPopup::tr("Last Week", "@option last week"), today.addDays(-7));
0103             addMenuAction(KDatePickerPopup::tr("Last Month", "@option last month"), today.addMonths(-1));
0104             addMenuAction(KDatePickerPopup::tr("Last Year", "@option last year"), today.addYears(-1));
0105         } else {
0106             for (auto it = m_dateMap.constBegin(); it != m_dateMap.constEnd(); ++it) {
0107                 if (it.value().isEmpty()) {
0108                     addMenuAction(QLocale().toString(it.key()), it.key());
0109                 } else if (it.value().toLower() == QLatin1String("separator")) {
0110                     q->addSeparator();
0111                 } else {
0112                     addMenuAction(it.value(), it.key());
0113                 }
0114             }
0115         }
0116 
0117         if (mModes & KDatePickerPopup::NoDate) {
0118             q->addSeparator();
0119         }
0120     }
0121 
0122     if (mModes & KDatePickerPopup::NoDate) {
0123         addMenuAction(KDatePickerPopup::tr("No Date", "@option do not specify a date"), QDate());
0124     }
0125 }
0126 
0127 void KDatePickerPopupPrivate::slotDateChanged(QDate date)
0128 {
0129     Q_EMIT q->dateChanged(date);
0130     q->hide();
0131 }
0132 
0133 KDatePickerPopup::KDatePickerPopup(Modes modes, QDate date, QWidget *parent)
0134     : QMenu(parent)
0135     , d(new KDatePickerPopupPrivate(this))
0136 {
0137     d->mModes = modes;
0138 
0139     d->mDatePicker = new KDatePicker(this);
0140     d->mDatePicker->setCloseButton(false);
0141 
0142     connect(d->mDatePicker, &KDatePicker::dateEntered, this, [this](QDate date) {
0143         d->slotDateChanged(date);
0144     });
0145     connect(d->mDatePicker, &KDatePicker::dateSelected, this, [this](QDate date) {
0146         d->slotDateChanged(date);
0147     });
0148 
0149     d->mDatePicker->setDate(date);
0150 
0151     connect(this, &QMenu::aboutToShow, this, [this]() {
0152         d->buildMenu();
0153     });
0154 }
0155 
0156 KDatePickerPopup::~KDatePickerPopup() = default;
0157 
0158 KDatePicker *KDatePickerPopup::datePicker() const
0159 {
0160     return d->mDatePicker;
0161 }
0162 
0163 void KDatePickerPopup::setDate(QDate date)
0164 {
0165     d->mDatePicker->setDate(date);
0166 }
0167 
0168 KDatePickerPopup::Modes KDatePickerPopup::modes() const
0169 {
0170     return d->mModes;
0171 }
0172 
0173 void KDatePickerPopup::setModes(KDatePickerPopup::Modes modes)
0174 {
0175     d->mModes = modes;
0176 }
0177 
0178 void KDatePickerPopup::setDateRange(const QDate &minDate, const QDate &maxDate)
0179 {
0180     d->setDateRange(minDate, maxDate);
0181 }
0182 
0183 QMap<QDate, QString> KDatePickerPopup::dateMap() const
0184 {
0185     return d->m_dateMap;
0186 }
0187 
0188 void KDatePickerPopup::setDateMap(const QMap<QDate, QString> &dateMap)
0189 {
0190     d->m_dateMap = dateMap;
0191 }
0192 
0193 #include "moc_kdatepickerpopup.cpp"