timeperiod.cpp
00001 /* 00002 * timeperiod.h - time period data entry widget 00003 * Program: kalarm 00004 * Copyright © 2003,2004,2007,2008 by David Jarvie <djarvie@kde.org> 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License along 00017 * with this program; if not, write to the Free Software Foundation, Inc., 00018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "kalarm.h" 00022 00023 #include <tqwidgetstack.h> 00024 #include <tqwhatsthis.h> 00025 00026 #include <klocale.h> 00027 #include <kdialog.h> 00028 00029 #include "combobox.h" 00030 #include "spinbox.h" 00031 #include "timespinbox.h" 00032 #include "timeperiod.moc" 00033 00034 00035 // Collect these widget labels together to ensure consistent wording and 00036 // translations across different modules. 00037 TQString TimePeriod::i18n_minutes() { return i18n("minutes"); } 00038 TQString TimePeriod::i18n_Minutes() { return i18n("Minutes"); } 00039 TQString TimePeriod::i18n_hours_mins() { return i18n("hours/minutes"); } 00040 TQString TimePeriod::i18n_Hours_Mins() { return i18n("Hours/Minutes"); } 00041 TQString TimePeriod::i18n_days() { return i18n("days"); } 00042 TQString TimePeriod::i18n_Days() { return i18n("Days"); } 00043 TQString TimePeriod::i18n_weeks() { return i18n("weeks"); } 00044 TQString TimePeriod::i18n_Weeks() { return i18n("Weeks"); } 00045 00046 static const int maxMinutes = 1000*60-1; // absolute maximum value for hours:minutes = 999H59M 00047 00048 /*============================================================================= 00049 = Class TimePeriod 00050 = Contains a time unit combo box, plus a time spinbox, to select a time period. 00051 =============================================================================*/ 00052 00053 TimePeriod::TimePeriod(bool allowHourMinute, TQWidget* parent, const char* name) 00054 : TQHBox(parent, name), 00055 mMaxDays(9999), 00056 mNoHourMinute(!allowHourMinute), 00057 mReadOnly(false) 00058 { 00059 setSpacing(KDialog::spacingHint()); 00060 00061 mSpinStack = new TQWidgetStack(this); 00062 mSpinBox = new SpinBox(mSpinStack); 00063 mSpinBox->setLineStep(1); 00064 mSpinBox->setLineShiftStep(10); 00065 mSpinBox->setRange(1, mMaxDays); 00066 connect(mSpinBox, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotDaysChanged(int))); 00067 mSpinStack->addWidget(mSpinBox, 0); 00068 00069 mTimeSpinBox = new TimeSpinBox(0, 99999, mSpinStack); 00070 mTimeSpinBox->setRange(1, maxMinutes); // max 999H59M 00071 connect(mTimeSpinBox, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotTimeChanged(int))); 00072 mSpinStack->addWidget(mTimeSpinBox, 1); 00073 00074 mSpinStack->setFixedSize(mSpinBox->sizeHint().expandedTo(mTimeSpinBox->sizeHint())); 00075 mHourMinuteRaised = mNoHourMinute; 00076 showHourMin(!mNoHourMinute); 00077 00078 mUnitsCombo = new ComboBox(false, this); 00079 if (mNoHourMinute) 00080 mDateOnlyOffset = 2; 00081 else 00082 { 00083 mDateOnlyOffset = 0; 00084 mUnitsCombo->insertItem(i18n_minutes()); 00085 mUnitsCombo->insertItem(i18n_hours_mins()); 00086 } 00087 mUnitsCombo->insertItem(i18n_days()); 00088 mUnitsCombo->insertItem(i18n_weeks()); 00089 mMaxUnitShown = WEEKS; 00090 mUnitsCombo->setFixedSize(mUnitsCombo->sizeHint()); 00091 connect(mUnitsCombo, TQT_SIGNAL(activated(int)), TQT_SLOT(slotUnitsSelected(int))); 00092 00093 setFocusProxy(mUnitsCombo); 00094 setTabOrder(mUnitsCombo, mSpinStack); 00095 } 00096 00097 void TimePeriod::setReadOnly(bool ro) 00098 { 00099 if (ro != mReadOnly) 00100 { 00101 mReadOnly = ro; 00102 mSpinBox->setReadOnly(ro); 00103 mTimeSpinBox->setReadOnly(ro); 00104 mUnitsCombo->setReadOnly(ro); 00105 } 00106 } 00107 00108 /****************************************************************************** 00109 * Set whether the editor text is to be selected whenever spin buttons are 00110 * clicked. Default is to select them. 00111 */ 00112 void TimePeriod::setSelectOnStep(bool sel) 00113 { 00114 mSpinBox->setSelectOnStep(sel); 00115 mTimeSpinBox->setSelectOnStep(sel); 00116 } 00117 00118 /****************************************************************************** 00119 * Set the input focus on the count field. 00120 */ 00121 void TimePeriod::setFocusOnCount() 00122 { 00123 mSpinStack->setFocus(); 00124 } 00125 00126 /****************************************************************************** 00127 * Set the maximum values for the hours:minutes and days/weeks spinboxes. 00128 * If 'hourmin' = 0, the hours:minutes maximum is left unchanged. 00129 */ 00130 void TimePeriod::setMaximum(int hourmin, int days) 00131 { 00132 int oldmins = minutes(); 00133 if (hourmin > 0) 00134 { 00135 if (hourmin > maxMinutes) 00136 hourmin = maxMinutes; 00137 mTimeSpinBox->setRange(1, hourmin); 00138 } 00139 mMaxDays = (days >= 0) ? days : 0; 00140 adjustDayWeekShown(); 00141 setUnitRange(); 00142 int mins = minutes(); 00143 if (mins != oldmins) 00144 emit valueChanged(mins); 00145 } 00146 00147 /****************************************************************************** 00148 * Get the specified number of minutes. 00149 * Reply = 0 if error. 00150 */ 00151 int TimePeriod::minutes() const 00152 { 00153 int factor = 0; 00154 switch (mUnitsCombo->currentItem() + mDateOnlyOffset) 00155 { 00156 case HOURS_MINUTES: 00157 return mTimeSpinBox->value(); 00158 case MINUTES: factor = 1; break; 00159 case DAYS: factor = 24*60; break; 00160 case WEEKS: factor = 7*24*60; break; 00161 } 00162 return mSpinBox->value() * factor; 00163 } 00164 00165 /****************************************************************************** 00166 * Initialise the controls with a specified time period. 00167 * The time unit combo-box is initialised to 'defaultUnits', but if 'dateOnly' 00168 * is true, it will never be initialised to minutes or hours/minutes. 00169 */ 00170 void TimePeriod::setMinutes(int mins, bool dateOnly, TimePeriod::Units defaultUnits) 00171 { 00172 int oldmins = minutes(); 00173 if (!dateOnly && mNoHourMinute) 00174 dateOnly = true; 00175 int item; 00176 if (mins) 00177 { 00178 int count = mins; 00179 if (mins % (24*60)) 00180 item = (defaultUnits == MINUTES && count <= mSpinBox->maxValue()) ? MINUTES : HOURS_MINUTES; 00181 else if (mins % (7*24*60)) 00182 { 00183 item = DAYS; 00184 count = mins / (24*60); 00185 } 00186 else 00187 { 00188 item = WEEKS; 00189 count = mins / (7*24*60); 00190 } 00191 if (item < mDateOnlyOffset) 00192 item = mDateOnlyOffset; 00193 else if (item > mMaxUnitShown) 00194 item = mMaxUnitShown; 00195 mUnitsCombo->setCurrentItem(item - mDateOnlyOffset); 00196 if (item == HOURS_MINUTES) 00197 mTimeSpinBox->setValue(count); 00198 else 00199 mSpinBox->setValue(count); 00200 item = setDateOnly(mins, dateOnly, false); 00201 } 00202 else 00203 { 00204 item = defaultUnits; 00205 if (item < mDateOnlyOffset) 00206 item = mDateOnlyOffset; 00207 else if (item > mMaxUnitShown) 00208 item = mMaxUnitShown; 00209 mUnitsCombo->setCurrentItem(item - mDateOnlyOffset); 00210 if (dateOnly && !mDateOnlyOffset || !dateOnly && mDateOnlyOffset) 00211 item = setDateOnly(mins, dateOnly, false); 00212 } 00213 showHourMin(item == HOURS_MINUTES && !mNoHourMinute); 00214 00215 int newmins = minutes(); 00216 if (newmins != oldmins) 00217 emit valueChanged(newmins); 00218 } 00219 00220 /****************************************************************************** 00221 * Enable/disable hours/minutes units (if hours/minutes were permitted in the 00222 * constructor). 00223 */ 00224 TimePeriod::Units TimePeriod::setDateOnly(int mins, bool dateOnly, bool signal) 00225 { 00226 int oldmins = 0; 00227 if (signal) 00228 oldmins = minutes(); 00229 int index = mUnitsCombo->currentItem(); 00230 Units units = static_cast<Units>(index + mDateOnlyOffset); 00231 if (!mNoHourMinute) 00232 { 00233 if (!dateOnly && mDateOnlyOffset) 00234 { 00235 // Change from date-only to allow hours/minutes 00236 mUnitsCombo->insertItem(i18n_minutes(), 0); 00237 mUnitsCombo->insertItem(i18n_hours_mins(), 1); 00238 mDateOnlyOffset = 0; 00239 adjustDayWeekShown(); 00240 mUnitsCombo->setCurrentItem(index += 2); 00241 } 00242 else if (dateOnly && !mDateOnlyOffset) 00243 { 00244 // Change from allowing hours/minutes to date-only 00245 mUnitsCombo->removeItem(0); 00246 mUnitsCombo->removeItem(0); 00247 mDateOnlyOffset = 2; 00248 if (index > 2) 00249 index -= 2; 00250 else 00251 index = 0; 00252 adjustDayWeekShown(); 00253 mUnitsCombo->setCurrentItem(index); 00254 if (units == HOURS_MINUTES || units == MINUTES) 00255 { 00256 // Set units to days and round up the warning period 00257 units = DAYS; 00258 mUnitsCombo->setCurrentItem(DAYS - mDateOnlyOffset); 00259 mSpinBox->setValue((mins + 1439) / 1440); 00260 } 00261 showHourMin(false); 00262 } 00263 } 00264 00265 if (signal) 00266 { 00267 int newmins = minutes(); 00268 if (newmins != oldmins) 00269 emit valueChanged(newmins); 00270 } 00271 return units; 00272 } 00273 00274 /****************************************************************************** 00275 * Adjust the days/weeks units shown to suit the maximum days limit. 00276 */ 00277 void TimePeriod::adjustDayWeekShown() 00278 { 00279 Units newMaxUnitShown = (mMaxDays >= 7) ? WEEKS : (mMaxDays || mDateOnlyOffset) ? DAYS : HOURS_MINUTES; 00280 if (newMaxUnitShown > mMaxUnitShown) 00281 { 00282 if (mMaxUnitShown < DAYS) 00283 mUnitsCombo->insertItem(i18n_days()); 00284 if (newMaxUnitShown == WEEKS) 00285 mUnitsCombo->insertItem(i18n_weeks()); 00286 } 00287 else if (newMaxUnitShown < mMaxUnitShown) 00288 { 00289 if (mMaxUnitShown == WEEKS) 00290 mUnitsCombo->removeItem(WEEKS - mDateOnlyOffset); 00291 if (newMaxUnitShown < DAYS) 00292 mUnitsCombo->removeItem(DAYS - mDateOnlyOffset); 00293 } 00294 mMaxUnitShown = newMaxUnitShown; 00295 } 00296 00297 /****************************************************************************** 00298 * Set the maximum value which may be entered into the day/week count field, 00299 * depending on the current unit selection. 00300 */ 00301 void TimePeriod::setUnitRange() 00302 { 00303 int maxval; 00304 switch (static_cast<Units>(mUnitsCombo->currentItem() + mDateOnlyOffset)) 00305 { 00306 case WEEKS: 00307 maxval = mMaxDays / 7; 00308 if (maxval) 00309 break; 00310 mUnitsCombo->setCurrentItem(DAYS - mDateOnlyOffset); 00311 // fall through to DAYS 00312 case DAYS: 00313 maxval = mMaxDays ? mMaxDays : 1; 00314 break; 00315 case MINUTES: 00316 maxval = mTimeSpinBox->maxValue(); 00317 break; 00318 case HOURS_MINUTES: 00319 default: 00320 return; 00321 } 00322 mSpinBox->setRange(1, maxval); 00323 } 00324 00325 /****************************************************************************** 00326 * Called when a new item is made current in the time units combo box. 00327 */ 00328 void TimePeriod::slotUnitsSelected(int index) 00329 { 00330 setUnitRange(); 00331 showHourMin(index + mDateOnlyOffset == HOURS_MINUTES); 00332 emit valueChanged(minutes()); 00333 } 00334 00335 /****************************************************************************** 00336 * Called when the value of the days/weeks spin box changes. 00337 */ 00338 void TimePeriod::slotDaysChanged(int) 00339 { 00340 if (!mHourMinuteRaised) 00341 emit valueChanged(minutes()); 00342 } 00343 00344 /****************************************************************************** 00345 * Called when the value of the time spin box changes. 00346 */ 00347 void TimePeriod::slotTimeChanged(int value) 00348 { 00349 if (mHourMinuteRaised) 00350 emit valueChanged(value); 00351 } 00352 00353 /****************************************************************************** 00354 * Set the currently displayed count widget. 00355 */ 00356 void TimePeriod::showHourMin(bool hourMinute) 00357 { 00358 if (hourMinute != mHourMinuteRaised) 00359 { 00360 mHourMinuteRaised = hourMinute; 00361 if (hourMinute) 00362 { 00363 mSpinStack->raiseWidget(mTimeSpinBox); 00364 mSpinStack->setFocusProxy(mTimeSpinBox); 00365 } 00366 else 00367 { 00368 mSpinStack->raiseWidget(mSpinBox); 00369 mSpinStack->setFocusProxy(mSpinBox); 00370 } 00371 } 00372 } 00373 00374 /****************************************************************************** 00375 * Set separate WhatsThis texts for the count spinboxes and the units combobox. 00376 * If the hours:minutes text is omitted, both spinboxes are set to the same 00377 * WhatsThis text. 00378 */ 00379 void TimePeriod::setWhatsThis(const TQString& units, const TQString& dayWeek, const TQString& hourMin) 00380 { 00381 TQWhatsThis::add(mUnitsCombo, units); 00382 TQWhatsThis::add(mSpinBox, dayWeek); 00383 TQWhatsThis::add(mTimeSpinBox, (hourMin.isNull() ? dayWeek : hourMin)); 00384 }