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 <kglobal.h> 00038 #include <klocale.h> 00039 #include <kcalendarsystem.h> 00040 #include <kiconloader.h> 00041 #include <kdialog.h> 00042 #include <kmessagebox.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 * Called when the value of the repeat count field changes, to reset the 00535 * minimum value to 1 if the value was 0. 00536 */ 00537 void RecurrenceEdit::repeatCountChanged(int value) 00538 { 00539 if (value > 0 && mRepeatCountEntry->minValue() == 0) 00540 mRepeatCountEntry->setMinValue(1); 00541 } 00542 00543 /****************************************************************************** 00544 * Add the date entered in the exception date edit control to the list of 00545 * exception dates. 00546 */ 00547 void RecurrenceEdit::addException() 00548 { 00549 if (!mExceptionDateEdit || !mExceptionDateEdit->isValid()) 00550 return; 00551 TQDate date = mExceptionDateEdit->date(); 00552 TQValueList<TQDate>::Iterator it; 00553 int index = 0; 00554 bool insert = true; 00555 for (it = mExceptionDates.begin(); it != mExceptionDates.end(); ++index, ++it) 00556 { 00557 if (date <= *it) 00558 { 00559 insert = (date != *it); 00560 break; 00561 } 00562 } 00563 if (insert) 00564 { 00565 mExceptionDates.insert(it, date); 00566 mExceptionDateList->insertItem(KGlobal::locale()->formatDate(date), index); 00567 } 00568 mExceptionDateList->setCurrentItem(index); 00569 enableExceptionButtons(); 00570 } 00571 00572 /****************************************************************************** 00573 * Change the currently highlighted exception date to that entered in the 00574 * exception date edit control. 00575 */ 00576 void RecurrenceEdit::changeException() 00577 { 00578 if (!mExceptionDateEdit || !mExceptionDateEdit->isValid()) 00579 return; 00580 int index = mExceptionDateList->currentItem(); 00581 if (index >= 0 && mExceptionDateList->isSelected(index)) 00582 { 00583 TQDate olddate = mExceptionDates[index]; 00584 TQDate newdate = mExceptionDateEdit->date(); 00585 if (newdate != olddate) 00586 { 00587 mExceptionDates.remove(mExceptionDates.at(index)); 00588 mExceptionDateList->removeItem(index); 00589 addException(); 00590 } 00591 } 00592 } 00593 00594 /****************************************************************************** 00595 * Delete the currently highlighted exception date. 00596 */ 00597 void RecurrenceEdit::deleteException() 00598 { 00599 int index = mExceptionDateList->currentItem(); 00600 if (index >= 0 && mExceptionDateList->isSelected(index)) 00601 { 00602 mExceptionDates.remove(mExceptionDates.at(index)); 00603 mExceptionDateList->removeItem(index); 00604 enableExceptionButtons(); 00605 } 00606 } 00607 00608 /****************************************************************************** 00609 * Enable/disable the exception group buttons according to whether any item is 00610 * selected in the exceptions listbox. 00611 */ 00612 void RecurrenceEdit::enableExceptionButtons() 00613 { 00614 int index = mExceptionDateList->currentItem(); 00615 bool enable = (index >= 0 && mExceptionDateList->isSelected(index)); 00616 if (mDeleteExceptionButton) 00617 mDeleteExceptionButton->setEnabled(enable); 00618 if (mChangeExceptionButton) 00619 mChangeExceptionButton->setEnabled(enable); 00620 00621 // Prevent the exceptions list box receiving keyboard focus is it's empty 00622 mExceptionDateList->setFocusPolicy(mExceptionDateList->count() ? TQ_WheelFocus : TQ_NoFocus); 00623 } 00624 00625 /****************************************************************************** 00626 * Notify this instance of a change in the alarm start date. 00627 */ 00628 void RecurrenceEdit::setStartDate(const TQDate& start, const TQDate& today) 00629 { 00630 if (!mReadOnly) 00631 { 00632 setRuleDefaults(start); 00633 if (start < today) 00634 { 00635 mEndDateEdit->setMinDate(today); 00636 if (mExceptionDateEdit) 00637 mExceptionDateEdit->setMinDate(today); 00638 } 00639 else 00640 { 00641 const TQString startString = i18n("Date cannot be earlier than start date", "start date"); 00642 mEndDateEdit->setMinDate(start, startString); 00643 if (mExceptionDateEdit) 00644 mExceptionDateEdit->setMinDate(start, startString); 00645 } 00646 } 00647 } 00648 00649 /****************************************************************************** 00650 * Specify the default recurrence end date. 00651 */ 00652 void RecurrenceEdit::setDefaultEndDate(const TQDate& end) 00653 { 00654 if (!mEndDateButton->isOn()) 00655 mEndDateEdit->setDate(end); 00656 } 00657 00658 void RecurrenceEdit::setEndDateTime(const DateTime& end) 00659 { 00660 mEndDateEdit->setDate(end.date()); 00661 mEndTimeEdit->setValue(end.time()); 00662 mEndTimeEdit->setEnabled(!end.isDateOnly()); 00663 mEndAnyTimeCheckBox->setChecked(end.isDateOnly()); 00664 } 00665 00666 DateTime RecurrenceEdit::endDateTime() const 00667 { 00668 if (mRuleButtonGroup->selected() == mAtLoginButton && mEndAnyTimeCheckBox->isChecked()) 00669 return DateTime(mEndDateEdit->date()); 00670 return DateTime(mEndDateEdit->date(), mEndTimeEdit->time()); 00671 } 00672 00673 /****************************************************************************** 00674 * Set all controls to their default values. 00675 */ 00676 void RecurrenceEdit::setDefaults(const TQDateTime& from) 00677 { 00678 mCurrStartDateTime = from; 00679 TQDate fromDate = from.date(); 00680 mNoEndDateButton->setChecked(true); 00681 00682 mSubDailyRule->setFrequency(1); 00683 mDailyRule->setFrequency(1); 00684 mWeeklyRule->setFrequency(1); 00685 mMonthlyRule->setFrequency(1); 00686 mYearlyRule->setFrequency(1); 00687 00688 setRuleDefaults(fromDate); 00689 mMonthlyRule->setType(MonthYearRule::DATE); // date in month 00690 mYearlyRule->setType(MonthYearRule::DATE); // date in year 00691 00692 mEndDateEdit->setDate(fromDate); 00693 00694 mNoEmitTypeChanged = true; 00695 int button; 00696 switch (Preferences::defaultRecurPeriod()) 00697 { 00698 case AT_LOGIN: button = mAtLoginButtonId; break; 00699 case ANNUAL: button = mYearlyButtonId; break; 00700 case MONTHLY: button = mMonthlyButtonId; break; 00701 case WEEKLY: button = mWeeklyButtonId; break; 00702 case DAILY: button = mDailyButtonId; break; 00703 case SUBDAILY: button = mSubDailyButtonId; break; 00704 case NO_RECUR: 00705 default: button = mNoneButtonId; break; 00706 } 00707 mRuleButtonGroup->setButton(button); 00708 mNoEmitTypeChanged = false; 00709 rangeTypeClicked(); 00710 enableExceptionButtons(); 00711 00712 saveState(); 00713 } 00714 00715 /****************************************************************************** 00716 * Set the controls for weekly, monthly and yearly rules which have not so far 00717 * been shown, to their default values, depending on the recurrence start date. 00718 */ 00719 void RecurrenceEdit::setRuleDefaults(const TQDate& fromDate) 00720 { 00721 int day = fromDate.day(); 00722 int dayOfWeek = fromDate.dayOfWeek(); 00723 int month = fromDate.month(); 00724 if (!mDailyShown) 00725 mDailyRule->setDays(true); 00726 if (!mWeeklyShown) 00727 mWeeklyRule->setDay(dayOfWeek); 00728 if (!mMonthlyShown) 00729 mMonthlyRule->setDefaultValues(day, dayOfWeek); 00730 if (!mYearlyShown) 00731 mYearlyRule->setDefaultValues(day, dayOfWeek, month); 00732 } 00733 00734 /****************************************************************************** 00735 * Set the state of all controls to reflect the data in the specified event. 00736 * Set 'keepDuration' true to prevent the recurrence count being adjusted to the 00737 * remaining number of recurrences. 00738 */ 00739 void RecurrenceEdit::set(const KAEvent& event, bool keepDuration) 00740 { 00741 setDefaults(event.mainDateTime().dateTime()); 00742 if (event.repeatAtLogin()) 00743 { 00744 mRuleButtonGroup->setButton(mAtLoginButtonId); 00745 mEndDateButton->setChecked(true); 00746 return; 00747 } 00748 mRuleButtonGroup->setButton(mNoneButtonId); 00749 KARecurrence* recurrence = event.recurrence(); 00750 if (!recurrence) 00751 return; 00752 KARecurrence::Type rtype = recurrence->type(); 00753 switch (rtype) 00754 { 00755 case KARecurrence::MINUTELY: 00756 mRuleButtonGroup->setButton(mSubDailyButtonId); 00757 break; 00758 00759 case KARecurrence::DAILY: 00760 { 00761 mRuleButtonGroup->setButton(mDailyButtonId); 00762 TQBitArray rDays = recurrence->days(); 00763 bool set = false; 00764 for (int i = 0; i < 7 && !set; ++i) 00765 set = rDays.testBit(i); 00766 if (set) 00767 mDailyRule->setDays(rDays); 00768 else 00769 mDailyRule->setDays(true); 00770 break; 00771 } 00772 case KARecurrence::WEEKLY: 00773 { 00774 mRuleButtonGroup->setButton(mWeeklyButtonId); 00775 TQBitArray rDays = recurrence->days(); 00776 mWeeklyRule->setDays(rDays); 00777 break; 00778 } 00779 case KARecurrence::MONTHLY_POS: // on nth (Tuesday) of the month 00780 { 00781 TQValueList<RecurrenceRule::WDayPos> posns = recurrence->monthPositions(); 00782 int i = posns.first().pos(); 00783 if (!i) 00784 { 00785 // It's every (Tuesday) of the month. Convert to a weekly recurrence 00786 // (but ignoring any non-every xxxDay positions). 00787 mRuleButtonGroup->setButton(mWeeklyButtonId); 00788 mWeeklyRule->setFrequency(recurrence->frequency()); 00789 TQBitArray rDays(7); 00790 for (TQValueList<RecurrenceRule::WDayPos>::ConstIterator it = posns.begin(); it != posns.end(); ++it) 00791 { 00792 if (!(*it).pos()) 00793 rDays.setBit((*it).day() - 1, 1); 00794 } 00795 mWeeklyRule->setDays(rDays); 00796 break; 00797 } 00798 mRuleButtonGroup->setButton(mMonthlyButtonId); 00799 mMonthlyRule->setPosition(i, posns.first().day()); 00800 break; 00801 } 00802 case KARecurrence::MONTHLY_DAY: // on nth day of the month 00803 { 00804 mRuleButtonGroup->setButton(mMonthlyButtonId); 00805 TQValueList<int> rmd = recurrence->monthDays(); 00806 int day = (rmd.isEmpty()) ? event.mainDate().day() : rmd.first(); 00807 mMonthlyRule->setDate(day); 00808 break; 00809 } 00810 case KARecurrence::ANNUAL_DATE: // on the nth day of (months...) in the year 00811 case KARecurrence::ANNUAL_POS: // on the nth (Tuesday) of (months...) in the year 00812 { 00813 if (rtype == KARecurrence::ANNUAL_DATE) 00814 { 00815 mRuleButtonGroup->setButton(mYearlyButtonId); 00816 const TQValueList<int> rmd = recurrence->monthDays(); 00817 int day = (rmd.isEmpty()) ? event.mainDate().day() : rmd.first(); 00818 mYearlyRule->setDate(day); 00819 mYearlyRule->setFeb29Type(recurrence->feb29Type()); 00820 } 00821 else if (rtype == KARecurrence::ANNUAL_POS) 00822 { 00823 mRuleButtonGroup->setButton(mYearlyButtonId); 00824 TQValueList<RecurrenceRule::WDayPos> posns = recurrence->yearPositions(); 00825 mYearlyRule->setPosition(posns.first().pos(), posns.first().day()); 00826 } 00827 mYearlyRule->setMonths(recurrence->yearMonths()); 00828 break; 00829 } 00830 default: 00831 return; 00832 } 00833 00834 mRule->setFrequency(recurrence->frequency()); 00835 00836 // Get range information 00837 TQDateTime endtime = mCurrStartDateTime; 00838 int duration = recurrence->duration(); 00839 if (duration == -1) 00840 mNoEndDateButton->setChecked(true); 00841 else if (duration) 00842 { 00843 mRepeatCountButton->setChecked(true); 00844 mRepeatCountEntry->setValue(duration); 00845 } 00846 else 00847 { 00848 mEndDateButton->setChecked(true); 00849 endtime = recurrence->endDateTime(); 00850 mEndTimeEdit->setValue(endtime.time()); 00851 } 00852 mEndDateEdit->setDate(endtime.date()); 00853 00854 // Get exception information 00855 mExceptionDates = event.recurrence()->exDates(); 00856 qHeapSort(mExceptionDates); 00857 mExceptionDateList->clear(); 00858 for (DateList::ConstIterator it = mExceptionDates.begin(); it != mExceptionDates.end(); ++it) 00859 mExceptionDateList->insertItem(KGlobal::locale()->formatDate(*it)); 00860 enableExceptionButtons(); 00861 00862 // Get repetition within recurrence 00863 mSubRepetition->set(event.repeatInterval(), event.repeatCount()); 00864 00865 rangeTypeClicked(); 00866 00867 saveState(); 00868 } 00869 00870 /****************************************************************************** 00871 * Update the specified KAEvent with the entered recurrence data. 00872 * If 'adjustStart' is true, the start date/time will be adjusted if necessary 00873 * to be the first date/time which recurs on or after the original start. 00874 */ 00875 void RecurrenceEdit::updateEvent(KAEvent& event, bool adjustStart) 00876 { 00877 // Get end date and repeat count, common to all types of recurring events 00878 TQDate endDate; 00879 TQTime endTime; 00880 int repeatCount; 00881 if (mNoEndDateButton->isChecked()) 00882 repeatCount = -1; 00883 else if (mRepeatCountButton->isChecked()) 00884 repeatCount = mRepeatCountEntry->value(); 00885 else 00886 { 00887 repeatCount = 0; 00888 endDate = mEndDateEdit->date(); 00889 endTime = mEndTimeEdit->time(); 00890 } 00891 00892 // Set up the recurrence according to the type selected 00893 TQButton* button = mRuleButtonGroup->selected(); 00894 event.setRepeatAtLogin(button == mAtLoginButton); 00895 int frequency = mRule ? mRule->frequency() : 0; 00896 if (button == mSubDailyButton) 00897 { 00898 TQDateTime endDateTime(endDate, endTime); 00899 event.setRecurMinutely(frequency, repeatCount, endDateTime); 00900 } 00901 else if (button == mDailyButton) 00902 { 00903 event.setRecurDaily(frequency, mDailyRule->days(), repeatCount, endDate); 00904 } 00905 else if (button == mWeeklyButton) 00906 { 00907 event.setRecurWeekly(frequency, mWeeklyRule->days(), repeatCount, endDate); 00908 } 00909 else if (button == mMonthlyButton) 00910 { 00911 if (mMonthlyRule->type() == MonthlyRule::POS) 00912 { 00913 // It's by position 00914 KAEvent::MonthPos pos; 00915 pos.days.fill(false); 00916 pos.days.setBit(mMonthlyRule->dayOfWeek() - 1); 00917 pos.weeknum = mMonthlyRule->week(); 00918 TQValueList<KAEvent::MonthPos> poses; 00919 poses.append(pos); 00920 event.setRecurMonthlyByPos(frequency, poses, repeatCount, endDate); 00921 } 00922 else 00923 { 00924 // It's by day 00925 int daynum = mMonthlyRule->date(); 00926 TQValueList<int> daynums; 00927 daynums.append(daynum); 00928 event.setRecurMonthlyByDate(frequency, daynums, repeatCount, endDate); 00929 } 00930 } 00931 else if (button == mYearlyButton) 00932 { 00933 TQValueList<int> months = mYearlyRule->months(); 00934 if (mYearlyRule->type() == YearlyRule::POS) 00935 { 00936 // It's by position 00937 KAEvent::MonthPos pos; 00938 pos.days.fill(false); 00939 pos.days.setBit(mYearlyRule->dayOfWeek() - 1); 00940 pos.weeknum = mYearlyRule->week(); 00941 TQValueList<KAEvent::MonthPos> poses; 00942 poses.append(pos); 00943 event.setRecurAnnualByPos(frequency, poses, months, repeatCount, endDate); 00944 } 00945 else 00946 { 00947 // It's by date in month 00948 event.setRecurAnnualByDate(frequency, months, mYearlyRule->date(), 00949 mYearlyRule->feb29Type(), repeatCount, endDate); 00950 } 00951 } 00952 else 00953 { 00954 event.setNoRecur(); 00955 return; 00956 } 00957 if (!event.recurs()) 00958 return; // an error occurred setting up the recurrence 00959 if (adjustStart) 00960 event.setFirstRecurrence(); 00961 00962 // Set up repetition within the recurrence. 00963 // N.B. This requires the main recurrence to be set up first. 00964 int count = mSubRepetition->count(); 00965 if (mRuleButtonType < SUBDAILY) 00966 count = 0; 00967 event.setRepetition(mSubRepetition->interval(), count); 00968 00969 // Set up exceptions 00970 event.recurrence()->setExDates(mExceptionDates); 00971 00972 event.setUpdated(); 00973 } 00974 00975 /****************************************************************************** 00976 * Save the state of all controls. 00977 */ 00978 void RecurrenceEdit::saveState() 00979 { 00980 mSavedRuleButton = mRuleButtonGroup->selected(); 00981 if (mRule) 00982 mRule->saveState(); 00983 mSavedRangeButton = mRangeButtonGroup->selected(); 00984 if (mSavedRangeButton == mRepeatCountButton) 00985 mSavedRecurCount = mRepeatCountEntry->value(); 00986 else if (mSavedRangeButton == mEndDateButton) 00987 mSavedEndDateTime.set(TQDateTime(mEndDateEdit->date(), mEndTimeEdit->time()), mEndAnyTimeCheckBox->isChecked()); 00988 mSavedExceptionDates = mExceptionDates; 00989 mSavedRepeatInterval = mSubRepetition->interval(); 00990 mSavedRepeatCount = mSubRepetition->count(); 00991 } 00992 00993 /****************************************************************************** 00994 * Check whether any of the controls have changed state since initialisation. 00995 */ 00996 bool RecurrenceEdit::stateChanged() const 00997 { 00998 if (mSavedRuleButton != mRuleButtonGroup->selected() 00999 || mSavedRangeButton != mRangeButtonGroup->selected() 01000 || mRule && mRule->stateChanged()) 01001 return true; 01002 if (mSavedRangeButton == mRepeatCountButton 01003 && mSavedRecurCount != mRepeatCountEntry->value()) 01004 return true; 01005 if (mSavedRangeButton == mEndDateButton 01006 && mSavedEndDateTime != DateTime(TQDateTime(mEndDateEdit->date(), mEndTimeEdit->time()), mEndAnyTimeCheckBox->isChecked())) 01007 return true; 01008 if (mSavedExceptionDates != mExceptionDates 01009 || mSavedRepeatInterval != mSubRepetition->interval() 01010 || mSavedRepeatCount != mSubRepetition->count()) 01011 return true; 01012 return false; 01013 } 01014 01015 01016 01017 /*============================================================================= 01018 = Class Rule 01019 = Base class for rule widgets, including recurrence frequency. 01020 =============================================================================*/ 01021 01022 Rule::Rule(const TQString& freqText, const TQString& freqWhatsThis, bool time, bool readOnly, TQWidget* parent, const char* name) 01023 : NoRule(parent, name) 01024 { 01025 mLayout = new TQVBoxLayout(this, 0, KDialog::spacingHint()); 01026 TQHBox* freqBox = new TQHBox(this); 01027 mLayout->addWidget(freqBox); 01028 TQHBox* box = new TQHBox(freqBox); // this is to control the TQWhatsThis text display area 01029 box->setSpacing(KDialog::spacingHint()); 01030 01031 TQLabel* label = new TQLabel(i18n("Recur e&very"), box); 01032 label->setFixedSize(label->sizeHint()); 01033 if (time) 01034 { 01035 mIntSpinBox = 0; 01036 mSpinBox = mTimeSpinBox = new TimeSpinBox(1, 5999, box); 01037 mTimeSpinBox->setFixedSize(mTimeSpinBox->sizeHint()); 01038 mTimeSpinBox->setReadOnly(readOnly); 01039 } 01040 else 01041 { 01042 mTimeSpinBox = 0; 01043 mSpinBox = mIntSpinBox = new SpinBox(1, 999, 1, box); 01044 mIntSpinBox->setFixedSize(mIntSpinBox->sizeHint()); 01045 mIntSpinBox->setReadOnly(readOnly); 01046 } 01047 connect(mSpinBox, TQT_SIGNAL(valueChanged(int)), TQT_SIGNAL(frequencyChanged())); 01048 label->setBuddy(mSpinBox); 01049 label = new TQLabel(freqText, box); 01050 label->setFixedSize(label->sizeHint()); 01051 box->setFixedSize(sizeHint()); 01052 TQWhatsThis::add(box, freqWhatsThis); 01053 01054 new TQWidget(freqBox); // left adjust the visible widgets 01055 freqBox->setFixedHeight(freqBox->sizeHint().height()); 01056 freqBox->setFocusProxy(mSpinBox); 01057 } 01058 01059 int Rule::frequency() const 01060 { 01061 if (mIntSpinBox) 01062 return mIntSpinBox->value(); 01063 if (mTimeSpinBox) 01064 return mTimeSpinBox->value(); 01065 return 0; 01066 } 01067 01068 void Rule::setFrequency(int n) 01069 { 01070 if (mIntSpinBox) 01071 mIntSpinBox->setValue(n); 01072 if (mTimeSpinBox) 01073 mTimeSpinBox->setValue(n); 01074 } 01075 01076 /****************************************************************************** 01077 * Save the state of all controls. 01078 */ 01079 void Rule::saveState() 01080 { 01081 mSavedFrequency = frequency(); 01082 } 01083 01084 /****************************************************************************** 01085 * Check whether any of the controls have changed state since initialisation. 01086 */ 01087 bool Rule::stateChanged() const 01088 { 01089 return (mSavedFrequency != frequency()); 01090 } 01091 01092 01093 /*============================================================================= 01094 = Class SubDailyRule 01095 = Sub-daily rule widget. 01096 =============================================================================*/ 01097 01098 SubDailyRule::SubDailyRule(bool readOnly, TQWidget* parent, const char* name) 01099 : Rule(i18n("hours:minutes"), 01100 i18n("Enter the number of hours and minutes between repetitions of the alarm"), 01101 true, readOnly, parent, name) 01102 { } 01103 01104 01105 /*============================================================================= 01106 = Class DayWeekRule 01107 = Daily/weekly rule widget base class. 01108 =============================================================================*/ 01109 01110 DayWeekRule::DayWeekRule(const TQString& freqText, const TQString& freqWhatsThis, const TQString& daysWhatsThis, 01111 bool readOnly, TQWidget* parent, const char* name) 01112 : Rule(freqText, freqWhatsThis, false, readOnly, parent, name), 01113 mSavedDays(7) 01114 { 01115 TQGridLayout* grid = new TQGridLayout(layout(), 1, 4, KDialog::spacingHint()); 01116 grid->setRowStretch(0, 1); 01117 01118 TQLabel* label = new TQLabel(i18n("On: Tuesday", "O&n:"), this); 01119 label->setFixedSize(label->sizeHint()); 01120 grid->addWidget(label, 0, 0, TQt::AlignRight | TQt::AlignTop); 01121 grid->addColSpacing(1, KDialog::spacingHint()); 01122 01123 // List the days of the week starting at the user's start day of the week. 01124 // Save the first day of the week, just in case it changes while the dialog is open. 01125 TQWidget* box = new TQWidget(this); // this is to control the TQWhatsThis text display area 01126 TQGridLayout* dgrid = new TQGridLayout(box, 4, 2, 0, KDialog::spacingHint()); 01127 const KCalendarSystem* calendar = KGlobal::locale()->calendar(); 01128 for (int i = 0; i < 7; ++i) 01129 { 01130 int day = KAlarm::localeDayInWeek_to_weekDay(i); 01131 mDayBox[i] = new CheckBox(calendar->weekDayName(day), box); 01132 mDayBox[i]->setFixedSize(mDayBox[i]->sizeHint()); 01133 mDayBox[i]->setReadOnly(readOnly); 01134 dgrid->addWidget(mDayBox[i], i%4, i/4, TQt::AlignAuto); 01135 } 01136 box->setFixedSize(box->sizeHint()); 01137 TQWhatsThis::add(box, daysWhatsThis); 01138 grid->addWidget(box, 0, 2, TQt::AlignAuto); 01139 label->setBuddy(mDayBox[0]); 01140 grid->setColStretch(3, 1); 01141 } 01142 01143 /****************************************************************************** 01144 * Fetch which days of the week have been ticked. 01145 */ 01146 TQBitArray DayWeekRule::days() const 01147 { 01148 TQBitArray ds(7); 01149 ds.fill(false); 01150 for (int i = 0; i < 7; ++i) 01151 if (mDayBox[i]->isChecked()) 01152 ds.setBit(KAlarm::localeDayInWeek_to_weekDay(i) - 1, 1); 01153 return ds; 01154 } 01155 01156 /****************************************************************************** 01157 * Tick/untick every day of the week. 01158 */ 01159 void DayWeekRule::setDays(bool tick) 01160 { 01161 for (int i = 0; i < 7; ++i) 01162 mDayBox[i]->setChecked(tick); 01163 } 01164 01165 /****************************************************************************** 01166 * Tick/untick each day of the week according to the specified bits. 01167 */ 01168 void DayWeekRule::setDays(const TQBitArray& days) 01169 { 01170 for (int i = 0; i < 7; ++i) 01171 { 01172 bool x = days.testBit(KAlarm::localeDayInWeek_to_weekDay(i) - 1); 01173 mDayBox[i]->setChecked(x); 01174 } 01175 } 01176 01177 /****************************************************************************** 01178 * Tick the specified day of the week, and untick all other days. 01179 */ 01180 void DayWeekRule::setDay(int dayOfWeek) 01181 { 01182 for (int i = 0; i < 7; ++i) 01183 mDayBox[i]->setChecked(false); 01184 if (dayOfWeek > 0 && dayOfWeek <= 7) 01185 mDayBox[KAlarm::weekDay_to_localeDayInWeek(dayOfWeek)]->setChecked(true); 01186 } 01187 01188 /****************************************************************************** 01189 * Validate: check that at least one day is selected. 01190 */ 01191 TQWidget* DayWeekRule::validate(TQString& errorMessage) 01192 { 01193 for (int i = 0; i < 7; ++i) 01194 if (mDayBox[i]->isChecked()) 01195 return 0; 01196 errorMessage = i18n("No day selected"); 01197 return mDayBox[0]; 01198 } 01199 01200 /****************************************************************************** 01201 * Save the state of all controls. 01202 */ 01203 void DayWeekRule::saveState() 01204 { 01205 Rule::saveState(); 01206 mSavedDays = days(); 01207 } 01208 01209 /****************************************************************************** 01210 * Check whether any of the controls have changed state since initialisation. 01211 */ 01212 bool DayWeekRule::stateChanged() const 01213 { 01214 return (Rule::stateChanged() 01215 || mSavedDays != days()); 01216 } 01217 01218 01219 /*============================================================================= 01220 = Class DailyRule 01221 = Daily rule widget. 01222 =============================================================================*/ 01223 01224 DailyRule::DailyRule(bool readOnly, TQWidget* parent, const char* name) 01225 : DayWeekRule(i18n("day(s)"), 01226 i18n("Enter the number of days between repetitions of the alarm"), 01227 i18n("Select the days of the week on which the alarm is allowed to occur"), 01228 readOnly, parent, name) 01229 { } 01230 01231 01232 /*============================================================================= 01233 = Class WeeklyRule 01234 = Weekly rule widget. 01235 =============================================================================*/ 01236 01237 WeeklyRule::WeeklyRule(bool readOnly, TQWidget* parent, const char* name) 01238 : DayWeekRule(i18n("week(s)"), 01239 i18n("Enter the number of weeks between repetitions of the alarm"), 01240 i18n("Select the days of the week on which to repeat the alarm"), 01241 readOnly, parent, name) 01242 { } 01243 01244 01245 /*============================================================================= 01246 = Class MonthYearRule 01247 = Monthly/yearly rule widget base class. 01248 =============================================================================*/ 01249 01250 MonthYearRule::MonthYearRule(const TQString& freqText, const TQString& freqWhatsThis, bool allowEveryWeek, 01251 bool readOnly, TQWidget* parent, const char* name) 01252 : Rule(freqText, freqWhatsThis, false, readOnly, parent, name), 01253 mEveryWeek(allowEveryWeek) 01254 { 01255 mButtonGroup = new ButtonGroup(this); 01256 mButtonGroup->hide(); 01257 01258 // Month day selector 01259 TQHBox* box = new TQHBox(this); 01260 box->setSpacing(KDialog::spacingHint()); 01261 layout()->addWidget(box); 01262 01263 mDayButton = new RadioButton(i18n("On day number in the month", "O&n day"), box); 01264 mDayButton->setFixedSize(mDayButton->sizeHint()); 01265 mDayButton->setReadOnly(readOnly); 01266 mDayButtonId = mButtonGroup->insert(mDayButton); 01267 TQWhatsThis::add(mDayButton, i18n("Repeat the alarm on the selected day of the month")); 01268 01269 mDayCombo = new ComboBox(false, box); 01270 mDayCombo->setSizeLimit(11); 01271 for (int i = 0; i < 31; ++i) 01272 mDayCombo->insertItem(TQString::number(i + 1)); 01273 mDayCombo->insertItem(i18n("Last day of month", "Last")); 01274 mDayCombo->setFixedSize(mDayCombo->sizeHint()); 01275 mDayCombo->setReadOnly(readOnly); 01276 TQWhatsThis::add(mDayCombo, i18n("Select the day of the month on which to repeat the alarm")); 01277 mDayButton->setFocusWidget(mDayCombo); 01278 connect(mDayCombo, TQT_SIGNAL(activated(int)), TQT_SLOT(slotDaySelected(int))); 01279 01280 box->setStretchFactor(new TQWidget(box), 1); // left adjust the controls 01281 box->setFixedHeight(box->sizeHint().height()); 01282 01283 // Month position selector 01284 box = new TQHBox(this); 01285 box->setSpacing(KDialog::spacingHint()); 01286 layout()->addWidget(box); 01287 01288 mPosButton = new RadioButton(i18n("On the 1st Tuesday", "On t&he"), box); 01289 mPosButton->setFixedSize(mPosButton->sizeHint()); 01290 mPosButton->setReadOnly(readOnly); 01291 mPosButtonId = mButtonGroup->insert(mPosButton); 01292 TQWhatsThis::add(mPosButton, 01293 i18n("Repeat the alarm on one day of the week, in the selected week of the month")); 01294 01295 mWeekCombo = new ComboBox(false, box); 01296 mWeekCombo->insertItem(i18n("1st")); 01297 mWeekCombo->insertItem(i18n("2nd")); 01298 mWeekCombo->insertItem(i18n("3rd")); 01299 mWeekCombo->insertItem(i18n("4th")); 01300 mWeekCombo->insertItem(i18n("5th")); 01301 mWeekCombo->insertItem(i18n("Last Monday in March", "Last")); 01302 mWeekCombo->insertItem(i18n("2nd Last")); 01303 mWeekCombo->insertItem(i18n("3rd Last")); 01304 mWeekCombo->insertItem(i18n("4th Last")); 01305 mWeekCombo->insertItem(i18n("5th Last")); 01306 if (mEveryWeek) 01307 { 01308 mWeekCombo->insertItem(i18n("Every (Monday...) in month", "Every")); 01309 mWeekCombo->setSizeLimit(11); 01310 } 01311 TQWhatsThis::add(mWeekCombo, i18n("Select the week of the month in which to repeat the alarm")); 01312 mWeekCombo->setFixedSize(mWeekCombo->sizeHint()); 01313 mWeekCombo->setReadOnly(readOnly); 01314 mPosButton->setFocusWidget(mWeekCombo); 01315 01316 mDayOfWeekCombo = new ComboBox(false, box); 01317 const KCalendarSystem* calendar = KGlobal::locale()->calendar(); 01318 for (int i = 0; i < 7; ++i) 01319 { 01320 int day = KAlarm::localeDayInWeek_to_weekDay(i); 01321 mDayOfWeekCombo->insertItem(calendar->weekDayName(day)); 01322 } 01323 mDayOfWeekCombo->setReadOnly(readOnly); 01324 TQWhatsThis::add(mDayOfWeekCombo, i18n("Select the day of the week on which to repeat the alarm")); 01325 01326 box->setStretchFactor(new TQWidget(box), 1); // left adjust the controls 01327 box->setFixedHeight(box->sizeHint().height()); 01328 connect(mButtonGroup, TQT_SIGNAL(buttonSet(int)), TQT_SLOT(clicked(int))); 01329 } 01330 01331 MonthYearRule::DayPosType MonthYearRule::type() const 01332 { 01333 return (mButtonGroup->selectedId() == mDayButtonId) ? DATE : POS; 01334 } 01335 01336 void MonthYearRule::setType(MonthYearRule::DayPosType type) 01337 { 01338 mButtonGroup->setButton(type == DATE ? mDayButtonId : mPosButtonId); 01339 } 01340 01341 void MonthYearRule::setDefaultValues(int dayOfMonth, int dayOfWeek) 01342 { 01343 --dayOfMonth; 01344 mDayCombo->setCurrentItem(dayOfMonth); 01345 mWeekCombo->setCurrentItem(dayOfMonth / 7); 01346 mDayOfWeekCombo->setCurrentItem(KAlarm::weekDay_to_localeDayInWeek(dayOfWeek)); 01347 } 01348 01349 int MonthYearRule::date() const 01350 { 01351 int daynum = mDayCombo->currentItem() + 1; 01352 return (daynum <= 31) ? daynum : 31 - daynum; 01353 } 01354 01355 int MonthYearRule::week() const 01356 { 01357 int weeknum = mWeekCombo->currentItem() + 1; 01358 return (weeknum <= 5) ? weeknum : (weeknum == 11) ? 0 : 5 - weeknum; 01359 } 01360 01361 int MonthYearRule::dayOfWeek() const 01362 { 01363 return KAlarm::localeDayInWeek_to_weekDay(mDayOfWeekCombo->currentItem()); 01364 } 01365 01366 void MonthYearRule::setDate(int dayOfMonth) 01367 { 01368 mButtonGroup->setButton(mDayButtonId); 01369 mDayCombo->setCurrentItem(dayOfMonth > 0 ? dayOfMonth - 1 : dayOfMonth < 0 ? 30 - dayOfMonth : 0); // day 0 shouldn't ever occur 01370 } 01371 01372 void MonthYearRule::setPosition(int week, int dayOfWeek) 01373 { 01374 mButtonGroup->setButton(mPosButtonId); 01375 mWeekCombo->setCurrentItem((week > 0) ? week - 1 : (week < 0) ? 4 - week : mEveryWeek ? 10 : 0); 01376 mDayOfWeekCombo->setCurrentItem(KAlarm::weekDay_to_localeDayInWeek(dayOfWeek)); 01377 } 01378 01379 void MonthYearRule::enableSelection(DayPosType type) 01380 { 01381 bool date = (type == DATE); 01382 mDayCombo->setEnabled(date); 01383 mWeekCombo->setEnabled(!date); 01384 mDayOfWeekCombo->setEnabled(!date); 01385 } 01386 01387 void MonthYearRule::clicked(int id) 01388 { 01389 enableSelection(id == mDayButtonId ? DATE : POS); 01390 } 01391 01392 void MonthYearRule::slotDaySelected(int index) 01393 { 01394 daySelected(index <= 30 ? index + 1 : 30 - index); 01395 } 01396 01397 /****************************************************************************** 01398 * Save the state of all controls. 01399 */ 01400 void MonthYearRule::saveState() 01401 { 01402 Rule::saveState(); 01403 mSavedType = type(); 01404 if (mSavedType == DATE) 01405 mSavedDay = date(); 01406 else 01407 { 01408 mSavedWeek = week(); 01409 mSavedWeekDay = dayOfWeek(); 01410 } 01411 } 01412 01413 /****************************************************************************** 01414 * Check whether any of the controls have changed state since initialisation. 01415 */ 01416 bool MonthYearRule::stateChanged() const 01417 { 01418 if (Rule::stateChanged() 01419 || mSavedType != type()) 01420 return true; 01421 if (mSavedType == DATE) 01422 { 01423 if (mSavedDay != date()) 01424 return true; 01425 } 01426 else 01427 { 01428 if (mSavedWeek != week() 01429 || mSavedWeekDay != dayOfWeek()) 01430 return true; 01431 } 01432 return false; 01433 } 01434 01435 01436 /*============================================================================= 01437 = Class MonthlyRule 01438 = Monthly rule widget. 01439 =============================================================================*/ 01440 01441 MonthlyRule::MonthlyRule(bool readOnly, TQWidget* parent, const char* name) 01442 : MonthYearRule(i18n("month(s)"), 01443 i18n("Enter the number of months between repetitions of the alarm"), 01444 false, readOnly, parent, name) 01445 { } 01446 01447 01448 /*============================================================================= 01449 = Class YearlyRule 01450 = Yearly rule widget. 01451 =============================================================================*/ 01452 01453 YearlyRule::YearlyRule(bool readOnly, TQWidget* parent, const char* name) 01454 : MonthYearRule(i18n("year(s)"), 01455 i18n("Enter the number of years between repetitions of the alarm"), 01456 true, readOnly, parent, name) 01457 { 01458 // Set up the month selection widgets 01459 TQBoxLayout* hlayout = new TQHBoxLayout(layout(), KDialog::spacingHint()); 01460 TQLabel* label = new TQLabel(i18n("List of months to select", "Months:"), this); 01461 label->setFixedSize(label->sizeHint()); 01462 hlayout->addWidget(label, 0, TQt::AlignAuto | TQt::AlignTop); 01463 01464 // List the months of the year. 01465 TQWidget* w = new TQWidget(this); // this is to control the TQWhatsThis text display area 01466 hlayout->addWidget(w, 1, TQt::AlignAuto); 01467 TQGridLayout* grid = new TQGridLayout(w, 4, 3, 0, KDialog::spacingHint()); 01468 const KCalendarSystem* calendar = KGlobal::locale()->calendar(); 01469 int year = TQDate::currentDate().year(); 01470 for (int i = 0; i < 12; ++i) 01471 { 01472 mMonthBox[i] = new CheckBox(calendar->monthName(i + 1, year, true), w); 01473 mMonthBox[i]->setFixedSize(mMonthBox[i]->sizeHint()); 01474 mMonthBox[i]->setReadOnly(readOnly); 01475 grid->addWidget(mMonthBox[i], i%3, i/3, TQt::AlignAuto); 01476 } 01477 connect(mMonthBox[1], TQT_SIGNAL(toggled(bool)), TQT_SLOT(enableFeb29())); 01478 w->setFixedHeight(w->sizeHint().height()); 01479 TQWhatsThis::add(w, i18n("Select the months of the year in which to repeat the alarm")); 01480 01481 // February 29th handling option 01482 TQHBox* f29box = new TQHBox(this); 01483 layout()->addWidget(f29box); 01484 TQHBox* box = new TQHBox(f29box); // this is to control the TQWhatsThis text display area 01485 box->setSpacing(KDialog::spacingHint()); 01486 mFeb29Label = new TQLabel(i18n("February 2&9th alarm in non-leap years:"), box); 01487 mFeb29Label->setFixedSize(mFeb29Label->sizeHint()); 01488 mFeb29Combo = new ComboBox(false, box); 01489 mFeb29Combo->insertItem(i18n("No date", "None")); 01490 mFeb29Combo->insertItem(i18n("1st March (short form)", "1 Mar")); 01491 mFeb29Combo->insertItem(i18n("28th February (short form)", "28 Feb")); 01492 mFeb29Combo->setFixedSize(mFeb29Combo->sizeHint()); 01493 mFeb29Combo->setReadOnly(readOnly); 01494 mFeb29Label->setBuddy(mFeb29Combo); 01495 box->setFixedSize(box->sizeHint()); 01496 TQWhatsThis::add(box, 01497 i18n("Select which date, if any, the February 29th alarm should trigger in non-leap years")); 01498 new TQWidget(f29box); // left adjust the visible widgets 01499 f29box->setFixedHeight(f29box->sizeHint().height()); 01500 } 01501 01502 void YearlyRule::setDefaultValues(int dayOfMonth, int dayOfWeek, int month) 01503 { 01504 MonthYearRule::setDefaultValues(dayOfMonth, dayOfWeek); 01505 --month; 01506 for (int i = 0; i < 12; ++i) 01507 mMonthBox[i]->setChecked(i == month); 01508 setFeb29Type(Preferences::defaultFeb29Type()); 01509 daySelected(dayOfMonth); // enable/disable month checkboxes as appropriate 01510 } 01511 01512 /****************************************************************************** 01513 * Fetch which months have been checked (1 - 12). 01514 * Reply = true if February has been checked. 01515 */ 01516 TQValueList<int> YearlyRule::months() const 01517 { 01518 TQValueList<int> mnths; 01519 for (int i = 0; i < 12; ++i) 01520 if (mMonthBox[i]->isChecked() && mMonthBox[i]->isEnabled()) 01521 mnths.append(i + 1); 01522 return mnths; 01523 } 01524 01525 /****************************************************************************** 01526 * Check/uncheck each month of the year according to the specified list. 01527 */ 01528 void YearlyRule::setMonths(const TQValueList<int>& mnths) 01529 { 01530 bool checked[12]; 01531 for (int i = 0; i < 12; ++i) 01532 checked[i] = false; 01533 for (TQValueListConstIterator<int> it = mnths.begin(); it != mnths.end(); ++it) 01534 checked[(*it) - 1] = true; 01535 for (int i = 0; i < 12; ++i) 01536 mMonthBox[i]->setChecked(checked[i]); 01537 enableFeb29(); 01538 } 01539 01540 /****************************************************************************** 01541 * Return the date for February 29th alarms in non-leap years. 01542 */ 01543 KARecurrence::Feb29Type YearlyRule::feb29Type() const 01544 { 01545 if (mFeb29Combo->isEnabled()) 01546 { 01547 switch (mFeb29Combo->currentItem()) 01548 { 01549 case 1: return KARecurrence::FEB29_MAR1; 01550 case 2: return KARecurrence::FEB29_FEB28; 01551 default: break; 01552 } 01553 } 01554 return KARecurrence::FEB29_FEB29; 01555 } 01556 01557 /****************************************************************************** 01558 * Set the date for February 29th alarms to trigger in non-leap years. 01559 */ 01560 void YearlyRule::setFeb29Type(KARecurrence::Feb29Type type) 01561 { 01562 int index; 01563 switch (type) 01564 { 01565 default: 01566 case KARecurrence::FEB29_FEB29: index = 0; break; 01567 case KARecurrence::FEB29_MAR1: index = 1; break; 01568 case KARecurrence::FEB29_FEB28: index = 2; break; 01569 } 01570 mFeb29Combo->setCurrentItem(index); 01571 } 01572 01573 /****************************************************************************** 01574 * Validate: check that at least one month is selected. 01575 */ 01576 TQWidget* YearlyRule::validate(TQString& errorMessage) 01577 { 01578 for (int i = 0; i < 12; ++i) 01579 if (mMonthBox[i]->isChecked() && mMonthBox[i]->isEnabled()) 01580 return 0; 01581 errorMessage = i18n("No month selected"); 01582 return mMonthBox[0]; 01583 } 01584 01585 /****************************************************************************** 01586 * Called when a yearly recurrence type radio button is clicked, 01587 * to enable/disable month checkboxes as appropriate for the date selected. 01588 */ 01589 void YearlyRule::clicked(int id) 01590 { 01591 MonthYearRule::clicked(id); 01592 daySelected(buttonType(id) == DATE ? date() : 1); 01593 } 01594 01595 /****************************************************************************** 01596 * Called when a day of the month is selected in a yearly recurrence, to 01597 * disable months for which the day is out of range. 01598 */ 01599 void YearlyRule::daySelected(int day) 01600 { 01601 mMonthBox[1]->setEnabled(day <= 29); // February 01602 bool enable = (day != 31); 01603 mMonthBox[3]->setEnabled(enable); // April 01604 mMonthBox[5]->setEnabled(enable); // June 01605 mMonthBox[8]->setEnabled(enable); // September 01606 mMonthBox[10]->setEnabled(enable); // November 01607 enableFeb29(); 01608 } 01609 01610 /****************************************************************************** 01611 * Enable/disable the February 29th combo box depending on whether February 01612 * 29th is selected. 01613 */ 01614 void YearlyRule::enableFeb29() 01615 { 01616 bool enable = (type() == DATE && date() == 29 && mMonthBox[1]->isChecked() && mMonthBox[1]->isEnabled()); 01617 mFeb29Label->setEnabled(enable); 01618 mFeb29Combo->setEnabled(enable); 01619 } 01620 01621 /****************************************************************************** 01622 * Save the state of all controls. 01623 */ 01624 void YearlyRule::saveState() 01625 { 01626 MonthYearRule::saveState(); 01627 mSavedMonths = months(); 01628 mSavedFeb29Type = feb29Type(); 01629 } 01630 01631 /****************************************************************************** 01632 * Check whether any of the controls have changed state since initialisation. 01633 */ 01634 bool YearlyRule::stateChanged() const 01635 { 01636 return (MonthYearRule::stateChanged() 01637 || mSavedMonths != months() 01638 || mSavedFeb29Type != feb29Type()); 01639 }