KDEUI
ktimecombobox.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 "ktimecombobox.h" 00021 00022 #include <QtCore/QTime> 00023 #include <QtGui/QKeyEvent> 00024 #include <QtGui/QLineEdit> 00025 00026 #include "kglobal.h" 00027 #include "kdebug.h" 00028 #include "klocale.h" 00029 #include "kcombobox.h" 00030 #include "kmessagebox.h" 00031 00032 class KTimeComboBoxPrivate 00033 { 00034 public: 00035 00036 KTimeComboBoxPrivate(KTimeComboBox *q); 00037 virtual ~KTimeComboBoxPrivate(); 00038 00039 QTime defaultMinTime(); 00040 QTime defaultMaxTime(); 00041 00042 QString timeFormatToInputMask(const QString &format, bool nullMask = false); 00043 QTime nearestIntervalTime(const QTime &time); 00044 QString formatTime(const QTime &time); 00045 QString convertDigits(const QString &digits); 00046 00047 void initTimeWidget(); 00048 void updateTimeWidget(); 00049 00050 // Q_PRIVATE_SLOTs 00051 void selectTime(int index); 00052 void editTime(const QString &text); 00053 void enterTime(const QTime &time); 00054 void parseTime(); 00055 void warnTime(); 00056 00057 KTimeComboBox *const q; 00058 00059 QTime m_time; 00060 KTimeComboBox::Options m_options; 00061 QTime m_minTime; 00062 QTime m_maxTime; 00063 QString m_minWarnMsg; 00064 QString m_maxWarnMsg; 00065 QString m_nullString; 00066 bool m_warningShown; 00067 KLocale::TimeFormatOptions m_displayFormat; 00068 int m_timeListInterval; 00069 QList<QTime> m_timeList; 00070 }; 00071 00072 KTimeComboBoxPrivate::KTimeComboBoxPrivate(KTimeComboBox *q) 00073 :q(q), 00074 m_time(QTime(0, 0, 0)), 00075 m_warningShown(false), 00076 m_displayFormat(KLocale::TimeDefault), 00077 m_timeListInterval(15) 00078 { 00079 m_options = KTimeComboBox::EditTime | KTimeComboBox::SelectTime; 00080 m_minTime = defaultMinTime(); 00081 m_maxTime = defaultMaxTime(); 00082 } 00083 00084 KTimeComboBoxPrivate::~KTimeComboBoxPrivate() 00085 { 00086 } 00087 00088 QTime KTimeComboBoxPrivate::defaultMinTime() 00089 { 00090 return QTime(0, 0, 0, 0); 00091 } 00092 00093 QTime KTimeComboBoxPrivate::defaultMaxTime() 00094 { 00095 return QTime(23, 59, 59, 999); 00096 } 00097 00098 QString KTimeComboBoxPrivate::timeFormatToInputMask(const QString &format, bool nullMask) 00099 { 00100 //TODO not sure this will always work, does it support DigitSets, am/pm is dodgy? 00101 QString mask = formatTime(QTime(12,34,56,789)); 00102 QString null = mask; 00103 mask.replace(convertDigits(QLatin1String("12")), QLatin1String("09")); 00104 null.replace(convertDigits(QLatin1String("12")), QLatin1String("")); 00105 mask.replace(convertDigits(QLatin1String("34")), QLatin1String("99")); 00106 null.replace(convertDigits(QLatin1String("34")), QLatin1String("")); 00107 mask.replace(convertDigits(QLatin1String("56")), QLatin1String("99")); 00108 null.replace(convertDigits(QLatin1String("56")), QLatin1String("")); 00109 mask.replace(convertDigits(QLatin1String("789")), QLatin1String("900")); 00110 null.replace(convertDigits(QLatin1String("789")), QLatin1String("")); 00111 if (format.contains(QLatin1String("%p")) || 00112 format.contains(QLatin1String("%P"))) { 00113 QString am = KGlobal::locale()->dayPeriodText(QTime(0, 0, 0)); 00114 QString pm = KGlobal::locale()->dayPeriodText(QTime(12, 0, 0)); 00115 int ampmLen = qMax(am.length(), pm.length()); 00116 QString ampmMask; 00117 for (int i = 0; i < ampmLen; ++i) { 00118 ampmMask.append(QLatin1Char('a')); 00119 } 00120 mask.replace(pm, ampmMask); 00121 null.replace(pm, QLatin1String("")); 00122 } 00123 00124 if (nullMask) { 00125 return null; 00126 } else { 00127 return mask; 00128 } 00129 } 00130 00131 QTime KTimeComboBoxPrivate::nearestIntervalTime(const QTime &time) 00132 { 00133 int i = 0; 00134 while (q->itemData(i).toTime() < time) { 00135 ++i; 00136 } 00137 QTime before = q->itemData(i).toTime(); 00138 QTime after = q->itemData(i + 1).toTime(); 00139 if (before.secsTo(time) <= time.secsTo(after)) { 00140 return before; 00141 } else { 00142 return after; 00143 } 00144 } 00145 00146 QString KTimeComboBoxPrivate::formatTime(const QTime &time) 00147 { 00148 return KGlobal::locale()->formatTime(time, m_displayFormat); 00149 } 00150 00151 QString KTimeComboBoxPrivate::convertDigits(const QString &digits) 00152 { 00153 return KGlobal::locale()->convertDigits(digits, KGlobal::locale()->dateTimeDigitSet()); 00154 } 00155 00156 void KTimeComboBoxPrivate::initTimeWidget() 00157 { 00158 q->blockSignals(true); 00159 q->clear(); 00160 00161 // Set the input mask from the current format 00162 q->lineEdit()->setInputMask(timeFormatToInputMask(KGlobal::locale()->timeFormat())); 00163 m_nullString = timeFormatToInputMask(KGlobal::locale()->timeFormat(), true); 00164 00165 // If EditTime then set the line edit 00166 q->lineEdit()->setReadOnly((m_options &KTimeComboBox::EditTime) != KTimeComboBox::EditTime); 00167 00168 // If SelectTime then make list items visible 00169 if ((m_options &KTimeComboBox::SelectTime) == KTimeComboBox::SelectTime) { 00170 q->setMaxVisibleItems(10); 00171 } else { 00172 q->setMaxVisibleItems(0); 00173 } 00174 00175 // Populate the drop-down time list 00176 // If no time list set the use the time interval 00177 if (m_timeList.isEmpty()) { 00178 QTime startTime = m_minTime; 00179 QTime thisTime(startTime.hour(), 0, 0, 0); 00180 while (thisTime.isValid() && thisTime <= startTime) { 00181 thisTime = thisTime.addSecs(m_timeListInterval * 60); 00182 } 00183 QTime endTime = m_maxTime; 00184 q->addItem(formatTime(startTime), startTime); 00185 while (thisTime.isValid() && thisTime < endTime) { 00186 q->addItem(formatTime(thisTime), thisTime); 00187 QTime newTime = thisTime.addSecs(m_timeListInterval * 60); 00188 if (newTime.isValid() && newTime > thisTime) { 00189 thisTime = newTime; 00190 } else { 00191 thisTime = QTime(); 00192 } 00193 } 00194 q->addItem(formatTime(endTime), endTime); 00195 } else { 00196 foreach (const QTime &thisTime, m_timeList) { 00197 if (thisTime.isValid() && thisTime >= m_minTime && thisTime <= m_maxTime) { 00198 q->addItem(formatTime(thisTime), thisTime); 00199 } 00200 } 00201 } 00202 q->blockSignals(false); 00203 } 00204 00205 void KTimeComboBoxPrivate::updateTimeWidget() 00206 { 00207 q->blockSignals(true); 00208 int pos = q->lineEdit()->cursorPosition(); 00209 //Set index before setting text otherwise it overwrites 00210 int i = 0; 00211 if (!m_time.isValid() || m_time < m_minTime) { 00212 i = 0; 00213 } else if (m_time > m_maxTime) { 00214 i = q->count() - 1; 00215 } else { 00216 while (q->itemData(i).toTime() < m_time && i < q->count() - 1) { 00217 ++i; 00218 } 00219 } 00220 q->setCurrentIndex(i); 00221 if (m_time.isValid()) { 00222 q->lineEdit()->setText(formatTime(m_time)); 00223 } else { 00224 q->lineEdit()->setText(QString()); 00225 } 00226 q->lineEdit()->setCursorPosition(pos); 00227 q->blockSignals(false); 00228 } 00229 00230 void KTimeComboBoxPrivate::selectTime(int index) 00231 { 00232 enterTime(q->itemData(index).toTime()); 00233 } 00234 00235 void KTimeComboBoxPrivate::editTime(const QString &text) 00236 { 00237 m_warningShown = false; 00238 emit q->timeEdited(KGlobal::locale()->readTime(text)); 00239 } 00240 00241 void KTimeComboBoxPrivate::parseTime() 00242 { 00243 m_time = KGlobal::locale()->readTime(q->lineEdit()->text()); 00244 } 00245 00246 void KTimeComboBoxPrivate::enterTime(const QTime &time) 00247 { 00248 q->setTime(time); 00249 warnTime(); 00250 emit q->timeEntered(m_time); 00251 } 00252 00253 void KTimeComboBoxPrivate::warnTime() 00254 { 00255 if (!m_warningShown && !q->isValid() && 00256 (m_options &KTimeComboBox::WarnOnInvalid) == KTimeComboBox::WarnOnInvalid) { 00257 QString warnMsg; 00258 if (!m_time.isValid()) { 00259 warnMsg = i18nc("@info", "The time you entered is invalid"); 00260 } else if (m_time < m_minTime) { 00261 if (m_minWarnMsg.isEmpty()) { 00262 warnMsg = i18nc("@info", "Time cannot be earlier than %1", formatTime(m_minTime)); 00263 } else { 00264 warnMsg = m_minWarnMsg; 00265 warnMsg.replace("%1", formatTime(m_minTime)); 00266 } 00267 } else if (m_time > m_maxTime) { 00268 if (m_maxWarnMsg.isEmpty()) { 00269 warnMsg = i18nc("@info", "Time cannot be later than %1", formatTime(m_maxTime)); 00270 } else { 00271 warnMsg = m_maxWarnMsg; 00272 warnMsg.replace("%1", formatTime(m_maxTime)); 00273 } 00274 } 00275 m_warningShown = true; 00276 KMessageBox::sorry(q, warnMsg); 00277 } 00278 } 00279 00280 KTimeComboBox::KTimeComboBox(QWidget *parent) 00281 :KComboBox(parent), 00282 d(new KTimeComboBoxPrivate(this)) 00283 { 00284 setEditable(true); 00285 setInsertPolicy(QComboBox::NoInsert); 00286 setSizeAdjustPolicy(QComboBox::AdjustToContents); 00287 d->initTimeWidget(); 00288 d->updateTimeWidget(); 00289 00290 connect( this, SIGNAL(activated(int)), 00291 this, SLOT(selectTime(int))); 00292 connect( this, SIGNAL(editTextChanged(const QString&)), 00293 this, SLOT(editTime(const QString&))); 00294 } 00295 00296 KTimeComboBox::~KTimeComboBox() 00297 { 00298 delete d; 00299 } 00300 00301 QTime KTimeComboBox::time() const 00302 { 00303 d->parseTime(); 00304 return d->m_time; 00305 } 00306 00307 void KTimeComboBox::setTime(const QTime &time) 00308 { 00309 if (time == d->m_time) { 00310 return; 00311 } 00312 00313 if ((d->m_options &KTimeComboBox::ForceTime) == KTimeComboBox::ForceTime) { 00314 assignTime(d->nearestIntervalTime(time)); 00315 } else { 00316 assignTime(time); 00317 } 00318 00319 d->updateTimeWidget(); 00320 emit timeChanged(d->m_time); 00321 } 00322 00323 void KTimeComboBox::assignTime(const QTime &time) 00324 { 00325 d->m_time = time; 00326 } 00327 00328 bool KTimeComboBox::isValid() const 00329 { 00330 d->parseTime(); 00331 return d->m_time.isValid() && 00332 d->m_time >= d->m_minTime && 00333 d->m_time <= d->m_maxTime; 00334 } 00335 00336 bool KTimeComboBox::isNull() const 00337 { 00338 return lineEdit()->text() == d->m_nullString; 00339 } 00340 00341 KTimeComboBox::Options KTimeComboBox::options() const 00342 { 00343 return d->m_options; 00344 } 00345 00346 void KTimeComboBox::setOptions(Options options) 00347 { 00348 if (options != d->m_options) { 00349 d->m_options = options; 00350 d->initTimeWidget(); 00351 d->updateTimeWidget(); 00352 } 00353 } 00354 00355 QTime KTimeComboBox::minimumTime() const 00356 { 00357 return d->m_minTime; 00358 } 00359 00360 void KTimeComboBox::setMinimumTime(const QTime &minTime, const QString &minWarnMsg) 00361 { 00362 setTimeRange(minTime, d->m_maxTime, minWarnMsg, d->m_maxWarnMsg); 00363 } 00364 00365 void KTimeComboBox::resetMinimumTime() 00366 { 00367 setTimeRange(d->defaultMinTime(), d->m_maxTime, QString(), d->m_maxWarnMsg); 00368 } 00369 00370 QTime KTimeComboBox::maximumTime() const 00371 { 00372 return d->m_maxTime; 00373 } 00374 00375 void KTimeComboBox::setMaximumTime(const QTime &maxTime, const QString &maxWarnMsg) 00376 { 00377 setTimeRange(d->m_minTime, maxTime, d->m_minWarnMsg, maxWarnMsg); 00378 } 00379 00380 void KTimeComboBox::resetMaximumTime() 00381 { 00382 setTimeRange(d->m_minTime, d->defaultMaxTime(), d->m_minWarnMsg, QString()); 00383 } 00384 00385 void KTimeComboBox::setTimeRange(const QTime &minTime, const QTime &maxTime, 00386 const QString &minWarnMsg, const QString &maxWarnMsg) 00387 { 00388 if (!minTime.isValid() || !maxTime.isValid() || minTime > maxTime) { 00389 return; 00390 } 00391 00392 if (minTime != d->m_minTime || maxTime != d->m_maxTime || 00393 minWarnMsg != d->m_minWarnMsg || maxWarnMsg != d->m_maxWarnMsg) { 00394 d->m_minTime = minTime; 00395 d->m_maxTime = maxTime; 00396 d->m_minWarnMsg = minWarnMsg; 00397 d->m_maxWarnMsg = maxWarnMsg; 00398 d->initTimeWidget(); 00399 d->updateTimeWidget(); 00400 } 00401 } 00402 00403 void KTimeComboBox::resetTimeRange() 00404 { 00405 setTimeRange(d->defaultMinTime(), d->defaultMaxTime(), QString(), QString()); 00406 } 00407 00408 KLocale::TimeFormatOptions KTimeComboBox::displayFormat() const 00409 { 00410 return d->m_displayFormat; 00411 } 00412 00413 void KTimeComboBox::setDisplayFormat(KLocale::TimeFormatOptions format) 00414 { 00415 if (format != d->m_displayFormat) { 00416 d->m_displayFormat = format; 00417 d->initTimeWidget(); 00418 d->updateTimeWidget(); 00419 } 00420 } 00421 00422 int KTimeComboBox::timeListInterval() const 00423 { 00424 return d->m_timeListInterval; 00425 } 00426 00427 void KTimeComboBox::setTimeListInterval(int minutes) 00428 { 00429 if (minutes != d->m_timeListInterval) { 00430 //Must be able to exactly divide the valid time period 00431 int lowMins = (d->m_minTime.hour() * 60) + d->m_minTime.minute(); 00432 int hiMins = (d->m_maxTime.hour() * 60) + d->m_maxTime.minute(); 00433 if (d->m_minTime.minute() == 0 && d->m_maxTime.minute() == 59) { 00434 ++hiMins; 00435 } 00436 if ((hiMins - lowMins) % minutes == 0) { 00437 d->m_timeListInterval = minutes; 00438 d->m_timeList.clear(); 00439 } else { 00440 return; 00441 } 00442 d->initTimeWidget(); 00443 } 00444 } 00445 00446 QList<QTime> KTimeComboBox::timeList() const 00447 { 00448 //Return the drop down list as it is what can be selected currently 00449 QList<QTime> list; 00450 int c = count(); 00451 for (int i = 0; i < c; ++i) { 00452 list.append(itemData(i).toTime()); 00453 } 00454 return list; 00455 } 00456 00457 void KTimeComboBox::setTimeList(QList<QTime> timeList, 00458 const QString &minWarnMsg, const QString &maxWarnMsg) 00459 { 00460 if (timeList != d->m_timeList) { 00461 d->m_timeList.clear(); 00462 foreach (const QTime &time, timeList) { 00463 if (time.isValid() && !d->m_timeList.contains(time)) { 00464 d->m_timeList.append(time); 00465 } 00466 } 00467 qSort(d->m_timeList); 00468 // Does the updateTimeWidget call for us 00469 setTimeRange(d->m_timeList.first(), d->m_timeList.last(), 00470 minWarnMsg, maxWarnMsg); 00471 } 00472 } 00473 00474 bool KTimeComboBox::eventFilter(QObject *object, QEvent *event) 00475 { 00476 return KComboBox::eventFilter(object, event); 00477 } 00478 00479 void KTimeComboBox::keyPressEvent(QKeyEvent *keyEvent) 00480 { 00481 QTime temp; 00482 switch (keyEvent->key()) { 00483 case Qt::Key_Down: 00484 temp = d->m_time.addSecs(-60); 00485 break; 00486 case Qt::Key_Up: 00487 temp = d->m_time.addSecs(60); 00488 break; 00489 case Qt::Key_PageDown: 00490 temp = d->m_time.addSecs(-3600); 00491 break; 00492 case Qt::Key_PageUp: 00493 temp = d->m_time.addSecs(3600); 00494 break; 00495 default: 00496 KComboBox::keyPressEvent(keyEvent); 00497 return; 00498 } 00499 if (temp.isValid() && temp >= d->m_minTime && temp <= d->m_maxTime) { 00500 d->enterTime(temp); 00501 } 00502 } 00503 00504 void KTimeComboBox::focusOutEvent(QFocusEvent *event) 00505 { 00506 d->parseTime(); 00507 d->warnTime(); 00508 KComboBox::focusOutEvent(event); 00509 } 00510 00511 void KTimeComboBox::showPopup() 00512 { 00513 KComboBox::showPopup(); 00514 } 00515 00516 void KTimeComboBox::hidePopup() 00517 { 00518 KComboBox::hidePopup(); 00519 } 00520 00521 void KTimeComboBox::mousePressEvent(QMouseEvent *event) 00522 { 00523 KComboBox::mousePressEvent(event); 00524 } 00525 00526 void KTimeComboBox::wheelEvent(QWheelEvent *event) 00527 { 00528 KComboBox::wheelEvent(event); 00529 } 00530 00531 void KTimeComboBox::focusInEvent(QFocusEvent *event) 00532 { 00533 KComboBox::focusInEvent(event); 00534 } 00535 00536 void KTimeComboBox::resizeEvent(QResizeEvent *event) 00537 { 00538 KComboBox::resizeEvent(event); 00539 } 00540 00541 #include "ktimecombobox.moc"
KDE 4.7 API Reference