summaryrefslogtreecommitdiffstats
path: root/kalarm/lib/timespinbox.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kalarm/lib/timespinbox.cpp')
-rw-r--r--kalarm/lib/timespinbox.cpp364
1 files changed, 364 insertions, 0 deletions
diff --git a/kalarm/lib/timespinbox.cpp b/kalarm/lib/timespinbox.cpp
new file mode 100644
index 00000000..7a22cd23
--- /dev/null
+++ b/kalarm/lib/timespinbox.cpp
@@ -0,0 +1,364 @@
+/*
+ * timespinbox.cpp - time spinbox widget
+ * Program: kalarm
+ * Copyright © 2001-2004,2007,2008 by David Jarvie <djarvie@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "kalarm.h"
+
+#include <qvalidator.h>
+#include <qlineedit.h>
+#include <klocale.h>
+
+#include "timespinbox.moc"
+
+
+class TimeSpinBox::TimeValidator : public QValidator
+{
+ public:
+ TimeValidator(int minMin, int maxMin, QWidget* parent, const char* name = 0)
+ : QValidator(parent, name),
+ minMinute(minMin), maxMinute(maxMin), m12Hour(false), mPm(false) { }
+ virtual State validate(QString&, int&) const;
+ int minMinute, maxMinute;
+ bool m12Hour;
+ bool mPm;
+};
+
+
+/*=============================================================================
+= Class TimeSpinBox
+= This is a spin box displaying a time in the format hh:mm, with a pair of
+= spin buttons for each of the hour and minute values.
+= It can operate in 3 modes:
+= 1) a time of day using the 24-hour clock.
+= 2) a time of day using the 12-hour clock. The value is held as 0:00 - 23:59,
+= but is displayed as 12:00 - 11:59. This is for use in a TimeEdit widget.
+= 3) a length of time, not restricted to the length of a day.
+=============================================================================*/
+
+/******************************************************************************
+ * Construct a wrapping 00:00 - 23:59, or 12:00 - 11:59 time spin box.
+ */
+TimeSpinBox::TimeSpinBox(bool use24hour, QWidget* parent, const char* name)
+ : SpinBox2(0, 1439, 1, 60, parent, name),
+ mMinimumValue(0),
+ m12Hour(!use24hour),
+ mPm(false),
+ mInvalid(false),
+ mEnteredSetValue(false)
+{
+ mValidator = new TimeValidator(0, 1439, this, "TimeSpinBox validator");
+ mValidator->m12Hour = m12Hour;
+ setValidator(mValidator);
+ setWrapping(true);
+ setReverseWithLayout(false); // keep buttons the same way round even if right-to-left language
+ setShiftSteps(5, 360); // shift-left button increments 5 min / 6 hours
+ setSelectOnStep(false);
+ setAlignment(Qt::AlignHCenter);
+ connect(this, SIGNAL(valueChanged(int)), SLOT(slotValueChanged(int)));
+}
+
+/******************************************************************************
+ * Construct a non-wrapping time spin box.
+ */
+TimeSpinBox::TimeSpinBox(int minMinute, int maxMinute, QWidget* parent, const char* name)
+ : SpinBox2(minMinute, maxMinute, 1, 60, parent, name),
+ mMinimumValue(minMinute),
+ m12Hour(false),
+ mInvalid(false),
+ mEnteredSetValue(false)
+{
+ mValidator = new TimeValidator(minMinute, maxMinute, this, "TimeSpinBox validator");
+ setValidator(mValidator);
+ setReverseWithLayout(false); // keep buttons the same way round even if right-to-left language
+ setShiftSteps(5, 300); // shift-left button increments 5 min / 5 hours
+ setSelectOnStep(false);
+ setAlignment(QApplication::reverseLayout() ? Qt::AlignLeft : Qt::AlignRight);
+}
+
+QString TimeSpinBox::shiftWhatsThis()
+{
+ return i18n("Press the Shift key while clicking the spin buttons to adjust the time by a larger step (6 hours / 5 minutes).");
+}
+
+QTime TimeSpinBox::time() const
+{
+ return QTime(value() / 60, value() % 60);
+}
+
+QString TimeSpinBox::mapValueToText(int v)
+{
+ if (m12Hour)
+ {
+ if (v < 60)
+ v += 720; // convert 0:nn to 12:nn
+ else if (v >= 780)
+ v -= 720; // convert 13 - 23 hours to 1 - 11
+ }
+ QString s;
+ s.sprintf((wrapping() ? "%02d:%02d" : "%d:%02d"), v/60, v%60);
+ return s;
+}
+
+/******************************************************************************
+ * Convert the user-entered text to a value in minutes.
+ * The allowed formats are:
+ * [hour]:[minute], where minute must be non-blank, or
+ * hhmm, 4 digits, where hour < 24.
+ */
+int TimeSpinBox::mapTextToValue(bool* ok)
+{
+ QString text = cleanText();
+ int colon = text.find(':');
+ if (colon >= 0)
+ {
+ // [h]:m format for any time value
+ QString hour = text.left(colon).stripWhiteSpace();
+ QString minute = text.mid(colon + 1).stripWhiteSpace();
+ if (!minute.isEmpty())
+ {
+ bool okmin;
+ bool okhour = true;
+ int m = minute.toUInt(&okmin);
+ int h = 0;
+ if (!hour.isEmpty())
+ h = hour.toUInt(&okhour);
+ if (okhour && okmin && m < 60)
+ {
+ if (m12Hour)
+ {
+ if (h == 0 || h > 12)
+ h = 100; // error
+ else if (h == 12)
+ h = 0; // convert 12:nn to 0:nn
+ if (mPm)
+ h += 12; // convert to PM
+ }
+ int t = h * 60 + m;
+ if (t >= mMinimumValue && t <= maxValue())
+ {
+ if (ok)
+ *ok = true;
+ return t;
+ }
+ }
+ }
+ }
+ else if (text.length() == 4)
+ {
+ // hhmm format for time of day
+ bool okn;
+ int mins = text.toUInt(&okn);
+ if (okn)
+ {
+ int m = mins % 100;
+ int h = mins / 100;
+ if (m12Hour)
+ {
+ if (h == 0 || h > 12)
+ h = 100; // error
+ else if (h == 12)
+ h = 0; // convert 12:nn to 0:nn
+ if (mPm)
+ h += 12; // convert to PM
+ }
+ int t = h * 60 + m;
+ if (h < 24 && m < 60 && t >= mMinimumValue && t <= maxValue())
+ {
+ if (ok)
+ *ok = true;
+ return t;
+ }
+ }
+
+ }
+ if (ok)
+ *ok = false;
+ return 0;
+}
+
+/******************************************************************************
+ * Set the spin box as valid or invalid.
+ * If newly invalid, the value is displayed as asterisks.
+ * If newly valid, the value is set to the minimum value.
+ */
+void TimeSpinBox::setValid(bool valid)
+{
+ if (valid && mInvalid)
+ {
+ mInvalid = false;
+ if (value() < mMinimumValue)
+ SpinBox2::setValue(mMinimumValue);
+ setSpecialValueText(QString());
+ SpinBox2::setMinValue(mMinimumValue);
+ }
+ else if (!valid && !mInvalid)
+ {
+ mInvalid = true;
+ SpinBox2::setMinValue(mMinimumValue - 1);
+ setSpecialValueText(QString::fromLatin1("**:**"));
+ SpinBox2::setValue(mMinimumValue - 1);
+ }
+}
+
+/******************************************************************************
+* Set the spin box's minimum value.
+*/
+void TimeSpinBox::setMinValue(int minutes)
+{
+ mMinimumValue = minutes;
+ SpinBox2::setMinValue(mMinimumValue - (mInvalid ? 1 : 0));
+}
+
+/******************************************************************************
+ * Set the spin box's value.
+ */
+void TimeSpinBox::setValue(int minutes)
+{
+ if (!mEnteredSetValue)
+ {
+ mEnteredSetValue = true;
+ mPm = (minutes >= 720);
+ if (minutes > maxValue())
+ setValid(false);
+ else
+ {
+ if (mInvalid)
+ {
+ mInvalid = false;
+ setSpecialValueText(QString());
+ SpinBox2::setMinValue(mMinimumValue);
+ }
+ SpinBox2::setValue(minutes);
+ mEnteredSetValue = false;
+ }
+ }
+}
+
+/******************************************************************************
+ * Step the spin box value.
+ * If it was invalid, set it valid and set the value to the minimum.
+ */
+void TimeSpinBox::stepUp()
+{
+ if (mInvalid)
+ setValid(true);
+ else
+ SpinBox2::stepUp();
+}
+
+void TimeSpinBox::stepDown()
+{
+ if (mInvalid)
+ setValid(true);
+ else
+ SpinBox2::stepDown();
+}
+
+bool TimeSpinBox::isValid() const
+{
+ return value() >= mMinimumValue;
+}
+
+void TimeSpinBox::slotValueChanged(int value)
+{
+ mPm = mValidator->mPm = (value >= 720);
+}
+
+QSize TimeSpinBox::sizeHint() const
+{
+ QSize sz = SpinBox2::sizeHint();
+ QFontMetrics fm(font());
+ return QSize(sz.width() + fm.width(":"), sz.height());
+}
+
+QSize TimeSpinBox::minimumSizeHint() const
+{
+ QSize sz = SpinBox2::minimumSizeHint();
+ QFontMetrics fm(font());
+ return QSize(sz.width() + fm.width(":"), sz.height());
+}
+
+/******************************************************************************
+ * Validate the time spin box input.
+ * The entered time must either be 4 digits, or it must contain a colon, but
+ * hours may be blank.
+ */
+QValidator::State TimeSpinBox::TimeValidator::validate(QString& text, int& /*cursorPos*/) const
+{
+ QString cleanText = text.stripWhiteSpace();
+ if (cleanText.isEmpty())
+ return QValidator::Intermediate;
+ QValidator::State state = QValidator::Acceptable;
+ QString hour;
+ bool ok;
+ int hr = 0;
+ int mn = 0;
+ int colon = cleanText.find(':');
+ if (colon >= 0)
+ {
+ QString minute = cleanText.mid(colon + 1);
+ if (minute.isEmpty())
+ state = QValidator::Intermediate;
+ else if ((mn = minute.toUInt(&ok)) >= 60 || !ok)
+ return QValidator::Invalid;
+
+ hour = cleanText.left(colon);
+ }
+ else if (maxMinute >= 1440)
+ {
+ // The hhmm form of entry is only allowed for time-of-day, i.e. <= 2359
+ hour = cleanText;
+ state = QValidator::Intermediate;
+ }
+ else
+ {
+ if (cleanText.length() > 4)
+ return QValidator::Invalid;
+ if (cleanText.length() < 4)
+ state = QValidator::Intermediate;
+ hour = cleanText.left(2);
+ QString minute = cleanText.mid(2);
+ if (!minute.isEmpty()
+ && ((mn = minute.toUInt(&ok)) >= 60 || !ok))
+ return QValidator::Invalid;
+ }
+
+ if (!hour.isEmpty())
+ {
+ hr = hour.toUInt(&ok);
+ if (m12Hour)
+ {
+ if (hr == 0 || hr > 12)
+ hr = 100; // error;
+ else if (hr == 12)
+ hr = 0; // convert 12:nn to 0:nn
+ if (mPm)
+ hr += 12; // convert to PM
+ }
+ if (!ok || hr > maxMinute/60)
+ return QValidator::Invalid;
+ }
+ if (state == QValidator::Acceptable)
+ {
+ int t = hr * 60 + mn;
+ if (t < minMinute || t > maxMinute)
+ return QValidator::Invalid;
+ }
+ return state;
+}