kalarm

recurrenceedit.cpp
00001 /*
00002  *  recurrenceedit.cpp  -  widget to edit the event's recurrence definition
00003  *  Program:  kalarm
00004  *  Copyright © 2002-2008 by David Jarvie <djarvie@kde.org>
00005  *
00006  *  Based originally on KOrganizer module koeditorrecurrence.cpp,
00007  *  Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org>
00008  *
00009  *  This program is free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version.
00013  *
00014  *  This program is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00017  *  GNU General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU General Public License along
00020  *  with this program; if not, write to the Free Software Foundation, Inc.,
00021  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00022  */
00023 
00024 #include "kalarm.h"
00025 
00026 #include <tqtooltip.h>
00027 #include <tqlayout.h>
00028 #include <tqvbox.h>
00029 #include <tqwidgetstack.h>
00030 #include <tqlistbox.h>
00031 #include <tqframe.h>
00032 #include <tqlabel.h>
00033 #include <tqpushbutton.h>
00034 #include <tqlineedit.h>
00035 #include <tqwhatsthis.h>
00036 
00037 #include <tdeglobal.h>
00038 #include <tdelocale.h>
00039 #include <kcalendarsystem.h>
00040 #include <kiconloader.h>
00041 #include <kdialog.h>
00042 #include <tdemessagebox.h>
00043 #include <kdebug.h>
00044 
00045 #include <libkcal/event.h>
00046 
00047 #include "alarmevent.h"
00048 #include "alarmtimewidget.h"
00049 #include "checkbox.h"
00050 #include "combobox.h"
00051 #include "dateedit.h"
00052 #include "functions.h"
00053 #include "kalarmapp.h"
00054 #include "karecurrence.h"
00055 #include "preferences.h"
00056 #include "radiobutton.h"
00057 #include "repetition.h"
00058 #include "spinbox.h"
00059 #include "timeedit.h"
00060 #include "timespinbox.h"
00061 #include "buttongroup.h"
00062 using namespace KCal;
00063 
00064 #include "recurrenceedit.moc"
00065 #include "recurrenceeditprivate.moc"
00066 
00067 // Collect these widget labels together to ensure consistent wording and
00068 // translations across different modules.
00069 TQString RecurrenceEdit::i18n_Norecur()           { return i18n("No recurrence"); }
00070 TQString RecurrenceEdit::i18n_NoRecur()           { return i18n("No Recurrence"); }
00071 TQString RecurrenceEdit::i18n_AtLogin()           { return i18n("At Login"); }
00072 TQString RecurrenceEdit::i18n_l_Atlogin()         { return i18n("At &login"); }
00073 TQString RecurrenceEdit::i18n_HourlyMinutely()    { return i18n("Hourly/Minutely"); }
00074 TQString RecurrenceEdit::i18n_u_HourlyMinutely()  { return i18n("Ho&urly/Minutely"); }
00075 TQString RecurrenceEdit::i18n_Daily()             { return i18n("Daily"); }
00076 TQString RecurrenceEdit::i18n_d_Daily()           { return i18n("&Daily"); }
00077 TQString RecurrenceEdit::i18n_Weekly()            { return i18n("Weekly"); }
00078 TQString RecurrenceEdit::i18n_w_Weekly()          { return i18n("&Weekly"); }
00079 TQString RecurrenceEdit::i18n_Monthly()           { return i18n("Monthly"); }
00080 TQString RecurrenceEdit::i18n_m_Monthly()         { return i18n("&Monthly"); }
00081 TQString RecurrenceEdit::i18n_Yearly()            { return i18n("Yearly"); }
00082 TQString RecurrenceEdit::i18n_y_Yearly()          { return i18n("&Yearly"); }
00083 
00084 
00085 RecurrenceEdit::RecurrenceEdit(bool readOnly, TQWidget* parent, const char* name)
00086     : TQFrame(parent, name),
00087       mRule(0),
00088       mRuleButtonType(INVALID_RECUR),
00089       mDailyShown(false),
00090       mWeeklyShown(false),
00091       mMonthlyShown(false),
00092       mYearlyShown(false),
00093       mNoEmitTypeChanged(true),
00094       mReadOnly(readOnly)
00095 {
00096     TQBoxLayout* layout;
00097     TQVBoxLayout* topLayout = new TQVBoxLayout(this, 0, KDialog::spacingHint());
00098 
00099     /* Create the recurrence rule Group box which holds the recurrence period
00100      * selection buttons, and the weekly, monthly and yearly recurrence rule
00101      * frames which specify options individual to each of these distinct
00102      * sections of the recurrence rule. Each frame is made visible by the
00103      * selection of its corresponding radio button.
00104      */
00105 
00106     TQGroupBox* recurGroup = new TQGroupBox(1, Qt::Vertical, i18n("Recurrence Rule"), this, "recurGroup");
00107     topLayout->addWidget(recurGroup);
00108     TQFrame* ruleFrame = new TQFrame(recurGroup, "ruleFrame");
00109     layout = new TQVBoxLayout(ruleFrame, 0);
00110     layout->addSpacing(KDialog::spacingHint()/2);
00111 
00112     layout = new TQHBoxLayout(layout, 0);
00113     TQBoxLayout* lay = new TQVBoxLayout(layout, 0);
00114     mRuleButtonGroup = new ButtonGroup(1, Qt::Horizontal, ruleFrame);
00115     mRuleButtonGroup->setInsideMargin(0);
00116     mRuleButtonGroup->setFrameStyle(TQFrame::NoFrame);
00117     lay->addWidget(mRuleButtonGroup);
00118     lay->addStretch();    // top-adjust the interval radio buttons
00119     connect(mRuleButtonGroup, TQT_SIGNAL(buttonSet(int)), TQT_SLOT(periodClicked(int)));
00120 
00121     mNoneButton = new RadioButton(i18n_Norecur(), mRuleButtonGroup);
00122     mNoneButton->setFixedSize(mNoneButton->sizeHint());
00123     mNoneButton->setReadOnly(mReadOnly);
00124     TQWhatsThis::add(mNoneButton, i18n("Do not repeat the alarm"));
00125 
00126     mAtLoginButton = new RadioButton(i18n_l_Atlogin(), mRuleButtonGroup);
00127     mAtLoginButton->setFixedSize(mAtLoginButton->sizeHint());
00128     mAtLoginButton->setReadOnly(mReadOnly);
00129     TQWhatsThis::add(mAtLoginButton,
00130           i18n("Trigger the alarm at the specified date/time and at every login until then.\n"
00131                "Note that it will also be triggered any time the alarm daemon is restarted."));
00132 
00133     mSubDailyButton = new RadioButton(i18n_u_HourlyMinutely(), mRuleButtonGroup);
00134     mSubDailyButton->setFixedSize(mSubDailyButton->sizeHint());
00135     mSubDailyButton->setReadOnly(mReadOnly);
00136     TQWhatsThis::add(mSubDailyButton,
00137           i18n("Repeat the alarm at hourly/minutely intervals"));
00138 
00139     mDailyButton = new RadioButton(i18n_d_Daily(), mRuleButtonGroup);
00140     mDailyButton->setFixedSize(mDailyButton->sizeHint());
00141     mDailyButton->setReadOnly(mReadOnly);
00142     TQWhatsThis::add(mDailyButton,
00143           i18n("Repeat the alarm at daily intervals"));
00144 
00145     mWeeklyButton = new RadioButton(i18n_w_Weekly(), mRuleButtonGroup);
00146     mWeeklyButton->setFixedSize(mWeeklyButton->sizeHint());
00147     mWeeklyButton->setReadOnly(mReadOnly);
00148     TQWhatsThis::add(mWeeklyButton,
00149           i18n("Repeat the alarm at weekly intervals"));
00150 
00151     mMonthlyButton = new RadioButton(i18n_m_Monthly(), mRuleButtonGroup);
00152     mMonthlyButton->setFixedSize(mMonthlyButton->sizeHint());
00153     mMonthlyButton->setReadOnly(mReadOnly);
00154     TQWhatsThis::add(mMonthlyButton,
00155           i18n("Repeat the alarm at monthly intervals"));
00156 
00157     mYearlyButton = new RadioButton(i18n_y_Yearly(), mRuleButtonGroup);
00158     mYearlyButton->setFixedSize(mYearlyButton->sizeHint());
00159     mYearlyButton->setReadOnly(mReadOnly);
00160     TQWhatsThis::add(mYearlyButton,
00161           i18n("Repeat the alarm at annual intervals"));
00162 
00163     mNoneButtonId     = mRuleButtonGroup->id(mNoneButton);
00164     mAtLoginButtonId  = mRuleButtonGroup->id(mAtLoginButton);
00165     mSubDailyButtonId = mRuleButtonGroup->id(mSubDailyButton);
00166     mDailyButtonId    = mRuleButtonGroup->id(mDailyButton);
00167     mWeeklyButtonId   = mRuleButtonGroup->id(mWeeklyButton);
00168     mMonthlyButtonId  = mRuleButtonGroup->id(mMonthlyButton);
00169     mYearlyButtonId   = mRuleButtonGroup->id(mYearlyButton);
00170 
00171     // Sub-repetition button
00172     mSubRepetition = new RepetitionButton(i18n("Sub-Repetition"), true, ruleFrame);
00173     mSubRepetition->setFixedSize(mSubRepetition->sizeHint());
00174     mSubRepetition->setReadOnly(mReadOnly);
00175     connect(mSubRepetition, TQT_SIGNAL(needsInitialisation()), TQT_SIGNAL(repeatNeedsInitialisation()));
00176     connect(mSubRepetition, TQT_SIGNAL(changed()), TQT_SIGNAL(frequencyChanged()));
00177     TQWhatsThis::add(mSubRepetition, i18n("Set up a repetition within the recurrence, to trigger the alarm multiple times each time the recurrence is due."));
00178     lay->addSpacing(KDialog::spacingHint());
00179     lay->addWidget(mSubRepetition);
00180 
00181     lay = new TQVBoxLayout(layout);
00182 
00183     lay->addStretch();
00184     layout = new TQHBoxLayout(lay);
00185 
00186     layout->addSpacing(KDialog::marginHint());
00187     TQFrame* divider = new TQFrame(ruleFrame);
00188     divider->setFrameStyle(TQFrame::VLine | TQFrame::Sunken);
00189     layout->addWidget(divider);
00190     layout->addSpacing(KDialog::marginHint());
00191 
00192     mNoRule       = new NoRule(ruleFrame, "noFrame");
00193     mSubDailyRule = new SubDailyRule(mReadOnly, ruleFrame, "subdayFrame");
00194     mDailyRule    = new DailyRule(mReadOnly, ruleFrame, "dayFrame");
00195     mWeeklyRule   = new WeeklyRule(mReadOnly, ruleFrame, "weekFrame");
00196     mMonthlyRule  = new MonthlyRule(mReadOnly, ruleFrame, "monthFrame");
00197     mYearlyRule   = new YearlyRule(mReadOnly, ruleFrame, "yearFrame");
00198 
00199     connect(mSubDailyRule, TQT_SIGNAL(frequencyChanged()), this, TQT_SIGNAL(frequencyChanged()));
00200     connect(mDailyRule, TQT_SIGNAL(frequencyChanged()), this, TQT_SIGNAL(frequencyChanged()));
00201     connect(mWeeklyRule, TQT_SIGNAL(frequencyChanged()), this, TQT_SIGNAL(frequencyChanged()));
00202     connect(mMonthlyRule, TQT_SIGNAL(frequencyChanged()), this, TQT_SIGNAL(frequencyChanged()));
00203     connect(mYearlyRule, TQT_SIGNAL(frequencyChanged()), this, TQT_SIGNAL(frequencyChanged()));
00204 
00205     mRuleStack = new TQWidgetStack(ruleFrame);
00206     layout->addWidget(mRuleStack);
00207     layout->addStretch(1);
00208     mRuleStack->addWidget(mNoRule, 0);
00209     mRuleStack->addWidget(mSubDailyRule, 1);
00210     mRuleStack->addWidget(mDailyRule, 2);
00211     mRuleStack->addWidget(mWeeklyRule, 3);
00212     mRuleStack->addWidget(mMonthlyRule, 4);
00213     mRuleStack->addWidget(mYearlyRule, 5);
00214     layout->addSpacing(KDialog::marginHint());
00215 
00216     // Create the recurrence range group which contains the controls
00217     // which specify how long the recurrence is to last.
00218 
00219     mRangeButtonGroup = new ButtonGroup(i18n("Recurrence End"), this, "mRangeButtonGroup");
00220     connect(mRangeButtonGroup, TQT_SIGNAL(buttonSet(int)), TQT_SLOT(rangeTypeClicked()));
00221     topLayout->addWidget(mRangeButtonGroup);
00222 
00223     TQVBoxLayout* vlayout = new TQVBoxLayout(mRangeButtonGroup, KDialog::marginHint(), KDialog::spacingHint());
00224     vlayout->addSpacing(fontMetrics().lineSpacing()/2);
00225     mNoEndDateButton = new RadioButton(i18n("No &end"), mRangeButtonGroup);
00226     mNoEndDateButton->setFixedSize(mNoEndDateButton->sizeHint());
00227     mNoEndDateButton->setReadOnly(mReadOnly);
00228     TQWhatsThis::add(mNoEndDateButton, i18n("Repeat the alarm indefinitely"));
00229     vlayout->addWidget(mNoEndDateButton, 1, TQt::AlignAuto);
00230     TQSize size = mNoEndDateButton->size();
00231 
00232     layout = new TQHBoxLayout(vlayout, KDialog::spacingHint());
00233     mRepeatCountButton = new RadioButton(i18n("End a&fter:"), mRangeButtonGroup);
00234     mRepeatCountButton->setReadOnly(mReadOnly);
00235     TQWhatsThis::add(mRepeatCountButton,
00236           i18n("Repeat the alarm for the number of times specified"));
00237     mRepeatCountEntry = new SpinBox(1, 9999, 1, mRangeButtonGroup);
00238     mRepeatCountEntry->setFixedSize(mRepeatCountEntry->sizeHint());
00239     mRepeatCountEntry->setLineShiftStep(10);
00240     mRepeatCountEntry->setSelectOnStep(false);
00241     mRepeatCountEntry->setReadOnly(mReadOnly);
00242     connect(mRepeatCountEntry, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(repeatCountChanged(int)));
00243     TQWhatsThis::add(mRepeatCountEntry,
00244           i18n("Enter the total number of times to trigger the alarm"));
00245     mRepeatCountButton->setFocusWidget(mRepeatCountEntry);
00246     mRepeatCountLabel = new TQLabel(i18n("occurrence(s)"), mRangeButtonGroup);
00247     mRepeatCountLabel->setFixedSize(mRepeatCountLabel->sizeHint());
00248     layout->addWidget(mRepeatCountButton);
00249     layout->addSpacing(KDialog::spacingHint());
00250     layout->addWidget(mRepeatCountEntry);
00251     layout->addWidget(mRepeatCountLabel);
00252     layout->addStretch();
00253     size = size.expandedTo(mRepeatCountButton->sizeHint());
00254 
00255     layout = new TQHBoxLayout(vlayout, KDialog::spacingHint());
00256     mEndDateButton = new RadioButton(i18n("End &by:"), mRangeButtonGroup);
00257     mEndDateButton->setReadOnly(mReadOnly);
00258     TQWhatsThis::add(mEndDateButton,
00259           i18n("Repeat the alarm until the date/time specified.\n\n"
00260                "Note: This applies to the main recurrence only. It does not limit any sub-repetition which will occur regardless after the last main recurrence."));
00261     mEndDateEdit = new DateEdit(mRangeButtonGroup);
00262     mEndDateEdit->setFixedSize(mEndDateEdit->sizeHint());
00263     mEndDateEdit->setReadOnly(mReadOnly);
00264     TQWhatsThis::add(mEndDateEdit,
00265           i18n("Enter the last date to repeat the alarm"));
00266     mEndDateButton->setFocusWidget(mEndDateEdit);
00267     mEndTimeEdit = new TimeEdit(mRangeButtonGroup);
00268     mEndTimeEdit->setFixedSize(mEndTimeEdit->sizeHint());
00269     mEndTimeEdit->setReadOnly(mReadOnly);
00270     static const TQString lastTimeText = i18n("Enter the last time to repeat the alarm.");
00271     TQWhatsThis::add(mEndTimeEdit, TQString("%1\n\n%2").arg(lastTimeText).arg(TimeSpinBox::shiftWhatsThis()));
00272     mEndAnyTimeCheckBox = new CheckBox(i18n("Any time"), mRangeButtonGroup);
00273     mEndAnyTimeCheckBox->setFixedSize(mEndAnyTimeCheckBox->sizeHint());
00274     mEndAnyTimeCheckBox->setReadOnly(mReadOnly);
00275     connect(mEndAnyTimeCheckBox, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotAnyTimeToggled(bool)));
00276     TQWhatsThis::add(mEndAnyTimeCheckBox,
00277           i18n("Stop repeating the alarm after your first login on or after the specified end date"));
00278     layout->addWidget(mEndDateButton);
00279     layout->addSpacing(KDialog::spacingHint());
00280     layout->addWidget(mEndDateEdit);
00281     layout->addWidget(mEndTimeEdit);
00282     layout->addWidget(mEndAnyTimeCheckBox);
00283     layout->addStretch();
00284     size = size.expandedTo(mEndDateButton->sizeHint());
00285 
00286     // Line up the widgets to the right of the radio buttons
00287     mRepeatCountButton->setFixedSize(size);
00288     mEndDateButton->setFixedSize(size);
00289 
00290     // Create the exceptions group which specifies dates to be excluded
00291     // from the recurrence.
00292 
00293     mExceptionGroup = new TQGroupBox(i18n("E&xceptions"), this, "mExceptionGroup");
00294     topLayout->addWidget(mExceptionGroup);
00295     topLayout->setStretchFactor(mExceptionGroup, 2);
00296     vlayout = new TQVBoxLayout(mExceptionGroup, KDialog::marginHint(), KDialog::spacingHint());
00297     vlayout->addSpacing(fontMetrics().lineSpacing()/2);
00298     layout = new TQHBoxLayout(vlayout, KDialog::spacingHint());
00299     vlayout = new TQVBoxLayout(layout);
00300 
00301     mExceptionDateList = new TQListBox(mExceptionGroup);
00302     mExceptionDateList->setSizePolicy(TQSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Expanding));
00303     connect(mExceptionDateList, TQT_SIGNAL(selectionChanged()), TQT_SLOT(enableExceptionButtons()));
00304     TQWhatsThis::add(mExceptionDateList,
00305           i18n("The list of exceptions, i.e. dates/times excluded from the recurrence"));
00306     vlayout->addWidget(mExceptionDateList);
00307 
00308     if (mReadOnly)
00309     {
00310         mExceptionDateEdit     = 0;
00311         mChangeExceptionButton = 0;
00312         mDeleteExceptionButton = 0;
00313     }
00314     else
00315     {
00316         vlayout = new TQVBoxLayout(layout);
00317         mExceptionDateEdit = new DateEdit(mExceptionGroup);
00318         mExceptionDateEdit->setFixedSize(mExceptionDateEdit->sizeHint());
00319         mExceptionDateEdit->setDate(TQDate::currentDate());
00320         TQWhatsThis::add(mExceptionDateEdit,
00321               i18n("Enter a date to insert in the exceptions list. "
00322                    "Use in conjunction with the Add or Change button below."));
00323         vlayout->addWidget(mExceptionDateEdit);
00324 
00325         layout = new TQHBoxLayout(vlayout, KDialog::spacingHint());
00326         TQPushButton* button = new TQPushButton(i18n("Add"), mExceptionGroup);
00327         button->setFixedSize(button->sizeHint());
00328         connect(button, TQT_SIGNAL(clicked()), TQT_SLOT(addException()));
00329         TQWhatsThis::add(button,
00330               i18n("Add the date entered above to the exceptions list"));
00331         layout->addWidget(button);
00332 
00333         mChangeExceptionButton = new TQPushButton(i18n("Change"), mExceptionGroup);
00334         mChangeExceptionButton->setFixedSize(mChangeExceptionButton->sizeHint());
00335         connect(mChangeExceptionButton, TQT_SIGNAL(clicked()), TQT_SLOT(changeException()));
00336         TQWhatsThis::add(mChangeExceptionButton,
00337               i18n("Replace the currently highlighted item in the exceptions list with the date entered above"));
00338         layout->addWidget(mChangeExceptionButton);
00339 
00340         mDeleteExceptionButton = new TQPushButton(i18n("Delete"), mExceptionGroup);
00341         mDeleteExceptionButton->setFixedSize(mDeleteExceptionButton->sizeHint());
00342         connect(mDeleteExceptionButton, TQT_SIGNAL(clicked()), TQT_SLOT(deleteException()));
00343         TQWhatsThis::add(mDeleteExceptionButton,
00344               i18n("Remove the currently highlighted item from the exceptions list"));
00345         layout->addWidget(mDeleteExceptionButton);
00346     }
00347 
00348     mNoEmitTypeChanged = false;
00349 }
00350 
00351 /******************************************************************************
00352  * Verify the consistency of the entered data.
00353  * Reply = widget to receive focus on error, or 0 if no error.
00354  */
00355 TQWidget* RecurrenceEdit::checkData(const TQDateTime& startDateTime, TQString& errorMessage) const
00356 {
00357     if (mAtLoginButton->isOn())
00358         return 0;
00359     const_cast<RecurrenceEdit*>(this)->mCurrStartDateTime = startDateTime;
00360     if (mEndDateButton->isChecked())
00361     {
00362         TQWidget* errWidget = 0;
00363         bool noTime = !mEndTimeEdit->isEnabled();
00364         TQDate endDate = mEndDateEdit->date();
00365         if (endDate < startDateTime.date())
00366             errWidget = mEndDateEdit;
00367         else if (!noTime  &&  TQDateTime(endDate, mEndTimeEdit->time()) < startDateTime)
00368             errWidget = mEndTimeEdit;
00369         if (errWidget)
00370         {
00371             errorMessage = noTime
00372                          ? i18n("End date is earlier than start date")
00373                          : i18n("End date/time is earlier than start date/time");
00374             return errWidget;
00375         }
00376     }
00377     if (!mRule)
00378         return 0;
00379     return mRule->validate(errorMessage);
00380 }
00381 
00382 /******************************************************************************
00383  * Called when a recurrence period radio button is clicked.
00384  */
00385 void RecurrenceEdit::periodClicked(int id)
00386 {
00387     RepeatType oldType = mRuleButtonType;
00388     bool none     = (id == mNoneButtonId);
00389     bool atLogin  = (id == mAtLoginButtonId);
00390     bool subdaily = (id == mSubDailyButtonId);
00391     if (none)
00392     {
00393         mRule = 0;
00394         mRuleButtonType = NO_RECUR;
00395     }
00396     else if (atLogin)
00397     {
00398         mRule = 0;
00399         mRuleButtonType = AT_LOGIN;
00400         mRangeButtonGroup->setButton(mRangeButtonGroup->id(mEndDateButton));
00401     }
00402     else if (subdaily)
00403     {
00404         mRule = mSubDailyRule;
00405         mRuleButtonType = SUBDAILY;
00406     }
00407     else if (id == mDailyButtonId)
00408     {
00409         mRule = mDailyRule;
00410         mRuleButtonType = DAILY;
00411         mDailyShown = true;
00412     }
00413     else if (id == mWeeklyButtonId)
00414     {
00415         mRule = mWeeklyRule;
00416         mRuleButtonType = WEEKLY;
00417         mWeeklyShown = true;
00418     }
00419     else if (id == mMonthlyButtonId)
00420     {
00421         mRule = mMonthlyRule;
00422         mRuleButtonType = MONTHLY;
00423         mMonthlyShown = true;
00424     }
00425     else if (id == mYearlyButtonId)
00426     {
00427         mRule = mYearlyRule;
00428         mRuleButtonType = ANNUAL;
00429         mYearlyShown = true;
00430     }
00431     else
00432         return;
00433 
00434     if (mRuleButtonType != oldType)
00435     {
00436         mRuleStack->raiseWidget(mRule ? mRule : mNoRule);
00437         if (oldType == NO_RECUR  ||  none)
00438             mRangeButtonGroup->setEnabled(!none);
00439         mExceptionGroup->setEnabled(!(none || atLogin));
00440         mEndAnyTimeCheckBox->setEnabled(atLogin);
00441         if (!none)
00442         {
00443             mNoEndDateButton->setEnabled(!atLogin);
00444             mRepeatCountButton->setEnabled(!atLogin);
00445         }
00446         rangeTypeClicked();
00447         mSubRepetition->setEnabled(!(none || atLogin));
00448         if (!mNoEmitTypeChanged)
00449             emit typeChanged(mRuleButtonType);
00450     }
00451 }
00452 
00453 void RecurrenceEdit::slotAnyTimeToggled(bool on)
00454 {
00455     TQButton* button = mRuleButtonGroup->selected();
00456     mEndTimeEdit->setEnabled((button == mAtLoginButton && !on)
00457                          ||  (button == mSubDailyButton && mEndDateButton->isChecked()));
00458 }
00459 
00460 /******************************************************************************
00461  * Called when a recurrence range type radio button is clicked.
00462  */
00463 void RecurrenceEdit::rangeTypeClicked()
00464 {
00465     bool endDate = mEndDateButton->isOn();
00466     mEndDateEdit->setEnabled(endDate);
00467     mEndTimeEdit->setEnabled(endDate
00468                              &&  ((mAtLoginButton->isOn() && !mEndAnyTimeCheckBox->isChecked())
00469                                   ||  mSubDailyButton->isOn()));
00470     bool repeatCount = mRepeatCountButton->isOn();
00471     mRepeatCountEntry->setEnabled(repeatCount);
00472     mRepeatCountLabel->setEnabled(repeatCount);
00473 }
00474 
00475 void RecurrenceEdit::showEvent(TQShowEvent*)
00476 {
00477     if (mRule)
00478         mRule->setFrequencyFocus();
00479     else
00480         mRuleButtonGroup->selected()->setFocus();
00481     emit shown();
00482 }
00483 
00484  /******************************************************************************
00485 * Return the sub-repetition count within the recurrence, i.e. the number of
00486 * repetitions after the main recurrence.
00487 */
00488 int RecurrenceEdit::subRepeatCount(int* subRepeatInterval) const
00489 {
00490     int count = (mRuleButtonType >= SUBDAILY) ? mSubRepetition->count() : 0;
00491     if (subRepeatInterval)
00492         *subRepeatInterval = count ? mSubRepetition->interval() : 0;
00493     return count;
00494 }
00495 
00496 /******************************************************************************
00497 *  Called when the Sub-Repetition button has been pressed to display the
00498 *  sub-repetition dialog.
00499 *  Alarm repetition has the following restrictions:
00500 *  1) Not allowed for a repeat-at-login alarm
00501 *  2) For a date-only alarm, the repeat interval must be a whole number of days.
00502 *  3) The overall repeat duration must be less than the recurrence interval.
00503 */
00504 void RecurrenceEdit::setSubRepetition(int reminderMinutes, bool dateOnly)
00505 {
00506     int maxDuration;
00507     switch (mRuleButtonType)
00508     {
00509         case RecurrenceEdit::NO_RECUR:
00510         case RecurrenceEdit::AT_LOGIN:   // alarm repeat not allowed
00511             maxDuration = 0;
00512             break;
00513         default:          // repeat duration must be less than recurrence interval
00514         {
00515             KAEvent event;
00516             updateEvent(event, false);
00517             maxDuration = event.longestRecurrenceInterval() - reminderMinutes - 1;
00518             break;
00519         }
00520     }
00521     mSubRepetition->initialise(mSubRepetition->interval(), mSubRepetition->count(), dateOnly, maxDuration);
00522     mSubRepetition->setEnabled(mRuleButtonType >= SUBDAILY && maxDuration);
00523 }
00524 
00525 /******************************************************************************
00526 * Activate the sub-repetition dialog.
00527 */
00528 void RecurrenceEdit::activateSubRepetition()
00529 {
00530     mSubRepetition->activate();
00531 }
00532 
00533 /******************************************************************************
00534 * For weekly, monthly and yearly recurrence, checks that the specified date
00535 * matches the days allowed. For the other recurrence simply return true.
00536 */
00537 bool RecurrenceEdit::validateDate(const DateTime &date) const
00538 {
00539   if (mRuleButtonType == RecurrenceEdit::DAILY)
00540   {
00541     TQBitArray selectedDays = mDailyRule->days();
00542     if (!selectedDays[date.date().dayOfWeek()-1])
00543       return false;
00544   }
00545   else if (mRuleButtonType == RecurrenceEdit::WEEKLY)
00546   {
00547     TQBitArray selectedDays = mWeeklyRule->days();
00548     if (!selectedDays[date.date().dayOfWeek()-1])
00549       return false;
00550   }
00551   else if (mRuleButtonType == RecurrenceEdit::MONTHLY)
00552   {
00553     if (mMonthlyRule->type() == MonthYearRule::DATE)
00554     {
00555       // on the nth day of the month
00556       int comboDate = mMonthlyRule->date();
00557       if ((comboDate > 0 && date.date().day() != comboDate) ||
00558           (comboDate <=0 && date.date().day() != date.date().daysInMonth()))
00559         return false;
00560     }
00561     else
00562     {
00563       // on the nth weekday (i.e. Monday) of the month
00564       if (date.date().dayOfWeek() != mMonthlyRule->dayOfWeek())
00565         return false;
00566 
00567       int monthDay = date.date().day();
00568       int weekNum = mMonthlyRule->week();
00569       int minDay = 0, maxDay = 0;
00570       if (weekNum > 0 )
00571       {
00572         minDay = (weekNum-1) * 7;
00573         maxDay = weekNum * 7;
00574       }
00575       else if (weekNum < 0)
00576       {
00577         int dim = date.date().daysInMonth();
00578         minDay = dim + weekNum * 7;
00579         maxDay = dim + (weekNum+1) * 7;
00580       }
00581       if (monthDay <= minDay || monthDay > maxDay)
00582         return false;
00583     }
00584   }
00585   else if (mRuleButtonType == RecurrenceEdit::ANNUAL)
00586   {
00587         TQValueList<int> months = mYearlyRule->months();
00588     if (!months.contains(date.date().month()))
00589       return false;
00590 
00591     if (mYearlyRule->type() == MonthYearRule::DATE)
00592     {
00593       // on the nth day of the month
00594       int comboDate = mYearlyRule->date();
00595       if ((comboDate > 0 && date.date().day() != comboDate) ||
00596           (comboDate <=0 && date.date().day() != date.date().daysInMonth()))
00597         return false;
00598     }
00599     else
00600     {
00601       // on the nth weekday (i.e. Monday) of the month
00602       if (date.date().dayOfWeek() != mYearlyRule->dayOfWeek())
00603         return false;
00604 
00605       int monthDay = date.date().day();
00606       int weekNum = mYearlyRule->week();
00607       int minDay = 0, maxDay = 0;
00608       if (weekNum > 0 )
00609       {
00610         minDay = (weekNum-1) * 7;
00611         maxDay = weekNum * 7;
00612       }
00613       else if (weekNum < 0)
00614       {
00615         int dim = date.date().daysInMonth();
00616         minDay = dim + weekNum * 7;
00617         maxDay = dim + (weekNum+1) * 7;
00618       }
00619       if (monthDay <= minDay || monthDay > maxDay)
00620         return false;
00621     }
00622   }
00623   return true;
00624 }
00625 
00626 /******************************************************************************
00627  * Called when the value of the repeat count field changes, to reset the
00628  * minimum value to 1 if the value was 0.
00629  */
00630 void RecurrenceEdit::repeatCountChanged(int value)
00631 {
00632     if (value > 0  &&  mRepeatCountEntry->minValue() == 0)
00633         mRepeatCountEntry->setMinValue(1);
00634 }
00635 
00636 /******************************************************************************
00637  * Add the date entered in the exception date edit control to the list of
00638  * exception dates.
00639  */
00640 void RecurrenceEdit::addException()
00641 {
00642     if (!mExceptionDateEdit  ||  !mExceptionDateEdit->isValid())
00643         return;
00644     TQDate date = mExceptionDateEdit->date();
00645     TQValueList<TQDate>::Iterator it;
00646     int index = 0;
00647     bool insert = true;
00648     for (it = mExceptionDates.begin();  it != mExceptionDates.end();  ++index, ++it)
00649     {
00650         if (date <= *it)
00651         {
00652             insert = (date != *it);
00653             break;
00654         }
00655     }
00656     if (insert)
00657     {
00658         mExceptionDates.insert(it, date);
00659         mExceptionDateList->insertItem(TDEGlobal::locale()->formatDate(date), index);
00660     }
00661     mExceptionDateList->setCurrentItem(index);
00662     enableExceptionButtons();
00663 }
00664 
00665 /******************************************************************************
00666  * Change the currently highlighted exception date to that entered in the
00667  * exception date edit control.
00668  */
00669 void RecurrenceEdit::changeException()
00670 {
00671     if (!mExceptionDateEdit  ||  !mExceptionDateEdit->isValid())
00672         return;
00673     int index = mExceptionDateList->currentItem();
00674     if (index >= 0  &&  mExceptionDateList->isSelected(index))
00675     {
00676         TQDate olddate = mExceptionDates[index];
00677         TQDate newdate = mExceptionDateEdit->date();
00678         if (newdate != olddate)
00679         {
00680             mExceptionDates.remove(mExceptionDates.at(index));
00681             mExceptionDateList->removeItem(index);
00682             addException();
00683         }
00684     }
00685 }
00686 
00687 /******************************************************************************
00688  * Delete the currently highlighted exception date.
00689  */
00690 void RecurrenceEdit::deleteException()
00691 {
00692     int index = mExceptionDateList->currentItem();
00693     if (index >= 0  &&  mExceptionDateList->isSelected(index))
00694     {
00695         mExceptionDates.remove(mExceptionDates.at(index));
00696         mExceptionDateList->removeItem(index);
00697         enableExceptionButtons();
00698     }
00699 }
00700 
00701 /******************************************************************************
00702  * Enable/disable the exception group buttons according to whether any item is
00703  * selected in the exceptions listbox.
00704  */
00705 void RecurrenceEdit::enableExceptionButtons()
00706 {
00707     int index = mExceptionDateList->currentItem();
00708     bool enable = (index >= 0  &&  mExceptionDateList->isSelected(index));
00709     if (mDeleteExceptionButton)
00710         mDeleteExceptionButton->setEnabled(enable);
00711     if (mChangeExceptionButton)
00712         mChangeExceptionButton->setEnabled(enable);
00713 
00714     // Prevent the exceptions list box receiving keyboard focus is it's empty
00715     mExceptionDateList->setFocusPolicy(mExceptionDateList->count() ? TQ_WheelFocus : TQ_NoFocus);
00716 }
00717 
00718 /******************************************************************************
00719  * Notify this instance of a change in the alarm start date.
00720  */
00721 void RecurrenceEdit::setStartDate(const TQDate& start, const TQDate& today)
00722 {
00723     if (!mReadOnly)
00724     {
00725         setRuleDefaults(start);
00726         if (start < today)
00727         {
00728             mEndDateEdit->setMinDate(today);
00729             if (mExceptionDateEdit)
00730                 mExceptionDateEdit->setMinDate(today);
00731         }
00732         else
00733         {
00734             const TQString startString = i18n("Date cannot be earlier than start date", "start date");
00735             mEndDateEdit->setMinDate(start, startString);
00736             if (mExceptionDateEdit)
00737                 mExceptionDateEdit->setMinDate(start, startString);
00738         }
00739     }
00740 }
00741 
00742 /******************************************************************************
00743  * Specify the default recurrence end date.
00744  */
00745 void RecurrenceEdit::setDefaultEndDate(const TQDate& end)
00746 {
00747     if (!mEndDateButton->isOn())
00748         mEndDateEdit->setDate(end);
00749 }
00750 
00751 void RecurrenceEdit::setEndDateTime(const DateTime& end)
00752 {
00753     mEndDateEdit->setDate(end.date());
00754     mEndTimeEdit->setValue(end.time());
00755     mEndTimeEdit->setEnabled(!end.isDateOnly());
00756     mEndAnyTimeCheckBox->setChecked(end.isDateOnly());
00757 }
00758 
00759 DateTime RecurrenceEdit::endDateTime() const
00760 {
00761     if (mRuleButtonGroup->selected() == mAtLoginButton  &&  mEndAnyTimeCheckBox->isChecked())
00762         return DateTime(mEndDateEdit->date());
00763     return DateTime(mEndDateEdit->date(), mEndTimeEdit->time());
00764 }
00765 
00766 /******************************************************************************
00767  * Set all controls to their default values.
00768  */
00769 void RecurrenceEdit::setDefaults(const TQDateTime& from)
00770 {
00771     mCurrStartDateTime = from;
00772     TQDate fromDate = from.date();
00773     mNoEndDateButton->setChecked(true);
00774 
00775     mSubDailyRule->setFrequency(1);
00776     mDailyRule->setFrequency(1);
00777     mWeeklyRule->setFrequency(1);
00778     mMonthlyRule->setFrequency(1);
00779     mYearlyRule->setFrequency(1);
00780 
00781     setRuleDefaults(fromDate);
00782     mMonthlyRule->setType(MonthYearRule::DATE);   // date in month
00783     mYearlyRule->setType(MonthYearRule::DATE);    // date in year
00784 
00785     mEndDateEdit->setDate(fromDate);
00786 
00787     mNoEmitTypeChanged = true;
00788     int button;
00789     switch (Preferences::defaultRecurPeriod())
00790     {
00791         case AT_LOGIN: button = mAtLoginButtonId;  break;
00792         case ANNUAL:   button = mYearlyButtonId;   break;
00793         case MONTHLY:  button = mMonthlyButtonId;  break;
00794         case WEEKLY:   button = mWeeklyButtonId;   break;
00795         case DAILY:    button = mDailyButtonId;    break;
00796         case SUBDAILY: button = mSubDailyButtonId; break;
00797         case NO_RECUR:
00798         default:       button = mNoneButtonId;     break;
00799     }
00800     mRuleButtonGroup->setButton(button);
00801     mNoEmitTypeChanged = false;
00802     rangeTypeClicked();
00803     enableExceptionButtons();
00804 
00805     saveState();
00806 }
00807 
00808 /******************************************************************************
00809  * Set the controls for weekly, monthly and yearly rules which have not so far
00810  * been shown, to their default values, depending on the recurrence start date.
00811  */
00812 void RecurrenceEdit::setRuleDefaults(const TQDate& fromDate)
00813 {
00814     int day       = fromDate.day();
00815     int dayOfWeek = fromDate.dayOfWeek();
00816     int month     = fromDate.month();
00817     if (!mDailyShown)
00818         mDailyRule->setDays(true);
00819     if (!mWeeklyShown)
00820         mWeeklyRule->setDay(dayOfWeek);
00821     if (!mMonthlyShown)
00822         mMonthlyRule->setDefaultValues(day, dayOfWeek);
00823     if (!mYearlyShown)
00824         mYearlyRule->setDefaultValues(day, dayOfWeek, month);
00825 }
00826 
00827 /******************************************************************************
00828 * Set the state of all controls to reflect the data in the specified event.
00829 * Set 'keepDuration' true to prevent the recurrence count being adjusted to the
00830 * remaining number of recurrences.
00831 */
00832 void RecurrenceEdit::set(const KAEvent& event, bool keepDuration)
00833 {
00834     setDefaults(event.mainDateTime().dateTime());
00835     if (event.repeatAtLogin())
00836     {
00837         mRuleButtonGroup->setButton(mAtLoginButtonId);
00838         mEndDateButton->setChecked(true);
00839         return;
00840     }
00841     mRuleButtonGroup->setButton(mNoneButtonId);
00842     KARecurrence* recurrence = event.recurrence();
00843     if (!recurrence)
00844         return;
00845     KARecurrence::Type rtype = recurrence->type();
00846     switch (rtype)
00847     {
00848         case KARecurrence::MINUTELY:
00849             mRuleButtonGroup->setButton(mSubDailyButtonId);
00850             break;
00851 
00852         case KARecurrence::DAILY:
00853         {
00854             mRuleButtonGroup->setButton(mDailyButtonId);
00855             TQBitArray rDays = recurrence->days();
00856             bool set = false;
00857             for (int i = 0;  i < 7 && !set;  ++i)
00858                 set = rDays.testBit(i);
00859             if (set)
00860                 mDailyRule->setDays(rDays);
00861             else
00862                 mDailyRule->setDays(true);
00863             break;
00864         }
00865         case KARecurrence::WEEKLY:
00866         {
00867             mRuleButtonGroup->setButton(mWeeklyButtonId);
00868             TQBitArray rDays = recurrence->days();
00869             mWeeklyRule->setDays(rDays);
00870             break;
00871         }
00872         case KARecurrence::MONTHLY_POS:    // on nth (Tuesday) of the month
00873         {
00874             TQValueList<RecurrenceRule::WDayPos> posns = recurrence->monthPositions();
00875             int i = posns.first().pos();
00876             if (!i)
00877             {
00878                 // It's every (Tuesday) of the month. Convert to a weekly recurrence
00879                 // (but ignoring any non-every xxxDay positions).
00880                 mRuleButtonGroup->setButton(mWeeklyButtonId);
00881                 mWeeklyRule->setFrequency(recurrence->frequency());
00882                 TQBitArray rDays(7);
00883                 for (TQValueList<RecurrenceRule::WDayPos>::ConstIterator it = posns.begin();  it != posns.end();  ++it)
00884                 {
00885                     if (!(*it).pos())
00886                         rDays.setBit((*it).day() - 1, 1);
00887                 }
00888                 mWeeklyRule->setDays(rDays);
00889                 break;
00890             }
00891             mRuleButtonGroup->setButton(mMonthlyButtonId);
00892             mMonthlyRule->setPosition(i, posns.first().day());
00893             break;
00894         }
00895         case KARecurrence::MONTHLY_DAY:     // on nth day of the month
00896         {
00897             mRuleButtonGroup->setButton(mMonthlyButtonId);
00898             TQValueList<int> rmd = recurrence->monthDays();
00899             int day = (rmd.isEmpty()) ? event.mainDate().day() : rmd.first();
00900             mMonthlyRule->setDate(day);
00901             break;
00902         }
00903         case KARecurrence::ANNUAL_DATE:   // on the nth day of (months...) in the year
00904         case KARecurrence::ANNUAL_POS:     // on the nth (Tuesday) of (months...) in the year
00905         {
00906             if (rtype == KARecurrence::ANNUAL_DATE)
00907             {
00908                 mRuleButtonGroup->setButton(mYearlyButtonId);
00909                 const TQValueList<int> rmd = recurrence->monthDays();
00910                 int day = (rmd.isEmpty()) ? event.mainDate().day() : rmd.first();
00911                 mYearlyRule->setDate(day);
00912                 mYearlyRule->setFeb29Type(recurrence->feb29Type());
00913             }
00914             else if (rtype == KARecurrence::ANNUAL_POS)
00915             {
00916                 mRuleButtonGroup->setButton(mYearlyButtonId);
00917                 TQValueList<RecurrenceRule::WDayPos> posns = recurrence->yearPositions();
00918                 mYearlyRule->setPosition(posns.first().pos(), posns.first().day());
00919             }
00920             mYearlyRule->setMonths(recurrence->yearMonths());
00921             break;
00922         }
00923         default:
00924             return;
00925     }
00926 
00927     mRule->setFrequency(recurrence->frequency());
00928 
00929     // Get range information
00930     TQDateTime endtime = mCurrStartDateTime;
00931     int duration = recurrence->duration();
00932     if (duration == -1)
00933         mNoEndDateButton->setChecked(true);
00934     else if (duration)
00935     {
00936         mRepeatCountButton->setChecked(true);
00937         mRepeatCountEntry->setValue(duration);
00938     }
00939     else
00940     {
00941         mEndDateButton->setChecked(true);
00942         endtime = recurrence->endDateTime();
00943         mEndTimeEdit->setValue(endtime.time());
00944     }
00945     mEndDateEdit->setDate(endtime.date());
00946 
00947     // Get exception information
00948     mExceptionDates = event.recurrence()->exDates();
00949     qHeapSort(mExceptionDates);
00950     mExceptionDateList->clear();
00951     for (DateList::ConstIterator it = mExceptionDates.begin();  it != mExceptionDates.end();  ++it)
00952         mExceptionDateList->insertItem(TDEGlobal::locale()->formatDate(*it));
00953     enableExceptionButtons();
00954 
00955     // Get repetition within recurrence
00956     mSubRepetition->set(event.repeatInterval(), event.repeatCount());
00957 
00958     rangeTypeClicked();
00959 
00960     saveState();
00961 }
00962 
00963 /******************************************************************************
00964  * Update the specified KAEvent with the entered recurrence data.
00965  * If 'adjustStart' is true, the start date/time will be adjusted if necessary
00966  * to be the first date/time which recurs on or after the original start.
00967  */
00968 void RecurrenceEdit::updateEvent(KAEvent& event, bool adjustStart)
00969 {
00970     // Get end date and repeat count, common to all types of recurring events
00971     TQDate  endDate;
00972     TQTime  endTime;
00973     int    repeatCount;
00974     if (mNoEndDateButton->isChecked())
00975         repeatCount = -1;
00976     else if (mRepeatCountButton->isChecked())
00977         repeatCount = mRepeatCountEntry->value();
00978     else
00979     {
00980         repeatCount = 0;
00981         endDate = mEndDateEdit->date();
00982         endTime = mEndTimeEdit->time();
00983     }
00984 
00985     // Set up the recurrence according to the type selected
00986     TQButton* button = mRuleButtonGroup->selected();
00987     event.setRepeatAtLogin(button == mAtLoginButton);
00988     int frequency = mRule ? mRule->frequency() : 0;
00989     if (button == mSubDailyButton)
00990     {
00991         TQDateTime endDateTime(endDate, endTime);
00992         event.setRecurMinutely(frequency, repeatCount, endDateTime);
00993     }
00994     else if (button == mDailyButton)
00995     {
00996         event.setRecurDaily(frequency, mDailyRule->days(), repeatCount, endDate);
00997     }
00998     else if (button == mWeeklyButton)
00999     {
01000         event.setRecurWeekly(frequency, mWeeklyRule->days(), repeatCount, endDate);
01001     }
01002     else if (button == mMonthlyButton)
01003     {
01004         if (mMonthlyRule->type() == MonthlyRule::POS)
01005         {
01006             // It's by position
01007             KAEvent::MonthPos pos;
01008             pos.days.fill(false);
01009             pos.days.setBit(mMonthlyRule->dayOfWeek() - 1);
01010             pos.weeknum = mMonthlyRule->week();
01011             TQValueList<KAEvent::MonthPos> poses;
01012             poses.append(pos);
01013             event.setRecurMonthlyByPos(frequency, poses, repeatCount, endDate);
01014         }
01015         else
01016         {
01017             // It's by day
01018             int daynum = mMonthlyRule->date();
01019             TQValueList<int> daynums;
01020             daynums.append(daynum);
01021             event.setRecurMonthlyByDate(frequency, daynums, repeatCount, endDate);
01022         }
01023     }
01024     else if (button == mYearlyButton)
01025     {
01026         TQValueList<int> months = mYearlyRule->months();
01027         if (mYearlyRule->type() == YearlyRule::POS)
01028         {
01029             // It's by position
01030             KAEvent::MonthPos pos;
01031             pos.days.fill(false);
01032             pos.days.setBit(mYearlyRule->dayOfWeek() - 1);
01033             pos.weeknum = mYearlyRule->week();
01034             TQValueList<KAEvent::MonthPos> poses;
01035             poses.append(pos);
01036             event.setRecurAnnualByPos(frequency, poses, months, repeatCount, endDate);
01037         }
01038         else
01039         {
01040             // It's by date in month
01041             event.setRecurAnnualByDate(frequency, months, mYearlyRule->date(),
01042                                        mYearlyRule->feb29Type(), repeatCount, endDate);
01043         }
01044     }
01045     else
01046     {
01047         event.setNoRecur();
01048         return;
01049     }
01050     if (!event.recurs())
01051         return;    // an error occurred setting up the recurrence
01052     if (adjustStart)
01053         event.setFirstRecurrence();
01054 
01055     // Set up repetition within the recurrence.
01056     // N.B. This requires the main recurrence to be set up first.
01057     int count = mSubRepetition->count();
01058     if (mRuleButtonType < SUBDAILY)
01059         count = 0;
01060     event.setRepetition(mSubRepetition->interval(), count);
01061 
01062     // Set up exceptions
01063     event.recurrence()->setExDates(mExceptionDates);
01064 
01065     event.setUpdated();
01066 }
01067 
01068 /******************************************************************************
01069  * Save the state of all controls.
01070  */
01071 void RecurrenceEdit::saveState()
01072 {
01073     mSavedRuleButton = mRuleButtonGroup->selected();
01074     if (mRule)
01075         mRule->saveState();
01076     mSavedRangeButton = mRangeButtonGroup->selected();
01077     if (mSavedRangeButton == mRepeatCountButton)
01078         mSavedRecurCount = mRepeatCountEntry->value();
01079     else if (mSavedRangeButton == mEndDateButton)
01080         mSavedEndDateTime.set(TQDateTime(mEndDateEdit->date(), mEndTimeEdit->time()), mEndAnyTimeCheckBox->isChecked());
01081     mSavedExceptionDates = mExceptionDates;
01082     mSavedRepeatInterval = mSubRepetition->interval();
01083     mSavedRepeatCount    = mSubRepetition->count();
01084 }
01085 
01086 /******************************************************************************
01087  * Check whether any of the controls have changed state since initialisation.
01088  */
01089 bool RecurrenceEdit::stateChanged() const
01090 {
01091     if (mSavedRuleButton  != mRuleButtonGroup->selected()
01092     ||  mSavedRangeButton != mRangeButtonGroup->selected()
01093     ||  (mRule  &&  mRule->stateChanged()))
01094         return true;
01095     if (mSavedRangeButton == mRepeatCountButton
01096     &&  mSavedRecurCount  != mRepeatCountEntry->value())
01097         return true;
01098     if (mSavedRangeButton == mEndDateButton
01099     &&  mSavedEndDateTime != DateTime(TQDateTime(mEndDateEdit->date(), mEndTimeEdit->time()), mEndAnyTimeCheckBox->isChecked()))
01100         return true;
01101     if (mSavedExceptionDates != mExceptionDates
01102     ||  mSavedRepeatInterval != mSubRepetition->interval()
01103     ||  mSavedRepeatCount    != mSubRepetition->count())
01104         return true;
01105     return false;
01106 }
01107 
01108 
01109 
01110 /*=============================================================================
01111 = Class Rule
01112 = Base class for rule widgets, including recurrence frequency.
01113 =============================================================================*/
01114 
01115 Rule::Rule(const TQString& freqText, const TQString& freqWhatsThis, bool time, bool readOnly, TQWidget* parent, const char* name)
01116     : NoRule(parent, name)
01117 {
01118     mLayout = new TQVBoxLayout(this, 0, KDialog::spacingHint());
01119     TQHBox* freqBox = new TQHBox(this);
01120     mLayout->addWidget(freqBox);
01121     TQHBox* box = new TQHBox(freqBox);    // this is to control the TQWhatsThis text display area
01122     box->setSpacing(KDialog::spacingHint());
01123 
01124     TQLabel* label = new TQLabel(i18n("Recur e&very"), box);
01125     label->setFixedSize(label->sizeHint());
01126     if (time)
01127     {
01128         mIntSpinBox = 0;
01129         mSpinBox = mTimeSpinBox = new TimeSpinBox(1, 5999, box);
01130         mTimeSpinBox->setFixedSize(mTimeSpinBox->sizeHint());
01131         mTimeSpinBox->setReadOnly(readOnly);
01132     }
01133     else
01134     {
01135         mTimeSpinBox = 0;
01136         mSpinBox = mIntSpinBox = new SpinBox(1, 999, 1, box);
01137         mIntSpinBox->setFixedSize(mIntSpinBox->sizeHint());
01138         mIntSpinBox->setReadOnly(readOnly);
01139     }
01140     connect(mSpinBox, TQT_SIGNAL(valueChanged(int)), TQT_SIGNAL(frequencyChanged()));
01141     label->setBuddy(mSpinBox);
01142     label = new TQLabel(freqText, box);
01143     label->setFixedSize(label->sizeHint());
01144     box->setFixedSize(sizeHint());
01145     TQWhatsThis::add(box, freqWhatsThis);
01146 
01147     new TQWidget(freqBox);     // left adjust the visible widgets
01148     freqBox->setFixedHeight(freqBox->sizeHint().height());
01149     freqBox->setFocusProxy(mSpinBox);
01150 }
01151 
01152 int Rule::frequency() const
01153 {
01154     if (mIntSpinBox)
01155         return mIntSpinBox->value();
01156     if (mTimeSpinBox)
01157         return mTimeSpinBox->value();
01158     return 0;
01159 }
01160 
01161 void Rule::setFrequency(int n)
01162 {
01163     if (mIntSpinBox)
01164         mIntSpinBox->setValue(n);
01165     if (mTimeSpinBox)
01166         mTimeSpinBox->setValue(n);
01167 }
01168 
01169 /******************************************************************************
01170  * Save the state of all controls.
01171  */
01172 void Rule::saveState()
01173 {
01174     mSavedFrequency = frequency();
01175 }
01176 
01177 /******************************************************************************
01178  * Check whether any of the controls have changed state since initialisation.
01179  */
01180 bool Rule::stateChanged() const
01181 {
01182     return (mSavedFrequency != frequency());
01183 }
01184 
01185 
01186 /*=============================================================================
01187 = Class SubDailyRule
01188 = Sub-daily rule widget.
01189 =============================================================================*/
01190 
01191 SubDailyRule::SubDailyRule(bool readOnly, TQWidget* parent, const char* name)
01192     : Rule(i18n("hours:minutes"),
01193            i18n("Enter the number of hours and minutes between repetitions of the alarm"),
01194            true, readOnly, parent, name)
01195 { }
01196 
01197 
01198 /*=============================================================================
01199 = Class DayWeekRule
01200 = Daily/weekly rule widget base class.
01201 =============================================================================*/
01202 
01203 DayWeekRule::DayWeekRule(const TQString& freqText, const TQString& freqWhatsThis, const TQString& daysWhatsThis,
01204                          bool readOnly, TQWidget* parent, const char* name)
01205     : Rule(freqText, freqWhatsThis, false, readOnly, parent, name),
01206       mSavedDays(7)
01207 {
01208     TQGridLayout* grid = new TQGridLayout(layout(), 1, 4, KDialog::spacingHint());
01209     grid->setRowStretch(0, 1);
01210 
01211     TQLabel* label = new TQLabel(i18n("On: Tuesday", "O&n:"), this);
01212     label->setFixedSize(label->sizeHint());
01213     grid->addWidget(label, 0, 0, TQt::AlignRight | TQt::AlignTop);
01214     grid->addColSpacing(1, KDialog::spacingHint());
01215 
01216     // List the days of the week starting at the user's start day of the week.
01217     // Save the first day of the week, just in case it changes while the dialog is open.
01218     TQWidget* box = new TQWidget(this);   // this is to control the TQWhatsThis text display area
01219     TQGridLayout* dgrid = new TQGridLayout(box, 4, 2, 0, KDialog::spacingHint());
01220     const KCalendarSystem* calendar = TDEGlobal::locale()->calendar();
01221     for (int i = 0;  i < 7;  ++i)
01222     {
01223         int day = KAlarm::localeDayInWeek_to_weekDay(i);
01224         mDayBox[i] = new CheckBox(calendar->weekDayName(day), box);
01225         mDayBox[i]->setFixedSize(mDayBox[i]->sizeHint());
01226         mDayBox[i]->setReadOnly(readOnly);
01227         dgrid->addWidget(mDayBox[i], i%4, i/4, TQt::AlignAuto);
01228     }
01229     box->setFixedSize(box->sizeHint());
01230     TQWhatsThis::add(box, daysWhatsThis);
01231     grid->addWidget(box, 0, 2, TQt::AlignAuto);
01232     label->setBuddy(mDayBox[0]);
01233     grid->setColStretch(3, 1);
01234 }
01235 
01236 /******************************************************************************
01237  * Fetch which days of the week have been ticked.
01238  */
01239 TQBitArray DayWeekRule::days() const
01240 {
01241     TQBitArray ds(7);
01242     ds.fill(false);
01243     for (int i = 0;  i < 7;  ++i)
01244         if (mDayBox[i]->isChecked())
01245             ds.setBit(KAlarm::localeDayInWeek_to_weekDay(i) - 1, 1);
01246     return ds;
01247 }
01248 
01249 /******************************************************************************
01250  * Tick/untick every day of the week.
01251  */
01252 void DayWeekRule::setDays(bool tick)
01253 {
01254     for (int i = 0;  i < 7;  ++i)
01255         mDayBox[i]->setChecked(tick);
01256 }
01257 
01258 /******************************************************************************
01259  * Tick/untick each day of the week according to the specified bits.
01260  */
01261 void DayWeekRule::setDays(const TQBitArray& days)
01262 {
01263     for (int i = 0;  i < 7;  ++i)
01264     {
01265         bool x = days.testBit(KAlarm::localeDayInWeek_to_weekDay(i) - 1);
01266         mDayBox[i]->setChecked(x);
01267     }
01268 }
01269 
01270 /******************************************************************************
01271  * Tick the specified day of the week, and untick all other days.
01272  */
01273 void DayWeekRule::setDay(int dayOfWeek)
01274 {
01275     for (int i = 0;  i < 7;  ++i)
01276         mDayBox[i]->setChecked(false);
01277     if (dayOfWeek > 0  &&  dayOfWeek <= 7)
01278         mDayBox[KAlarm::weekDay_to_localeDayInWeek(dayOfWeek)]->setChecked(true);
01279 }
01280 
01281 /******************************************************************************
01282  * Validate: check that at least one day is selected.
01283  */
01284 TQWidget* DayWeekRule::validate(TQString& errorMessage)
01285 {
01286     for (int i = 0;  i < 7;  ++i)
01287         if (mDayBox[i]->isChecked())
01288             return 0;
01289     errorMessage = i18n("No day selected");
01290     return mDayBox[0];
01291 }
01292 
01293 /******************************************************************************
01294  * Save the state of all controls.
01295  */
01296 void DayWeekRule::saveState()
01297 {
01298     Rule::saveState();
01299     mSavedDays = days();
01300 }
01301 
01302 /******************************************************************************
01303  * Check whether any of the controls have changed state since initialisation.
01304  */
01305 bool DayWeekRule::stateChanged() const
01306 {
01307     return (Rule::stateChanged()
01308         ||  mSavedDays != days());
01309 }
01310 
01311 
01312 /*=============================================================================
01313 = Class DailyRule
01314 = Daily rule widget.
01315 =============================================================================*/
01316 
01317 DailyRule::DailyRule(bool readOnly, TQWidget* parent, const char* name)
01318     : DayWeekRule(i18n("day(s)"),
01319                   i18n("Enter the number of days between repetitions of the alarm"),
01320                   i18n("Select the days of the week on which the alarm is allowed to occur"),
01321                   readOnly, parent, name)
01322 { }
01323 
01324 
01325 /*=============================================================================
01326 = Class WeeklyRule
01327 = Weekly rule widget.
01328 =============================================================================*/
01329 
01330 WeeklyRule::WeeklyRule(bool readOnly, TQWidget* parent, const char* name)
01331     : DayWeekRule(i18n("week(s)"),
01332                   i18n("Enter the number of weeks between repetitions of the alarm"),
01333                   i18n("Select the days of the week on which to repeat the alarm"),
01334                   readOnly, parent, name)
01335 { }
01336 
01337 
01338 /*=============================================================================
01339 = Class MonthYearRule
01340 = Monthly/yearly rule widget base class.
01341 =============================================================================*/
01342 
01343 MonthYearRule::MonthYearRule(const TQString& freqText, const TQString& freqWhatsThis, bool allowEveryWeek,
01344                              bool readOnly, TQWidget* parent, const char* name)
01345     : Rule(freqText, freqWhatsThis, false, readOnly, parent, name),
01346       mEveryWeek(allowEveryWeek)
01347 {
01348     mButtonGroup = new ButtonGroup(this);
01349     mButtonGroup->hide();
01350 
01351     // Month day selector
01352     TQHBox* box = new TQHBox(this);
01353     box->setSpacing(KDialog::spacingHint());
01354     layout()->addWidget(box);
01355 
01356     mDayButton = new RadioButton(i18n("On day number in the month", "O&n day"), box);
01357     mDayButton->setFixedSize(mDayButton->sizeHint());
01358     mDayButton->setReadOnly(readOnly);
01359     mDayButtonId = mButtonGroup->insert(mDayButton);
01360     TQWhatsThis::add(mDayButton, i18n("Repeat the alarm on the selected day of the month"));
01361 
01362     mDayCombo = new ComboBox(false, box);
01363     mDayCombo->setSizeLimit(11);
01364     for (int i = 0;  i < 31;  ++i)
01365         mDayCombo->insertItem(TQString::number(i + 1));
01366     mDayCombo->insertItem(i18n("Last day of month", "Last"));
01367     mDayCombo->setFixedSize(mDayCombo->sizeHint());
01368     mDayCombo->setReadOnly(readOnly);
01369     TQWhatsThis::add(mDayCombo, i18n("Select the day of the month on which to repeat the alarm"));
01370     mDayButton->setFocusWidget(mDayCombo);
01371     connect(mDayCombo, TQT_SIGNAL(activated(int)), TQT_SLOT(slotDaySelected(int)));
01372 
01373     box->setStretchFactor(new TQWidget(box), 1);    // left adjust the controls
01374     box->setFixedHeight(box->sizeHint().height());
01375 
01376     // Month position selector
01377     box = new TQHBox(this);
01378     box->setSpacing(KDialog::spacingHint());
01379     layout()->addWidget(box);
01380 
01381     mPosButton = new RadioButton(i18n("On the 1st Tuesday", "On t&he"), box);
01382     mPosButton->setFixedSize(mPosButton->sizeHint());
01383     mPosButton->setReadOnly(readOnly);
01384     mPosButtonId = mButtonGroup->insert(mPosButton);
01385     TQWhatsThis::add(mPosButton,
01386           i18n("Repeat the alarm on one day of the week, in the selected week of the month"));
01387 
01388     mWeekCombo = new ComboBox(false, box);
01389     mWeekCombo->insertItem(i18n("1st"));
01390     mWeekCombo->insertItem(i18n("2nd"));
01391     mWeekCombo->insertItem(i18n("3rd"));
01392     mWeekCombo->insertItem(i18n("4th"));
01393     mWeekCombo->insertItem(i18n("5th"));
01394     mWeekCombo->insertItem(i18n("Last Monday in March", "Last"));
01395     mWeekCombo->insertItem(i18n("2nd Last"));
01396     mWeekCombo->insertItem(i18n("3rd Last"));
01397     mWeekCombo->insertItem(i18n("4th Last"));
01398     mWeekCombo->insertItem(i18n("5th Last"));
01399     if (mEveryWeek)
01400     {
01401         mWeekCombo->insertItem(i18n("Every (Monday...) in month", "Every"));
01402         mWeekCombo->setSizeLimit(11);
01403     }
01404     TQWhatsThis::add(mWeekCombo, i18n("Select the week of the month in which to repeat the alarm"));
01405     mWeekCombo->setFixedSize(mWeekCombo->sizeHint());
01406     mWeekCombo->setReadOnly(readOnly);
01407     mPosButton->setFocusWidget(mWeekCombo);
01408 
01409     mDayOfWeekCombo = new ComboBox(false, box);
01410     const KCalendarSystem* calendar = TDEGlobal::locale()->calendar();
01411     for (int i = 0;  i < 7;  ++i)
01412     {
01413         int day = KAlarm::localeDayInWeek_to_weekDay(i);
01414         mDayOfWeekCombo->insertItem(calendar->weekDayName(day));
01415     }
01416     mDayOfWeekCombo->setReadOnly(readOnly);
01417     TQWhatsThis::add(mDayOfWeekCombo, i18n("Select the day of the week on which to repeat the alarm"));
01418 
01419     box->setStretchFactor(new TQWidget(box), 1);    // left adjust the controls
01420     box->setFixedHeight(box->sizeHint().height());
01421     connect(mButtonGroup, TQT_SIGNAL(buttonSet(int)), TQT_SLOT(clicked(int)));
01422 }
01423 
01424 MonthYearRule::DayPosType MonthYearRule::type() const
01425 {
01426     return (mButtonGroup->selectedId() == mDayButtonId) ? DATE : POS;
01427 }
01428 
01429 void MonthYearRule::setType(MonthYearRule::DayPosType type)
01430 {
01431     mButtonGroup->setButton(type == DATE ? mDayButtonId : mPosButtonId);
01432 }
01433 
01434 void MonthYearRule::setDefaultValues(int dayOfMonth, int dayOfWeek)
01435 {
01436     --dayOfMonth;
01437     mDayCombo->setCurrentItem(dayOfMonth);
01438     mWeekCombo->setCurrentItem(dayOfMonth / 7);
01439     mDayOfWeekCombo->setCurrentItem(KAlarm::weekDay_to_localeDayInWeek(dayOfWeek));
01440 }
01441 
01442 int MonthYearRule::date() const
01443 {
01444     int daynum  = mDayCombo->currentItem() + 1;
01445     return (daynum <= 31) ? daynum : 31 - daynum;
01446 }
01447 
01448 int MonthYearRule::week() const
01449 {
01450     int weeknum = mWeekCombo->currentItem() + 1;
01451     return (weeknum <= 5) ? weeknum : (weeknum == 11) ? 0 : 5 - weeknum;
01452 }
01453 
01454 int MonthYearRule::dayOfWeek() const
01455 {
01456     return KAlarm::localeDayInWeek_to_weekDay(mDayOfWeekCombo->currentItem());
01457 }
01458 
01459 void MonthYearRule::setDate(int dayOfMonth)
01460 {
01461     mButtonGroup->setButton(mDayButtonId);
01462     mDayCombo->setCurrentItem(dayOfMonth > 0 ? dayOfMonth - 1 : dayOfMonth < 0 ? 30 - dayOfMonth : 0);   // day 0 shouldn't ever occur
01463 }
01464 
01465 void MonthYearRule::setPosition(int week, int dayOfWeek)
01466 {
01467     mButtonGroup->setButton(mPosButtonId);
01468     mWeekCombo->setCurrentItem((week > 0) ? week - 1 : (week < 0) ? 4 - week : mEveryWeek ? 10 : 0);
01469     mDayOfWeekCombo->setCurrentItem(KAlarm::weekDay_to_localeDayInWeek(dayOfWeek));
01470 }
01471 
01472 void MonthYearRule::enableSelection(DayPosType type)
01473 {
01474     bool date = (type == DATE);
01475     mDayCombo->setEnabled(date);
01476     mWeekCombo->setEnabled(!date);
01477     mDayOfWeekCombo->setEnabled(!date);
01478 }
01479 
01480 void MonthYearRule::clicked(int id)
01481 {
01482     enableSelection(id == mDayButtonId ? DATE : POS);
01483 }
01484 
01485 void MonthYearRule::slotDaySelected(int index)
01486 {
01487     daySelected(index <= 30 ? index + 1 : 30 - index);
01488 }
01489 
01490 /******************************************************************************
01491  * Save the state of all controls.
01492  */
01493 void MonthYearRule::saveState()
01494 {
01495     Rule::saveState();
01496     mSavedType = type();
01497     if (mSavedType == DATE)
01498         mSavedDay = date();
01499     else
01500     {
01501         mSavedWeek    = week();
01502         mSavedWeekDay = dayOfWeek();
01503     }
01504 }
01505 
01506 /******************************************************************************
01507  * Check whether any of the controls have changed state since initialisation.
01508  */
01509 bool MonthYearRule::stateChanged() const
01510 {
01511     if (Rule::stateChanged()
01512     ||  mSavedType != type())
01513         return true;
01514     if (mSavedType == DATE)
01515     {
01516         if (mSavedDay != date())
01517             return true;
01518     }
01519     else
01520     {
01521         if (mSavedWeek    != week()
01522         ||  mSavedWeekDay != dayOfWeek())
01523             return true;
01524     }
01525     return false;
01526 }
01527 
01528 
01529 /*=============================================================================
01530 = Class MonthlyRule
01531 = Monthly rule widget.
01532 =============================================================================*/
01533 
01534 MonthlyRule::MonthlyRule(bool readOnly, TQWidget* parent, const char* name)
01535     : MonthYearRule(i18n("month(s)"),
01536            i18n("Enter the number of months between repetitions of the alarm"),
01537            false, readOnly, parent, name)
01538 { }
01539 
01540 
01541 /*=============================================================================
01542 = Class YearlyRule
01543 = Yearly rule widget.
01544 =============================================================================*/
01545 
01546 YearlyRule::YearlyRule(bool readOnly, TQWidget* parent, const char* name)
01547     : MonthYearRule(i18n("year(s)"),
01548            i18n("Enter the number of years between repetitions of the alarm"),
01549            true, readOnly, parent, name)
01550 {
01551     // Set up the month selection widgets
01552     TQBoxLayout* hlayout = new TQHBoxLayout(layout(), KDialog::spacingHint());
01553     TQLabel* label = new TQLabel(i18n("List of months to select", "Months:"), this);
01554     label->setFixedSize(label->sizeHint());
01555     hlayout->addWidget(label, 0, TQt::AlignAuto | TQt::AlignTop);
01556 
01557     // List the months of the year.
01558     TQWidget* w = new TQWidget(this);   // this is to control the TQWhatsThis text display area
01559     hlayout->addWidget(w, 1, TQt::AlignAuto);
01560     TQGridLayout* grid = new TQGridLayout(w, 4, 3, 0, KDialog::spacingHint());
01561     const KCalendarSystem* calendar = TDEGlobal::locale()->calendar();
01562     int year = TQDate::currentDate().year();
01563     for (int i = 0;  i < 12;  ++i)
01564     {
01565         mMonthBox[i] = new CheckBox(calendar->monthName(i + 1, year, true), w);
01566         mMonthBox[i]->setFixedSize(mMonthBox[i]->sizeHint());
01567         mMonthBox[i]->setReadOnly(readOnly);
01568         grid->addWidget(mMonthBox[i], i%3, i/3, TQt::AlignAuto);
01569     }
01570     connect(mMonthBox[1], TQT_SIGNAL(toggled(bool)), TQT_SLOT(enableFeb29()));
01571     w->setFixedHeight(w->sizeHint().height());
01572     TQWhatsThis::add(w, i18n("Select the months of the year in which to repeat the alarm"));
01573 
01574     // February 29th handling option
01575     TQHBox* f29box = new TQHBox(this);
01576     layout()->addWidget(f29box);
01577     TQHBox* box = new TQHBox(f29box);    // this is to control the TQWhatsThis text display area
01578     box->setSpacing(KDialog::spacingHint());
01579     mFeb29Label = new TQLabel(i18n("February 2&9th alarm in non-leap years:"), box);
01580     mFeb29Label->setFixedSize(mFeb29Label->sizeHint());
01581     mFeb29Combo = new ComboBox(false, box);
01582     mFeb29Combo->insertItem(i18n("No date", "None"));
01583     mFeb29Combo->insertItem(i18n("1st March (short form)", "1 Mar"));
01584     mFeb29Combo->insertItem(i18n("28th February (short form)", "28 Feb"));
01585     mFeb29Combo->setFixedSize(mFeb29Combo->sizeHint());
01586     mFeb29Combo->setReadOnly(readOnly);
01587     mFeb29Label->setBuddy(mFeb29Combo);
01588     box->setFixedSize(box->sizeHint());
01589     TQWhatsThis::add(box,
01590           i18n("Select which date, if any, the February 29th alarm should trigger in non-leap years"));
01591     new TQWidget(f29box);     // left adjust the visible widgets
01592     f29box->setFixedHeight(f29box->sizeHint().height());
01593 }
01594 
01595 void YearlyRule::setDefaultValues(int dayOfMonth, int dayOfWeek, int month)
01596 {
01597     MonthYearRule::setDefaultValues(dayOfMonth, dayOfWeek);
01598     --month;
01599     for (int i = 0;  i < 12;  ++i)
01600         mMonthBox[i]->setChecked(i == month);
01601     setFeb29Type(Preferences::defaultFeb29Type());
01602     daySelected(dayOfMonth);     // enable/disable month checkboxes as appropriate
01603 }
01604 
01605 /******************************************************************************
01606  * Fetch which months have been checked (1 - 12).
01607  * Reply = true if February has been checked.
01608  */
01609 TQValueList<int> YearlyRule::months() const
01610 {
01611     TQValueList<int> mnths;
01612     for (int i = 0;  i < 12;  ++i)
01613         if (mMonthBox[i]->isChecked()  &&  mMonthBox[i]->isEnabled())
01614             mnths.append(i + 1);
01615     return mnths;
01616 }
01617 
01618 /******************************************************************************
01619  * Check/uncheck each month of the year according to the specified list.
01620  */
01621 void YearlyRule::setMonths(const TQValueList<int>& mnths)
01622 {
01623     bool checked[12];
01624     for (int i = 0;  i < 12;  ++i)
01625         checked[i] = false;
01626     for (TQValueListConstIterator<int> it = mnths.begin();  it != mnths.end();  ++it)
01627         checked[(*it) - 1] = true;
01628     for (int i = 0;  i < 12;  ++i)
01629         mMonthBox[i]->setChecked(checked[i]);
01630     enableFeb29();
01631 }
01632 
01633 /******************************************************************************
01634  * Return the date for February 29th alarms in non-leap years.
01635  */
01636 KARecurrence::Feb29Type YearlyRule::feb29Type() const
01637 {
01638     if (mFeb29Combo->isEnabled())
01639     {
01640         switch (mFeb29Combo->currentItem())
01641         {
01642             case 1:   return KARecurrence::FEB29_MAR1;
01643             case 2:   return KARecurrence::FEB29_FEB28;
01644             default:  break;
01645         }
01646     }
01647     return KARecurrence::FEB29_FEB29;
01648 }
01649 
01650 /******************************************************************************
01651  * Set the date for February 29th alarms to trigger in non-leap years.
01652  */
01653 void YearlyRule::setFeb29Type(KARecurrence::Feb29Type type)
01654 {
01655     int index;
01656     switch (type)
01657     {
01658         default:
01659         case KARecurrence::FEB29_FEB29:  index = 0;  break;
01660         case KARecurrence::FEB29_MAR1:   index = 1;  break;
01661         case KARecurrence::FEB29_FEB28:  index = 2;  break;
01662     }
01663     mFeb29Combo->setCurrentItem(index);
01664 }
01665 
01666 /******************************************************************************
01667  * Validate: check that at least one month is selected.
01668  */
01669 TQWidget* YearlyRule::validate(TQString& errorMessage)
01670 {
01671     for (int i = 0;  i < 12;  ++i)
01672         if (mMonthBox[i]->isChecked()  &&  mMonthBox[i]->isEnabled())
01673             return 0;
01674     errorMessage = i18n("No month selected");
01675     return mMonthBox[0];
01676 }
01677 
01678 /******************************************************************************
01679  * Called when a yearly recurrence type radio button is clicked,
01680  * to enable/disable month checkboxes as appropriate for the date selected.
01681  */
01682 void YearlyRule::clicked(int id)
01683 {
01684     MonthYearRule::clicked(id);
01685     daySelected(buttonType(id) == DATE ? date() : 1);
01686 }
01687 
01688 /******************************************************************************
01689  * Called when a day of the month is selected in a yearly recurrence, to
01690  * disable months for which the day is out of range.
01691  */
01692 void YearlyRule::daySelected(int day)
01693 {
01694     mMonthBox[1]->setEnabled(day <= 29);  // February
01695     bool enable = (day != 31);
01696     mMonthBox[3]->setEnabled(enable);     // April
01697     mMonthBox[5]->setEnabled(enable);     // June
01698     mMonthBox[8]->setEnabled(enable);     // September
01699     mMonthBox[10]->setEnabled(enable);    // November
01700     enableFeb29();
01701 }
01702 
01703 /******************************************************************************
01704  * Enable/disable the February 29th combo box depending on whether February
01705  * 29th is selected.
01706  */
01707 void YearlyRule::enableFeb29()
01708 {
01709     bool enable = (type() == DATE  &&  date() == 29  &&  mMonthBox[1]->isChecked()  &&  mMonthBox[1]->isEnabled());
01710     mFeb29Label->setEnabled(enable);
01711     mFeb29Combo->setEnabled(enable);
01712 }
01713 
01714 /******************************************************************************
01715  * Save the state of all controls.
01716  */
01717 void YearlyRule::saveState()
01718 {
01719     MonthYearRule::saveState();
01720     mSavedMonths    = months();
01721     mSavedFeb29Type = feb29Type();
01722 }
01723 
01724 /******************************************************************************
01725  * Check whether any of the controls have changed state since initialisation.
01726  */
01727 bool YearlyRule::stateChanged() const
01728 {
01729     return (MonthYearRule::stateChanged()
01730         ||  mSavedMonths    != months()
01731         ||  mSavedFeb29Type != feb29Type());
01732 }