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 
30 class 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  */
57 TimeSpinBox::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  */
79 TimeSpinBox::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 
99 TQTime TimeSpinBox::time() const
100 {
101  return TQTime(value() / 60, value() % 60);
102 }
103 
104 TQString 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  */
124 int 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  */
200 void 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 */
222 void TimeSpinBox::setMinValue(int minutes)
223 {
224  mMinimumValue = minutes;
225  SpinBox2::setMinValue(mMinimumValue - (mInvalid ? 1 : 0));
226 }
227 
228 /******************************************************************************
229  * Set the spin box's value.
230  */
231 void 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 
278 void TimeSpinBox::slotValueChanged(int value)
279 {
280  mPm = mValidator->mPm = (value >= 720);
281 }
282 
283 TQSize TimeSpinBox::sizeHint() const
284 {
285  TQSize sz = SpinBox2::sizeHint();
286  TQFontMetrics fm(font());
287  return TQSize(sz.width() + fm.width(":"), sz.height());
288 }
289 
290 TQSize 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  */
302 TQValidator::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