00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "kalarm.h"
00025
00026 #include <qtooltip.h>
00027 #include <qlayout.h>
00028 #include <qvbox.h>
00029 #include <qwidgetstack.h>
00030 #include <qlistbox.h>
00031 #include <qframe.h>
00032 #include <qlabel.h>
00033 #include <qpushbutton.h>
00034 #include <qlineedit.h>
00035 #include <qwhatsthis.h>
00036
00037 #include <kglobal.h>
00038 #include <klocale.h>
00039 #include <kiconloader.h>
00040 #include <kdialog.h>
00041 #include <kmessagebox.h>
00042 #include <kdebug.h>
00043
00044 #include <libkcal/event.h>
00045
00046 #include "alarmevent.h"
00047 #include "alarmtimewidget.h"
00048 #include "checkbox.h"
00049 #include "combobox.h"
00050 #include "dateedit.h"
00051 #include "functions.h"
00052 #include "kalarmapp.h"
00053 #include "karecurrence.h"
00054 #include "preferences.h"
00055 #include "radiobutton.h"
00056 #include "spinbox.h"
00057 #include "timeedit.h"
00058 #include "timespinbox.h"
00059 #include "buttongroup.h"
00060 using namespace KCal;
00061
00062 #include "recurrenceedit.moc"
00063 #include "recurrenceeditprivate.moc"
00064
00065 static QString weekDayName(int day, const KLocale*);
00066
00067
00068
00069 QString RecurrenceEdit::i18n_Norecur() { return i18n("No recurrence"); }
00070 QString RecurrenceEdit::i18n_NoRecur() { return i18n("No Recurrence"); }
00071 QString RecurrenceEdit::i18n_AtLogin() { return i18n("At Login"); }
00072 QString RecurrenceEdit::i18n_l_Atlogin() { return i18n("At &login"); }
00073 QString RecurrenceEdit::i18n_HourlyMinutely() { return i18n("Hourly/Minutely"); }
00074 QString RecurrenceEdit::i18n_u_HourlyMinutely() { return i18n("Ho&urly/Minutely"); }
00075 QString RecurrenceEdit::i18n_Daily() { return i18n("Daily"); }
00076 QString RecurrenceEdit::i18n_d_Daily() { return i18n("&Daily"); }
00077 QString RecurrenceEdit::i18n_Weekly() { return i18n("Weekly"); }
00078 QString RecurrenceEdit::i18n_w_Weekly() { return i18n("&Weekly"); }
00079 QString RecurrenceEdit::i18n_Monthly() { return i18n("Monthly"); }
00080 QString RecurrenceEdit::i18n_m_Monthly() { return i18n("&Monthly"); }
00081 QString RecurrenceEdit::i18n_Yearly() { return i18n("Yearly"); }
00082 QString RecurrenceEdit::i18n_y_Yearly() { return i18n("&Yearly"); }
00083
00084
00085 RecurrenceEdit::RecurrenceEdit(bool readOnly, QWidget* parent, const char* name)
00086 : QFrame(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 QBoxLayout* layout;
00097 QVBoxLayout* topLayout = new QVBoxLayout(this, 0, KDialog::spacingHint());
00098
00099
00100
00101
00102
00103
00104
00105
00106 QGroupBox* recurGroup = new QGroupBox(1, Qt::Vertical, i18n("Recurrence Rule"), this, "recurGroup");
00107 topLayout->addWidget(recurGroup);
00108 QFrame* ruleFrame = new QFrame(recurGroup, "ruleFrame");
00109 layout = new QVBoxLayout(ruleFrame, 0);
00110 layout->addSpacing(KDialog::spacingHint()/2);
00111
00112 layout = new QHBoxLayout(layout, 0);
00113 QBoxLayout* lay = new QVBoxLayout(layout, 0);
00114 mRuleButtonGroup = new ButtonGroup(1, Qt::Horizontal, ruleFrame);
00115 mRuleButtonGroup->setInsideMargin(0);
00116 mRuleButtonGroup->setFrameStyle(QFrame::NoFrame);
00117 lay->addWidget(mRuleButtonGroup);
00118 lay->addStretch();
00119 connect(mRuleButtonGroup, SIGNAL(buttonSet(int)), SLOT(periodClicked(int)));
00120
00121 mNoneButton = new RadioButton(i18n_Norecur(), mRuleButtonGroup);
00122 mNoneButton->setFixedSize(mNoneButton->sizeHint());
00123 mNoneButton->setReadOnly(mReadOnly);
00124 QWhatsThis::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 QWhatsThis::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 QWhatsThis::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 QWhatsThis::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 QWhatsThis::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 QWhatsThis::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 QWhatsThis::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 lay = new QVBoxLayout(layout);
00172
00173 lay->addStretch();
00174 layout = new QHBoxLayout(lay);
00175
00176 layout->addSpacing(KDialog::marginHint());
00177 QFrame* divider = new QFrame(ruleFrame);
00178 divider->setFrameStyle(QFrame::VLine | QFrame::Sunken);
00179 layout->addWidget(divider);
00180 layout->addSpacing(KDialog::marginHint());
00181
00182 mNoRule = new NoRule(ruleFrame, "noFrame");
00183 mSubDailyRule = new SubDailyRule(mReadOnly, ruleFrame, "subdayFrame");
00184 mDailyRule = new DailyRule(mReadOnly, ruleFrame, "dayFrame");
00185 mWeeklyRule = new WeeklyRule(mReadOnly, ruleFrame, "weekFrame");
00186 mMonthlyRule = new MonthlyRule(mReadOnly, ruleFrame, "monthFrame");
00187 mYearlyRule = new YearlyRule(mReadOnly, ruleFrame, "yearFrame");
00188
00189 connect(mSubDailyRule, SIGNAL(frequencyChanged()), this, SIGNAL(frequencyChanged()));
00190 connect(mDailyRule, SIGNAL(frequencyChanged()), this, SIGNAL(frequencyChanged()));
00191 connect(mWeeklyRule, SIGNAL(frequencyChanged()), this, SIGNAL(frequencyChanged()));
00192 connect(mMonthlyRule, SIGNAL(frequencyChanged()), this, SIGNAL(frequencyChanged()));
00193 connect(mYearlyRule, SIGNAL(frequencyChanged()), this, SIGNAL(frequencyChanged()));
00194
00195 mRuleStack = new QWidgetStack(ruleFrame);
00196 layout->addWidget(mRuleStack);
00197 layout->addStretch(1);
00198 mRuleStack->addWidget(mNoRule, 0);
00199 mRuleStack->addWidget(mSubDailyRule, 1);
00200 mRuleStack->addWidget(mDailyRule, 2);
00201 mRuleStack->addWidget(mWeeklyRule, 3);
00202 mRuleStack->addWidget(mMonthlyRule, 4);
00203 mRuleStack->addWidget(mYearlyRule, 5);
00204 layout->addSpacing(KDialog::marginHint());
00205
00206
00207
00208
00209 mRangeButtonGroup = new ButtonGroup(i18n("Recurrence End"), this, "mRangeButtonGroup");
00210 connect(mRangeButtonGroup, SIGNAL(buttonSet(int)), SLOT(rangeTypeClicked()));
00211 topLayout->addWidget(mRangeButtonGroup);
00212
00213 QVBoxLayout* vlayout = new QVBoxLayout(mRangeButtonGroup, KDialog::marginHint(), KDialog::spacingHint());
00214 vlayout->addSpacing(fontMetrics().lineSpacing()/2);
00215 mNoEndDateButton = new RadioButton(i18n("No &end"), mRangeButtonGroup);
00216 mNoEndDateButton->setFixedSize(mNoEndDateButton->sizeHint());
00217 mNoEndDateButton->setReadOnly(mReadOnly);
00218 QWhatsThis::add(mNoEndDateButton, i18n("Repeat the alarm indefinitely"));
00219 vlayout->addWidget(mNoEndDateButton, 1, Qt::AlignAuto);
00220 QSize size = mNoEndDateButton->size();
00221
00222 layout = new QHBoxLayout(vlayout, KDialog::spacingHint());
00223 mRepeatCountButton = new RadioButton(i18n("End a&fter:"), mRangeButtonGroup);
00224 mRepeatCountButton->setReadOnly(mReadOnly);
00225 QWhatsThis::add(mRepeatCountButton,
00226 i18n("Repeat the alarm for the number of times specified"));
00227 mRepeatCountEntry = new SpinBox(1, 9999, 1, mRangeButtonGroup);
00228 mRepeatCountEntry->setFixedSize(mRepeatCountEntry->sizeHint());
00229 mRepeatCountEntry->setLineShiftStep(10);
00230 mRepeatCountEntry->setSelectOnStep(false);
00231 mRepeatCountEntry->setReadOnly(mReadOnly);
00232 connect(mRepeatCountEntry, SIGNAL(valueChanged(int)), SLOT(repeatCountChanged(int)));
00233 QWhatsThis::add(mRepeatCountEntry,
00234 i18n("Enter the total number of times to trigger the alarm"));
00235 mRepeatCountButton->setFocusWidget(mRepeatCountEntry);
00236 mRepeatCountLabel = new QLabel(i18n("occurrence(s)"), mRangeButtonGroup);
00237 mRepeatCountLabel->setFixedSize(mRepeatCountLabel->sizeHint());
00238 layout->addWidget(mRepeatCountButton);
00239 layout->addSpacing(KDialog::spacingHint());
00240 layout->addWidget(mRepeatCountEntry);
00241 layout->addWidget(mRepeatCountLabel);
00242 layout->addStretch();
00243 size = size.expandedTo(mRepeatCountButton->sizeHint());
00244
00245 layout = new QHBoxLayout(vlayout, KDialog::spacingHint());
00246 mEndDateButton = new RadioButton(i18n("End &by:"), mRangeButtonGroup);
00247 mEndDateButton->setReadOnly(mReadOnly);
00248 QWhatsThis::add(mEndDateButton,
00249 i18n("Repeat the alarm until the date/time specified"));
00250 mEndDateEdit = new DateEdit(mRangeButtonGroup);
00251 mEndDateEdit->setFixedSize(mEndDateEdit->sizeHint());
00252 mEndDateEdit->setReadOnly(mReadOnly);
00253 QWhatsThis::add(mEndDateEdit,
00254 i18n("Enter the last date to repeat the alarm"));
00255 mEndDateButton->setFocusWidget(mEndDateEdit);
00256 mEndTimeEdit = new TimeEdit(mRangeButtonGroup);
00257 mEndTimeEdit->setFixedSize(mEndTimeEdit->sizeHint());
00258 mEndTimeEdit->setReadOnly(mReadOnly);
00259 static const QString lastTimeText = i18n("Enter the last time to repeat the alarm.");
00260 QWhatsThis::add(mEndTimeEdit, QString("%1\n\n%2").arg(lastTimeText).arg(TimeSpinBox::shiftWhatsThis()));
00261 mEndAnyTimeCheckBox = new CheckBox(i18n("Any time"), mRangeButtonGroup);
00262 mEndAnyTimeCheckBox->setFixedSize(mEndAnyTimeCheckBox->sizeHint());
00263 mEndAnyTimeCheckBox->setReadOnly(mReadOnly);
00264 connect(mEndAnyTimeCheckBox, SIGNAL(toggled(bool)), SLOT(slotAnyTimeToggled(bool)));
00265 QWhatsThis::add(mEndAnyTimeCheckBox,
00266 i18n("Stop repeating the alarm after your first login on or after the specified end date"));
00267 layout->addWidget(mEndDateButton);
00268 layout->addSpacing(KDialog::spacingHint());
00269 layout->addWidget(mEndDateEdit);
00270 layout->addWidget(mEndTimeEdit);
00271 layout->addWidget(mEndAnyTimeCheckBox);
00272 layout->addStretch();
00273 size = size.expandedTo(mEndDateButton->sizeHint());
00274
00275
00276 mRepeatCountButton->setFixedSize(size);
00277 mEndDateButton->setFixedSize(size);
00278
00279
00280
00281
00282 mExceptionGroup = new QGroupBox(i18n("E&xceptions"), this, "mExceptionGroup");
00283 topLayout->addWidget(mExceptionGroup);
00284 topLayout->setStretchFactor(mExceptionGroup, 2);
00285 vlayout = new QVBoxLayout(mExceptionGroup, KDialog::marginHint(), KDialog::spacingHint());
00286 vlayout->addSpacing(fontMetrics().lineSpacing()/2);
00287 layout = new QHBoxLayout(vlayout, KDialog::spacingHint());
00288 vlayout = new QVBoxLayout(layout);
00289
00290 mExceptionDateList = new QListBox(mExceptionGroup);
00291 mExceptionDateList->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
00292 connect(mExceptionDateList, SIGNAL(selectionChanged()), SLOT(enableExceptionButtons()));
00293 QWhatsThis::add(mExceptionDateList,
00294 i18n("The list of exceptions, i.e. dates/times excluded from the recurrence"));
00295 vlayout->addWidget(mExceptionDateList);
00296
00297 if (mReadOnly)
00298 {
00299 mExceptionDateEdit = 0;
00300 mChangeExceptionButton = 0;
00301 mDeleteExceptionButton = 0;
00302 }
00303 else
00304 {
00305 vlayout = new QVBoxLayout(layout);
00306 mExceptionDateEdit = new DateEdit(mExceptionGroup);
00307 mExceptionDateEdit->setFixedSize(mExceptionDateEdit->sizeHint());
00308 mExceptionDateEdit->setDate(QDate::currentDate());
00309 QWhatsThis::add(mExceptionDateEdit,
00310 i18n("Enter a date to insert in the exceptions list. "
00311 "Use in conjunction with the Add or Change button below."));
00312 vlayout->addWidget(mExceptionDateEdit);
00313
00314 layout = new QHBoxLayout(vlayout, KDialog::spacingHint());
00315 QPushButton* button = new QPushButton(i18n("Add"), mExceptionGroup);
00316 button->setFixedSize(button->sizeHint());
00317 connect(button, SIGNAL(clicked()), SLOT(addException()));
00318 QWhatsThis::add(button,
00319 i18n("Add the date entered above to the exceptions list"));
00320 layout->addWidget(button);
00321
00322 mChangeExceptionButton = new QPushButton(i18n("Change"), mExceptionGroup);
00323 mChangeExceptionButton->setFixedSize(mChangeExceptionButton->sizeHint());
00324 connect(mChangeExceptionButton, SIGNAL(clicked()), SLOT(changeException()));
00325 QWhatsThis::add(mChangeExceptionButton,
00326 i18n("Replace the currently highlighted item in the exceptions list with the date entered above"));
00327 layout->addWidget(mChangeExceptionButton);
00328
00329 mDeleteExceptionButton = new QPushButton(i18n("Delete"), mExceptionGroup);
00330 mDeleteExceptionButton->setFixedSize(mDeleteExceptionButton->sizeHint());
00331 connect(mDeleteExceptionButton, SIGNAL(clicked()), SLOT(deleteException()));
00332 QWhatsThis::add(mDeleteExceptionButton,
00333 i18n("Remove the currently highlighted item from the exceptions list"));
00334 layout->addWidget(mDeleteExceptionButton);
00335 }
00336
00337 mNoEmitTypeChanged = false;
00338 }
00339
00340
00341
00342
00343
00344 QWidget* RecurrenceEdit::checkData(const QDateTime& startDateTime, QString& errorMessage) const
00345 {
00346 if (mAtLoginButton->isOn())
00347 return 0;
00348 const_cast<RecurrenceEdit*>(this)->mCurrStartDateTime = startDateTime;
00349 if (mEndDateButton->isChecked())
00350 {
00351 QWidget* errWidget = 0;
00352 bool noTime = !mEndTimeEdit->isEnabled();
00353 QDate endDate = mEndDateEdit->date();
00354 if (endDate < startDateTime.date())
00355 errWidget = mEndDateEdit;
00356 else if (!noTime && QDateTime(endDate, mEndTimeEdit->time()) < startDateTime)
00357 errWidget = mEndTimeEdit;
00358 if (errWidget)
00359 {
00360 errorMessage = noTime
00361 ? i18n("End date is earlier than start date")
00362 : i18n("End date/time is earlier than start date/time");
00363 return errWidget;
00364 }
00365 }
00366 if (!mRule)
00367 return 0;
00368 return mRule->validate(errorMessage);
00369 }
00370
00371
00372
00373
00374 void RecurrenceEdit::periodClicked(int id)
00375 {
00376 RepeatType oldType = mRuleButtonType;
00377 bool none = (id == mNoneButtonId);
00378 bool atLogin = (id == mAtLoginButtonId);
00379 bool subdaily = (id == mSubDailyButtonId);
00380 if (none)
00381 {
00382 mRule = 0;
00383 mRuleButtonType = NO_RECUR;
00384 }
00385 else if (atLogin)
00386 {
00387 mRule = 0;
00388 mRuleButtonType = AT_LOGIN;
00389 mRangeButtonGroup->setButton(mRangeButtonGroup->id(mEndDateButton));
00390 }
00391 else if (subdaily)
00392 {
00393 mRule = mSubDailyRule;
00394 mRuleButtonType = SUBDAILY;
00395 }
00396 else if (id == mDailyButtonId)
00397 {
00398 mRule = mDailyRule;
00399 mRuleButtonType = DAILY;
00400 mDailyShown = true;
00401 }
00402 else if (id == mWeeklyButtonId)
00403 {
00404 mRule = mWeeklyRule;
00405 mRuleButtonType = WEEKLY;
00406 mWeeklyShown = true;
00407 }
00408 else if (id == mMonthlyButtonId)
00409 {
00410 mRule = mMonthlyRule;
00411 mRuleButtonType = MONTHLY;
00412 mMonthlyShown = true;
00413 }
00414 else if (id == mYearlyButtonId)
00415 {
00416 mRule = mYearlyRule;
00417 mRuleButtonType = ANNUAL;
00418 mYearlyShown = true;
00419 }
00420 else
00421 return;
00422
00423 if (mRuleButtonType != oldType)
00424 {
00425 mRuleStack->raiseWidget(mRule ? mRule : mNoRule);
00426 if (oldType == NO_RECUR || none)
00427 mRangeButtonGroup->setEnabled(!none);
00428 mExceptionGroup->setEnabled(!(none || atLogin));
00429 mEndAnyTimeCheckBox->setEnabled(atLogin);
00430 if (!none)
00431 {
00432 mNoEndDateButton->setEnabled(!atLogin);
00433 mRepeatCountButton->setEnabled(!atLogin);
00434 }
00435 rangeTypeClicked();
00436 if (!mNoEmitTypeChanged)
00437 emit typeChanged(mRuleButtonType);
00438 }
00439 }
00440
00441 void RecurrenceEdit::slotAnyTimeToggled(bool on)
00442 {
00443 QButton* button = mRuleButtonGroup->selected();
00444 mEndTimeEdit->setEnabled(button == mAtLoginButton && !on
00445 || button == mSubDailyButton && mEndDateButton->isChecked());
00446 }
00447
00448
00449
00450
00451 void RecurrenceEdit::rangeTypeClicked()
00452 {
00453 bool endDate = mEndDateButton->isOn();
00454 mEndDateEdit->setEnabled(endDate);
00455 mEndTimeEdit->setEnabled(endDate
00456 && (mAtLoginButton->isOn() && !mEndAnyTimeCheckBox->isChecked()
00457 || mSubDailyButton->isOn()));
00458 bool repeatCount = mRepeatCountButton->isOn();
00459 mRepeatCountEntry->setEnabled(repeatCount);
00460 mRepeatCountLabel->setEnabled(repeatCount);
00461 }
00462
00463 void RecurrenceEdit::showEvent(QShowEvent*)
00464 {
00465 if (mRule)
00466 mRule->setFrequencyFocus();
00467 else
00468 mRuleButtonGroup->selected()->setFocus();
00469 emit shown();
00470 }
00471
00472
00473
00474
00475
00476 void RecurrenceEdit::repeatCountChanged(int value)
00477 {
00478 if (value > 0 && mRepeatCountEntry->minValue() == 0)
00479 mRepeatCountEntry->setMinValue(1);
00480 }
00481
00482
00483
00484
00485
00486 void RecurrenceEdit::addException()
00487 {
00488 if (!mExceptionDateEdit || !mExceptionDateEdit->isValid())
00489 return;
00490 QDate date = mExceptionDateEdit->date();
00491 QValueList<QDate>::Iterator it;
00492 int index = 0;
00493 bool insert = true;
00494 for (it = mExceptionDates.begin(); it != mExceptionDates.end(); ++index, ++it)
00495 {
00496 if (date <= *it)
00497 {
00498 insert = (date != *it);
00499 break;
00500 }
00501 }
00502 if (insert)
00503 {
00504 mExceptionDates.insert(it, date);
00505 mExceptionDateList->insertItem(KGlobal::locale()->formatDate(date), index);
00506 }
00507 mExceptionDateList->setCurrentItem(index);
00508 enableExceptionButtons();
00509 }
00510
00511
00512
00513
00514
00515 void RecurrenceEdit::changeException()
00516 {
00517 if (!mExceptionDateEdit || !mExceptionDateEdit->isValid())
00518 return;
00519 int index = mExceptionDateList->currentItem();
00520 if (index >= 0 && mExceptionDateList->isSelected(index))
00521 {
00522 QDate olddate = mExceptionDates[index];
00523 QDate newdate = mExceptionDateEdit->date();
00524 if (newdate != olddate)
00525 {
00526 mExceptionDates.remove(mExceptionDates.at(index));
00527 mExceptionDateList->removeItem(index);
00528 addException();
00529 }
00530 }
00531 }
00532
00533
00534
00535
00536 void RecurrenceEdit::deleteException()
00537 {
00538 int index = mExceptionDateList->currentItem();
00539 if (index >= 0 && mExceptionDateList->isSelected(index))
00540 {
00541 mExceptionDates.remove(mExceptionDates.at(index));
00542 mExceptionDateList->removeItem(index);
00543 enableExceptionButtons();
00544 }
00545 }
00546
00547
00548
00549
00550
00551 void RecurrenceEdit::enableExceptionButtons()
00552 {
00553 int index = mExceptionDateList->currentItem();
00554 bool enable = (index >= 0 && mExceptionDateList->isSelected(index));
00555 if (mDeleteExceptionButton)
00556 mDeleteExceptionButton->setEnabled(enable);
00557 if (mChangeExceptionButton)
00558 mChangeExceptionButton->setEnabled(enable);
00559
00560
00561 mExceptionDateList->setFocusPolicy(mExceptionDateList->count() ? QWidget::WheelFocus : QWidget::NoFocus);
00562 }
00563
00564
00565
00566
00567 void RecurrenceEdit::setStartDate(const QDate& start, const QDate& today)
00568 {
00569 if (!mReadOnly)
00570 {
00571 setRuleDefaults(start);
00572 if (start < today)
00573 {
00574 mEndDateEdit->setMinDate(today);
00575 if (mExceptionDateEdit)
00576 mExceptionDateEdit->setMinDate(today);
00577 }
00578 else
00579 {
00580 const QString startString = i18n("Date cannot be earlier than start date", "start date");
00581 mEndDateEdit->setMinDate(start, startString);
00582 if (mExceptionDateEdit)
00583 mExceptionDateEdit->setMinDate(start, startString);
00584 }
00585 }
00586 }
00587
00588
00589
00590
00591 void RecurrenceEdit::setDefaultEndDate(const QDate& end)
00592 {
00593 if (!mEndDateButton->isOn())
00594 mEndDateEdit->setDate(end);
00595 }
00596
00597 void RecurrenceEdit::setEndDateTime(const DateTime& end)
00598 {
00599 mEndDateEdit->setDate(end.date());
00600 mEndTimeEdit->setValue(end.time());
00601 mEndTimeEdit->setEnabled(!end.isDateOnly());
00602 mEndAnyTimeCheckBox->setChecked(end.isDateOnly());
00603 }
00604
00605 DateTime RecurrenceEdit::endDateTime() const
00606 {
00607 if (mRuleButtonGroup->selected() == mAtLoginButton && mEndAnyTimeCheckBox->isChecked())
00608 return DateTime(mEndDateEdit->date());
00609 return DateTime(mEndDateEdit->date(), mEndTimeEdit->time());
00610 }
00611
00612
00613
00614
00615 void RecurrenceEdit::setDefaults(const QDateTime& from)
00616 {
00617 mCurrStartDateTime = from;
00618 QDate fromDate = from.date();
00619 mNoEndDateButton->setChecked(true);
00620
00621 mSubDailyRule->setFrequency(1);
00622 mDailyRule->setFrequency(1);
00623 mWeeklyRule->setFrequency(1);
00624 mMonthlyRule->setFrequency(1);
00625 mYearlyRule->setFrequency(1);
00626
00627 setRuleDefaults(fromDate);
00628 mMonthlyRule->setType(MonthYearRule::DATE);
00629 mYearlyRule->setType(MonthYearRule::DATE);
00630
00631 mEndDateEdit->setDate(fromDate);
00632
00633 mNoEmitTypeChanged = true;
00634 int button;
00635 switch (Preferences::defaultRecurPeriod())
00636 {
00637 case AT_LOGIN: button = mAtLoginButtonId; break;
00638 case ANNUAL: button = mYearlyButtonId; break;
00639 case MONTHLY: button = mMonthlyButtonId; break;
00640 case WEEKLY: button = mWeeklyButtonId; break;
00641 case DAILY: button = mDailyButtonId; break;
00642 case SUBDAILY: button = mSubDailyButtonId; break;
00643 case NO_RECUR:
00644 default: button = mNoneButtonId; break;
00645 }
00646 mRuleButtonGroup->setButton(button);
00647 mNoEmitTypeChanged = false;
00648 rangeTypeClicked();
00649 enableExceptionButtons();
00650
00651 saveState();
00652 }
00653
00654
00655
00656
00657
00658 void RecurrenceEdit::setRuleDefaults(const QDate& fromDate)
00659 {
00660 int day = fromDate.day();
00661 int dayOfWeek = fromDate.dayOfWeek();
00662 int month = fromDate.month();
00663 if (!mDailyShown)
00664 mDailyRule->setDays(true);
00665 if (!mWeeklyShown)
00666 mWeeklyRule->setDay(dayOfWeek);
00667 if (!mMonthlyShown)
00668 mMonthlyRule->setDefaultValues(day, dayOfWeek);
00669 if (!mYearlyShown)
00670 mYearlyRule->setDefaultValues(day, dayOfWeek, month);
00671 }
00672
00673
00674
00675
00676 void RecurrenceEdit::set(const KAEvent& event)
00677 {
00678 setDefaults(event.mainDateTime().dateTime());
00679 if (event.repeatAtLogin())
00680 {
00681 mRuleButtonGroup->setButton(mAtLoginButtonId);
00682 mEndDateButton->setChecked(true);
00683 return;
00684 }
00685 mRuleButtonGroup->setButton(mNoneButtonId);
00686 int repeatDuration;
00687 KARecurrence* recurrence = event.recurrence();
00688 if (!recurrence)
00689 return;
00690 KARecurrence::Type rtype = recurrence->type();
00691 switch (rtype)
00692 {
00693 case KARecurrence::MINUTELY:
00694 mRuleButtonGroup->setButton(mSubDailyButtonId);
00695 break;
00696
00697 case KARecurrence::DAILY:
00698 {
00699 mRuleButtonGroup->setButton(mDailyButtonId);
00700 QBitArray rDays = recurrence->days();
00701 bool set = false;
00702 for (int i = 0; i < 7 && !set; ++i)
00703 set = rDays.testBit(i);
00704 if (set)
00705 mDailyRule->setDays(rDays);
00706 else
00707 mDailyRule->setDays(true);
00708 break;
00709 }
00710 case KARecurrence::WEEKLY:
00711 {
00712 mRuleButtonGroup->setButton(mWeeklyButtonId);
00713 QBitArray rDays = recurrence->days();
00714 mWeeklyRule->setDays(rDays);
00715 break;
00716 }
00717 case KARecurrence::MONTHLY_POS:
00718 {
00719 QValueList<RecurrenceRule::WDayPos> posns = recurrence->monthPositions();
00720 int i = posns.first().pos();
00721 if (!i)
00722 {
00723
00724
00725 mRuleButtonGroup->setButton(mWeeklyButtonId);
00726 mWeeklyRule->setFrequency(recurrence->frequency());
00727 QBitArray rDays(7);
00728 for (QValueList<RecurrenceRule::WDayPos>::ConstIterator it = posns.begin(); it != posns.end(); ++it)
00729 {
00730 if (!(*it).pos())
00731 rDays.setBit((*it).day() - 1, 1);
00732 }
00733 mWeeklyRule->setDays(rDays);
00734 break;
00735 }
00736 mRuleButtonGroup->setButton(mMonthlyButtonId);
00737 mMonthlyRule->setPosition(i, posns.first().day());
00738 break;
00739 }
00740 case KARecurrence::MONTHLY_DAY:
00741 {
00742 mRuleButtonGroup->setButton(mMonthlyButtonId);
00743 QValueList<int> rmd = recurrence->monthDays();
00744 int day = (rmd.isEmpty()) ? event.mainDate().day() : rmd.first();
00745 mMonthlyRule->setDate(day);
00746 break;
00747 }
00748 case KARecurrence::ANNUAL_DATE:
00749 case KARecurrence::ANNUAL_POS:
00750 {
00751 if (rtype == KARecurrence::ANNUAL_DATE)
00752 {
00753 mRuleButtonGroup->setButton(mYearlyButtonId);
00754 const QValueList<int> rmd = recurrence->monthDays();
00755 int day = (rmd.isEmpty()) ? event.mainDate().day() : rmd.first();
00756 mYearlyRule->setDate(day);
00757 mYearlyRule->setFeb29Type(recurrence->feb29Type());
00758 }
00759 else if (rtype == KARecurrence::ANNUAL_POS)
00760 {
00761 mRuleButtonGroup->setButton(mYearlyButtonId);
00762 QValueList<RecurrenceRule::WDayPos> posns = recurrence->yearPositions();
00763 mYearlyRule->setPosition(posns.first().pos(), posns.first().day());
00764 }
00765 mYearlyRule->setMonths(recurrence->yearMonths());
00766 break;
00767 }
00768 default:
00769 return;
00770 }
00771
00772 mRule->setFrequency(recurrence->frequency());
00773 repeatDuration = event.remainingRecurrences();
00774
00775
00776 QDateTime endtime = mCurrStartDateTime;
00777 if (repeatDuration == -1)
00778 mNoEndDateButton->setChecked(true);
00779 else if (repeatDuration)
00780 {
00781 mRepeatCountButton->setChecked(true);
00782 if (event.mainExpired())
00783 {
00784 mRepeatCountEntry->setMinValue(0);
00785 repeatDuration = 0;
00786 }
00787 mRepeatCountEntry->setValue(repeatDuration);
00788 }
00789 else
00790 {
00791 mEndDateButton->setChecked(true);
00792 endtime = recurrence->endDateTime();
00793 mEndTimeEdit->setValue(endtime.time());
00794 }
00795 mEndDateEdit->setDate(endtime.date());
00796
00797
00798 mExceptionDates = event.recurrence()->exDates();
00799 qHeapSort(mExceptionDates);
00800 mExceptionDateList->clear();
00801 for (DateList::ConstIterator it = mExceptionDates.begin(); it != mExceptionDates.end(); ++it)
00802 mExceptionDateList->insertItem(KGlobal::locale()->formatDate(*it));
00803 enableExceptionButtons();
00804
00805 rangeTypeClicked();
00806
00807 saveState();
00808 }
00809
00810
00811
00812
00813
00814
00815 void RecurrenceEdit::updateEvent(KAEvent& event, bool adjustStart)
00816 {
00817
00818 QDate endDate;
00819 QTime endTime;
00820 int repeatCount;
00821 if (mNoEndDateButton->isChecked())
00822 repeatCount = -1;
00823 else if (mRepeatCountButton->isChecked())
00824 repeatCount = mRepeatCountEntry->value();
00825 else
00826 {
00827 repeatCount = 0;
00828 endDate = mEndDateEdit->date();
00829 endTime = mEndTimeEdit->time();
00830 }
00831
00832
00833 QButton* button = mRuleButtonGroup->selected();
00834 event.setRepeatAtLogin(button == mAtLoginButton);
00835 int frequency = mRule ? mRule->frequency() : 0;
00836 if (button == mSubDailyButton)
00837 {
00838 QDateTime endDateTime(endDate, endTime);
00839 event.setRecurMinutely(frequency, repeatCount, endDateTime);
00840 }
00841 else if (button == mDailyButton)
00842 {
00843 event.setRecurDaily(frequency, mDailyRule->days(), repeatCount, endDate);
00844 }
00845 else if (button == mWeeklyButton)
00846 {
00847 event.setRecurWeekly(frequency, mWeeklyRule->days(), repeatCount, endDate);
00848 }
00849 else if (button == mMonthlyButton)
00850 {
00851 if (mMonthlyRule->type() == MonthlyRule::POS)
00852 {
00853
00854 KAEvent::MonthPos pos;
00855 pos.days.fill(false);
00856 pos.days.setBit(mMonthlyRule->dayOfWeek() - 1);
00857 pos.weeknum = mMonthlyRule->week();
00858 QValueList<KAEvent::MonthPos> poses;
00859 poses.append(pos);
00860 event.setRecurMonthlyByPos(frequency, poses, repeatCount, endDate);
00861 }
00862 else
00863 {
00864
00865 int daynum = mMonthlyRule->date();
00866 QValueList<int> daynums;
00867 daynums.append(daynum);
00868 event.setRecurMonthlyByDate(frequency, daynums, repeatCount, endDate);
00869 }
00870 }
00871 else if (button == mYearlyButton)
00872 {
00873 QValueList<int> months = mYearlyRule->months();
00874 if (mYearlyRule->type() == YearlyRule::POS)
00875 {
00876
00877 KAEvent::MonthPos pos;
00878 pos.days.fill(false);
00879 pos.days.setBit(mYearlyRule->dayOfWeek() - 1);
00880 pos.weeknum = mYearlyRule->week();
00881 QValueList<KAEvent::MonthPos> poses;
00882 poses.append(pos);
00883 event.setRecurAnnualByPos(frequency, poses, months, repeatCount, endDate);
00884 }
00885 else
00886 {
00887
00888 event.setRecurAnnualByDate(frequency, months, mYearlyRule->date(),
00889 mYearlyRule->feb29Type(), repeatCount, endDate);
00890 }
00891 }
00892 else
00893 {
00894 event.setNoRecur();
00895 return;
00896 }
00897 if (!event.recurs())
00898 return;
00899 if (adjustStart)
00900 event.setFirstRecurrence();
00901
00902
00903 event.recurrence()->setExDates(mExceptionDates);
00904 event.setUpdated();
00905 }
00906
00907
00908
00909
00910 void RecurrenceEdit::saveState()
00911 {
00912 mSavedRuleButton = mRuleButtonGroup->selected();
00913 if (mRule)
00914 mRule->saveState();
00915 mSavedRangeButton = mRangeButtonGroup->selected();
00916 if (mSavedRangeButton == mRepeatCountButton)
00917 mSavedRepeatCount = mRepeatCountEntry->value();
00918 else if (mSavedRangeButton == mEndDateButton)
00919 mSavedEndDateTime.set(QDateTime(mEndDateEdit->date(), mEndTimeEdit->time()), mEndAnyTimeCheckBox->isChecked());
00920 mSavedExceptionDates = mExceptionDates;
00921 }
00922
00923
00924
00925
00926 bool RecurrenceEdit::stateChanged() const
00927 {
00928 if (mSavedRuleButton != mRuleButtonGroup->selected()
00929 || mSavedRangeButton != mRangeButtonGroup->selected()
00930 || mRule && mRule->stateChanged())
00931 return true;
00932 if (mSavedRangeButton == mRepeatCountButton
00933 && mSavedRepeatCount != mRepeatCountEntry->value())
00934 return true;
00935 if (mSavedRangeButton == mEndDateButton
00936 && mSavedEndDateTime != DateTime(QDateTime(mEndDateEdit->date(), mEndTimeEdit->time()), mEndAnyTimeCheckBox->isChecked()))
00937 return true;
00938 if (mSavedExceptionDates != mExceptionDates)
00939 return true;
00940 return false;
00941 }
00942
00943
00944
00945
00946
00947
00948
00949
00950 Rule::Rule(const QString& freqText, const QString& freqWhatsThis, bool time, bool readOnly, QWidget* parent, const char* name)
00951 : NoRule(parent, name)
00952 {
00953 mLayout = new QVBoxLayout(this, 0, KDialog::spacingHint());
00954 QHBox* freqBox = new QHBox(this);
00955 mLayout->addWidget(freqBox);
00956 QHBox* box = new QHBox(freqBox);
00957 box->setSpacing(KDialog::spacingHint());
00958
00959 QLabel* label = new QLabel(i18n("Recur e&very"), box);
00960 label->setFixedSize(label->sizeHint());
00961 if (time)
00962 {
00963 mIntSpinBox = 0;
00964 mSpinBox = mTimeSpinBox = new TimeSpinBox(1, 5999, box);
00965 mTimeSpinBox->setFixedSize(mTimeSpinBox->sizeHint());
00966 mTimeSpinBox->setReadOnly(readOnly);
00967 }
00968 else
00969 {
00970 mTimeSpinBox = 0;
00971 mSpinBox = mIntSpinBox = new SpinBox(1, 999, 1, box);
00972 mIntSpinBox->setFixedSize(mIntSpinBox->sizeHint());
00973 mIntSpinBox->setReadOnly(readOnly);
00974 }
00975 connect(mSpinBox, SIGNAL(valueChanged(int)), SIGNAL(frequencyChanged()));
00976 label->setBuddy(mSpinBox);
00977 label = new QLabel(freqText, box);
00978 label->setFixedSize(label->sizeHint());
00979 box->setFixedSize(sizeHint());
00980 QWhatsThis::add(box, freqWhatsThis);
00981
00982 new QWidget(freqBox);
00983 freqBox->setFixedHeight(freqBox->sizeHint().height());
00984 freqBox->setFocusProxy(mSpinBox);
00985 }
00986
00987 int Rule::frequency() const
00988 {
00989 if (mIntSpinBox)
00990 return mIntSpinBox->value();
00991 if (mTimeSpinBox)
00992 return mTimeSpinBox->value();
00993 return 0;
00994 }
00995
00996 void Rule::setFrequency(int n)
00997 {
00998 if (mIntSpinBox)
00999 mIntSpinBox->setValue(n);
01000 if (mTimeSpinBox)
01001 mTimeSpinBox->setValue(n);
01002 }
01003
01004
01005
01006
01007 void Rule::saveState()
01008 {
01009 mSavedFrequency = frequency();
01010 }
01011
01012
01013
01014
01015 bool Rule::stateChanged() const
01016 {
01017 return (mSavedFrequency != frequency());
01018 }
01019
01020
01021
01022
01023
01024
01025
01026 SubDailyRule::SubDailyRule(bool readOnly, QWidget* parent, const char* name)
01027 : Rule(i18n("hours:minutes"),
01028 i18n("Enter the number of hours and minutes between repetitions of the alarm"),
01029 true, readOnly, parent, name)
01030 { }
01031
01032
01033
01034
01035
01036
01037
01038 DayWeekRule::DayWeekRule(const QString& freqText, const QString& freqWhatsThis, const QString& daysWhatsThis,
01039 bool readOnly, QWidget* parent, const char* name)
01040 : Rule(freqText, freqWhatsThis, false, readOnly, parent, name),
01041 mSavedDays(7)
01042 {
01043 QGridLayout* grid = new QGridLayout(layout(), 1, 4, KDialog::spacingHint());
01044 grid->setRowStretch(0, 1);
01045
01046 QLabel* label = new QLabel(i18n("On: Tuesday", "O&n:"), this);
01047 label->setFixedSize(label->sizeHint());
01048 grid->addWidget(label, 0, 0, Qt::AlignRight | Qt::AlignTop);
01049 grid->addColSpacing(1, KDialog::spacingHint());
01050
01051
01052
01053 QWidget* box = new QWidget(this);
01054 QGridLayout* dgrid = new QGridLayout(box, 4, 2, 0, KDialog::spacingHint());
01055 const KLocale* locale = KGlobal::locale();
01056 for (int i = 0; i < 7; ++i)
01057 {
01058 int day = KAlarm::localeDayInWeek_to_weekDay(i);
01059 mDayBox[i] = new CheckBox(weekDayName(day, locale), box);
01060 mDayBox[i]->setFixedSize(mDayBox[i]->sizeHint());
01061 mDayBox[i]->setReadOnly(readOnly);
01062 dgrid->addWidget(mDayBox[i], i%4, i/4, Qt::AlignAuto);
01063 }
01064 box->setFixedSize(box->sizeHint());
01065 QWhatsThis::add(box, daysWhatsThis);
01066 grid->addWidget(box, 0, 2, Qt::AlignAuto);
01067 label->setBuddy(mDayBox[0]);
01068 grid->setColStretch(3, 1);
01069 }
01070
01071
01072
01073
01074 QBitArray DayWeekRule::days() const
01075 {
01076 QBitArray ds(7);
01077 ds.fill(false);
01078 for (int i = 0; i < 7; ++i)
01079 if (mDayBox[i]->isChecked())
01080 ds.setBit(KAlarm::localeDayInWeek_to_weekDay(i) - 1, 1);
01081 return ds;
01082 }
01083
01084
01085
01086
01087 void DayWeekRule::setDays(bool tick)
01088 {
01089 for (int i = 0; i < 7; ++i)
01090 mDayBox[i]->setChecked(tick);
01091 }
01092
01093
01094
01095
01096 void DayWeekRule::setDays(QBitArray& days)
01097 {
01098 for (int i = 0; i < 7; ++i)
01099 {
01100 bool x = days.testBit(KAlarm::localeDayInWeek_to_weekDay(i) - 1);
01101 mDayBox[i]->setChecked(x);
01102 }
01103 }
01104
01105
01106
01107
01108 void DayWeekRule::setDay(int dayOfWeek)
01109 {
01110 for (int i = 0; i < 7; ++i)
01111 mDayBox[i]->setChecked(false);
01112 if (dayOfWeek > 0 && dayOfWeek <= 7)
01113 mDayBox[KAlarm::weekDay_to_localeDayInWeek(dayOfWeek)]->setChecked(true);
01114 }
01115
01116
01117
01118
01119 QWidget* DayWeekRule::validate(QString& errorMessage)
01120 {
01121 for (int i = 0; i < 7; ++i)
01122 if (mDayBox[i]->isChecked())
01123 return 0;
01124 errorMessage = i18n("No day selected");
01125 return mDayBox[0];
01126 }
01127
01128
01129
01130
01131 void DayWeekRule::saveState()
01132 {
01133 Rule::saveState();
01134 mSavedDays = days();
01135 }
01136
01137
01138
01139
01140 bool DayWeekRule::stateChanged() const
01141 {
01142 return (Rule::stateChanged()
01143 || mSavedDays != days());
01144 }
01145
01146
01147
01148
01149
01150
01151
01152 DailyRule::DailyRule(bool readOnly, QWidget* parent, const char* name)
01153 : DayWeekRule(i18n("day(s)"),
01154 i18n("Enter the number of days between repetitions of the alarm"),
01155 #if KDE_IS_VERSION(3,9,0)
01156 i18n("Select the days of the week on which the alarm is allowed to occur"),
01157 #else
01158 i18n("Select the days of the week on which to repeat the alarm"),
01159 #endif
01160 readOnly, parent, name)
01161 { }
01162
01163
01164
01165
01166
01167
01168
01169 WeeklyRule::WeeklyRule(bool readOnly, QWidget* parent, const char* name)
01170 : DayWeekRule(i18n("week(s)"),
01171 i18n("Enter the number of weeks between repetitions of the alarm"),
01172 i18n("Select the days of the week on which to repeat the alarm"),
01173 readOnly, parent, name)
01174 { }
01175
01176
01177
01178
01179
01180
01181
01182 MonthYearRule::MonthYearRule(const QString& freqText, const QString& freqWhatsThis, bool allowEveryWeek,
01183 bool readOnly, QWidget* parent, const char* name)
01184 : Rule(freqText, freqWhatsThis, false, readOnly, parent, name),
01185 mEveryWeek(allowEveryWeek)
01186 {
01187 mButtonGroup = new ButtonGroup(this);
01188 mButtonGroup->hide();
01189
01190
01191 QHBox* box = new QHBox(this);
01192 box->setSpacing(KDialog::spacingHint());
01193 layout()->addWidget(box);
01194
01195 mDayButton = new RadioButton(i18n("On day number in the month", "O&n day"), box);
01196 mDayButton->setFixedSize(mDayButton->sizeHint());
01197 mDayButton->setReadOnly(readOnly);
01198 mDayButtonId = mButtonGroup->insert(mDayButton);
01199 QWhatsThis::add(mDayButton, i18n("Repeat the alarm on the selected day of the month"));
01200
01201 mDayCombo = new ComboBox(false, box);
01202 mDayCombo->setSizeLimit(11);
01203 for (int i = 0; i < 31; ++i)
01204 mDayCombo->insertItem(QString::number(i + 1));
01205 mDayCombo->insertItem(i18n("Last day of month", "Last"));
01206 mDayCombo->setFixedSize(mDayCombo->sizeHint());
01207 mDayCombo->setReadOnly(readOnly);
01208 QWhatsThis::add(mDayCombo, i18n("Select the day of the month on which to repeat the alarm"));
01209 mDayButton->setFocusWidget(mDayCombo);
01210 connect(mDayCombo, SIGNAL(activated(int)), SLOT(slotDaySelected(int)));
01211
01212 box->setStretchFactor(new QWidget(box), 1);
01213 box->setFixedHeight(box->sizeHint().height());
01214
01215
01216 box = new QHBox(this);
01217 box->setSpacing(KDialog::spacingHint());
01218 layout()->addWidget(box);
01219
01220 mPosButton = new RadioButton(i18n("On the 1st Tuesday", "On t&he"), box);
01221 mPosButton->setFixedSize(mPosButton->sizeHint());
01222 mPosButton->setReadOnly(readOnly);
01223 mPosButtonId = mButtonGroup->insert(mPosButton);
01224 QWhatsThis::add(mPosButton,
01225 i18n("Repeat the alarm on one day of the week, in the selected week of the month"));
01226
01227 mWeekCombo = new ComboBox(false, box);
01228 mWeekCombo->insertItem(i18n("1st"));
01229 mWeekCombo->insertItem(i18n("2nd"));
01230 mWeekCombo->insertItem(i18n("3rd"));
01231 mWeekCombo->insertItem(i18n("4th"));
01232 mWeekCombo->insertItem(i18n("5th"));
01233 mWeekCombo->insertItem(i18n("Last Monday in March", "Last"));
01234 mWeekCombo->insertItem(i18n("2nd Last"));
01235 mWeekCombo->insertItem(i18n("3rd Last"));
01236 mWeekCombo->insertItem(i18n("4th Last"));
01237 mWeekCombo->insertItem(i18n("5th Last"));
01238 if (mEveryWeek)
01239 {
01240 mWeekCombo->insertItem(i18n("Every (Monday...) in month", "Every"));
01241 mWeekCombo->setSizeLimit(11);
01242 }
01243 QWhatsThis::add(mWeekCombo, i18n("Select the week of the month in which to repeat the alarm"));
01244 mWeekCombo->setFixedSize(mWeekCombo->sizeHint());
01245 mWeekCombo->setReadOnly(readOnly);
01246 mPosButton->setFocusWidget(mWeekCombo);
01247
01248 mDayOfWeekCombo = new ComboBox(false, box);
01249 const KLocale* locale = KGlobal::locale();
01250 for (int i = 0; i < 7; ++i)
01251 {
01252 int day = KAlarm::localeDayInWeek_to_weekDay(i);
01253 mDayOfWeekCombo->insertItem(weekDayName(day, locale));
01254 }
01255 mDayOfWeekCombo->setReadOnly(readOnly);
01256 QWhatsThis::add(mDayOfWeekCombo, i18n("Select the day of the week on which to repeat the alarm"));
01257
01258 box->setStretchFactor(new QWidget(box), 1);
01259 box->setFixedHeight(box->sizeHint().height());
01260 connect(mButtonGroup, SIGNAL(buttonSet(int)), SLOT(clicked(int)));
01261 }
01262
01263 MonthYearRule::DayPosType MonthYearRule::type() const
01264 {
01265 return (mButtonGroup->selectedId() == mDayButtonId) ? DATE : POS;
01266 }
01267
01268 void MonthYearRule::setType(MonthYearRule::DayPosType type)
01269 {
01270 mButtonGroup->setButton(type == DATE ? mDayButtonId : mPosButtonId);
01271 }
01272
01273 void MonthYearRule::setDefaultValues(int dayOfMonth, int dayOfWeek)
01274 {
01275 --dayOfMonth;
01276 mDayCombo->setCurrentItem(dayOfMonth);
01277 mWeekCombo->setCurrentItem(dayOfMonth / 7);
01278 mDayOfWeekCombo->setCurrentItem(KAlarm::weekDay_to_localeDayInWeek(dayOfWeek));
01279 }
01280
01281 int MonthYearRule::date() const
01282 {
01283 int daynum = mDayCombo->currentItem() + 1;
01284 return (daynum <= 31) ? daynum : 31 - daynum;
01285 }
01286
01287 int MonthYearRule::week() const
01288 {
01289 int weeknum = mWeekCombo->currentItem() + 1;
01290 return (weeknum <= 5) ? weeknum : (weeknum == 11) ? 0 : 5 - weeknum;
01291 }
01292
01293 int MonthYearRule::dayOfWeek() const
01294 {
01295 return KAlarm::localeDayInWeek_to_weekDay(mDayOfWeekCombo->currentItem());
01296 }
01297
01298 void MonthYearRule::setDate(int dayOfMonth)
01299 {
01300 mButtonGroup->setButton(mDayButtonId);
01301 mDayCombo->setCurrentItem(dayOfMonth > 0 ? dayOfMonth - 1 : dayOfMonth < 0 ? 30 - dayOfMonth : 0);
01302 }
01303
01304 void MonthYearRule::setPosition(int week, int dayOfWeek)
01305 {
01306 mButtonGroup->setButton(mPosButtonId);
01307 mWeekCombo->setCurrentItem((week > 0) ? week - 1 : (week < 0) ? 4 - week : mEveryWeek ? 10 : 0);
01308 mDayOfWeekCombo->setCurrentItem(KAlarm::weekDay_to_localeDayInWeek(dayOfWeek));
01309 }
01310
01311 void MonthYearRule::enableSelection(DayPosType type)
01312 {
01313 bool date = (type == DATE);
01314 mDayCombo->setEnabled(date);
01315 mWeekCombo->setEnabled(!date);
01316 mDayOfWeekCombo->setEnabled(!date);
01317 }
01318
01319 void MonthYearRule::clicked(int id)
01320 {
01321 enableSelection(id == mDayButtonId ? DATE : POS);
01322 }
01323
01324 void MonthYearRule::slotDaySelected(int index)
01325 {
01326 daySelected(index <= 30 ? index + 1 : 30 - index);
01327 }
01328
01329
01330
01331
01332 void MonthYearRule::saveState()
01333 {
01334 Rule::saveState();
01335 mSavedType = type();
01336 if (mSavedType == DATE)
01337 mSavedDay = date();
01338 else
01339 {
01340 mSavedWeek = week();
01341 mSavedWeekDay = dayOfWeek();
01342 }
01343 }
01344
01345
01346
01347
01348 bool MonthYearRule::stateChanged() const
01349 {
01350 if (Rule::stateChanged()
01351 || mSavedType != type())
01352 return true;
01353 if (mSavedType == DATE)
01354 {
01355 if (mSavedDay != date())
01356 return true;
01357 }
01358 else
01359 {
01360 if (mSavedWeek != week()
01361 || mSavedWeekDay != dayOfWeek())
01362 return true;
01363 }
01364 return false;
01365 }
01366
01367
01368
01369
01370
01371
01372
01373 MonthlyRule::MonthlyRule(bool readOnly, QWidget* parent, const char* name)
01374 : MonthYearRule(i18n("month(s)"),
01375 i18n("Enter the number of months between repetitions of the alarm"),
01376 false, readOnly, parent, name)
01377 { }
01378
01379
01380
01381
01382
01383
01384
01385 YearlyRule::YearlyRule(bool readOnly, QWidget* parent, const char* name)
01386 : MonthYearRule(i18n("year(s)"),
01387 i18n("Enter the number of years between repetitions of the alarm"),
01388 true, readOnly, parent, name)
01389 {
01390
01391 QBoxLayout* hlayout = new QHBoxLayout(layout(), KDialog::spacingHint());
01392 QLabel* label = new QLabel(i18n("first week of January", "of:"), this);
01393 label->setFixedSize(label->sizeHint());
01394 hlayout->addWidget(label, 0, Qt::AlignAuto | Qt::AlignTop);
01395
01396
01397 QWidget* w = new QWidget(this);
01398 hlayout->addWidget(w, 1, Qt::AlignAuto);
01399 QGridLayout* grid = new QGridLayout(w, 4, 3, 0, KDialog::spacingHint());
01400 const KLocale* locale = KGlobal::locale();
01401 mMonthBox[0] = new CheckBox(locale->translate("January"), w);
01402 mMonthBox[1] = new CheckBox(locale->translate("February"), w);
01403 mMonthBox[2] = new CheckBox(locale->translate("March"), w);
01404 mMonthBox[3] = new CheckBox(locale->translate("April"), w);
01405 mMonthBox[4] = new CheckBox(locale->translate("May"), w);
01406 mMonthBox[5] = new CheckBox(locale->translate("June"), w);
01407 mMonthBox[6] = new CheckBox(locale->translate("July"), w);
01408 mMonthBox[7] = new CheckBox(locale->translate("August"), w);
01409 mMonthBox[8] = new CheckBox(locale->translate("September"), w);
01410 mMonthBox[9] = new CheckBox(locale->translate("October"), w);
01411 mMonthBox[10] = new CheckBox(locale->translate("November"), w);
01412 mMonthBox[11] = new CheckBox(locale->translate("December"), w);
01413 for (int i = 0; i < 12; ++i)
01414 {
01415 mMonthBox[i]->setFixedSize(mMonthBox[i]->sizeHint());
01416 mMonthBox[i]->setReadOnly(readOnly);
01417 grid->addWidget(mMonthBox[i], i%4, i/4, Qt::AlignAuto);
01418 }
01419 connect(mMonthBox[1], SIGNAL(toggled(bool)), SLOT(enableFeb29()));
01420 w->setFixedHeight(w->sizeHint().height());
01421 QWhatsThis::add(w, i18n("Select the months of the year in which to repeat the alarm"));
01422
01423
01424 QHBox* f29box = new QHBox(this);
01425 layout()->addWidget(f29box);
01426 QHBox* box = new QHBox(f29box);
01427 box->setSpacing(KDialog::spacingHint());
01428 mFeb29Label = new QLabel(i18n("February 2&9th alarm in non-leap years:"), box);
01429 mFeb29Label->setFixedSize(mFeb29Label->sizeHint());
01430 mFeb29Combo = new ComboBox(false, box);
01431 mFeb29Combo->insertItem(i18n("No date", "None"));
01432 mFeb29Combo->insertItem(i18n("1st March (short form)", "1 Mar"));
01433 mFeb29Combo->insertItem(i18n("28th February (short form)", "28 Feb"));
01434 mFeb29Combo->setFixedSize(mFeb29Combo->sizeHint());
01435 mFeb29Combo->setReadOnly(readOnly);
01436 mFeb29Label->setBuddy(mFeb29Combo);
01437 box->setFixedSize(box->sizeHint());
01438 QWhatsThis::add(box,
01439 i18n("Select which date, if any, the February 29th alarm should trigger in non-leap years"));
01440 new QWidget(f29box);
01441 f29box->setFixedHeight(f29box->sizeHint().height());
01442 }
01443
01444 void YearlyRule::setDefaultValues(int dayOfMonth, int dayOfWeek, int month)
01445 {
01446 MonthYearRule::setDefaultValues(dayOfMonth, dayOfWeek);
01447 --month;
01448 for (int i = 0; i < 12; ++i)
01449 mMonthBox[i]->setChecked(i == month);
01450 setFeb29Type(Preferences::defaultFeb29Type());
01451 daySelected(dayOfMonth);
01452 }
01453
01454
01455
01456
01457
01458 QValueList<int> YearlyRule::months() const
01459 {
01460 QValueList<int> mnths;
01461 for (int i = 0; i < 12; ++i)
01462 if (mMonthBox[i]->isChecked() && mMonthBox[i]->isEnabled())
01463 mnths.append(i + 1);
01464 return mnths;
01465 }
01466
01467
01468
01469
01470 void YearlyRule::setMonths(const QValueList<int>& mnths)
01471 {
01472 bool checked[12];
01473 for (int i = 0; i < 12; ++i)
01474 checked[i] = false;
01475 for (QValueListConstIterator<int> it = mnths.begin(); it != mnths.end(); ++it)
01476 checked[(*it) - 1] = true;
01477 for (int i = 0; i < 12; ++i)
01478 mMonthBox[i]->setChecked(checked[i]);
01479 enableFeb29();
01480 }
01481
01482
01483
01484
01485 KARecurrence::Feb29Type YearlyRule::feb29Type() const
01486 {
01487 if (mFeb29Combo->isEnabled())
01488 {
01489 switch (mFeb29Combo->currentItem())
01490 {
01491 case 1: return KARecurrence::FEB29_MAR1;
01492 case 2: return KARecurrence::FEB29_FEB28;
01493 default: break;
01494 }
01495 }
01496 return KARecurrence::FEB29_FEB29;
01497 }
01498
01499
01500
01501
01502 void YearlyRule::setFeb29Type(KARecurrence::Feb29Type type)
01503 {
01504 int index;
01505 switch (type)
01506 {
01507 default:
01508 case KARecurrence::FEB29_FEB29: index = 0; break;
01509 case KARecurrence::FEB29_MAR1: index = 1; break;
01510 case KARecurrence::FEB29_FEB28: index = 2; break;
01511 }
01512 mFeb29Combo->setCurrentItem(index);
01513 }
01514
01515
01516
01517
01518 QWidget* YearlyRule::validate(QString& errorMessage)
01519 {
01520 for (int i = 0; i < 12; ++i)
01521 if (mMonthBox[i]->isChecked() && mMonthBox[i]->isEnabled())
01522 return 0;
01523 errorMessage = i18n("No month selected");
01524 return mMonthBox[0];
01525 }
01526
01527
01528
01529
01530
01531 void YearlyRule::clicked(int id)
01532 {
01533 MonthYearRule::clicked(id);
01534 daySelected(buttonType(id) == DATE ? date() : 1);
01535 }
01536
01537
01538
01539
01540
01541 void YearlyRule::daySelected(int day)
01542 {
01543 mMonthBox[1]->setEnabled(day <= 29);
01544 bool enable = (day != 31);
01545 mMonthBox[3]->setEnabled(enable);
01546 mMonthBox[5]->setEnabled(enable);
01547 mMonthBox[8]->setEnabled(enable);
01548 mMonthBox[10]->setEnabled(enable);
01549 enableFeb29();
01550 }
01551
01552
01553
01554
01555
01556 void YearlyRule::enableFeb29()
01557 {
01558 bool enable = (type() == DATE && date() == 29 && mMonthBox[1]->isChecked() && mMonthBox[1]->isEnabled());
01559 mFeb29Label->setEnabled(enable);
01560 mFeb29Combo->setEnabled(enable);
01561 }
01562
01563
01564
01565
01566 void YearlyRule::saveState()
01567 {
01568 MonthYearRule::saveState();
01569 mSavedMonths = months();
01570 mSavedFeb29Type = feb29Type();
01571 }
01572
01573
01574
01575
01576 bool YearlyRule::stateChanged() const
01577 {
01578 return (MonthYearRule::stateChanged()
01579 || mSavedMonths != months()
01580 || mSavedFeb29Type != feb29Type());
01581 }
01582
01583 QString weekDayName(int day, const KLocale* locale)
01584 {
01585 switch (day)
01586 {
01587 case 1: return locale->translate("Monday");
01588 case 2: return locale->translate("Tuesday");
01589 case 3: return locale->translate("Wednesday");
01590 case 4: return locale->translate("Thursday");
01591 case 5: return locale->translate("Friday");
01592 case 6: return locale->translate("Saturday");
01593 case 7: return locale->translate("Sunday");
01594 }
01595 return QString();
01596 }