kalarm

repetition.cpp

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