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