kalarm/lib

timespinbox.cpp
1/*
2 * timespinbox.cpp - time spinbox widget
3 * Program: kalarm
4 * Copyright © 2001-2004,2007,2008 by David Jarvie <djarvie@kde.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21#include "kalarm.h"
22
23#include <tqvalidator.h>
24#include <tqlineedit.h>
25#include <tdelocale.h>
26
27#include "timespinbox.moc"
28
29
30class TimeSpinBox::TimeValidator : public TQValidator
31{
32 public:
33 TimeValidator(int minMin, int maxMin, TQWidget* parent, const char* name = 0)
34 : TQValidator(parent, name),
35 minMinute(minMin), maxMinute(maxMin), m12Hour(false), mPm(false) { }
36 virtual State validate(TQString&, int&) const;
37 int minMinute, maxMinute;
38 bool m12Hour;
39 bool mPm;
40};
41
42
43/*=============================================================================
44= Class TimeSpinBox
45= This is a spin box displaying a time in the format hh:mm, with a pair of
46= spin buttons for each of the hour and minute values.
47= It can operate in 3 modes:
48= 1) a time of day using the 24-hour clock.
49= 2) a time of day using the 12-hour clock. The value is held as 0:00 - 23:59,
50= but is displayed as 12:00 - 11:59. This is for use in a TimeEdit widget.
51= 3) a length of time, not restricted to the length of a day.
52=============================================================================*/
53
54/******************************************************************************
55 * Construct a wrapping 00:00 - 23:59, or 12:00 - 11:59 time spin box.
56 */
57TimeSpinBox::TimeSpinBox(bool use24hour, TQWidget* parent, const char* name)
58 : SpinBox2(0, 1439, 1, 60, parent, name),
59 mMinimumValue(0),
60 m12Hour(!use24hour),
61 mPm(false),
62 mInvalid(false),
63 mEnteredSetValue(false)
64{
65 mValidator = new TimeValidator(0, 1439, this, "TimeSpinBox validator");
66 mValidator->m12Hour = m12Hour;
67 setValidator(mValidator);
68 setWrapping(true);
69 setReverseWithLayout(false); // keep buttons the same way round even if right-to-left language
70 setShiftSteps(5, 360); // shift-left button increments 5 min / 6 hours
71 setSelectOnStep(false);
72 setAlignment(TQt::AlignHCenter);
73 connect(this, TQ_SIGNAL(valueChanged(int)), TQ_SLOT(slotValueChanged(int)));
74}
75
76/******************************************************************************
77 * Construct a non-wrapping time spin box.
78 */
79TimeSpinBox::TimeSpinBox(int minMinute, int maxMinute, TQWidget* parent, const char* name)
80 : SpinBox2(minMinute, maxMinute, 1, 60, parent, name),
81 mMinimumValue(minMinute),
82 m12Hour(false),
83 mInvalid(false),
84 mEnteredSetValue(false)
85{
86 mValidator = new TimeValidator(minMinute, maxMinute, this, "TimeSpinBox validator");
87 setValidator(mValidator);
88 setReverseWithLayout(false); // keep buttons the same way round even if right-to-left language
89 setShiftSteps(5, 300); // shift-left button increments 5 min / 5 hours
90 setSelectOnStep(false);
91 setAlignment(TQApplication::reverseLayout() ? TQt::AlignLeft : TQt::AlignRight);
92}
93
95{
96 return i18n("Press the Shift key while clicking the spin buttons to adjust the time by a larger step (6 hours / 5 minutes).");
97}
98
99TQTime TimeSpinBox::time() const
100{
101 return TQTime(value() / 60, value() % 60);
102}
103
104TQString TimeSpinBox::mapValueToText(int v)
105{
106 if (m12Hour)
107 {
108 if (v < 60)
109 v += 720; // convert 0:nn to 12:nn
110 else if (v >= 780)
111 v -= 720; // convert 13 - 23 hours to 1 - 11
112 }
113 TQString s;
114 s.sprintf((wrapping() ? "%02d:%02d" : "%d:%02d"), v/60, v%60);
115 return s;
116}
117
118/******************************************************************************
119 * Convert the user-entered text to a value in minutes.
120 * The allowed formats are:
121 * [hour]:[minute], where minute must be non-blank, or
122 * hhmm, 4 digits, where hour < 24.
123 */
124int TimeSpinBox::mapTextToValue(bool* ok)
125{
126 TQString text = cleanText();
127 int colon = text.find(':');
128 if (colon >= 0)
129 {
130 // [h]:m format for any time value
131 TQString hour = text.left(colon).stripWhiteSpace();
132 TQString minute = text.mid(colon + 1).stripWhiteSpace();
133 if (!minute.isEmpty())
134 {
135 bool okmin;
136 bool okhour = true;
137 int m = minute.toUInt(&okmin);
138 int h = 0;
139 if (!hour.isEmpty())
140 h = hour.toUInt(&okhour);
141 if (okhour && okmin && m < 60)
142 {
143 if (m12Hour)
144 {
145 if (h == 0 || h > 12)
146 h = 100; // error
147 else if (h == 12)
148 h = 0; // convert 12:nn to 0:nn
149 if (mPm)
150 h += 12; // convert to PM
151 }
152 int t = h * 60 + m;
153 if (t >= mMinimumValue && t <= maxValue())
154 {
155 if (ok)
156 *ok = true;
157 return t;
158 }
159 }
160 }
161 }
162 else if (text.length() == 4)
163 {
164 // hhmm format for time of day
165 bool okn;
166 int mins = text.toUInt(&okn);
167 if (okn)
168 {
169 int m = mins % 100;
170 int h = mins / 100;
171 if (m12Hour)
172 {
173 if (h == 0 || h > 12)
174 h = 100; // error
175 else if (h == 12)
176 h = 0; // convert 12:nn to 0:nn
177 if (mPm)
178 h += 12; // convert to PM
179 }
180 int t = h * 60 + m;
181 if (h < 24 && m < 60 && t >= mMinimumValue && t <= maxValue())
182 {
183 if (ok)
184 *ok = true;
185 return t;
186 }
187 }
188
189 }
190 if (ok)
191 *ok = false;
192 return 0;
193}
194
195/******************************************************************************
196 * Set the spin box as valid or invalid.
197 * If newly invalid, the value is displayed as asterisks.
198 * If newly valid, the value is set to the minimum value.
199 */
200void TimeSpinBox::setValid(bool valid)
201{
202 if (valid && mInvalid)
203 {
204 mInvalid = false;
205 if (value() < mMinimumValue)
206 SpinBox2::setValue(mMinimumValue);
207 setSpecialValueText(TQString());
208 SpinBox2::setMinValue(mMinimumValue);
209 }
210 else if (!valid && !mInvalid)
211 {
212 mInvalid = true;
213 SpinBox2::setMinValue(mMinimumValue - 1);
214 setSpecialValueText(TQString::fromLatin1("**:**"));
215 SpinBox2::setValue(mMinimumValue - 1);
216 }
217}
218
219/******************************************************************************
220* Set the spin box's minimum value.
221*/
223{
224 mMinimumValue = minutes;
225 SpinBox2::setMinValue(mMinimumValue - (mInvalid ? 1 : 0));
226}
227
228/******************************************************************************
229 * Set the spin box's value.
230 */
231void TimeSpinBox::setValue(int minutes)
232{
233 if (!mEnteredSetValue)
234 {
235 mEnteredSetValue = true;
236 mPm = (minutes >= 720);
237 if (minutes > maxValue())
238 setValid(false);
239 else
240 {
241 if (mInvalid)
242 {
243 mInvalid = false;
244 setSpecialValueText(TQString());
245 SpinBox2::setMinValue(mMinimumValue);
246 }
247 SpinBox2::setValue(minutes);
248 mEnteredSetValue = false;
249 }
250 }
251}
252
253/******************************************************************************
254 * Step the spin box value.
255 * If it was invalid, set it valid and set the value to the minimum.
256 */
258{
259 if (mInvalid)
260 setValid(true);
261 else
263}
264
266{
267 if (mInvalid)
268 setValid(true);
269 else
271}
272
274{
275 return value() >= mMinimumValue;
276}
277
278void TimeSpinBox::slotValueChanged(int value)
279{
280 mPm = mValidator->mPm = (value >= 720);
281}
282
283TQSize TimeSpinBox::sizeHint() const
284{
285 TQSize sz = SpinBox2::sizeHint();
286 TQFontMetrics fm(font());
287 return TQSize(sz.width() + fm.width(":"), sz.height());
288}
289
290TQSize TimeSpinBox::minimumSizeHint() const
291{
292 TQSize sz = SpinBox2::minimumSizeHint();
293 TQFontMetrics fm(font());
294 return TQSize(sz.width() + fm.width(":"), sz.height());
295}
296
297/******************************************************************************
298 * Validate the time spin box input.
299 * The entered time must either be 4 digits, or it must contain a colon, but
300 * hours may be blank.
301 */
302TQValidator::State TimeSpinBox::TimeValidator::validate(TQString& text, int& /*cursorPos*/) const
303{
304 TQString cleanText = text.stripWhiteSpace();
305 if (cleanText.isEmpty())
306 return TQValidator::Intermediate;
307 TQValidator::State state = TQValidator::Acceptable;
308 TQString hour;
309 bool ok;
310 int hr = 0;
311 int mn = 0;
312 int colon = cleanText.find(':');
313 if (colon >= 0)
314 {
315 TQString minute = cleanText.mid(colon + 1);
316 if (minute.isEmpty())
317 state = TQValidator::Intermediate;
318 else if ((mn = minute.toUInt(&ok)) >= 60 || !ok)
319 return TQValidator::Invalid;
320
321 hour = cleanText.left(colon);
322 }
323 else if (maxMinute >= 1440)
324 {
325 // The hhmm form of entry is only allowed for time-of-day, i.e. <= 2359
326 hour = cleanText;
327 state = TQValidator::Intermediate;
328 }
329 else
330 {
331 if (cleanText.length() > 4)
332 return TQValidator::Invalid;
333 if (cleanText.length() < 4)
334 state = TQValidator::Intermediate;
335 hour = cleanText.left(2);
336 TQString minute = cleanText.mid(2);
337 if (!minute.isEmpty()
338 && ((mn = minute.toUInt(&ok)) >= 60 || !ok))
339 return TQValidator::Invalid;
340 }
341
342 if (!hour.isEmpty())
343 {
344 hr = hour.toUInt(&ok);
345 if (m12Hour)
346 {
347 if (hr == 0 || hr > 12)
348 hr = 100; // error;
349 else if (hr == 12)
350 hr = 0; // convert 12:nn to 0:nn
351 if (mPm)
352 hr += 12; // convert to PM
353 }
354 if (!ok || hr > maxMinute/60)
355 return TQValidator::Invalid;
356 }
357 if (state == TQValidator::Acceptable)
358 {
359 int t = hr * 60 + mn;
360 if (t < minMinute || t > maxMinute)
361 return TQValidator::Invalid;
362 }
363 return state;
364}
Spin box with a pair of spin buttons on either side.
Definition: spinbox2.h:57
bool wrapping() const
Returns whether it is possible to step the value from the highest value to the lowest value and vice ...
Definition: spinbox2.h:116
void setAlignment(int a)
Set the text alignment of the widget.
Definition: spinbox2.h:119
TQString text() const
Returns the spin box's text, including any prefix() and suffix().
Definition: spinbox2.h:92
virtual void setValidator(const TQValidator *v)
Sets the validator to v.
Definition: spinbox2.h:128
void valueChanged(int value)
Signal which is emitted whenever the value of the spin box changes.
void setSelectOnStep(bool sel)
Sets whether the spin box value text should be selected when its value is stepped.
Definition: spinbox2.h:83
void setReverseWithLayout(bool reverse)
Sets whether the spin button pairs should be reversed for a right-to-left language.
Definition: spinbox2.cpp:109
int maxValue() const
Returns the maximum value of the spin box.
Definition: spinbox2.h:140
virtual void setSpecialValueText(const TQString &text)
Sets the special-value text which, if non-null, is displayed instead of a numeric value when the curr...
Definition: spinbox2.h:103
virtual void setMinValue(int val)
Sets the minimum value of the spin box.
Definition: spinbox2.cpp:195
virtual void stepDown()
Decrements the current value by subtracting the unshifted step increment for the right-hand spin butt...
Definition: spinbox2.h:234
virtual TQString cleanText() const
Returns the spin box's text with no prefix(), suffix() or leading or trailing whitespace.
Definition: spinbox2.h:98
virtual void setWrapping(bool on)
Sets whether it is possible to step the value from the highest value to the lowest value and vice ver...
Definition: spinbox2.cpp:125
int value() const
Returns the current value of the spin box.
Definition: spinbox2.h:148
virtual void setValue(int val)
Sets the current value to val.
Definition: spinbox2.h:222
virtual void stepUp()
Increments the current value by adding the unshifted step increment for the right-hand spin buttons.
Definition: spinbox2.h:230
void setShiftSteps(int line, int page)
Sets the shifted step increments for the two pairs of spin buttons, i.e.
Definition: spinbox2.cpp:166
virtual void stepUp()
Increments the spin box value.
static TQString shiftWhatsThis()
Returns a text describing use of the shift key as an accelerator for the spin buttons,...
Definition: timespinbox.cpp:94
virtual void setMinValue(int minutes)
Sets the maximum value which can be held in the spin box.
virtual void setValue(int minutes)
Sets the value of the spin box.
TQTime time() const
Returns the current value held in the spin box.
Definition: timespinbox.cpp:99
bool isValid() const
Returns true if the spin box holds a valid value.
virtual void stepDown()
Decrements the spin box value.
void setValid(bool)
Sets the spin box as holding a valid or invalid value.
TimeSpinBox(bool use24hour, TQWidget *parent=0, const char *name=0)
Constructor for a wrapping time spin box which can be used to enter a time of day.
Definition: timespinbox.cpp:57