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 <QPushButton>
00027 #include <QLabel>
00028 #include <QStackedWidget>
00029 #include <QListWidget>
00030 #include <QGroupBox>
00031 #include <QGridLayout>
00032 #include <QHBoxLayout>
00033 #include <QVBoxLayout>
00034 #include <QtAlgorithms>
00035
00036 #include <kglobal.h>
00037 #include <klocale.h>
00038 #include <kcalendarsystem.h>
00039 #include <kiconloader.h>
00040 #include <kdialog.h>
00041 #include <kmessagebox.h>
00042 #include <kdebug.h>
00043
00044 #include <kcal/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 "repetition.h"
00057 #include "spinbox.h"
00058 #include "timeedit.h"
00059 #include "timespinbox.h"
00060 #include "buttongroup.h"
00061 using namespace KCal;
00062
00063 #include "recurrenceedit.moc"
00064 #include "recurrenceeditprivate.moc"
00065
00066
00067 class ListWidget : public QListWidget
00068 {
00069 public:
00070 explicit ListWidget(QWidget* parent) : QListWidget(parent) {}
00071 virtual QSize sizeHint() const { return minimumSizeHint(); }
00072 };
00073
00074
00075
00076 QString RecurrenceEdit::i18n_combo_NoRecur() { return i18nc("@item:inlistbox Recurrence type", "No Recurrence"); }
00077 QString RecurrenceEdit::i18n_combo_AtLogin() { return i18nc("@item:inlistbox Recurrence type", "At Login"); }
00078 QString RecurrenceEdit::i18n_combo_HourlyMinutely() { return i18nc("@item:inlistbox Recurrence type", "Hourly/Minutely"); }
00079 QString RecurrenceEdit::i18n_combo_Daily() { return i18nc("@item:inlistbox Recurrence type", "Daily"); }
00080 QString RecurrenceEdit::i18n_combo_Weekly() { return i18nc("@item:inlistbox Recurrence type", "Weekly"); }
00081 QString RecurrenceEdit::i18n_combo_Monthly() { return i18nc("@item:inlistbox Recurrence type", "Monthly"); }
00082 QString RecurrenceEdit::i18n_combo_Yearly() { return i18nc("@item:inlistbox Recurrence type", "Yearly"); }
00083
00084
00085 RecurrenceEdit::RecurrenceEdit(bool readOnly, QWidget* parent)
00086 : QFrame(parent),
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 kDebug();
00097 QVBoxLayout* topLayout = new QVBoxLayout(this);
00098 topLayout->setMargin(0);
00099 topLayout->setSpacing(KDialog::spacingHint());
00100
00101
00102
00103
00104
00105
00106
00107
00108 QGroupBox* recurGroup = new QGroupBox(i18nc("@title:group", "Recurrence Rule"), this);
00109 topLayout->addWidget(recurGroup);
00110 QHBoxLayout* hlayout = new QHBoxLayout(recurGroup);
00111 hlayout->setMargin(KDialog::marginHint());
00112 hlayout->setSpacing(KDialog::marginHint());
00113
00114
00115 QVBoxLayout* vlayout = new QVBoxLayout();
00116 vlayout->setSpacing(0);
00117 vlayout->setMargin(0);
00118 hlayout->addLayout(vlayout);
00119 mRuleButtonGroup = new ButtonGroup(recurGroup);
00120 connect(mRuleButtonGroup, SIGNAL(buttonSet(QAbstractButton*)), SLOT(periodClicked(QAbstractButton*)));
00121
00122 mNoneButton = new RadioButton(i18n_combo_NoRecur(), recurGroup);
00123 mNoneButton->setFixedSize(mNoneButton->sizeHint());
00124 mNoneButton->setReadOnly(mReadOnly);
00125 mNoneButton->setWhatsThis(i18nc("@info:whatsthis", "Do not repeat the alarm"));
00126 mRuleButtonGroup->addButton(mNoneButton);
00127 vlayout->addWidget(mNoneButton);
00128
00129 mAtLoginButton = new RadioButton(i18n_combo_AtLogin(), recurGroup);
00130 mAtLoginButton->setFixedSize(mAtLoginButton->sizeHint());
00131 mAtLoginButton->setReadOnly(mReadOnly);
00132 mAtLoginButton->setWhatsThis(i18nc("@info:whatsthis",
00133 "<para>Trigger the alarm at the specified date/time and at every login until then.</para>"
00134 "<para>Note that it will also be triggered any time <application>KAlarm</application> is restarted.</para>"));
00135 mRuleButtonGroup->addButton(mAtLoginButton);
00136 vlayout->addWidget(mAtLoginButton);
00137
00138 mSubDailyButton = new RadioButton(i18n_combo_HourlyMinutely(), recurGroup);
00139 mSubDailyButton->setFixedSize(mSubDailyButton->sizeHint());
00140 mSubDailyButton->setReadOnly(mReadOnly);
00141 mSubDailyButton->setWhatsThis(i18nc("@info:whatsthis", "Repeat the alarm at hourly/minutely intervals"));
00142 mRuleButtonGroup->addButton(mSubDailyButton);
00143 vlayout->addWidget(mSubDailyButton);
00144
00145 mDailyButton = new RadioButton(i18n_combo_Daily(), recurGroup);
00146 mDailyButton->setFixedSize(mDailyButton->sizeHint());
00147 mDailyButton->setReadOnly(mReadOnly);
00148 mDailyButton->setWhatsThis(i18nc("@info:whatsthis", "Repeat the alarm at daily intervals"));
00149 mRuleButtonGroup->addButton(mDailyButton);
00150 vlayout->addWidget(mDailyButton);
00151
00152 mWeeklyButton = new RadioButton(i18n_combo_Weekly(), recurGroup);
00153 mWeeklyButton->setFixedSize(mWeeklyButton->sizeHint());
00154 mWeeklyButton->setReadOnly(mReadOnly);
00155 mWeeklyButton->setWhatsThis(i18nc("@info:whatsthis", "Repeat the alarm at weekly intervals"));
00156 mRuleButtonGroup->addButton(mWeeklyButton);
00157 vlayout->addWidget(mWeeklyButton);
00158
00159 mMonthlyButton = new RadioButton(i18n_combo_Monthly(), recurGroup);
00160 mMonthlyButton->setFixedSize(mMonthlyButton->sizeHint());
00161 mMonthlyButton->setReadOnly(mReadOnly);
00162 mMonthlyButton->setWhatsThis(i18nc("@info:whatsthis", "Repeat the alarm at monthly intervals"));
00163 mRuleButtonGroup->addButton(mMonthlyButton);
00164 vlayout->addWidget(mMonthlyButton);
00165
00166 mYearlyButton = new RadioButton(i18n_combo_Yearly(), recurGroup);
00167 mYearlyButton->setFixedSize(mYearlyButton->sizeHint());
00168 mYearlyButton->setReadOnly(mReadOnly);
00169 mYearlyButton->setWhatsThis(i18nc("@info:whatsthis", "Repeat the alarm at annual intervals"));
00170 mRuleButtonGroup->addButton(mYearlyButton);
00171 vlayout->addWidget(mYearlyButton);
00172 vlayout->addStretch();
00173
00174
00175 mSubRepetition = new RepetitionButton(i18nc("@action:button", "Sub-Repetition"), true, recurGroup);
00176 mSubRepetition->setFixedSize(mSubRepetition->sizeHint());
00177 mSubRepetition->setReadOnly(mReadOnly);
00178 connect(mSubRepetition, SIGNAL(needsInitialisation()), SIGNAL(repeatNeedsInitialisation()));
00179 connect(mSubRepetition, SIGNAL(changed()), SIGNAL(frequencyChanged()));
00180 mSubRepetition->setWhatsThis(i18nc("@info:whatsthis",
00181 "Set up a repetition within the recurrence, to trigger the alarm multiple times each time the recurrence is due."));
00182 vlayout->addSpacing(KDialog::spacingHint());
00183 vlayout->addWidget(mSubRepetition);
00184
00185
00186 vlayout = new QVBoxLayout();
00187 vlayout->setMargin(0);
00188 hlayout->addLayout(vlayout);
00189 QFrame* divider = new QFrame(recurGroup);
00190 divider->setFrameStyle(QFrame::VLine | QFrame::Sunken);
00191 vlayout->addWidget(divider, 1);
00192
00193
00194 mRuleStack = new QStackedWidget(recurGroup);
00195 hlayout->addWidget(mRuleStack);
00196 hlayout->addStretch(1);
00197 mNoRule = new NoRule(mRuleStack);
00198 mSubDailyRule = new SubDailyRule(mReadOnly, mRuleStack);
00199 mDailyRule = new DailyRule(mReadOnly, mRuleStack);
00200 mWeeklyRule = new WeeklyRule(mReadOnly, mRuleStack);
00201 mMonthlyRule = new MonthlyRule(mReadOnly, mRuleStack);
00202 mYearlyRule = new YearlyRule(mReadOnly, mRuleStack);
00203
00204 connect(mSubDailyRule, SIGNAL(frequencyChanged()), this, SIGNAL(frequencyChanged()));
00205 connect(mDailyRule, SIGNAL(frequencyChanged()), this, SIGNAL(frequencyChanged()));
00206 connect(mWeeklyRule, SIGNAL(frequencyChanged()), this, SIGNAL(frequencyChanged()));
00207 connect(mMonthlyRule, SIGNAL(frequencyChanged()), this, SIGNAL(frequencyChanged()));
00208 connect(mYearlyRule, SIGNAL(frequencyChanged()), this, SIGNAL(frequencyChanged()));
00209
00210 mRuleStack->addWidget(mNoRule);
00211 mRuleStack->addWidget(mSubDailyRule);
00212 mRuleStack->addWidget(mDailyRule);
00213 mRuleStack->addWidget(mWeeklyRule);
00214 mRuleStack->addWidget(mMonthlyRule);
00215 mRuleStack->addWidget(mYearlyRule);
00216 hlayout->addSpacing(KDialog::marginHint());
00217
00218
00219
00220
00221 mRangeButtonBox = new QGroupBox(i18nc("@title:group", "Recurrence End"), this);
00222 topLayout->addWidget(mRangeButtonBox);
00223 mRangeButtonGroup = new ButtonGroup(mRangeButtonBox);
00224 connect(mRangeButtonGroup, SIGNAL(buttonSet(QAbstractButton*)), SLOT(rangeTypeClicked()));
00225
00226 vlayout = new QVBoxLayout(mRangeButtonBox);
00227 vlayout->setMargin(KDialog::marginHint());
00228 vlayout->setSpacing(KDialog::spacingHint());
00229 mNoEndDateButton = new RadioButton(i18nc("@option:radio", "No end"), mRangeButtonBox);
00230 mNoEndDateButton->setFixedSize(mNoEndDateButton->sizeHint());
00231 mNoEndDateButton->setReadOnly(mReadOnly);
00232 mNoEndDateButton->setWhatsThis(i18nc("@info:whatsthis", "Repeat the alarm indefinitely"));
00233 mRangeButtonGroup->addButton(mNoEndDateButton);
00234 vlayout->addWidget(mNoEndDateButton, 1, Qt::AlignLeft);
00235 QSize size = mNoEndDateButton->size();
00236
00237 hlayout = new QHBoxLayout();
00238 hlayout->setMargin(0);
00239 vlayout->addLayout(hlayout);
00240 mRepeatCountButton = new RadioButton(i18nc("@option:radio", "End after:"), mRangeButtonBox);
00241 mRepeatCountButton->setReadOnly(mReadOnly);
00242 mRepeatCountButton->setWhatsThis(i18nc("@info:whatsthis", "Repeat the alarm for the number of times specified"));
00243 mRangeButtonGroup->addButton(mRepeatCountButton);
00244 mRepeatCountEntry = new SpinBox(1, 9999, mRangeButtonBox);
00245 mRepeatCountEntry->setFixedSize(mRepeatCountEntry->sizeHint());
00246 mRepeatCountEntry->setSingleShiftStep(10);
00247 mRepeatCountEntry->setSelectOnStep(false);
00248 mRepeatCountEntry->setReadOnly(mReadOnly);
00249 connect(mRepeatCountEntry, SIGNAL(valueChanged(int)), SLOT(repeatCountChanged(int)));
00250 mRepeatCountEntry->setWhatsThis(i18nc("@info:whatsthis", "Enter the total number of times to trigger the alarm"));
00251 mRepeatCountButton->setFocusWidget(mRepeatCountEntry);
00252 mRepeatCountLabel = new QLabel(i18nc("@label", "occurrence(s)"), mRangeButtonBox);
00253 mRepeatCountLabel->setFixedSize(mRepeatCountLabel->sizeHint());
00254 hlayout->addWidget(mRepeatCountButton);
00255 hlayout->addSpacing(KDialog::spacingHint());
00256 hlayout->addWidget(mRepeatCountEntry);
00257 hlayout->addWidget(mRepeatCountLabel);
00258 hlayout->addStretch();
00259 size = size.expandedTo(mRepeatCountButton->sizeHint());
00260
00261 hlayout = new QHBoxLayout();
00262 hlayout->setMargin(0);
00263 vlayout->addLayout(hlayout);
00264 mEndDateButton = new RadioButton(i18nc("@option:radio", "End by:"), mRangeButtonBox);
00265 mEndDateButton->setReadOnly(mReadOnly);
00266 mEndDateButton->setWhatsThis(
00267 i18nc("@info:whatsthis", "<para>Repeat the alarm until the date/time specified.</para>"
00268 "<para><note>This applies to the main recurrence only. It does not limit any sub-repetition which will occur regardless after the last main recurrence.</note></para>"));
00269 mRangeButtonGroup->addButton(mEndDateButton);
00270 mEndDateEdit = new DateEdit(mRangeButtonBox);
00271 mEndDateEdit->setReadOnly(mReadOnly);
00272 static const QString tzText = i18nc("@info/plain", "This uses the same time zone as the start time.");
00273 mEndDateEdit->setWhatsThis(i18nc("@info:whatsthis",
00274 "<para>Enter the last date to repeat the alarm.</para><para>%1</para>", tzText));
00275 mEndDateButton->setFocusWidget(mEndDateEdit);
00276 mEndTimeEdit = new TimeEdit(mRangeButtonBox);
00277 mEndTimeEdit->setFixedSize(mEndTimeEdit->sizeHint());
00278 mEndTimeEdit->setReadOnly(mReadOnly);
00279 mEndTimeEdit->setWhatsThis(i18nc("@info:whatsthis",
00280 "<para>Enter the last time to repeat the alarm.</para><para>%1</para><para>%2</para>", tzText, TimeSpinBox::shiftWhatsThis()));
00281 mEndAnyTimeCheckBox = new CheckBox(i18nc("@option:check", "Any time"), mRangeButtonBox);
00282 mEndAnyTimeCheckBox->setFixedSize(mEndAnyTimeCheckBox->sizeHint());
00283 mEndAnyTimeCheckBox->setReadOnly(mReadOnly);
00284 connect(mEndAnyTimeCheckBox, SIGNAL(toggled(bool)), SLOT(slotAnyTimeToggled(bool)));
00285 mEndAnyTimeCheckBox->setWhatsThis(i18nc("@info:whatsthis", "Stop repeating the alarm after your first login on or after the specified end date"));
00286 hlayout->addWidget(mEndDateButton);
00287 hlayout->addSpacing(KDialog::spacingHint());
00288 hlayout->addWidget(mEndDateEdit);
00289 hlayout->addWidget(mEndTimeEdit);
00290 hlayout->addWidget(mEndAnyTimeCheckBox);
00291 hlayout->addStretch();
00292 size = size.expandedTo(mEndDateButton->sizeHint());
00293
00294
00295 mRepeatCountButton->setFixedSize(size);
00296 mEndDateButton->setFixedSize(size);
00297
00298
00299
00300
00301 mExceptionGroup = new QGroupBox(i18nc("@title:group", "Exceptions"), this);
00302 topLayout->addWidget(mExceptionGroup);
00303 topLayout->setStretchFactor(mExceptionGroup, 2);
00304 hlayout = new QHBoxLayout(mExceptionGroup);
00305 hlayout->setMargin(KDialog::marginHint());
00306 hlayout->setSpacing(KDialog::spacingHint());
00307 vlayout = new QVBoxLayout();
00308 vlayout->setMargin(0);
00309 hlayout->addLayout(vlayout);
00310
00311 mExceptionDateList = new ListWidget(mExceptionGroup);
00312 connect(mExceptionDateList, SIGNAL(currentRowChanged(int)), SLOT(enableExceptionButtons()));
00313 mExceptionDateList->setWhatsThis(i18nc("@info:whatsthis", "The list of exceptions, i.e. dates/times excluded from the recurrence"));
00314 vlayout->addWidget(mExceptionDateList);
00315
00316 if (mReadOnly)
00317 {
00318 mExceptionDateEdit = 0;
00319 mChangeExceptionButton = 0;
00320 mDeleteExceptionButton = 0;
00321 }
00322 else
00323 {
00324 vlayout = new QVBoxLayout();
00325 vlayout->setMargin(0);
00326 hlayout->addLayout(vlayout);
00327 mExceptionDateEdit = new DateEdit(mExceptionGroup);
00328 mExceptionDateEdit->setDate(QDate::currentDate());
00329 mExceptionDateEdit->setWhatsThis(i18nc("@info:whatsthis",
00330 "Enter a date to insert in the exceptions list. "
00331 "Use in conjunction with the Add or Change button below."));
00332 vlayout->addWidget(mExceptionDateEdit, 0, Qt::AlignLeft);
00333
00334 hlayout = new QHBoxLayout();
00335 hlayout->setMargin(0);
00336 vlayout->addLayout(hlayout);
00337 QPushButton* button = new QPushButton(i18nc("@action:button", "Add"), mExceptionGroup);
00338 button->setFixedSize(button->sizeHint());
00339 connect(button, SIGNAL(clicked()), SLOT(addException()));
00340 button->setWhatsThis(i18nc("@info:whatsthis", "Add the date entered above to the exceptions list"));
00341 hlayout->addWidget(button);
00342
00343 mChangeExceptionButton = new QPushButton(i18nc("@action:button", "Change"), mExceptionGroup);
00344 mChangeExceptionButton->setFixedSize(mChangeExceptionButton->sizeHint());
00345 connect(mChangeExceptionButton, SIGNAL(clicked()), SLOT(changeException()));
00346 mChangeExceptionButton->setWhatsThis(i18nc("@info:whatsthis",
00347 "Replace the currently highlighted item in the exceptions list with the date entered above"));
00348 hlayout->addWidget(mChangeExceptionButton);
00349
00350 mDeleteExceptionButton = new QPushButton(i18nc("@action:button", "Delete"), mExceptionGroup);
00351 mDeleteExceptionButton->setFixedSize(mDeleteExceptionButton->sizeHint());
00352 connect(mDeleteExceptionButton, SIGNAL(clicked()), SLOT(deleteException()));
00353 mDeleteExceptionButton->setWhatsThis(i18nc("@info:whatsthis", "Remove the currently highlighted item from the exceptions list"));
00354 hlayout->addWidget(mDeleteExceptionButton);
00355 }
00356
00357 mWorkTimeOnly = new CheckBox(i18nc("@option:check", "Only during working time"), mExceptionGroup);
00358 mWorkTimeOnly->setFixedSize(mWorkTimeOnly->sizeHint());
00359 mWorkTimeOnly->setReadOnly(mReadOnly);
00360 mWorkTimeOnly->setWhatsThis(i18nc("@info:whatsthis",
00361 "<para>Only execute the alarm during working hours, on working days.</para>"
00362 "<para>You can specify working days and hours in the Configuration dialog.</para>"));
00363 vlayout->addWidget(mWorkTimeOnly);
00364
00365 mNoEmitTypeChanged = false;
00366 }
00367
00368
00369
00370
00371
00372 QWidget* RecurrenceEdit::checkData(const KDateTime& startDateTime, QString& errorMessage) const
00373 {
00374 if (mAtLoginButton->isChecked())
00375 return 0;
00376 const_cast<RecurrenceEdit*>(this)->mCurrStartDateTime = startDateTime;
00377 if (mEndDateButton->isChecked())
00378 {
00379
00380 QWidget* errWidget = 0;
00381 bool noTime = !mEndTimeEdit->isEnabled();
00382 QDate endDate = mEndDateEdit->date();
00383 if (endDate < startDateTime.date())
00384 errWidget = mEndDateEdit;
00385 else if (!noTime && QDateTime(endDate, mEndTimeEdit->time()) < startDateTime.dateTime())
00386 errWidget = mEndTimeEdit;
00387 if (errWidget)
00388 {
00389 errorMessage = noTime
00390 ? i18nc("@info", "End date is earlier than start date")
00391 : i18nc("@info", "End date/time is earlier than start date/time");
00392 return errWidget;
00393 }
00394 }
00395 if (!mRule)
00396 return 0;
00397 return mRule->validate(errorMessage);
00398 }
00399
00400
00401
00402
00403 void RecurrenceEdit::periodClicked(QAbstractButton* button)
00404 {
00405 RepeatType oldType = mRuleButtonType;
00406 bool none = (button == mNoneButton);
00407 bool atLogin = (button == mAtLoginButton);
00408 bool subdaily = (button == mSubDailyButton);
00409 if (none)
00410 {
00411 mRule = 0;
00412 mRuleButtonType = NO_RECUR;
00413 }
00414 else if (atLogin)
00415 {
00416 mRule = 0;
00417 mRuleButtonType = AT_LOGIN;
00418 mEndDateButton->setChecked(true);
00419 }
00420 else if (subdaily)
00421 {
00422 mRule = mSubDailyRule;
00423 mRuleButtonType = SUBDAILY;
00424 }
00425 else if (button == mDailyButton)
00426 {
00427 mRule = mDailyRule;
00428 mRuleButtonType = DAILY;
00429 mDailyShown = true;
00430 }
00431 else if (button == mWeeklyButton)
00432 {
00433 mRule = mWeeklyRule;
00434 mRuleButtonType = WEEKLY;
00435 mWeeklyShown = true;
00436 }
00437 else if (button == mMonthlyButton)
00438 {
00439 mRule = mMonthlyRule;
00440 mRuleButtonType = MONTHLY;
00441 mMonthlyShown = true;
00442 }
00443 else if (button == mYearlyButton)
00444 {
00445 mRule = mYearlyRule;
00446 mRuleButtonType = ANNUAL;
00447 mYearlyShown = true;
00448 }
00449 else
00450 return;
00451
00452 if (mRuleButtonType != oldType)
00453 {
00454 mRuleStack->setCurrentWidget(mRule ? mRule : mNoRule);
00455 if (oldType == NO_RECUR || none)
00456 mRangeButtonBox->setEnabled(!none);
00457 mExceptionGroup->setEnabled(!(none || atLogin));
00458 mEndAnyTimeCheckBox->setEnabled(atLogin);
00459 if (!none)
00460 {
00461 mNoEndDateButton->setEnabled(!atLogin);
00462 mRepeatCountButton->setEnabled(!atLogin);
00463 }
00464 rangeTypeClicked();
00465 mSubRepetition->setEnabled(!(none || atLogin));
00466 if (!mNoEmitTypeChanged)
00467 emit typeChanged(mRuleButtonType);
00468 }
00469 }
00470
00471 void RecurrenceEdit::slotAnyTimeToggled(bool on)
00472 {
00473 QAbstractButton* button = mRuleButtonGroup->checkedButton();
00474 mEndTimeEdit->setEnabled((button == mAtLoginButton && !on)
00475 || (button == mSubDailyButton && mEndDateButton->isChecked()));
00476 }
00477
00478
00479
00480
00481 void RecurrenceEdit::rangeTypeClicked()
00482 {
00483 bool endDate = mEndDateButton->isChecked();
00484 mEndDateEdit->setEnabled(endDate);
00485 mEndTimeEdit->setEnabled(endDate
00486 && ((mAtLoginButton->isChecked() && !mEndAnyTimeCheckBox->isChecked())
00487 || mSubDailyButton->isChecked()));
00488 bool repeatCount = mRepeatCountButton->isChecked();
00489 mRepeatCountEntry->setEnabled(repeatCount);
00490 mRepeatCountLabel->setEnabled(repeatCount);
00491 }
00492
00493 void RecurrenceEdit::showEvent(QShowEvent*)
00494 {
00495 if (mRule)
00496 mRule->setFrequencyFocus();
00497 else
00498 mRuleButtonGroup->checkedButton()->setFocus();
00499 emit shown();
00500 }
00501
00502
00503
00504
00505
00506 int RecurrenceEdit::subRepeatCount(Duration* subRepeatInterval) const
00507 {
00508 int count = (mRuleButtonType >= SUBDAILY) ? mSubRepetition->count() : 0;
00509 if (subRepeatInterval)
00510 *subRepeatInterval = count ? mSubRepetition->interval() : Duration(0);
00511 return count;
00512 }
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522 void RecurrenceEdit::setSubRepetition(int reminderMinutes, bool dateOnly)
00523 {
00524 int maxDuration;
00525 switch (mRuleButtonType)
00526 {
00527 case RecurrenceEdit::NO_RECUR:
00528 case RecurrenceEdit::AT_LOGIN:
00529 maxDuration = 0;
00530 break;
00531 default:
00532 {
00533 KAEvent event;
00534 updateEvent(event, false);
00535 maxDuration = event.longestRecurrenceInterval().asSeconds()/60 - reminderMinutes - 1;
00536 break;
00537 }
00538 }
00539 mSubRepetition->initialise(mSubRepetition->interval(), mSubRepetition->count(), dateOnly, maxDuration);
00540 mSubRepetition->setEnabled(mRuleButtonType >= SUBDAILY && maxDuration);
00541 }
00542
00543
00544
00545
00546 void RecurrenceEdit::activateSubRepetition()
00547 {
00548 mSubRepetition->activate();
00549 }
00550
00551
00552
00553
00554
00555 void RecurrenceEdit::repeatCountChanged(int value)
00556 {
00557 if (value > 0 && mRepeatCountEntry->minimum() == 0)
00558 mRepeatCountEntry->setMinimum(1);
00559 }
00560
00561
00562
00563
00564
00565 void RecurrenceEdit::addException()
00566 {
00567 if (!mExceptionDateEdit || !mExceptionDateEdit->isValid())
00568 return;
00569 QDate date = mExceptionDateEdit->date();
00570 DateList::Iterator it;
00571 int index = 0;
00572 bool insert = true;
00573 for (it = mExceptionDates.begin(); it != mExceptionDates.end(); ++index, ++it)
00574 {
00575 if (date <= *it)
00576 {
00577 insert = (date != *it);
00578 break;
00579 }
00580 }
00581 if (insert)
00582 {
00583 mExceptionDates.insert(it, date);
00584 mExceptionDateList->insertItem(index, new QListWidgetItem(KGlobal::locale()->formatDate(date)));
00585 }
00586 mExceptionDateList->setCurrentItem(mExceptionDateList->item(index));
00587 enableExceptionButtons();
00588 }
00589
00590
00591
00592
00593
00594 void RecurrenceEdit::changeException()
00595 {
00596 if (!mExceptionDateEdit || !mExceptionDateEdit->isValid())
00597 return;
00598 QListWidgetItem* item = mExceptionDateList->currentItem();
00599 if (item && mExceptionDateList->isItemSelected(item))
00600 {
00601 int index = mExceptionDateList->row(item);
00602 QDate olddate = mExceptionDates[index];
00603 QDate newdate = mExceptionDateEdit->date();
00604 if (newdate != olddate)
00605 {
00606 mExceptionDates.removeAt(index);
00607 mExceptionDateList->takeItem(index);
00608 addException();
00609 }
00610 }
00611 }
00612
00613
00614
00615
00616 void RecurrenceEdit::deleteException()
00617 {
00618 QListWidgetItem* item = mExceptionDateList->currentItem();
00619 if (item && mExceptionDateList->isItemSelected(item))
00620 {
00621 int index = mExceptionDateList->row(item);
00622 mExceptionDates.removeAt(index);
00623 mExceptionDateList->takeItem(index);
00624 enableExceptionButtons();
00625 }
00626 }
00627
00628
00629
00630
00631
00632 void RecurrenceEdit::enableExceptionButtons()
00633 {
00634 QListWidgetItem* item = mExceptionDateList->currentItem();
00635 bool enable = item;
00636 if (mDeleteExceptionButton)
00637 mDeleteExceptionButton->setEnabled(enable);
00638 if (mChangeExceptionButton)
00639 mChangeExceptionButton->setEnabled(enable);
00640
00641
00642 mExceptionDateList->setFocusPolicy(mExceptionDateList->count() ? Qt::WheelFocus : Qt::NoFocus);
00643 }
00644
00645
00646
00647
00648 void RecurrenceEdit::setStartDate(const QDate& start, const QDate& today)
00649 {
00650 if (!mReadOnly)
00651 {
00652 setRuleDefaults(start);
00653 if (start < today)
00654 {
00655 mEndDateEdit->setMinDate(today);
00656 if (mExceptionDateEdit)
00657 mExceptionDateEdit->setMinDate(today);
00658 }
00659 else
00660 {
00661 const QString startString = i18nc("@info Date cannot be earlier than start date", "start date");
00662 mEndDateEdit->setMinDate(start, startString);
00663 if (mExceptionDateEdit)
00664 mExceptionDateEdit->setMinDate(start, startString);
00665 }
00666 }
00667 }
00668
00669
00670
00671
00672 void RecurrenceEdit::setDefaultEndDate(const QDate& end)
00673 {
00674 if (!mEndDateButton->isChecked())
00675 mEndDateEdit->setDate(end);
00676 }
00677
00678 void RecurrenceEdit::setEndDateTime(const KDateTime& end)
00679 {
00680 KDateTime edt = end.toTimeSpec(mCurrStartDateTime.timeSpec());
00681 mEndDateEdit->setDate(edt.date());
00682 mEndTimeEdit->setValue(edt.time());
00683 mEndTimeEdit->setEnabled(!end.isDateOnly());
00684 mEndAnyTimeCheckBox->setChecked(end.isDateOnly());
00685 }
00686
00687 KDateTime RecurrenceEdit::endDateTime() const
00688 {
00689 if (mRuleButtonGroup->checkedButton() == mAtLoginButton && mEndAnyTimeCheckBox->isChecked())
00690 return KDateTime(mEndDateEdit->date(), mCurrStartDateTime.timeSpec());
00691 return KDateTime(mEndDateEdit->date(), mEndTimeEdit->time(), mCurrStartDateTime.timeSpec());
00692 }
00693
00694
00695
00696
00697 void RecurrenceEdit::setDefaults(const KDateTime& from)
00698 {
00699 mCurrStartDateTime = from;
00700 QDate fromDate = from.date();
00701 mNoEndDateButton->setChecked(true);
00702
00703 mSubDailyRule->setFrequency(1);
00704 mDailyRule->setFrequency(1);
00705 mWeeklyRule->setFrequency(1);
00706 mMonthlyRule->setFrequency(1);
00707 mYearlyRule->setFrequency(1);
00708
00709 setRuleDefaults(fromDate);
00710 mMonthlyRule->setType(MonthYearRule::DATE);
00711 mYearlyRule->setType(MonthYearRule::DATE);
00712
00713 mEndDateEdit->setDate(fromDate);
00714
00715 mNoEmitTypeChanged = true;
00716 RadioButton* button;
00717 switch (Preferences::defaultRecurPeriod())
00718 {
00719 case AT_LOGIN: button = mAtLoginButton; break;
00720 case ANNUAL: button = mYearlyButton; break;
00721 case MONTHLY: button = mMonthlyButton; break;
00722 case WEEKLY: button = mWeeklyButton; break;
00723 case DAILY: button = mDailyButton; break;
00724 case SUBDAILY: button = mSubDailyButton; break;
00725 case NO_RECUR:
00726 default: button = mNoneButton; break;
00727 }
00728 button->setChecked(true);
00729 mNoEmitTypeChanged = false;
00730 rangeTypeClicked();
00731 enableExceptionButtons();
00732
00733 saveState();
00734 }
00735
00736
00737
00738
00739
00740 void RecurrenceEdit::setRuleDefaults(const QDate& fromDate)
00741 {
00742 int day = fromDate.day();
00743 int dayOfWeek = fromDate.dayOfWeek();
00744 int month = fromDate.month();
00745 if (!mDailyShown)
00746 mDailyRule->setDays(true);
00747 if (!mWeeklyShown)
00748 mWeeklyRule->setDay(dayOfWeek);
00749 if (!mMonthlyShown)
00750 mMonthlyRule->setDefaultValues(day, dayOfWeek);
00751 if (!mYearlyShown)
00752 mYearlyRule->setDefaultValues(day, dayOfWeek, month);
00753 }
00754
00755
00756
00757
00758
00759
00760 void RecurrenceEdit::set(const KAEvent& event, bool keepDuration)
00761 {
00762 setDefaults(event.mainDateTime().kDateTime());
00763 if (event.repeatAtLogin())
00764 {
00765 mAtLoginButton->setChecked(true);
00766 mEndDateButton->setChecked(true);
00767 return;
00768 }
00769 mNoneButton->setChecked(true);
00770 KARecurrence* recurrence = event.recurrence();
00771 if (!recurrence)
00772 return;
00773 KARecurrence::Type rtype = recurrence->type();
00774 switch (rtype)
00775 {
00776 case KARecurrence::MINUTELY:
00777 mSubDailyButton->setChecked(true);
00778 break;
00779
00780 case KARecurrence::DAILY:
00781 {
00782 mDailyButton->setChecked(true);
00783 QBitArray rDays = recurrence->days();
00784 bool set = false;
00785 for (int i = 0; i < 7 && !set; ++i)
00786 set = rDays.testBit(i);
00787 if (set)
00788 mDailyRule->setDays(rDays);
00789 else
00790 mDailyRule->setDays(true);
00791 break;
00792 }
00793 case KARecurrence::WEEKLY:
00794 {
00795 mWeeklyButton->setChecked(true);
00796 QBitArray rDays = recurrence->days();
00797 mWeeklyRule->setDays(rDays);
00798 break;
00799 }
00800 case KARecurrence::MONTHLY_POS:
00801 {
00802 QList<RecurrenceRule::WDayPos> posns = recurrence->monthPositions();
00803 int i = posns.first().pos();
00804 if (!i)
00805 {
00806
00807
00808 mWeeklyButton->setChecked(true);
00809 mWeeklyRule->setFrequency(recurrence->frequency());
00810 QBitArray rDays(7);
00811 for (int i = 0, end = posns.count(); i < end; ++i)
00812 {
00813 if (!posns[i].pos())
00814 rDays.setBit(posns[i].day() - 1, 1);
00815 }
00816 mWeeklyRule->setDays(rDays);
00817 break;
00818 }
00819 mMonthlyButton->setChecked(true);
00820 mMonthlyRule->setPosition(i, posns.first().day());
00821 break;
00822 }
00823 case KARecurrence::MONTHLY_DAY:
00824 {
00825 mMonthlyButton->setChecked(true);
00826 QList<int> rmd = recurrence->monthDays();
00827 int day = (rmd.isEmpty()) ? event.mainDate().day() : rmd.first();
00828 mMonthlyRule->setDate(day);
00829 break;
00830 }
00831 case KARecurrence::ANNUAL_DATE:
00832 case KARecurrence::ANNUAL_POS:
00833 {
00834 if (rtype == KARecurrence::ANNUAL_DATE)
00835 {
00836 mYearlyButton->setChecked(true);
00837 const QList<int> rmd = recurrence->monthDays();
00838 int day = (rmd.isEmpty()) ? event.mainDate().day() : rmd.first();
00839 mYearlyRule->setDate(day);
00840 mYearlyRule->setFeb29Type(recurrence->feb29Type());
00841 }
00842 else if (rtype == KARecurrence::ANNUAL_POS)
00843 {
00844 mYearlyButton->setChecked(true);
00845 QList<RecurrenceRule::WDayPos> posns = recurrence->yearPositions();
00846 mYearlyRule->setPosition(posns.first().pos(), posns.first().day());
00847 }
00848 mYearlyRule->setMonths(recurrence->yearMonths());
00849 break;
00850 }
00851 default:
00852 return;
00853 }
00854
00855 mRule->setFrequency(recurrence->frequency());
00856
00857
00858 KDateTime endtime = mCurrStartDateTime;
00859 int duration = recurrence->duration();
00860 if (duration == -1)
00861 mNoEndDateButton->setChecked(true);
00862 else if (duration)
00863 {
00864 mRepeatCountButton->setChecked(true);
00865 mRepeatCountEntry->setValue(duration);
00866 }
00867 else
00868 {
00869 mEndDateButton->setChecked(true);
00870 endtime = recurrence->endDateTime();
00871 mEndTimeEdit->setValue(endtime.time());
00872 }
00873 mEndDateEdit->setDate(endtime.date());
00874
00875
00876 mExceptionDates = event.recurrence()->exDates();
00877 qSort(mExceptionDates);
00878 mExceptionDateList->clear();
00879 for (DateList::ConstIterator it = mExceptionDates.begin(); it != mExceptionDates.end(); ++it)
00880 new QListWidgetItem(KGlobal::locale()->formatDate(*it), mExceptionDateList);
00881 enableExceptionButtons();
00882 mWorkTimeOnly->setChecked(event.workTimeOnly());
00883
00884
00885 mSubRepetition->set(event.repeatInterval(), event.repeatCount());
00886
00887 rangeTypeClicked();
00888
00889 saveState();
00890 }
00891
00892
00893
00894
00895
00896
00897 void RecurrenceEdit::updateEvent(KAEvent& event, bool adjustStart)
00898 {
00899
00900 QDate endDate;
00901 QTime endTime;
00902 int repeatCount;
00903 if (mNoEndDateButton->isChecked())
00904 repeatCount = -1;
00905 else if (mRepeatCountButton->isChecked())
00906 repeatCount = mRepeatCountEntry->value();
00907 else
00908 {
00909 repeatCount = 0;
00910 endDate = mEndDateEdit->date();
00911 endTime = mEndTimeEdit->time();
00912 }
00913
00914
00915 event.startChanges();
00916 QAbstractButton* button = mRuleButtonGroup->checkedButton();
00917 event.setRepeatAtLogin(button == mAtLoginButton);
00918 int frequency = mRule ? mRule->frequency() : 0;
00919 if (button == mSubDailyButton)
00920 {
00921 KDateTime endDateTime(endDate, endTime, mCurrStartDateTime.timeSpec());
00922 event.setRecurMinutely(frequency, repeatCount, endDateTime);
00923 }
00924 else if (button == mDailyButton)
00925 {
00926 event.setRecurDaily(frequency, mDailyRule->days(), repeatCount, endDate);
00927 }
00928 else if (button == mWeeklyButton)
00929 {
00930 event.setRecurWeekly(frequency, mWeeklyRule->days(), repeatCount, endDate);
00931 }
00932 else if (button == mMonthlyButton)
00933 {
00934 if (mMonthlyRule->type() == MonthlyRule::POS)
00935 {
00936
00937 KAEvent::MonthPos pos;
00938 pos.days.fill(false);
00939 pos.days.setBit(mMonthlyRule->dayOfWeek() - 1);
00940 pos.weeknum = mMonthlyRule->week();
00941 QList<KAEvent::MonthPos> poses;
00942 poses.append(pos);
00943 event.setRecurMonthlyByPos(frequency, poses, repeatCount, endDate);
00944 }
00945 else
00946 {
00947
00948 int daynum = mMonthlyRule->date();
00949 QList<int> daynums;
00950 daynums.append(daynum);
00951 event.setRecurMonthlyByDate(frequency, daynums, repeatCount, endDate);
00952 }
00953 }
00954 else if (button == mYearlyButton)
00955 {
00956 QList<int> months = mYearlyRule->months();
00957 if (mYearlyRule->type() == YearlyRule::POS)
00958 {
00959
00960 KAEvent::MonthPos pos;
00961 pos.days.fill(false);