kdatecombobox.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright 2011 John Layt <john@layt.net> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include "kdatecombobox.h" 00021 00022 #include <QtGui/QAbstractItemView> 00023 #include <QtGui/QApplication> 00024 #include <QtGui/QKeyEvent> 00025 #include <QtGui/QMenu> 00026 #include <QtGui/QLineEdit> 00027 #include <QtGui/QWidgetAction> 00028 00029 #include "kdebug.h" 00030 #include "klocale.h" 00031 #include "klocalizeddate.h" 00032 #include "kcombobox.h" 00033 #include "kdatepicker.h" 00034 #include "kmessagebox.h" 00035 00036 class KDateComboBoxPrivate 00037 { 00038 public: 00039 00040 KDateComboBoxPrivate(KDateComboBox *q); 00041 virtual ~KDateComboBoxPrivate(); 00042 00043 QDate defaultMinDate(); 00044 QDate defaultMaxDate(); 00045 00046 QString formatDate(const QDate &date); 00047 00048 void initDateWidget(); 00049 void addMenuAction(const QString &text, const QDate &date); 00050 void updateDateWidget(); 00051 00052 // Q_PRIVATE_SLOTs 00053 void clickDate(); 00054 void selectDate(QAction *action); 00055 void editDate(const QString &text); 00056 void enterDate(const QDate &date); 00057 void parseDate(); 00058 void warnDate(); 00059 00060 KDateComboBox *const q; 00061 QMenu *m_dateMenu; 00062 KDatePicker *m_datePicker; 00063 QWidgetAction *m_datePickerAction; 00064 00065 KLocalizedDate m_date; 00066 KDateComboBox::Options m_options; 00067 QDate m_minDate; 00068 QDate m_maxDate; 00069 QString m_minWarnMsg; 00070 QString m_maxWarnMsg; 00071 bool m_warningShown; 00072 KLocale::DateFormat m_displayFormat; 00073 QMap<QDate, QString> m_dateMap; 00074 }; 00075 00076 KDateComboBoxPrivate::KDateComboBoxPrivate(KDateComboBox *q) 00077 :q(q), 00078 m_dateMenu(new QMenu(q)), 00079 m_datePicker(new KDatePicker(q)), 00080 m_datePickerAction(new QWidgetAction(q)), 00081 m_displayFormat(KLocale::ShortDate) 00082 { 00083 m_options = KDateComboBox::EditDate | KDateComboBox::SelectDate | KDateComboBox::DatePicker | KDateComboBox::DateKeywords; 00084 m_date.setDate(QDate::currentDate()); 00085 m_minDate = defaultMinDate(); 00086 m_maxDate = defaultMaxDate(); 00087 m_datePicker->setCloseButton(false); 00088 m_datePickerAction->setObjectName(QLatin1String("DatePicker")); 00089 m_datePickerAction->setDefaultWidget(m_datePicker); 00090 } 00091 00092 KDateComboBoxPrivate::~KDateComboBoxPrivate() 00093 { 00094 } 00095 00096 QDate KDateComboBoxPrivate::defaultMinDate() 00097 { 00098 return m_date.calendar()->earliestValidDate(); 00099 } 00100 00101 QDate KDateComboBoxPrivate::defaultMaxDate() 00102 { 00103 return m_date.calendar()->latestValidDate(); 00104 } 00105 00106 QString KDateComboBoxPrivate::formatDate(const QDate &date) 00107 { 00108 return m_date.calendar()->formatDate(date, m_displayFormat); 00109 } 00110 00111 void KDateComboBoxPrivate::initDateWidget() 00112 { 00113 q->blockSignals(true); 00114 q->clear(); 00115 00116 // If EditTime then set the line edit 00117 q->lineEdit()->setReadOnly((m_options &KDateComboBox::EditDate) != KDateComboBox::EditDate); 00118 00119 // If SelectTime then make list items visible 00120 if ((m_options &KDateComboBox::SelectDate) == KDateComboBox::SelectDate || 00121 (m_options &KDateComboBox::DatePicker) == KDateComboBox::DatePicker || 00122 (m_options &KDateComboBox::DatePicker) == KDateComboBox::DateKeywords) { 00123 q->setMaxVisibleItems(1); 00124 } else { 00125 q->setMaxVisibleItems(0); 00126 } 00127 00128 q->setSizeAdjustPolicy(QComboBox::AdjustToContents); 00129 q->addItem(m_date.formatDate(m_displayFormat)); 00130 q->setCurrentIndex(0); 00131 q->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); 00132 q->blockSignals(false); 00133 00134 m_dateMenu->clear(); 00135 00136 if ((m_options &KDateComboBox::SelectDate) == KDateComboBox::SelectDate) { 00137 00138 if ((m_options &KDateComboBox::DatePicker) == KDateComboBox::DatePicker) { 00139 m_dateMenu->addAction(m_datePickerAction); 00140 m_dateMenu->addSeparator(); 00141 } 00142 00143 if ((m_options &KDateComboBox::DateKeywords) == KDateComboBox::DateKeywords) { 00144 if (m_dateMap.isEmpty()) { 00145 addMenuAction(i18nc("@option next year", "Next Year" ), m_date.addYears(1).date()); 00146 addMenuAction(i18nc("@option next month", "Next Month"), m_date.addMonths(1).date()); 00147 addMenuAction(i18nc("@option next week", "Next Week" ), m_date.addDays(m_date.daysInWeek()).date()); 00148 addMenuAction(i18nc("@option tomorrow", "Tomorrow" ), m_date.addDays(1).date()); 00149 addMenuAction(i18nc("@option today", "Today" ), m_date.date()); 00150 addMenuAction(i18nc("@option yesterday", "Yesterday" ), m_date.addDays(-1).date()); 00151 addMenuAction(i18nc("@option last week", "Last Week" ), m_date.addDays(-m_date.daysInWeek()).date()); 00152 addMenuAction(i18nc("@option last month", "Last Month"), m_date.addMonths(-1).date()); 00153 addMenuAction(i18nc("@option last year", "Last Year" ), m_date.addYears(-1).date()); 00154 m_dateMenu->addSeparator(); 00155 addMenuAction(i18nc("@option do not specify a date", "No Date"), QDate()); 00156 } else { 00157 QMapIterator<QDate, QString> i(m_dateMap); 00158 while (i.hasNext()) { 00159 i.next(); 00160 if (i.value().isEmpty()) { 00161 addMenuAction(formatDate(i.key()), i.key()); 00162 } else if (i.value().toLower() == QLatin1String("separator")) { 00163 m_dateMenu->addSeparator(); 00164 } else { 00165 addMenuAction(i.value(), i.key()); 00166 } 00167 } 00168 } 00169 } 00170 00171 } 00172 } 00173 00174 void KDateComboBoxPrivate::addMenuAction(const QString &text, const QDate &date) 00175 { 00176 QAction *action = new QAction(m_dateMenu); 00177 action->setText(text); 00178 action->setData(date); 00179 m_dateMenu->addAction(action); 00180 } 00181 00182 void KDateComboBoxPrivate::updateDateWidget() 00183 { 00184 q->blockSignals(true); 00185 m_datePicker->blockSignals(true); 00186 m_datePicker->setDate(m_date.date()); 00187 int pos = q->lineEdit()->cursorPosition(); 00188 q->setItemText(0, m_date.formatDate(m_displayFormat)); 00189 q->lineEdit()->setText(m_date.formatDate(m_displayFormat)); 00190 q->lineEdit()->setCursorPosition(pos); 00191 m_datePicker->blockSignals(false); 00192 q->blockSignals(false); 00193 } 00194 00195 void KDateComboBoxPrivate::selectDate(QAction *action) 00196 { 00197 if (action->objectName() != QLatin1String("DatePicker")) { 00198 enterDate(action->data().toDate()); 00199 } 00200 } 00201 00202 void KDateComboBoxPrivate::clickDate() 00203 { 00204 enterDate(m_datePicker->date()); 00205 } 00206 00207 void KDateComboBoxPrivate::editDate(const QString &text) 00208 { 00209 m_warningShown = false; 00210 emit q->dateEdited(m_date.readDate(text).date()); 00211 } 00212 00213 void KDateComboBoxPrivate::parseDate() 00214 { 00215 m_date.setDate(m_date.readDate(q->lineEdit()->text()).date()); 00216 } 00217 00218 void KDateComboBoxPrivate::enterDate(const QDate &date) 00219 { 00220 q->setDate(date); 00221 // Re-add the combo box item in order to retain the correct widget width 00222 q->blockSignals(true); 00223 q->clear(); 00224 q->setSizeAdjustPolicy(QComboBox::AdjustToContents); 00225 q->addItem(m_date.formatDate(m_displayFormat)); 00226 q->setCurrentIndex(0); 00227 q->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); 00228 q->blockSignals(false); 00229 00230 m_dateMenu->hide(); 00231 warnDate(); 00232 emit q->dateEntered(m_date.date()); 00233 } 00234 00235 void KDateComboBoxPrivate::warnDate() 00236 { 00237 if (!m_warningShown && !q->isValid() && 00238 (m_options &KDateComboBox::WarnOnInvalid) == KDateComboBox::WarnOnInvalid) { 00239 QString warnMsg; 00240 if (!m_date.date().isValid()) { 00241 warnMsg = i18nc("@info", "The date you entered is invalid"); 00242 } else if (m_date.date() < m_minDate) { 00243 if (m_minWarnMsg.isEmpty()) { 00244 warnMsg = i18nc("@info", "Date cannot be earlier than %1", formatDate(m_minDate)); 00245 } else { 00246 warnMsg = m_minWarnMsg; 00247 warnMsg.replace("%1", formatDate(m_minDate)); 00248 } 00249 } else if (m_date.date() > m_maxDate) { 00250 if (m_maxWarnMsg.isEmpty()) { 00251 warnMsg = i18nc("@info", "Date cannot be later than %1", formatDate(m_maxDate)); 00252 } else { 00253 warnMsg = m_maxWarnMsg; 00254 warnMsg.replace("%1", formatDate(m_maxDate)); 00255 } 00256 } 00257 m_warningShown = true; 00258 KMessageBox::sorry(q, warnMsg); 00259 } 00260 } 00261 00262 00263 KDateComboBox::KDateComboBox(QWidget *parent) 00264 :KComboBox(parent), 00265 d(new KDateComboBoxPrivate(this)) 00266 { 00267 setEditable(true); 00268 setMaxVisibleItems(1); 00269 setInsertPolicy(QComboBox::NoInsert); 00270 d->m_datePicker->installEventFilter(this); 00271 d->initDateWidget(); 00272 d->updateDateWidget(); 00273 00274 connect(d->m_dateMenu, SIGNAL(triggered(QAction*)), 00275 this, SLOT(selectDate(QAction*))); 00276 connect(this, SIGNAL(editTextChanged(const QString&)), 00277 this, SLOT(editDate(const QString&))); 00278 connect(d->m_datePicker, SIGNAL(dateEntered(const QDate&)), 00279 this, SLOT(enterDate(const QDate&))); 00280 connect(d->m_datePicker, SIGNAL(tableClicked()), 00281 this, SLOT(clickDate())); 00282 } 00283 00284 KDateComboBox::~KDateComboBox() 00285 { 00286 delete d; 00287 } 00288 00289 QDate KDateComboBox::date() const 00290 { 00291 d->parseDate(); 00292 return d->m_date.date(); 00293 } 00294 00295 void KDateComboBox::setDate(const QDate &date) 00296 { 00297 if (date == d->m_date.date()) { 00298 return; 00299 } 00300 00301 assignDate(date); 00302 d->updateDateWidget(); 00303 emit dateChanged(d->m_date.date()); 00304 } 00305 00306 void KDateComboBox::assignDate(const QDate &date) 00307 { 00308 d->m_date = date; 00309 } 00310 00311 KLocale::CalendarSystem KDateComboBox::calendarSystem() const 00312 { 00313 return d->m_date.calendarSystem(); 00314 } 00315 00316 void KDateComboBox::setCalendarSystem(KLocale::CalendarSystem calendarSystem) 00317 { 00318 if (calendarSystem != d->m_date.calendarSystem()) { 00319 assignCalendarSystem(calendarSystem); 00320 } 00321 } 00322 00323 void KDateComboBox::assignCalendarSystem(KLocale::CalendarSystem calendarSystem) 00324 { 00325 d->m_date.setCalendarSystem(calendarSystem); 00326 } 00327 00328 const KCalendarSystem *KDateComboBox::calendar() const 00329 { 00330 return d->m_date.calendar(); 00331 } 00332 00333 void KDateComboBox::setCalendar(KCalendarSystem *calendar) 00334 { 00335 d->m_date = KLocalizedDate(d->m_date.date(), calendar); 00336 } 00337 00338 bool KDateComboBox::isValid() const 00339 { 00340 d->parseDate(); 00341 return d->m_date.isValid() && 00342 d->m_date >= d->m_minDate && 00343 d->m_date <= d->m_maxDate; 00344 } 00345 00346 bool KDateComboBox::isNull() const 00347 { 00348 return lineEdit()->text().isEmpty(); 00349 } 00350 00351 KDateComboBox::Options KDateComboBox::options() const 00352 { 00353 return d->m_options; 00354 } 00355 00356 void KDateComboBox::setOptions(Options options) 00357 { 00358 if (options != d->m_options) { 00359 d->m_options = options; 00360 d->initDateWidget(); 00361 d->updateDateWidget(); 00362 } 00363 } 00364 00365 QDate KDateComboBox::minimumDate() const 00366 { 00367 return d->m_minDate; 00368 } 00369 00370 void KDateComboBox::setMinimumDate(const QDate &minDate, const QString &minWarnMsg) 00371 { 00372 setDateRange(minDate, d->m_maxDate, minWarnMsg, d->m_maxWarnMsg); 00373 } 00374 00375 void KDateComboBox::resetMinimumDate() 00376 { 00377 setDateRange(d->defaultMinDate(), d->m_maxDate, QString(), d->m_maxWarnMsg); 00378 } 00379 00380 QDate KDateComboBox::maximumDate() const 00381 { 00382 return d->m_maxDate; 00383 } 00384 00385 void KDateComboBox::setMaximumDate(const QDate &maxDate, const QString &maxWarnMsg) 00386 { 00387 setDateRange(d->m_minDate, maxDate, d->m_minWarnMsg, maxWarnMsg); 00388 } 00389 00390 void KDateComboBox::resetMaximumDate() 00391 { 00392 setDateRange(d->m_minDate, d->defaultMaxDate(), d->m_minWarnMsg, QString()); 00393 } 00394 00395 void KDateComboBox::setDateRange(const QDate &minDate, 00396 const QDate &maxDate, 00397 const QString &minWarnMsg, 00398 const QString &maxWarnMsg) 00399 { 00400 if (!minDate.isValid() || !maxDate.isValid() || minDate > maxDate) { 00401 return; 00402 } 00403 00404 if (minDate != d->m_minDate || maxDate != d->m_maxDate || 00405 minWarnMsg != d->m_minWarnMsg || maxWarnMsg != d->m_maxWarnMsg) { 00406 d->m_minDate = minDate; 00407 d->m_maxDate = maxDate; 00408 d->m_minWarnMsg = minWarnMsg; 00409 d->m_maxWarnMsg = maxWarnMsg; 00410 } 00411 } 00412 00413 void KDateComboBox::resetDateRange() 00414 { 00415 setDateRange(d->defaultMinDate(), d->defaultMaxDate(), QString(), QString()); 00416 } 00417 00418 KLocale::DateFormat KDateComboBox::displayFormat() const 00419 { 00420 return d->m_displayFormat; 00421 } 00422 00423 void KDateComboBox::setDisplayFormat(KLocale::DateFormat format) 00424 { 00425 if (format != d->m_displayFormat) { 00426 d->m_displayFormat = format; 00427 d->initDateWidget(); 00428 d->updateDateWidget(); 00429 } 00430 } 00431 00432 QMap<QDate, QString> KDateComboBox::dateMap() const 00433 { 00434 return d->m_dateMap; 00435 } 00436 00437 void KDateComboBox::setDateMap(QMap<QDate, QString> dateMap) 00438 { 00439 if (dateMap != d->m_dateMap) { 00440 d->m_dateMap.clear(); 00441 d->m_dateMap = dateMap; 00442 d->initDateWidget(); 00443 } 00444 } 00445 00446 bool KDateComboBox::eventFilter(QObject *object, QEvent *event) 00447 { 00448 return KComboBox::eventFilter(object, event); 00449 } 00450 00451 void KDateComboBox::keyPressEvent(QKeyEvent *keyEvent) 00452 { 00453 QDate temp; 00454 switch (keyEvent->key()) { 00455 case Qt::Key_Down: 00456 temp = d->m_date.addDays(-1).date(); 00457 break; 00458 case Qt::Key_Up: 00459 temp = d->m_date.addDays(1).date(); 00460 break; 00461 case Qt::Key_PageDown: 00462 temp = d->m_date.addMonths(-1).date(); 00463 break; 00464 case Qt::Key_PageUp: 00465 temp = d->m_date.addMonths(1).date(); 00466 break; 00467 default: 00468 KComboBox::keyPressEvent(keyEvent); 00469 return; 00470 } 00471 if (temp.isValid() && temp >= d->m_minDate && temp <= d->m_maxDate) { 00472 d->enterDate(temp); 00473 } 00474 } 00475 00476 void KDateComboBox::focusOutEvent(QFocusEvent *event) 00477 { 00478 d->parseDate(); 00479 d->warnDate(); 00480 KComboBox::focusOutEvent(event); 00481 } 00482 00483 void KDateComboBox::showPopup() 00484 { 00485 if (!isEditable() || 00486 !d->m_dateMenu || 00487 (d->m_options &KDateComboBox::SelectDate) != KDateComboBox::SelectDate) { 00488 return; 00489 } 00490 00491 d->m_datePicker->blockSignals(true); 00492 d->m_datePicker->setDate(d->m_date.date()); 00493 d->m_datePicker->blockSignals(false); 00494 00495 const QRect desk = KGlobalSettings::desktopGeometry(this); 00496 00497 QPoint popupPoint = mapToGlobal(QPoint(0, 0)); 00498 00499 const int dateFrameHeight = d->m_dateMenu->sizeHint().height(); 00500 if (popupPoint.y() + height() + dateFrameHeight > desk.bottom()) { 00501 popupPoint.setY(popupPoint.y() - dateFrameHeight); 00502 } else { 00503 popupPoint.setY(popupPoint.y() + height()); 00504 } 00505 00506 const int dateFrameWidth = d->m_dateMenu->sizeHint().width(); 00507 if (popupPoint.x() + dateFrameWidth > desk.right()) { 00508 popupPoint.setX(desk.right() - dateFrameWidth); 00509 } 00510 00511 if (popupPoint.x() < desk.left()) { 00512 popupPoint.setX(desk.left()); 00513 } 00514 00515 if (popupPoint.y() < desk.top()) { 00516 popupPoint.setY(desk.top()); 00517 } 00518 00519 d->m_dateMenu->popup(popupPoint); 00520 } 00521 00522 void KDateComboBox::hidePopup() 00523 { 00524 KComboBox::hidePopup(); 00525 } 00526 00527 void KDateComboBox::mousePressEvent(QMouseEvent *event) 00528 { 00529 KComboBox::mousePressEvent(event); 00530 } 00531 00532 void KDateComboBox::wheelEvent(QWheelEvent *event) 00533 { 00534 KComboBox::wheelEvent(event); 00535 } 00536 00537 void KDateComboBox::focusInEvent(QFocusEvent *event) 00538 { 00539 KComboBox::focusInEvent(event); 00540 } 00541 00542 void KDateComboBox::resizeEvent(QResizeEvent *event) 00543 { 00544 KComboBox::resizeEvent(event); 00545 } 00546 00547 #include "kdatecombobox.moc"
KDE 4.8 API Reference