File indexing completed on 2024-05-12 05:09:47
0001 /*************************************************************************** 0002 Copyright (C) 2003-2009 Robby Stephenson <robby@periapsis.org> 0003 ***************************************************************************/ 0004 0005 /*************************************************************************** 0006 * * 0007 * This program is free software; you can redistribute it and/or * 0008 * modify it under the terms of the GNU General Public License as * 0009 * published by the Free Software Foundation; either version 2 of * 0010 * the License or (at your option) version 3 or any later version * 0011 * accepted by the membership of KDE e.V. (or its successor approved * 0012 * by the membership of KDE e.V.), which shall act as a proxy * 0013 * defined in Section 14 of version 3 of the license. * 0014 * * 0015 * This program is distributed in the hope that it will be useful, * 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0018 * GNU General Public License for more details. * 0019 * * 0020 * You should have received a copy of the GNU General Public License * 0021 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 0022 * * 0023 ***************************************************************************/ 0024 0025 // this class borrows heavily from kdateedit.h in the kdepim module 0026 // which is Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org> 0027 // and published under the LGPL 0028 0029 #include "datewidget.h" 0030 #include "spinbox.h" 0031 0032 #include <KComboBox> 0033 #include <KDatePicker> 0034 0035 #include <QPushButton> 0036 #include <QHBoxLayout> 0037 #include <QFrame> 0038 #include <QDate> 0039 #include <QEvent> 0040 #include <QMenu> 0041 #include <QWidgetAction> 0042 #include <QApplication> 0043 #include <QDesktopWidget> 0044 0045 using Tellico::GUI::DateWidget; 0046 0047 class DateWidget::DatePickerAction : public QWidgetAction 0048 { 0049 Q_OBJECT 0050 0051 public: 0052 DatePickerAction( KDatePicker *widget, QObject *parent ) 0053 : QWidgetAction( parent ), 0054 mDatePicker( widget ), mOriginalParent( widget->parentWidget() ) 0055 { 0056 } 0057 0058 protected: 0059 QWidget *createWidget( QWidget *parent ) Q_DECL_OVERRIDE 0060 { 0061 mDatePicker->setParent( parent ); 0062 return mDatePicker; 0063 } 0064 0065 void deleteWidget( QWidget *widget ) Q_DECL_OVERRIDE 0066 { 0067 if ( widget != mDatePicker ) { 0068 return; 0069 } 0070 0071 mDatePicker->setParent( mOriginalParent ); 0072 } 0073 0074 private: 0075 KDatePicker *mDatePicker; 0076 QWidget *mOriginalParent; 0077 }; 0078 0079 DateWidget::DateWidget(QWidget* parent_) : QWidget(parent_) { 0080 QBoxLayout* l = new QHBoxLayout(this); 0081 l->setContentsMargins(0, 0, 0, 0); 0082 0083 // 0 allows empty value 0084 m_daySpin = new SpinBox(0, 31, this); 0085 l->addWidget(m_daySpin, 1); 0086 l->setStretchFactor(m_daySpin, 1); 0087 0088 m_monthCombo = new KComboBox(false, this); 0089 l->addWidget(m_monthCombo, 1); 0090 l->setStretchFactor(m_monthCombo, 1); 0091 // allow empty item 0092 m_monthCombo->addItem(QString()); 0093 for(int i = 1; ; ++i) { 0094 QString str = QLocale().standaloneMonthName(i, QLocale::LongFormat); 0095 if(str.isEmpty()) { 0096 break; 0097 } 0098 m_monthCombo->addItem(str); 0099 } 0100 0101 // the min year is the value when the year is empty 0102 const int minYear = QDate::fromJulianDay(0).year() - 1; 0103 m_yearSpin = new SpinBox(minYear, 9999, this); 0104 m_yearSpin->setValue(minYear); 0105 l->addWidget(m_yearSpin, 1); 0106 l->setStretchFactor(m_yearSpin, 1); 0107 0108 void (SpinBox::* valueChangedInt)(int) = &SpinBox::valueChanged; 0109 void (KComboBox::* indexChanged)(int) = &KComboBox::currentIndexChanged; 0110 connect(m_daySpin, valueChangedInt, this, &DateWidget::slotDateChanged); 0111 connect(m_monthCombo, indexChanged, this, &DateWidget::slotDateChanged); 0112 connect(m_yearSpin, valueChangedInt, this, &DateWidget::slotDateChanged); 0113 0114 m_dateButton = new QPushButton(this); 0115 m_dateButton->setIcon(QIcon::fromTheme(QStringLiteral("view-pim-calendar"))); 0116 connect(m_dateButton, &QAbstractButton::clicked, this, &DateWidget::slotShowPicker); 0117 l->addWidget(m_dateButton, 0); 0118 0119 m_menu = new QMenu(this); 0120 m_menu->hide(); 0121 0122 m_picker = new KDatePicker(m_menu); 0123 m_picker->setCloseButton(false); 0124 connect(m_picker, &KDatePicker::dateEntered, this, &DateWidget::slotDateEntered); 0125 connect(m_picker, &KDatePicker::dateSelected, this, &DateWidget::slotDateSelected); 0126 0127 m_menu->addAction(new DatePickerAction(m_picker, m_menu)); 0128 } 0129 0130 DateWidget::~DateWidget() { 0131 } 0132 0133 void DateWidget::slotDateChanged() { 0134 int day = m_daySpin->value(); 0135 day = qMin(qMax(day, m_daySpin->minimum()), m_daySpin->maximum()); 0136 0137 int m = m_monthCombo->currentIndex(); 0138 m = qMin(qMax(m, 0), m_monthCombo->count()-1); 0139 0140 int y = m_yearSpin->value(); 0141 y = qMin(qMax(y, m_yearSpin->minimum()), m_yearSpin->maximum()); 0142 0143 // if all are valid, set this date 0144 if(day > m_daySpin->minimum() && m > 0 && y > m_yearSpin->minimum()) { 0145 QDate d(y, m, day); 0146 setDate(d); 0147 } 0148 emit signalModified(); 0149 } 0150 0151 QDate DateWidget::date() const { 0152 // possible for either day, month, or year to be empty 0153 // in which case a null date is returned 0154 int day = m_daySpin->value(); 0155 // min value is the empty one 0156 if(day == m_daySpin->minimum()) { 0157 return QDate(); 0158 } 0159 int month = m_monthCombo->currentIndex(); 0160 if(month == 0) { 0161 return QDate(); 0162 } 0163 int year = m_yearSpin->value(); 0164 if(year == m_yearSpin->minimum()) { 0165 return QDate(); 0166 } 0167 return QDate(year, month, day); 0168 } 0169 0170 QString DateWidget::text() const { 0171 // possible for either day, month, or year to be empty 0172 // but not all three 0173 bool empty = true; 0174 // format is "year-month-day" 0175 QString s; 0176 if(m_yearSpin->value() > m_yearSpin->minimum()) { 0177 s += QString::number(m_yearSpin->value()); 0178 empty = false; 0179 } 0180 s += QLatin1Char('-'); 0181 // first item is empty 0182 if(m_monthCombo->currentIndex() > 0) { 0183 // zero-pad to two digits 0184 if(m_monthCombo->currentIndex() < 10) { 0185 s += QLatin1Char('0'); 0186 } 0187 s += QString::number(m_monthCombo->currentIndex()); 0188 empty = false; 0189 } 0190 s += QLatin1Char('-'); 0191 if(m_daySpin->value() > m_daySpin->minimum()) { 0192 // zero-pad to two digits 0193 if(m_daySpin->value() < 10) { 0194 s += QLatin1Char('0'); 0195 } 0196 s += QString::number(m_daySpin->value()); 0197 empty = false; 0198 } 0199 return empty ? QString() : s; 0200 } 0201 0202 void DateWidget::setDate(const QDate& date_) { 0203 const QDate oldDate = date(); 0204 0205 m_daySpin->blockSignals(true); 0206 m_monthCombo->blockSignals(true); 0207 m_yearSpin->blockSignals(true); 0208 0209 m_daySpin->setMaximum(date_.daysInMonth()); 0210 m_daySpin->setValue(date_.day()); 0211 m_monthCombo->setCurrentIndex(date_.month()); // don't subtract 1 since there's the blank first item 0212 m_yearSpin->setValue(date_.year()); 0213 0214 m_daySpin->blockSignals(false); 0215 m_monthCombo->blockSignals(false); 0216 m_yearSpin->blockSignals(false); 0217 0218 if(oldDate != date_) { 0219 emit signalModified(); 0220 } 0221 } 0222 0223 void DateWidget::setDate(const QString& date_) { 0224 m_daySpin->blockSignals(true); 0225 m_monthCombo->blockSignals(true); 0226 m_yearSpin->blockSignals(true); 0227 0228 QStringList s = date_.split(QLatin1Char('-')); 0229 bool ok = true; 0230 int y = s.count() > 0 ? s[0].toInt(&ok) : m_yearSpin->minimum(); 0231 if(!ok) { 0232 y = m_yearSpin->minimum(); 0233 ok = true; 0234 } 0235 y = qMin(qMax(y, m_yearSpin->minimum()), m_yearSpin->maximum()); 0236 m_yearSpin->setValue(y); 0237 0238 int m = s.count() > 1 ? s[1].toInt(&ok) : 0; 0239 if(!ok) { 0240 m = 0; 0241 ok = true; 0242 } 0243 m = qMin(qMax(m, 0), m_monthCombo->count()-1); 0244 m_monthCombo->setCurrentIndex(m); 0245 0246 // need to update number of days in month 0247 // for now set date to 1 0248 QDate date(y, (m == 0 ? 1 : m), 1); 0249 m_daySpin->setMaximum(date.daysInMonth()); 0250 0251 int day = s.count() > 2 ? s[2].toInt(&ok) : m_daySpin->minimum(); 0252 if(!ok) { 0253 day = m_daySpin->minimum(); 0254 } 0255 day = qMin(qMax(day, m_daySpin->minimum()), m_daySpin->maximum()); 0256 m_daySpin->setValue(day); 0257 0258 m_daySpin->blockSignals(false); 0259 m_monthCombo->blockSignals(false); 0260 m_yearSpin->blockSignals(false); 0261 0262 // if all are valid, set this date 0263 if(day > m_daySpin->minimum() && m > 0 && y > m_yearSpin->minimum()) { 0264 QDate d(y, m, day); 0265 m_picker->blockSignals(true); 0266 m_picker->setDate(d); 0267 m_picker->blockSignals(false); 0268 } 0269 } 0270 0271 void DateWidget::clear() { 0272 m_daySpin->blockSignals(true); 0273 m_monthCombo->blockSignals(true); 0274 m_yearSpin->blockSignals(true); 0275 m_picker->blockSignals(true); 0276 0277 m_daySpin->setValue(m_daySpin->minimum()); 0278 m_monthCombo->setCurrentIndex(0); 0279 m_yearSpin->setValue(m_yearSpin->minimum()); 0280 m_picker->setDate(QDate::currentDate()); 0281 0282 m_daySpin->blockSignals(false); 0283 m_monthCombo->blockSignals(false); 0284 m_yearSpin->blockSignals(false); 0285 m_picker->blockSignals(false); 0286 } 0287 0288 void DateWidget::slotShowPicker() { 0289 QRect desk = QApplication::desktop()->screenGeometry(this); 0290 QPoint popupPoint = mapToGlobal(QPoint(0, 0)); 0291 0292 int dateFrameHeight = m_menu->sizeHint().height(); 0293 if(popupPoint.y() + height() + dateFrameHeight > desk.bottom()) { 0294 popupPoint.setY(popupPoint.y() - dateFrameHeight); 0295 } else { 0296 popupPoint.setY(popupPoint.y() + height()); 0297 } 0298 int dateFrameWidth = m_menu->sizeHint().width(); 0299 if(popupPoint.x() + width() > desk.right()) { 0300 popupPoint.setX(desk.right() - dateFrameWidth); 0301 } else { 0302 popupPoint.setX(popupPoint.x() + width() - dateFrameWidth); 0303 } 0304 0305 if(popupPoint.x() < desk.left()) { 0306 popupPoint.setX( desk.left()); 0307 } 0308 if(popupPoint.y() < desk.top()) { 0309 popupPoint.setY(desk.top()); 0310 } 0311 0312 QDate d = date(); 0313 if(d.isValid()) { 0314 m_picker->setDate(d); 0315 } 0316 0317 m_menu->popup(popupPoint); 0318 } 0319 0320 void DateWidget::slotDateSelected(QDate date_) { 0321 if(date_.isValid()) { 0322 setDate(date_); 0323 m_menu->hide(); 0324 } 0325 } 0326 0327 void DateWidget::slotDateEntered(QDate date_) { 0328 if(date_.isValid()) { 0329 setDate(date_); 0330 } 0331 } 0332 0333 #include "datewidget.moc"