kalarm

repetition.cpp

00001 /*
00002  *  repetition.cpp  -  pushbutton and dialogue to specify alarm repetition
00003  *  Program:  kalarm
00004  *  Copyright © 2004,2005,2007 by David Jarvie <software@astrojar.org.uk>
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 <qlabel.h>
00024 #include <qlayout.h>
00025 #include <qtimer.h>
00026 #include <qwhatsthis.h>
00027 
00028 #include <kdialog.h>
00029 #include <kseparator.h>
00030 #include <klocale.h>
00031 
00032 #include "buttongroup.h"
00033 #include "radiobutton.h"
00034 #include "spinbox.h"
00035 #include "timeperiod.h"
00036 #include "timeselector.h"
00037 #include "repetition.moc"
00038 
00039 
00040 /*=============================================================================
00041 = Class RepetitionButton
00042 = Button to display the Simple Alarm Repetition dialogue.
00043 =============================================================================*/
00044 
00045 RepetitionButton::RepetitionButton(const QString& caption, bool waitForInitialisation, QWidget* parent, const char* name)
00046     : QPushButton(caption, parent, name),
00047       mDialog(0),
00048       mInterval(0),
00049       mCount(0),
00050       mMaxDuration(-1),
00051       mDateOnly(false),
00052       mWaitForInit(waitForInitialisation),
00053       mReadOnly(false)
00054 {
00055     setToggleButton(true);
00056     setOn(false);
00057     connect(this, SIGNAL(clicked()), SLOT(slotPressed()));
00058 }
00059 
00060 void RepetitionButton::set(int interval, int count)
00061 {
00062     mInterval = interval;
00063     mCount = count;
00064     setOn(mInterval && mCount);
00065 }
00066 
00067 /******************************************************************************
00068 *  Set the data for the dialog.
00069 */
00070 void RepetitionButton::set(int interval, int count, bool dateOnly, int maxDuration)
00071 {
00072     mInterval    = interval;
00073     mCount       = count;
00074     mMaxDuration = maxDuration;
00075     mDateOnly    = dateOnly;
00076     setOn(mInterval && mCount);
00077 }
00078 
00079 /******************************************************************************
00080 *  Create the alarm repetition dialog.
00081 *  If 'waitForInitialisation' is true, the dialog won't be displayed until set()
00082 *  is called to initialise its data.
00083 */
00084 void RepetitionButton::activate(bool waitForInitialisation)
00085 {
00086     if (!mDialog)
00087         mDialog = new RepetitionDlg(i18n("Alarm Repetition"), mReadOnly, this);
00088     mDialog->set(mInterval, mCount, mDateOnly, mMaxDuration);
00089     if (waitForInitialisation)
00090         emit needsInitialisation();     // request dialog initialisation
00091     else
00092         displayDialog();    // display the dialog now
00093 }
00094 
00095 /******************************************************************************
00096 *  Set the data for the dialog and display it.
00097 *  To be called only after needsInitialisation() has been emitted.
00098 */
00099 void RepetitionButton::initialise(int interval, int count, bool dateOnly, int maxDuration)
00100 {
00101     mInterval    = interval;
00102     mCount       = count;
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 simple alarm 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     if (mReadOnly)
00124     {
00125         mDialog->setReadOnly(true);
00126         mDialog->exec();
00127     }
00128     else if (mDialog->exec() == QDialog::Accepted)
00129     {
00130         mCount    = mDialog->count();
00131         mInterval = mDialog->interval();
00132         emit changed();
00133     }
00134     setOn(mInterval && mCount);
00135     delete mDialog;
00136     mDialog = 0;
00137 }
00138 
00139 
00140 /*=============================================================================
00141 = Class RepetitionDlg
00142 = Simple alarm repetition dialogue.
00143 * Note that the displayed repetition count is one greater than the value set or
00144 * returned in the external methods.
00145 =============================================================================*/
00146 
00147 static const int MAX_COUNT = 9999;    // maximum range for count spinbox
00148 
00149 
00150 RepetitionDlg::RepetitionDlg(const QString& caption, bool readOnly, QWidget* parent, const char* name)
00151     : KDialogBase(parent, name, true, caption, Ok|Cancel),
00152       mMaxDuration(-1),
00153       mDateOnly(false),
00154       mReadOnly(readOnly)
00155 {
00156     int spacing = spacingHint();
00157     QWidget* page = new QWidget(this);
00158     setMainWidget(page);
00159     QVBoxLayout* topLayout = new QVBoxLayout(page, 0, spacing);
00160 
00161     QBoxLayout* layout = new QHBoxLayout(topLayout, 0);
00162     int hintMargin = 2*marginHint();
00163     layout->addSpacing(hintMargin);
00164     QLabel* hintLabel = new QLabel(
00165          i18n("Use this dialog either:\n"
00166               "- instead of the Recurrence tab, or\n"
00167               "- after using the Recurrence tab, to set up a repetition within a repetition."),
00168          page);
00169     hintLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
00170     hintLabel->setLineWidth(2);
00171     hintLabel->setMargin(marginHint());
00172     hintLabel->setAlignment(Qt::WordBreak);
00173 //  hintLabel->setTextFormat(Qt::RichText);
00174     layout->addWidget(hintLabel);
00175     layout->addSpacing(hintMargin);
00176     topLayout->addSpacing(spacing);
00177 
00178     // Group the other controls together so that the minimum width can be found easily
00179     QWidget* controls = new QWidget(page);
00180     topLayout->addWidget(controls);
00181     topLayout = new QVBoxLayout(controls, 0, spacing);
00182 
00183     mTimeSelector = new TimeSelector(i18n("Repeat every 10 minutes", "&Repeat every"), QString::null,
00184                       i18n("Check to repeat the alarm each time it recurs. "
00185                            "Instead of the alarm triggering once at each recurrence, "
00186                            "this option makes the alarm trigger multiple times at each recurrence."),
00187                       i18n("Enter the time between repetitions of the alarm"),
00188                       true, controls);
00189     mTimeSelector->setFixedSize(mTimeSelector->sizeHint());
00190     connect(mTimeSelector, SIGNAL(valueChanged(int)), SLOT(intervalChanged(int)));
00191     connect(mTimeSelector, SIGNAL(toggled(bool)), SLOT(repetitionToggled(bool)));
00192     topLayout->addWidget(mTimeSelector, 0, Qt::AlignAuto);
00193 
00194     mButtonGroup = new ButtonGroup(controls, "buttonGroup");
00195     connect(mButtonGroup, SIGNAL(buttonSet(int)), SLOT(typeClicked()));
00196     topLayout->addWidget(mButtonGroup);
00197 
00198     QBoxLayout* vlayout = new QVBoxLayout(mButtonGroup, marginHint(), spacing);
00199     layout = new QHBoxLayout(vlayout, spacing);
00200     mCountButton = new RadioButton(i18n("&Number of repetitions:"), mButtonGroup);
00201     mCountButton->setFixedSize(mCountButton->sizeHint());
00202     QWhatsThis::add(mCountButton,
00203           i18n("Check to specify the number of times the alarm should repeat after each recurrence"));
00204     layout->addWidget(mCountButton);
00205     mCount = new SpinBox(1, MAX_COUNT, 1, mButtonGroup);
00206     mCount->setFixedSize(mCount->sizeHint());
00207     mCount->setLineShiftStep(10);
00208     mCount->setSelectOnStep(false);
00209     connect(mCount, SIGNAL(valueChanged(int)), SLOT(countChanged(int)));
00210     QWhatsThis::add(mCount,
00211           i18n("Enter the number of times to trigger the alarm after its initial occurrence"));
00212     layout->addWidget(mCount);
00213     mCountButton->setFocusWidget(mCount);
00214     layout->addStretch();
00215 
00216     layout = new QHBoxLayout(vlayout, spacing);
00217     mDurationButton = new RadioButton(i18n("&Duration:"), mButtonGroup);
00218     mDurationButton->setFixedSize(mDurationButton->sizeHint());
00219     QWhatsThis::add(mDurationButton,
00220           i18n("Check to specify how long the alarm is to be repeated"));
00221     layout->addWidget(mDurationButton);
00222     mDuration = new TimePeriod(true, mButtonGroup);
00223     mDuration->setFixedSize(mDuration->sizeHint());
00224     connect(mDuration, SIGNAL(valueChanged(int)), SLOT(durationChanged(int)));
00225     QWhatsThis::add(mDuration,
00226           i18n("Enter the length of time to repeat the alarm"));
00227     layout->addWidget(mDuration);
00228     mDurationButton->setFocusWidget(mDuration);
00229     layout->addStretch();
00230 
00231     hintLabel->setMinimumWidth(controls->sizeHint().width() - 2*hintMargin);   // this enables a minimum size for the dialogue
00232 
00233     mCountButton->setChecked(true);
00234     repetitionToggled(false);
00235     setReadOnly(mReadOnly);
00236 }
00237 
00238 /******************************************************************************
00239 *  Set the state of all controls to reflect the data in the specified alarm.
00240 */
00241 void RepetitionDlg::set(int interval, int count, bool dateOnly, int maxDuration)
00242 {
00243     if (!interval)
00244         count = 0;
00245     else if (!count)
00246         interval = 0;
00247     if (dateOnly != mDateOnly)
00248     {
00249         mDateOnly = dateOnly;
00250         mTimeSelector->setDateOnly(mDateOnly);
00251         mDuration->setDateOnly(mDateOnly);
00252     }
00253     mMaxDuration = maxDuration;
00254     if (mMaxDuration)
00255     {
00256         int maxhm = (mMaxDuration > 0) ? mMaxDuration : 9999;
00257         int maxdw = (mMaxDuration > 0) ? mMaxDuration / 1440 : 9999;
00258         mTimeSelector->setMaximum(maxhm, maxdw);
00259         mDuration->setMaximum(maxhm, maxdw);
00260     }
00261     if (!mMaxDuration  ||  !count)
00262         mTimeSelector->setChecked(false);
00263     else
00264     {
00265         TimePeriod::Units units = mDateOnly ? TimePeriod::DAYS : TimePeriod::HOURS_MINUTES;
00266         mTimeSelector->setMinutes(interval, mDateOnly, units);
00267         bool on = mTimeSelector->isChecked();
00268         repetitionToggled(on);    // enable/disable controls
00269         if (on)
00270             intervalChanged(interval);    // ensure mCount range is set
00271         mCount->setValue(count);
00272         mDuration->setMinutes(count * interval, mDateOnly, units);
00273         mCountButton->setChecked(true);
00274     }
00275     mTimeSelector->setEnabled(mMaxDuration);
00276 }
00277 
00278 /******************************************************************************
00279 *  Set the read-only status.
00280 */
00281 void RepetitionDlg::setReadOnly(bool ro)
00282 {
00283     ro = ro || mReadOnly;
00284     mTimeSelector->setReadOnly(ro);
00285     mCountButton->setReadOnly(ro);
00286     mCount->setReadOnly(ro);
00287     mDurationButton->setReadOnly(ro);
00288     mDuration->setReadOnly(ro);
00289 }
00290 
00291 /******************************************************************************
00292 *  Get the period between repetitions in minutes.
00293 */
00294 int RepetitionDlg::interval() const
00295 {
00296     return mTimeSelector->minutes();
00297 }
00298 
00299 /******************************************************************************
00300 *  Set the entered repeat count.
00301 */
00302 int RepetitionDlg::count() const
00303 {
00304     int interval = mTimeSelector->minutes();
00305     if (interval)
00306     {
00307         if (mCountButton->isOn())
00308             return mCount->value();
00309         if (mDurationButton->isOn())
00310             return mDuration->minutes() / interval;
00311     }
00312     return 0;    // no repetition
00313 }
00314 
00315 /******************************************************************************
00316 *  Called when the time interval widget has changed value.
00317 *  Adjust the maximum repetition count accordingly.
00318 */
00319 void RepetitionDlg::intervalChanged(int minutes)
00320 {
00321     if (mTimeSelector->isChecked())
00322     {
00323         mCount->setRange(1, (mMaxDuration >= 0 ? mMaxDuration / minutes : MAX_COUNT));
00324         if (mCountButton->isOn())
00325             countChanged(mCount->value());
00326         else
00327             durationChanged(mDuration->minutes());
00328     }
00329 }
00330 
00331 /******************************************************************************
00332 *  Called when the count spinbox has changed value.
00333 *  Adjust the duration accordingly.
00334 */
00335 void RepetitionDlg::countChanged(int count)
00336 {
00337     int interval = mTimeSelector->minutes();
00338     if (interval)
00339     {
00340         bool blocked = mDuration->signalsBlocked();
00341         mDuration->blockSignals(true);
00342         mDuration->setMinutes(count * interval, mDateOnly,
00343                               (mDateOnly ? TimePeriod::DAYS : TimePeriod::HOURS_MINUTES));
00344         mDuration->blockSignals(blocked);
00345     }
00346 }
00347 
00348 /******************************************************************************
00349 *  Called when the duration widget has changed value.
00350 *  Adjust the count accordingly.
00351 */
00352 void RepetitionDlg::durationChanged(int minutes)
00353 {
00354     int interval = mTimeSelector->minutes();
00355     if (interval)
00356     {
00357         bool blocked = mCount->signalsBlocked();
00358         mCount->blockSignals(true);
00359         mCount->setValue(minutes / interval);
00360         mCount->blockSignals(blocked);
00361     }
00362 }
00363 
00364 /******************************************************************************
00365 *  Called when the time period widget is toggled on or off.
00366 */
00367 void RepetitionDlg::repetitionToggled(bool on)
00368 {
00369     if (mMaxDuration == 0)
00370         on = false;
00371     mButtonGroup->setEnabled(on);
00372     mCount->setEnabled(on  &&  mCountButton->isOn());
00373     mDuration->setEnabled(on  &&  mDurationButton->isOn());
00374 }
00375 
00376 /******************************************************************************
00377 *  Called when one of the count or duration radio buttons is toggled.
00378 */
00379 void RepetitionDlg::typeClicked()
00380 {
00381     if (mTimeSelector->isChecked())
00382     {
00383         mCount->setEnabled(mCountButton->isOn());
00384         mDuration->setEnabled(mDurationButton->isOn());
00385     }
00386 }
KDE Home | KDE Accessibility Home | Description of Access Keys