repetition.cpp
00001 /* 00002 * repetition.cpp - pushbutton and dialogue to specify alarm sub-repetition 00003 * Program: kalarm 00004 * Copyright © 2004,2005,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 <tqlayout.h> 00024 #include <tqwhatsthis.h> 00025 00026 #include <kdebug.h> 00027 #include <kdialog.h> 00028 #include <klocale.h> 00029 00030 #include "buttongroup.h" 00031 #include "radiobutton.h" 00032 #include "spinbox.h" 00033 #include "timeperiod.h" 00034 #include "timeselector.h" 00035 #include "repetition.moc" 00036 00037 00038 /*============================================================================= 00039 = Class RepetitionButton 00040 = Button to display the Alarm Sub-Repetition dialogue. 00041 =============================================================================*/ 00042 00043 RepetitionButton::RepetitionButton(const TQString& caption, bool waitForInitialisation, TQWidget* parent, const char* name) 00044 : TQPushButton(caption, parent, name), 00045 mDialog(0), 00046 mInterval(0), 00047 mCount(0), 00048 mMaxDuration(-1), 00049 mDateOnly(false), 00050 mWaitForInit(waitForInitialisation), 00051 mReadOnly(false) 00052 { 00053 setToggleButton(true); 00054 setOn(false); 00055 connect(this, TQT_SIGNAL(clicked()), TQT_SLOT(slotPressed())); 00056 } 00057 00058 void RepetitionButton::set(int interval, int count) 00059 { 00060 mInterval = interval; 00061 mCount = count; 00062 setOn(mInterval && mCount); 00063 } 00064 00065 /****************************************************************************** 00066 * Set the data for the dialog. 00067 */ 00068 void RepetitionButton::set(int interval, int count, bool dateOnly, int maxDuration) 00069 { 00070 mInterval = interval; 00071 mCount = count; 00072 mMaxDuration = maxDuration; 00073 mDateOnly = dateOnly; 00074 setOn(mInterval && mCount); 00075 } 00076 00077 /****************************************************************************** 00078 * Create the alarm repetition dialog. 00079 * If 'waitForInitialisation' is true, the dialog won't be displayed until set() 00080 * is called to initialise its data. 00081 */ 00082 void RepetitionButton::activate(bool waitForInitialisation) 00083 { 00084 if (!mDialog) 00085 mDialog = new RepetitionDlg(i18n("Alarm Sub-Repetition"), mReadOnly, this); 00086 mDialog->set(mInterval, mCount, mDateOnly, mMaxDuration); 00087 if (waitForInitialisation) 00088 emit needsInitialisation(); // request dialog initialisation 00089 else 00090 displayDialog(); // display the dialog now 00091 } 00092 00093 /****************************************************************************** 00094 * Set the data for the dialog and display it. 00095 * To be called only after needsInitialisation() has been emitted. 00096 */ 00097 void RepetitionButton::initialise(int interval, int count, bool dateOnly, int maxDuration) 00098 { 00099 if (maxDuration > 0 && interval > maxDuration) 00100 count = 0; 00101 mCount = count; 00102 mInterval = interval; 00103 mMaxDuration = maxDuration; 00104 mDateOnly = dateOnly; 00105 if (mDialog) 00106 { 00107 mDialog->set(interval, count, dateOnly, maxDuration); 00108 displayDialog(); // display the dialog now 00109 } 00110 else 00111 setOn(mInterval && mCount); 00112 } 00113 00114 /****************************************************************************** 00115 * Display the alarm sub-repetition dialog. 00116 * Alarm repetition has the following restrictions: 00117 * 1) Not allowed for a repeat-at-login alarm 00118 * 2) For a date-only alarm, the repeat interval must be a whole number of days. 00119 * 3) The overall repeat duration must be less than the recurrence interval. 00120 */ 00121 void RepetitionButton::displayDialog() 00122 { 00123 kdDebug(5950) << "RepetitionButton::displayDialog()" << endl; 00124 bool change = false; 00125 if (mReadOnly) 00126 { 00127 mDialog->setReadOnly(true); 00128 mDialog->exec(); 00129 } 00130 else if (mDialog->exec() == TQDialog::Accepted) 00131 { 00132 mCount = mDialog->count(); 00133 mInterval = mDialog->interval(); 00134 change = true; 00135 } 00136 setOn(mInterval && mCount); 00137 delete mDialog; 00138 mDialog = 0; 00139 if (change) 00140 emit changed(); // delete dialog first, or initialise() will redisplay dialog 00141 } 00142 00143 00144 /*============================================================================= 00145 = Class RepetitionDlg 00146 = Alarm sub-repetition dialogue. 00147 =============================================================================*/ 00148 00149 static const int MAX_COUNT = 9999; // maximum range for count spinbox 00150 00151 00152 RepetitionDlg::RepetitionDlg(const TQString& caption, bool readOnly, TQWidget* parent, const char* name) 00153 : KDialogBase(parent, name, true, caption, Ok|Cancel), 00154 mMaxDuration(-1), 00155 mDateOnly(false), 00156 mReadOnly(readOnly) 00157 { 00158 int spacing = spacingHint(); 00159 TQWidget* page = new TQWidget(this); 00160 setMainWidget(page); 00161 TQVBoxLayout* topLayout = new TQVBoxLayout(page, 0, spacing); 00162 00163 mTimeSelector = new TimeSelector(i18n("Repeat every 10 minutes", "&Repeat every"), TQString(), 00164 i18n("Instead of the alarm triggering just once at each recurrence, " 00165 "checking this option makes the alarm trigger multiple times at each recurrence."), 00166 i18n("Enter the time between repetitions of the alarm"), 00167 true, page); 00168 mTimeSelector->setFixedSize(mTimeSelector->sizeHint()); 00169 connect(mTimeSelector, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(intervalChanged(int))); 00170 connect(mTimeSelector, TQT_SIGNAL(toggled(bool)), TQT_SLOT(repetitionToggled(bool))); 00171 topLayout->addWidget(mTimeSelector, 0, TQt::AlignAuto); 00172 00173 mButtonGroup = new ButtonGroup(page, "buttonGroup"); 00174 connect(mButtonGroup, TQT_SIGNAL(buttonSet(int)), TQT_SLOT(typeClicked())); 00175 topLayout->addWidget(mButtonGroup); 00176 00177 TQBoxLayout* vlayout = new TQVBoxLayout(mButtonGroup, marginHint(), spacing); 00178 TQBoxLayout* layout = new TQHBoxLayout(vlayout, spacing); 00179 mCountButton = new RadioButton(i18n("&Number of repetitions:"), mButtonGroup); 00180 mCountButton->setFixedSize(mCountButton->sizeHint()); 00181 TQWhatsThis::add(mCountButton, 00182 i18n("Check to specify the number of times the alarm should repeat after each recurrence")); 00183 layout->addWidget(mCountButton); 00184 mCount = new SpinBox(1, MAX_COUNT, 1, mButtonGroup); 00185 mCount->setFixedSize(mCount->sizeHint()); 00186 mCount->setLineShiftStep(10); 00187 mCount->setSelectOnStep(false); 00188 connect(mCount, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(countChanged(int))); 00189 TQWhatsThis::add(mCount, 00190 i18n("Enter the number of times to trigger the alarm after its initial occurrence")); 00191 layout->addWidget(mCount); 00192 mCountButton->setFocusWidget(mCount); 00193 layout->addStretch(); 00194 00195 layout = new TQHBoxLayout(vlayout, spacing); 00196 mDurationButton = new RadioButton(i18n("&Duration:"), mButtonGroup); 00197 mDurationButton->setFixedSize(mDurationButton->sizeHint()); 00198 TQWhatsThis::add(mDurationButton, 00199 i18n("Check to specify how long the alarm is to be repeated")); 00200 layout->addWidget(mDurationButton); 00201 mDuration = new TimePeriod(true, mButtonGroup); 00202 mDuration->setFixedSize(mDuration->sizeHint()); 00203 connect(mDuration, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(durationChanged(int))); 00204 TQWhatsThis::add(mDuration, 00205 i18n("Enter the length of time to repeat the alarm")); 00206 layout->addWidget(mDuration); 00207 mDurationButton->setFocusWidget(mDuration); 00208 layout->addStretch(); 00209 00210 mCountButton->setChecked(true); 00211 repetitionToggled(false); 00212 setReadOnly(mReadOnly); 00213 } 00214 00215 /****************************************************************************** 00216 * Set the state of all controls to reflect the data in the specified alarm. 00217 */ 00218 void RepetitionDlg::set(int interval, int count, bool dateOnly, int maxDuration) 00219 { 00220 if (!interval) 00221 count = 0; 00222 else if (!count) 00223 interval = 0; 00224 if (dateOnly != mDateOnly) 00225 { 00226 mDateOnly = dateOnly; 00227 mTimeSelector->setDateOnly(mDateOnly); 00228 mDuration->setDateOnly(mDateOnly); 00229 } 00230 mMaxDuration = maxDuration; 00231 if (mMaxDuration) 00232 { 00233 int maxhm = (mMaxDuration > 0) ? mMaxDuration : 9999; 00234 int maxdw = (mMaxDuration > 0) ? mMaxDuration / 1440 : 9999; 00235 mTimeSelector->setMaximum(maxhm, maxdw); 00236 mDuration->setMaximum(maxhm, maxdw); 00237 } 00238 // Set the units - needed later if the control is unchecked initially. 00239 TimePeriod::Units units = mDateOnly ? TimePeriod::DAYS : TimePeriod::HOURS_MINUTES; 00240 mTimeSelector->setMinutes(interval, mDateOnly, units); 00241 if (!mMaxDuration || !count) 00242 mTimeSelector->setChecked(false); 00243 else 00244 { 00245 bool on = mTimeSelector->isChecked(); 00246 repetitionToggled(on); // enable/disable controls 00247 if (on) 00248 intervalChanged(interval); // ensure mCount range is set 00249 mCount->setValue(count); 00250 mDuration->setMinutes(count * interval, mDateOnly, units); 00251 mCountButton->setChecked(true); 00252 } 00253 mTimeSelector->setEnabled(mMaxDuration); 00254 } 00255 00256 /****************************************************************************** 00257 * Set the read-only status. 00258 */ 00259 void RepetitionDlg::setReadOnly(bool ro) 00260 { 00261 ro = ro || mReadOnly; 00262 mTimeSelector->setReadOnly(ro); 00263 mCountButton->setReadOnly(ro); 00264 mCount->setReadOnly(ro); 00265 mDurationButton->setReadOnly(ro); 00266 mDuration->setReadOnly(ro); 00267 } 00268 00269 /****************************************************************************** 00270 * Get the period between repetitions in minutes. 00271 */ 00272 int RepetitionDlg::interval() const 00273 { 00274 return mTimeSelector->minutes(); 00275 } 00276 00277 /****************************************************************************** 00278 * Set the entered repeat count. 00279 */ 00280 int RepetitionDlg::count() const 00281 { 00282 int interval = mTimeSelector->minutes(); 00283 if (interval) 00284 { 00285 if (mCountButton->isOn()) 00286 return mCount->value(); 00287 if (mDurationButton->isOn()) 00288 return mDuration->minutes() / interval; 00289 } 00290 return 0; // no repetition 00291 } 00292 00293 /****************************************************************************** 00294 * Called when the time interval widget has changed value. 00295 * Adjust the maximum repetition count accordingly. 00296 */ 00297 void RepetitionDlg::intervalChanged(int minutes) 00298 { 00299 if (mTimeSelector->isChecked() && minutes > 0) 00300 { 00301 mCount->setRange(1, (mMaxDuration >= 0 ? mMaxDuration / minutes : MAX_COUNT)); 00302 if (mCountButton->isOn()) 00303 countChanged(mCount->value()); 00304 else 00305 durationChanged(mDuration->minutes()); 00306 } 00307 } 00308 00309 /****************************************************************************** 00310 * Called when the count spinbox has changed value. 00311 * Adjust the duration accordingly. 00312 */ 00313 void RepetitionDlg::countChanged(int count) 00314 { 00315 int interval = mTimeSelector->minutes(); 00316 if (interval) 00317 { 00318 bool blocked = mDuration->signalsBlocked(); 00319 mDuration->blockSignals(true); 00320 mDuration->setMinutes(count * interval, mDateOnly, 00321 (mDateOnly ? TimePeriod::DAYS : TimePeriod::HOURS_MINUTES)); 00322 mDuration->blockSignals(blocked); 00323 } 00324 } 00325 00326 /****************************************************************************** 00327 * Called when the duration widget has changed value. 00328 * Adjust the count accordingly. 00329 */ 00330 void RepetitionDlg::durationChanged(int minutes) 00331 { 00332 int interval = mTimeSelector->minutes(); 00333 if (interval) 00334 { 00335 bool blocked = mCount->signalsBlocked(); 00336 mCount->blockSignals(true); 00337 mCount->setValue(minutes / interval); 00338 mCount->blockSignals(blocked); 00339 } 00340 } 00341 00342 /****************************************************************************** 00343 * Called when the time period widget is toggled on or off. 00344 */ 00345 void RepetitionDlg::repetitionToggled(bool on) 00346 { 00347 if (mMaxDuration == 0) 00348 on = false; 00349 mButtonGroup->setEnabled(on); 00350 mCount->setEnabled(on && mCountButton->isOn()); 00351 mDuration->setEnabled(on && mDurationButton->isOn()); 00352 } 00353 00354 /****************************************************************************** 00355 * Called when one of the count or duration radio buttons is toggled. 00356 */ 00357 void RepetitionDlg::typeClicked() 00358 { 00359 if (mTimeSelector->isChecked()) 00360 { 00361 mCount->setEnabled(mCountButton->isOn()); 00362 mDuration->setEnabled(mDurationButton->isOn()); 00363 } 00364 }