kalarm

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::null,
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, Qt::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 }