kalarm/lib

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 <qwidgetstack.h>
00024 #include <qwhatsthis.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 QString TimePeriod::i18n_minutes()      { return i18n("minutes"); }
00038 QString TimePeriod::i18n_Minutes()      { return i18n("Minutes"); }
00039 QString TimePeriod::i18n_hours_mins()   { return i18n("hours/minutes"); }
00040 QString TimePeriod::i18n_Hours_Mins()   { return i18n("Hours/Minutes"); }
00041 QString TimePeriod::i18n_days()         { return i18n("days"); }
00042 QString TimePeriod::i18n_Days()         { return i18n("Days"); }
00043 QString TimePeriod::i18n_weeks()        { return i18n("weeks"); }
00044 QString 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, QWidget* parent, const char* name)
00054     : QHBox(parent, name),
00055       mMaxDays(9999),
00056       mNoHourMinute(!allowHourMinute),
00057       mReadOnly(false)
00058 {
00059     setSpacing(KDialog::spacingHint());
00060 
00061     mSpinStack = new QWidgetStack(this);
00062     mSpinBox = new SpinBox(mSpinStack);
00063     mSpinBox->setLineStep(1);
00064     mSpinBox->setLineShiftStep(10);
00065     mSpinBox->setRange(1, mMaxDays);
00066     connect(mSpinBox, SIGNAL(valueChanged(int)), 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, SIGNAL(valueChanged(int)), 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, SIGNAL(activated(int)), 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 QString& units, const QString& dayWeek, const QString& hourMin)
00380 {
00381     QWhatsThis::add(mUnitsCombo, units);
00382     QWhatsThis::add(mSpinBox, dayWeek);
00383     QWhatsThis::add(mTimeSpinBox, (hourMin.isNull() ? dayWeek : hourMin));
00384 }
KDE Home | KDE Accessibility Home | Description of Access Keys