kalarm/lib

timeperiod.cpp
1 /*
2  * timeperiod.h - time period data entry widget
3  * Program: kalarm
4  * Copyright © 2003,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 <tqwidgetstack.h>
24 #include <tqwhatsthis.h>
25 
26 #include <tdelocale.h>
27 #include <kdialog.h>
28 
29 #include "combobox.h"
30 #include "spinbox.h"
31 #include "timespinbox.h"
32 #include "timeperiod.moc"
33 
34 
35 // Collect these widget labels together to ensure consistent wording and
36 // translations across different modules.
37 TQString TimePeriod::i18n_minutes() { return i18n("minutes"); }
38 TQString TimePeriod::i18n_Minutes() { return i18n("Minutes"); }
39 TQString TimePeriod::i18n_hours_mins() { return i18n("hours/minutes"); }
40 TQString TimePeriod::i18n_Hours_Mins() { return i18n("Hours/Minutes"); }
41 TQString TimePeriod::i18n_days() { return i18n("days"); }
42 TQString TimePeriod::i18n_Days() { return i18n("Days"); }
43 TQString TimePeriod::i18n_weeks() { return i18n("weeks"); }
44 TQString TimePeriod::i18n_Weeks() { return i18n("Weeks"); }
45 
46 static const int maxMinutes = 1000*60-1; // absolute maximum value for hours:minutes = 999H59M
47 
48 /*=============================================================================
49 = Class TimePeriod
50 = Contains a time unit combo box, plus a time spinbox, to select a time period.
51 =============================================================================*/
52 
53 TimePeriod::TimePeriod(bool allowHourMinute, TQWidget* parent, const char* name)
54  : TQHBox(parent, name),
55  mMaxDays(9999),
56  mNoHourMinute(!allowHourMinute),
57  mReadOnly(false)
58 {
59  setSpacing(KDialog::spacingHint());
60 
61  mSpinStack = new TQWidgetStack(this);
62  mSpinBox = new SpinBox(mSpinStack);
63  mSpinBox->setLineStep(1);
64  mSpinBox->setLineShiftStep(10);
65  mSpinBox->setRange(1, mMaxDays);
66  connect(mSpinBox, TQ_SIGNAL(valueChanged(int)), TQ_SLOT(slotDaysChanged(int)));
67  mSpinStack->addWidget(mSpinBox, 0);
68 
69  mTimeSpinBox = new TimeSpinBox(0, 99999, mSpinStack);
70  mTimeSpinBox->setRange(1, maxMinutes); // max 999H59M
71  connect(mTimeSpinBox, TQ_SIGNAL(valueChanged(int)), TQ_SLOT(slotTimeChanged(int)));
72  mSpinStack->addWidget(mTimeSpinBox, 1);
73 
74  mSpinStack->setFixedSize(mSpinBox->sizeHint().expandedTo(mTimeSpinBox->sizeHint()));
75  mHourMinuteRaised = mNoHourMinute;
76  showHourMin(!mNoHourMinute);
77 
78  mUnitsCombo = new ComboBox(false, this);
79  if (mNoHourMinute)
80  mDateOnlyOffset = 2;
81  else
82  {
83  mDateOnlyOffset = 0;
84  mUnitsCombo->insertItem(i18n_minutes());
85  mUnitsCombo->insertItem(i18n_hours_mins());
86  }
87  mUnitsCombo->insertItem(i18n_days());
88  mUnitsCombo->insertItem(i18n_weeks());
89  mMaxUnitShown = WEEKS;
90  mUnitsCombo->setFixedSize(mUnitsCombo->sizeHint());
91  connect(mUnitsCombo, TQ_SIGNAL(activated(int)), TQ_SLOT(slotUnitsSelected(int)));
92 
93  setFocusProxy(mUnitsCombo);
94  setTabOrder(mUnitsCombo, mSpinStack);
95 }
96 
98 {
99  if (ro != mReadOnly)
100  {
101  mReadOnly = ro;
102  mSpinBox->setReadOnly(ro);
103  mTimeSpinBox->setReadOnly(ro);
104  mUnitsCombo->setReadOnly(ro);
105  }
106 }
107 
108 /******************************************************************************
109 * Set whether the editor text is to be selected whenever spin buttons are
110 * clicked. Default is to select them.
111 */
113 {
114  mSpinBox->setSelectOnStep(sel);
115  mTimeSpinBox->setSelectOnStep(sel);
116 }
117 
118 /******************************************************************************
119 * Set the input focus on the count field.
120 */
122 {
123  mSpinStack->setFocus();
124 }
125 
126 /******************************************************************************
127 * Set the maximum values for the hours:minutes and days/weeks spinboxes.
128 * If 'hourmin' = 0, the hours:minutes maximum is left unchanged.
129 */
130 void TimePeriod::setMaximum(int hourmin, int days)
131 {
132  int oldmins = minutes();
133  if (hourmin > 0)
134  {
135  if (hourmin > maxMinutes)
136  hourmin = maxMinutes;
137  mTimeSpinBox->setRange(1, hourmin);
138  }
139  mMaxDays = (days >= 0) ? days : 0;
140  adjustDayWeekShown();
141  setUnitRange();
142  int mins = minutes();
143  if (mins != oldmins)
144  emit valueChanged(mins);
145 }
146 
147 /******************************************************************************
148  * Get the specified number of minutes.
149  * Reply = 0 if error.
150  */
152 {
153  int factor = 0;
154  switch (mUnitsCombo->currentItem() + mDateOnlyOffset)
155  {
156  case HOURS_MINUTES:
157  return mTimeSpinBox->value();
158  case MINUTES: factor = 1; break;
159  case DAYS: factor = 24*60; break;
160  case WEEKS: factor = 7*24*60; break;
161  }
162  return mSpinBox->value() * factor;
163 }
164 
165 /******************************************************************************
166 * Initialise the controls with a specified time period.
167 * The time unit combo-box is initialised to 'defaultUnits', but if 'dateOnly'
168 * is true, it will never be initialised to minutes or hours/minutes.
169 */
170 void TimePeriod::setMinutes(int mins, bool dateOnly, TimePeriod::Units defaultUnits)
171 {
172  int oldmins = minutes();
173  if (!dateOnly && mNoHourMinute)
174  dateOnly = true;
175  int item;
176  if (mins)
177  {
178  int count = mins;
179  if (mins % (24*60))
180  item = (defaultUnits == MINUTES && count <= mSpinBox->maxValue()) ? MINUTES : HOURS_MINUTES;
181  else if (mins % (7*24*60))
182  {
183  item = DAYS;
184  count = mins / (24*60);
185  }
186  else
187  {
188  item = WEEKS;
189  count = mins / (7*24*60);
190  }
191  if (item < mDateOnlyOffset)
192  item = mDateOnlyOffset;
193  else if (item > mMaxUnitShown)
194  item = mMaxUnitShown;
195  mUnitsCombo->setCurrentItem(item - mDateOnlyOffset);
196  if (item == HOURS_MINUTES)
197  mTimeSpinBox->setValue(count);
198  else
199  mSpinBox->setValue(count);
200  item = setDateOnly(mins, dateOnly, false);
201  }
202  else
203  {
204  item = defaultUnits;
205  if (item < mDateOnlyOffset)
206  item = mDateOnlyOffset;
207  else if (item > mMaxUnitShown)
208  item = mMaxUnitShown;
209  mUnitsCombo->setCurrentItem(item - mDateOnlyOffset);
210  if ((dateOnly && !mDateOnlyOffset) || (!dateOnly && mDateOnlyOffset))
211  item = setDateOnly(mins, dateOnly, false);
212  }
213  showHourMin(item == HOURS_MINUTES && !mNoHourMinute);
214 
215  int newmins = minutes();
216  if (newmins != oldmins)
217  emit valueChanged(newmins);
218 }
219 
220 /******************************************************************************
221 * Enable/disable hours/minutes units (if hours/minutes were permitted in the
222 * constructor).
223 */
224 TimePeriod::Units TimePeriod::setDateOnly(int mins, bool dateOnly, bool signal)
225 {
226  int oldmins = 0;
227  if (signal)
228  oldmins = minutes();
229  int index = mUnitsCombo->currentItem();
230  Units units = static_cast<Units>(index + mDateOnlyOffset);
231  if (!mNoHourMinute)
232  {
233  if (!dateOnly && mDateOnlyOffset)
234  {
235  // Change from date-only to allow hours/minutes
236  mUnitsCombo->insertItem(i18n_minutes(), 0);
237  mUnitsCombo->insertItem(i18n_hours_mins(), 1);
238  mDateOnlyOffset = 0;
239  adjustDayWeekShown();
240  mUnitsCombo->setCurrentItem(index += 2);
241  }
242  else if (dateOnly && !mDateOnlyOffset)
243  {
244  // Change from allowing hours/minutes to date-only
245  mUnitsCombo->removeItem(0);
246  mUnitsCombo->removeItem(0);
247  mDateOnlyOffset = 2;
248  if (index > 2)
249  index -= 2;
250  else
251  index = 0;
252  adjustDayWeekShown();
253  mUnitsCombo->setCurrentItem(index);
254  if (units == HOURS_MINUTES || units == MINUTES)
255  {
256  // Set units to days and round up the warning period
257  units = DAYS;
258  mUnitsCombo->setCurrentItem(DAYS - mDateOnlyOffset);
259  mSpinBox->setValue((mins + 1439) / 1440);
260  }
261  showHourMin(false);
262  }
263  }
264 
265  if (signal)
266  {
267  int newmins = minutes();
268  if (newmins != oldmins)
269  emit valueChanged(newmins);
270  }
271  return units;
272 }
273 
274 /******************************************************************************
275 * Adjust the days/weeks units shown to suit the maximum days limit.
276 */
277 void TimePeriod::adjustDayWeekShown()
278 {
279  Units newMaxUnitShown = (mMaxDays >= 7) ? WEEKS : (mMaxDays || mDateOnlyOffset) ? DAYS : HOURS_MINUTES;
280  if (newMaxUnitShown > mMaxUnitShown)
281  {
282  if (mMaxUnitShown < DAYS)
283  mUnitsCombo->insertItem(i18n_days());
284  if (newMaxUnitShown == WEEKS)
285  mUnitsCombo->insertItem(i18n_weeks());
286  }
287  else if (newMaxUnitShown < mMaxUnitShown)
288  {
289  if (mMaxUnitShown == WEEKS)
290  mUnitsCombo->removeItem(WEEKS - mDateOnlyOffset);
291  if (newMaxUnitShown < DAYS)
292  mUnitsCombo->removeItem(DAYS - mDateOnlyOffset);
293  }
294  mMaxUnitShown = newMaxUnitShown;
295 }
296 
297 /******************************************************************************
298 * Set the maximum value which may be entered into the day/week count field,
299 * depending on the current unit selection.
300 */
301 void TimePeriod::setUnitRange()
302 {
303  int maxval;
304  switch (static_cast<Units>(mUnitsCombo->currentItem() + mDateOnlyOffset))
305  {
306  case WEEKS:
307  maxval = mMaxDays / 7;
308  if (maxval)
309  break;
310  mUnitsCombo->setCurrentItem(DAYS - mDateOnlyOffset);
311  // fall through to DAYS
312  case DAYS:
313  maxval = mMaxDays ? mMaxDays : 1;
314  break;
315  case MINUTES:
316  maxval = mTimeSpinBox->maxValue();
317  break;
318  case HOURS_MINUTES:
319  default:
320  return;
321  }
322  mSpinBox->setRange(1, maxval);
323 }
324 
325 /******************************************************************************
326 * Called when a new item is made current in the time units combo box.
327 */
328 void TimePeriod::slotUnitsSelected(int index)
329 {
330  setUnitRange();
331  showHourMin(index + mDateOnlyOffset == HOURS_MINUTES);
332  emit valueChanged(minutes());
333 }
334 
335 /******************************************************************************
336 * Called when the value of the days/weeks spin box changes.
337 */
338 void TimePeriod::slotDaysChanged(int)
339 {
340  if (!mHourMinuteRaised)
341  emit valueChanged(minutes());
342 }
343 
344 /******************************************************************************
345 * Called when the value of the time spin box changes.
346 */
347 void TimePeriod::slotTimeChanged(int value)
348 {
349  if (mHourMinuteRaised)
350  emit valueChanged(value);
351 }
352 
353 /******************************************************************************
354  * Set the currently displayed count widget.
355  */
356 void TimePeriod::showHourMin(bool hourMinute)
357 {
358  if (hourMinute != mHourMinuteRaised)
359  {
360  mHourMinuteRaised = hourMinute;
361  if (hourMinute)
362  {
363  mSpinStack->raiseWidget(mTimeSpinBox);
364  mSpinStack->setFocusProxy(mTimeSpinBox);
365  }
366  else
367  {
368  mSpinStack->raiseWidget(mSpinBox);
369  mSpinStack->setFocusProxy(mSpinBox);
370  }
371  }
372 }
373 
374 /******************************************************************************
375  * Set separate WhatsThis texts for the count spinboxes and the units combobox.
376  * If the hours:minutes text is omitted, both spinboxes are set to the same
377  * WhatsThis text.
378  */
379 void TimePeriod::setWhatsThis(const TQString& units, const TQString& dayWeek, const TQString& hourMin)
380 {
381  TQWhatsThis::add(mUnitsCombo, units);
382  TQWhatsThis::add(mSpinBox, dayWeek);
383  TQWhatsThis::add(mTimeSpinBox, (hourMin.isNull() ? dayWeek : hourMin));
384 }
A TQComboBox with read-only option.
Definition: combobox.h:38
virtual void setReadOnly(bool readOnly)
Sets whether the combo box is read-only for the user.
Definition: combobox.cpp:35
void setRange(int minValue, int maxValue)
Sets the minimum and maximum values of the spin box.
Definition: spinbox2.h:146
void setSelectOnStep(bool sel)
Sets whether the spin box value text should be selected when its value is stepped.
Definition: spinbox2.h:83
int maxValue() const
Returns the maximum value of the spin box.
Definition: spinbox2.h:140
virtual void setReadOnly(bool readOnly)
Sets whether the spin box can be changed by the user.
Definition: spinbox2.cpp:99
int value() const
Returns the current value of the spin box.
Definition: spinbox2.h:148
Spin box with accelerated shift key stepping and read-only option.
Definition: spinbox.h:43
void setLineShiftStep(int step)
Sets the shifted step increment, i.e.
Definition: spinbox.cpp:109
int maxValue() const
Returns the maximum value of the spin box.
Definition: spinbox.h:75
void setSelectOnStep(bool sel)
Sets whether the spin box value text should be selected when its value is stepped.
Definition: spinbox.h:69
virtual void setReadOnly(bool readOnly)
Sets whether the spin box can be changed by the user.
Definition: spinbox.cpp:72
void setRange(int minValue, int maxValue)
Sets the minimum and maximum values of the spin box.
Definition: spinbox.h:81
void setLineStep(int step)
Sets the unshifted step increment, i.e.
Definition: spinbox.cpp:102
void setMinutes(int minutes, bool dateOnly, Units defaultUnits)
Initialises the time period value.
Definition: timeperiod.cpp:170
void setWhatsThis(const TQString &units, const TQString &dayWeek, const TQString &hourMin=TQString())
Sets separate WhatsThis texts for the count spin boxes and the units combo box.
Definition: timeperiod.cpp:379
TimePeriod(bool allowMinute, TQWidget *parent, const char *name=0)
Constructor.
Definition: timeperiod.cpp:53
void setSelectOnStep(bool select)
Sets whether the editor text is to be selected whenever spin buttons are clicked.
Definition: timeperiod.cpp:112
void valueChanged(int minutes)
This signal is emitted whenever the value held in the widget changes.
virtual void setReadOnly(bool readOnly)
Sets whether the widget is read-only for the user.
Definition: timeperiod.cpp:97
Units
Units for the time period.
Definition: timeperiod.h:61
void setMaximum(int hourmin, int days)
Sets the maximum values for the minutes and hours/minutes, and days/weeks spin boxes.
Definition: timeperiod.cpp:130
int minutes() const
Gets the entered time period expressed in minutes.
Definition: timeperiod.cpp:151
void setDateOnly(bool dateOnly)
Enables or disables minutes and hours/minutes units in the combo box.
Definition: timeperiod.h:92
void setFocusOnCount()
Sets the input focus to the count field.
Definition: timeperiod.cpp:121
Hours/minutes time entry widget.
Definition: timespinbox.h:46
virtual void setValue(int minutes)
Sets the value of the spin box.