KDEUI
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->addItem(m_date.formatDate(m_displayFormat)); 00129 q->setCurrentIndex(0); 00130 q->setSizeAdjustPolicy(QComboBox::AdjustToContents); 00131 00132 m_dateMenu->clear(); 00133 00134 if ((m_options &KDateComboBox::SelectDate) == KDateComboBox::SelectDate) { 00135 00136 if ((m_options &KDateComboBox::DatePicker) == KDateComboBox::DatePicker) { 00137 m_dateMenu->addAction(m_datePickerAction); 00138 m_dateMenu->addSeparator(); 00139 } 00140 00141 if ((m_options &KDateComboBox::DateKeywords) == KDateComboBox::DateKeywords) { 00142 if (m_dateMap.isEmpty()) { 00143 addMenuAction(i18nc("@option next year", "Next Year" ), m_date.addYears(1).date()); 00144 addMenuAction(i18nc("@option next month", "Next Month"), m_date.addMonths(1).date()); 00145 addMenuAction(i18nc("@option next week", "Next Week" ), m_date.addDays(m_date.daysInWeek()).date()); 00146 addMenuAction(i18nc("@option tomorrow", "Tomorrow" ), m_date.addDays(1).date()); 00147 addMenuAction(i18nc("@option today", "Today" ), m_date.date()); 00148 addMenuAction(i18nc("@option yesterday", "Yesterday" ), m_date.addDays(-1).date()); 00149 addMenuAction(i18nc("@option last week", "Last Week" ), m_date.addDays(-m_date.daysInWeek()).date()); 00150 addMenuAction(i18nc("@option last month", "Last Month"), m_date.addMonths(-1).date()); 00151 addMenuAction(i18nc("@option last year", "Last Year" ), m_date.addYears(-1).date()); 00152 m_dateMenu->addSeparator(); 00153 addMenuAction(i18nc("@option do not specify a date", "No Date"), QDate()); 00154 } else { 00155 QMapIterator<QDate, QString> i(m_dateMap); 00156 while (i.hasNext()) { 00157 i.next(); 00158 if (i.value().isEmpty()) { 00159 addMenuAction(formatDate(i.key()), i.key()); 00160 } else if (i.value().toLower() == QLatin1String("separator")) { 00161 m_dateMenu->addSeparator(); 00162 } else { 00163 addMenuAction(i.value(), i.key()); 00164 } 00165 } 00166 } 00167 } 00168 00169 } 00170 } 00171 00172 void KDateComboBoxPrivate::addMenuAction(const QString &text, const QDate &date) 00173 { 00174 QAction *action = new QAction(m_dateMenu); 00175 action->setText(text); 00176 action->setData(date); 00177 m_dateMenu->addAction(action); 00178 } 00179 00180 void KDateComboBoxPrivate::updateDateWidget() 00181 { 00182 q->blockSignals(true); 00183 m_datePicker->blockSignals(true); 00184 m_datePicker->setDate(m_date.date()); 00185 int pos = q->lineEdit()->cursorPosition(); 00186 q->setItemText(0, m_date.formatDate(m_displayFormat)); 00187 q->lineEdit()->setText(m_date.formatDate(m_displayFormat)); 00188 q->lineEdit()->setCursorPosition(pos); 00189 m_datePicker->blockSignals(false); 00190 q->blockSignals(false); 00191 } 00192 00193 void KDateComboBoxPrivate::selectDate(QAction *action) 00194 { 00195 if (action->objectName() != QLatin1String("DatePicker")) { 00196 enterDate(action->data().toDate()); 00197 } 00198 } 00199 00200 void KDateComboBoxPrivate::clickDate() 00201 { 00202 enterDate(m_datePicker->date()); 00203 } 00204 00205 void KDateComboBoxPrivate::editDate(const QString &text) 00206 { 00207 m_warningShown = false; 00208 emit q->dateEdited(m_date.readDate(text).date()); 00209 } 00210 00211 void KDateComboBoxPrivate::parseDate() 00212 { 00213 m_date.setDate(m_date.readDate(q->lineEdit()->text()).date()); 00214 } 00215 00216 void KDateComboBoxPrivate::enterDate(const QDate &date) 00217 { 00218 q->setDate(date); 00219 m_dateMenu->hide(); 00220 warnDate(); 00221 emit q->dateEntered(m_date.date()); 00222 } 00223 00224 void KDateComboBoxPrivate::warnDate() 00225 { 00226 if (!m_warningShown && !q->isValid() && 00227 (m_options &KDateComboBox::WarnOnInvalid) == KDateComboBox::WarnOnInvalid) { 00228 QString warnMsg; 00229 if (!m_date.date().isValid()) { 00230 warnMsg = i18nc("@info", "The date you entered is invalid"); 00231 } else if (m_date.date() < m_minDate) { 00232 if (m_minWarnMsg.isEmpty()) { 00233 warnMsg = i18nc("@info", "Date cannot be earlier than %1", formatDate(m_minDate)); 00234 } else { 00235 warnMsg = m_minWarnMsg; 00236 warnMsg.replace("%1", formatDate(m_minDate)); 00237 } 00238 } else if (m_date.date() > m_maxDate) { 00239 if (m_maxWarnMsg.isEmpty()) { 00240 warnMsg = i18nc("@info", "Date cannot be later than %1", formatDate(m_maxDate)); 00241 } else { 00242 warnMsg = m_maxWarnMsg; 00243 warnMsg.replace("%1", formatDate(m_maxDate)); 00244 } 00245 } 00246 m_warningShown = true; 00247 KMessageBox::sorry(q, warnMsg); 00248 } 00249 } 00250 00251 00252 KDateComboBox::KDateComboBox(QWidget *parent) 00253 :KComboBox(parent), 00254 d(new KDateComboBoxPrivate(this)) 00255 { 00256 setEditable(true); 00257 setMaxVisibleItems(1); 00258 setInsertPolicy(QComboBox::NoInsert); 00259 setSizeAdjustPolicy(QComboBox::AdjustToContents); 00260 d->m_datePicker->installEventFilter(this); 00261 d->initDateWidget(); 00262 d->updateDateWidget(); 00263 00264 connect(d->m_dateMenu, SIGNAL(triggered(QAction*)), 00265 this, SLOT(selectDate(QAction*))); 00266 connect(this, SIGNAL(editTextChanged(const QString&)), 00267 this, SLOT(editDate(const QString&))); 00268 connect(d->m_datePicker, SIGNAL(dateEntered(const QDate&)), 00269 this, SLOT(enterDate(const QDate&))); 00270 connect(d->m_datePicker, SIGNAL(tableClicked()), 00271 this, SLOT(clickDate())); 00272 } 00273 00274 KDateComboBox::~KDateComboBox() 00275 { 00276 delete d; 00277 } 00278 00279 QDate KDateComboBox::date() const 00280 { 00281 d->parseDate(); 00282 return d->m_date.date(); 00283 } 00284 00285 void KDateComboBox::setDate(const QDate &date) 00286 { 00287 if (date == d->m_date.date()) { 00288 return; 00289 } 00290 00291 assignDate(date); 00292 d->updateDateWidget(); 00293 emit dateChanged(d->m_date.date()); 00294 } 00295 00296 void KDateComboBox::assignDate(const QDate &date) 00297 { 00298 d->m_date = date; 00299 } 00300 00301 KLocale::CalendarSystem KDateComboBox::calendarSystem() const 00302 { 00303 return d->m_date.calendarSystem(); 00304 } 00305 00306 void KDateComboBox::setCalendarSystem(KLocale::CalendarSystem calendarSystem) 00307 { 00308 if (calendarSystem != d->m_date.calendarSystem()) { 00309 assignCalendarSystem(calendarSystem); 00310 } 00311 } 00312 00313 void KDateComboBox::assignCalendarSystem(KLocale::CalendarSystem calendarSystem) 00314 { 00315 d->m_date.setCalendarSystem(calendarSystem); 00316 } 00317 00318 const KCalendarSystem *KDateComboBox::calendar() const 00319 { 00320 return d->m_date.calendar(); 00321 } 00322 00323 void KDateComboBox::setCalendar(KCalendarSystem *calendar) 00324 { 00325 d->m_date = KLocalizedDate(d->m_date.date(), calendar); 00326 } 00327 00328 bool KDateComboBox::isValid() const 00329 { 00330 d->parseDate(); 00331 return d->m_date.isValid() && 00332 d->m_date >= d->m_minDate && 00333 d->m_date <= d->m_maxDate; 00334 } 00335 00336 bool KDateComboBox::isNull() const 00337 { 00338 return lineEdit()->text().isEmpty(); 00339 } 00340 00341 KDateComboBox::Options KDateComboBox::options() const 00342 { 00343 return d->m_options; 00344 } 00345 00346 void KDateComboBox::setOptions(Options options) 00347 { 00348 if (options != d->m_options) { 00349 d->m_options = options; 00350 d->initDateWidget(); 00351 d->updateDateWidget(); 00352 } 00353 } 00354 00355 QDate KDateComboBox::minimumDate() const 00356 { 00357 return d->m_minDate; 00358 } 00359 00360 void KDateComboBox::setMinimumDate(const QDate &minDate, const QString &minWarnMsg) 00361 { 00362 setDateRange(minDate, d->m_maxDate, minWarnMsg, d->m_maxWarnMsg); 00363 } 00364 00365 void KDateComboBox::resetMinimumDate() 00366 { 00367 setDateRange(d->defaultMinDate(), d->m_maxDate, QString(), d->m_maxWarnMsg); 00368 } 00369 00370 QDate KDateComboBox::maximumDate() const 00371 { 00372 return d->m_maxDate; 00373 } 00374 00375 void KDateComboBox::setMaximumDate(const QDate &maxDate, const QString &maxWarnMsg) 00376 { 00377 setDateRange(d->m_minDate, maxDate, d->m_minWarnMsg, maxWarnMsg); 00378 } 00379 00380 void KDateComboBox::resetMaximumDate() 00381 { 00382 setDateRange(d->m_minDate, d->defaultMaxDate(), d->m_minWarnMsg, QString()); 00383 } 00384 00385 void KDateComboBox::setDateRange(const QDate &minDate, 00386 const QDate &maxDate, 00387 const QString &minWarnMsg, 00388 const QString &maxWarnMsg) 00389 { 00390 if (!minDate.isValid() || !maxDate.isValid() || minDate > maxDate) { 00391 return; 00392 } 00393 00394 if (minDate != d->m_minDate || maxDate != d->m_maxDate || 00395 minWarnMsg != d->m_minWarnMsg || maxWarnMsg != d->m_maxWarnMsg) { 00396 d->m_minDate = minDate; 00397 d->m_maxDate = maxDate; 00398 d->m_minWarnMsg = minWarnMsg; 00399 d->m_maxWarnMsg = maxWarnMsg; 00400 } 00401 } 00402 00403 void KDateComboBox::resetDateRange() 00404 { 00405 setDateRange(d->defaultMinDate(), d->defaultMaxDate(), QString(), QString()); 00406 } 00407 00408 KLocale::DateFormat KDateComboBox::displayFormat() const 00409 { 00410 return d->m_displayFormat; 00411 } 00412 00413 void KDateComboBox::setDisplayFormat(KLocale::DateFormat format) 00414 { 00415 if (format != d->m_displayFormat) { 00416 d->m_displayFormat = format; 00417 d->initDateWidget(); 00418 d->updateDateWidget(); 00419 } 00420 } 00421 00422 QMap<QDate, QString> KDateComboBox::dateMap() const 00423 { 00424 return d->m_dateMap; 00425 } 00426 00427 void KDateComboBox::setDateMap(QMap<QDate, QString> dateMap) 00428 { 00429 if (dateMap != d->m_dateMap) { 00430 d->m_dateMap.clear(); 00431 d->m_dateMap = dateMap; 00432 d->initDateWidget(); 00433 } 00434 } 00435 00436 bool KDateComboBox::eventFilter(QObject *object, QEvent *event) 00437 { 00438 return KComboBox::eventFilter(object, event); 00439 } 00440 00441 void KDateComboBox::keyPressEvent(QKeyEvent *keyEvent) 00442 { 00443 QDate temp; 00444 switch (keyEvent->key()) { 00445 case Qt::Key_Down: 00446 temp = d->m_date.addDays(-1).date(); 00447 return; 00448 case Qt::Key_Up: 00449 temp = d->m_date.addDays(1).date(); 00450 return; 00451 case Qt::Key_PageDown: 00452 temp = d->m_date.addMonths(-1).date(); 00453 return; 00454 case Qt::Key_PageUp: 00455 temp = d->m_date.addMonths(1).date(); 00456 return; 00457 default: 00458 KComboBox::keyPressEvent(keyEvent); 00459 } 00460 if (temp.isValid() && temp >= d->m_minDate && temp <= d->m_maxDate) { 00461 d->enterDate(temp); 00462 } 00463 } 00464 00465 void KDateComboBox::focusOutEvent(QFocusEvent *event) 00466 { 00467 d->parseDate(); 00468 d->warnDate(); 00469 KComboBox::focusOutEvent(event); 00470 } 00471 00472 void KDateComboBox::showPopup() 00473 { 00474 if (!isEditable() || 00475 !d->m_dateMenu || 00476 (d->m_options &KDateComboBox::SelectDate) != KDateComboBox::SelectDate) { 00477 return; 00478 } 00479 00480 d->m_datePicker->blockSignals(true); 00481 d->m_datePicker->setDate(d->m_date.date()); 00482 d->m_datePicker->blockSignals(false); 00483 00484 const QRect desk = KGlobalSettings::desktopGeometry(this); 00485 00486 QPoint popupPoint = mapToGlobal(QPoint(0, 0)); 00487 00488 const int dateFrameHeight = d->m_dateMenu->sizeHint().height(); 00489 if (popupPoint.y() + height() + dateFrameHeight > desk.bottom()) { 00490 popupPoint.setY(popupPoint.y() - dateFrameHeight); 00491 } else { 00492 popupPoint.setY(popupPoint.y() + height()); 00493 } 00494 00495 const int dateFrameWidth = d->m_dateMenu->sizeHint().width(); 00496 if (popupPoint.x() + dateFrameWidth > desk.right()) { 00497 popupPoint.setX(desk.right() - dateFrameWidth); 00498 } 00499 00500 if (popupPoint.x() < desk.left()) { 00501 popupPoint.setX(desk.left()); 00502 } 00503 00504 if (popupPoint.y() < desk.top()) { 00505 popupPoint.setY(desk.top()); 00506 } 00507 00508 d->m_dateMenu->popup(popupPoint); 00509 } 00510 00511 void KDateComboBox::hidePopup() 00512 { 00513 KComboBox::hidePopup(); 00514 } 00515 00516 void KDateComboBox::mousePressEvent(QMouseEvent *event) 00517 { 00518 KComboBox::mousePressEvent(event); 00519 } 00520 00521 void KDateComboBox::wheelEvent(QWheelEvent *event) 00522 { 00523 KComboBox::wheelEvent(event); 00524 } 00525 00526 void KDateComboBox::focusInEvent(QFocusEvent *event) 00527 { 00528 KComboBox::focusInEvent(event); 00529 } 00530 00531 void KDateComboBox::resizeEvent(QResizeEvent *event) 00532 { 00533 KComboBox::resizeEvent(event); 00534 } 00535 00536 #include "kdatecombobox.moc"
KDE 4.7 API Reference