/* * timeperiod.h - time period data entry widget * Program: kalarm * Copyright © 2003,2004,2007,2008 by David Jarvie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kalarm.h" #include #include #include #include #include "combobox.h" #include "spinbox.h" #include "timespinbox.h" #include "timeperiod.moc" // Collect these widget labels together to ensure consistent wording and // translations across different modules. TQString TimePeriod::i18n_minutes() { return i18n("minutes"); } TQString TimePeriod::i18n_Minutes() { return i18n("Minutes"); } TQString TimePeriod::i18n_hours_mins() { return i18n("hours/minutes"); } TQString TimePeriod::i18n_Hours_Mins() { return i18n("Hours/Minutes"); } TQString TimePeriod::i18n_days() { return i18n("days"); } TQString TimePeriod::i18n_Days() { return i18n("Days"); } TQString TimePeriod::i18n_weeks() { return i18n("weeks"); } TQString TimePeriod::i18n_Weeks() { return i18n("Weeks"); } static const int maxMinutes = 1000*60-1; // absolute maximum value for hours:minutes = 999H59M /*============================================================================= = Class TimePeriod = Contains a time unit combo box, plus a time spinbox, to select a time period. =============================================================================*/ TimePeriod::TimePeriod(bool allowHourMinute, TQWidget* parent, const char* name) : TQHBox(parent, name), mMaxDays(9999), mNoHourMinute(!allowHourMinute), mReadOnly(false) { setSpacing(KDialog::spacingHint()); mSpinStack = new TQWidgetStack(this); mSpinBox = new SpinBox(mSpinStack); mSpinBox->setLineStep(1); mSpinBox->setLineShiftStep(10); mSpinBox->setRange(1, mMaxDays); connect(mSpinBox, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotDaysChanged(int))); mSpinStack->addWidget(mSpinBox, 0); mTimeSpinBox = new TimeSpinBox(0, 99999, mSpinStack); mTimeSpinBox->setRange(1, maxMinutes); // max 999H59M connect(mTimeSpinBox, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotTimeChanged(int))); mSpinStack->addWidget(mTimeSpinBox, 1); mSpinStack->setFixedSize(mSpinBox->sizeHint().expandedTo(mTimeSpinBox->sizeHint())); mHourMinuteRaised = mNoHourMinute; showHourMin(!mNoHourMinute); mUnitsCombo = new ComboBox(false, this); if (mNoHourMinute) mDateOnlyOffset = 2; else { mDateOnlyOffset = 0; mUnitsCombo->insertItem(i18n_minutes()); mUnitsCombo->insertItem(i18n_hours_mins()); } mUnitsCombo->insertItem(i18n_days()); mUnitsCombo->insertItem(i18n_weeks()); mMaxUnitShown = WEEKS; mUnitsCombo->setFixedSize(mUnitsCombo->sizeHint()); connect(mUnitsCombo, TQT_SIGNAL(activated(int)), TQT_SLOT(slotUnitsSelected(int))); setFocusProxy(mUnitsCombo); setTabOrder(mUnitsCombo, mSpinStack); } void TimePeriod::setReadOnly(bool ro) { if (ro != mReadOnly) { mReadOnly = ro; mSpinBox->setReadOnly(ro); mTimeSpinBox->setReadOnly(ro); mUnitsCombo->setReadOnly(ro); } } /****************************************************************************** * Set whether the editor text is to be selected whenever spin buttons are * clicked. Default is to select them. */ void TimePeriod::setSelectOnStep(bool sel) { mSpinBox->setSelectOnStep(sel); mTimeSpinBox->setSelectOnStep(sel); } /****************************************************************************** * Set the input focus on the count field. */ void TimePeriod::setFocusOnCount() { mSpinStack->setFocus(); } /****************************************************************************** * Set the maximum values for the hours:minutes and days/weeks spinboxes. * If 'hourmin' = 0, the hours:minutes maximum is left unchanged. */ void TimePeriod::setMaximum(int hourmin, int days) { int oldmins = minutes(); if (hourmin > 0) { if (hourmin > maxMinutes) hourmin = maxMinutes; mTimeSpinBox->setRange(1, hourmin); } mMaxDays = (days >= 0) ? days : 0; adjustDayWeekShown(); setUnitRange(); int mins = minutes(); if (mins != oldmins) emit valueChanged(mins); } /****************************************************************************** * Get the specified number of minutes. * Reply = 0 if error. */ int TimePeriod::minutes() const { int factor = 0; switch (mUnitsCombo->currentItem() + mDateOnlyOffset) { case HOURS_MINUTES: return mTimeSpinBox->value(); case MINUTES: factor = 1; break; case DAYS: factor = 24*60; break; case WEEKS: factor = 7*24*60; break; } return mSpinBox->value() * factor; } /****************************************************************************** * Initialise the controls with a specified time period. * The time unit combo-box is initialised to 'defaultUnits', but if 'dateOnly' * is true, it will never be initialised to minutes or hours/minutes. */ void TimePeriod::setMinutes(int mins, bool dateOnly, TimePeriod::Units defaultUnits) { int oldmins = minutes(); if (!dateOnly && mNoHourMinute) dateOnly = true; int item; if (mins) { int count = mins; if (mins % (24*60)) item = (defaultUnits == MINUTES && count <= mSpinBox->maxValue()) ? MINUTES : HOURS_MINUTES; else if (mins % (7*24*60)) { item = DAYS; count = mins / (24*60); } else { item = WEEKS; count = mins / (7*24*60); } if (item < mDateOnlyOffset) item = mDateOnlyOffset; else if (item > mMaxUnitShown) item = mMaxUnitShown; mUnitsCombo->setCurrentItem(item - mDateOnlyOffset); if (item == HOURS_MINUTES) mTimeSpinBox->setValue(count); else mSpinBox->setValue(count); item = setDateOnly(mins, dateOnly, false); } else { item = defaultUnits; if (item < mDateOnlyOffset) item = mDateOnlyOffset; else if (item > mMaxUnitShown) item = mMaxUnitShown; mUnitsCombo->setCurrentItem(item - mDateOnlyOffset); if ((dateOnly && !mDateOnlyOffset) || (!dateOnly && mDateOnlyOffset)) item = setDateOnly(mins, dateOnly, false); } showHourMin(item == HOURS_MINUTES && !mNoHourMinute); int newmins = minutes(); if (newmins != oldmins) emit valueChanged(newmins); } /****************************************************************************** * Enable/disable hours/minutes units (if hours/minutes were permitted in the * constructor). */ TimePeriod::Units TimePeriod::setDateOnly(int mins, bool dateOnly, bool signal) { int oldmins = 0; if (signal) oldmins = minutes(); int index = mUnitsCombo->currentItem(); Units units = static_cast(index + mDateOnlyOffset); if (!mNoHourMinute) { if (!dateOnly && mDateOnlyOffset) { // Change from date-only to allow hours/minutes mUnitsCombo->insertItem(i18n_minutes(), 0); mUnitsCombo->insertItem(i18n_hours_mins(), 1); mDateOnlyOffset = 0; adjustDayWeekShown(); mUnitsCombo->setCurrentItem(index += 2); } else if (dateOnly && !mDateOnlyOffset) { // Change from allowing hours/minutes to date-only mUnitsCombo->removeItem(0); mUnitsCombo->removeItem(0); mDateOnlyOffset = 2; if (index > 2) index -= 2; else index = 0; adjustDayWeekShown(); mUnitsCombo->setCurrentItem(index); if (units == HOURS_MINUTES || units == MINUTES) { // Set units to days and round up the warning period units = DAYS; mUnitsCombo->setCurrentItem(DAYS - mDateOnlyOffset); mSpinBox->setValue((mins + 1439) / 1440); } showHourMin(false); } } if (signal) { int newmins = minutes(); if (newmins != oldmins) emit valueChanged(newmins); } return units; } /****************************************************************************** * Adjust the days/weeks units shown to suit the maximum days limit. */ void TimePeriod::adjustDayWeekShown() { Units newMaxUnitShown = (mMaxDays >= 7) ? WEEKS : (mMaxDays || mDateOnlyOffset) ? DAYS : HOURS_MINUTES; if (newMaxUnitShown > mMaxUnitShown) { if (mMaxUnitShown < DAYS) mUnitsCombo->insertItem(i18n_days()); if (newMaxUnitShown == WEEKS) mUnitsCombo->insertItem(i18n_weeks()); } else if (newMaxUnitShown < mMaxUnitShown) { if (mMaxUnitShown == WEEKS) mUnitsCombo->removeItem(WEEKS - mDateOnlyOffset); if (newMaxUnitShown < DAYS) mUnitsCombo->removeItem(DAYS - mDateOnlyOffset); } mMaxUnitShown = newMaxUnitShown; } /****************************************************************************** * Set the maximum value which may be entered into the day/week count field, * depending on the current unit selection. */ void TimePeriod::setUnitRange() { int maxval; switch (static_cast(mUnitsCombo->currentItem() + mDateOnlyOffset)) { case WEEKS: maxval = mMaxDays / 7; if (maxval) break; mUnitsCombo->setCurrentItem(DAYS - mDateOnlyOffset); // fall through to DAYS case DAYS: maxval = mMaxDays ? mMaxDays : 1; break; case MINUTES: maxval = mTimeSpinBox->maxValue(); break; case HOURS_MINUTES: default: return; } mSpinBox->setRange(1, maxval); } /****************************************************************************** * Called when a new item is made current in the time units combo box. */ void TimePeriod::slotUnitsSelected(int index) { setUnitRange(); showHourMin(index + mDateOnlyOffset == HOURS_MINUTES); emit valueChanged(minutes()); } /****************************************************************************** * Called when the value of the days/weeks spin box changes. */ void TimePeriod::slotDaysChanged(int) { if (!mHourMinuteRaised) emit valueChanged(minutes()); } /****************************************************************************** * Called when the value of the time spin box changes. */ void TimePeriod::slotTimeChanged(int value) { if (mHourMinuteRaised) emit valueChanged(value); } /****************************************************************************** * Set the currently displayed count widget. */ void TimePeriod::showHourMin(bool hourMinute) { if (hourMinute != mHourMinuteRaised) { mHourMinuteRaised = hourMinute; if (hourMinute) { mSpinStack->raiseWidget(mTimeSpinBox); mSpinStack->setFocusProxy(mTimeSpinBox); } else { mSpinStack->raiseWidget(mSpinBox); mSpinStack->setFocusProxy(mSpinBox); } } } /****************************************************************************** * Set separate WhatsThis texts for the count spinboxes and the units combobox. * If the hours:minutes text is omitted, both spinboxes are set to the same * WhatsThis text. */ void TimePeriod::setWhatsThis(const TQString& units, const TQString& dayWeek, const TQString& hourMin) { TQWhatsThis::add(mUnitsCombo, units); TQWhatsThis::add(mSpinBox, dayWeek); TQWhatsThis::add(mTimeSpinBox, (hourMin.isNull() ? dayWeek : hourMin)); }